diff options
| author | paul <paul> | 2002-12-13 20:15:29 +0000 | 
|---|---|---|
| committer | paul <paul> | 2002-12-13 20:15:29 +0000 | 
| commit | 718e3744195351130f4ce7dbe0613f4b3e23df93 (patch) | |
| tree | bac2ad39971cd43f31241ef123bd4e470f695ac9 /bgpd | |
Initial revision
Diffstat (limited to 'bgpd')
57 files changed, 50789 insertions, 0 deletions
diff --git a/bgpd/.cvsignore b/bgpd/.cvsignore new file mode 100644 index 0000000000..8edffb6e50 --- /dev/null +++ b/bgpd/.cvsignore @@ -0,0 +1,8 @@ +Makefile +*.o +bgpd +bgp_btoa +bgpd.conf +tags +TAGS +.deps diff --git a/bgpd/BGP4-MIB.txt b/bgpd/BGP4-MIB.txt new file mode 100644 index 0000000000..c911316c27 --- /dev/null +++ b/bgpd/BGP4-MIB.txt @@ -0,0 +1,929 @@ +    BGP4-MIB DEFINITIONS ::= BEGIN + +        IMPORTS +            MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, +            IpAddress, Integer32, Counter32, Gauge32, mib-2 +                FROM SNMPv2-SMI +            MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP +                FROM SNMPv2-CONF; + +        bgp MODULE-IDENTITY +            LAST-UPDATED "9902100000Z" +            ORGANIZATION "IETF IDR Working Group" +            CONTACT-INFO "E-mail:  idr@merit.net + +                          Susan Hares  (Editor) +                          Merit Network +                          4251 Plymouth Road +                          Suite C +                          Ann Arbor, MI 48105-2785 +                          Tel: +1 734 936 2095 +                          Fax: +1 734 647 3185 +                          E-mail: skh@merit.edu + +                          Jeff Johnson (Editor) +                          RedBack Networks, Inc. +                          1389 Moffett Park Drive +                          Sunnyvale, CA  94089-1134 +                          Tel: +1 408 548 3516 +                          Fax: +1 408 548 3599 +                          E-mail: jeff@redback.com" +            DESCRIPTION +                    "The MIB module for BGP-4." +            REVISION    "9902100000Z" +            DESCRIPTION +                    "Corrected duplicate OBJECT IDENTIFIER +                     assignment in the conformance information." +            REVISION    "9601080000Z" +            DESCRIPTION +                    "1) Fixed the definitions of the traps to +                     make them equivalent to their initial +                     definition in RFC 1269. +                     2) Added compliance and conformance info." +            ::= { mib-2 15 } + +        bgpVersion OBJECT-TYPE +            SYNTAX     OCTET STRING (SIZE (1..255)) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "Vector of supported BGP protocol version +                    numbers.  Each peer negotiates the version +                    from this vector.  Versions are identified +                    via the string of bits contained within this +                    object.  The first octet contains bits 0 to +                    7, the second octet contains bits 8 to 15, +                    and so on, with the most significant bit +                    referring to the lowest bit number in the +                    octet (e.g., the MSB of the first octet +                    refers to bit 0).  If a bit, i, is present +                    and set, then the version (i+1) of the BGP +                    is supported." +            ::= { bgp 1 } + +        bgpLocalAs OBJECT-TYPE +            SYNTAX     INTEGER (0..65535) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The local autonomous system number." +            ::= { bgp 2 } + + + +        -- BGP Peer table.  This table contains, one entry per BGP +        -- peer, information about the BGP peer. + +        bgpPeerTable OBJECT-TYPE +            SYNTAX     SEQUENCE OF BgpPeerEntry +            MAX-ACCESS not-accessible +            STATUS     current +            DESCRIPTION +                    "BGP peer table.  This table contains, +                    one entry per BGP peer, information about the +                    connections with BGP peers." +            ::= { bgp 3 } + +        bgpPeerEntry OBJECT-TYPE +            SYNTAX     BgpPeerEntry +            MAX-ACCESS not-accessible +            STATUS     current +            DESCRIPTION +                    "Entry containing information about the +                    connection with a BGP peer." +            INDEX { bgpPeerRemoteAddr } +            ::= { bgpPeerTable 1 } + +        BgpPeerEntry ::= SEQUENCE { +                bgpPeerIdentifier +                    IpAddress, +                bgpPeerState +                    INTEGER, +                bgpPeerAdminStatus +                    INTEGER, +                bgpPeerNegotiatedVersion +                    Integer32, +                bgpPeerLocalAddr +                    IpAddress, +                bgpPeerLocalPort +                    INTEGER, +                bgpPeerRemoteAddr +                    IpAddress, +                bgpPeerRemotePort +                    INTEGER, +                bgpPeerRemoteAs +                    INTEGER, +                bgpPeerInUpdates +                    Counter32, +                bgpPeerOutUpdates +                    Counter32, +                bgpPeerInTotalMessages +                    Counter32, +                bgpPeerOutTotalMessages +                    Counter32, +                bgpPeerLastError +                    OCTET STRING, +                bgpPeerFsmEstablishedTransitions +                    Counter32, +                bgpPeerFsmEstablishedTime +                    Gauge32, +                bgpPeerConnectRetryInterval +                    INTEGER, +                bgpPeerHoldTime +                    INTEGER, +                bgpPeerKeepAlive +                    INTEGER, +                bgpPeerHoldTimeConfigured +                    INTEGER, +                bgpPeerKeepAliveConfigured +                    INTEGER, +                bgpPeerMinASOriginationInterval +                    INTEGER, +                bgpPeerMinRouteAdvertisementInterval +                    INTEGER, +                bgpPeerInUpdateElapsedTime +                    Gauge32 +                } + +        bgpPeerIdentifier OBJECT-TYPE +            SYNTAX     IpAddress +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The BGP Identifier of this entry's BGP peer." +            ::= { bgpPeerEntry 1 } + +        bgpPeerState OBJECT-TYPE +            SYNTAX     INTEGER { +                                idle(1), +                                connect(2), +                                active(3), +                                opensent(4), +                                openconfirm(5), +                                established(6) +                       } +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The BGP peer connection state." +            ::= { bgpPeerEntry 2 } + +        bgpPeerAdminStatus OBJECT-TYPE +            SYNTAX     INTEGER { +                                stop(1), +                                start(2) +                       } +            MAX-ACCESS read-write +            STATUS     current +            DESCRIPTION +                    "The desired state of the BGP connection.  A +                    transition from 'stop' to 'start' will cause +                    the BGP Start Event to be generated.  A +                    transition from 'start' to 'stop' will cause +                    the BGP Stop Event to be generated.  This +                    parameter can be used to restart BGP peer +                    connections.  Care should be used in providing +                    write access to this object without adequate +                    authentication." +            ::= { bgpPeerEntry 3 } + +        bgpPeerNegotiatedVersion OBJECT-TYPE +            SYNTAX     Integer32 +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The negotiated version of BGP running between +                    the two peers." +            ::= { bgpPeerEntry 4 } + +        bgpPeerLocalAddr OBJECT-TYPE +            SYNTAX     IpAddress +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The local IP address of this entry's BGP +                    connection." +            ::= { bgpPeerEntry 5 } + +        bgpPeerLocalPort OBJECT-TYPE +            SYNTAX     INTEGER (0..65535) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The local port for the TCP connection between +                    the BGP peers." +            ::= { bgpPeerEntry 6 } + +        bgpPeerRemoteAddr OBJECT-TYPE +            SYNTAX     IpAddress +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The remote IP address of this entry's BGP +                    peer." +            ::= { bgpPeerEntry 7 } + +        bgpPeerRemotePort OBJECT-TYPE +            SYNTAX     INTEGER (0..65535) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The remote port for the TCP connection between +                    the BGP peers.  Note that the objects +                    bgpPeerLocalAddr, bgpPeerLocalPort, +                    bgpPeerRemoteAddr and bgpPeerRemotePort +                    provide the appropriate reference to the +                    standard MIB TCP connection table." +            ::= { bgpPeerEntry 8 } + +        bgpPeerRemoteAs OBJECT-TYPE +            SYNTAX     INTEGER (0..65535) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The remote autonomous system number." +            ::= { bgpPeerEntry 9 } + +        bgpPeerInUpdates OBJECT-TYPE +            SYNTAX     Counter32 +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The number of BGP UPDATE messages received on +                    this connection.  This object should be +                    initialized to zero (0) when the connection is +                    established." +            ::= { bgpPeerEntry 10 } + +        bgpPeerOutUpdates OBJECT-TYPE +            SYNTAX     Counter32 +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The number of BGP UPDATE messages transmitted +                    on this connection.  This object should be +                    initialized to zero (0) when the connection is +                    established." +            ::= { bgpPeerEntry 11 } + +        bgpPeerInTotalMessages OBJECT-TYPE +            SYNTAX     Counter32 +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The total number of messages received from the +                    remote peer on this connection.  This object +                    should be initialized to zero when the +                    connection is established." +            ::= { bgpPeerEntry 12 } + +        bgpPeerOutTotalMessages OBJECT-TYPE +            SYNTAX     Counter32 +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The total number of messages transmitted to +                    the remote peer on this connection.  This object +                    should be initialized to zero when the +                    connection is established." +            ::= { bgpPeerEntry 13 } + +        bgpPeerLastError OBJECT-TYPE +            SYNTAX     OCTET STRING (SIZE (2)) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The last error code and subcode seen by this +                    peer on this connection.  If no error has +                    occurred, this field is zero.  Otherwise, the +                    first byte of this two byte OCTET STRING +                    contains the error code, and the second byte +                    contains the subcode." +            ::= { bgpPeerEntry 14 } + +        bgpPeerFsmEstablishedTransitions OBJECT-TYPE +            SYNTAX     Counter32 +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The total number of times the BGP FSM +                    transitioned into the established state." +            ::= { bgpPeerEntry 15 } + +        bgpPeerFsmEstablishedTime OBJECT-TYPE +            SYNTAX     Gauge32 +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "This timer indicates how long (in seconds) this +                    peer has been in the Established state or how long +                    since this peer was last in the Established state. +                    It is set to zero when a new peer is configured or +                    the router is booted." +            ::= { bgpPeerEntry 16 } + +        bgpPeerConnectRetryInterval OBJECT-TYPE +            SYNTAX     INTEGER (1..65535) +            MAX-ACCESS read-write +            STATUS     current +            DESCRIPTION +                    "Time interval in seconds for the ConnectRetry +                    timer.  The suggested value for this timer is +                    120 seconds." +            ::= { bgpPeerEntry 17 } + +        bgpPeerHoldTime OBJECT-TYPE +            SYNTAX     INTEGER  ( 0 | 3..65535 ) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "Time interval in seconds for the Hold Timer +                    established with the peer.  The value of this +                    object is calculated by this BGP speaker by +                    using the smaller of the value in +                    bgpPeerHoldTimeConfigured and the Hold Time +                    received in the OPEN message.  This value +                    must be at lease three seconds if it is not +                    zero (0) in which case the Hold Timer has +                    not been established with the peer, or, the +                    value of bgpPeerHoldTimeConfigured is zero (0)." +            ::= { bgpPeerEntry 18 } + +        bgpPeerKeepAlive OBJECT-TYPE +            SYNTAX     INTEGER ( 0 | 1..21845 ) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "Time interval in seconds for the KeepAlive +                    timer established with the peer.  The value of +                    this object is calculated by this BGP speaker +                    such that, when compared with bgpPeerHoldTime, +                    it has the same proportion as what +                    bgpPeerKeepAliveConfigured has when compared +                    with bgpPeerHoldTimeConfigured.  If the value +                    of this object is zero (0), it indicates that +                    the KeepAlive timer has not been established +                    with the peer, or, the value of +                    bgpPeerKeepAliveConfigured is zero (0)." +            ::= { bgpPeerEntry 19 } + +        bgpPeerHoldTimeConfigured OBJECT-TYPE +            SYNTAX     INTEGER ( 0 | 3..65535 ) +            MAX-ACCESS read-write +            STATUS     current +            DESCRIPTION +                    "Time interval in seconds for the Hold Time +                    configured for this BGP speaker with this peer. +                    This value is placed in an OPEN message sent to +                    this peer by this BGP speaker, and is compared +                    with the Hold Time field in an OPEN message +                    received from the peer when determining the Hold +                    Time (bgpPeerHoldTime) with the peer.  This value +                    must not be less than three seconds if it is not +                    zero (0) in which case the Hold Time is NOT to be +                    established with the peer.  The suggested value for +                    this timer is 90 seconds." +            ::= { bgpPeerEntry 20 } + +        bgpPeerKeepAliveConfigured OBJECT-TYPE +            SYNTAX     INTEGER ( 0 | 1..21845 ) +            MAX-ACCESS read-write +            STATUS     current +            DESCRIPTION +                    "Time interval in seconds for the KeepAlive timer +                    configured for this BGP speaker with this peer. +                    The value of this object will only determine the +                    KEEPALIVE messages' frequency relative to the value +                    specified in bgpPeerHoldTimeConfigured; the actual +                    time interval for the KEEPALIVE messages is +                    indicated by bgpPeerKeepAlive.  A reasonable +                    maximum value for this timer would be configured to +                    be one third of that of bgpPeerHoldTimeConfigured. +                    If the value of this object is zero (0), no +                    periodical KEEPALIVE messages are sent to the peer +                    after the BGP connection has been established.  The +                    suggested value for this timer is 30 seconds." +            ::= { bgpPeerEntry 21 } + +        bgpPeerMinASOriginationInterval OBJECT-TYPE +            SYNTAX     INTEGER (1..65535) +            MAX-ACCESS read-write +            STATUS     current +            DESCRIPTION +                    "Time interval in seconds for the +                    MinASOriginationInterval timer. +                    The suggested value for this timer is 15 seconds." +            ::= { bgpPeerEntry 22 } + +        bgpPeerMinRouteAdvertisementInterval OBJECT-TYPE +            SYNTAX     INTEGER (1..65535) +            MAX-ACCESS read-write +            STATUS     current +            DESCRIPTION +                    "Time interval in seconds for the +                    MinRouteAdvertisementInterval timer. +                    The suggested value for this timer is 30 seconds." +            ::= { bgpPeerEntry 23 } + +        bgpPeerInUpdateElapsedTime OBJECT-TYPE +            SYNTAX     Gauge32 +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "Elapsed time in seconds since the last BGP +                    UPDATE message was received from the peer. +                    Each time bgpPeerInUpdates is incremented, +                    the value of this object is set to zero (0)." +            ::= { bgpPeerEntry 24 } + + + +        bgpIdentifier OBJECT-TYPE +            SYNTAX     IpAddress +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The BGP Identifier of local system." +            ::= { bgp 4 } + + + +        -- Received Path Attribute Table.  This table contains, +        -- one entry per path to a network, path attributes +        -- received from all peers running BGP version 3 or less. +        -- This table is obsolete, having been replaced in +        -- functionality with the bgp4PathAttrTable. + +        bgpRcvdPathAttrTable OBJECT-TYPE +            SYNTAX     SEQUENCE OF BgpPathAttrEntry +            MAX-ACCESS not-accessible +            STATUS     obsolete +            DESCRIPTION +                    "The BGP Received Path Attribute Table contains +                    information about paths to destination networks +                    received from all peers running BGP version 3 or +                    less." +            ::= { bgp 5 } + +        bgpPathAttrEntry OBJECT-TYPE +            SYNTAX     BgpPathAttrEntry +            MAX-ACCESS not-accessible +            STATUS     obsolete +            DESCRIPTION +                    "Information about a path to a network." +            INDEX { bgpPathAttrDestNetwork, +                    bgpPathAttrPeer        } +            ::= { bgpRcvdPathAttrTable 1 } + +        BgpPathAttrEntry ::= SEQUENCE { +            bgpPathAttrPeer +                 IpAddress, +            bgpPathAttrDestNetwork +                 IpAddress, +            bgpPathAttrOrigin +                 INTEGER, +            bgpPathAttrASPath +                 OCTET STRING, +            bgpPathAttrNextHop +                 IpAddress, +            bgpPathAttrInterASMetric +                 Integer32 +        } + +        bgpPathAttrPeer OBJECT-TYPE +            SYNTAX     IpAddress +            MAX-ACCESS read-only +            STATUS     obsolete +            DESCRIPTION +                    "The IP address of the peer where the path +                    information was learned." +            ::= { bgpPathAttrEntry 1 } + +        bgpPathAttrDestNetwork OBJECT-TYPE +            SYNTAX     IpAddress +            MAX-ACCESS read-only +            STATUS     obsolete +            DESCRIPTION +                    "The address of the destination network." +            ::= { bgpPathAttrEntry 2 } + +        bgpPathAttrOrigin OBJECT-TYPE +            SYNTAX     INTEGER { +                           igp(1),-- networks are interior +                           egp(2),-- networks learned via EGP +                           incomplete(3) -- undetermined +                       } +            MAX-ACCESS read-only +            STATUS     obsolete +            DESCRIPTION +                 "The ultimate origin of the path information." +            ::= { bgpPathAttrEntry 3 } + +        bgpPathAttrASPath OBJECT-TYPE +            SYNTAX     OCTET STRING (SIZE (2..255)) +            MAX-ACCESS read-only +            STATUS     obsolete +            DESCRIPTION +                    "The set of ASs that must be traversed to reach +                    the network.  This object is probably best +                    represented as SEQUENCE OF INTEGER.  For SMI +                    compatibility, though, it is represented as +                    OCTET STRING.  Each AS is represented as a pair +                    of octets according to the following algorithm: + +                        first-byte-of-pair = ASNumber / 256; +                        second-byte-of-pair = ASNumber & 255;" +            ::= { bgpPathAttrEntry 4 } + +        bgpPathAttrNextHop OBJECT-TYPE +            SYNTAX     IpAddress +            MAX-ACCESS read-only +            STATUS     obsolete +            DESCRIPTION +                    "The address of the border router that should +                    be used for the destination network." +            ::= { bgpPathAttrEntry 5 } + +        bgpPathAttrInterASMetric OBJECT-TYPE +            SYNTAX     Integer32 +            MAX-ACCESS read-only +            STATUS     obsolete +            DESCRIPTION +                    "The optional inter-AS metric.  If this +                    attribute has not been provided for this route, +                    the value for this object is 0." +            ::= { bgpPathAttrEntry 6 } + + + +        -- BGP-4 Received Path Attribute Table.  This table contains, +        -- one entry per path to a network, path attributes +        -- received from all peers running BGP-4. + +        bgp4PathAttrTable OBJECT-TYPE +            SYNTAX     SEQUENCE OF Bgp4PathAttrEntry +            MAX-ACCESS not-accessible +            STATUS     current +            DESCRIPTION +                    "The BGP-4 Received Path Attribute Table contains +                    information about paths to destination networks +                    received from all BGP4 peers." +            ::= { bgp 6 } + +        bgp4PathAttrEntry OBJECT-TYPE +            SYNTAX     Bgp4PathAttrEntry +            MAX-ACCESS not-accessible +            STATUS     current +            DESCRIPTION +                    "Information about a path to a network." +            INDEX { bgp4PathAttrIpAddrPrefix, +                    bgp4PathAttrIpAddrPrefixLen, +                    bgp4PathAttrPeer            } +            ::= { bgp4PathAttrTable 1 } + +        Bgp4PathAttrEntry ::= SEQUENCE { +            bgp4PathAttrPeer +                 IpAddress, +            bgp4PathAttrIpAddrPrefixLen +                 INTEGER, +            bgp4PathAttrIpAddrPrefix +                 IpAddress, +            bgp4PathAttrOrigin +                 INTEGER, +            bgp4PathAttrASPathSegment +                 OCTET STRING, +            bgp4PathAttrNextHop +                 IpAddress, +            bgp4PathAttrMultiExitDisc +                 INTEGER, +            bgp4PathAttrLocalPref +                 INTEGER, +            bgp4PathAttrAtomicAggregate +                 INTEGER, +            bgp4PathAttrAggregatorAS +                 INTEGER, +            bgp4PathAttrAggregatorAddr +                 IpAddress, +            bgp4PathAttrCalcLocalPref +                 INTEGER, +            bgp4PathAttrBest +                 INTEGER, +            bgp4PathAttrUnknown +                 OCTET STRING +        } + +        bgp4PathAttrPeer OBJECT-TYPE +            SYNTAX     IpAddress +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The IP address of the peer where the path +                    information was learned." +            ::= { bgp4PathAttrEntry 1 } +        bgp4PathAttrIpAddrPrefixLen OBJECT-TYPE +            SYNTAX     INTEGER (0..32) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "Length in bits of the IP address prefix in the +                    Network Layer Reachability Information field." +            ::= { bgp4PathAttrEntry 2 } + +        bgp4PathAttrIpAddrPrefix OBJECT-TYPE +            SYNTAX     IpAddress +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "An IP address prefix in the Network Layer +                    Reachability Information field.  This object +                    is an IP address containing the prefix with +                    length specified by bgp4PathAttrIpAddrPrefixLen. +                    Any bits beyond the length specified by +                    bgp4PathAttrIpAddrPrefixLen are zeroed." +            ::= { bgp4PathAttrEntry 3 } + +        bgp4PathAttrOrigin OBJECT-TYPE +            SYNTAX     INTEGER { +                                 igp(1),-- networks are interior +                                 egp(2),-- networks learned via EGP +                                 incomplete(3) -- undetermined +                               } +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The ultimate origin of the path information." +            ::= { bgp4PathAttrEntry 4 } + +        bgp4PathAttrASPathSegment OBJECT-TYPE +            SYNTAX     OCTET STRING (SIZE (2..255)) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The sequence of AS path segments.  Each AS +                    path segment is represented by a triple +                    <type, length, value>. + +                    The type is a 1-octet field which has two +                    possible values: +                         1      AS_SET: unordered set of ASs a +                                     route in the UPDATE message +                                     has traversed +                         2      AS_SEQUENCE: ordered set of ASs +                                     a route in the UPDATE message +                                     has traversed. + +                    The length is a 1-octet field containing the +                    number of ASs in the value field. + +                    The value field contains one or more AS +                    numbers, each AS is represented in the octet +                    string as a pair of octets according to the +                    following algorithm: + +                        first-byte-of-pair = ASNumber / 256; +                        second-byte-of-pair = ASNumber & 255;" +            ::= { bgp4PathAttrEntry 5 } + +        bgp4PathAttrNextHop OBJECT-TYPE +            SYNTAX     IpAddress +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The address of the border router that should +                    be used for the destination network." +            ::= { bgp4PathAttrEntry 6 } + +        bgp4PathAttrMultiExitDisc OBJECT-TYPE +            SYNTAX     INTEGER (-1..2147483647) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "This metric is used to discriminate between +                    multiple exit points to an adjacent autonomous +                    system.  A value of -1 indicates the absence of +                    this attribute." +            ::= { bgp4PathAttrEntry 7 } + +        bgp4PathAttrLocalPref OBJECT-TYPE +            SYNTAX     INTEGER (-1..2147483647) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The originating BGP4 speaker's degree of +                    preference for an advertised route.  A value of +                    -1 indicates the absence of this attribute." +            ::= { bgp4PathAttrEntry 8 } + +        bgp4PathAttrAtomicAggregate OBJECT-TYPE +            SYNTAX     INTEGER { +                           lessSpecificRrouteNotSelected(1), +                           lessSpecificRouteSelected(2) +                       } +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "Whether or not a system has selected +                    a less specific route without selecting a +                    more specific route." +            ::= { bgp4PathAttrEntry 9 } + +        bgp4PathAttrAggregatorAS OBJECT-TYPE +            SYNTAX     INTEGER (0..65535) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The AS number of the last BGP4 speaker that +                    performed route aggregation.  A value of zero (0) +                    indicates the absence of this attribute." +            ::= { bgp4PathAttrEntry 10 } + +        bgp4PathAttrAggregatorAddr OBJECT-TYPE +            SYNTAX     IpAddress +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The IP address of the last BGP4 speaker that +                     performed route aggregation.  A value of +                     0.0.0.0 indicates the absence of this attribute." +            ::= { bgp4PathAttrEntry 11 } + +        bgp4PathAttrCalcLocalPref OBJECT-TYPE +            SYNTAX     INTEGER (-1..2147483647) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "The degree of preference calculated by the +                    receiving BGP4 speaker for an advertised route. +                    A value of -1 indicates the absence of this +                    attribute." +            ::= { bgp4PathAttrEntry 12 } + +        bgp4PathAttrBest OBJECT-TYPE +            SYNTAX     INTEGER { +                           false(1),-- not chosen as best route +                           true(2) -- chosen as best route +                       } +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "An indication of whether or not this route +                    was chosen as the best BGP4 route." +            ::= { bgp4PathAttrEntry 13 } + +        bgp4PathAttrUnknown OBJECT-TYPE +            SYNTAX     OCTET STRING (SIZE(0..255)) +            MAX-ACCESS read-only +            STATUS     current +            DESCRIPTION +                    "One or more path attributes not understood +                     by this BGP4 speaker.  Size zero (0) indicates +                     the absence of such attribute(s).  Octets +                     beyond the maximum size, if any, are not +                     recorded by this object." +            ::= { bgp4PathAttrEntry 14 } + + +        -- Traps. + +        -- note that in RFC 1657, bgpTraps was incorrectly +        -- assigned a value of { bgp 7 }, and each of the +        -- traps had the bgpPeerRemoteAddr object inappropriately +        -- removed from their OBJECTS clause.  The following +        -- definitions restore the semantics of the traps as +        -- they were initially defined in RFC 1269. + +        -- { bgp 7 } is unused + +        bgpTraps          OBJECT IDENTIFIER ::= { bgp 0 } + +        bgpEstablished NOTIFICATION-TYPE +            OBJECTS { bgpPeerRemoteAddr, +                      bgpPeerLastError, +                      bgpPeerState      } +            STATUS  current +            DESCRIPTION +                    "The BGP Established event is generated when +                    the BGP FSM enters the ESTABLISHED state." +            ::= { bgpTraps 1 } + +        bgpBackwardTransition NOTIFICATION-TYPE +            OBJECTS { bgpPeerRemoteAddr, +                      bgpPeerLastError, +                      bgpPeerState      } +            STATUS  current +            DESCRIPTION +                    "The BGPBackwardTransition Event is generated +                    when the BGP FSM moves from a higher numbered +                    state to a lower numbered state." +            ::= { bgpTraps 2 } + +        -- conformance information + +        bgpMIBConformance OBJECT IDENTIFIER ::= { bgp 8 } +        bgpMIBCompliances OBJECT IDENTIFIER ::= { bgpMIBConformance 1 } +        bgpMIBGroups      OBJECT IDENTIFIER ::= { bgpMIBConformance 2 } + +        -- compliance statements + +        bgpMIBCompliance MODULE-COMPLIANCE +            STATUS  current +            DESCRIPTION +                    "The compliance statement for entities which +                     implement the BGP4 mib." +            MODULE  -- this module +                MANDATORY-GROUPS { bgp4MIBGlobalsGroup, +                                   bgp4MIBPeerGroup, +                                   bgp4MIBPathAttrGroup, +                                   bgp4MIBNotificationGroup } +            ::= { bgpMIBCompliances 1 } + +        -- units of conformance + +        bgp4MIBGlobalsGroup OBJECT-GROUP +            OBJECTS { bgpVersion, +                      bgpLocalAs, +                      bgpIdentifier } +            STATUS  current +            DESCRIPTION +                    "A collection of objects providing information +                     on global BGP state." +            ::= { bgpMIBGroups 1 } + +        bgp4MIBPeerGroup OBJECT-GROUP +            OBJECTS { bgpPeerIdentifier, +                      bgpPeerState, +                      bgpPeerAdminStatus, +                      bgpPeerNegotiatedVersion, +                      bgpPeerLocalAddr, +                      bgpPeerLocalPort, +                      bgpPeerRemoteAddr, +                      bgpPeerRemotePort, +                      bgpPeerRemoteAs, +                      bgpPeerInUpdates, +                      bgpPeerOutUpdates, +                      bgpPeerInTotalMessages, +                      bgpPeerOutTotalMessages, +                      bgpPeerLastError, +                      bgpPeerFsmEstablishedTransitions, +                      bgpPeerFsmEstablishedTime, +                      bgpPeerConnectRetryInterval, +                      bgpPeerHoldTime, +                      bgpPeerKeepAlive, +                      bgpPeerHoldTimeConfigured, +                      bgpPeerKeepAliveConfigured, +                      bgpPeerMinASOriginationInterval, +                      bgpPeerMinRouteAdvertisementInterval, +                      bgpPeerInUpdateElapsedTime } +            STATUS  current +            DESCRIPTION +                    "A collection of objects for managing +                     BGP peers." +            ::= { bgpMIBGroups 2 } + +        bgp4MIBRcvdPathAttrGroup OBJECT-GROUP +            OBJECTS { bgpPathAttrPeer, +                      bgpPathAttrDestNetwork, +                      bgpPathAttrOrigin, +                      bgpPathAttrASPath, +                      bgpPathAttrNextHop, +                      bgpPathAttrInterASMetric } +            STATUS  obsolete +            DESCRIPTION +                    "A collection of objects for managing BGP +                     path entries. + +                     This conformance group is obsolete, +                     replaced by bgp4MIBPathAttrGroup." +            ::= { bgpMIBGroups 3 } + +        bgp4MIBPathAttrGroup OBJECT-GROUP +            OBJECTS { bgp4PathAttrPeer, +                      bgp4PathAttrIpAddrPrefixLen, +                      bgp4PathAttrIpAddrPrefix, +                      bgp4PathAttrOrigin, +                      bgp4PathAttrASPathSegment, +                      bgp4PathAttrNextHop, +                      bgp4PathAttrMultiExitDisc, +                      bgp4PathAttrLocalPref, +                      bgp4PathAttrAtomicAggregate, +                      bgp4PathAttrAggregatorAS, +                      bgp4PathAttrAggregatorAddr, +                      bgp4PathAttrCalcLocalPref, +                      bgp4PathAttrBest, +                      bgp4PathAttrUnknown } +            STATUS  current +            DESCRIPTION +                    "A collection of objects for managing +                     BGP path entries." +            ::= { bgpMIBGroups 4 } + +        bgp4MIBNotificationGroup NOTIFICATION-GROUP +            NOTIFICATIONS { bgpEstablished, +                            bgpBackwardTransition } +            STATUS  current +            DESCRIPTION +                    "A collection of notifications for signaling +                    changes in BGP peer relationships." +            ::= { bgpMIBGroups 5 } + +    END diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog new file mode 100644 index 0000000000..4f7a20e936 --- /dev/null +++ b/bgpd/ChangeLog @@ -0,0 +1,2368 @@ +2002-10-23  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgp_aspath.c (aspath_init): Extend hash size from default to +	32767. +	(aspath_key_make): Use unsigned shoft for making hash.  Suggested +	by: Marc Evans <Marc@SoftwareHackery.Com> + +2002-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgp_clist.c (community_entry_free): Fix memory leak of standard +	extcommunity-list config string. + +2002-08-19  Akihiro Mizutani <mizutani@net-chef.net> + +	* bgp_route.c (route_vty_out_detail): Fix bug of router-id display +	when multiple instance is used. + +2002-08-18  Akihiro Mizutani <mizutani@net-chef.net> + +	* bgpd.c: Make "default-originate" and "maximum-prefix" commands +	available in peer-group configuration. + +2002-08-13  Akihiro Mizutani <mizutani@net-chef.net> + +	* bgp_packet.c (bgp_open_send): Put Opt Parm Len 0 when last +	capability packet cause error or dont-capability-negotiate option +	is specified. + +2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* zebra-0.93 released. + +2001-10-28  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_vty_init): Translate update commands are removed. + +2001-10-10  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_static_set): Add workaround for BGP static +	route announcement when there is no zebra running. + +2001-10-08  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (neighbor_remote_as_unicast): Remove "remote-as nlri +	unicast multicast" commands. + +2001-09-14  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_open.c: When we receive capability route-refresh, we should +	check we send the capability not we receive the capability. + +	* bgp_route.c (bgp_network_mask_natural_route_map): network +	statement route-map is added. + +2001-08-31  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgp_advertise.c (bgp_advertise_intern): attr must be interned +	before looking up hash table. + +2001-08-30  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgpd.h (struct peer): BGP filter is moved from peer_conf to +	peer. + +2001-08-28  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgp_nexthop.c (bnc_nexthop_free): Fix next pointer bug. +	Suggested by: "Hong-Sung Kim" <hoskim@lanbird.co.kr>. + +2001-08-26  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgp_table.c (bgp_node_create): Clearn memory before use it. + +2001-08-24  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* Change to use bgp_table.[ch]. + +2001-08-23  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgpd.c (bgp_init): Add "transparent-as" and +	"transparent-nexthop" for old version compatibility. + +2001-08-23  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.h (struct peer): default-originate route-map is added. + +	* bgp_route.c: When self originated route is advertised with +	attrubute-unchanged, nexthop was not properly set.  This bug is +	fixed. + +2001-08-22  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c (neighbor_attr_unchanged): transparent-as and +	transparent-next-hop commands are restructured.  Instead of +	current transparent-* commands, attribute-unchanged command is +	introduced. + +	neighbor A.B.C.D attribute-unchanged [as-path|next-hop|med] + +	(neighbor_default_originate): "default-originate" configuration +	announce default route even 0.0.0.0/0 does not exists in BGP RIB. + +2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* zebra-0.92a released. + +2001-08-19  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c: AF specific soft-reconfiguration inbound commands are +	added. + +2001-08-17  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgp_route.c (bgp_show_callback): Do not do community NULL check. + +	* bgp_community.c (community_cmp): Add check for commnunity NULL +	check. + +	* bgp_routemap.c (route_match_community): Do not check comunity is +	NULL.  It may match to community-list "^$". + +	* bgp_community.c (community_match): Add check for community is +	NULL case. + +2001-08-17  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c: AF specific route-reflector-client and +	route-server-client configuration are added. + +2001-08-17  Rick Payne <rickp@ayrnetworks.com> + +	* bgp_clist.c (community_match_regexp): Check special ^$ case. + +2001-08-17  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_clist.c (community_list_match): Fix bug of community list +	permit and deny check. + +2001-08-16  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_mplsvpn.c (bgp_mplsvpn_init): Add AF specific "nexthop-self" +	command. + +2001-08-15  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.h (PEER_FLAG_SEND_COMMUNITY): Per AF based configuration +	flag is introduced. + +	* bgp_mplsvpn.c (bgp_mplsvpn_init): VPNv4 filtering is added. + +2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* zebra-0.92 released. + +2001-08-13  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgpd.c (bgp_delete): "no router bgp" free static, aggregate, rib +	table properly. + +2001-08-12  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgp_route.c (bgp_node_safi): Return SAFI of current node. +	(bgp_config_write_network_vpnv4): VPNv4 static configuration +	display. + +2001-08-11  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgpd.c (no_bgp_ipv4_multicast_route_map): Add IPv4 multicast +	node filter commands. + +2001-08-11  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.h (PEER_FLAG_IGNORE_LINK_LOCAL_NEXTHOP): Add +	"ignore-link-local-nexthop" flag for ignore link-local nexthop for +	IPv6. + +2001-08-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgpd.c (address_family_ipv4_multicast): "address-family ipv4 +	multicast" is added. +	(address_family_ipv6_unicast): "address-family ipv6 unicast" is +	added. +	 +2001-08-07  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c (bgp_process): Use flag instead of as_selected +	memeber in struct bgp_info. + +	* bgp_route.h (struct bgp_info): Remove as_selected memeber from +	struct bgp_info. + +2001-07-31  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgp_route.c (bgp_announce_check): Enclose sending time AS loop +	check code with #ifdef BGP_SEND_ASPATH_CHECK. + +2001-07-29  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgp_packet.c (bgp_withdraw_send): Simplify address family check. + +	* bgpd.h (BGP_INFO_HOLDDOWN): Introduce new macro to check BGP +	information is alive or not. + +	* bgp_community.c: Use community_val_get() on all OS. + +2001-07-24  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgp_route.c (bgp_announce_check): Simplify set next-hop self +	check. + +2001-07-24  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c (bgp_announce_check): To route server clients, we +	announce AS path, MED and nexthop transparently. + +2001-06-21  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c (route_set_atomic_aggregate_free): Do not call +	XFREE.  No memory is allocated in +	route_set_atomic_aggregate_compile(). + +2001-06-21  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c (bgp_route_map_init): `match nlri` and `set nlri` +	are replaced by `address-family ipv4` and `address-family vpnvr'. + +2001-06-19  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_withdraw): Add check for BGP_PEER_CONFED. +	Reported by Rick Payne <rickp@rossfell.co.uk>. + +2001-06-17  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_zebra.c (bgp_zebra_announce): When global IPv6 nexthop is +	empty, use socket's remote address for the nexthop. + +2001-06-04  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgpd.c (peer_delete): Fix memory leak.  Reported by Yosi Yarchi +	<Yosi_Yarchi@KereniX.com> + +2001-06-01  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgpd.c (bgp_delete): Fix memory leak.  Reported by Yosi Yarchi +	<Yosi_Yarchi@KereniX.com> + +2001-05-27  Kunihiro Ishiguro  <kunihiro@ipinfusion.com> + +	* bgp_route.c (bgp_route_clear_with_afi_vpnv4): Use next instead +	of ri->next. + +	* bgp_packet.c (bgp_withdraw_send): MPLS/VPN withdraw takes effect +	when HAVE_IPV6 is not defined. + +2001-03-07  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgpd.c (peer_timers_set): Adjust keepalive timer to fit less +	than holdtime / 3. +	(bgp_confederation_peers_unset): Only set peer->local_as when +	confederation is enabled. +	(bgp_timers): Add "timers bgp <0-65535> <0-65535>" command. + +	* bgp_route.c (bgp_announce_check): Set med of redistributed route +	when it is announced to EBGP peer. + +2001-03-06  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_nexthop.c (bgp_scan_ipv4): bgp_scan() call bgp_process() for +	all prefixes. + +2001-03-06  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.c (bgp_attr_origin): When bgpd send NOTIFICATION with +	erroneous attribute (type, length and value), it does include +	attribute flags field. + +2001-02-21  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_route.c (bgp_announce_check): The route reflector is not +	allowed to modify the attributes of the reflected IBGP routes. + +2001-02-20  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_route.c (bgp_info_cmp): During path seleciton, BGP +	confederation peer is treated as same as IBGP peer. + +2001-02-19  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_redistribute_add): Initialize attr_new with +	attr.  Call aspath_unintern when return from this function. + +2001-02-19  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgpd.c (bgp_router_id_set): Reset BGP peer when router-id is +	changed. + +2001-02-18  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_packet.c (bgp_open_receive): When user configure holdtimer, +	do not refrect the value to current session. + +2001-02-16  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_aggregate_delete): Set BGP_INFO_ATTR_CHANGE to +	suppress route withdraw. + +	* bgp_damp.c (bgp_damp_init): Fix bug of flap dampening. + +2001-02-16  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_aspath.c (aspath_make_str_count): Use ',' for separator for +	AS_SET and AS_CONFED_SET. + +2001-02-15  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_process): Do not consider suppress route. + +	* bgp_aspath.c (aspath_aggregate_as_set_add): Reset asset when +	aspath->data is realloced. + +2001-02-15  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_attr.c (bgp_attr_aggregate_intern): Do not set atomic +	aggregate when using as-set. + +2001-02-14  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgpd.c (bgp_confederation_peers_unset): Set peer's local-as +	correctly. + +	* bgp_route.c (bgp_update): Just ignore AS path loop for +	confederation peer. + +2001-02-10  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_aggregate_set): Add as_set argument. +	(bgp_aggregate_unset): Remove summary_only argument. +	(aggregate_address_as_set): New commands. +	"aggregate-address A.B.C.D/M as-set" +	"no aggregate-address A.B.C.D/M as-set" + +2001-02-08  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_route.c (bgp_announce_check): Do not modify nexthop when the +	route is passed by route reflector. + +2001-02-08  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c: "no bgp dampening" with argument. +	(bgp_announce_check): Do not modify nexthop when the route is +	passed by route reflector. + +2001-02-07  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgpd.c (neighbor_passive): Change "neighbor NEIGHBOR remote-as +	ASN passive" to "neighbor NEIGHBOR passive". +	(bgp_announce_check): Check well-known community attribute even +	when "no neighbor send-community" is set. + +2001-02-03  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_fsm.c (bgp_establish): Do not send keepalive at established +	time when keepalive timer is configured as zero. + +2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.c (bgp_attr_check): When peer is IBGP peer, local +	preference is well-known attribute. + +2001-01-30  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* zebra-0.91 is released. + +	* bgp_attr.h (struct attr): Comment out DPA value. +	(struct attr): Change refcnt type from int to unsinged long. + +	* bgp_attr.c (attrhash_key_make): Likewise. +	(attrhash_cmp): Likewise. +	(bgp_attr_dpa): Likewise. + +2001-01-30  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_route.c (bgp_info_cmp): Make route selection completely same +	as Cisco's. + +2001-01-30  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.h (BGP_ATTR_FLAG_OPTIONAL): Rename old ATTR_FLAG_* to +	BGP_ATTR_FLAG_* to clarify meenings. + +2001-01-30  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_route.c (route_vty_out): Display argument to suppress same +	prefix information display. +	(route_vty_out_route): Don't display mask information for +	classfull network. + +2001-01-30  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.h (SET_BITMAP): Simple bitmapping macros. + +	* bgp_attr.c (bgp_attr_parse): Use bitmap for attribute type +	check. + +2001-01-29  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.c (bgp_mp_reach_parse): Enclose loggin with BGP_DEBUG. +	(bgp_attr_parse): Comment out well-known attribute check. + +2001-01-28  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_static_unset): Link-local IPv6 address can't be +	used for network advertisement. +	(nlri_parse): When link-local IPv6 address NLRI comes from +	remote-peer, log the information then simply ignore it. + +	* bgp_zebra.c (zebra_read_ipv6): Link-local IPv6 address is not +	redistributed. + +	* bgp_route.c (bgp_update): Check IPv6 global nexthop +	reachability. + +2001-01-26  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_update): Check nexthop points local address or +	not. +	(bgp_static_update_vpnv4): Set valid flag. + +	* bgp_attr.c (bgp_attr_parse): Duplicate attribute check. +	(bgp_attr_parse): Well-known attribute check. + +	* bgp_open.c (bgp_auth_parse): Authentication is not yet supported. + +	* bgp_packet.c (bgp_valid_marker): Check marker is synchronized. + +	* bgpd.c (clear_bgp): Send NOTIFICATION Cease when SEND_CEASE is +	defined. + +	* bgp_snmp.c (bgp4PathAttrTable): Fix compile error. + +2001-01-24  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_network_import_check): New command for IGP network +	check. + +2001-01-23  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_nexthop.c (bgp_scan): Run bgp_process when IGP metric is +	changed.  Call bgp_process once for each node. + +2001-01-23  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_route.c (bgp_info_cmp): Add IGP metric comparison. + +2001-01-23  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_info_cmp): Add IGP metric comparison. + +	* bgp_nexthop.c (bgp_nexthop_lookup): Set IGP metric for valid +	IBGP route. + +2001-01-23  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_route.c (show_ip_bgp_prefix_longer): Add new commands. +	"show ip bgp A.B.C.D/M longer-prefixes" +	"show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes" +	"show ipv6 bgp X:X::X:X/M longer-prefixes" +	"show ipv6 mbgp X:X::X:X/M longer-prefixes" +	 +2001-01-20  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_route.c (show_ip_bgp_cidr_only): Add new commands. +	"show ip bgp cidr-only" +	"show ip bgp ipv4 (unicast|multicast) cidr-only" +	 +2001-01-18  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_route.c (bgp_update): AS path lookup check is done in +	bgp_update() not in attr_parse(). + +2001-01-18  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_update): Call bgp_aggregate_decrement() just +	before bgp_attr_unintern(). + +2001-01-17  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_update): Now intern is performed very last part +	of the BGP packet update procedure. + +2001-01-17  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_route.c (bgp_update): When implicit withdraw occur, reuse +	existing bgp_info structure. + +2001-01-17  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_aggregate_decrement): Fix bug of aggregate +	address matching method. +	(bgp_update):  + +	* bgp_nexthop.c (bgp_nexthop_onlink): Separate EBGP nexthop onlink +	check and IBGP nexthop route check. + +2001-01-16  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_route.h (BGP_INFO_ATRR_CHANGED): Added for track attribute +	change. + +2001-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.h (struct bgp_info): Remove selected flag.  Use +	BGP_INFO_SELECTED for flags instead. +	(struct bgp_info): Remove valid flag.  Use BGP_INFO_VALID for +	flags instead. +	(struct bgp_info): Add igpmetric for IBGP route nexthop IGP +	metric. +	(struct bgp_info_tab): Struct bgp_info_tag is integrated into +	struct bgp_info. +	(BGP_INFO_ATRR_CHANGED): Added for track attribute change. + +	* bgp_community.c (community_val_get): gcc-2.95 on +	sparc-sun-solaris cause crush.  This function is for avoid the +	crush. + +2001-01-15  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_packet.c (bgp_open_receive): Translated peer's packet_size +	clear bug is fixed. + +2001-01-14  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_packet.c (bgp_open_receive): Return notification with +	supported version number. + +2001-01-13  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_show_summary): Display AS path and community +	entries.  Suggested by: "Matt Ranney" <mjr@ranney.com>. + +	* bgp_packet.c (bgp_read_packet): Fix bug of unblocking BGP socket +	read.  When BGP packet read is partial, we must get size and type +	from packet again. + +2001-01-12  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_route.c (bgp_update): Do not unset BGP_INFO_HISTORY flag. +	(bgp_update): When there is a history entry increment route count. +	(bgp_damp_set): Check BGP_CONFIG_DAMPENING flag. + +	* bgp_damp.c (bgp_damp_withdraw): Set status to +	BGP_DAMP_DISCONTINUE. + +2001-01-11  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.c (bgp_mp_reach_parse): Fix warning code when second +	IPv6 nexthop is not link-local addresss. + +2001-01-11  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_damp.c (bgp_config_write_damp): Smart flap dampening +	configuration display. +	(bgp_damp_info_print): Display elapsed time from flap started. + +	* bgp_damp.h (struct bgp_damp_info): Add flap start time. + +	* bgpd.c (peer_create): Set last read time. +	(bgp_show_peer): Display last read time. +	(bgp_show_summary): Use BGP_CONFIG_DAMPENING flag to check +	configuration. +	 +	* bgpd.h (BGP_CONFIG_DAMPENING): Add new configuration option. +	(struct peer): Add last read time member. +	(BGP_VERSION_MP_4): Remove obsolete definition. + +2001-01-10  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_nexthop.c: Remove OLD_RIB codes. + +	* bgp_route.c (bgp_process): Likewise. + +	* zebra-0.90 is released. + +	* bgp_route.h (BGP_INFO_HISTORY): Remove damped member from struct +	bgp_info.  Instead of that use BGP_INFO_DAMPED flag. +	(struct bgp_info): Remove invalid member from struct bgp_info. +	Instead of that use BGP_INFO_HISTORY flag. + +2001-01-10  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgp_damp.c (bgp_damp_info_print): New function to display +	dampening status. +	(DEFAULT_HARF_LIFE): Define default value. +	(DEFAULT_REUSE): Likewise. +	(DEFAULT_SUPPRESS): Likewise. +	(bgp_config_write_damp): When config value is same as default +	value, simply display "bgp dampening" to configuration. + +	* bgp_damp.h (struct bgp_damp_info): Add flap member. + +	* bgp_route.h (struct bgp_info): Added for BGP flap dampening +	history status. + +2001-01-10  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_nexthop.c (bgp_connected_add): Point-to-point connected +	address is properly handled. +	(bgp_connected_delete): Likewise. + +	* bgp_route.c (bgp_route_init): Turn off BGP Flap dampening code +	until it works fine. + +2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_show_summary): Add BGP_VERSION_MP_4 case. + +	* bgp_route.c (bgp_update): When this is not damped route, clear +	ri pointer. + +2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_main.c: Add "-n" no_kernel option to not install route to +	kernel.  Suggested by: "Matt Ranney" <mjr@ranney.com> + +2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_nexthop.c (bgp_connected_add): Revert point-to-point +	connected route patch.  Reported by ruud@ruud.org (Ruud de Rooij) + +	* bgp_damp.c (bgp_config_write_damp): Add configuration display +	function. + +	* bgp_route.c (bgp_info_free): Set NULL to BGP dampening +	information when BGP info structure is freed. +	(bgp_info_cmp): Check damped flag. +	(bgp_announce_check): Damped route is not announced. + +2001-01-09  "Akihiro Mizutani" <mizutani@dml.com> + +	* bgpd.c (neighbor_capability_route_refresh): Change "neighbor +	route-refresh" command to "neighbor capability route-refresh". +	(clear_bgp_soft_in): Change soft-reconfig method. + +	clear ip bgp <neighbor> soft in +        -------------------------------------- +        Try stored cache first then route-refresh + +        clear ip bgp <neighbor> in +        --------------------------------- +        Try route-refresh first then try to use stored cache + +2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_nexthop.c (bgp_connected_add): Check point-to-point +	connected route.  Reported by ruud@ruud.org (Ruud de Rooij) + +2001-01-08  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_nexthop.c (bgp_nexthop_lookup): When IBGP nexthop is +	changed, refresh it. + +2001-01-04  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.h (struct bgp_info_tag): Add as_selected to +	bgp_info_tag. + +2001-01-03  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.h (struct bgp_info_tag): Add damped and bgp_damp_info +	member for BGP flap dampening. + +	* bgp_damp.c: New file is added. + +	* bgp_damp.h: Likewise. + +2001-01-01  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.h (BGP_VTYSH_PATH): Change "/tmp/bgpd" to "/tmp/.bgpd". + +2000-12-29  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_nexthop.c (zlookup_connect): Change to use UNIX domain +	socket for zebra communication. + +2000-12-29  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c (bgp_process): Fix "bgp deterministic-med" process. + +2000-12-27  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c (bgp_process): Add "bgp deterministic-med" process. + +2000-12-25  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c (bgp_info_cmp): Use ntohl comparing router ID. + +2000-12-18  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c (bgp_info_cmp): When over three same prefix exit, +	withdrawing best prefix perform router ID comparison. + +2000-12-15  Akihiro Mizutani  <mizutani@dml.com> + +	* bgp_route.c (bgp_info_cmp): Do not compare router ID when the +	routes comes from EBGP peer.  When originator ID is same, take +	shorter cluster-list route.  If cluster-list is same take smaller +	IP address neighbor's route. + +	* bgpd.c (bgp_bestpath_aspath_ignore): Add "bgp bestpath as-path +	ignore" command.  When this option is set, do not concider AS path +	length when route selection. +	(bgp_bestpath_compare_router_id): Add "bgp bestpath +	compare-routerid".  When this option is set, compare router ID +	when the routes comes from EBGP peer. +	 +2000-12-15  Akihiro Mizutani  <mizutani@dml.com> + +	* bgp_route.c (bgp_info_cmp): Compare originator ID when it is +	available. + +2000-12-14  Akihiro Mizutani  <mizutani@dml.com> + +	* bgp_packet.c (bgp_notify_receive): Disply received Notify data +	information. + +2000-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_filter.c (as_filter_free): Use MTYPE_AS_FILTER_STR to make +	it sure the memory is freed. + +	* bgp_route.c (route_vty_out_detail): Do not use AF_INET6 outside +	HAVE_IPV6. + +2000-12-08  Akihiro Mizutani  <mizutani@dml.com> + +	* bgp_packet.c (bgp_notify_send_with_data): Store BGP notification +	data part. + +	* bgp_network.c (bgp_accept): When BGP connection comes from +	unconfigured IP address, close socket immediately. + +	* bgpd.c: Fix some display format. + +2000-11-29  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_packet.c (bgp_keepalive_send): Delete duplicate +	bgp_packet_set_size () call. + +2000-11-28  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_packet.c (bgp_read_packet): Remove debug codes. + +2000-11-27  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_snmp.c (write_bgpPeerTable): Add SNMP set method routine. + +	* bgp_fsm.c (bgp_stop): Use fsm_change_status to change peer's +	status. +	(bgp_establish): Likewise. + +2000-11-26  Akihiro Mizutani  <mizutani@dml.com> + +	* bgp_open.c: Fix error messages. + +2000-11-25  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_fsm.c (bgp_establish): Call BGP trap when the peer is +	established. +	(bgp_stop): Call BGP trap when the peer is dropped. + +2000-11-24  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_snmp.c (bgp4PathAttrTable): Return BGP path attribute table. + +	* bgpd.h (struct peer): Add update_time for track last update +	received time. + +	* bgp_packet.c (bgp_notify_receive): Preserv notify code and sub +	code in any case. + +	* bgp_snmp.c (bgpPeerTable): Return remote router ID instead of +	peering IP address. +	(bgpPeerTable): Return actual BGP version number. + +2000-11-22  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_debug.c (bgp_notify_print): Notify data length display bug +	is fixed. + +2000-11-16  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_nexthop.c (zlookup_connect): When UNIX domain connection to +	zebra is enabled, use the method. + +2000-11-16  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c: Revise debug message output. + +2000-11-15  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_clist.c (ip_community_list): Fix bug of string comparison. + +2000-11-14  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_community.c (community_match): Fix bug of memcmp return +	value check. + +2000-11-07  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_clist.c (community_list_match_exact): Add check for +	entry->style is COMMUNITY_LIST. +	(community_match_regexp): Apply new com_nthval macro. + +2000-11-07  Rick Payne <rickp@rossfell.co.uk> + +	* bgp_routemap.c (route_set_community_delete): "set +	community-delete COMMUNITY-LIST" is added. + +	* bgp_community.c (community_del_val): Delete one community. +	(community_delete): Delete all community included in list. +	(community_match): Fix bug of matching community value. + +	* bgp_clist.c (community_entry_free): Free community regular +	expression. +	(community_entry_make): Default style is COMMUNITY_LIST. +	(community_entry_lookup): Make it sure style is COMMUNITY_LIST. +	(community_entry_regexp_lookup): New function for community +	regular expression lookup. +	(community_match_regexp): New function. +	(community_delete_regexp): New function. +	(community_list_delete_entries): New function. +	(community_list_match): Add COMMUNITY_REGEXP treatment. +	(community_list_match_exact): Likewise. +	(config_write_community): Write community list according to +	entry->style. + +2000-11-07  Rick Payne <rickp@rossfell.co.uk> + +	* bgp_attr.c (bgp_attr_aspath): AS path first AS check. + +	* bgp_clist.c (struct community_entry): Add style, regexp, reg to +	community_entry. + +2000-11-06  Rick Payne <rickp@rossfell.co.uk> + +	* bgp_aspath.c (aspath_firstas_check): AS path first AS check. + +	* bgpd.c (bgp_enforce_first_as): New command "bgp +	enforce-first-as". + +	* bgpd.h (BGP_CONFIG_ENFORCE_FIRST_AS): Add new flag. + +2000-11-06  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_community.c (community_compare): Copy byte stream data to +	actual value instead of using type casting hack. +	(community_add_val): Likewise. +	(community_uniq_sort): Likewise. +	(community_print): Likewise. +	(community_print_vty): Likewise. +	(community_include): Use memcmp to compare community value. + +	* bgp_community.h (com_lastval): com_lastval and com_nthval macro +	return pointer. + +2000-11-06  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.h (struct peer): Add established and dropped member for +	count peering up/down statistics. + +	* bgpd.c (bgp_show_peer): Display peering up/down statistics. + +	* bgp_fsm.c (bgp_establish): Increment established count. +	(bgp_stop): Increment dropped count. + +	* bgp_packet.c (bgp_notify_receive): Increament notify count. + +2000-11-1  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_fsm.c: Fix bug of holdtimer is not reset when bgp cleared.  + +2000-10-31  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.h: Static bit flag is set by (1 << DIGIT). + +2000-10-24  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_ecommunity.c (ecommunity_dup): Extended community display +	format fix. + +2000-10-24  Arkadiusz Miskiewicz <misiek@pld.org.pl> + +	* bgp_network.c (bgp_serv_sock_addrinfo): Use gai_strerror. +	(bgp_serv_sock_addrinfo): Check address family. + +2000-10-23  Jochen Friedrich <jochen@scram.de> + +	* bgp_snmp.c: bgp_oid and bgpd_oid are used in smux_open after it +	is registered.  So those variables must be static. + +2000-10-23  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_routemap.c (route_match_ip_next_hop): Change "match ip +	next-hop" argument from IP address to access-list name. +	Remove zebra-0.88 compatibility commands. +        "match ip prefix-list WORD" +        "match ipv6 prefix-list WORD" +	 +2000-10-23  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c (route_match_ipv6_next_hop_compile): Fix bug of +	passing the pointer to the pointer of struct in6_addr instead of +	the pointer of struct in6_addr in "match ipv6 next-hop" command. + +	* bgp_route.c (bgp_announce_check): Enclose IPv6 part with +	HAVE_IPV6. + +2000-10-20  Jasper Wallace <jasper@ivision.co.uk> + +	* bgp_snmp.c (bgpPeerTable): ntohs missing bug is fixed.  Change +	to use linklist.c.  Define COUNTER32 as ASN_COUNTER. + +2000-10-18  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_announce_check): attr->nexthop empty check +	should be done by attr->nexthop.s_addr instead of strcmp. + +2000-10-18  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_zebra.c (zebra_read_ipv4): Pass nexthop value to +	bgp_redistribute_add(). + +	* bgp_nexthop.c (bgp_multiaccess_check_v4): New function for +	checking IPv4 multiaccess nexthop. + +	* bgp_route.c (bgp_announce_check): In case of the nexthop is +	reachable on multiaccess media, do not change nexthop. +	(bgp_redistribute_add): Set nexthop when the value is passed. + +2000-10-17  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_fsm.c (bgp_timer_set): If peer is passive mode, do not set +	connect timer. +	(bgp_start): If the peer is passive mode, force to move to Active +	mode. + +2000-10-17  Horms <horms@vergenet.net> + +	* bgp_debug.c (debug_bgp_fsm): Fix typo. + +2000-10-17  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c: "show ipv6 bgp" route display improvement. + +2000-10-03  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (neighbor_routes): Allocate sockunion for callback +	function. +	(bgp_show_neighbor_route): Remove static declaration for union +	sockunion. + +	* bgpd.c (peer_update_source_set): Clean previously allocated +	memory before allocate new one. + +2000-10-03  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c (neighbor_routes): Add show neighbor's routes +	command. +	"show ip bgp neighbors (A.B.C.D|X:X::X:X) routes" +	"show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes" +	"show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes" +	"show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes" + +2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* zebra-0.89 is released. + +2000-10-02  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c: "bgp deterministic-med" command is added. + +2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_nexthop.c (bgp_connected_add): Apply mask for connected +	route addition and deletion. + +2000-09-29  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c (aspath_cmp_left): Skip confederation AS segment +	when comparing leftmost AS number. + +2000-09-29  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c (peer_route_reflector): Route reflector can be set for +	IBGP peer. +	(bgp_distribute_set): Fix bug of string check for (in|out). +	(bgp_show_summary): Display total neighbor count. + +2000-09-28  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_attr.c (bgp_packet_attribute): Only add cluster_list and +	originator for clinet to client routes. +	(bgp_packet_attribute): Add new cluster_list to the beginning of +	existing cluster_list. +	(bgp_packet_attribute): Fix bug of originator is rewritten even +	when originator is already set. + +2000-09-27  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_client_to_client_reflection): Add new command. +	"no bgp client-to-client reflection" +	"bgp client-to-client reflection" + +	* bgpd.h (BGP_CONFIG_NO_CLIENT_TO_CLIENT): Add new definition. + +2000-09-26  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_packet.c (bgp_read): Make BGP packet read to non-blocking +	read. +	(bgp_read_packet): Likewise. +	(bgp_read_packet): When errono is EAGAIN, try to read it again. + +	* bgp_fsm.c (bgp_stop): Clear packet size and read buffer. + +2000-09-26  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_routemap.c: Configuration of prefix-list match is shown as +	"match ip address prefix-list <WORD>".  Old configuration "match +	ip prefix-list <WORD>" is left for compatibilitty. + +2000-09-25  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.h (BGP_CONFIG_MED_MISSING_AS_WORST): Changed from +	BGP_CONFIG_MISSING_AS_WORST. + +	* bgpd.c (bgp_bestpath_med): Change missing-as-worst syntax. +	Old "bgp bestpath missing-as-worst" +	New "bgp bestpath med missing-as-worst" + +2000-09-24  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c: Compare MED properly in case of CONFED-IBGP. + +2000-09-21  steve@Watt.COM (Steve Watt) + +	* bgp_debug.h: Do not declare debug variables conf_bgp_debug_* and +	term_bgp_debug_*. + +	* bgp_debug.c: Declare variables here. + +2000-09-21  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c: MBGP soft-reconfiguration command is added. +	clear ip bgp x.x.x.x ipv4 (unicast|multicast) in +	clear ip bgp x.x.x.x ipv4 (unicast|multicast) out +	clear ip bgp x.x.x.x ipv4 (unicast|multicast) soft +	clear ip bgp <1-65535> ipv4 (unicast|multicast) in +	clear ip bgp <1-65535> ipv4 (unicast|multicast) out +	clear ip bgp <1-65535> ipv4 (unicast|multicast) soft +	clear ip bgp * ipv4 (unicast|multicast) in +	clear ip bgp * ipv4 (unicast|multicast) out +	clear ip bgp * ipv4 (unicast|multicast) soft + +	Change "clear ip bgp vpnv4 x.x.x.x soft" command to +	"clear ip bgp x.x.x.x vpnv4 unicast soft". + +	"bgp bestpath med confed" command is added. +	 +	* bgpd.h (BGP_CONFIG_MED_CONFED): Add New definition. + +2000-09-18  Rick Payne <rickp@rossfell.co.uk> + +	* bgpd.c (bgp_show_peer): Fix misplaced #endif. + +2000-09-12  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c (bgp_default_local_preference): Add "bgp default +	local-preference" command. + +	* bgp_nexthop.c (no_bgp_scan_time): Add "no bgp scan-time" +	command. + +2000-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_zebra.c (bgp_zebra_announce): BGP confederation peer's routes +	are passed to zebra like IBGP route. + +2000-09-10  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c (bgp_config_write_peer): Make it consistent passive +	configuration. + +	* bgp_route.c: Community match command is added. +	"show ip bgp community <val>" +	"show ip bgp community <val> exact-match" + +2000-09-08  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_nexthop.c (bgp_nexthop_lookup): ebgp-multihop routes are +	treated as IBGP routes. + +2000-09-08  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c (bgp_show_route): When local-AS community route is +	selected, display "not advertised outside local AS" to "show ip +	route A.B.C.D" output. +	(show_ip_bgp_ipv4_filter_list): Add below four commands. +	"show ip bgp ipv4 (unicast|multicast) filter-list WORD" +	"show ip bgp ipv4 (unicast|multicast) community" +	"show ip bgp ipv4 (unicast|multicast) community-list WORD" +	"show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match" +	 +	* bgp_clist.c (community_list_match_exact): Community exact match +	function. + +2000-09-07  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_update): Add peer's ttl check. + +	* bgpd.h (struct peer): Structure member refresh is renamed to +	refresh_adv. + +	* bgpd.c (clear_bgp_soft_in): Check PEER_FLAG_ROUTE_REFRESH flag +	when soft reconfiguration is performed. + +	* bgp_zebra.c (bgp_zebra_announce): When the peer is EBGP and +	ebgp-multiphop is set, set ZEBRA_FLAG_INTERNAL for nexthop lookup. + +	* bgp_route.h (struct bgp_info_tag): Add valid flag. + +2000-08-25  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c: Add AS base BGP soft reconfiguration. + +	* bgp_route.c: When no-advertise or no-export route is selected, +	"show ip bgp" display "not advertised to EBGP peer" or "not +	advertised to any peer" message. +	 +2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* zebra-0.88 is released. + +	* bgp_dump.c (dump_bgp_routes): Change "dump bgp routes" to "dump +	bgp route-mrt" to support MRT specific dump format. + +	* bgpd.c (bgp_init): "clear ip bgp vpnv4 soft {in,out}" command is +	added. + +	* bgp_route.c (bgp_update): Currently nexthop check is only works +	for IPv4. + +2000-08-17  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd. (clear_ip_bgp_all_soft): Add "clear ip bgp * soft" for +	both inbound and outbound soft reconfiguration. + +2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (clear_ip_bgp_peer_soft_out): Add soft-reconfiguration +	outbound. +	(peer_new): Set route-refresh flag. + +2000-08-16  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c: "no bgp router-id A.B.C.D" alias is added.  "no bgp +	cluster-id A.B.C.D" alias is added.  " bgp cluster-id +	<1-4294967295>" alias is added.  "clear ip bgp * soft in" command +	is added.  "clear ip bgp A.B.C.D in" alias is added.  "clear ip +	bgp * in" alias is added. + +2000-08-16  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_update): Add soft_reconfig flag.  When the flag +	is set do not install the route into Adj-RIBs-In. +	(bgp_update): Perform implicit withdraw before filtering of the +	route. + +	* bgp_packet.c (bgp_read): draft-ietf-idr-bgp-route-refresh-01.txt +	capability code and BGP message can be accepted. + +	* bgp_open.c (bgp_capability_parse): Likewise. + +	* bgp_route.c (bgp_refresh_table): New function for route refresh. +	(bgp_refresh_rib): Likewise. + +	* bgpd.c (bgp_show_peer): Display route refresh status. + +	* bgp_route.c (bgp_aggregate_add): Add check for the route +	validness. +	(bgp_aggregate_delete): Likewise. + +2000-08-15  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_nexthop.c (bgp_scan): Care for aggregate route when the +	route become inaccessible. + +2000-08-15  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c (show_ip_bgp_prefix): "show ip bgp A.B.C.D/M" +	command is added. + +2000-08-15  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_zebra.c (bgp_interface_up): Register connected route. +	(bgp_interface_down): Unregister connected route. + +2000-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.h (struct bgp_info): Add distance to the structure. + +	* bgp_route.c (bgp_aggregate_increment): Aggregate route only +	match to smaller prefixlen route not match same prefixlen route. +	(bgp_aggregate_decrement): Likewise. +	(bgp_aggregate_add): Likewise. +	(bgp_aggregate_delete): Likewise. +	(bgp_network_backdoor): Add backdoor network configuration. + +	* bgpd.h (struct bgp ): Add distance_{ebgp,ibgp,local} for store +	configuration distance value. + +	* bgp_route.c (bgp_update): Filter EBGP route which has non +	connected nexthop. + +	* bgp_attr.c (bgp_attr_aggregate_intern): New function for +	aggregate route.  Set origin to IGP.  Set atomic aggregate flag. +	Set aggregator AS and address. +	(bgp_attr_aggregate_intern): Check BGP_CONFIG_CONFEDERATION when +	filling aggregator_as. + +	* bgp_route.c (bgp_process): Delete suppress check for install +	suppressed route into local routing table. +	(bgp_aggregate_increment): Use bgp_attr_aggregate_intern() instead +	of bgp_attr_default_intern (). +	(bgp_aggregate_add): Likewise. + +	* bgpd.c (bgp_get): Call bgp_if_update_all() after BGP instance is +	created.  This is for avoid 0.0.0.0 router-id. + +2000-08-13  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c (route_vty_out_detail): Display "valid" when the +	route is valied.  Display "aggregated" when the route is +	aggregated.  "Advertisements suppressed by an aggregate" is +	displayed when the route is suppressed. +	(bgp_info_cmp): Prefer EBGP than Confed-EBGP. + +2000-08-10  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c (route_vty_out_detail): Display format change. + +2000-08-06  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_update): Only AFI_IP nexthop check is enabled. + +	* bgpd.c (bgp_delete): Delete static route before delete peer +	configuration. + +2000-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c: Include bgpd/bgp_nexthop.h. + +2000-07-31  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c (bgp_show_summary): "show ip bgp summary" shows own BGP +	identifier.  And status is changed like below. + +	State/Pref   -> State/PfxRcd +	Shutdown     -> Idle (Admin) +	PrefixOvflw  -> Idle (PfxCt) + +	* bgp_route.c (route_vty_out): Show internal route as "i". + +2000-07-13  Jim Bowen <jimb@zereau.net> + +	* bgp_snmp.c: Add BGP peer MIB implementation. + +2000-07-12  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c (bgp_show_peer): Fix typo. + +2000-07-11  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_routemap.c: Add commands for deleting set without argument. + +2000-07-03  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_zebra.c: Fix redistribute help strings. + +2000-07-01  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_show): When bgpd works as vtysh server send all +	output to vty at once. + +2000-06-13  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_mplsvpn.c (no_vpnv4_network): "no network A.B.C.D/M rd WORD +	tag WORD" command is added. + +	* bgp_ecommunity.c (ecommunity_vty_out): New function added. + +2000-06-12  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_show): Fix total number of prefix count bug. + +	* bgpd.c (bgp_show_peer): Display VPNv4 unicast configuration and +	negotiation result in "show ip bgp neighbors". + +2000-06-12  Akihiro Mizutani <mizutani@dml.com> + +	* bgpd.c: Fix help strings. +	 +	* bgpd.h: Likewise. +	 +2000-06-11  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_aggregate_unset): Fix bug of checking rn->info +	instead of rn.  Reported by Akihiro Mizutani <mizutani@dml.com>. + +	* bgp_mplsvpn.c (vpnv4_network): For testing purpose, "network +	A.B.C.D rd RD" is added to address-family vpnv4 unicast node. + +	* bgp_route.c (bgp_static_set): Set safi to p.safi. + +2000-06-10  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_show_prefix_list): Change to use bgp_show(). +	(bgp_show_regexp): Change to use bgp_show(). +	(show_adj_route): Change to display header. + +	* bgpd.c (clear_bgp): Set peer->v_start to default value when peer +	is cleared manually. + +	* bgp_route.c (bgp_show_route): New function which display +	specific BGP route.  Divided from bgp_show(). +	(bgp_static_delete): Delete all static route. + +2000-06-09  NOGUCHI Kay <kay@v6.access.co.jp> + +	* bgp_route.c (show_ipv6_bgp): "show ipv6 bgp" is broken with +	invalid privious fix.  Now show_ipv6_bgp and show_ipv6_bgp_route +	take care of "show ipv6 bgp [X:X::X:X]".  Same change for "show ip +	mbgp" and "show ipv6 mbgp". + +2000-06-07  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_route.c: Fix help strings and command arguments. + +2000-06-06  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_ecommunity.c: Include prefix.h + +2000-06-05  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.h (struct bgp_info_tag): New structure to hold tag +	value. + +	* bgp_route.c (bgp_adj_set): table NULL check is added. +	(bgp_adj_unset): Likewise. +	(bgp_adj_lookup): Likewise. +	(bgp_adj_clear): Likewise. +	(route_vty_out): Add SAFI check for nexthop display. +	(bgp_withdraw): Add SAFI check for withdraw route. + +	* Remove all #ifdef MPLS_VPN then include it as default. + +	* bgpd.c: Temporary disable peer-group command until the +	implementation is completed. + +	* bgp_routemap.c (bgp_route_map_init): Install +	route_metric_match_cmd. +	(route_match_metric_compile): MED value compile using strtoul. + +2000-06-05  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_filter.c: Fix help strings.  Change REGEXP to LINE.  Change +	NAME to WORD. + +	* Change command argument to more comprehensive. + +	METRIC         -> <0-4294967295> +	WEIGHT         -> <0-4294967295> +	LOCAL_PREF     -> <0-4294967295> +	IP_ADDR        -> A.B.C.D +	AS             -> <1-65535> +	AS-PATH-NAME   -> WORD +	ACCESS_LIST    -> WORD +	PREFIX_LIST    -> WORD +	COMMUNITY      -> AA:NN +	EXT_COMMUNITY  -> ASN:nn_or_IP-address:nn +	IPv6_ADDR      -> X:X::X:X + +	* bgp_clist.c: Fix help strings. + +2000-06-03  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (peer_active): Add new function for check the peer is +	active or not. +	(neighbor_activate): New command "neighbor PEER activate" and "no +	neighbor PEER activate" are added. + +	* bgp_packet.c: Include bgpd/bgp_mplsvpn.h. + +2000-06-02  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_clist.c: Fix commuity-list help strings. + +	* bgp_routemap.c: Fix "set community" help strings.  Add #define +	SET_STR.  Use (unicast|multicast) argument for "set nlri" command. +	 +2000-06-01  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c (route_set_community_none_cmd): "set community +	none" command is added to route-map. + +2000-06-01  Akihiro Mizutani <mizutani@dml.com> + +	* bgp_debug.c: Change "show debug" to "show debugging".  Now "show +	debugging" is not used in VIEW_NODE. + +2000-05-30  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_fsm.c (bgp_timer_set): Add check for shutdown flag.  This +	fix unconditional BGP connection. + +	* bgpd.c (peer_shutdown): Replace peer_shutdown() with +	peer_change_flag_with_reset(). + +2000-05-26  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (no_bgp_default_ipv4_unicast): Add "no bgp default +	ipv4-unicast" command. + +	* bgpd.h (BGP_CONFIG_NO_DEFAULT_IPV4): Add new definition. + +	* bgp_filter.c (as_list_delete): Free all AS filter. + +	* bgp_clist.c (community_list_delete): Free all community entry. + +	* bgp_filter.c (no_ip_as_path_all): New DEFUN for "no ip as-path +	access-list NAME". + +	* bgp_clist.c (no_ip_community_list_all): New DEFUN for "no ip +	community-list NAME". + +2000-05-19  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (ipv6_mbgp_neighbor_routes): Change "show ip bgp PEER +	routes" to "show ip bgp PEER received-routes" + +2000-05-14  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_ecommunity.c (ecommunity_parse): New file for Extended +	Communities attribute. +	* bgp_ecommunity.h: Likewise. + +2000-05-11  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_mplsvpn.h: New file for MPLS-VPN. +	* bgp_mplsvpn.c: Likewise. + +	* bgpd.c (bgp_delete): Fix bug of "no router bgp" crush. + +2000-05-10  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_bestpath_missing_as_worst): Add "bgp bestpath +	missing-as-worst". + +2000-05-08  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c (match_community): Clarify help of "match +	community". + +2000-05-02  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c (aspath_cmp_left): Remove debug code. + +2000-04-27  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_info_cmp): Compare MED only both routes comes +	from same neighboring AS. + +	* bgp_aspath.c (aspath_cmp_left): Compare leftmost AS value. + +	* bgp_route.c (bgp_info_cmp): Fix misused htonl() to ntohl(). + +2000-04-26  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_output_filter): When distribute-list's +	corresponding access-list does not exist, filter all routes. +	(bgp_input_filter): Likewise. + +2000-04-19  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.c (bgp_packet_attribute): Propagate MED to IBGP peer. + +	* bgp_route.c (bgp_info_cmp): Add evaluation of local preference. + +2000-04-18  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_distribute_update): Add struct access_list * +	argument. + +2000-04-17  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_clist.c (community_list_dup_check): Add duplicate insertion +	check. + +	* bgp_filter.c (as_list_dup_check): Add duplicate insertion check. + +	* bgp_route.c (bgp_show): Fix undeclared write variable. + +2000-04-13  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c: Add "match ip address prefix-list". + +2000-03-29  Rick Payne <rickp@rossfell.co.uk> + +	* bgp_aspath.c (aspath_strip_confed): Fix realloc problem. + +2000-03-16  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_fsm.c (bgp_reconnect): Connect retry timer is expired when +	the peer status is Connect. + +2000-03-03  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* Fix bug of rewritten originator-id. + +2000-01-27  Rick Payne <rickp@rossfell.co.uk> + +	* bgp_aspath.c (aspath_delimiter_char): New function.  Instead of +	directly referencing array, search proper AS path delimiter. +	(aspath_strip_confed): Strip the confederation stuff from the +	front of an AS path. +	(aspath_add_left_confed): New function for adding specified AS to +	the leftmost AS_CONFED_SEQUENCE. + +	* bgp_aspath.h: Change AS_CONFED_SEQUENCE and AS_CONFED_SET value +	to Cisco compatible. + +	* bgpd.c (bgp_confederation_id_set): Confederation configuration. +	(bgp_confederation_id_unset): Likewise. +	(bgp_confederation_peers_check): Likewise. +	(bgp_confederation_peers_add): Likewise. +	(bgp_confederation_peers_remove): Likewise. +	(bgp_confederation_peers_set): Likewise. +	(bgp_confederation_peers_unset): Likewise. +	(bgp_confederation_peers_print): Likewise. +	 +2000-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c: Introduce peer_change_flag_with_reset() fucntion. + +2000-01-17  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_open.c (bgp_open_option_parse): When there is no common +	capability send Unsupported Capability error to the peer. + +2000-01-14  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_open.c (bgp_capability_mp): Fix bug of mis-negotiation about +	IPv6 unicast. + +	* bgpd.c (bgp_init): Add "soft-reconfiguration inbound" command. +	 +2000-01-12  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (neighbor_strict_capability): Add +	"strict-capability-match" command. + +	* bgp_zebra.c (bgp_if_update): Ignore NET127 determining +	router-id. + +	* bgpd.c (peer_override_capability): Add "override-capability" +	command. + +1999-12-16  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_packet.c (bgp_write): Change status to Idle and set timer +	after write failed. + +1999-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_zebra.c (bgp_zebra_announce): Add info->selected check. + +1999-12-12  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (nlri_unfeasible): nlri_unfeasible() is merged with +	nlri_parse(). + +1999-12-10  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_fsm.h (BGP_EVENT_DELETE): Macro added. + +	* bgp_fsm.c (bgp_stop): Clear all event threads of the peer when +	the peer is cleared. + +	* bgp_zebra.c (bgp_nexthop_set): Clear interface index of +	link-local address.  This is KAME specific problem. + +1999-12-06  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.c (bgp_mp_reach_parse): Comment out previous code for a +	while.  We don't completely detect the link is shared or not at +	this moment. + +	* bgp_packet.c (bgp_notify_send): Make shortcut call of +	bgp_write() and bgp_stop(). + +	* bgp_attr.c (bgp_mp_reach_parse): Fix serious bug when getting +	global and link-local address. + +1999-12-05  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (no_neighbor_port): New command added. +	(peer_new): Set send_community. + +1999-12-04  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (show_ip_bgp_summary): Changed to use bgp_show_summary(). +	(show_ip_mbgp_summary): Likewise. +	(show_ipv6_bgp_summary): Likewise. +	(show_ipv6_mbgp_summary): Add new command. +	(peer_free): Free peer->host. +	(peer_lookup_by_su): Delete function. +	(ipv6_bgp_neighbor): Changed to use peer_remote_as(). +	(sockunion_vty_out): Function deleted. +	(vty_clear_bgp): Use afi instead of family. +	Delete old list bgp_list.  Use struct newlist *bgplist. +	(peer_lookup_by_host): Function deleted. + +1999-12-03  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.h (struct peer_group): New structure added. +	(struct peer_conf): New structure added. +	(struct	peer): Change all prefix_count to unsigned long. +	 +	* bgpd.c: Reconstruct all of VTY commands reflect internal +	structure change. +	Use bgplist instead of bgp_list. +	Use peerlist intstead of peer_list. + +	* bgp_attr.c (bgp_mp_reach_parse): If nlri_parse return -1, stop +	parsing then return immediately. + +	* bgp_route.c (nlri_parse): When NLRI parse error occured, return +	-1. +	(nlri_process): Use pcount_v4_{unicast,multicast}. +	(nlri_delete): Likewise. + +1999-11-25  Robert Olsson <Robert.Olsson@data.slu.se> + +	* bgp_routemap.c (route_match_nlri): `match nlri +	unicast|multicast' and `set nlri unicast|multicast' command are +	added. + +1999-11-22  Robert Olsson <Robert.Olsson@data.slu.se> + +	* bgpd.c: Add translate-update support. + +	* bgpd.h (TRANSLATE_UPDATE_OFF): Add translate-update definition. + +1999-11-19  Robert.Olsson@data.slu.se + +	* bgp_route.c (bgp_peer_delete): Add MBGP peer clear codes. + +1999-11-14  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_open.c (bgp_capability_mp): Temporary comment out +	SAFI_UNICAST_MULTICAST handling until we know the meanings. + +1999-11-13  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_btoa.c: New file added. + +1999-11-12  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.h (struct peer): Add dont_capability flag. +	(struct peer): Add override_capability flag. + +	* bgpd.c (neighbor_dont_capability_negotiation): `neighbor PEER +	dont-capability-negotiation' added. + +1999-11-12  Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us> + +	* bgp_attr.c (bgp_mp_reach_parse): Ignore link-local addresses +	attribute from non-shared-network peers. + +1999-11-10  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_snmp.c: New file added. + +	* BGP4-MIB.txt: Updated to the latest Internet-Draft +	draft-ietf-idr-bgp4-mib-04.txt. + +1999-11-09  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_route_init): Add `show ipv6 bgp prefix-list'. + +	* bgp_attr.c (bgp_mp_unreach_parse): Enclose safi setup with +	#ifdef HAVE_MBGPV4. + +1999-11-08  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_dump.c (no_dump_bgp_all): Add [PATH] and [INTERVAL] to no +	dump bgp commands. +	(config_write_bgp_dump): Write interval value to the +	configuration. + +1999-11-07  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_zebra.c: Redistribute route-map support is added. + +	* bgp_zebra.h: New file added. + +1999-11-04  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_dump.c: BGP packet dump routine compatible with MRT. +	* bgp_dump.h: BGP packet dump routine compatible with MRT. + +	* bgp_debug.c: Renamed from bgp_dump.c +	* bgp_debug.h: Renamed from bgp_dump.h + +1999-10-27  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* BGP4-MIB.txt: New file added.  Edited version of RFC1657. + +1999-10-25  Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us> + +	* bgp_route.c (bgp_announce): If we're not on a shared network +	with the peer and we don't have a link-local next hop, but the +	inbound next-hop has a link-local address, don't readvertise it to +	our peer. + +1999-10-25  Marc Boucher <marc@mbsi.ca> + +	* bgp_zebra.c: Add redistribute kernel command. + +1999-10-25  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_reset): New function added. + +	* bgpd.conf.sample2: Add IPv6 configuration sample. + +1999-10-24  Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us> + +	* bgp_route.c (ipv6_aggregate_address): Function added. + +1999-10-21  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_packet.c (bgp_update): Unintern aspath, community, cluster +	list after parsing BGP update packet. + +	* bgp_attr.c (bgp_attr_aspath): Intern parsed aspath. +	(bgp_attr_community): Intern parsed community. +	(bgp_attr_cluster_list): Intern parsed cluster list. + +	* bgp_routemap.c: Add `set community-additive' command. + +1999-10-21  Alexandr D. Kanevskiy <kad@blackcatlinux.com> + +	* bgp_routemap.c (route_set_local_pref): Fix bug of setting +	attribute flag. + +1999-10-21  Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us> + +	* bgp_route.c (bgp_announce): Add check of IPv6 default route +	announcement. + +	* bgp_packet.c (bgp_update_send): Add BGP announcement logging. + +1999-10-15  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* `show ip[v6] bgp PREFIX' show uptime of the route. + +1999-10-04  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_filter_set): Delete PEER_FAMILY_{IPV4,IPV6}. instead +	of that use AF_INET and AF_INET6 directly. +	(vty_clear_bgp): Add new function to support various clear ip bgp +	method. + +1999-10-04  Lars Fenneberg <lf@elemental.net> + +	* bgpd.c (clear_ip_bgp): Add `clear ip bgp ASN'. + +1999-10-03  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c: Add `match ip prefix-list' and `match ipv6 +	prefix-list'. + +1999-09-28  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_collision_detect): Add BGP collision detection +	function. + +1999-09-26  Blake Meike <bmeike@adero.com> + +	* bgpd.c (neighbor_port): New command `neighbor PEER port PORT' is +	added. + +1999-08-24  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (no_neighbor_timers_keepalive): Change MIN to min.  Add +	min() macro. + +1999-08-19  Rick Payne <rickp@rossfell.co.uk> + +	* bgp_packet.c (bgp_open): BGP holdtimer bug is fixed.  Make BGP +	keepalive timer configurable. + +1999-08-15  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_zebra.c (bgp_redistribute_set): Fix redistribute bug. + +1999-08-13  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_peer_display): show ip bgp neighbors PEER only list +	the peer not all of them. + +1999-08-11  Rick Payne <rickp@rossfell.co.uk> + +	* bgp_route.c (bgp_announce): Remove MED if its an EBGP peer - +	will get overwritten by route-maps. + +1999-08-08  Rick Payne <rickp@rossfell.co.uk> + +	* bgp_routemap.c: Multi protocol route-map modification. + +1999-08-01  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c: Set network statement route's origin attribute as +	igp. + +	* bgp_zebra.c: Set redistribute route's origin attribute as +	incomplete. + +	* bgp_route.c (bgp_info_cmp): Add attribute existance check, +	origin attribute check, BGP peer type check. + +1999-07-30  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_peer_delete): Reselect of IPv6 route. + +1999-07-29  Rick Payne <rickp@rossfell.co.uk> + +	* Changed route-maps to behave in a more cisco-like fashion + +1999-07-27  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_fsm.c (bgp_stop): Very serious bug of bgp_stop () is fixed. +	When multiple route to the same destination exist, bgpd try to +	announce the information to stopped peer.  Then add orphan write +	thread is added.  This cause many strange behavior of bgpd. +	Reported by Georg Hitsch <georg@atnet.at>. + +1999-07-23  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c: Change peer's A.B.C.D to PEER. + +1999-07-22  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_announce): Add hack for link-local nexthop. + +	* bgp_zebra.c (bgp_zebra_announce): Fill in nexthop address from +	local address. + +1999-07-21  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_packet.c (bgp_open): Holdtime fetch bug is fixed.  Reported +	by Yuji SEKIYA <sekiya@sfc.wide.ad.jp>. + +1999-07-15  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_fsm.c (fsm_holdtime): Don't close file descriptor in +	fsm_holdtime (). + +1999-07-11  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c: Add `set atomic-aggregate' command. + +1999-07-06  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c (route_set_ip_nexthop_cmd): Change "ip nexthop" +	to "ip next-hop". +	 +1999-07-02  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (show_ipv6_bgp_regexp): `show ipv6 bgp regexp' +	added. + +1999-07-01  Rick Payne <rickp@rossfell.co.uk> + +	* bgp_zebra.c (zebra_init): Install standard commands to +	ZEBRA_NODE. + +1999-06-28  Rick Payne <rickp@rossfell.co.uk> + +	* bgpd.c (bgp_delete): bgp peer deletion bug is fixed. + +1999-06-25  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c: Add neighbor update-source command as ALIAS to +	neighbor_interface. + +1999-06-19  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.c (bgp_packet_attribute): Send community attribute when +	send_community flag is set. + +	* bgpd.h (struct peer): Add send_community flag. + +1999-06-12  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (router_bgp): router bgp's argument changed from AS_NO to +	<1-65535>. + +1999-06-08  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.h (struct bgp_info): Add subtype for BGP route type. + +1999-06-07  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_community.c (community_merge): Function added. + +1999-06-04  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_clist.c: New file. +	* bgp_clist.h: New file. + +	* bgp_community.h (COMMUNITY_LOCAL_AS): Added for Cisco +	compatibility. +	(COMMUNITY_NO_ADVERTISE): Fix typo. + +1999-05-30  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c: Add `set weight WEIGHT' command. + +	* bgpd.c: Remove all_digit_check function.  Instead of that use +	all_digit function in lib/prefix.c. + +	* bgp_routemap.c (bgp_route_map_init): Install +	no_set_ipv6_nexthop_global_cmd and no_set_ipv6_nexthop_local_cmd +	element to the RMAP_NODE. + +1999-05-28  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c (aspath_make_str): Declare aspath_delimiter_char +	inside aspath_make_str function. +	(aspath_prepend): New function is added for AS path prepend. +	(aspath_make_str_count): Renamed from aspath_make_str.  AS path +	count is set to the structure. +	(aspath_merge): New function. + +1999-05-22  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_zebra.c (redistribute_bgp): Add new DEFUN. +	(no_redistribute_bgp): Likewise. +	(router_zebra): Semantics changed.  Now 'router zebra' is default +	behavior of bgpd. + +1999-05-14  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c: Add some commands to bgp route-map. +	match ip next-hop: New command. +	match metric: New command. +	set metric: Doc fix. +	set local-preference: Add DEFUN. + +1999-05-14  Stephen R. van den Berg <srb@cuci.nl> + +	* bgp_main.c (signal_init): SIGTERM call sigint. +	(sigint): Loggging more better message. + +1999-05-12  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.c (bgp_packet_attribute): AS path attribute extended +	length bit check is added. + +1999-05-11  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c (bgp_route_map_init): Call route_map_install_set +	function with route_set_local_pref_cmd argument. +	(no_match_aspath): Function added. +	(route_set_metric): Set attribute flag bit. + +	* bgp_attr.c (bgp_packet_attribute): MULTI_EXIT_DISC is now in BGP +	packet. + +1999-05-07  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (no_neighbor_timers_holdtime): `no neighbor PEER timers +	holdtime' command is added. + +	* bgpd.h (BGP_DEFAULT_HOLDTIME_BIG): Delete define. + +	* bgpd.c (bgp_prefix_list_set): New function added. +	(bgp_prefix_list_unset): Likewise. +	(bgp_prefix_list_update): Likewise. +	(show_ip_bgp_neighbors): prefix-list information display. + +1999-05-06  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_delete): Function added for `no router bgp'. + +1999-05-05  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_dump.c (bgp_dump_attr): Add originator_id display. + +	* bgpd.c (bgp_router_id): Even when address is malformed set the +	value to configuration bug fixed. +	(no_bgp_router_id): New function. +	(no_bgp_cluster_id): New function. + +1999-05-04  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.h (BGP_ATTR_ORIGINATOR_ID): Changed from BGP_ATTR_ORIGINATOR. + +1999-05-02  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (bgp_announce): Add route reflector check. + +1999-05-01  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_cluster_id): Add function for route reflector. +	(neighbor_route_reflector_client): Likewise. +	(no_neighbor_route_reflector_client): Likewise. + +	* bgpd.h (struct bgp ): Add cluster for route reflector. + +	* bgp_route.c (show_ip_bgp_prefix_list): New command is added. + +1999-04-24  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* Makefile.am (noinst_HEADERS): Add bgp_filter.h + +	* bgp_aspath.c (aspath_undup): Function deleted.  aspath_free () +	has same functionality. + +	* bgp_filter.h: New file. + +	* bgp_aspath.c (aspath_unintern): Rename aspath_free () to +	aspath_unintern () +	(aspath_free): New function. + +1999-04-23  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c (aspath_aggregate): Function added. + +	* bgp_aspath.h (aspath_aggregate): Prototype added. + +	* bgp_aspath.c (aspath_empty_aspath): New argument +	gated_dont_eat_flag is added. + +1999-04-18  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c: Add bgp_aggregate_ipv4 and bgp_aggregate_ipv6. + +1999-04-17  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c (aggregate_address): Function added. + +	* bgp_zebra.c (zebra_read): Change log to zlog. + +1999-04-15  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* Makefile.am (noninst_HEADERS): Added for make dist. + +1999-04-09  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* aspath_regex.c: Removed from distribution. + +1999-04-07  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.c (bgp_packet_attribute): Old draft-00 packet treatment +	bug fixed. + +1999-04-06  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c (aspath_add_left): Fix empty aspath bug.  Reported +	by kad@gibson.skif.net. + +	* bgp_regex.[ch]: New file added. + +	 +1999-04-05  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_filter.c: New file added. + +1999-04-01  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c (aspath_empty_aspath): Change for peering with +	gated. + +1999-03-24  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_main.c (main): Default loggin method changed from syslog to +	stdout. + +1999-03-05  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c: Delete obsolete default attribute DEFUN. + +1999-03-04  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.c: Make attribute structure put into attribute hash. + +1999-03-02  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_view.c : Delete file. + +1999-02-25  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_routemap.c (bgp_apply_route_map): Add prefix argument.  + +	* bgp_route.h (struct bgp_info): Add bgp_info structre.  I'll +	replace bgp_route with this. + +	* bgp_routemap.c (route_match_ip_address): Fix bug of passing non +	prefix value to access_list_apply().  + +	* bgpd.conf.sample: Add route-map sample. +	Delete obsolete default-attr statements. + +	* bgp_packet.c: Use stream_fifo for packet queueing. + +1999-02-24  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c (aspath_add_left): add non empty aspath treatment. + +	* bgp_main.c: include unistd.h for daemon(). + +	* bgp_route.c (nlri_process): add IPv6 table lookup. + +	* bgp_attr.c (route_parse_ipv6): call nlri_process(). +	(attr_make): Obsolete function attr_make deleted. + +1999-02-22  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c (aspath_add_left): change function name from +	aspath_add_leftmost_as(). + +1999-02-21  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c: add aspath_add_leftmost_as (). + +1999-02-18  Peter Galbavy  <Peter.Galbavy@knowledge.com> + +	* syslog support added + +1999-01-26  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c: DEFUN (neighbor_nexthop): deleted. +	DEFUN (neighbor_distribute_list): added. + +1999-01-19  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.h (struct peer ): header_buf and read_buf is removed. + +	* bgp_peer.[ch]: Deleted.  Peer related functions are merged to +	bgpd.c + +	* bgp_network.c: New file. +	* bgp_network.h: New file. + +	* bgp_packet.h: New file. +	 +1999-01-11  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_packet.c (bgp_keepalive_send): Now BGP keepalive packet is +	buffered. + +1999-01-08  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_packet.c: New file. + +1998-12-22  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_zebra.c (zebra_client): Use zebra_connect() in lib/client.c.  + +	* `show ip bgp' bug fixed. +	* aspath_log (): Remove argument logfp. + +1998-12-15  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_fsm.h: New file. + +1998-12-15  Magnus Ahltorp <map@stacken.kth.se> + +	* bgp_attr.c, bgp_community.h, bgp_dump.c, bgp_fsm.c, bgp_open.c +	bgp_peer.c, bgp_peer.h, bgp_route.c, bgp_route.h, bgp_view.c +	bgpd.c, bgpd.h, bgp_attr.c, bgp_community.h, bgp_dump.c, +	bgp_fsm.c, bgp_open.c, bgp_peer.c, bgp_peer.h: Prototype fixes. + +1998-12-09  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (bgp_config_write): Delete vector v argument. + +1998-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.h: Delete annoying ld_[124]byte and st_[124]byte macros. + +1998-11-23  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_radix.[ch]: removed. + +1998-09-15  HEO SeonMeyong  <seirios@matrix.iri.co.jp> + +	* bgp_main.c: ifdef HYDRANGEA -> ifdef KAME + +1998-08-13  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_dump.c: delete nroute(). + +1998-05-19  Yamshita TAKAO  <jargon@lares.dti.ne.jp> + +	* bgp_aspath.c: HAVE_CONFIG_H typo :-) +	* bgpd.h: Modify for compile on Solaris. +	* bgp_aspath.h: likewize +	* bgp_community.h: likewize +	* bgp_routemap.c: likewize + +1998-05-18  Yamshita TAKAO  <jargon@lares.dti.ne.jp> + +	* bgpd.h: Modify for compile on Solaris. +	* bgp_aspath.h: likewize + +1998-05-08  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* routemap.[ch]: move to ../lib directory. + +1998-05-07  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* routemap.c (route_map_apply): add function. + +1998-05-06  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* routemap.h: add file. + +	* bgp_peer.h (enum ): change PEER_{IBGP,EBGP} to BGP_PEER_{IBGP,EBGP} + +1998-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* Makefile.am: sysconfdir_DATA added. + +1998-05-02  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_dump.c: add `debug bgp fsm' +		      add `no debug bgp fsm' +		      add `show debug bgp' +	* bgp_open.c: File added. + +1998-05-01  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* .cvsignore: File added. + +1998-04-30  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_community.[ch]: File added. + +1998-03-04  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd now use lib/thread.[ch]. + +1998-01-06  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.c (show_ip_bgp_neighbors): add 'show ip bgp neighbors' command. + +	* bgpd.h (BGP_DEFAULT_START_TIMER): change from 1 to 30. + +1997-12-30  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_vty.c: bgp_vty.c deleted. + +	* bgpd.c (config_write_neighbor): add ebgp-multihop command. + +1997-12-29  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_fsm.c: [-p bgp_port] and [-P vty_port] works + +1997-12-06  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_vty.c: new file. + +	* bgp_attr.c: add new logging system. + +1997-11-23  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* Change all inet_addr call into inet_aton. + +1997-11-10  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_radix.c: change radix_peer_delete + +1997-10-04  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c: move AS_TOKEN_??? definition from header to c source. + +1997-09-12  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_dump.c (bgp_log_route): add dump_attr function + +1997-09-06  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c (aspath_test): change AS_SET brace from '[' to '{' +	* bgp_dump.c (bgp_log_route): change logfile format. + +1997-08-19  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_open.c (bgp_open): move bgp_open function from bgpd.c +	* bgp_attr.c (community_str2com): add community value generation +	* bgp_attr.h: add SAFI definition for BGP-4+ + +1997-08-18  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgpd.h: add BGP_OPEN_OPT_CAP for Capabilities Optional Parameter +	* Makefile.in: add bgp_open.o, delete bgp_loop.o +	* bgp_open.c: newfile which manages BGP Open message +	* bgp_loop.c: this file is merged with bgp_fsm.c +	* bgp_radix.c (radix_add): radix_add() now return route_t instead +	of int +	(bgp_sim): now we can read update & withdraw from file +	* bgp_route.c: add route_free() call into route_parse etc. + +1997-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_radix.c: Radix code is completely rewritten. It has better +	memory treatment than old one. + +1997-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_route.c: route_alloc for route struct allocation statistics. +	* bgpd.c (bgp_make_update): now we cann announce MED attribute. +	* bgp_aspath.c (aspath_print_all): change aspath_print_all output +	format. + +1997-08-13  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_term.c (term_parse): add command : show asstat, show ashash +	* bgp_aspath.c: aspath_cmp bug fix +	(aspath_print_all): add aspath_print_all (); +	* bgp_peer.h: delete rlist element from struct peer. + +1997-08-12  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c: completely rewritten. +	* bgp_aspath.h: completely rewritten. +	add AsPath, AsSegment structure +	add AS_SET treatment +	change Hash codes + +1997-08-09  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_attr.h: add Attribute flags defines +	* bgp_route.c: delete rlist related functions +	* bgp_aspath.c (as_origin): add as_origin function +	(aspath_print): move from bgp_dump.c and add support of AS_SET +	change Hash related function names. + +1997-08-08  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.h: add next entry, delete rlist entry from struct aspath + +1997-08-04  Kunihiro Ishiguro  <kunihiro@zebra.org> + +	* bgp_aspath.c (as_sort): add function as_sort +	* bgp_aspath.h: add IBGP, EBGP + diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am new file mode 100644 index 0000000000..7f739f6e3f --- /dev/null +++ b/bgpd/Makefile.am @@ -0,0 +1,44 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +noinst_LIBRARIES = libbgp.a +sbin_PROGRAMS = bgpd + +libbgp_a_SOURCES = \ +	bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ +	bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ +	bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ +	bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ +	bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c + +noinst_HEADERS = \ +	bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ +	bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \ +	bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ +	bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ +	bgp_advertise.h bgp_snmp.h bgp_vty.h + +bgpd_SOURCES = \ +	bgp_main.c $(libbgp_a_SOURCES) + +bgpd_LDADD = ../lib/libzebra.a + +sysconf_DATA = bgpd.conf.sample bgpd.conf.sample2 + +EXTRA_DIST = $(sysconf_DATA) BGP4-MIB.txt + +install-sysconfDATA: $(sysconf_DATA) +	@$(NORMAL_INSTALL) +	$(mkinstalldirs) $(DESTDIR)$(sysconfdir) +	@list='$(sysconf_DATA)'; for p in $$list; do \ +	  if test -f $(srcdir)/$$p; then \ +	    echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ +	    $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ +	  else if test -f $$p; then \ +	    echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ +	    $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ +	  fi; fi; \ +	done diff --git a/bgpd/Makefile.in b/bgpd/Makefile.in new file mode 100644 index 0000000000..06c51892b3 --- /dev/null +++ b/bgpd/Makefile.in @@ -0,0 +1,534 @@ +# Makefile.in generated by automake 1.7 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_triplet = @host@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURSES = @CURSES@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LDFLAGS = @LDFLAGS@ +LIBPAM = @LIBPAM@ +LIBS = @LIBS@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OBJEXT = @OBJEXT@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +INSTALL_SDATA = @INSTALL@ -m 600 + +noinst_LIBRARIES = libbgp.a +sbin_PROGRAMS = bgpd + +libbgp_a_SOURCES = \ +	bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ +	bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ +	bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ +	bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ +	bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c + + +noinst_HEADERS = \ +	bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ +	bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \ +	bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ +	bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ +	bgp_advertise.h bgp_snmp.h bgp_vty.h + + +bgpd_SOURCES = \ +	bgp_main.c $(libbgp_a_SOURCES) + + +bgpd_LDADD = ../lib/libzebra.a + +sysconf_DATA = bgpd.conf.sample bgpd.conf.sample2 + +EXTRA_DIST = $(sysconf_DATA) BGP4-MIB.txt +subdir = bgpd +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libbgp_a_AR = $(AR) cru +libbgp_a_LIBADD = +am_libbgp_a_OBJECTS = bgpd.$(OBJEXT) bgp_fsm.$(OBJEXT) \ +	bgp_aspath.$(OBJEXT) bgp_community.$(OBJEXT) bgp_attr.$(OBJEXT) \ +	bgp_debug.$(OBJEXT) bgp_route.$(OBJEXT) bgp_zebra.$(OBJEXT) \ +	bgp_open.$(OBJEXT) bgp_routemap.$(OBJEXT) bgp_packet.$(OBJEXT) \ +	bgp_network.$(OBJEXT) bgp_filter.$(OBJEXT) bgp_regex.$(OBJEXT) \ +	bgp_clist.$(OBJEXT) bgp_dump.$(OBJEXT) bgp_snmp.$(OBJEXT) \ +	bgp_ecommunity.$(OBJEXT) bgp_mplsvpn.$(OBJEXT) \ +	bgp_nexthop.$(OBJEXT) bgp_damp.$(OBJEXT) bgp_table.$(OBJEXT) \ +	bgp_advertise.$(OBJEXT) bgp_vty.$(OBJEXT) +libbgp_a_OBJECTS = $(am_libbgp_a_OBJECTS) +sbin_PROGRAMS = bgpd$(EXEEXT) +PROGRAMS = $(sbin_PROGRAMS) + +am__objects_1 = bgpd.$(OBJEXT) bgp_fsm.$(OBJEXT) bgp_aspath.$(OBJEXT) \ +	bgp_community.$(OBJEXT) bgp_attr.$(OBJEXT) bgp_debug.$(OBJEXT) \ +	bgp_route.$(OBJEXT) bgp_zebra.$(OBJEXT) bgp_open.$(OBJEXT) \ +	bgp_routemap.$(OBJEXT) bgp_packet.$(OBJEXT) \ +	bgp_network.$(OBJEXT) bgp_filter.$(OBJEXT) bgp_regex.$(OBJEXT) \ +	bgp_clist.$(OBJEXT) bgp_dump.$(OBJEXT) bgp_snmp.$(OBJEXT) \ +	bgp_ecommunity.$(OBJEXT) bgp_mplsvpn.$(OBJEXT) \ +	bgp_nexthop.$(OBJEXT) bgp_damp.$(OBJEXT) bgp_table.$(OBJEXT) \ +	bgp_advertise.$(OBJEXT) bgp_vty.$(OBJEXT) +am_bgpd_OBJECTS = bgp_main.$(OBJEXT) $(am__objects_1) +bgpd_OBJECTS = $(am_bgpd_OBJECTS) +bgpd_DEPENDENCIES = ../lib/libzebra.a +bgpd_LDFLAGS = + +DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/bgp_advertise.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_aspath.Po ./$(DEPDIR)/bgp_attr.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_clist.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_community.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_damp.Po ./$(DEPDIR)/bgp_debug.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_dump.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_ecommunity.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_filter.Po ./$(DEPDIR)/bgp_fsm.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_main.Po ./$(DEPDIR)/bgp_mplsvpn.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_network.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_nexthop.Po ./$(DEPDIR)/bgp_open.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_packet.Po ./$(DEPDIR)/bgp_regex.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_route.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_routemap.Po ./$(DEPDIR)/bgp_snmp.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_table.Po ./$(DEPDIR)/bgp_vty.Po \ +@AMDEP_TRUE@	./$(DEPDIR)/bgp_zebra.Po ./$(DEPDIR)/bgpd.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ +	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libbgp_a_SOURCES) $(bgpd_SOURCES) +DATA = $(sysconf_DATA) + +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in +SOURCES = $(libbgp_a_SOURCES) $(bgpd_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4) +	cd $(top_srcdir) && \ +	  $(AUTOMAKE) --foreign  bgpd/Makefile +Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status +	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: +	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libbgp.a: $(libbgp_a_OBJECTS) $(libbgp_a_DEPENDENCIES)  +	-rm -f libbgp.a +	$(libbgp_a_AR) libbgp.a $(libbgp_a_OBJECTS) $(libbgp_a_LIBADD) +	$(RANLIB) libbgp.a +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-sbinPROGRAMS: $(sbin_PROGRAMS) +	@$(NORMAL_INSTALL) +	$(mkinstalldirs) $(DESTDIR)$(sbindir) +	@list='$(sbin_PROGRAMS)'; for p in $$list; do \ +	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ +	  if test -f $$p \ +	  ; then \ +	    f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ +	   echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \ +	   $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \ +	  else :; fi; \ +	done + +uninstall-sbinPROGRAMS: +	@$(NORMAL_UNINSTALL) +	@list='$(sbin_PROGRAMS)'; for p in $$list; do \ +	  f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ +	  echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ +	  rm -f $(DESTDIR)$(sbindir)/$$f; \ +	done + +clean-sbinPROGRAMS: +	-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +bgpd$(EXEEXT): $(bgpd_OBJECTS) $(bgpd_DEPENDENCIES)  +	@rm -f bgpd$(EXEEXT) +	$(LINK) $(bgpd_LDFLAGS) $(bgpd_OBJECTS) $(bgpd_LDADD) $(LIBS) + +mostlyclean-compile: +	-rm -f *.$(OBJEXT) core *.core + +distclean-compile: +	-rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_advertise.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_aspath.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_attr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_clist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_community.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_damp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_debug.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_dump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_ecommunity.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_filter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_fsm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_mplsvpn.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_network.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_nexthop.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_open.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_packet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_regex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_route.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_routemap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_snmp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_table.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_vty.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_zebra.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgpd.Po@am__quote@ + +distclean-depend: +	-rm -rf ./$(DEPDIR) + +.c.o: +@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@	  -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCC_TRUE@	then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@	else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@	fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@	$(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@	  -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \ +@am__fastdepCC_TRUE@	then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@	else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@	fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@	$(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'` +uninstall-info-am: +sysconfDATA_INSTALL = $(INSTALL_DATA) + +uninstall-sysconfDATA: +	@$(NORMAL_UNINSTALL) +	@list='$(sysconf_DATA)'; for p in $$list; do \ +	  f="`echo $$p | sed -e 's|^.*/||'`"; \ +	  echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \ +	  rm -f $(DESTDIR)$(sysconfdir)/$$f; \ +	done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) +	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ +	unique=`for i in $$list; do \ +	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ +	  done | \ +	  $(AWK) '    { files[$$0] = 1; } \ +	       END { for (i in files) print i; }'`; \ +	mkid -fID $$unique + +TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \ +		$(TAGS_FILES) $(LISP) +	tags=; \ +	here=`pwd`; \ +	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \ +	unique=`for i in $$list; do \ +	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ +	  done | \ +	  $(AWK) '    { files[$$0] = 1; } \ +	       END { for (i in files) print i; }'`; \ +	test -z "$(ETAGS_ARGS)$$tags$$unique" \ +	  || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ +	     $$tags $$unique + +ctags: CTAGS +CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \ +		$(TAGS_FILES) $(LISP) +	tags=; \ +	here=`pwd`; \ +	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \ +	unique=`for i in $$list; do \ +	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ +	  done | \ +	  $(AWK) '    { files[$$0] = 1; } \ +	       END { for (i in files) print i; }'`; \ +	test -z "$(CTAGS_ARGS)$$tags$$unique" \ +	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ +	     $$tags $$unique + +GTAGS: +	here=`$(am__cd) $(top_builddir) && pwd` \ +	  && cd $(top_srcdir) \ +	  && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: +	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) +	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ +	list='$(DISTFILES)'; for file in $$list; do \ +	  case $$file in \ +	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ +	  esac; \ +	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ +	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ +	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \ +	    dir="/$$dir"; \ +	    $(mkinstalldirs) "$(distdir)$$dir"; \ +	  else \ +	    dir=''; \ +	  fi; \ +	  if test -d $$d/$$file; then \ +	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ +	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ +	    fi; \ +	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ +	  else \ +	    test -f $(distdir)/$$file \ +	    || cp -p $$d/$$file $(distdir)/$$file \ +	    || exit 1; \ +	  fi; \ +	done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) + +installdirs: +	$(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am +	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: +	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ +	  INSTALL_STRIP_FLAG=-s \ +	  `test -z '$(STRIP)' || \ +	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: +	-rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: +	@echo "This command is intended for maintainers to use" +	@echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-sbinPROGRAMS \ +	mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ +	distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-sbinPROGRAMS install-sysconfDATA + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \ +	uninstall-sysconfDATA + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ +	clean-noinstLIBRARIES clean-sbinPROGRAMS ctags distclean \ +	distclean-compile distclean-depend distclean-generic \ +	distclean-tags distdir dvi dvi-am info info-am install \ +	install-am install-data install-data-am install-exec \ +	install-exec-am install-info install-info-am install-man \ +	install-sbinPROGRAMS install-strip install-sysconfDATA \ +	installcheck installcheck-am installdirs maintainer-clean \ +	maintainer-clean-generic mostlyclean mostlyclean-compile \ +	mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ +	uninstall-am uninstall-info-am uninstall-sbinPROGRAMS \ +	uninstall-sysconfDATA + + +install-sysconfDATA: $(sysconf_DATA) +	@$(NORMAL_INSTALL) +	$(mkinstalldirs) $(DESTDIR)$(sysconfdir) +	@list='$(sysconf_DATA)'; for p in $$list; do \ +	  if test -f $(srcdir)/$$p; then \ +	    echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ +	    $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ +	  else if test -f $$p; then \ +	    echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ +	    $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ +	  fi; fi; \ +	done +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c new file mode 100644 index 0000000000..4778a9773d --- /dev/null +++ b/bgpd/bgp_advertise.c @@ -0,0 +1,405 @@ +/* BGP advertisement and adjacency +   Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "command.h" +#include "memory.h" +#include "prefix.h" +#include "hash.h" +#include "thread.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_advertise.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_mplsvpn.h" + +/* BGP advertise attribute is used for pack same attribute update into +   one packet.  To do that we maintain attribute hash in struct +   peer.  */ +static struct bgp_advertise_attr * +baa_new () +{ +  return (struct bgp_advertise_attr *) +    XCALLOC (MTYPE_BGP_ADVERTISE_ATTR, sizeof (struct bgp_advertise_attr)); +} + +static void +baa_free (struct bgp_advertise_attr *baa) +{ +  XFREE (MTYPE_BGP_ADVERTISE_ATTR, baa); +} + +static void * +baa_hash_alloc (struct bgp_advertise_attr *ref) +{ +  struct bgp_advertise_attr *baa; + +  baa = baa_new (); +  baa->attr = ref->attr; +  return baa; +} + +static unsigned int +baa_hash_key (struct bgp_advertise_attr *baa) +{ +  return attrhash_key_make (baa->attr); +} + +static int +baa_hash_cmp (struct bgp_advertise_attr *baa1, struct bgp_advertise_attr *baa2) +{ +  return attrhash_cmp (baa1->attr, baa2->attr); +} + +/* BGP update and withdraw information is stored in BGP advertise +   structure.  This structure is referred from BGP adjacency +   information.  */ +static struct bgp_advertise * +bgp_advertise_new () +{ +  return (struct bgp_advertise *)  +    XCALLOC (MTYPE_BGP_ADVERTISE, sizeof (struct bgp_advertise)); +} + +void +bgp_advertise_free (struct bgp_advertise *adv) +{ +  XFREE (MTYPE_BGP_ADVERTISE, adv); +} + +void +bgp_advertise_add (struct bgp_advertise_attr *baa, +		   struct bgp_advertise *adv) +{ +  adv->next = baa->adv; +  if (baa->adv) +    baa->adv->prev = adv; +  baa->adv = adv; +} + +void +bgp_advertise_delete (struct bgp_advertise_attr *baa, +		      struct bgp_advertise *adv) +{ +  if (adv->next) +    adv->next->prev = adv->prev; +  if (adv->prev) +    adv->prev->next = adv->next; +  else +    baa->adv = adv->next; +} + +static struct bgp_advertise_attr * +bgp_advertise_intern (struct hash *hash, struct attr *attr) +{ +  struct bgp_advertise_attr ref; +  struct bgp_advertise_attr *baa; + +  ref.attr = bgp_attr_intern (attr); +  baa = (struct bgp_advertise_attr *) hash_get (hash, &ref, baa_hash_alloc); +  baa->refcnt++; + +  return baa; +} + +void +bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa) +{ +  if (baa->refcnt) +    baa->refcnt--; + +  if (baa->refcnt && baa->attr) +    bgp_attr_unintern (baa->attr); +  else +    { +      if (baa->attr) +	{ +	  hash_release (hash, baa); +	  bgp_attr_unintern (baa->attr); +	} +      baa_free (baa); +    } +} + +/* BGP adjacency keeps minimal advertisement information.  */ +void +bgp_adj_out_free (struct bgp_adj_out *adj) +{ +  XFREE (MTYPE_BGP_ADJ_OUT, adj); +} + +int +bgp_adj_out_lookup (struct peer *peer, struct prefix *p, +		    afi_t afi, safi_t safi, struct bgp_node *rn) +{ +  struct bgp_adj_out *adj; + +  for (adj = rn->adj_out; adj; adj = adj->next) +    if (adj->peer == peer) +      break; + +  if (! adj) +    return 0; + +  return (adj->adv  +	  ? (adj->adv->baa ? 1 : 0) +	  : (adj->attr ? 1 : 0)); +} + +struct bgp_advertise * +bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj, +		     afi_t afi, safi_t safi) +{ +  struct bgp_advertise *adv; +  struct bgp_advertise_attr *baa; +  struct bgp_advertise *next; + +  adv = adj->adv; +  baa = adv->baa; +  next = NULL; + +  if (baa) +    { +      /* Unlink myself from advertise attribute FIFO.  */ +      bgp_advertise_delete (baa, adv); + +      /* Fetch next advertise candidate. */ +      next = baa->adv; + +      /* Unintern BGP advertise attribute.  */ +      bgp_advertise_unintern (peer->hash[afi][safi], baa); +      adv->baa = NULL; +      adv->rn = NULL; +    } + +  /* Unlink myself from advertisement FIFO.  */ +  FIFO_DEL (adv); + +  /* Free memory.  */ +  bgp_advertise_free (adj->adv); +  adj->adv = NULL; + +  return next; +} + +void +bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p, +		 struct attr *attr, afi_t afi, safi_t safi, +		 struct bgp_info *binfo) +{ +  struct bgp_adj_out *adj = NULL; +  struct bgp_advertise *adv; + +#ifdef DISABLE_BGP_ANNOUNCE +  return; +#endif /* DISABLE_BGP_ANNOUNCE */ + +  /* Look for adjacency information. */ +  if (rn) +    { +      for (adj = rn->adj_out; adj; adj = adj->next) +	if (adj->peer == peer) +	  break; +    } + +  if (! adj) +    { +      adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out)); + +      if (rn) +        { +          BGP_ADJ_OUT_ADD (rn, adj); +          bgp_lock_node (rn); +        } +    } + +  if (adj->adv) +    bgp_advertise_clean (peer, adj, afi, safi); + +  adj->peer = peer; +  adj->adv = bgp_advertise_new (); + +  adv = adj->adv; +  adv->rn = rn; +  adv->binfo = binfo; +  if (attr) +    adv->baa = bgp_advertise_intern (peer->hash[afi][safi], attr); +  else +    adv->baa = baa_new (); +  adv->adj = adj; + +  /* Add new advertisement to advertisement attribute list. */ +  bgp_advertise_add (adv->baa, adv); + +  FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo); +} + +void +bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p,  +		   afi_t afi, safi_t safi) +{ +  struct bgp_adj_out *adj; +  struct bgp_advertise *adv; + +#ifdef DISABLE_BGP_ANNOUNCE +  return; +#endif /* DISABLE_BGP_ANNOUNCE */ + +  /* Lookup existing adjacency, if it is not there return immediately.  */ +  for (adj = rn->adj_out; adj; adj = adj->next) +    if (adj->peer == peer) +      break; + +  if (! adj) +    return; + +  /* Clearn up previous advertisement.  */ +  if (adj->adv) +    bgp_advertise_clean (peer, adj, afi, safi); + +  if (adj->attr) +    { +      /* We need advertisement structure.  */ +      adj->adv = bgp_advertise_new (); +      adv = adj->adv; +      adv->rn = rn; +      adv->adj = adj; + +      /* Add to synchronization entry for withdraw announcement.  */ +      FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo); + +      /* Schedule packet write. */ +      BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +    } +  else +    { +      /* Remove myself from adjacency. */ +      BGP_ADJ_OUT_DEL (rn, adj); +       +      /* Free allocated information.  */ +      bgp_adj_out_free (adj); + +      bgp_unlock_node (rn); +    } +} + +void +bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj,  +		    struct peer *peer, afi_t afi, safi_t safi) +{ +  if (adj->attr) +    bgp_attr_unintern (adj->attr); + +  if (adj->adv) +    bgp_advertise_clean (peer, adj, afi, safi); + +  BGP_ADJ_OUT_DEL (rn, adj); +  bgp_adj_out_free (adj); +} + +void +bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr) +{ +  struct bgp_adj_in *adj; + +  for (adj = rn->adj_in; adj; adj = adj->next) +    { +      if (adj->peer == peer) +	{ +	  if (adj->attr != attr) +	    { +	      bgp_attr_unintern (adj->attr); +	      adj->attr = bgp_attr_intern (attr); +	    } +	  return; +	} +    } +  adj = XCALLOC (MTYPE_BGP_ADJ_IN, sizeof (struct bgp_adj_in)); +  adj->peer = peer; +  adj->attr = bgp_attr_intern (attr); +  BGP_ADJ_IN_ADD (rn, adj); +  bgp_lock_node (rn); +} + +void +bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai) +{ +  bgp_attr_unintern (bai->attr); +  BGP_ADJ_IN_DEL (rn, bai); +  XFREE (MTYPE_BGP_ADJ_IN, bai); +} + +void +bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) +{ +  struct bgp_adj_in *adj; + +  for (adj = rn->adj_in; adj; adj = adj->next) +    if (adj->peer == peer) +      break; + +  if (! adj) +    return; + +  bgp_adj_in_remove (rn, adj); +  bgp_unlock_node (rn); +} + +void +bgp_sync_init (struct peer *peer) +{ +  afi_t afi; +  safi_t safi; +  struct bgp_synchronize *sync; + +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      { +	sync = XCALLOC (MTYPE_TMP, sizeof (struct bgp_synchronize)); +	FIFO_INIT (&sync->update); +	FIFO_INIT (&sync->withdraw); +	FIFO_INIT (&sync->withdraw_low); +	peer->sync[afi][safi] = sync; +	peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp); +      } +} + +void +bgp_sync_delete (struct peer *peer) +{ +  afi_t afi; +  safi_t safi; + +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      { +	if (peer->sync[afi][safi]) +	  XFREE (MTYPE_TMP, peer->sync[afi][safi]); +	peer->sync[afi][safi] = NULL; + +	hash_free (peer->hash[afi][safi]); +      } +} diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h new file mode 100644 index 0000000000..e2ae010446 --- /dev/null +++ b/bgpd/bgp_advertise.h @@ -0,0 +1,178 @@ +/* BGP advertisement and adjacency +   Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +/* BGP advertise FIFO.  */ +struct bgp_advertise_fifo +{ +  struct bgp_advertise *next; +  struct bgp_advertise *prev; +}; + +/* BGP advertise attribute.  */ +struct bgp_advertise_attr +{ +  /* Head of advertisement pointer. */ +  struct bgp_advertise *adv; + +  /* Reference counter.  */ +  unsigned long refcnt; + +  /* Attribute pointer to be announced.  */ +  struct attr *attr; +}; + +struct bgp_advertise +{ +  /* FIFO for advertisement.  */ +  struct bgp_advertise_fifo fifo; + +  /* Link list for same attribute advertise.  */ +  struct bgp_advertise *next; +  struct bgp_advertise *prev; + +  /* Prefix information.  */ +  struct bgp_node *rn; + +  /* Reference pointer.  */ +  struct bgp_adj_out *adj; + +  /* Advertisement attribute.  */ +  struct bgp_advertise_attr *baa; + +  /* BGP info.  */ +  struct bgp_info *binfo; +}; + +/* BGP adjacency out.  */ +struct bgp_adj_out +{ +  /* Lined list pointer.  */ +  struct bgp_adj_out *next; +  struct bgp_adj_out *prev; + +  /* Advertised peer.  */ +  struct peer *peer; + +  /* Advertised attribute.  */ +  struct attr *attr; + +  /* Advertisement information.  */ +  struct bgp_advertise *adv; +}; + +/* BGP adjacency in. */ +struct bgp_adj_in +{ +  /* Linked list pointer.  */ +  struct bgp_adj_in *next; +  struct bgp_adj_in *prev; + +  /* Received peer.  */ +  struct peer *peer; + +  /* Received attribute.  */ +  struct attr *attr; +}; + +/* BGP advertisement list.  */ +struct bgp_synchronize +{ +  struct bgp_advertise_fifo update; +  struct bgp_advertise_fifo withdraw; +  struct bgp_advertise_fifo withdraw_low; +}; + +/* FIFO -- first in first out structure and macros.  */ +struct fifo +{ +  struct fifo *next; +  struct fifo *prev; +}; + +#define FIFO_INIT(F)                                  \ +  do {                                                \ +    struct fifo *Xfifo = (struct fifo *)(F);          \ +    Xfifo->next = Xfifo->prev = Xfifo;                \ +  } while (0) + +#define FIFO_ADD(F,N)                                 \ +  do {                                                \ +    struct fifo *Xfifo = (struct fifo *)(F);          \ +    struct fifo *Xnode = (struct fifo *)(N);          \ +    Xnode->next = Xfifo;                              \ +    Xnode->prev = Xfifo->prev;                        \ +    Xfifo->prev = Xfifo->prev->next = Xnode;          \ +  } while (0) + +#define FIFO_DEL(N)                                   \ +  do {                                                \ +    struct fifo *Xnode = (struct fifo *)(N);          \ +    Xnode->prev->next = Xnode->next;                  \ +    Xnode->next->prev = Xnode->prev;                  \ +  } while (0) + +#define FIFO_HEAD(F)                                  \ +  ((((struct fifo *)(F))->next == (struct fifo *)(F)) \ +  ? NULL : (F)->next) + +/* BGP adjacency linked list.  */ +#define BGP_INFO_ADD(N,A,TYPE)                        \ +  do {                                                \ +    (A)->prev = NULL;                                 \ +    (A)->next = (N)->TYPE;                            \ +    if ((N)->TYPE)                                    \ +      (N)->TYPE->prev = (A);                          \ +    (N)->TYPE = (A);                                  \ +  } while (0) + +#define BGP_INFO_DEL(N,A,TYPE)                        \ +  do {                                                \ +    if ((A)->next)                                    \ +      (A)->next->prev = (A)->prev;                    \ +    if ((A)->prev)                                    \ +      (A)->prev->next = (A)->next;                    \ +    else                                              \ +      (N)->TYPE = (A)->next;                          \ +  } while (0) + +#define BGP_ADJ_IN_ADD(N,A)    BGP_INFO_ADD(N,A,adj_in) +#define BGP_ADJ_IN_DEL(N,A)    BGP_INFO_DEL(N,A,adj_in) +#define BGP_ADJ_OUT_ADD(N,A)   BGP_INFO_ADD(N,A,adj_out) +#define BGP_ADJ_OUT_DEL(N,A)   BGP_INFO_DEL(N,A,adj_out) + +/* Prototypes.  */ +void bgp_adj_out_set (struct bgp_node *, struct peer *, struct prefix *, +		      struct attr *, afi_t, safi_t, struct bgp_info *); +void bgp_adj_out_unset (struct bgp_node *, struct peer *, struct prefix *, +			afi_t, safi_t); +void bgp_adj_out_remove (struct bgp_node *, struct bgp_adj_out *,  +			 struct peer *, afi_t, safi_t); +int bgp_adj_out_lookup (struct peer *, struct prefix *, afi_t, safi_t, +			struct bgp_node *); + +void bgp_adj_in_set (struct bgp_node *, struct peer *, struct attr *); +void bgp_adj_in_unset (struct bgp_node *, struct peer *); +void bgp_adj_in_remove (struct bgp_node *, struct bgp_adj_in *); + +struct bgp_advertise * +bgp_advertise_clean (struct peer *, struct bgp_adj_out *, afi_t, safi_t); + +void bgp_sync_init (struct peer *); +void bgp_sync_delete (struct peer *); diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c new file mode 100644 index 0000000000..fc5efb1967 --- /dev/null +++ b/bgpd/bgp_aspath.c @@ -0,0 +1,1186 @@ +/* AS path management routines. +   Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "hash.h" +#include "memory.h" +#include "vector.h" +#include "vty.h" +#include "str.h" +#include "log.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_aspath.h" + +/* Attr. Flags and Attr. Type Code. */ +#define AS_HEADER_SIZE        2	  + +/* Two octet is used for AS value. */ +#define AS_VALUE_SIZE         sizeof (as_t) + +/* AS segment octet length. */ +#define ASSEGMENT_LEN(X)  ((X)->length * AS_VALUE_SIZE + AS_HEADER_SIZE) + +/* To fetch and store as segment value. */ +struct assegment +{ +  u_char type; +  u_char length; +  as_t asval[1]; +}; + +/* Hash for aspath.  This is the top level structure of AS path. */ +struct hash *ashash; + +static struct aspath * +aspath_new () +{ +  struct aspath *aspath; + +  aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); +  memset (aspath, 0, sizeof (struct aspath)); +  return aspath; +} + +/* Free AS path structure. */ +void +aspath_free (struct aspath *aspath) +{ +  if (!aspath) +    return; +  if (aspath->data) +    XFREE (MTYPE_AS_SEG, aspath->data); +  if (aspath->str) +    XFREE (MTYPE_AS_STR, aspath->str); +  XFREE (MTYPE_AS_PATH, aspath); +} + +/* Unintern aspath from AS path bucket. */ +void +aspath_unintern (struct aspath *aspath) +{ +  struct aspath *ret; + +  if (aspath->refcnt) +    aspath->refcnt--; + +  if (aspath->refcnt == 0) +    { +      /* This aspath must exist in aspath hash table. */ +      ret = hash_release (ashash, aspath); +      assert (ret != NULL); +      aspath_free (aspath); +    } +} + +/* Return the start or end delimiters for a particular Segment type */ +#define AS_SEG_START 0 +#define AS_SEG_END 1 +static char +aspath_delimiter_char (u_char type, u_char which) +{ +  int i; +  struct +  { +    int type; +    char start; +    char end; +  } aspath_delim_char [] = +    { +      { AS_SET,             '{', '}' }, +      { AS_SEQUENCE,        ' ', ' ' }, +      { AS_CONFED_SET,      '[', ']' }, +      { AS_CONFED_SEQUENCE, '(', ')' }, +      { 0 } +    }; + +  for (i = 0; aspath_delim_char[i].type != 0; i++) +    { +      if (aspath_delim_char[i].type == type) +	{ +	  if (which == AS_SEG_START) +	    return aspath_delim_char[i].start; +	  else if (which == AS_SEG_END) +	    return aspath_delim_char[i].end; +	} +    } +  return ' '; +} + +/* Convert aspath structure to string expression. */ +char * +aspath_make_str_count (struct aspath *as) +{ +  int space; +  u_char type; +  caddr_t pnt; +  caddr_t end; +  struct assegment *assegment; +  int str_size = ASPATH_STR_DEFAULT_LEN; +  int str_pnt; +  u_char *str_buf; +  int count = 0; + +  /* Empty aspath. */ +  if (as->length == 0) +    { +      str_buf = XMALLOC (MTYPE_AS_STR, 1); +      str_buf[0] = '\0'; +      as->count = count; +      return str_buf; +    } + +  /* Set default value. */ +  space = 0; +  type = AS_SEQUENCE; + +  /* Set initial pointer. */ +  pnt = as->data; +  end = pnt + as->length; + +  str_buf = XMALLOC (MTYPE_AS_STR, str_size); +  str_pnt = 0; + +  assegment = (struct assegment *) pnt; + +  while (pnt < end) +    { +      int i; +      int estimate_len; + +      /* For fetch value. */ +      assegment = (struct assegment *) pnt; + +      /* Check AS type validity. */ +      if ((assegment->type != AS_SET) &&  +	  (assegment->type != AS_SEQUENCE) && +	  (assegment->type != AS_CONFED_SET) &&  +	  (assegment->type != AS_CONFED_SEQUENCE)) +	{ +	  XFREE (MTYPE_AS_STR, str_buf); +	  return NULL; +	} + +      /* Check AS length. */ +      if ((pnt + (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE) > end) +	{ +	  XFREE (MTYPE_AS_STR, str_buf); +	  return NULL; +	} + +      /* Buffer length check. */ +      estimate_len = ((assegment->length * 6) + 4); +       +      /* String length check. */ +      while (str_pnt + estimate_len >= str_size) +	{ +	  str_size *= 2; +	  str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size); +	} + +      /* If assegment type is changed, print previous type's end +         character. */ +      if (type != AS_SEQUENCE) +	str_buf[str_pnt++] = aspath_delimiter_char (type, AS_SEG_END); +      if (space) +	str_buf[str_pnt++] = ' '; + +      if (assegment->type != AS_SEQUENCE) +	str_buf[str_pnt++] = aspath_delimiter_char (assegment->type, AS_SEG_START); + +      space = 0; + +      /* Increment count - ignoring CONFED SETS/SEQUENCES */ +      if (assegment->type != AS_CONFED_SEQUENCE +	  && assegment->type != AS_CONFED_SET) +	{ +	  if (assegment->type == AS_SEQUENCE) +	    count += assegment->length; +	  else if (assegment->type == AS_SET) +	    count++; +	} + +      for (i = 0; i < assegment->length; i++) +	{ +	  int len; + +	  if (space) +	    { +	      if (assegment->type == AS_SET +		  || assegment->type == AS_CONFED_SET) +		str_buf[str_pnt++] = ','; +	      else +		str_buf[str_pnt++] = ' '; +	    } +	  else +	    space = 1; + +	  len = sprintf (str_buf + str_pnt, "%d", ntohs (assegment->asval[i])); +	  str_pnt += len; +	} + +      type = assegment->type; +      pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE; +    } + +  if (assegment->type != AS_SEQUENCE) +    str_buf[str_pnt++] = aspath_delimiter_char (assegment->type, AS_SEG_END); + +  str_buf[str_pnt] = '\0'; + +  as->count = count; + +  return str_buf; +} + +/* Intern allocated AS path. */ +struct aspath * +aspath_intern (struct aspath *aspath) +{ +  struct aspath *find; +   +  /* Assert this AS path structure is not interned. */ +  assert (aspath->refcnt == 0); + +  /* Check AS path hash. */ +  find = hash_get (ashash, aspath, hash_alloc_intern); + +  if (find != aspath) +      aspath_free (aspath); + +  find->refcnt++; + +  if (! find->str) +    find->str = aspath_make_str_count (find); + +  return find; +} + +/* Duplicate aspath structure.  Created same aspath structure but +   reference count and AS path string is cleared. */ +struct aspath * +aspath_dup (struct aspath *aspath) +{ +  struct aspath *new; + +  new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); +  memset (new, 0, sizeof (struct aspath)); + +  new->length = aspath->length; + +  if (new->length) +    { +      new->data = XMALLOC (MTYPE_AS_SEG, aspath->length); +      memcpy (new->data, aspath->data, aspath->length); +    } +  else +    new->data = NULL; + +  /* new->str = aspath_make_str_count (aspath); */ + +  return new; +} + +void * +aspath_hash_alloc (struct aspath *arg) +{ +  struct aspath *aspath; + +  /* New aspath strucutre is needed. */ +  aspath = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); +  memset ((void *) aspath, 0, sizeof (struct aspath)); +  aspath->length = arg->length; + +  /* In case of IBGP connection aspath's length can be zero. */ +  if (arg->length) +    { +      aspath->data = XMALLOC (MTYPE_AS_SEG, arg->length); +      memcpy (aspath->data, arg->data, arg->length); +    } +  else +    aspath->data = NULL; + +  /* Make AS path string. */ +  aspath->str = aspath_make_str_count (aspath); + +  /* Malformed AS path value. */ +  if (! aspath->str) +    { +      aspath_free (aspath); +      return NULL; +    } + +  return aspath; +} + +/* AS path parse function.  pnt is a pointer to byte stream and length +   is length of byte stream.  If there is same AS path in the the AS +   path hash then return it else make new AS path structure. */ +struct aspath * +aspath_parse (caddr_t pnt, int length) +{ +  struct aspath as; +  struct aspath *find; + +  /* If length is odd it's malformed AS path. */ +  if (length % 2) +    return NULL; + +  /* Looking up aspath hash entry. */ +  as.data = pnt; +  as.length = length; + +  /* If already same aspath exist then return it. */ +  find = hash_get (ashash, &as, aspath_hash_alloc); +  if (! find) +    return NULL; +  find->refcnt++; + +  return find; +} + +#define min(A,B) ((A) < (B) ? (A) : (B)) + +#define ASSEGMENT_SIZE(N)  (AS_HEADER_SIZE + ((N) * AS_VALUE_SIZE)) + +struct aspath * +aspath_aggregate_segment_copy (struct aspath *aspath, struct assegment *seg, +			       int i) +{ +  struct assegment *newseg; + +  if (! aspath->data) +    { +      aspath->data = XMALLOC (MTYPE_AS_SEG, ASSEGMENT_SIZE (i)); +      newseg = (struct assegment *) aspath->data; +      aspath->length = ASSEGMENT_SIZE (i); +    } +  else +    { +      aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, +			       aspath->length + ASSEGMENT_SIZE (i)); +      newseg = (struct assegment *) (aspath->data + aspath->length); +      aspath->length += ASSEGMENT_SIZE (i); +    } + +  newseg->type = seg->type; +  newseg->length = i; +  memcpy (newseg->asval, seg->asval, (i * AS_VALUE_SIZE)); + +  return aspath; +} + +struct assegment * +aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset, +			     as_t as) +{ +  int i; + +  /* If this is first AS set member, create new as-set segment. */ +  if (asset == NULL) +    { +      if (! aspath->data) +	{ +	  aspath->data = XMALLOC (MTYPE_AS_SEG, ASSEGMENT_SIZE (1)); +	  asset = (struct assegment *) aspath->data; +	  aspath->length = ASSEGMENT_SIZE (1); +	} +      else +	{ +	  aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, +				   aspath->length + ASSEGMENT_SIZE (1)); +	  asset = (struct assegment *) (aspath->data + aspath->length); +	  aspath->length += ASSEGMENT_SIZE (1); +	} +      asset->type = AS_SET; +      asset->length = 1; +      asset->asval[0] = as; +    } +  else +    { +      size_t offset; + +      /* Check this AS value already exists or not. */ +      for (i = 0; i < asset->length; i++) +	if (asset->asval[i] == as) +	  return asset; + +      offset = (caddr_t) asset - (caddr_t) aspath->data; +      aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, +			       aspath->length + AS_VALUE_SIZE); + +      asset = (struct assegment *) (aspath->data + offset); +      aspath->length += AS_VALUE_SIZE; +      asset->asval[asset->length] = as; +      asset->length++; +    } + +  return asset; +} + +/* Modify as1 using as2 for aggregation. */ +struct aspath * +aspath_aggregate (struct aspath *as1, struct aspath *as2) +{ +  int i; +  int minlen; +  int match; +  int match1; +  int match2; +  caddr_t cp1; +  caddr_t cp2; +  caddr_t end1; +  caddr_t end2; +  struct assegment *seg1; +  struct assegment *seg2; +  struct aspath *aspath; +  struct assegment *asset; + +  match = 0; +  minlen = 0; +  aspath = NULL; +  asset = NULL; +  cp1 = as1->data; +  end1 = as1->data + as1->length; +  cp2 = as2->data; +  end2 = as2->data + as2->length; + +  seg1 = (struct assegment *) cp1; +  seg2 = (struct assegment *) cp2; + +  /* First of all check common leading sequence. */ +  while ((cp1 < end1) && (cp2 < end2)) +    { +      /* Check segment type. */ +      if (seg1->type != seg2->type) +	break; + +      /* Minimum segment length. */ +      minlen = min (seg1->length, seg2->length); + +      for (match = 0; match < minlen; match++) +	if (seg1->asval[match] != seg2->asval[match]) +	  break; + +      if (match) +	{ +	  if (! aspath) +	    aspath = aspath_new(); +	  aspath = aspath_aggregate_segment_copy (aspath, seg1, match); +	} + +      if (match != minlen || match != seg1->length  +	  || seg1->length != seg2->length) +	break; + +      cp1 += ((seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE); +      cp2 += ((seg2->length * AS_VALUE_SIZE) + AS_HEADER_SIZE); + +      seg1 = (struct assegment *) cp1; +      seg2 = (struct assegment *) cp2; +    } + +  if (! aspath) +    aspath = aspath_new(); + +  /* Make as-set using rest of all information. */ +  match1 = match; +  while (cp1 < end1) +    { +      seg1 = (struct assegment *) cp1; + +      for (i = match1; i < seg1->length; i++) +	asset = aspath_aggregate_as_set_add (aspath, asset, seg1->asval[i]); + +      match1 = 0; +      cp1 += ((seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE); +    } + +  match2 = match; +  while (cp2 < end2) +    { +      seg2 = (struct assegment *) cp2; + +      for (i = match2; i < seg2->length; i++) +	asset = aspath_aggregate_as_set_add (aspath, asset, seg2->asval[i]); + +      match2 = 0; +      cp2 += ((seg2->length * AS_VALUE_SIZE) + AS_HEADER_SIZE); +    } + +  return aspath; +} + +/* When a BGP router receives an UPDATE with an MP_REACH_NLRI +   attribute, check the leftmost AS number in the AS_PATH attribute is +   or not the peer's AS number. */  +int +aspath_firstas_check (struct aspath *aspath, as_t asno) +{ +  caddr_t pnt; +  struct assegment *assegment; + +  if (aspath == NULL) +    return 0; + +  pnt = aspath->data; +  assegment = (struct assegment *) pnt; + +  if (assegment +      && assegment->type == AS_SEQUENCE +      && assegment->asval[0] == htons (asno)) +    return 1; + +  return 0; +} + +/* AS path loop check.  If aspath contains asno then return 1. */ +int +aspath_loop_check (struct aspath *aspath, as_t asno) +{ +  caddr_t pnt; +  caddr_t end; +  struct assegment *assegment; +  int count = 0; + +  if (aspath == NULL) +    return 0; + +  pnt = aspath->data; +  end = aspath->data + aspath->length; + +  while (pnt < end) +    { +      int i; +      assegment = (struct assegment *) pnt; +       +      for (i = 0; i < assegment->length; i++) +	if (assegment->asval[i] == htons (asno)) +	  count++; + +      pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE; +    } +  return count; +} + +/* When all of AS path is private AS return 1.  */ +int +aspath_private_as_check (struct aspath *aspath) +{ +  caddr_t pnt; +  caddr_t end; +  struct assegment *assegment; + +  if (aspath == NULL) +    return 0; + +  if (aspath->length == 0) +    return 0; + +  pnt = aspath->data; +  end = aspath->data + aspath->length; + +  while (pnt < end) +    { +      int i; +      assegment = (struct assegment *) pnt; +       +      for (i = 0; i < assegment->length; i++) +	{ +	  if (ntohs (assegment->asval[i]) < BGP_PRIVATE_AS_MIN +	      || ntohs (assegment->asval[i]) > BGP_PRIVATE_AS_MAX) +	    return 0; +	} +      pnt += (assegment->length * AS_VALUE_SIZE) + AS_HEADER_SIZE; +    } +  return 1; +} + +/* Merge as1 to as2.  as2 should be uninterned aspath. */ +struct aspath * +aspath_merge (struct aspath *as1, struct aspath *as2) +{ +  caddr_t data; + +  if (! as1 || ! as2) +    return NULL; + +  data = XMALLOC (MTYPE_AS_SEG, as1->length + as2->length); +  memcpy (data, as1->data, as1->length); +  memcpy (data + as1->length, as2->data, as2->length); + +  XFREE (MTYPE_AS_SEG, as2->data); +  as2->data = data; +  as2->length += as1->length; +  as2->count += as1->count; +  return as2; +} + +/* Prepend as1 to as2.  as2 should be uninterned aspath. */ +struct aspath * +aspath_prepend (struct aspath *as1, struct aspath *as2) +{ +  caddr_t pnt; +  caddr_t end; +  struct assegment *seg1 = NULL; +  struct assegment *seg2 = NULL; + +  if (! as1 || ! as2) +    return NULL; + +  seg2 = (struct assegment *) as2->data; + +  /* In case of as2 is empty AS. */ +  if (seg2 == NULL) +    { +      as2->length = as1->length; +      as2->data = XMALLOC (MTYPE_AS_SEG, as1->length); +      as2->count = as1->count; +      memcpy (as2->data, as1->data, as1->length); +      return as2; +    } + +  /* assegment points last segment of as1. */ +  pnt = as1->data; +  end = as1->data + as1->length; +  while (pnt < end) +    { +      seg1 = (struct assegment *) pnt; +      pnt += (seg1->length * AS_VALUE_SIZE) + AS_HEADER_SIZE; +    } + +  /* In case of as1 is empty AS. */ +  if (seg1 == NULL) +    return as2; + +  /* Compare last segment type of as1 and first segment type of as2. */ +  if (seg1->type != seg2->type) +    return aspath_merge (as1, as2); + +  if (seg1->type == AS_SEQUENCE) +    { +      caddr_t newdata; +      struct assegment *seg = NULL; +       +      newdata = XMALLOC (MTYPE_AS_SEG,  +			 as1->length + as2->length - AS_HEADER_SIZE); +      memcpy (newdata, as1->data, as1->length); +      seg = (struct assegment *) (newdata + ((caddr_t)seg1 - as1->data)); +      seg->length += seg2->length; +      memcpy (newdata + as1->length, as2->data + AS_HEADER_SIZE, +	      as2->length - AS_HEADER_SIZE); + +      XFREE (MTYPE_AS_SEG, as2->data); +      as2->data = newdata; +      as2->length += (as1->length - AS_HEADER_SIZE); +      as2->count += as1->count; + +      return as2; +    } +  else +    { +      /* AS_SET merge code is needed at here. */ +      return aspath_merge (as1, as2); +    } + +  /* Not reached */ +} + +/* Add specified AS to the leftmost of aspath. */ +static struct aspath * +aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type) +{ +  struct assegment *assegment; + +  assegment = (struct assegment *) aspath->data; + +  /* In case of empty aspath. */ +  if (assegment == NULL || assegment->length == 0) +    { +      aspath->length = AS_HEADER_SIZE + AS_VALUE_SIZE; + +      if (assegment) +	aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, aspath->length); +      else +	aspath->data = XMALLOC (MTYPE_AS_SEG, aspath->length); + +      assegment = (struct assegment *) aspath->data; +      assegment->type = type; +      assegment->length = 1; +      assegment->asval[0] = htons (asno); + +      return aspath; +    } + +  if (assegment->type == type) +    { +      caddr_t newdata; +      struct assegment *newsegment; + +      newdata = XMALLOC (MTYPE_AS_SEG, aspath->length + AS_VALUE_SIZE); +      newsegment = (struct assegment *) newdata; + +      newsegment->type = type; +      newsegment->length = assegment->length + 1; +      newsegment->asval[0] = htons (asno); + +      memcpy (newdata + AS_HEADER_SIZE + AS_VALUE_SIZE, +	      aspath->data + AS_HEADER_SIZE,  +	      aspath->length - AS_HEADER_SIZE); + +      XFREE (MTYPE_AS_SEG, aspath->data); + +      aspath->data = newdata; +      aspath->length += AS_VALUE_SIZE; +    } else { +      caddr_t newdata; +      struct assegment *newsegment; + +      newdata = XMALLOC (MTYPE_AS_SEG, aspath->length + AS_VALUE_SIZE + AS_HEADER_SIZE); +      newsegment = (struct assegment *) newdata; + +      newsegment->type = type; +      newsegment->length = 1; +      newsegment->asval[0] = htons (asno); + +      memcpy (newdata + AS_HEADER_SIZE + AS_VALUE_SIZE, +	      aspath->data, +	      aspath->length); + +      XFREE (MTYPE_AS_SEG, aspath->data); + +      aspath->data = newdata; +      aspath->length += AS_HEADER_SIZE + AS_VALUE_SIZE; +    } + +  return aspath; +} + +/* Add specified AS to the leftmost of aspath. */ +struct aspath * +aspath_add_seq (struct aspath *aspath, as_t asno) +{ +  return aspath_add_one_as (aspath, asno, AS_SEQUENCE); +} + +/* Compare leftmost AS value for MED check.  If as1's leftmost AS and +   as2's leftmost AS is same return 1. */ +int +aspath_cmp_left (struct aspath *aspath1, struct aspath *aspath2) +{ +  struct assegment *seg1; +  struct assegment *seg2; +  as_t as1; +  as_t as2; + +  seg1 = (struct assegment *) aspath1->data; +  seg2 = (struct assegment *) aspath2->data; + +  while (seg1 && seg1->length  +	 && (seg1->type == AS_CONFED_SEQUENCE || seg1->type == AS_CONFED_SET)) +    seg1 = (struct assegment *) ((caddr_t) seg1 + ASSEGMENT_LEN (seg1)); +  while (seg2 && seg2->length  +	 && (seg2->type == AS_CONFED_SEQUENCE || seg2->type == AS_CONFED_SET)) +    seg2 = (struct assegment *) ((caddr_t) seg2 + ASSEGMENT_LEN (seg2)); + +  /* Check as1's */ +  if (seg1 == NULL || seg1->length == 0 || seg1->type != AS_SEQUENCE) +    return 0; +  as1 = seg1->asval[0]; + +  if (seg2 == NULL || seg2->length == 0 || seg2->type != AS_SEQUENCE) +    return 0; +  as2 = seg2->asval[0]; + +  if (as1 == as2) +    return 1; + +  return 0; +} + +/* Compare leftmost AS value for MED check.  If as1's leftmost AS and +   as2's leftmost AS is same return 1. (confederation as-path +   only).  */ +int +aspath_cmp_left_confed (struct aspath *aspath1, struct aspath *aspath2) +{ +  struct assegment *seg1; +  struct assegment *seg2; + +  as_t as1; +  as_t as2; + +  if (aspath1->count || aspath2->count)  +    return 0; + +  seg1 = (struct assegment *) aspath1->data; +  seg2 = (struct assegment *) aspath2->data; + +  /* Check as1's */ +  if (seg1 == NULL || seg1->length == 0 || seg1->type != AS_CONFED_SEQUENCE) +    return 0; +  as1 = seg1->asval[0]; + +  /* Check as2's */ +  if (seg2 == NULL || seg2->length == 0 || seg2->type != AS_CONFED_SEQUENCE) +    return 0; +  as2 = seg2->asval[0]; + +  if (as1 == as2) +    return 1; + +  return 0; +} + +/* Delete first sequential AS_CONFED_SEQUENCE from aspath.  */ +struct aspath * +aspath_delete_confed_seq (struct aspath *aspath) +{ +  int seglen; +  struct assegment *assegment; + +  if (! aspath) +    return aspath; + +  assegment = (struct assegment *) aspath->data; + +  while (assegment) +    { +      if (assegment->type != AS_CONFED_SEQUENCE) +	return aspath; + +      seglen = ASSEGMENT_LEN (assegment); + +      if (seglen == aspath->length) +	{ +	  XFREE (MTYPE_AS_SEG, aspath->data); +	  aspath->data = NULL; +	  aspath->length = 0; +	} +      else +	{ +	  memcpy (aspath->data, aspath->data + seglen, +		  aspath->length - seglen); +	  aspath->data = XREALLOC (MTYPE_AS_SEG, aspath->data, +				   aspath->length - seglen); +	  aspath->length -= seglen; +	} + +      assegment = (struct assegment *) aspath->data; +    } +  return aspath; +} + +/* Add new AS number to the leftmost part of the aspath as +   AS_CONFED_SEQUENCE.  */ +struct aspath* +aspath_add_confed_seq (struct aspath *aspath, as_t asno) +{ +  return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE); +} + +/* Add new as value to as path structure. */ +void +aspath_as_add (struct aspath *as, as_t asno) +{ +  caddr_t pnt; +  caddr_t end; +  struct assegment *assegment; + +  /* Increase as->data for new as value. */ +  as->data = XREALLOC (MTYPE_AS_SEG, as->data, as->length + 2); +  as->length += 2; + +  pnt = as->data; +  end = as->data + as->length; +  assegment = (struct assegment *) pnt; + +  /* Last segment search procedure. */ +  while (pnt + 2 < end) +    { +      assegment = (struct assegment *) pnt; + +      /* We add 2 for segment_type and segment_length and segment +         value assegment->length * 2. */ +      pnt += (AS_HEADER_SIZE + (assegment->length * AS_VALUE_SIZE)); +    } + +  assegment->asval[assegment->length] = htons (asno); +  assegment->length++; +} + +/* Add new as segment to the as path. */ +void +aspath_segment_add (struct aspath *as, int type) +{ +  struct assegment *assegment; + +  if (as->data == NULL) +    { +      as->data = XMALLOC (MTYPE_AS_SEG, 2); +      assegment = (struct assegment *) as->data; +      as->length = 2; +    } +  else +    { +      as->data = XREALLOC (MTYPE_AS_SEG, as->data, as->length + 2); +      assegment = (struct assegment *) (as->data + as->length); +      as->length += 2; +    } + +  assegment->type = type; +  assegment->length = 0; +} + +struct aspath * +aspath_empty () +{ +  return aspath_parse (NULL, 0); +} + +struct aspath * +aspath_empty_get () +{ +  struct aspath *aspath; + +  aspath = aspath_new (); +  aspath->str = aspath_make_str_count (aspath); +  return aspath; +} + +unsigned long +aspath_count () +{ +  return ashash->count; +}      + +/*  +   Theoretically, one as path can have: + +   One BGP packet size should be less than 4096. +   One BGP attribute size should be less than 4096 - BGP header size. +   One BGP aspath size should be less than 4096 - BGP header size - +       BGP mandantry attribute size. +*/ + +/* AS path string lexical token enum. */ +enum as_token +{ +  as_token_asval, +  as_token_set_start, +  as_token_set_end, +  as_token_confed_start, +  as_token_confed_end, +  as_token_unknown +}; + +/* Return next token and point for string parse. */ +char * +aspath_gettoken (char *buf, enum as_token *token, u_short *asno) +{ +  char *p = buf; + +  /* Skip space. */ +  while (isspace ((int) *p)) +    p++; + +  /* Check the end of the string and type specify characters +     (e.g. {}()). */ +  switch (*p) +    { +    case '\0': +      return NULL; +      break; +    case '{': +      *token = as_token_set_start; +      p++; +      return p; +      break; +    case '}': +      *token = as_token_set_end; +      p++; +      return p; +      break; +    case '(': +      *token = as_token_confed_start; +      p++; +      return p; +      break; +    case ')': +      *token = as_token_confed_end; +      p++; +      return p; +      break; +    } + +  /* Check actual AS value. */ +  if (isdigit ((int) *p))  +    { +      u_short asval; + +      *token = as_token_asval; +      asval = (*p - '0'); +      p++; +      while (isdigit ((int) *p))  +	{ +	  asval *= 10; +	  asval += (*p - '0'); +	  p++; +	} +      *asno = asval; +      return p; +    } +   +  /* There is no match then return unknown token. */ +  *token = as_token_unknown; +  return  p++; +} + +struct aspath * +aspath_str2aspath (char *str) +{ +  enum as_token token; +  u_short as_type; +  u_short asno; +  struct aspath *aspath; +  int needtype; + +  aspath = aspath_new (); + +  /* We start default type as AS_SEQUENCE. */ +  as_type = AS_SEQUENCE; +  needtype = 1; + +  while ((str = aspath_gettoken (str, &token, &asno)) != NULL) +    { +      switch (token) +	{ +	case as_token_asval: +	  if (needtype) +	    { +	      aspath_segment_add (aspath, as_type); +	      needtype = 0; +	    } +	  aspath_as_add (aspath, asno); +	  break; +	case as_token_set_start: +	  as_type = AS_SET; +	  aspath_segment_add (aspath, as_type); +	  needtype = 0; +	  break; +	case as_token_set_end: +	  as_type = AS_SEQUENCE; +	  needtype = 1; +	  break; +	case as_token_confed_start: +	  as_type = AS_CONFED_SEQUENCE; +	  aspath_segment_add (aspath, as_type); +	  needtype = 0; +	  break; +	case as_token_confed_end: +	  as_type = AS_SEQUENCE; +	  needtype = 1; +	  break; +	case as_token_unknown: +	default: +	  return NULL; +	  break; +	} +    } + +  aspath->str = aspath_make_str_count (aspath); + +  return aspath; +} + +/* Make hash value by raw aspath data. */ +unsigned int +aspath_key_make (struct aspath *aspath) +{ +  unsigned int key = 0; +  int length; +  unsigned short *pnt; + +  length = aspath->length / 2; +  pnt = (unsigned short *) aspath->data; + +  while (length) +    { +      key += *pnt++; +      length--; +    } + +  return key; +} + +/* If two aspath have same value then return 1 else return 0 */ +int +aspath_cmp (struct aspath *as1, struct aspath *as2) +{ +  if (as1->length == as2->length  +      && !memcmp (as1->data, as2->data, as1->length)) +    return 1; +  else +    return 0; +} + +/* AS path hash initialize. */ +void +aspath_init () +{ +  ashash = hash_create_size (32767, aspath_key_make, aspath_cmp); +} + +/* return and as path value */ +const char * +aspath_print (struct aspath *as) +{ +  return as->str; +} + +/* Printing functions */ +void +aspath_print_vty (struct vty *vty, struct aspath *as) +{ +  vty_out (vty, "%s", as->str); +} + +void +aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty) +{ +  struct aspath *as; + +  as = (struct aspath *) backet->data; + +  vty_out (vty, "[%p:%d] (%ld) ", backet, backet->key, as->refcnt); +  vty_out (vty, "%s%s", as->str, VTY_NEWLINE); +} + +/* Print all aspath and hash information.  This function is used from +   `show ip bgp paths' command. */ +void +aspath_print_all_vty (struct vty *vty) +{ +  hash_iterate (ashash,  +		(void (*) (struct hash_backet *, void *)) +		aspath_show_all_iterator, +		vty); +} diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h new file mode 100644 index 0000000000..0295fafb51 --- /dev/null +++ b/bgpd/bgp_aspath.h @@ -0,0 +1,77 @@ +/* AS path related definitions. +   Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +/* AS path segment type.  */ +#define AS_SET                       1 +#define AS_SEQUENCE                  2 +#define AS_CONFED_SEQUENCE           3 +#define AS_CONFED_SET                4 + +/* Private AS range defined in RFC2270.  */ +#define BGP_PRIVATE_AS_MIN       64512 +#define BGP_PRIVATE_AS_MAX       65535 + +/* AS path may be include some AsSegments.  */ +struct aspath  +{ +  /* Reference count to this aspath.  */ +  unsigned long refcnt; + +  /* Rawdata length.  */ +  int length; + +  /* AS count.  */ +  int count; + +  /* Rawdata.  */ +  caddr_t data; + +  /* String expression of AS path.  This string is used by vty output +     and AS path regular expression match.  */ +  char *str; +}; + +#define ASPATH_STR_DEFAULT_LEN 32 + +/* Prototypes. */ +void aspath_init (); +struct aspath *aspath_parse (); +struct aspath *aspath_dup (struct aspath *); +struct aspath *aspath_aggregate (struct aspath *, struct aspath *); +struct aspath *aspath_prepend (struct aspath *, struct aspath *); +struct aspath *aspath_add_seq (struct aspath *, as_t); +struct aspath *aspath_add_confed_seq (struct aspath *, as_t); +int aspath_cmp_left (struct aspath *, struct aspath *); +int aspath_cmp_left_confed (struct aspath *, struct aspath *); +struct aspath *aspath_delete_confed_seq (struct aspath *); +struct aspath *aspath_empty (); +struct aspath *aspath_empty_get (); +struct aspath *aspath_str2aspath (char *); +void aspath_free (struct aspath *); +struct aspath *aspath_intern (struct aspath *); +void aspath_unintern (struct aspath *); +const char *aspath_print (struct aspath *); +void aspath_print_vty (struct vty *, struct aspath *); +void aspath_print_all_vty (struct vty *); +unsigned int aspath_key_make (struct aspath *); +int aspath_loop_check (struct aspath *, as_t); +int aspath_private_as_check (struct aspath *); +int aspath_firstas_check (struct aspath *, as_t); +unsigned long aspath_count (); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c new file mode 100644 index 0000000000..480bb912fa --- /dev/null +++ b/bgpd/bgp_attr.c @@ -0,0 +1,1838 @@ +/* BGP attributes management routines. +   Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "linklist.h" +#include "prefix.h" +#include "memory.h" +#include "vector.h" +#include "vty.h" +#include "stream.h" +#include "log.h" +#include "hash.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_ecommunity.h" + +/* Attribute strings for logging. */ +struct message attr_str [] =  +{ +  { BGP_ATTR_ORIGIN,           "ORIGIN" },  +  { BGP_ATTR_AS_PATH,          "AS_PATH" },  +  { BGP_ATTR_NEXT_HOP,         "NEXT_HOP" },  +  { BGP_ATTR_MULTI_EXIT_DISC,  "MULTI_EXIT_DISC" },  +  { BGP_ATTR_LOCAL_PREF,       "LOCAL_PREF" },  +  { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },  +  { BGP_ATTR_AGGREGATOR,       "AGGREGATOR" },  +  { BGP_ATTR_COMMUNITIES,      "COMMUNITY" },  +  { BGP_ATTR_ORIGINATOR_ID,    "ORIGINATOR_ID" }, +  { BGP_ATTR_CLUSTER_LIST,     "CLUSTERLIST" },  +  { BGP_ATTR_DPA,              "DPA" }, +  { BGP_ATTR_ADVERTISER,       "ADVERTISER"} , +  { BGP_ATTR_RCID_PATH,        "RCID_PATH" }, +  { BGP_ATTR_MP_REACH_NLRI,    "MP_REACH_NLRI" }, +  { BGP_ATTR_MP_UNREACH_NLRI,  "MP_UNREACH_NLRI" }, +  { 0, NULL } +}; + +struct hash *cluster_hash; + +void * +cluster_hash_alloc (struct cluster_list *val) +{ +  struct cluster_list *cluster; + +  cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list)); +  cluster->length = val->length; + +  if (cluster->length) +    { +      cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length); +      memcpy (cluster->list, val->list, val->length); +    } +  else +    cluster->list = NULL; + +  cluster->refcnt = 0; + +  return cluster; +} + +/* Cluster list related functions. */ +struct cluster_list * +cluster_parse (caddr_t pnt, int length) +{ +  struct cluster_list tmp; +  struct cluster_list *cluster; + +  tmp.length = length; +  tmp.list = (struct in_addr *) pnt; + +  cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc); +  cluster->refcnt++; +  return cluster; +} + +int +cluster_loop_check (struct cluster_list *cluster, struct in_addr originator) +{ +  int i; +     +  for (i = 0; i < cluster->length / 4; i++) +    if (cluster->list[i].s_addr == originator.s_addr) +      return 1; +  return 0; +} + +unsigned int +cluster_hash_key_make (struct cluster_list *cluster) +{ +  unsigned int key = 0; +  int length; +  caddr_t pnt; + +  length = cluster->length; +  pnt = (caddr_t) cluster->list; +   +  while (length) +    key += pnt[--length]; + +  return key; +} + +int +cluster_hash_cmp (struct cluster_list *cluster1, struct cluster_list *cluster2) +{ +  if (cluster1->length == cluster2->length && +      memcmp (cluster1->list, cluster2->list, cluster1->length) == 0) +    return 1; +  return 0; +} + +void +cluster_free (struct cluster_list *cluster) +{ +  if (cluster->list) +    XFREE (MTYPE_CLUSTER_VAL, cluster->list); +  XFREE (MTYPE_CLUSTER, cluster); +} + +struct cluster_list * +cluster_dup (struct cluster_list *cluster) +{ +  struct cluster_list *new; + +  new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list)); +  memset (new, 0, sizeof (struct cluster_list)); +  new->length = cluster->length; + +  if (cluster->length) +    { +      new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length); +      memcpy (new->list, cluster->list, cluster->length); +    } +  else +    new->list = NULL; +   +  return new; +} + +struct cluster_list * +cluster_intern (struct cluster_list *cluster) +{ +  struct cluster_list *find; + +  find = hash_get (cluster_hash, cluster, cluster_hash_alloc); +  find->refcnt++; + +  return find; +} + +void +cluster_unintern (struct cluster_list *cluster) +{ +  struct cluster_list *ret; + +  if (cluster->refcnt) +    cluster->refcnt--; + +  if (cluster->refcnt == 0) +    { +      ret = hash_release (cluster_hash, cluster); +      cluster_free (cluster); +    } +} + +void +cluster_init () +{ +  cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp); +} + +/* Unknown transit attribute. */ +struct hash *transit_hash; + +void +transit_free (struct transit *transit) +{ +  if (transit->val) +    XFREE (MTYPE_TRANSIT_VAL, transit->val); +  XFREE (MTYPE_TRANSIT, transit); +} + +void * +transit_hash_alloc (struct transit *transit) +{ +  /* Transit structure is already allocated.  */ +  return transit; +} + +struct transit * +transit_intern (struct transit *transit) +{ +  struct transit *find; + +  find = hash_get (transit_hash, transit, transit_hash_alloc); +  if (find != transit) +    transit_free (transit); +  find->refcnt++; + +  return find; +} + +void +transit_unintern (struct transit *transit) +{ +  struct transit *ret; + +  if (transit->refcnt) +    transit->refcnt--; + +  if (transit->refcnt == 0) +    { +      ret = hash_release (transit_hash, transit); +      transit_free (transit); +    } +} + +unsigned int +transit_hash_key_make (struct transit *transit) +{ +  unsigned int key = 0; +  int length; +  caddr_t pnt; + +  length = transit->length; +  pnt = (caddr_t) transit->val; +   +  while (length) +    key += pnt[--length]; + +  return key; +} + +int +transit_hash_cmp (struct transit *transit1, struct transit *transit2) +{ +  if (transit1->length == transit2->length && +      memcmp (transit1->val, transit2->val, transit1->length) == 0) +    return 1; +  return 0; +} + +void +transit_init () +{ +  transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp); +} + +/* Attribute hash routines. */ + +struct hash *attrhash; + +unsigned int +attrhash_key_make (struct attr *attr) +{ +  unsigned int key = 0; + +  key += attr->origin; +  key += attr->nexthop.s_addr; +  key += attr->med; +  key += attr->local_pref; +  key += attr->aggregator_as; +  key += attr->aggregator_addr.s_addr; +  key += attr->weight; + +  key += attr->mp_nexthop_global_in.s_addr; +  if (attr->aspath) +    key += aspath_key_make (attr->aspath); +  if (attr->community) +    key += community_hash_make (attr->community); +  if (attr->ecommunity) +    key += ecommunity_hash_make (attr->ecommunity); +  if (attr->cluster) +    key += cluster_hash_key_make (attr->cluster); +  if (attr->transit) +    key += transit_hash_key_make (attr->transit); + +#ifdef HAVE_IPV6 + { +   int i; +    +   key += attr->mp_nexthop_len; +   for (i = 0; i < 16; i++) +     key += attr->mp_nexthop_global.s6_addr[i]; +   for (i = 0; i < 16; i++) +     key += attr->mp_nexthop_local.s6_addr[i]; + } +#endif /* HAVE_IPV6 */ + +  return key; +} + +int +attrhash_cmp (struct attr *attr1, struct attr *attr2) +{ +  if (attr1->flag == attr2->flag +      && attr1->origin == attr2->origin +      && attr1->nexthop.s_addr == attr2->nexthop.s_addr +      && attr1->med == attr2->med +      && attr1->local_pref == attr2->local_pref +      && attr1->aggregator_as == attr2->aggregator_as +      && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr +      && attr1->weight == attr2->weight +#ifdef HAVE_IPV6 +      && attr1->mp_nexthop_len == attr2->mp_nexthop_len +      && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global) +      && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local) +#endif /* HAVE_IPV6 */ +      && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in) +      && attr1->aspath == attr2->aspath +      && attr1->community == attr2->community +      && attr1->ecommunity == attr2->ecommunity +      && attr1->cluster == attr2->cluster +      && attr1->transit == attr2->transit) +    return 1; +  else +    return 0; +} + +void +attrhash_init () +{ +  attrhash = hash_create (attrhash_key_make, attrhash_cmp); +} + +void +attr_show_all_iterator (struct hash_backet *backet, struct vty *vty) +{ +  struct attr *attr = backet->data; + +  vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,  +	   inet_ntoa (attr->nexthop), VTY_NEWLINE); +} + +void +attr_show_all (struct vty *vty) +{ +  hash_iterate (attrhash,  +		(void (*)(struct hash_backet *, void *)) +		attr_show_all_iterator, +		vty); +} + +void * +bgp_attr_hash_alloc (struct attr *val) +{ +  struct attr *attr; + +  attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr)); +  *attr = *val; +  attr->refcnt = 0; +  return attr; +} + +/* Internet argument attribute. */ +struct attr * +bgp_attr_intern (struct attr *attr) +{ +  struct attr *find; + +  /* Intern referenced strucutre. */ +  if (attr->aspath) +    { +      if (! attr->aspath->refcnt) +	attr->aspath = aspath_intern (attr->aspath); +      else +	attr->aspath->refcnt++; +    } +  if (attr->community) +    { +      if (! attr->community->refcnt) +	attr->community = community_intern (attr->community); +      else +	attr->community->refcnt++; +    } +  if (attr->ecommunity) +    { +      if (! attr->ecommunity->refcnt) +	attr->ecommunity = ecommunity_intern (attr->ecommunity); +      else +	attr->ecommunity->refcnt++; +    } +  if (attr->cluster) +    { +      if (! attr->cluster->refcnt) +	attr->cluster = cluster_intern (attr->cluster); +      else +	attr->cluster->refcnt++; +    } +  if (attr->transit) +    { +      if (! attr->transit->refcnt) +	attr->transit = transit_intern (attr->transit); +      else +	attr->transit->refcnt++; +    } + +  find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc); +  find->refcnt++; + +  return find; +} + +/* Make network statement's attribute. */ +struct attr * +bgp_attr_default_set (struct attr *attr, u_char origin) +{ +  memset (attr, 0, sizeof (struct attr)); + +  attr->origin = origin; +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); +  attr->aspath = aspath_empty (); +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); +  attr->weight = 32768; +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); +#ifdef HAVE_IPV6 +  attr->mp_nexthop_len = 16; +#endif +  return attr; +} + +/* Make network statement's attribute. */ +struct attr * +bgp_attr_default_intern (u_char origin) +{ +  struct attr attr; +  struct attr *new; + +  memset (&attr, 0, sizeof (struct attr)); + +  attr.origin = origin; +  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); +  attr.aspath = aspath_empty (); +  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); +  attr.weight = 32768; +  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); +#ifdef HAVE_IPV6 +  attr.mp_nexthop_len = 16; +#endif + +  new = bgp_attr_intern (&attr); +  aspath_unintern (new->aspath); +  return new; +} + +struct attr * +bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, +			   struct aspath *aspath, +			   struct community *community, int as_set) +{ +  struct attr attr; +  struct attr *new; + +  memset (&attr, 0, sizeof (struct attr)); + +  /* Origin attribute. */ +  attr.origin = origin; +  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); + +  /* AS path attribute. */ +  if (aspath) +    attr.aspath = aspath_intern (aspath); +  else +    attr.aspath = aspath_empty (); +  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + +  /* Next hop attribute.  */ +  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); + +  if (community) +    { +      attr.community = community; +      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); +    } + +  attr.weight = 32768; +#ifdef HAVE_IPV6 +  attr.mp_nexthop_len = 16; +#endif +  if (! as_set) +    attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); +  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); +  if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) +    attr.aggregator_as = bgp->confed_id; +  else +    attr.aggregator_as = bgp->as; +  attr.aggregator_addr = bgp->router_id; + +  new = bgp_attr_intern (&attr); +  aspath_unintern (new->aspath); +  return new; +} + +/* Free bgp attribute and aspath. */ +void +bgp_attr_unintern (struct attr *attr) +{ +  struct attr *ret; +  struct aspath *aspath; +  struct community *community; +  struct ecommunity *ecommunity; +  struct cluster_list *cluster; +  struct transit *transit; + +  /* Decrement attribute reference. */ +  attr->refcnt--; +  aspath = attr->aspath; +  community = attr->community; +  ecommunity = attr->ecommunity; +  cluster = attr->cluster; +  transit = attr->transit; + +  /* If reference becomes zero then free attribute object. */ +  if (attr->refcnt == 0) +    {     +      ret = hash_release (attrhash, attr); +      assert (ret != NULL); +      XFREE (MTYPE_ATTR, attr); +    } + +  /* aspath refcount shoud be decrement. */ +  if (aspath) +    aspath_unintern (aspath); +  if (community) +    community_unintern (community); +  if (ecommunity) +    ecommunity_unintern (ecommunity); +  if (cluster) +    cluster_unintern (cluster); +  if (transit) +    transit_unintern (transit); +} + +void +bgp_attr_flush (struct attr *attr) +{ +  if (attr->aspath && ! attr->aspath->refcnt) +    aspath_free (attr->aspath); +  if (attr->community && ! attr->community->refcnt) +    community_free (attr->community); +  if (attr->ecommunity && ! attr->ecommunity->refcnt) +    ecommunity_free (attr->ecommunity); +  if (attr->cluster && ! attr->cluster->refcnt) +    cluster_free (attr->cluster); +  if (attr->transit && ! attr->transit->refcnt) +    transit_free (attr->transit); +} + +/* Get origin attribute of the update message. */ +int +bgp_attr_origin (struct peer *peer, bgp_size_t length,  +		 struct attr *attr, u_char flag, u_char *startp) +{ +  bgp_size_t total; + +  /* total is entire attribute length include Attribute Flags (1), +     Attribute Type code (1) and Attribute length (1 or 2).  */ +  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + +  /* If any recognized attribute has Attribute Flags that conflict +     with the Attribute Type Code, then the Error Subcode is set to +     Attribute Flags Error.  The Data field contains the erroneous +     attribute (type, length and value). */ +  if (flag != BGP_ATTR_FLAG_TRANS) +    { +      zlog (peer->log, LOG_ERR,  +	    "Origin attribute flag isn't transitive %d", flag); +      bgp_notify_send_with_data (peer,  +				 BGP_NOTIFY_UPDATE_ERR,  +				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, +				 startp, total); +      return -1; +    } + +  /* If any recognized attribute has Attribute Length that conflicts +     with the expected length (based on the attribute type code), then +     the Error Subcode is set to Attribute Length Error.  The Data +     field contains the erroneous attribute (type, length and +     value). */ +  if (length != 1) +    { +      zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d", +	    length); +      bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,  +				 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +				 startp, total); +      return -1; +    } + +  /* Fetch origin attribute. */ +  attr->origin = stream_getc (BGP_INPUT (peer)); + +  /* If the ORIGIN attribute has an undefined value, then the Error +     Subcode is set to Invalid Origin Attribute.  The Data field +     contains the unrecognized attribute (type, length and value). */ +  if ((attr->origin != BGP_ORIGIN_IGP) +      && (attr->origin != BGP_ORIGIN_EGP) +      && (attr->origin != BGP_ORIGIN_INCOMPLETE)) +    { +      zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d", +	      attr->origin); + +      bgp_notify_send_with_data (peer,  +				 BGP_NOTIFY_UPDATE_ERR,  +				 BGP_NOTIFY_UPDATE_INVAL_ORIGIN, +				 startp, total); +      return -1; +    } + +  /* Set oring attribute flag. */ +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); + +  return 0; +} + +/* Parse AS path information.  This function is wrapper of +   aspath_parse. */ +int +bgp_attr_aspath (struct peer *peer, bgp_size_t length,  +		 struct attr *attr, u_char flag, u_char *startp) +{ +  struct bgp *bgp; +  struct aspath *aspath; +  bgp_size_t total; + +  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + +  /* Flag check. */ +  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) +      || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) +    { +      zlog (peer->log, LOG_ERR,  +	    "Origin attribute flag isn't transitive %d", flag); +      bgp_notify_send_with_data (peer,  +				 BGP_NOTIFY_UPDATE_ERR,  +				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, +				 startp, total); +      return -1; +    } + +  /* In case of IBGP, length will be zero. */ +  attr->aspath = aspath_parse (stream_pnt (peer->ibuf), length); +  if (! attr->aspath) +    { +      zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length); +      bgp_notify_send (peer,  +		       BGP_NOTIFY_UPDATE_ERR,  +		       BGP_NOTIFY_UPDATE_MAL_AS_PATH); +      return -1; +    } + +  bgp = peer->bgp; +     +  /* First AS check for EBGP. */ +  if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS)) +    { +      if (peer_sort (peer) == BGP_PEER_EBGP  +	  && ! aspath_firstas_check (attr->aspath, peer->as)) + 	{ + 	  zlog (peer->log, LOG_ERR, + 		"%s incorrect first AS (must be %d)", peer->host, peer->as); + 	  bgp_notify_send (peer, + 			   BGP_NOTIFY_UPDATE_ERR, + 			   BGP_NOTIFY_UPDATE_MAL_AS_PATH); +	  return -1; + 	} +    } + +  /* local-as prepend */ +  if (peer->change_local_as && +      ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) +    { +      aspath = aspath_dup (attr->aspath); +      aspath = aspath_add_seq (aspath, peer->change_local_as); +      aspath_unintern (attr->aspath); +      attr->aspath = aspath_intern (aspath); +    } + +  /* Forward pointer. */ +  stream_forward (peer->ibuf, length); + +  /* Set aspath attribute flag. */ +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); + +  return 0; +} + +/* Nexthop attribute. */ +int +bgp_attr_nexthop (struct peer *peer, bgp_size_t length,  +		  struct attr *attr, u_char flag, u_char *startp) +{ +  bgp_size_t total; + +  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + +  /* Flag check. */ +  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) +      || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) +    { +      zlog (peer->log, LOG_ERR,  +	    "Origin attribute flag isn't transitive %d", flag); +      bgp_notify_send_with_data (peer,  +				 BGP_NOTIFY_UPDATE_ERR,  +				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, +				 startp, total); +      return -1; +    } + +  /* Check nexthop attribute length. */ +  if (length != 4) +    { +      zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]", +	      length); + +      bgp_notify_send_with_data (peer,  +				 BGP_NOTIFY_UPDATE_ERR,  +				 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +				 startp, total); +      return -1; +    } + +  attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf); +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); + +  return 0; +} + +/* MED atrribute. */ +int +bgp_attr_med (struct peer *peer, bgp_size_t length,  +	      struct attr *attr, u_char flag, u_char *startp) +{ +  bgp_size_t total; + +  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + +  /* Length check. */ +  if (length != 4) +    { +      zlog (peer->log, LOG_ERR,  +	    "MED attribute length isn't four [%d]", length); +       +      bgp_notify_send_with_data (peer,  +				 BGP_NOTIFY_UPDATE_ERR,  +				 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +				 startp, total); +      return -1; +    } + +  attr->med = stream_getl (peer->ibuf); + +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + +  return 0; +} + +/* Local preference attribute. */ +int +bgp_attr_local_pref (struct peer *peer, bgp_size_t length,  +		     struct attr *attr, u_char flag) +{ +  /* If it is contained in an UPDATE message that is received from an +     external peer, then this attribute MUST be ignored by the +     receiving speaker. */ +  if (peer_sort (peer) == BGP_PEER_EBGP) +    { +      stream_forward (peer->ibuf, length); +      return 0; +    } + +  if (length == 4)  +    attr->local_pref = stream_getl (peer->ibuf); +  else  +    attr->local_pref = 0; + +  /* Set atomic aggregate flag. */ +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); + +  return 0; +} + +/* Atomic aggregate. */ +int +bgp_attr_atomic (struct peer *peer, bgp_size_t length,  +		 struct attr *attr, u_char flag) +{ +  if (length != 0) +    { +      zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length); + +      bgp_notify_send (peer,  +		       BGP_NOTIFY_UPDATE_ERR,  +		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); +      return -1; +    } + +  /* Set atomic aggregate flag. */ +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + +  return 0; +} + +/* Aggregator attribute */ +int +bgp_attr_aggregator (struct peer *peer, bgp_size_t length, +		     struct attr *attr, u_char flag) +{ +  if (length != 6) +    { +      zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length); + +      bgp_notify_send (peer, +		       BGP_NOTIFY_UPDATE_ERR, +		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); +      return -1; +    } +  attr->aggregator_as = stream_getw (peer->ibuf); +  attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf); + +  /* Set atomic aggregate flag. */ +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); + +  return 0; +} + +/* Community attribute. */ +int +bgp_attr_community (struct peer *peer, bgp_size_t length,  +		    struct attr *attr, u_char flag) +{ +  if (length == 0) +    attr->community = NULL; +  else +    { +      attr->community = community_parse (stream_pnt (peer->ibuf), length); +      stream_forward (peer->ibuf, length); +    } + +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); + +  return 0; +} + +/* Originator ID attribute. */ +int +bgp_attr_originator_id (struct peer *peer, bgp_size_t length,  +			struct attr *attr, u_char flag) +{ +  if (length != 4) +    { +      zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length); + +      bgp_notify_send (peer,  +		       BGP_NOTIFY_UPDATE_ERR,  +		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); +      return -1; +    } + +  attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf); + +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); + +  return 0; +} + +/* Cluster list attribute. */ +int +bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,  +		       struct attr *attr, u_char flag) +{ +  /* Check length. */ +  if (length % 4) +    { +      zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length); + +      bgp_notify_send (peer,  +		       BGP_NOTIFY_UPDATE_ERR,  +		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); +      return -1; +    } + +  attr->cluster = cluster_parse (stream_pnt (peer->ibuf), length); + +  stream_forward (peer->ibuf, length);; + +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST); + +  return 0; +} + +/* Multiprotocol reachability information parse. */ +int +bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, +		    struct bgp_nlri *mp_update) +{ +  u_int16_t afi; +  u_char safi; +  u_char snpa_num; +  u_char snpa_len; +  u_char *lim; +  bgp_size_t nlri_len; +  int ret; +  struct stream *s; +   +  /* Set end of packet. */ +  s = peer->ibuf; +  lim = stream_pnt (s) + length; + +  /* Load AFI, SAFI. */ +  afi = stream_getw (s); +  safi = stream_getc (s); + +  /* Get nexthop length. */ +  attr->mp_nexthop_len = stream_getc (s); + +  /* Nexthop length check. */ +  switch (attr->mp_nexthop_len) +    { +    case 4: +      stream_get (&attr->mp_nexthop_global_in, s, 4); +      break; +    case 12: +      { +	u_int32_t rd_high; +	u_int32_t rd_low; + +	rd_high = stream_getl (s); +	rd_low = stream_getl (s); +	stream_get (&attr->mp_nexthop_global_in, s, 4); +      } +      break; +#ifdef HAVE_IPV6 +    case 16: +      stream_get (&attr->mp_nexthop_global, s, 16); +      break; +    case 32: +      stream_get (&attr->mp_nexthop_global, s, 16); +      stream_get (&attr->mp_nexthop_local, s, 16); +      if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local)) +	{ +	  char buf1[INET6_ADDRSTRLEN]; +	  char buf2[INET6_ADDRSTRLEN]; + +	  if (BGP_DEBUG (update, UPDATE_IN)) +	    zlog_warn ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host, +		       inet_ntop (AF_INET6, &attr->mp_nexthop_global, +				  buf1, INET6_ADDRSTRLEN), +		       inet_ntop (AF_INET6, &attr->mp_nexthop_local, +				  buf2, INET6_ADDRSTRLEN)); + +	  attr->mp_nexthop_len = 16; +	} +      break; +#endif /* HAVE_IPV6 */ +    default: +      zlog_info ("Wrong multiprotocol next hop length: %d",  +		 attr->mp_nexthop_len); +      return -1; +      break; +    } + +  snpa_num = stream_getc (s); + +  while (snpa_num--) +    { +      snpa_len = stream_getc (s); +      stream_forward (s, (snpa_len + 1) >> 1); +    } +   +  /* If peer is based on old draft-00. I read NLRI length from the +     packet. */ +  if (peer->version == BGP_VERSION_MP_4_DRAFT_00) +    { +      bgp_size_t nlri_total_len; +      nlri_total_len = stream_getw (s); +    } + +  nlri_len = lim - stream_pnt (s); +  +  if (safi != BGP_SAFI_VPNV4) +    { +      ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len); +      if (ret < 0) +	return -1; +    } + +  mp_update->afi = afi; +  mp_update->safi = safi; +  mp_update->nlri = stream_pnt (s); +  mp_update->length = nlri_len; + +  stream_forward (s, nlri_len); + +  return 0; +} + +/* Multiprotocol unreachable parse */ +int +bgp_mp_unreach_parse (struct peer *peer, int length,  +		      struct bgp_nlri *mp_withdraw) +{ +  struct stream *s; +  u_int16_t afi; +  u_char safi; +  u_char *lim; +  u_int16_t withdraw_len; +  int ret; + +  s = peer->ibuf; +  lim = stream_pnt (s) + length; + +  afi = stream_getw (s); +  safi = stream_getc (s); + +  withdraw_len = lim - stream_pnt (s); + +  if (safi != BGP_SAFI_VPNV4) +    { +      ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len); +      if (ret < 0) +	return -1; +    } + +  mp_withdraw->afi = afi; +  mp_withdraw->safi = safi; +  mp_withdraw->nlri = stream_pnt (s); +  mp_withdraw->length = withdraw_len; + +  stream_forward (s, withdraw_len); + +  return 0; +} + +/* Extended Community attribute. */ +int +bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,  +			  struct attr *attr, u_char flag) +{ +  if (length == 0) +    attr->ecommunity = NULL; +  else +    { +      attr->ecommunity = ecommunity_parse (stream_pnt (peer->ibuf), length); +      stream_forward (peer->ibuf, length); +    } +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); + +  return 0; +} + +/* BGP unknown attribute treatment. */ +int +bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, +		  u_char type, bgp_size_t length, u_char *startp) +{ +  bgp_size_t total; +  struct transit *transit; + +  if (BGP_DEBUG (events, EVENTS)) +    zlog (peer->log, LOG_INFO,  +	  "Unknown attribute type %d length %d is received", type, length); + +  /* Forward read pointer of input stream. */ +  stream_forward (peer->ibuf, length); + +  /* Adjest total length to include type and length. */ +  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + +  /* If any of the mandatory well-known attributes are not recognized, +     then the Error Subcode is set to Unrecognized Well-known +     Attribute.  The Data field contains the unrecognized attribute +     (type, length and value). */ +  if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) +    { +      /* Adjust startp to do not include flag value. */ +      bgp_notify_send_with_data (peer,  +				 BGP_NOTIFY_UPDATE_ERR,  +				 BGP_NOTIFY_UPDATE_UNREC_ATTR, +				 startp, total); +      return -1; +    } + +  /* Unrecognized non-transitive optional attributes must be quietly +     ignored and not passed along to other BGP peers. */ +  if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) +    return 0; + +  /* If a path with recognized transitive optional attribute is +     accepted and passed along to other BGP peers and the Partial bit +     in the Attribute Flags octet is set to 1 by some previous AS, it +     is not set back to 0 by the current AS. */ +  SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL); + +  /* Store transitive attribute to the end of attr->transit. */ +  if (! attr->transit) +    { +      attr->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit)); +      memset (attr->transit, 0, sizeof (struct transit)); +    } + +  transit = attr->transit; + +  if (transit->val) +    transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,  +			     transit->length + total); +  else +    transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total); + +  memcpy (transit->val + transit->length, startp, total); +  transit->length += total; + +  return 0; +} + +/* Read attribute of update packet.  This function is called from +   bgp_update() in bgpd.c.  */ +int +bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, +		struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw) +{ +  int ret; +  u_char flag; +  u_char type; +  bgp_size_t length; +  u_char *startp, *endp; +  u_char *attr_endp; +  u_char seen[BGP_ATTR_BITMAP_SIZE]; + +  /* Initialize bitmap. */ +  memset (seen, 0, BGP_ATTR_BITMAP_SIZE); + +  /* End pointer of BGP attribute. */ +  endp = BGP_INPUT_PNT (peer) + size; + +  /* Get attributes to the end of attribute length. */ +  while (BGP_INPUT_PNT (peer) < endp) +    { +      /* Check remaining length check.*/ +      if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN) +	{ +	  zlog (peer->log, LOG_WARNING,  +		"%s error BGP attribute length %d is smaller than min len", +		peer->host, endp - STREAM_PNT (BGP_INPUT (peer))); + +	  bgp_notify_send (peer,  +			   BGP_NOTIFY_UPDATE_ERR,  +			   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); +	  return -1; +	} + +      /* Fetch attribute flag and type. */ +      startp = BGP_INPUT_PNT (peer); +      flag = stream_getc (BGP_INPUT (peer)); +      type = stream_getc (BGP_INPUT (peer)); + +      /* Check extended attribue length bit. */ +      if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)) +	length = stream_getw (BGP_INPUT (peer)); +      else +	length = stream_getc (BGP_INPUT (peer)); +       +      /* If any attribute appears more than once in the UPDATE +	 message, then the Error Subcode is set to Malformed Attribute +	 List. */ + +      if (CHECK_BITMAP (seen, type)) +	{ +	  zlog (peer->log, LOG_WARNING, +		"%s error BGP attribute type %d appears twice in a message", +		peer->host, type); + +	  bgp_notify_send (peer,  +			   BGP_NOTIFY_UPDATE_ERR,  +			   BGP_NOTIFY_UPDATE_MAL_ATTR); +	  return -1; +	} + +      /* Set type to bitmap to check duplicate attribute.  `type' is +	 unsigned char so it never overflow bitmap range. */ + +      SET_BITMAP (seen, type); + +      /* Overflow check. */ +      attr_endp =  BGP_INPUT_PNT (peer) + length; + +      if (attr_endp > endp) +	{ +	  zlog (peer->log, LOG_WARNING,  +		"%s BGP type %d length %d is too large, attribute total length is %d.  attr_endp is %p.  endp is %p", peer->host, type, length, size, attr_endp, endp); +	  bgp_notify_send (peer,  +			   BGP_NOTIFY_UPDATE_ERR,  +			   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); +	  return -1; +	} + +      /* OK check attribute and store it's value. */ +      switch (type) +	{ +	case BGP_ATTR_ORIGIN: +	  ret = bgp_attr_origin (peer, length, attr, flag, startp); +	  break; +	case BGP_ATTR_AS_PATH: +	  ret = bgp_attr_aspath (peer, length, attr, flag, startp); +	  break; +	case BGP_ATTR_NEXT_HOP:	 +	  ret = bgp_attr_nexthop (peer, length, attr, flag, startp); +	  break; +	case BGP_ATTR_MULTI_EXIT_DISC: +	  ret = bgp_attr_med (peer, length, attr, flag, startp); +	  break; +	case BGP_ATTR_LOCAL_PREF: +	  ret = bgp_attr_local_pref (peer, length, attr, flag); +	  break; +	case BGP_ATTR_ATOMIC_AGGREGATE: +	  ret = bgp_attr_atomic (peer, length, attr, flag); +	  break; +	case BGP_ATTR_AGGREGATOR: +	  ret = bgp_attr_aggregator (peer, length, attr, flag); +	  break; +	case BGP_ATTR_COMMUNITIES: +	  ret = bgp_attr_community (peer, length, attr, flag); +	  break; +	case BGP_ATTR_ORIGINATOR_ID: +	  ret = bgp_attr_originator_id (peer, length, attr, flag); +	  break; +	case BGP_ATTR_CLUSTER_LIST: +	  ret = bgp_attr_cluster_list (peer, length, attr, flag); +	  break; +	case BGP_ATTR_MP_REACH_NLRI: +	  ret = bgp_mp_reach_parse (peer, length, attr, mp_update); +	  break; +	case BGP_ATTR_MP_UNREACH_NLRI: +	  ret = bgp_mp_unreach_parse (peer, length, mp_withdraw); +	  break; +	case BGP_ATTR_EXT_COMMUNITIES: +	  ret = bgp_attr_ext_communities (peer, length, attr, flag); +	  break; +	default: +	  ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); +	  break; +	} + +      /* If error occured immediately return to the caller. */ +      if (ret < 0) +	return ret; + +      /* Check the fetched length. */ +      if (BGP_INPUT_PNT (peer) != attr_endp) +	{ +	  zlog (peer->log, LOG_WARNING,  +		"%s BGP attribute fetch error", peer->host); +	  bgp_notify_send (peer,  +			   BGP_NOTIFY_UPDATE_ERR,  +			   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); +	  return -1; +	} +    } + +  /* Check final read pointer is same as end pointer. */ +  if (BGP_INPUT_PNT (peer) != endp) +    { +      zlog (peer->log, LOG_WARNING,  +	    "%s BGP attribute length mismatch", peer->host); +      bgp_notify_send (peer,  +		       BGP_NOTIFY_UPDATE_ERR,  +		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); +      return -1; +    } + +  /* Finally intern unknown attribute. */ +  if (attr->transit) +    attr->transit = transit_intern (attr->transit); + +  return 0; +} + +/* Well-known attribute check. */ +int +bgp_attr_check (struct peer *peer, struct attr *attr) +{ +  u_char type = 0; +   +  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) +    type = BGP_ATTR_ORIGIN; + +  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) +    type = BGP_ATTR_AS_PATH; + +  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) +    type = BGP_ATTR_NEXT_HOP; + +  if (peer_sort (peer) == BGP_PEER_IBGP +      && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) +    type = BGP_ATTR_LOCAL_PREF; + +  if (type) +    { +      zlog (peer->log, LOG_WARNING,  +	    "%s Missing well-known attribute %d.", +	    peer->host, type); +      bgp_notify_send_with_data (peer,  +				 BGP_NOTIFY_UPDATE_ERR,  +				 BGP_NOTIFY_UPDATE_MISS_ATTR, +				 &type, 1); +      return -1; +    } +  return 0; +} + +int stream_put_prefix (struct stream *, struct prefix *); + +/* Make attribute packet. */ +bgp_size_t +bgp_packet_attribute (struct bgp *bgp, struct peer *peer, +		      struct stream *s, struct attr *attr, struct prefix *p, +		      afi_t afi, safi_t safi, struct peer *from, +		      struct prefix_rd *prd, u_char *tag) +{ +  unsigned long cp; +  struct aspath *aspath; + +  if (! bgp) +    bgp = bgp_get_default (); + +  /* Remember current pointer. */ +  cp = stream_get_putp (s); + +  /* Origin attribute. */ +  stream_putc (s, BGP_ATTR_FLAG_TRANS); +  stream_putc (s, BGP_ATTR_ORIGIN); +  stream_putc (s, 1); +  stream_putc (s, attr->origin); + +  /* AS path attribute. */ + +  /* If remote-peer is EBGP */ +  if (peer_sort (peer) == BGP_PEER_EBGP +      && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) +	  || attr->aspath->length == 0) +      && ! (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) +	    && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))) +    {     +      aspath = aspath_dup (attr->aspath); + +      if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) +	{ +	  /* Strip the confed info, and then stuff our path CONFED_ID +	     on the front */ +	  aspath = aspath_delete_confed_seq (aspath); +	  aspath = aspath_add_seq (aspath, bgp->confed_id); +	} +      else +	{ +	  aspath = aspath_add_seq (aspath, peer->local_as); +	  if (peer->change_local_as) +	    aspath = aspath_add_seq (aspath, peer->change_local_as); +	} +    } +  else if (peer_sort (peer) == BGP_PEER_CONFED) +    { +      /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */ +      aspath = aspath_dup (attr->aspath); +      aspath = aspath_add_confed_seq (aspath, peer->local_as); +    } +  else +    aspath = attr->aspath; + +  /* AS path attribute extended length bit check. */ +  if (aspath->length > 255) +    { +      stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); +      stream_putc (s, BGP_ATTR_AS_PATH); +      stream_putw (s, aspath->length); +    } +  else +    { +      stream_putc (s, BGP_ATTR_FLAG_TRANS); +      stream_putc(s, BGP_ATTR_AS_PATH); +      stream_putc (s, aspath->length); +    } +  stream_put (s, aspath->data, aspath->length); + +  if (aspath != attr->aspath) +    aspath_free (aspath); + +  /* Nexthop attribute. */ +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP) +    { +      stream_putc (s, BGP_ATTR_FLAG_TRANS); +      stream_putc (s, BGP_ATTR_NEXT_HOP); +      stream_putc (s, 4); +      if (safi == SAFI_MPLS_VPN) +	{ +	  if (attr->nexthop.s_addr == 0) +	    stream_put_ipv4 (s, peer->nexthop.v4.s_addr); +	  else +	    stream_put_ipv4 (s, attr->nexthop.s_addr); +	} +      else +	stream_put_ipv4 (s, attr->nexthop.s_addr); +    } + +  /* MED attribute. */ +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) +    { +      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); +      stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC); +      stream_putc (s, 4); +      stream_putl (s, attr->med); +    } + +  /* Local preference. */ +  if (peer_sort (peer) == BGP_PEER_IBGP || +      peer_sort (peer) == BGP_PEER_CONFED) +    { +      stream_putc (s, BGP_ATTR_FLAG_TRANS); +      stream_putc (s, BGP_ATTR_LOCAL_PREF); +      stream_putc (s, 4); +      stream_putl (s, attr->local_pref); +    } + +  /* Atomic aggregate. */ +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE)) +    { +      stream_putc (s, BGP_ATTR_FLAG_TRANS); +      stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE); +      stream_putc (s, 0); +    } + +  /* Aggregator. */ +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)) +    { +      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); +      stream_putc (s, BGP_ATTR_AGGREGATOR); +      stream_putc (s, 6); +      stream_putw (s, attr->aggregator_as); +      stream_put_ipv4 (s, attr->aggregator_addr.s_addr); +    } + +  /* Community attribute. */ +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)  +      && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))) +    { +      if (attr->community->size * 4 > 255) +	{ +	  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); +	  stream_putc (s, BGP_ATTR_COMMUNITIES); +	  stream_putw (s, attr->community->size * 4); +	} +      else +	{ +	  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); +	  stream_putc (s, BGP_ATTR_COMMUNITIES); +	  stream_putc (s, attr->community->size * 4); +	} +      stream_put (s, attr->community->val, attr->community->size * 4); +    } + +  /* Route Reflector. */ +  if (peer_sort (peer) == BGP_PEER_IBGP +      && from +      && peer_sort (from) == BGP_PEER_IBGP) +    { +      /* Originator ID. */ +      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); +      stream_putc (s, BGP_ATTR_ORIGINATOR_ID); +      stream_putc (s, 4); + +      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) +	stream_put_in_addr (s, &attr->originator_id); +      else +	{ +	  if (from) +	    stream_put_in_addr (s, &from->remote_id); +	  else +	    stream_put_in_addr (s, &attr->originator_id); +	} + +      /* Cluster list. */ +      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); +      stream_putc (s, BGP_ATTR_CLUSTER_LIST); +       +      if (attr->cluster) +	{ +	  stream_putc (s, attr->cluster->length + 4); +	  /* If this peer configuration's parent BGP has cluster_id. */ +	  if (bgp->config & BGP_CONFIG_CLUSTER_ID) +	    stream_put_in_addr (s, &bgp->cluster_id); +	  else +	    stream_put_in_addr (s, &bgp->router_id); +	  stream_put (s, attr->cluster->list, attr->cluster->length); +	} +      else +	{ +	  stream_putc (s, 4); +	  /* If this peer configuration's parent BGP has cluster_id. */ +	  if (bgp->config & BGP_CONFIG_CLUSTER_ID) +	    stream_put_in_addr (s, &bgp->cluster_id); +	  else +	    stream_put_in_addr (s, &bgp->router_id); +	} +    } + +#ifdef HAVE_IPV6 +  /* If p is IPv6 address put it into attribute. */ +  if (p->family == AF_INET6) +    { +      unsigned long sizep; +      unsigned long draftp = 0; + +      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); +      stream_putc (s, BGP_ATTR_MP_REACH_NLRI); +      sizep = stream_get_putp (s); +      stream_putc (s, 0);	/* Length of this attribute. */ +      stream_putw (s, AFI_IP6);	/* AFI */ +      stream_putc (s, safi);	/* SAFI */ + +      stream_putc (s, attr->mp_nexthop_len); + +      if (attr->mp_nexthop_len == 16) +	stream_put (s, &attr->mp_nexthop_global, 16); +      else if (attr->mp_nexthop_len == 32) +	{ +	  stream_put (s, &attr->mp_nexthop_global, 16); +	  stream_put (s, &attr->mp_nexthop_local, 16); +	} +       +      /* SNPA */ +      stream_putc (s, 0); + +      /* In case of old draft BGP-4+. */ +      if (peer->version == BGP_VERSION_MP_4_DRAFT_00) +	{ +	  draftp = stream_get_putp (s); +	  stream_putw (s, 0); +	} +       +      /* Prefix write. */ +      stream_put_prefix (s, p); + +      /* Set MP attribute length. */ +      stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1); + +      /* In case of old draft BGP-4+. */ +      if (peer->version == BGP_VERSION_MP_4_DRAFT_00) +	stream_putw_at (s, draftp, (stream_get_putp (s) - draftp) - 2); +    } +#endif /* HAVE_IPV6 */ + +  if (p->family == AF_INET && safi == SAFI_MULTICAST) +    { +      unsigned long sizep; +      unsigned long draftp = 0; + +      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); +      stream_putc (s, BGP_ATTR_MP_REACH_NLRI); +      sizep = stream_get_putp (s); +      stream_putc (s, 0);	/* Length of this attribute. */ +      stream_putw (s, AFI_IP);	/* AFI */ +      stream_putc (s, SAFI_MULTICAST);	/* SAFI */ + +      stream_putc (s, 4); +      stream_put_ipv4 (s, attr->nexthop.s_addr); + +      /* SNPA */ +      stream_putc (s, 0); + +      /* In case of old draft BGP-4+. */ +      if (peer->version == BGP_VERSION_MP_4_DRAFT_00) +	{ +	  draftp = stream_get_putp (s); +	  stream_putw (s, 0); +	} +       +      /* Prefix write. */ +      stream_put_prefix (s, p); + +      /* Set MP attribute length. */ +      stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1); + +      /* In case of old draft BGP-4+. */ +      if (peer->version == BGP_VERSION_MP_4_DRAFT_00) +	stream_putw_at (s, draftp, (stream_get_putp (s) - draftp) - 2); +    } + +  if (p->family == AF_INET && safi == SAFI_MPLS_VPN) +    { +      unsigned long sizep; +      unsigned long draftp = 0; + +      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); +      stream_putc (s, BGP_ATTR_MP_REACH_NLRI); +      sizep = stream_get_putp (s); +      stream_putc (s, 0);	/* Length of this attribute. */ +      stream_putw (s, AFI_IP);	/* AFI */ +      stream_putc (s, BGP_SAFI_VPNV4);	/* SAFI */ + +      stream_putc (s, 12); +      stream_putl (s, 0); +      stream_putl (s, 0); +      stream_put (s, &attr->mp_nexthop_global_in, 4); + +      /* SNPA */ +      stream_putc (s, 0); + +      /* In case of old draft BGP-4+. */ +      if (peer->version == BGP_VERSION_MP_4_DRAFT_00) +	{ +	  draftp = stream_get_putp (s); +	  stream_putw (s, 0); +	} +       +      /* Tag, RD, Prefix write. */ +      stream_putc (s, p->prefixlen + 88); +      stream_put (s, tag, 3); +      stream_put (s, prd->val, 8); +      stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); + +      /* Set MP attribute length. */ +      stream_putc_at (s, sizep, (stream_get_putp (s) - sizep) - 1); + +      /* In case of old draft BGP-4+. */ +      if (peer->version == BGP_VERSION_MP_4_DRAFT_00) +	stream_putw_at (s, draftp, (stream_get_putp (s) - draftp) - 2); +    } + +  /* Extended Communities attribute. */ +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)  +      && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) +    { +      if (attr->ecommunity->size * 8 > 255) +	{ +	  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); +	  stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); +	  stream_putw (s, attr->ecommunity->size * 8); +	} +      else +	{ +	  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); +	  stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); +	  stream_putc (s, attr->ecommunity->size * 8); +	} +      stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8); +    } + +  /* Unknown transit attribute. */ +  if (attr->transit) +    stream_put (s, attr->transit->val, attr->transit->length); + +  /* Return total size of attribute. */ +  return stream_get_putp (s) - cp; +} + +bgp_size_t +bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, +		     afi_t afi, safi_t safi, struct prefix_rd *prd, +		     u_char *tag) +{ +  unsigned long cp; +  unsigned long attrlen_pnt; +  bgp_size_t size; + +  cp = stream_get_putp (s); + +  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); +  stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI); + +  attrlen_pnt = stream_get_putp (s); +  stream_putc (s, 0);		/* Length of this attribute. */ + +  stream_putw (s, family2afi (p->family)); + +  if (safi == SAFI_MPLS_VPN) +    { +      /* SAFI */ +      stream_putc (s, BGP_SAFI_VPNV4); + +      /* prefix. */ +      stream_putc (s, p->prefixlen + 88); +      stream_put (s, tag, 3); +      stream_put (s, prd->val, 8); +      stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); +    } +  else +    { +      /* SAFI */ +      stream_putc (s, safi); + +      /* prefix */ +      stream_put_prefix (s, p); +    } + +  /* Set MP attribute length. */ +  size = stream_get_putp (s) - attrlen_pnt - 1; +  stream_putc_at (s, attrlen_pnt, size); + +  return stream_get_putp (s) - cp; +} + +/* Initialization of attribute. */ +void +bgp_attr_init () +{ +  void attrhash_init (); + +  aspath_init (); +  attrhash_init (); +  community_init (); +  ecommunity_init (); +  cluster_init (); +  transit_init (); +} + +/* Make attribute packet. */ +void +bgp_dump_routes_attr (struct stream *s, struct attr *attr) +{ +  unsigned long cp; +  unsigned long len; +  struct aspath *aspath; + +  /* Remember current pointer. */ +  cp = stream_get_putp (s); + +  /* Place holder of length. */ +  stream_putw (s, 0); + +  /* Origin attribute. */ +  stream_putc (s, BGP_ATTR_FLAG_TRANS); +  stream_putc (s, BGP_ATTR_ORIGIN); +  stream_putc (s, 1); +  stream_putc (s, attr->origin); + +  aspath = attr->aspath; + +  if (aspath->length > 255) +    { +      stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); +      stream_putc (s, BGP_ATTR_AS_PATH); +      stream_putw (s, aspath->length); +    } +  else +    { +      stream_putc (s, BGP_ATTR_FLAG_TRANS); +      stream_putc (s, BGP_ATTR_AS_PATH); +      stream_putc (s, aspath->length); +    } +  stream_put (s, aspath->data, aspath->length); + +  /* Nexthop attribute. */ +  stream_putc (s, BGP_ATTR_FLAG_TRANS); +  stream_putc (s, BGP_ATTR_NEXT_HOP); +  stream_putc (s, 4); +  stream_put_ipv4 (s, attr->nexthop.s_addr); + +  /* MED attribute. */ +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) +    { +      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); +      stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC); +      stream_putc (s, 4); +      stream_putl (s, attr->med); +    } + +  /* Local preference. */ +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) +    { +      stream_putc (s, BGP_ATTR_FLAG_TRANS); +      stream_putc (s, BGP_ATTR_LOCAL_PREF); +      stream_putc (s, 4); +      stream_putl (s, attr->local_pref); +    } + +  /* Atomic aggregate. */ +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE)) +    { +      stream_putc (s, BGP_ATTR_FLAG_TRANS); +      stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE); +      stream_putc (s, 0); +    } + +  /* Aggregator. */ +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)) +    { +      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); +      stream_putc (s, BGP_ATTR_AGGREGATOR); +      stream_putc (s, 6); +      stream_putw (s, attr->aggregator_as); +      stream_put_ipv4 (s, attr->aggregator_addr.s_addr); +    } + +  /* Community attribute. */ +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)) +    { +      if (attr->community->size * 4 > 255) +	{ +	  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); +	  stream_putc (s, BGP_ATTR_COMMUNITIES); +	  stream_putw (s, attr->community->size * 4); +	} +      else +	{ +	  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); +	  stream_putc (s, BGP_ATTR_COMMUNITIES); +	  stream_putc (s, attr->community->size * 4); +	} +      stream_put (s, attr->community->val, attr->community->size * 4); +    } + +  /* Return total size of attribute. */ +  len = stream_get_putp (s) - cp - 2; +  stream_putw_at (s, cp, len); +} diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h new file mode 100644 index 0000000000..9c5bf87913 --- /dev/null +++ b/bgpd/bgp_attr.h @@ -0,0 +1,125 @@ +/* BGP attributes.  +   Copyright (C) 1996, 97, 98 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +/* Simple bit mapping. */ +#define BITMAP_NBBY 8 + +#define SET_BITMAP(MAP, NUM) \ +        SET_FLAG (MAP[(NUM) / BITMAP_NBBY], 1 << ((NUM) % BITMAP_NBBY)) + +#define CHECK_BITMAP(MAP, NUM) \ +        CHECK_FLAG (MAP[(NUM) / BITMAP_NBBY], 1 << ((NUM) % BITMAP_NBBY)) + +/* BGP Attribute type range. */ +#define BGP_ATTR_TYPE_RANGE     256 +#define BGP_ATTR_BITMAP_SIZE    (BGP_ATTR_TYPE_RANGE / BITMAP_NBBY) + +/* BGP Attribute flags. */ +#define BGP_ATTR_FLAG_OPTIONAL  0x80	/* Attribute is optional. */ +#define BGP_ATTR_FLAG_TRANS     0x40	/* Attribute is transitive. */ +#define BGP_ATTR_FLAG_PARTIAL   0x20	/* Attribute is partial. */ +#define BGP_ATTR_FLAG_EXTLEN    0x10	/* Extended length flag. */ + +/* BGP attribute header must bigger than 2. */ +#define BGP_ATTR_MIN_LEN        2       /* Attribute flag and type. */ + +/* BGP attribute structure. */ +struct attr +{ +  /* Reference count of this attribute. */ +  unsigned long refcnt; + +  /* Flag of attribute is set or not. */ +  u_int32_t flag; + +  /* Attributes. */ +  u_char origin; +  struct in_addr nexthop; +  u_int32_t med; +  u_int32_t local_pref; +  as_t aggregator_as; +  struct in_addr aggregator_addr; +  u_int32_t weight; +  struct in_addr originator_id; +  struct cluster_list *cluster; + +  u_char mp_nexthop_len; +#ifdef HAVE_IPV6 +  struct in6_addr mp_nexthop_global; +  struct in6_addr mp_nexthop_local; +#endif /* HAVE_IPV6 */ +  struct in_addr mp_nexthop_global_in; +  struct in_addr mp_nexthop_local_in; + +  /* AS Path structure */ +  struct aspath *aspath; + +  /* Community structure */ +  struct community *community;	 + +  /* Extended Communities attribute. */ +  struct ecommunity *ecommunity; + +  /* Unknown transitive attribute. */ +  struct transit *transit; +}; + +/* Router Reflector related structure. */ +struct cluster_list +{ +  unsigned long refcnt; +  int length; +  struct in_addr *list; +}; + +/* Unknown transit attribute. */ +struct transit +{ +  unsigned long refcnt; +  int length; +  u_char *val; +}; + +#define ATTR_FLAG_BIT(X)  (1 << ((X) - 1)) + +/* Prototypes. */ +void bgp_attr_init (); +int bgp_attr_parse (struct peer *, struct attr *, bgp_size_t, +		    struct bgp_nlri *, struct bgp_nlri *); +int bgp_attr_check (struct peer *, struct attr *); +struct attr *bgp_attr_intern (struct attr *attr); +void bgp_attr_unintern (struct attr *); +void bgp_attr_flush (struct attr *); +struct attr *bgp_attr_default_set (struct attr *attr, u_char); +struct attr *bgp_attr_default_intern (u_char); +struct attr *bgp_attr_aggregate_intern (struct bgp *, u_char, struct aspath *, struct community *, int as_set); +bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *, struct stream *, struct attr *, struct prefix *, afi_t, safi_t, struct peer *, struct prefix_rd *, u_char *); +bgp_size_t bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, afi_t, safi_t, struct prefix_rd *, u_char *); +void bgp_dump_routes_attr (struct stream *, struct attr *); +unsigned int attrhash_key_make (struct attr *); +int attrhash_cmp (struct attr *, struct attr *); +void attr_show_all (struct vty *); + +/* Cluster list prototypes. */ +int cluster_loop_check (struct cluster_list *, struct in_addr); +void cluster_unintern (struct cluster_list *); + +/* Transit attribute prototypes. */ +void transit_unintern (struct transit *); diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c new file mode 100644 index 0000000000..7c70881451 --- /dev/null +++ b/bgpd/bgp_btoa.c @@ -0,0 +1,291 @@ +/* BGP dump to ascii converter +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "zebra.h" +#include "stream.h" +#include "log.h" +#include "prefix.h" +#include "command.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_dump.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_aspath.h" + +enum MRT_MSG_TYPES { +   MSG_NULL, +   MSG_START,                   /* sender is starting up */ +   MSG_DIE,                     /* receiver should shut down */ +   MSG_I_AM_DEAD,               /* sender is shutting down */ +   MSG_PEER_DOWN,               /* sender's peer is down */ +   MSG_PROTOCOL_BGP,            /* msg is a BGP packet */ +   MSG_PROTOCOL_RIP,            /* msg is a RIP packet */ +   MSG_PROTOCOL_IDRP,           /* msg is an IDRP packet */ +   MSG_PROTOCOL_RIPNG,          /* msg is a RIPNG packet */ +   MSG_PROTOCOL_BGP4PLUS,       /* msg is a BGP4+ packet */ +   MSG_PROTOCOL_BGP4PLUS_01,    /* msg is a BGP4+ (draft 01) packet */ +   MSG_PROTOCOL_OSPF,           /* msg is an OSPF packet */ +   MSG_TABLE_DUMP               /* routing table dump */ +}; + +int +attr_parse (struct stream *s, u_int16_t len) +{ +  u_int flag; +  u_int type; +  u_int16_t length; +  u_int16_t lim; + +  lim = s->getp + len; + +  printf ("attr_parse s->getp %d, len %d, lim %d\n", s->getp, len, lim); + +  while (s->getp < lim) +    { +      flag = stream_getc (s); +      type = stream_getc (s); + +      if (flag & ATTR_FLAG_EXTLEN) +	length = stream_getw (s); +      else +	length = stream_getc (s); + +      printf ("FLAG: %d\n", flag); +      printf ("TYPE: %d\n", type); +      printf ("Len: %d\n", length); + +      switch (type) +	{ +	case BGP_ATTR_ORIGIN: +	  { +	    u_char origin; +	    origin = stream_getc (s); +	    printf ("ORIGIN: %d\n", origin); +	  } +	  break; +	case BGP_ATTR_AS_PATH: +	  { +	    struct aspath aspath; + +	    aspath.data = (s->data + s->getp); +	    aspath.length = length; +	    aspath.str = aspath_make_str_count (&aspath); +	    printf ("ASPATH: %s\n", aspath.str); +	    free (aspath.str); +	     +	    stream_forward (s, length); +	  } +	  break; +	case BGP_ATTR_NEXT_HOP:	 +	  { +	    struct in_addr nexthop; +	    nexthop.s_addr = stream_get_ipv4 (s); +	    printf ("NEXTHOP: %s\n", inet_ntoa (nexthop)); +	    /* stream_forward (s, length); */ +	  } +	  break; +	default: +	  stream_forward (s, length); +	  break; +	} +    } + +  return 0; +} + +int +main (int argc, char **argv) +{ +  int ret; +  FILE *fp; +  struct stream *s; +  time_t now; +  int type; +  int subtype; +  int len; +  int source_as; +  int dest_as; +  int ifindex; +  int family; +  struct in_addr sip; +  struct in_addr dip; +  u_int16_t viewno, seq_num; +  struct prefix_ipv4 p; + +  s = stream_new (10000); + +  if (argc != 2) +    { +      fprintf (stderr, "Usage: %s FILENAME\n", argv[0]); +      exit (1); +    } +  fp = fopen (argv[1], "r"); +  if (!fp) +    { +      perror ("fopen"); +      exit (1); +    } +   +  while (1) +    { +      stream_reset (s); + +      ret = fread (s->data, 12, 1, fp); +      if (feof (fp)) +	{ +	  printf ("END OF FILE\n"); +	  break; +	} +      if (ferror (fp)) +	{ +	  printf ("ERROR OF FREAD\n"); +	  break; +	} + +      /* Extract header. */ +      now = stream_getl (s); +      type = stream_getw (s); +      subtype = stream_getw (s); +      len = stream_getl (s); + +      printf ("TIME: %s", ctime (&now)); + +      /* printf ("TYPE: %d/%d\n", type, subtype); */ + +      if (type == MSG_PROTOCOL_BGP4MP) +	printf ("TYPE: BGP4MP"); +      else if (type == MSG_TABLE_DUMP) +	printf ("TYPE: MSG_TABLE_DUMP"); +      else +	printf ("TYPE: Unknown %d", type); + +      if (type == MSG_TABLE_DUMP) +	switch (subtype) +	  { +	  case AFI_IP: +	    printf ("/AFI_IP\n"); +	    break; +	  case AFI_IP6: +	    printf ("/AFI_IP6\n"); +	    break; +	  default: +	    printf ("/UNKNOWN %d", subtype); +	    break; +	  } +      else +	{ +	  switch (subtype) +	    { +	    case BGP4MP_STATE_CHANGE: +	      printf ("/CHANGE\n"); +	      break; +	    case BGP4MP_MESSAGE: +	      printf ("/MESSAGE\n"); +	      break; +	    case BGP4MP_ENTRY: +	      printf ("/ENTRY\n"); +	      break; +	    case BGP4MP_SNAPSHOT: +	      printf ("/SNAPSHOT\n"); +	      break; +	    default: +	      printf ("/UNKNOWN %d", subtype); +	      break; +	    } +	} + +      printf ("len: %d\n", len); + +      ret = fread (s->data + 12, len, 1, fp); +      if (feof (fp)) +	{ +	  printf ("ENDOF FILE 2\n"); +	  break; +	} +      if (ferror (fp)) +	{ +	  printf ("ERROR OF FREAD 2\n"); +	  break; +	} + +      /* printf ("now read %d\n", len); */ + +      if (type == MSG_TABLE_DUMP) +	{ +	  u_char status; +	  time_t originated; +	  struct in_addr peer; +	  u_int16_t attrlen; + +	  viewno = stream_getw (s); +	  seq_num = stream_getw (s); +	  printf ("VIEW: %d\n", viewno); +	  printf ("SEQUENCE: %d\n", seq_num); + +	  /* start */ +	  while (s->getp < len - 16) +	    { +	      p.prefix.s_addr = stream_get_ipv4 (s); +	      p.prefixlen = stream_getc (s); +	      printf ("PREFIX: %s/%d\n", inet_ntoa (p.prefix), p.prefixlen); + +	      status = stream_getc (s); +	      originated = stream_getl (s); +	      peer.s_addr = stream_get_ipv4 (s); +	      source_as = stream_getw(s); + +	      printf ("FROM: %s AS%d\n", inet_ntoa (peer), source_as); +	      printf ("ORIGINATED: %s", ctime (&originated)); + +	      attrlen = stream_getw (s); +	      printf ("ATTRLEN: %d\n", attrlen); + +	      attr_parse (s, attrlen); + +	      printf ("STATUS: 0x%x\n", status); +	    } +	} +      else +	{ +	  source_as = stream_getw (s); +	  dest_as = stream_getw (s); +	  printf ("source_as: %d\n", source_as); +	  printf ("dest_as: %d\n", dest_as); + +	  ifindex = stream_getw (s); +	  family = stream_getw (s); + +	  printf ("ifindex: %d\n", ifindex); +	  printf ("family: %d\n", family); + +	  sip.s_addr = stream_get_ipv4 (s); +	  dip.s_addr = stream_get_ipv4 (s); +	   +	  printf ("saddr: %s\n", inet_ntoa (sip)); +	  printf ("daddr: %s\n", inet_ntoa (dip)); + +	  printf ("\n"); +	} +    } +  fclose (fp); +  return 0; +} diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c new file mode 100644 index 0000000000..0b6a2e8cce --- /dev/null +++ b/bgpd/bgp_clist.c @@ -0,0 +1,905 @@ +/* BGP community-list and extcommunity-list. +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "command.h" +#include "prefix.h" +#include "memory.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_clist.h" + +/* Lookup master structure for community-list or +   extcommunity-list.  */ +struct community_list_master * +community_list_master_lookup (struct community_list_handler *ch, int style) +{ +  if (ch) +    switch (style) +      { +      case COMMUNITY_LIST_STANDARD: +      case COMMUNITY_LIST_EXPANDED: +      case COMMUNITY_LIST_AUTO: +	return &ch->community_list; +	break; +      case EXTCOMMUNITY_LIST_STANDARD: +      case EXTCOMMUNITY_LIST_EXPANDED: +      case EXTCOMMUNITY_LIST_AUTO: +	return &ch->extcommunity_list; +      } +  return NULL; +} + +/* Allocate a new community list entry.  */ +struct community_entry * +community_entry_new () +{ +  struct community_entry *new; + +  new = XMALLOC (MTYPE_COMMUNITY_LIST_ENTRY, sizeof (struct community_entry)); +  memset (new, 0, sizeof (struct community_entry)); +  return new; +} + +/* Free community list entry.  */ +void +community_entry_free (struct community_entry *entry) +{ +  switch (entry->style) +    { +    case COMMUNITY_LIST_STANDARD: +      if (entry->u.com) +	community_free (entry->u.com); +      break; +    case EXTCOMMUNITY_LIST_STANDARD: +      /* In case of standard extcommunity-list, configuration string +	 is made by ecommunity_ecom2str().  */ +      if (entry->config) +	XFREE (MTYPE_ECOMMUNITY_STR, entry->config); +      if (entry->u.ecom) +	ecommunity_free (entry->u.ecom); +      break; +    case COMMUNITY_LIST_EXPANDED: +    case EXTCOMMUNITY_LIST_EXPANDED: +      if (entry->config) +	XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config); +      if (entry->reg) +	bgp_regex_free (entry->reg); +    default: +      break; +    } +  XFREE (MTYPE_COMMUNITY_LIST_ENTRY, entry); +} + +/* Allocate a new community-list.  */ +struct community_list * +community_list_new () +{ +  struct community_list *new; + +  new = XMALLOC (MTYPE_COMMUNITY_LIST, sizeof (struct community_list)); +  memset (new, 0, sizeof (struct community_list)); +  return new; +} + +/* Free community-list.  */ +void +community_list_free (struct community_list *list) +{ +  if (list->name) +    XFREE (MTYPE_COMMUNITY_LIST_NAME, list->name); +  XFREE (MTYPE_COMMUNITY_LIST, list); +} + +struct community_list * +community_list_insert (struct community_list_handler *ch, +		       char *name, int style) +{ +  int i; +  long number; +  struct community_list *new; +  struct community_list *point; +  struct community_list_list *list; +  struct community_list_master *cm; + +  /* Lookup community-list master.  */ +  cm = community_list_master_lookup (ch, style); +  if (! cm) +    return NULL; + +  /* Allocate new community_list and copy given name. */ +  new = community_list_new (); +  new->name = XSTRDUP (MTYPE_COMMUNITY_LIST_NAME, name); + +  /* If name is made by all digit character.  We treat it as +     number. */ +  for (number = 0, i = 0; i < strlen (name); i++) +    { +      if (isdigit ((int) name[i])) +	number = (number * 10) + (name[i] - '0'); +      else +	break; +    } + +  /* In case of name is all digit character */ +  if (i == strlen (name)) +    { +      new->sort = COMMUNITY_LIST_NUMBER; + +      /* Set access_list to number list. */ +      list = &cm->num; + +      for (point = list->head; point; point = point->next) +	if (atol (point->name) >= number) +	  break; +    } +  else +    { +      new->sort = COMMUNITY_LIST_STRING; + +      /* Set access_list to string list. */ +      list = &cm->str; +   +      /* Set point to insertion point. */ +      for (point = list->head; point; point = point->next) +	if (strcmp (point->name, name) >= 0) +	  break; +    } + +  /* Link to upper list.  */ +  new->parent = list; + +  /* In case of this is the first element of master. */ +  if (list->head == NULL) +    { +      list->head = list->tail = new; +      return new; +    } + +  /* In case of insertion is made at the tail of access_list. */ +  if (point == NULL) +    { +      new->prev = list->tail; +      list->tail->next = new; +      list->tail = new; +      return new; +    } + +  /* In case of insertion is made at the head of access_list. */ +  if (point == list->head) +    { +      new->next = list->head; +      list->head->prev = new; +      list->head = new; +      return new; +    } + +  /* Insertion is made at middle of the access_list. */ +  new->next = point; +  new->prev = point->prev; + +  if (point->prev) +    point->prev->next = new; +  point->prev = new; + +  return new; +} + +struct community_list * +community_list_lookup (struct community_list_handler *ch, +		       char *name, int style) +{ +  struct community_list *list; +  struct community_list_master *cm; + +  if (! name) +    return NULL; + +  cm = community_list_master_lookup (ch, style); +  if (! cm) +    return NULL; + +  for (list = cm->num.head; list; list = list->next) +    if (strcmp (list->name, name) == 0) +      return list; +  for (list = cm->str.head; list; list = list->next) +    if (strcmp (list->name, name) == 0) +      return list; + +  return NULL; +} + +struct community_list * +community_list_get (struct community_list_handler *ch, char *name, int style) +{ +  struct community_list *list; + +  list = community_list_lookup (ch, name, style); +  if (! list) +    list = community_list_insert (ch, name, style); +  return list; +} + +void +community_list_delete (struct community_list *list) +{ +  struct community_list_list *clist; +  struct community_entry *entry, *next; + +  for (entry = list->head; entry; entry = next) +    { +      next = entry->next; +      community_entry_free (entry); +    } + +  clist = list->parent; + +  if (list->next) +    list->next->prev = list->prev; +  else +    clist->tail = list->prev; + +  if (list->prev) +    list->prev->next = list->next; +  else +    clist->head = list->next; + +  community_list_free (list); +} + +int  +community_list_empty_p (struct community_list *list) +{ +  return (list->head == NULL && list->tail == NULL) ? 1 : 0; +} + +/* Add community-list entry to the list.  */ +static void +community_list_entry_add (struct community_list *list,  +			  struct community_entry *entry) +{ +  entry->next = NULL; +  entry->prev = list->tail; + +  if (list->tail) +    list->tail->next = entry; +  else +    list->head = entry; +  list->tail = entry; +} + +/* Delete community-list entry from the list.  */ +static void +community_list_entry_delete (struct community_list *list, +			     struct community_entry *entry, int style) +{ +  if (entry->next) +    entry->next->prev = entry->prev; +  else +    list->tail = entry->prev; + +  if (entry->prev) +    entry->prev->next = entry->next; +  else +    list->head = entry->next; + +  community_entry_free (entry); + +  if (community_list_empty_p (list)) +    community_list_delete (list); +} + +/* Lookup community-list entry from the list.  */ +static struct community_entry * +community_list_entry_lookup (struct community_list *list, void *arg, +			     int direct) +{ +  struct community_entry *entry; + +  for (entry = list->head; entry; entry = entry->next) +    { +      switch (entry->style) +	{ +	case COMMUNITY_LIST_STANDARD: +	  if (community_cmp (entry->u.com, arg)) +	    return entry; +	  break; +	case EXTCOMMUNITY_LIST_STANDARD: +	  if (ecommunity_cmp (entry->u.ecom, arg)) +	    return entry; +	  break; +	case COMMUNITY_LIST_EXPANDED: +	case EXTCOMMUNITY_LIST_EXPANDED: +	  if (strcmp (entry->config, arg) == 0) +	    return entry; +	  break; +	default: +	  break; +	} +    } +  return NULL; +} + +/* Internal function to perform regular expression match for community +   attribute.  */ +static int +community_regexp_match (struct community *com, regex_t *reg) +{ +  char *str; + +  /* When there is no communities attribute it is treated as empty +     string.  */ +  if (com == NULL || com->size == 0) +    str = ""; +  else +    str = community_str (com); + +  /* Regular expression match.  */ +  if (regexec (reg, str, 0, NULL, 0) == 0) +    return 1; + +  /* No match.  */ +  return 0; +} + +/* Delete community attribute using regular expression match.  Return +   modified communites attribute.  */ +static struct community * +community_regexp_delete (struct community *com, regex_t *reg) +{ +  int i; +  u_int32_t comval; +  /* Maximum is "65535:65535" + '\0'. */ +  char c[12]; +  char *str; + +  if (! com) +    return NULL; + +  i = 0; +  while (i < com->size) +    { +      memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); +      comval = ntohl (comval); + +      switch (comval) +	{ +	case COMMUNITY_INTERNET: +	  str = "internet"; +	  break; +	case COMMUNITY_NO_EXPORT: +	  str = "no-export"; +	  break; +	case COMMUNITY_NO_ADVERTISE: +	  str = "no-advertise"; +	  break; +	case COMMUNITY_LOCAL_AS: +	  str = "local-AS"; +	  break; +	default: +	  sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF); +	  str = c; +	  break; +	} + +      if (regexec (reg, str, 0, NULL, 0) == 0) +	community_del_val (com, com_nthval (com, i)); +      else +	i++; +    } +  return com; +} + +/* When given community attribute matches to the community-list return +   1 else return 0.  */ +int +community_list_match (struct community *com, struct community_list *list) +{ +  struct community_entry *entry; + +  for (entry = list->head; entry; entry = entry->next) +    { +      if (entry->any) +	return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + +      if (entry->style == COMMUNITY_LIST_STANDARD) +	{ +	  if (community_include (entry->u.com, COMMUNITY_INTERNET)) +	    return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + +	  if (community_match (com, entry->u.com)) +	    return entry->direct == COMMUNITY_PERMIT ? 1 : 0; +	} +      else if (entry->style == COMMUNITY_LIST_EXPANDED) +	{ +	  if (community_regexp_match (com, entry->reg)) +	    return entry->direct == COMMUNITY_PERMIT ? 1 : 0; +	} +    } +  return 0; +} + +/* Perform exact matching.  In case of expanded community-list, do +   same thing as community_list_match().  */ +int +community_list_exact_match (struct community *com, struct community_list *list) +{ +  struct community_entry *entry; + +  for (entry = list->head; entry; entry = entry->next) +    { +      if (entry->any) +	return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + +      if (entry->style == COMMUNITY_LIST_STANDARD) +	{ +	  if (community_include (entry->u.com, COMMUNITY_INTERNET)) +	    return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + +	  if (community_cmp (com, entry->u.com)) +	    return entry->direct == COMMUNITY_PERMIT ? 1 : 0; +	} +      else if (entry->style == COMMUNITY_LIST_EXPANDED) +	{ +	  if (community_regexp_match (com, entry->reg)) +	    return entry->direct == COMMUNITY_PERMIT ? 1 : 0; +	} +    } +  return 0; +} + +/* Delete all permitted communities in the list from com1 */ +struct community * +community_list_match_delete (struct community *com, +			     struct community_list *list) +{ +  struct community_entry *entry; + +  for (entry = list->head; entry; entry = entry->next) +    { +      if (entry->any && entry->direct == COMMUNITY_PERMIT) +	{ +	  /* This is a tricky part.  Currently only +	     route_set_community_delete() uses this function.  In the +	     function com->size is zero, it free the community +	     structure.  */ +	  com->size = 0; +	  return com; +	} + +      if (entry->style == COMMUNITY_LIST_STANDARD) +	{ +	  if (entry->direct == COMMUNITY_PERMIT) +	    community_delete (com, entry->u.com); +	} +      else if (entry->style == COMMUNITY_LIST_EXPANDED) +	{ +	  if (entry->direct == COMMUNITY_PERMIT) +	    community_regexp_delete (com, entry->reg); +	} +    } +  return com; +} + +/* To avoid duplicated entry in the community-list, this function +   compares specified entry to existing entry.  */ +int +community_list_dup_check (struct community_list *list,  +			  struct community_entry *new) +{ +  struct community_entry *entry; +   +  for (entry = list->head; entry; entry = entry->next) +    { +      if (entry->style != new->style) +	continue; + +      if (entry->direct != new->direct) +	continue; + +      if (entry->any != new->any) +	continue; + +      if (entry->any) +	return 1; + +      switch (entry->style) +	{ +	case COMMUNITY_LIST_STANDARD: +	  if (community_cmp (entry->u.com, new->u.com)) +	    return 1; +	  break; +	case EXTCOMMUNITY_LIST_STANDARD: +	  if (ecommunity_cmp (entry->u.ecom, new->u.ecom)) +	    return 1; +	  break; +	case COMMUNITY_LIST_EXPANDED: +	case EXTCOMMUNITY_LIST_EXPANDED: +	  if (strcmp (entry->config, new->config) == 0) +	    return 1; +	  break; +	default: +	  break; +	} +    } +  return 0; +} + +/* Set community-list.  */ +int +community_list_set (struct community_list_handler *ch, +		    char *name, char *str, int direct, int style) +{ +  struct community_entry *entry; +  struct community_list *list; +  struct community *com; +  regex_t *regex; + +  entry = NULL; + +  /* Get community list. */ +  list = community_list_get (ch, name, style); + +  /* When community-list already has entry, new entry should have same +     style.  If you want to have mixed style community-list, you can +     comment out this check.  */ +  if (! community_list_empty_p (list)) +    { +      struct community_entry *first; + +      first = list->head; + +      if (style == COMMUNITY_LIST_AUTO) +	style = first->style; +      else if (style != first->style) +	{ +	  return (first->style == COMMUNITY_LIST_STANDARD +		  ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT +		  : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT); +	} +    } + +  /* When str is NULL, it is matches any.  */ +  if (! str) +    { +      entry = community_entry_new (); +      entry->direct = direct; +      entry->any = 1; +      if (style == COMMUNITY_LIST_AUTO) +	entry->style = COMMUNITY_LIST_STANDARD; +      else +	entry->style = style; +    } +  else +    { +      /* Standard community-list parse.  String must be converted into +	 community structure without problem.  */ +      if (style == COMMUNITY_LIST_STANDARD || style == COMMUNITY_LIST_AUTO) +	{ +	  com = community_str2com (str); +	  if (com) +	    { +	      entry = community_entry_new (); +	      entry->u.com = com; +	      entry->direct = direct; +	      entry->style = COMMUNITY_LIST_STANDARD; +	    } +	  else if (style == COMMUNITY_LIST_STANDARD) +	    return COMMUNITY_LIST_ERR_MALFORMED_VAL; +	   +	  /* We can't convert string into communities value.  When +	     community-list type is auto, fall dawn to regular expression +	     match.  */ +	} + +      /* Expanded community-list parse.  String may include regular +	 expression.  */ +      if (! entry && (style == COMMUNITY_LIST_EXPANDED +		      || style == COMMUNITY_LIST_AUTO)) +	{ +	  regex = bgp_regcomp (str); +	  if (regex) +	    { +	      entry = community_entry_new (); +	      entry->reg = regex; +	      entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str); +	      entry->direct = direct; +	      entry->style = COMMUNITY_LIST_EXPANDED; +	    } +	  else +	    return COMMUNITY_LIST_ERR_MALFORMED_VAL; +	} +    } + +  /* Do not put duplicated community entry.  */ +  if (community_list_dup_check (list, entry)) +    community_entry_free (entry); +  else +    community_list_entry_add (list, entry); + +  return 0; +} + +/* Unset community-list.  When str is NULL, delete all of +   community-list entry belongs to the specified name.  */ +int +community_list_unset (struct community_list_handler *ch, +		      char *name, char *str, int direct, int style) +{ +  struct community_entry *entry; +  struct community_list *list; +  struct community *com; +  regex_t *regex; + +  entry = NULL; + +  /* Lookup community list.  */ +  list = community_list_lookup (ch, name, style); +  if (list == NULL) +    return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + +  /* Delete all of entry belongs to this community-list.  */ +  if (! str) +    { +      community_list_delete (list); +      return 0; +    } + +  /* Community list string is specified.  Lookup entry from community +     list.  */ +  if (style == COMMUNITY_LIST_STANDARD || style == COMMUNITY_LIST_AUTO) +    { +      com = community_str2com (str); +      if (com) +	{ +	  entry = community_list_entry_lookup (list, com, direct); +	  community_free (com); +	} +      else if (style == COMMUNITY_LIST_STANDARD) +	return COMMUNITY_LIST_ERR_MALFORMED_VAL; + +      /* If we can't convert string into community and community-list +	 type is auto, fall dawn to expanded community-list.  */ +    } + +  /* Expanded community-list parse.  String may include regular +     expression.  */ +  if (! entry  +      && (style == COMMUNITY_LIST_EXPANDED || style == COMMUNITY_LIST_AUTO)) +    { +      regex = bgp_regcomp (str); +      if (regex) +	{ +	  entry = community_list_entry_lookup (list, str, direct); +	  bgp_regex_free (regex); +	} +      else +	return COMMUNITY_LIST_ERR_MALFORMED_VAL; +    } + +  if (! entry) +    return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + +  community_list_entry_delete (list, entry, style); + +  return 0; +} + +/* Set extcommunity-list.  */ +int +extcommunity_list_set (struct community_list_handler *ch, +		       char *name, char *str, int direct, int style) +{ +  struct community_entry *entry; +  struct community_list *list; +  struct ecommunity *ecom; +  regex_t *regex; + +  entry = NULL; + +  /* Get community list. */ +  list = community_list_get (ch, name, style); + +  /* When community-list already has entry, new entry should have same +     style.  If you want to have mixed style community-list, you can +     comment out this check.  */ +  if (! community_list_empty_p (list)) +    { +      struct community_entry *first; + +      first = list->head; + +      if (style == EXTCOMMUNITY_LIST_AUTO) +	style = first->style; +      else if (style != first->style) +	{ +	  return (first->style == EXTCOMMUNITY_LIST_STANDARD +		  ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT +		  : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT); +	} +    } + +  /* When str is NULL, it is matches any.  */ +  if (! str) +    { +      entry = community_entry_new (); +      entry->direct = direct; +      entry->any = 1; +      if (style == EXTCOMMUNITY_LIST_AUTO) +	entry->style = EXTCOMMUNITY_LIST_STANDARD; +      else +	entry->style = style; +    } +  else +    { +      /* Standard extcommunity-list parse.  String is converted into +	 ecommunity structure.  */ +      if (style == EXTCOMMUNITY_LIST_STANDARD +	  || style == EXTCOMMUNITY_LIST_AUTO) +	{ +	  /* Type is unknown.  String includes keyword.  */ +	  ecom = ecommunity_str2com (str, 0, 1); +	  if (ecom) +	    { +	      entry = community_entry_new (); +	      entry->config  +		= ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST); +	      ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY); +	      entry->u.ecom = ecom; +	      entry->direct = direct; +	      entry->style = EXTCOMMUNITY_LIST_STANDARD; +	    } +	  else if (style == EXTCOMMUNITY_LIST_STANDARD) +	    return COMMUNITY_LIST_ERR_MALFORMED_VAL; + +	  /* We can't convert string into communities value.  When +	     community-list type is auto, fall dawn to regular expression +	     match.  */ +	} + +      /* Expanded extcommunity-list parse.  String may include regular +	 expression.  */ +      if (! entry && (style == EXTCOMMUNITY_LIST_EXPANDED +		      || style == EXTCOMMUNITY_LIST_AUTO)) +	{ +	  regex = bgp_regcomp (str); +	  if (regex) +	    { +	      entry = community_entry_new (); +	      entry->reg = regex; +	      entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str); +	      entry->direct = direct; +	      entry->style = EXTCOMMUNITY_LIST_EXPANDED; +	    } +	  else +	    return COMMUNITY_LIST_ERR_MALFORMED_VAL; +	} +    } + +  /* Do not put duplicated community entry.  */ +  if (community_list_dup_check (list, entry)) +    community_entry_free (entry); +  else +    community_list_entry_add (list, entry); + +  return 0; +} + +/* Unset extcommunity-list.  When str is NULL, delete all of +   extcommunity-list entry belongs to the specified name.  */ +int +extcommunity_list_unset (struct community_list_handler *ch, +			 char *name, char *str, int direct, int style) +{ +  struct community_entry *entry; +  struct community_list *list; +  struct ecommunity *ecom = NULL; +  regex_t *regex; + +  entry = NULL; + +  /* Lookup extcommunity list.  */ +  list = community_list_lookup (ch, name, style); +  if (list == NULL) +    return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + +  /* Delete all of entry belongs to this extcommunity-list.  */ +  if (! str) +    { +      community_list_delete (list); +      return 0; +    } + +  /* Community list string is specified.  Lookup entry from community +     list.  */ +  if (style == EXTCOMMUNITY_LIST_STANDARD || style == EXTCOMMUNITY_LIST_AUTO) +    { +      ecom = ecommunity_str2com (str, 0, 1); +      if (ecom) +	{ +	  entry = community_list_entry_lookup (list, ecom, direct); +	  ecommunity_free (ecom); +	} +      else if (style == COMMUNITY_LIST_STANDARD) +	return COMMUNITY_LIST_ERR_MALFORMED_VAL; + +      /* If we can't convert string into community and community-list +	 type is auto, fall dawn to expanded community-list.  */ +    } + +  /* Expanded community-list parse.  String may include regular +     expression.  */ +  if (! entry  +      && (style == COMMUNITY_LIST_EXPANDED || style == COMMUNITY_LIST_AUTO)) +    { +      regex = bgp_regcomp (str); +      if (regex) +	{ +	  entry = community_list_entry_lookup (list, str, direct); +	  bgp_regex_free (regex); +	} +      else +	return COMMUNITY_LIST_ERR_MALFORMED_VAL; +    } + +  if (! entry) +    return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + +  community_list_entry_delete (list, entry, style); + +  return 0; +} + +/* Initializa community-list.  Return community-list handler.  */ +struct community_list_handler * +community_list_init () +{ +  struct community_list_handler *ch; +  ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER, +		sizeof (struct community_list_handler)); +  return ch; +} + +/* Terminate community-list.  */ +void +community_list_terminate (struct community_list_handler *ch) +{ +  struct community_list_master *cm; +  struct community_list *list; + +  cm = &ch->community_list; +  while ((list = cm->num.head) != NULL) +    community_list_delete (list); +  while ((list = cm->str.head) != NULL) +    community_list_delete (list); + +  cm = &ch->extcommunity_list; +  while ((list = cm->num.head) != NULL) +    community_list_delete (list); +  while ((list = cm->str.head) != NULL) +    community_list_delete (list); + +  XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch); +} diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h new file mode 100644 index 0000000000..ffc707c284 --- /dev/null +++ b/bgpd/bgp_clist.h @@ -0,0 +1,143 @@ +/* BGP Community list. +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +/* Community-list deny and permit.  */ +#define COMMUNITY_DENY                 0 +#define COMMUNITY_PERMIT               1 + +/* Number and string based community-list name.  */ +#define COMMUNITY_LIST_STRING          0 +#define COMMUNITY_LIST_NUMBER          1 + +/* Community-list entry types.  */ +#define COMMUNITY_LIST_STANDARD        0 /* Standard community-list.  */ +#define COMMUNITY_LIST_EXPANDED        1 /* Expanded community-list.  */ +#define COMMUNITY_LIST_AUTO            2 /* Automatically detected.  */ +#define EXTCOMMUNITY_LIST_STANDARD     3 /* Standard extcommunity-list.  */ +#define EXTCOMMUNITY_LIST_EXPANDED     4 /* Expanded extcommunity-list.  */ +#define EXTCOMMUNITY_LIST_AUTO         5 /* Automatically detected.  */ + +/* Community-list.  */ +struct community_list +{ +  /* Name of the community-list.  */ +  char *name; + +  /* String or number.  */ +  int sort; + +  /* Link to upper list.  */ +  struct community_list_list *parent; + +  /* Linked list for other community-list.  */ +  struct community_list *next; +  struct community_list *prev; + +  /* Community-list entry in this community-list.  */ +  struct community_entry *head; +  struct community_entry *tail; +}; + +/* Each entry in community-list.  */ +struct community_entry +{ +  struct community_entry *next; +  struct community_entry *prev; + +  /* Permit or deny.  */ +  u_char direct; + +  /* Standard or expanded.  */ +  u_char style; + +  /* Any match.  */ +  u_char any; + +  /* Community structure.  */ +  union +  { +    struct community *com; +    struct ecommunity *ecom; +  } u; + +  /* Configuration string.  */ +  char *config; + +  /* Expanded community-list regular expression.  */ +  regex_t *reg; +}; + +/* Linked list of community-list.  */ +struct community_list_list +{ +  struct community_list *head; +  struct community_list *tail; +}; + +/* Master structure of community-list and extcommunity-list.  */ +struct community_list_master +{ +  struct community_list_list num; +  struct community_list_list str; +}; + +/* Community-list handler.  community_list_init() returns this +   structure as handler.  */ +struct community_list_handler +{ +  /* Community-list.  */ +  struct community_list_master community_list; + +  /* Exteded community-list.  */ +  struct community_list_master extcommunity_list; +}; + +/* Error code of community-list.  */ +#define COMMUNITY_LIST_ERR_CANT_FIND_LIST        -1 +#define COMMUNITY_LIST_ERR_MALFORMED_VAL         -2 +#define COMMUNITY_LIST_ERR_STANDARD_CONFLICT     -3 +#define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT     -4 + +/* Handler.  */ +extern struct community_list_handler *bgp_clist; + +/* Prototypes.  */ +struct community_list_handler *community_list_init (); + +int community_list_set (struct community_list_handler *ch, +			char *name, char *str, int direct, int style); +int community_list_unset (struct community_list_handler *ch, +			  char *name, char *str, int direct, int style); +int extcommunity_list_set (struct community_list_handler *ch, +			   char *name, char *str, int direct, int style); +int extcommunity_list_unset (struct community_list_handler *ch, +			     char *name, char *str, int direct, int style); + +struct community_list_master * +community_list_master_lookup (struct community_list_handler *, int); + +struct community_list * +community_list_lookup (struct community_list_handler *, char *, int); + +int community_list_match (struct community *, struct community_list *); +int community_list_exact_match (struct community *, struct community_list *); +struct community * +community_list_match_delete (struct community *, +			     struct community_list *); diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c new file mode 100644 index 0000000000..83b1cc5e70 --- /dev/null +++ b/bgpd/bgp_community.c @@ -0,0 +1,629 @@ +/* Community attribute related functions. +   Copyright (C) 1998, 2001 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "hash.h" +#include "memory.h" + +#include "bgpd/bgp_community.h" + +/* Hash of community attribute. */ +struct hash *comhash; + +/* Allocate a new communities value.  */ +struct community * +community_new () +{ +  return (struct community *) XCALLOC (MTYPE_COMMUNITY, +				       sizeof (struct community)); +} + +/* Free communities value.  */ +void +community_free (struct community *com) +{ +  if (com->val) +    XFREE (MTYPE_COMMUNITY_VAL, com->val); +  if (com->str) +    XFREE (MTYPE_COMMUNITY_STR, com->str); +  XFREE (MTYPE_COMMUNITY, com); +} + +/* Add one community value to the community. */ +void +community_add_val (struct community *com, u_int32_t val) +{ +  com->size++; +  if (com->val) +    com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com)); +  else +    com->val = XMALLOC (MTYPE_COMMUNITY_VAL, com_length (com)); + +  val = htonl (val); +  memcpy (com_lastval (com), &val, sizeof (u_int32_t)); +} + +/* Delete one community. */ +void +community_del_val (struct community *com, u_int32_t *val) +{ +  int i = 0; +  int c = 0; + +  if (! com->val) +    return; + +  while (i < com->size) +    { +      if (memcmp (com->val + i, val, sizeof (u_int32_t)) == 0) +	{ +	  c = com->size -i -1; + +	  if (c > 0) +	    memcpy (com->val + i, com->val + (i + 1), c * sizeof (val)); + +	  com->size--; + +	  if (com->size > 0) +	    com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, +				 com_length (com)); +	  else +	    { +	      XFREE (MTYPE_COMMUNITY_VAL, com->val); +	      com->val = NULL; +	    } +	  return; +	} +      i++; +    } +} + +/* Delete all communities listed in com2 from com1 */ +struct community * +community_delete (struct community *com1, struct community *com2) +{ +  int i = 0; + +  while(i < com2->size) +    { +      community_del_val (com1, com2->val + i); +      i++; +    } + +  return com1; +} + +/* Callback function from qsort(). */ +int +community_compare (const void *a1, const void *a2) +{ +  u_int32_t v1; +  u_int32_t v2; + +  memcpy (&v1, a1, sizeof (u_int32_t)); +  memcpy (&v2, a2, sizeof (u_int32_t)); +  v1 = ntohl (v1); +  v2 = ntohl (v2); + +  if (v1 < v2) +    return -1; +  if (v1 > v2) +    return 1; +  return 0; +} + +int +community_include (struct community *com, u_int32_t val) +{ +  int i; + +  val = htonl (val); + +  for (i = 0; i < com->size; i++) +    if (memcmp (&val, com_nthval (com, i), sizeof (u_int32_t)) == 0) +      return 1; + +  return 0; +} + +u_int32_t +community_val_get (struct community *com, int i) +{ +  u_char *p; +  u_int32_t val; + +  p = (u_char *) com->val; +  p += (i * 4); + +  memcpy (&val, p, sizeof (u_int32_t)); + +  return ntohl (val); +} + +/* Sort and uniq given community. */ +struct community * +community_uniq_sort (struct community *com) +{ +  int i; +  struct community *new; +  u_int32_t val; + +  if (! com) +    return NULL; +   +  new = community_new ();; +   +  for (i = 0; i < com->size; i++) +    { +      val = community_val_get (com, i); + +      if (! community_include (new, val)) +	community_add_val (new, val); +    } + +  qsort (new->val, new->size, sizeof (u_int32_t), community_compare); + +  return new; +} + +/* Convert communities attribute to string. + +   For Well-known communities value, below keyword is used. + +   0x0             "internet"     +   0xFFFFFF01      "no-export" +   0xFFFFFF02      "no-advertise" +   0xFFFFFF03      "local-AS" + +   For other values, "AS:VAL" format is used.  */ +static char * +community_com2str  (struct community *com) +{ +  int i; +  char *str; +  char *pnt; +  int len; +  int first; +  u_int32_t comval; +  u_int16_t as; +  u_int16_t val; + +  /* When communities attribute is empty.  */ +  if (com->size == 0) +    { +      str = XMALLOC (MTYPE_COMMUNITY_STR, 1); +      str[0] = '\0'; +      return str; +    } + +  /* Memory allocation is time consuming work.  So we calculate +     required string length first.  */ +  len = 0; + +  for (i = 0; i < com->size; i++) +    { +      memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); +      comval = ntohl (comval); + +      switch (comval)  +	{ +	case COMMUNITY_INTERNET: +	  len += strlen (" internet"); +	  break; +	case COMMUNITY_NO_EXPORT: +	  len += strlen (" no-export"); +	  break; +	case COMMUNITY_NO_ADVERTISE: +	  len += strlen (" no-advertise"); +	  break; +	case COMMUNITY_LOCAL_AS: +	  len += strlen (" local-AS"); +	  break; +	default: +	  len += strlen (" 65536:65535"); +	  break; +	} +    } + +  /* Allocate memory.  */ +  str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len); +  first = 1; + +  /* Fill in string.  */ +  for (i = 0; i < com->size; i++) +    { +      memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); +      comval = ntohl (comval); + +      if (first) +	first = 0; +      else +	*pnt++ = ' '; + +      switch (comval)  +	{ +	case COMMUNITY_INTERNET: +	  strcpy (pnt, "internet"); +	  pnt += strlen ("internet"); +	  break; +	case COMMUNITY_NO_EXPORT: +	  strcpy (pnt, "no-export"); +	  pnt += strlen ("no-export"); +	  break; +	case COMMUNITY_NO_ADVERTISE: +	  strcpy (pnt, "no-advertise"); +	  pnt += strlen ("no-advertise"); +	  break; +	case COMMUNITY_LOCAL_AS: +	  strcpy (pnt, "local-AS"); +	  pnt += strlen ("local-AS"); +	  break; +	default: +	  as = (comval >> 16) & 0xFFFF; +	  val = comval & 0xFFFF; +	  sprintf (pnt, "%d:%d", as, val); +	  pnt += strlen (pnt); +	  break; +	} +    } +  *pnt = '\0'; + +  return str; +} + +/* Intern communities attribute.  */ +struct community * +community_intern (struct community *com) +{ +  struct community *find; + +  /* Assert this community structure is not interned. */ +  assert (com->refcnt == 0); + +  /* Lookup community hash. */ +  find = (struct community *) hash_get (comhash, com, hash_alloc_intern); + +  /* Arguemnt com is allocated temporary.  So when it is not used in +     hash, it should be freed.  */ +  if (find != com) +    community_free (com); + +  /* Increment refrence counter.  */ +  find->refcnt++; + +  /* Make string.  */ +  if (! find->str) +    find->str = community_com2str (find); + +  return find; +} + +/* Free community attribute. */ +void +community_unintern (struct community *com) +{ +  struct community *ret; + +  if (com->refcnt) +    com->refcnt--; + +  /* Pull off from hash.  */ +  if (com->refcnt == 0) +    { +      /* Community value com must exist in hash. */ +      ret = (struct community *) hash_release (comhash, com); +      assert (ret != NULL); + +      community_free (com); +    } +} + +/* Create new community attribute. */ +struct community * +community_parse (char *pnt, u_short length) +{ +  struct community tmp; +  struct community *new; + +  /* If length is malformed return NULL. */ +  if (length % 4) +    return NULL; + +  /* Make temporary community for hash look up. */ +  tmp.size = length / 4; +  tmp.val = (u_int32_t *) pnt; + +  new = community_uniq_sort (&tmp); + +  return community_intern (new); +} + +struct community * +community_dup (struct community *com) +{ +  struct community *new; + +  new = XCALLOC (MTYPE_COMMUNITY, sizeof (struct community)); +  new->size = com->size; +  if (new->size) +    { +      new->val = XMALLOC (MTYPE_COMMUNITY_VAL, com->size * 4); +      memcpy (new->val, com->val, com->size * 4); +    } +  else +    new->val = NULL; +  return new; +} + +/* Retrun string representation of communities attribute. */ +char * +community_str (struct community *com) +{ +  if (! com->str) +    com->str = community_com2str (com); +  return com->str; +} + +/* Make hash value of community attribute. This function is used by +   hash package.*/ +unsigned int +community_hash_make (struct community *com) +{ +  int c; +  unsigned int key; +  unsigned char *pnt; + +  key = 0; +  pnt = (unsigned char *)com->val; +   +  for(c = 0; c < com->size * 4; c++) +    key += pnt[c]; +       +  return key; +} + +int +community_match (struct community *com1, struct community *com2) +{ +  int i = 0; +  int j = 0; + +  if (com1 == NULL && com2 == NULL) +    return 1; + +  if (com1 == NULL || com2 == NULL) +    return 0; + +  if (com1->size < com2->size) +    return 0; + +  /* Every community on com2 needs to be on com1 for this to match */ +  while (i < com1->size && j < com2->size) +    { +      if (memcmp (com1->val + i, com2->val + j, sizeof (u_int32_t)) == 0) +	j++; +      i++; +    } + +  if (j == com2->size) +    return 1; +  else +    return 0; +} + +/* If two aspath have same value then return 1 else return 0. This +   function is used by hash package. */ +int +community_cmp (struct community *com1, struct community *com2) +{ +  if (com1 == NULL && com2 == NULL) +    return 1; +  if (com1 == NULL || com2 == NULL) +    return 0; + +  if (com1->size == com2->size) +    if (memcmp (com1->val, com2->val, com1->size * 4) == 0) +      return 1; +  return 0; +} + +/* Add com2 to the end of com1. */ +struct community * +community_merge (struct community *com1, struct community *com2) +{ +  if (com1->val) +    com1->val = XREALLOC (MTYPE_COMMUNITY_VAL, com1->val,  +			  (com1->size + com2->size) * 4); +  else +    com1->val = XMALLOC (MTYPE_COMMUNITY_VAL, (com1->size + com2->size) * 4); + +  memcpy (com1->val + com1->size, com2->val, com2->size * 4); +  com1->size += com2->size; + +  return com1; +} + +/* Community token enum. */ +enum community_token +{ +  community_token_val, +  community_token_no_export, +  community_token_no_advertise, +  community_token_local_as, +  community_token_unknown +}; + +/* Get next community token from string. */ +char * +community_gettoken (char *buf, enum community_token *token, u_int32_t *val) +{ +  char *p = buf; + +  /* Skip white space. */ +  while (isspace ((int) *p)) +    p++; + +  /* Check the end of the line. */ +  if (*p == '\0') +    return NULL; + +  /* Well known community string check. */ +  if (isalpha ((int) *p))  +    { +      if (strncmp (p, "internet", strlen ("internet")) == 0) +	{ +	  *val = COMMUNITY_INTERNET; +	  *token = community_token_no_export; +	  p += strlen ("internet"); +	  return p; +	} +      if (strncmp (p, "no-export", strlen ("no-export")) == 0) +	{ +	  *val = COMMUNITY_NO_EXPORT; +	  *token = community_token_no_export; +	  p += strlen ("no-export"); +	  return p; +	} +      if (strncmp (p, "no-advertise", strlen ("no-advertise")) == 0) +	{ +	  *val = COMMUNITY_NO_ADVERTISE; +	  *token = community_token_no_advertise; +	  p += strlen ("no-advertise"); +	  return p; +	} +      if (strncmp (p, "local-AS", strlen ("local-AS")) == 0) +	{ +	  *val = COMMUNITY_LOCAL_AS; +	  *token = community_token_local_as; +	  p += strlen ("local-AS"); +	  return p; +	} + +      /* Unknown string. */ +      *token = community_token_unknown; +      return p; +    } + +  /* Community value. */ +  if (isdigit ((int) *p))  +    { +      int separator = 0; +      int digit = 0; +      u_int32_t community_low = 0; +      u_int32_t community_high = 0; + +      while (isdigit ((int) *p) || *p == ':')  +	{ +	  if (*p == ':')  +	    { +	      if (separator) +		{ +		  *token = community_token_unknown; +		  return p; +		} +	      else +		{ +		  separator = 1; +		  digit = 0; +		  community_high = community_low << 16; +		  community_low = 0; +		} +	    } +	  else  +	    { +	      digit = 1; +	      community_low *= 10; +	      community_low += (*p - '0'); +	    } +	  p++; +	} +      if (! digit) +	{ +	  *token = community_token_unknown; +	  return p; +	} +      *val = community_high + community_low; +      *token = community_token_val; +      return p; +    } +  *token = community_token_unknown; +  return p; +} + +/* convert string to community structure */ +struct community * +community_str2com (char *str) +{ +  struct community *com = NULL; +  struct community *com_sort = NULL; +  u_int32_t val; +  enum community_token token; + +  while ((str = community_gettoken (str, &token, &val)))  +    { +      switch (token) +	{ +	case community_token_val: +	case community_token_no_export: +	case community_token_no_advertise: +	case community_token_local_as: +	  if (com == NULL) +	    com = community_new(); +	  community_add_val (com, val); +	  break; +	case community_token_unknown: +	default: +	  if (com) +	    community_free (com); +	  return NULL; +	  break; +	} +    } +   +  if (! com) +    return NULL; + +  com_sort = community_uniq_sort (com); +  community_free (com); + +  return com_sort; +} + +/* Return communities hash entry count.  */ +unsigned long +community_count () +{ +  return comhash->count; +} + +/* Return communities hash.  */ +struct hash * +community_hash () +{ +  return comhash; +} + +/* Initialize comminity related hash. */ +void +community_init () +{ +  comhash = hash_create (community_hash_make, community_cmp); +} diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h new file mode 100644 index 0000000000..58b3f9e68c --- /dev/null +++ b/bgpd/bgp_community.h @@ -0,0 +1,68 @@ +/* Community attribute related functions. +   Copyright (C) 1998 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +/* Communities attribute.  */ +struct community  +{ +  /* Reference count of communities value.  */ +  unsigned long refcnt; + +  /* Communities value size.  */ +  int size; + +  /* Communities value.  */ +  u_int32_t *val; + +  /* String of community attribute.  This sring is used by vty output +     and expanded community-list for regular expression match.  */ +  char *str; +}; + +/* Well-known communities value.  */ +#define COMMUNITY_INTERNET              0x0 +#define COMMUNITY_NO_EXPORT             0xFFFFFF01 +#define COMMUNITY_NO_ADVERTISE          0xFFFFFF02 +#define COMMUNITY_NO_EXPORT_SUBCONFED   0xFFFFFF03 +#define COMMUNITY_LOCAL_AS              0xFFFFFF03 + +/* Macros of community attribute.  */ +#define com_length(X)    ((X)->size * 4) +#define com_lastval(X)   ((X)->val + (X)->size - 1) +#define com_nthval(X,n)  ((X)->val + (n)) + +/* Prototypes of communities attribute functions.  */ +void community_init (); +void community_free (struct community *); +struct community *community_uniq_sort (struct community *); +struct community *community_parse (char *, u_short); +struct community *community_intern (struct community *); +void community_unintern (struct community *); +char *community_str (struct community *); +unsigned int community_hash_make (struct community *); +struct community *community_str2com (char *); +int community_match (struct community *, struct community *); +int community_cmp (struct community *, struct community *); +struct community *community_merge (struct community *, struct community *); +struct community *community_delete (struct community *, struct community *); +struct community *community_dup (struct community *); +int community_include (struct community *, u_int32_t); +void community_del_val (struct community *, u_int32_t *); +unsigned long community_count (); +struct hash *community_hash (); diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c new file mode 100644 index 0000000000..d70105f55a --- /dev/null +++ b/bgpd/bgp_damp.c @@ -0,0 +1,648 @@ +/* BGP flap dampening +   Copyright (C) 2001 IP Infusion Inc. + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> +#include <math.h> + +#include "prefix.h" +#include "memory.h" +#include "command.h" +#include "log.h" +#include "thread.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_damp.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h"  +#include "bgpd/bgp_advertise.h" + +/* Global variable to access damping configuration */ +struct bgp_damp_config bgp_damp_cfg; +struct bgp_damp_config *damp = &bgp_damp_cfg; + +/* Utility macro to add and delete BGP dampening information to no +   used list.  */ +#define BGP_DAMP_LIST_ADD(N,A)  BGP_INFO_ADD(N,A,no_reuse_list) +#define BGP_DAMP_LIST_DEL(N,A)  BGP_INFO_DEL(N,A,no_reuse_list) + +/* Calculate reuse list index by penalty value.  */ +static int +bgp_reuse_index (int penalty) +{ +  int i; +  int index; + +  i = (int)(((double) penalty / damp->reuse_limit - 1.0) * damp->scale_factor); +   +  if ( i >= damp->reuse_index_size ) +    i = damp->reuse_index_size - 1; + +  index = damp->reuse_index[i] - damp->reuse_index[0]; + +  return (damp->reuse_offset + index) % damp->reuse_list_size;   +} + +/* Add BGP dampening information to reuse list.  */ +static void  +bgp_reuse_list_add (struct bgp_damp_info *bdi) +{ +  int index; + +  index = bdi->index = bgp_reuse_index (bdi->penalty); + +  bdi->prev = NULL; +  bdi->next = damp->reuse_list[index]; +  if (damp->reuse_list[index]) +    damp->reuse_list[index]->prev = bdi; +  damp->reuse_list[index] = bdi; +} + +/* Delete BGP dampening information from reuse list.  */ +static void +bgp_reuse_list_delete (struct bgp_damp_info *bdi) +{ +  if (bdi->next) +    bdi->next->prev = bdi->prev; +  if (bdi->prev) +    bdi->prev->next = bdi->next; +  else +    damp->reuse_list[bdi->index] = bdi->next; +}    + +/* Return decayed penalty value.  */ +int  +bgp_damp_decay (time_t tdiff, int penalty) +{ +  int i; + +  i = (int) ((double) tdiff / DELTA_T); + +  if (i == 0) +    return penalty;  +   +  if (i >= damp->decay_array_size) +    return 0; + +  return (int) (penalty * damp->decay_array[i]); +} + +/* Handler of reuse timer event.  Each route in the current reuse-list +   is evaluated.  RFC2439 Section 4.8.7.  */ +int +bgp_reuse_timer (struct thread *t) +{ +  struct bgp_damp_info *bdi; +  struct bgp_damp_info *next; +  time_t t_now, t_diff; +  struct bgp *bgp; +  int bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t); + +  damp->t_reuse = NULL; +  damp->t_reuse = +    thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE); + +  bgp = bgp_get_default (); +  if (! bgp) +    return 0; + +  t_now = time (NULL); + +  /* 1.  save a pointer to the current zeroth queue head and zero the +     list head entry.  */ +  bdi = damp->reuse_list[damp->reuse_offset]; +  damp->reuse_list[damp->reuse_offset] = NULL; + +  /* 2.  set offset = modulo reuse-list-size ( offset + 1 ), thereby +     rotating the circular queue of list-heads.  */ +  damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size; + +  /* 3. if ( the saved list head pointer is non-empty ) */ +  for (; bdi; bdi = next) +    { +      next = bdi->next; + +      /* Set t-diff = t-now - t-updated.  */ +      t_diff = t_now - bdi->t_updated; + +      /* Set figure-of-merit = figure-of-merit * decay-array-ok [t-diff] */ +      bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);    + +      /* Set t-updated = t-now.  */ +      bdi->t_updated = t_now; + +      /* if (figure-of-merit < reuse).  */ +      if (bdi->penalty < damp->reuse_limit) +	{ +	  /* Reuse the route.  */ +	  UNSET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED); +	  bdi->suppress_time = 0; + +	  if (bdi->lastrecord == BGP_RECORD_UPDATE) +	    { +	      UNSET_FLAG (bdi->binfo->flags, BGP_INFO_HISTORY); +	      bgp_aggregate_increment (bgp, &bdi->rn->p, bdi->binfo, +				       bdi->afi, bdi->safi);    +	      bgp_process (bgp, bdi->rn, bdi->afi, bdi->safi); +	    } + +	  if (bdi->penalty <= damp->reuse_limit / 2.0) +	    bgp_damp_info_free (bdi, 1); +	  else +	    BGP_DAMP_LIST_ADD (damp, bdi); +	} +      else +	/* Re-insert into another list (See RFC2439 Section 4.8.6).  */ +	bgp_reuse_list_add (bdi); +    } + +  return 0; +} + +/* A route becomes unreachable (RFC2439 Section 4.8.2).  */ +int +bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn, +		   afi_t afi, safi_t safi, int attr_change) +{ +  time_t t_now; +  struct bgp_damp_info *bdi; +  double last_penalty = 0; +   +  t_now = time (NULL); + +  /* Processing Unreachable Messages.  */ +  bdi = binfo->damp_info; + +  if (bdi == NULL) +    { +      /* If there is no previous stability history. */ + +      /* RFC2439 said: +	 1. allocate a damping structure. +         2. set figure-of-merit = 1. +         3. withdraw the route.  */ + +      bdi =  XCALLOC (MTYPE_BGP_DAMP_INFO, sizeof (struct bgp_damp_info)); +      bdi->binfo = binfo; +      bdi->rn = rn; +      bdi->penalty = (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY); +      bdi->flap = 1; +      bdi->start_time = t_now; +      bdi->suppress_time = 0; +      bdi->index = -1; +      bdi->afi = afi; +      bdi->safi = safi; +      binfo->damp_info = bdi; +      BGP_DAMP_LIST_ADD (damp, bdi); +    } +  else +    { +      last_penalty = bdi->penalty; + +      /* 1. Set t-diff = t-now - t-updated.  */ +      bdi->penalty =  +	(bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty)  +	 + (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY)); + +      if (bdi->penalty > damp->ceiling) +	bdi->penalty = damp->ceiling; + +      bdi->flap++; +    } +   +  bdi->lastrecord = BGP_RECORD_WITHDRAW; +  bdi->t_updated = t_now; + +  /* Make this route as historical status.  */ +  SET_FLAG (binfo->flags, BGP_INFO_HISTORY); + +  /* Remove the route from a reuse list if it is on one.  */ +  if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)) +    { +      /* If decay rate isn't equal to 0, reinsert brn. */   +      if (bdi->penalty != last_penalty) +	{ +	  bgp_reuse_list_delete (bdi); +	  bgp_reuse_list_add (bdi);   +	} +      return BGP_DAMP_SUPPRESSED;  +    } + +  /* If not suppressed before, do annonunce this withdraw and +     insert into reuse_list.  */ +  if (bdi->penalty >= damp->suppress_value) +    { +      SET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED); +      bdi->suppress_time = t_now; +      BGP_DAMP_LIST_DEL (damp, bdi); +      bgp_reuse_list_add (bdi); +    } + +  return BGP_DAMP_USED; +} + +int +bgp_damp_update (struct bgp_info *binfo, struct bgp_node *rn,  +		 afi_t afi, safi_t safi) +{ +  time_t t_now; +  struct bgp_damp_info *bdi; +  int status; + +  bdi = binfo->damp_info; +  if (! bdi) +    return BGP_DAMP_USED; + +  t_now = time (NULL); +  UNSET_FLAG (binfo->flags, BGP_INFO_HISTORY);  + +  bdi->lastrecord = BGP_RECORD_UPDATE; +  bdi->penalty = bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty); + +  if (! CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED) +      && (bdi->penalty < damp->suppress_value)) +    status = BGP_DAMP_USED; +  else if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED) +	   && (bdi->penalty < damp->reuse_limit) ) +    { +      UNSET_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED); +      bgp_reuse_list_delete (bdi); +      BGP_DAMP_LIST_ADD (damp, bdi); +      bdi->suppress_time = 0; +      status = BGP_DAMP_USED; +    } +  else +    status = BGP_DAMP_SUPPRESSED;   + +  if (bdi->penalty > damp->reuse_limit / 2.0) +    bdi->t_updated = t_now; +  else +    bgp_damp_info_free (bdi, 0); +	 +  return status; +} + +/* Remove dampening information and history route.  */ +int  +bgp_damp_scan (struct bgp_info *binfo, afi_t afi, safi_t safi) +{ +  time_t t_now, t_diff; +  struct bgp_damp_info *bdi; + +  t_now = time (NULL); +  bdi = binfo->damp_info; +  +  if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) +    { +      t_diff = t_now - bdi->suppress_time; + +      if (t_diff >= damp->max_suppress_time) +        { +          UNSET_FLAG (binfo->flags, BGP_INFO_DAMPED); +          bgp_reuse_list_delete (bdi); +	  BGP_DAMP_LIST_ADD (damp, bdi); +          bdi->penalty = damp->reuse_limit; +          bdi->suppress_time = 0; +          bdi->t_updated = t_now; +           +          /* Need to announce UPDATE once this binfo is usable again. */ +          if (bdi->lastrecord == BGP_RECORD_UPDATE) +            return 1; +          else +            return 0; +        } +    } +  else +    { +      t_diff = t_now - bdi->t_updated; +      bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty); + +      if (bdi->penalty <= damp->reuse_limit / 2.0) +        { +          /* release the bdi, bdi->binfo. */   +          bgp_damp_info_free (bdi, 1); +          return 0; +        }             +      else +        bdi->t_updated = t_now; +    }        +  return 0; +} + +void +bgp_damp_info_free (struct bgp_damp_info *bdi, int withdraw) +{ +  struct bgp_info *binfo; +  void bgp_info_delete (struct bgp_node *, struct bgp_info *); +  void bgp_info_free (struct bgp_info *); + +  if (! bdi) +    return; + +  binfo = bdi->binfo; +  binfo->damp_info = NULL; + +  if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) +    bgp_reuse_list_delete (bdi); +  else +    BGP_DAMP_LIST_DEL (damp, bdi); + +  UNSET_FLAG (binfo->flags, BGP_INFO_DAMPED); +  UNSET_FLAG (binfo->flags, BGP_INFO_HISTORY); + +  if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) +    { +      bgp_info_delete (bdi->rn, binfo); +      bgp_info_free (binfo); +      bgp_unlock_node (bdi->rn); +    } +  XFREE (MTYPE_BGP_DAMP_INFO, bdi); +} + +void +bgp_damp_parameter_set (int hlife, int reuse, int sup, int maxsup) +{ +  double reuse_max_ratio; +  int i; +  double j; +	 +  damp->suppress_value = sup; +  damp->half_life = hlife; +  damp->reuse_limit = reuse; +  damp->max_suppress_time = maxsup; + +  /* Initialize params per bgp_damp_config. */ +  damp->reuse_index_size = REUSE_ARRAY_SIZE; + +  damp->ceiling = (int)(damp->reuse_limit * (pow(2, (double)damp->max_suppress_time/damp->half_life)));  + +  /* Decay-array computations */ +  damp->decay_array_size = ceil ((double) damp->max_suppress_time / DELTA_T); +  damp->decay_array = XMALLOC (MTYPE_BGP_DAMP_ARRAY, +			       sizeof(double) * (damp->decay_array_size)); +  damp->decay_array[0] = 1.0; +  damp->decay_array[1] = exp ((1.0/((double)damp->half_life/DELTA_T)) * log(0.5)); + +  /* Calculate decay values for all possible times */ +  for (i = 2; i < damp->decay_array_size; i++) +    damp->decay_array[i] = damp->decay_array[i-1] * damp->decay_array[1]; +	 +  /* Reuse-list computations */ +  i = ceil ((double)damp->max_suppress_time / DELTA_REUSE) + 1; +  if (i > REUSE_LIST_SIZE || i == 0) +    i = REUSE_LIST_SIZE; +  damp->reuse_list_size = i;  + +  damp->reuse_list = XCALLOC (MTYPE_BGP_DAMP_ARRAY,  +			      damp->reuse_list_size  +			      * sizeof (struct bgp_reuse_node *)); +  memset (damp->reuse_list, 0x00,  +          damp->reuse_list_size * sizeof (struct bgp_reuse_node *));   + +  /* Reuse-array computations */ +  damp->reuse_index = XMALLOC (MTYPE_BGP_DAMP_ARRAY,  +			       sizeof(int) * damp->reuse_index_size); +  memset (damp->reuse_index, 0x00, +          damp->reuse_list_size * sizeof (int)); + +  reuse_max_ratio = (double)damp->ceiling/damp->reuse_limit; +  j = (exp((double)damp->max_suppress_time/damp->half_life) * log10(2.0)); +  if ( reuse_max_ratio > j && j != 0 ) +    reuse_max_ratio = j; + +  damp->scale_factor = (double)damp->reuse_index_size/(reuse_max_ratio - 1); + +  for (i = 0; i < damp->reuse_index_size; i++) +    { +      damp->reuse_index[i] =  +	(int)(((double)damp->half_life / DELTA_REUSE) +	      * log10 (1.0 / (damp->reuse_limit * ( 1.0 + ((double)i/damp->scale_factor)))) / log10(0.5)); +    } +} + +int +bgp_damp_enable (struct bgp *bgp, afi_t afi, safi_t safi, int half, +		 int reuse, int suppress, int max) +{ +  if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) +    { +      if (damp->half_life == half +	  && damp->reuse_limit == reuse +	  && damp->suppress_value == suppress +	  && damp->max_suppress_time == max) +	return 0; +      bgp_damp_disable (bgp, afi, safi); +    } + +  SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); +  bgp_damp_parameter_set (half, reuse, suppress, max); + +  /* Register reuse timer.  */ +  if (! damp->t_reuse) +    damp->t_reuse =  +      thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE); + +  return 0; +} + +void +bgp_damp_config_clean (struct bgp_damp_config *damp) +{ +  /* Free decay array */ +  XFREE (MTYPE_BGP_DAMP_ARRAY, damp->decay_array); + +  /* Free reuse index array */ +  XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_index); + +  /* Free reuse list array. */ +  XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_list); +} + +/* Clean all the bgp_damp_info stored in reuse_list. */ +void +bgp_damp_info_clean () +{ +  int i; +  struct bgp_damp_info *bdi, *next; + +  damp->reuse_offset = 0; + +  for (i = 0; i < damp->reuse_list_size; i++) +    { +      if (! damp->reuse_list[i]) +	continue; + +      for (bdi = damp->reuse_list[i]; bdi; bdi = next) +	{ +	  next = bdi->next; +	  bgp_damp_info_free (bdi, 1); +	} +      damp->reuse_list[i] = NULL; +    } + +  for (bdi = damp->no_reuse_list; bdi; bdi = next) +    { +      next = bdi->next; +      bgp_damp_info_free (bdi, 1); +    } +  damp->no_reuse_list = NULL; +} + +int +bgp_damp_disable (struct bgp *bgp, afi_t afi, safi_t safi) +{ +  /* Cancel reuse thread. */ +  if (damp->t_reuse ) +    thread_cancel (damp->t_reuse); +  damp->t_reuse = NULL; + +  /* Clean BGP dampening information.  */ +  bgp_damp_info_clean (); + +  /* Clear configuration */ +  bgp_damp_config_clean (&bgp_damp_cfg); + +  UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); +  return 0; +} + +int +bgp_config_write_damp (struct vty *vty) +{ +  if (&bgp_damp_cfg) +    { +      if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE*60 +	  && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE +	  && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS +	  && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4) +	vty_out (vty, " bgp dampening%s", VTY_NEWLINE); +      else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE*60 +	       && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE +	       && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS +	       && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4) +	vty_out (vty, " bgp dampening %d%s", +		 bgp_damp_cfg.half_life/60, +		 VTY_NEWLINE); +      else +	vty_out (vty, " bgp dampening %d %d %d %d%s", +		 bgp_damp_cfg.half_life/60, +		 bgp_damp_cfg.reuse_limit, +		 bgp_damp_cfg.suppress_value, +		 bgp_damp_cfg.max_suppress_time/60, +		 VTY_NEWLINE); +      return 1; +    } +  return 0; +} + +#define BGP_UPTIME_LEN 25 + +char * +bgp_get_reuse_time (int penalty, char *buf, size_t len) +{ +  time_t reuse_time = 0; +  struct tm *tm = NULL; + +  if (penalty > damp->reuse_limit) +    { +      reuse_time = (int) (DELTA_T * ((log((double)damp->reuse_limit/penalty))/(log(damp->decay_array[1]))));  + +      if (reuse_time > damp->max_suppress_time) +	reuse_time = damp->max_suppress_time; + +      tm = gmtime (&reuse_time); +    } +  else  +    reuse_time = 0; + +  /* Making formatted timer strings. */ +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 +  if (reuse_time == 0) +    snprintf (buf, len, "00:00:00"); +  else if (reuse_time < ONE_DAY_SECOND) +    snprintf (buf, len, "%02d:%02d:%02d",  +              tm->tm_hour, tm->tm_min, tm->tm_sec); +  else if (reuse_time < ONE_WEEK_SECOND) +    snprintf (buf, len, "%dd%02dh%02dm",  +              tm->tm_yday, tm->tm_hour, tm->tm_min); +  else +    snprintf (buf, len, "%02dw%dd%02dh",  +              tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);  + +  return buf; +} +  +void +bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo)   +{ +  struct bgp_damp_info *bdi; +  time_t t_now, t_diff; +  char timebuf[BGP_UPTIME_LEN]; +  int penalty; + +  /* BGP dampening information.  */ +  bdi = binfo->damp_info; + +  /* If dampening is not enabled or there is no dampening information, +     return immediately.  */ +  if (! damp || ! bdi) +    return; + +  /* Calculate new penalty.  */ +  t_now = time (NULL); +  t_diff = t_now - bdi->t_updated; +  penalty = bgp_damp_decay (t_diff, bdi->penalty); + +  vty_out (vty, "      Dampinfo: penalty %d, flapped %d times in %s", +           penalty, bdi->flap, +	   peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN)); + +  if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED) +      && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) +    vty_out (vty, ", reuse in %s", +	     bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN)); + +  vty_out (vty, "%s", VTY_NEWLINE); +} + +char * +bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo) +{ +  struct bgp_damp_info *bdi; +  time_t t_now, t_diff; +  char timebuf[BGP_UPTIME_LEN]; +  int penalty; + +  /* BGP dampening information.  */ +  bdi = binfo->damp_info; + +  /* If dampening is not enabled or there is no dampening information, +     return immediately.  */ +  if (! damp || ! bdi) +    return NULL; + +  /* Calculate new penalty.  */ +  t_now = time (NULL); +  t_diff = t_now - bdi->t_updated; +  penalty = bgp_damp_decay (t_diff, bdi->penalty); + +  return  bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN); +} diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h new file mode 100644 index 0000000000..f3b9bd6dbc --- /dev/null +++ b/bgpd/bgp_damp.h @@ -0,0 +1,141 @@ +/* BGP flap dampening +   Copyright (C) 2001 IP Infusion Inc. + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +/* Structure maintained on a per-route basis. */ +struct bgp_damp_info +{ +  /* Doubly linked list.  This information must be linked to +     reuse_list or no_reuse_list.  */ +  struct bgp_damp_info *next; +  struct bgp_damp_info *prev; + +  /* Figure-of-merit.  */ +  int penalty; + +  /* Number of flapping.  */ +  int flap; +	 +  /* First flap time  */ +  time_t start_time; +  +  /* Last time penalty was updated.  */ +  time_t t_updated; + +  /* Time of route start to be suppressed.  */ +  time_t suppress_time; + +  /* Back reference to bgp_info. */ +  struct bgp_info *binfo; + +  /* Back reference to bgp_node. */ +  struct bgp_node *rn; + +  /* Current index in the reuse_list. */ +  int index; + +  /* Last time message type. */ +  u_char lastrecord; +#define BGP_RECORD_UPDATE	1 +#define BGP_RECORD_WITHDRAW	2 + +  afi_t afi; +  safi_t safi; +}; + +/* Specified parameter set configuration. */ +struct bgp_damp_config +{ +  /* Value over which routes suppressed.  */ +  int suppress_value; + +  /* Value below which suppressed routes reused.  */ +  int reuse_limit;     + +  /* Max time a route can be suppressed.  */ +  int max_suppress_time;       + +  /* Time during which accumulated penalty reduces by half.  */ +  int half_life;  + +  /* Non-configurable parameters but fixed at implementation time. +   * To change this values, init_bgp_damp() should be modified. +   */ +  int tmax;		  /* Max time previous instability retained */ +  int reuse_list_size;		/* Number of reuse lists */ +  int reuse_index_size;		/* Size of reuse index array */ + +  /* Non-configurable parameters.  Most of these are calculated from +   * the configurable parameters above. +   */ +  unsigned int ceiling;		/* Max value a penalty can attain */ +  int decay_rate_per_tick;	/* Calculated from half-life */ +  int decay_array_size;		/* Calculated using config parameters */ +  double scale_factor; +  int reuse_scale_factor;  +          +  /* Decay array per-set based. */  +  double *decay_array;	 + +  /* Reuse index array per-set based. */  +  int *reuse_index; + +  /* Reuse list array per-set based. */   +  struct bgp_damp_info **reuse_list; +  int reuse_offset; +         +  /* All dampening information which is not on reuse list.  */ +  struct bgp_damp_info *no_reuse_list; + +  /* Reuse timer thread per-set base. */ +  struct thread* t_reuse; +}; + +#define BGP_DAMP_NONE           0 +#define BGP_DAMP_USED		1 +#define BGP_DAMP_SUPPRESSED	2 + +/* Time granularity for reuse lists */ +#define DELTA_REUSE	          10 + +/* Time granularity for decay arrays */ +#define DELTA_T 	           5 + +#define DEFAULT_PENALTY         1000 + +#define DEFAULT_HALF_LIFE         15 +#define DEFAULT_REUSE 	       	 750 +#define DEFAULT_SUPPRESS 	2000 + +#define REUSE_LIST_SIZE          256 +#define REUSE_ARRAY_SIZE        1024 + +int bgp_damp_enable (struct bgp *, afi_t, safi_t, int, int, int, int); +int bgp_damp_disable (struct bgp *, afi_t, safi_t); +int bgp_damp_withdraw (struct bgp_info *, struct bgp_node *, +		       afi_t, safi_t, int); +int bgp_damp_update (struct bgp_info *, struct bgp_node *, afi_t, safi_t); +int bgp_damp_scan (struct bgp_info *, afi_t, safi_t); +void bgp_damp_info_free (struct bgp_damp_info *, int); +void bgp_damp_info_clean (); +char * bgp_get_reuse_time (int, char*, size_t); +int bgp_damp_decay (time_t, int); +int bgp_config_write_damp (struct vty *); +void bgp_damp_info_vty (struct vty *, struct bgp_info *); +char * bgp_damp_reuse_time_vty (struct vty *, struct bgp_info *); diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c new file mode 100644 index 0000000000..bb1a61072a --- /dev/null +++ b/bgpd/bgp_debug.c @@ -0,0 +1,732 @@ +/* BGP-4, BGP-4+ packet debug routine +   Copyright (C) 1996, 97, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "version.h" +#include "prefix.h" +#include "linklist.h" +#include "stream.h" +#include "command.h" +#include "str.h" +#include "log.h" +#include "sockunion.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_community.h" + +unsigned long conf_bgp_debug_fsm; +unsigned long conf_bgp_debug_events; +unsigned long conf_bgp_debug_packet; +unsigned long conf_bgp_debug_filter; +unsigned long conf_bgp_debug_keepalive; +unsigned long conf_bgp_debug_update; +unsigned long conf_bgp_debug_normal; + +unsigned long term_bgp_debug_fsm; +unsigned long term_bgp_debug_events; +unsigned long term_bgp_debug_packet; +unsigned long term_bgp_debug_filter; +unsigned long term_bgp_debug_keepalive; +unsigned long term_bgp_debug_update; +unsigned long term_bgp_debug_normal; + +/* messages for BGP-4 status */ +struct message bgp_status_msg[] =  +{ +  { 0, "null" }, +  { Idle, "Idle" }, +  { Connect, "Connect" }, +  { Active, "Active" }, +  { OpenSent, "OpenSent" }, +  { OpenConfirm, "OpenConfirm" }, +  { Established, "Established" }, +}; +int bgp_status_msg_max = BGP_STATUS_MAX; + +/* BGP message type string. */ +char *bgp_type_str[] = +{ +  NULL, +  "OPEN", +  "UPDATE", +  "NOTIFICATION", +  "KEEPALIVE", +  "ROUTE-REFRESH", +  "CAPABILITY" +}; + +/* message for BGP-4 Notify */ +struct message bgp_notify_msg[] =  +{ +  { 0, "" }, +  { BGP_NOTIFY_HEADER_ERR, "Message Header Error"}, +  { BGP_NOTIFY_OPEN_ERR, "OPEN Message Error"}, +  { BGP_NOTIFY_UPDATE_ERR, "UPDATE Message Error"}, +  { BGP_NOTIFY_HOLD_ERR, "Hold Timer Expired"}, +  { BGP_NOTIFY_FSM_ERR, "Finite State Machine Error"}, +  { BGP_NOTIFY_CEASE, "Cease"}, +  { BGP_NOTIFY_CAPABILITY_ERR, "CAPABILITY Message Error"}, +}; +int bgp_notify_msg_max = BGP_NOTIFY_MAX; + +struct message bgp_notify_head_msg[] =  +{ +  { 0, "null"}, +  { BGP_NOTIFY_HEADER_NOT_SYNC, "/Connection Not Synchronized."}, +  { BGP_NOTIFY_HEADER_BAD_MESLEN, "/Bad Message Length."}, +  { BGP_NOTIFY_HEADER_BAD_MESTYPE, "/Bad Message Type."} +}; +int bgp_notify_head_msg_max = BGP_NOTIFY_HEADER_MAX; + +struct message bgp_notify_open_msg[] =  +{ +  { 0, "null" }, +  { BGP_NOTIFY_OPEN_UNSUP_VERSION, "/Unsupported Version Number." }, +  { BGP_NOTIFY_OPEN_BAD_PEER_AS, "/Bad Peer AS."}, +  { BGP_NOTIFY_OPEN_BAD_BGP_IDENT, "/Bad BGP Identifier."}, +  { BGP_NOTIFY_OPEN_UNSUP_PARAM, "/Unsupported Optional Parameter."}, +  { BGP_NOTIFY_OPEN_AUTH_FAILURE, "/Authentication Failure."}, +  { BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, "/Unacceptable Hold Time."},  +  { BGP_NOTIFY_OPEN_UNSUP_CAPBL, "/Unsupported Capability."}, +}; +int bgp_notify_open_msg_max = BGP_NOTIFY_OPEN_MAX; + +struct message bgp_notify_update_msg[] =  +{ +  { 0, "null"},  +  { BGP_NOTIFY_UPDATE_MAL_ATTR, "/Malformed Attribute List."}, +  { BGP_NOTIFY_UPDATE_UNREC_ATTR, "/Unrecognized Well-known Attribute."}, +  { BGP_NOTIFY_UPDATE_MISS_ATTR, "/Missing Well-known Attribute."}, +  { BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, "/Attribute Flags Error."}, +  { BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, "/Attribute Length Error."}, +  { BGP_NOTIFY_UPDATE_INVAL_ORIGIN, "/Invalid ORIGIN Attribute."}, +  { BGP_NOTIFY_UPDATE_AS_ROUTE_LOOP, "/AS Routing Loop."}, +  { BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, "/Invalid NEXT_HOP Attribute."}, +  { BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, "/Optional Attribute Error."}, +  { BGP_NOTIFY_UPDATE_INVAL_NETWORK, "/Invalid Network Field."}, +  { BGP_NOTIFY_UPDATE_MAL_AS_PATH, "/Malformed AS_PATH."}, +}; +int bgp_notify_update_msg_max = BGP_NOTIFY_UPDATE_MAX; + +struct message bgp_notify_cease_msg[] = +{ +  { 0, ""}, +  { BGP_NOTIFY_CEASE_MAX_PREFIX, "/Maximum Number of Prefixes Reached."}, +  { BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administratively Shutdown."}, +  { BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer Unconfigured."}, +  { BGP_NOTIFY_CEASE_ADMIN_RESET, "/Administratively Reset."}, +  { BGP_NOTIFY_CEASE_CONNECT_REJECT, "/Connection Rejected."}, +  { BGP_NOTIFY_CEASE_CONFIG_CHANGE, "/Other Configuration Change."}, +}; +int bgp_notify_cease_msg_max = BGP_NOTIFY_CEASE_MAX; + +struct message bgp_notify_capability_msg[] =  +{ +  { 0, "null" }, +  { BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value." }, +  { BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length."}, +  { BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value."}, +}; +int bgp_notify_capability_msg_max = BGP_NOTIFY_CAPABILITY_MAX; + +/* Origin strings. */ +char *bgp_origin_str[] = {"i","e","?"}; +char *bgp_origin_long_str[] = {"IGP","EGP","incomplete"}; + +/* Dump attribute. */ +void +bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size) +{ + +  if (! attr) +    return; + +  snprintf (buf, size, "nexthop %s", inet_ntoa (attr->nexthop)); +  snprintf (buf + strlen (buf), size - strlen (buf), ", origin %s", +	    bgp_origin_str[attr->origin]); + +#ifdef HAVE_IPV6 +  { +    char addrbuf[BUFSIZ]; + +    /* Add MP case. */ +    if (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32) +      snprintf (buf + strlen (buf), size - strlen (buf), ", mp_nexthop %s", +		inet_ntop (AF_INET6, &attr->mp_nexthop_global,  +			   addrbuf, BUFSIZ)); + +    if (attr->mp_nexthop_len == 32) +      snprintf (buf + strlen (buf), size - strlen (buf), "(%s)", +		inet_ntop (AF_INET6, &attr->mp_nexthop_local,  +			   addrbuf, BUFSIZ)); +  } +#endif /* HAVE_IPV6 */ + +  if (peer_sort (peer) == BGP_PEER_IBGP) +    snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %d", +	      attr->local_pref); + +  if (attr->med) +    snprintf (buf + strlen (buf), size - strlen (buf), ", metric %d", +	      attr->med); + +  if (attr->community)  +    snprintf (buf + strlen (buf), size - strlen (buf), ", community %s", +	      community_str (attr->community)); + +  if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) +    snprintf (buf + strlen (buf), size - strlen (buf), ", atomic-aggregate"); + +  if (attr->aggregator_as) +    snprintf (buf + strlen (buf), size - strlen (buf), ", aggregated by %d %s", +	      attr->aggregator_as, inet_ntoa (attr->aggregator_addr)); + +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) +    snprintf (buf + strlen (buf), size - strlen (buf), ", originator %s", +	      inet_ntoa (attr->originator_id)); + +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST)) +    { +      int i; + +      snprintf (buf + strlen (buf), size - strlen (buf), ", clusterlist "); +      for (i = 0; i < attr->cluster->length / 4; i++) +	snprintf (buf + strlen (buf), size - strlen (buf), "%s", +		  inet_ntoa (attr->cluster->list[i])); +    } + +  if (attr->aspath)  +    snprintf (buf + strlen (buf), size - strlen (buf), ", path %s", +	      aspath_print (attr->aspath)); +} + +/* dump notify packet */ +void +bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, char *direct) +{ +  char *subcode_str; + +  subcode_str = ""; + +  switch (bgp_notify->code)  +    { +    case BGP_NOTIFY_HEADER_ERR: +      subcode_str = LOOKUP (bgp_notify_head_msg, bgp_notify->subcode); +      break; +    case BGP_NOTIFY_OPEN_ERR: +      subcode_str = LOOKUP (bgp_notify_open_msg, bgp_notify->subcode); +      break; +    case BGP_NOTIFY_UPDATE_ERR: +      subcode_str = LOOKUP (bgp_notify_update_msg, bgp_notify->subcode); +      break; +    case BGP_NOTIFY_HOLD_ERR: +      subcode_str = ""; +      break; +    case BGP_NOTIFY_FSM_ERR: +      subcode_str = ""; +      break; +    case BGP_NOTIFY_CEASE: +      subcode_str = LOOKUP (bgp_notify_cease_msg, bgp_notify->subcode); +      break; +    case BGP_NOTIFY_CAPABILITY_ERR: +      subcode_str = LOOKUP (bgp_notify_capability_msg, bgp_notify->subcode); +      break; +    } +  if (BGP_DEBUG (normal, NORMAL)) +    plog_info (peer->log, "%s %s NOTIFICATION %d/%d (%s%s) %d bytes %s", +	       peer ? peer->host : "", +	       direct, bgp_notify->code, bgp_notify->subcode, +	       LOOKUP (bgp_notify_msg, bgp_notify->code), +	       subcode_str, bgp_notify->length, +	       bgp_notify->data ? bgp_notify->data : ""); +} + +/* Debug option setting interface. */ +unsigned long bgp_debug_option = 0; + +int   +debug (unsigned int option) +{ +  return bgp_debug_option & option;  +} + +DEFUN (debug_bgp_fsm, +       debug_bgp_fsm_cmd, +       "debug bgp fsm", +       DEBUG_STR +       BGP_STR +       "BGP Finite State Machine\n") +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_ON (fsm, FSM); +  else +    { +      TERM_DEBUG_ON (fsm, FSM); +      vty_out (vty, "BGP fsm debugging is on%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_fsm, +       no_debug_bgp_fsm_cmd, +       "no debug bgp fsm", +       NO_STR +       DEBUG_STR +       BGP_STR +       "Finite State Machine\n") +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_OFF (fsm, FSM); +  else +    { +      TERM_DEBUG_OFF (fsm, FSM); +      vty_out (vty, "BGP fsm debugging is off%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_fsm, +       undebug_bgp_fsm_cmd, +       "undebug bgp fsm", +       UNDEBUG_STR +       DEBUG_STR +       BGP_STR +       "Finite State Machine\n") + +DEFUN (debug_bgp_events, +       debug_bgp_events_cmd, +       "debug bgp events", +       DEBUG_STR +       BGP_STR +       "BGP events\n") +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_ON (events, EVENTS); +  else +    { +      TERM_DEBUG_ON (events, EVENTS); +      vty_out (vty, "BGP events debugging is on%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_events, +       no_debug_bgp_events_cmd, +       "no debug bgp events", +       NO_STR +       DEBUG_STR +       BGP_STR +       "BGP events\n") +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_OFF (events, EVENTS); +  else +    { +      TERM_DEBUG_OFF (events, EVENTS); +      vty_out (vty, "BGP events debugging is off%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_events, +       undebug_bgp_events_cmd, +       "undebug bgp events", +       UNDEBUG_STR +       BGP_STR +       "BGP events\n") + +DEFUN (debug_bgp_filter, +       debug_bgp_filter_cmd, +       "debug bgp filters", +       DEBUG_STR +       BGP_STR +       "BGP filters\n") +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_ON (filter, FILTER); +  else +    { +      TERM_DEBUG_ON (filter, FILTER); +      vty_out (vty, "BGP filters debugging is on%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_filter, +       no_debug_bgp_filter_cmd, +       "no debug bgp filters", +       NO_STR +       DEBUG_STR +       BGP_STR +       "BGP filters\n") +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_OFF (filter, FILTER); +  else +    { +      TERM_DEBUG_OFF (filter, FILTER); +      vty_out (vty, "BGP filters debugging is off%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_filter, +       undebug_bgp_filter_cmd, +       "undebug bgp filters", +       UNDEBUG_STR +       BGP_STR +       "BGP filters\n") + +DEFUN (debug_bgp_keepalive, +       debug_bgp_keepalive_cmd, +       "debug bgp keepalives", +       DEBUG_STR +       BGP_STR +       "BGP keepalives\n") +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_ON (keepalive, KEEPALIVE); +  else +    { +      TERM_DEBUG_ON (keepalive, KEEPALIVE); +      vty_out (vty, "BGP keepalives debugging is on%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_keepalive, +       no_debug_bgp_keepalive_cmd, +       "no debug bgp keepalives", +       NO_STR +       DEBUG_STR +       BGP_STR +       "BGP keepalives\n") +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_OFF (keepalive, KEEPALIVE); +  else +    { +      TERM_DEBUG_OFF (keepalive, KEEPALIVE); +      vty_out (vty, "BGP keepalives debugging is off%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_keepalive, +       undebug_bgp_keepalive_cmd, +       "undebug bgp keepalives", +       UNDEBUG_STR +       BGP_STR +       "BGP keepalives\n") + +DEFUN (debug_bgp_update, +       debug_bgp_update_cmd, +       "debug bgp updates", +       DEBUG_STR +       BGP_STR +       "BGP updates\n") +{ +  if (vty->node == CONFIG_NODE) +    { +      DEBUG_ON (update, UPDATE_IN); +      DEBUG_ON (update, UPDATE_OUT); +    } +  else +    { +      TERM_DEBUG_ON (update, UPDATE_IN); +      TERM_DEBUG_ON (update, UPDATE_OUT); +      vty_out (vty, "BGP updates debugging is on%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +DEFUN (debug_bgp_update_direct, +       debug_bgp_update_direct_cmd, +       "debug bgp updates (in|out)", +       DEBUG_STR +       BGP_STR +       "BGP updates\n" +       "Inbound updates\n" +       "Outbound updates\n") +{ +  if (vty->node == CONFIG_NODE) +    { +      if (strncmp ("i", argv[0], 1) == 0) +	{ +	  DEBUG_OFF (update, UPDATE_OUT); +	  DEBUG_ON (update, UPDATE_IN); +	} +      else +	{	 +	  DEBUG_OFF (update, UPDATE_IN); +	  DEBUG_ON (update, UPDATE_OUT); +	} +    } +  else +    { +      if (strncmp ("i", argv[0], 1) == 0) +	{ +	  TERM_DEBUG_OFF (update, UPDATE_OUT); +	  TERM_DEBUG_ON (update, UPDATE_IN); +	  vty_out (vty, "BGP updates debugging is on (inbound)%s", VTY_NEWLINE); +	} +      else +	{ +	  TERM_DEBUG_OFF (update, UPDATE_IN); +	  TERM_DEBUG_ON (update, UPDATE_OUT); +	  vty_out (vty, "BGP updates debugging is on (outbound)%s", VTY_NEWLINE); +	} +    } +  return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_update, +       no_debug_bgp_update_cmd, +       "no debug bgp updates", +       NO_STR +       DEBUG_STR +       BGP_STR +       "BGP updates\n") +{ +  if (vty->node == CONFIG_NODE) +    { +      DEBUG_OFF (update, UPDATE_IN); +      DEBUG_OFF (update, UPDATE_OUT); +    } +  else +    { +      TERM_DEBUG_OFF (update, UPDATE_IN); +      TERM_DEBUG_OFF (update, UPDATE_OUT); +      vty_out (vty, "BGP updates debugging is off%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_update, +       undebug_bgp_update_cmd, +       "undebug bgp updates", +       UNDEBUG_STR +       BGP_STR +       "BGP updates\n") + +DEFUN (debug_bgp_normal, +       debug_bgp_normal_cmd, +       "debug bgp", +       DEBUG_STR +       BGP_STR) +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_ON (normal, NORMAL); +  else +    { +      TERM_DEBUG_ON (normal, NORMAL); +      vty_out (vty, "BGP debugging is on%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_normal, +       no_debug_bgp_normal_cmd, +       "no debug bgp", +       NO_STR +       DEBUG_STR +       BGP_STR) +{ +  if (vty->node == CONFIG_NODE) +    DEBUG_OFF (normal, NORMAL); +  else +    { +      TERM_DEBUG_OFF (normal, NORMAL); +      vty_out (vty, "BGP debugging is off%s", VTY_NEWLINE); +    } +  return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_normal, +       undebug_bgp_normal_cmd, +       "undebug bgp", +       UNDEBUG_STR +       BGP_STR) + +DEFUN (no_debug_bgp_all, +       no_debug_bgp_all_cmd, +       "no debug all bgp", +       NO_STR +       DEBUG_STR +       "Enable all debugging\n" +       BGP_STR) +{ +  TERM_DEBUG_OFF (normal, NORMAL); +  TERM_DEBUG_OFF (events, EVENTS); +  TERM_DEBUG_OFF (keepalive, KEEPALIVE); +  TERM_DEBUG_OFF (update, UPDATE_IN); +  TERM_DEBUG_OFF (update, UPDATE_OUT); +  TERM_DEBUG_OFF (fsm, FSM); +  TERM_DEBUG_OFF (filter, FILTER); +  vty_out (vty, "All possible debugging has been turned off%s", VTY_NEWLINE); +       +  return CMD_SUCCESS; +} + +ALIAS (no_debug_bgp_all, +       undebug_bgp_all_cmd, +       "undebug all bgp", +       UNDEBUG_STR +       "Enable all debugging\n" +       BGP_STR) + +DEFUN (show_debugging_bgp, +       show_debugging_bgp_cmd, +       "show debugging bgp", +       SHOW_STR +       DEBUG_STR +       BGP_STR) +{ +  vty_out (vty, "BGP debugging status:%s", VTY_NEWLINE); + +  if (BGP_DEBUG (normal, NORMAL)) +    vty_out (vty, "  BGP debugging is on%s", VTY_NEWLINE); +  if (BGP_DEBUG (events, EVENTS)) +    vty_out (vty, "  BGP events debugging is on%s", VTY_NEWLINE); +  if (BGP_DEBUG (keepalive, KEEPALIVE)) +    vty_out (vty, "  BGP keepalives debugging is on%s", VTY_NEWLINE); +  if (BGP_DEBUG (update, UPDATE_IN) && BGP_DEBUG (update, UPDATE_OUT)) +    vty_out (vty, "  BGP updates debugging is on%s", VTY_NEWLINE); +  else if (BGP_DEBUG (update, UPDATE_IN)) +    vty_out (vty, "  BGP updates debugging is on (inbound)%s", VTY_NEWLINE); +  else if (BGP_DEBUG (update, UPDATE_OUT)) +    vty_out (vty, "  BGP updates debugging is on (outbound)%s", VTY_NEWLINE); +  if (BGP_DEBUG (fsm, FSM)) +    vty_out (vty, "  BGP fsm debugging is on%s", VTY_NEWLINE); +  if (BGP_DEBUG (filter, FILTER)) +    vty_out (vty, "  BGP filter debugging is on%s", VTY_NEWLINE); +  vty_out (vty, "%s", VTY_NEWLINE); +  return CMD_SUCCESS; +} + +int +bgp_config_write_debug (struct vty *vty) +{ +  int write = 0; + +  if (CONF_BGP_DEBUG (normal, NORMAL)) +    { +      vty_out (vty, "debug bgp%s", VTY_NEWLINE); +      write++; +    } + +  if (CONF_BGP_DEBUG (events, EVENTS)) +    { +      vty_out (vty, "debug bgp events%s", VTY_NEWLINE); +      write++; +    } + +  if (CONF_BGP_DEBUG (keepalive, KEEPALIVE)) +    { +      vty_out (vty, "debug bgp keepalives%s", VTY_NEWLINE); +      write++; +    } + +  if (CONF_BGP_DEBUG (update, UPDATE_IN) && CONF_BGP_DEBUG (update, UPDATE_OUT)) +    { +      vty_out (vty, "debug bgp updates%s", VTY_NEWLINE); +      write++; +    } +  else if (CONF_BGP_DEBUG (update, UPDATE_IN)) +    { +      vty_out (vty, "debug bgp updates in%s", VTY_NEWLINE); +      write++; +    } +  else if (CONF_BGP_DEBUG (update, UPDATE_OUT)) +    { +      vty_out (vty, "debug bgp updates out%s", VTY_NEWLINE); +      write++; +    } + +  if (CONF_BGP_DEBUG (fsm, FSM)) +    { +      vty_out (vty, "debug bgp fsm%s", VTY_NEWLINE); +      write++; +    } + +  if (CONF_BGP_DEBUG (filter, FILTER)) +    { +      vty_out (vty, "debug bgp filters%s", VTY_NEWLINE); +      write++; +    } + +  return write; +} + +struct cmd_node debug_node = +{ +  DEBUG_NODE, +  "", +  1 +}; + +void +bgp_debug_init () +{ +  install_node (&debug_node, bgp_config_write_debug); + +  install_element (ENABLE_NODE, &show_debugging_bgp_cmd); + +  install_element (ENABLE_NODE, &debug_bgp_fsm_cmd); +  install_element (CONFIG_NODE, &debug_bgp_fsm_cmd); +  install_element (ENABLE_NODE, &debug_bgp_events_cmd); +  install_element (CONFIG_NODE, &debug_bgp_events_cmd); +  install_element (ENABLE_NODE, &debug_bgp_filter_cmd); +  install_element (CONFIG_NODE, &debug_bgp_filter_cmd); +  install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd); +  install_element (CONFIG_NODE, &debug_bgp_keepalive_cmd); +  install_element (ENABLE_NODE, &debug_bgp_update_cmd); +  install_element (CONFIG_NODE, &debug_bgp_update_cmd); +  install_element (ENABLE_NODE, &debug_bgp_update_direct_cmd); +  install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd); +  install_element (ENABLE_NODE, &debug_bgp_normal_cmd); +  install_element (CONFIG_NODE, &debug_bgp_normal_cmd); + +  install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd); +  install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd); +  install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd); +  install_element (ENABLE_NODE, &no_debug_bgp_events_cmd); +  install_element (ENABLE_NODE, &undebug_bgp_events_cmd); +  install_element (CONFIG_NODE, &no_debug_bgp_events_cmd); +  install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd); +  install_element (ENABLE_NODE, &undebug_bgp_filter_cmd); +  install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd); +  install_element (ENABLE_NODE, &no_debug_bgp_keepalive_cmd); +  install_element (ENABLE_NODE, &undebug_bgp_keepalive_cmd); +  install_element (CONFIG_NODE, &no_debug_bgp_keepalive_cmd); +  install_element (ENABLE_NODE, &no_debug_bgp_update_cmd); +  install_element (ENABLE_NODE, &undebug_bgp_update_cmd); +  install_element (CONFIG_NODE, &no_debug_bgp_update_cmd); +  install_element (ENABLE_NODE, &no_debug_bgp_normal_cmd); +  install_element (ENABLE_NODE, &undebug_bgp_normal_cmd); +  install_element (CONFIG_NODE, &no_debug_bgp_normal_cmd); +  install_element (ENABLE_NODE, &no_debug_bgp_all_cmd); +  install_element (ENABLE_NODE, &undebug_bgp_all_cmd); +} diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h new file mode 100644 index 0000000000..06ba075789 --- /dev/null +++ b/bgpd/bgp_debug.h @@ -0,0 +1,113 @@ +/* BGP message debug header. +   Copyright (C) 1996, 97, 98 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +/* sort of packet direction */ +#define DUMP_ON        1 +#define DUMP_SEND      2 +#define DUMP_RECV      4 + +/* for dump_update */ +#define DUMP_WITHDRAW  8 +#define DUMP_NLRI     16 + +/* dump detail */ +#define DUMP_DETAIL   32 + +extern int dump_open; +extern int dump_update; +extern int dump_keepalive; +extern int dump_notify; + +extern int Debug_Event; +extern int Debug_Keepalive; +extern int Debug_Update; +extern int Debug_Radix; + +#define	NLRI	 1 +#define	WITHDRAW 2 +#define	NO_OPT	 3 +#define	SEND	 4 +#define	RECV	 5 +#define	DETAIL	 6 + +/* Prototypes. */ +void bgp_debug_init (); +void bgp_packet_dump (struct stream *); + +int debug (unsigned int option); + +extern unsigned long conf_bgp_debug_fsm; +extern unsigned long conf_bgp_debug_events; +extern unsigned long conf_bgp_debug_packet; +extern unsigned long conf_bgp_debug_filter; +extern unsigned long conf_bgp_debug_keepalive; +extern unsigned long conf_bgp_debug_update; +extern unsigned long conf_bgp_debug_normal; + +extern unsigned long term_bgp_debug_fsm; +extern unsigned long term_bgp_debug_events; +extern unsigned long term_bgp_debug_packet; +extern unsigned long term_bgp_debug_filter; +extern unsigned long term_bgp_debug_keepalive; +extern unsigned long term_bgp_debug_update; +extern unsigned long term_bgp_debug_normal; + +#define BGP_DEBUG_FSM                 0x01 +#define BGP_DEBUG_EVENTS              0x01 +#define BGP_DEBUG_PACKET              0x01 +#define BGP_DEBUG_FILTER              0x01 +#define BGP_DEBUG_KEEPALIVE           0x01 +#define BGP_DEBUG_UPDATE_IN           0x01 +#define BGP_DEBUG_UPDATE_OUT          0x02 +#define BGP_DEBUG_NORMAL              0x01 + +#define BGP_DEBUG_PACKET_SEND         0x01 +#define BGP_DEBUG_PACKET_SEND_DETAIL  0x02 + +#define BGP_DEBUG_PACKET_RECV         0x01 +#define BGP_DEBUG_PACKET_RECV_DETAIL  0x02 + +#define CONF_DEBUG_ON(a, b)	(conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b)) +#define CONF_DEBUG_OFF(a, b)	(conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b)) + +#define TERM_DEBUG_ON(a, b)	(term_bgp_debug_ ## a |= (BGP_DEBUG_ ## b)) +#define TERM_DEBUG_OFF(a, b)	(term_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b)) + +#define DEBUG_ON(a, b) \ +    do { \ +	CONF_DEBUG_ON(a, b); \ +	TERM_DEBUG_ON(a, b); \ +    } while (0) +#define DEBUG_OFF(a, b) \ +    do { \ +	CONF_DEBUG_OFF(a, b); \ +	TERM_DEBUG_OFF(a, b); \ +    } while (0) + +#define BGP_DEBUG(a, b)		(term_bgp_debug_ ## a & BGP_DEBUG_ ## b) +#define CONF_BGP_DEBUG(a, b)    (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b) + +extern char *bgp_type_str[]; + +void bgp_dump_attr (struct peer *, struct attr *, char *, size_t); +void bgp_notify_print (struct peer *, struct bgp_notify *, char *); + +extern struct message bgp_status_msg[]; +extern int bgp_status_msg_max; diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c new file mode 100644 index 0000000000..fca51edc7c --- /dev/null +++ b/bgpd/bgp_dump.c @@ -0,0 +1,741 @@ +/* BGP-4 dump routine +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "log.h" +#include "stream.h" +#include "sockunion.h" +#include "command.h" +#include "prefix.h" +#include "thread.h" +#include "bgpd/bgp_table.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_dump.h" + +enum bgp_dump_type +{ +  BGP_DUMP_ALL, +  BGP_DUMP_UPDATES, +  BGP_DUMP_ROUTES +}; + +enum MRT_MSG_TYPES { +   MSG_NULL, +   MSG_START,                   /* sender is starting up */ +   MSG_DIE,                     /* receiver should shut down */ +   MSG_I_AM_DEAD,               /* sender is shutting down */ +   MSG_PEER_DOWN,               /* sender's peer is down */ +   MSG_PROTOCOL_BGP,            /* msg is a BGP packet */ +   MSG_PROTOCOL_RIP,            /* msg is a RIP packet */ +   MSG_PROTOCOL_IDRP,           /* msg is an IDRP packet */ +   MSG_PROTOCOL_RIPNG,          /* msg is a RIPNG packet */ +   MSG_PROTOCOL_BGP4PLUS,       /* msg is a BGP4+ packet */ +   MSG_PROTOCOL_BGP4PLUS_01,    /* msg is a BGP4+ (draft 01) packet */ +   MSG_PROTOCOL_OSPF,           /* msg is an OSPF packet */ +   MSG_TABLE_DUMP               /* routing table dump */ +}; + +struct bgp_dump +{ +  enum bgp_dump_type type; + +  char *filename; + +  FILE *fp; + +  unsigned int interval; + +  char *interval_str; + +  struct thread *t_interval; +}; + +/* BGP packet dump output buffer. */ +struct stream *bgp_dump_obuf; + +/* BGP dump strucuture for 'dump bgp all' */ +struct bgp_dump bgp_dump_all; + +/* BGP dump structure for 'dump bgp updates' */ +struct bgp_dump bgp_dump_updates; + +/* BGP dump structure for 'dump bgp routes' */ +struct bgp_dump bgp_dump_routes; + +/* Dump whole BGP table is very heavy process.  */ +struct thread *t_bgp_dump_routes; + +/* Some define for BGP packet dump. */ +FILE * +bgp_dump_open_file (struct bgp_dump *bgp_dump) +{ +  int ret; +  time_t clock; +  struct tm *tm; +  char fullpath[MAXPATHLEN]; +  char realpath[MAXPATHLEN]; + +  time (&clock); +  tm = localtime (&clock); + +  if (bgp_dump->filename[0] != DIRECTORY_SEP) +    { +      sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename); +      ret = strftime (realpath, MAXPATHLEN, fullpath, tm); +    } +  else +    ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm); + +  if (ret == 0) +    { +      zlog_warn ("bgp_dump_open_file: strftime error"); +      return NULL; +    } + +  if (bgp_dump->fp) +    fclose (bgp_dump->fp); + + +  bgp_dump->fp = fopen (realpath, "w"); + +  if (bgp_dump->fp == NULL) +    return NULL; + +  return bgp_dump->fp; +} + +int +bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval) +{ +  int bgp_dump_interval_func (struct thread *); + +  bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func,  +					   bgp_dump, interval); +  return 0; +} + +/* Dump common header. */ +void +bgp_dump_header (struct stream *obuf, int type, int subtype) +{ +  time_t now; + +  /* Set header. */ +  time (&now); + +  /* Put dump packet header. */ +  stream_putl (obuf, now);	 +  stream_putw (obuf, type); +  stream_putw (obuf, subtype); + +  stream_putl (obuf, 0);	/* len */ +} + +void +bgp_dump_set_size (struct stream *s, int type) +{ +  stream_putl_at (s, 8, stream_get_putp (s) - BGP_DUMP_HEADER_SIZE); +} + +void +bgp_dump_routes_entry (struct prefix *p, struct bgp_info *info, int afi, +		       int type, unsigned int seq) +{ +  struct stream *obuf; +  struct attr *attr; +  struct peer *peer; +  int plen; +  int safi = 0; + +  /* Make dump stream. */ +  obuf = bgp_dump_obuf; +  stream_reset (obuf); + +  attr = info->attr; +  peer = info->peer; + +  /* We support MRT's old format. */ +  if (type == MSG_TABLE_DUMP) +    { +      bgp_dump_header (obuf, MSG_TABLE_DUMP, afi); +      stream_putw (obuf, 0);	/* View # */ +      stream_putw (obuf, seq);	/* Sequence number. */ +    } +  else +    { +      bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY); +       +      stream_putl (obuf, info->uptime); /* Time Last Change */ +      stream_putw (obuf, afi);	/* Address Family */ +      stream_putc (obuf, safi);	/* SAFI */ +    } + +  if (afi == AFI_IP) +    { +      if (type == MSG_TABLE_DUMP) +	{ +	  /* Prefix */ +	  stream_put_in_addr (obuf, &p->u.prefix4); +	  stream_putc (obuf, p->prefixlen); + +	  /* Status */ +	  stream_putc (obuf, 1); + +	  /* Originated */ +	  stream_putl (obuf, info->uptime); + +	  /* Peer's IP address */ +	  stream_put_in_addr (obuf, &peer->su.sin.sin_addr); + +	  /* Peer's AS number. */ +	  stream_putw (obuf, peer->as); + +	  /* Dump attribute. */ +	  bgp_dump_routes_attr (obuf, attr); +	} +      else +	{ +	  /* Next-Hop-Len */ +	  stream_putc (obuf, IPV4_MAX_BYTELEN); +	  stream_put_in_addr (obuf, &attr->nexthop); +	  stream_putc (obuf, p->prefixlen); +	  plen = PSIZE (p->prefixlen); +	  stream_put (obuf, &p->u.prefix4, plen); +	  bgp_dump_routes_attr (obuf, attr); +	} +    } +#ifdef HAVE_IPV6 +  else if (afi == AFI_IP6) +    { +      if (type == MSG_TABLE_DUMP) +	{ +	  /* Prefix */ +	  stream_write (obuf, (u_char *)&p->u.prefix6, IPV6_MAX_BYTELEN); +	  stream_putc (obuf, p->prefixlen); + +	  /* Status */ +	  stream_putc (obuf, 1); + +	  /* Originated */ +	  stream_putl (obuf, info->uptime); + +	  /* Peer's IP address */ +	  stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr, +			IPV6_MAX_BYTELEN); + +	  /* Peer's AS number. */ +	  stream_putw (obuf, peer->as); + +	  /* Dump attribute. */ +	  bgp_dump_routes_attr (obuf, attr); +	} +      else +	{ +	  ; +	} +    } +#endif /* HAVE_IPV6 */ + +  /* Set length. */ +  bgp_dump_set_size (obuf, type); + +  fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_routes.fp); +  fflush (bgp_dump_routes.fp); +} + +/* Runs under child process. */ +void +bgp_dump_routes_func (int afi) +{ +  struct stream *obuf; +  struct bgp_node *rn; +  struct bgp_info *info; +  struct bgp *bgp; +  struct bgp_table *table; +  unsigned int seq = 0; + +  obuf = bgp_dump_obuf; + +  bgp = bgp_get_default (); +  if (!bgp) +    return; + +  if (bgp_dump_routes.fp == NULL) +    return; + +  /* Walk down each BGP route. */ +  table = bgp->rib[afi][SAFI_UNICAST]; + +  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) +    for (info = rn->info; info; info = info->next) +      bgp_dump_routes_entry (&rn->p, info, afi, MSG_TABLE_DUMP, seq++); +} + +int +bgp_dump_interval_func (struct thread *t) +{ +  struct bgp_dump *bgp_dump; + +  bgp_dump = THREAD_ARG (t); +  bgp_dump->t_interval = NULL; + +  if (bgp_dump_open_file (bgp_dump) == NULL) +    return 0; + +  /* In case of bgp_dump_routes, we need special route dump function. */ +  if (bgp_dump->type == BGP_DUMP_ROUTES) +    { +      bgp_dump_routes_func (AFI_IP); +      bgp_dump_routes_func (AFI_IP6); +    } + +  bgp_dump_interval_add (bgp_dump, bgp_dump->interval); +   +  return 0; +} + +/* Dump common information. */ +void +bgp_dump_common (struct stream *obuf, struct peer *peer) +{ +  char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +  /* Source AS number and Destination AS number. */ +  stream_putw (obuf, peer->as); +  stream_putw (obuf, peer->local_as); + +  if (peer->afc[AFI_IP][SAFI_UNICAST]) +    { +      stream_putw (obuf, peer->ifindex); +      stream_putw (obuf, AFI_IP); + +      stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN); + +      if (peer->su_local) +	stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN); +      else +	stream_put (obuf, empty, IPV4_MAX_BYTELEN); +    } +#ifdef HAVE_IPV6 +  else if (peer->afc[AFI_IP6][SAFI_UNICAST]) +    { +      /* Interface Index and Address family. */ +      stream_putw (obuf, peer->ifindex); +      stream_putw (obuf, AFI_IP6); + +      /* Source IP Address and Destination IP Address. */ +      stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN); + +      if (peer->su_local) +	stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN); +      else +	stream_put (obuf, empty, IPV6_MAX_BYTELEN); +    } +#endif /* HAVE_IPV6 */ +} + +/* Dump BGP status change. */ +void +bgp_dump_state (struct peer *peer, int status_old, int status_new) +{ +  struct stream *obuf; + +  /* If dump file pointer is disabled return immediately. */ +  if (bgp_dump_all.fp == NULL) +    return; + +  /* Make dump stream. */ +  obuf = bgp_dump_obuf; +  stream_reset (obuf); + +  bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE); +  bgp_dump_common (obuf, peer); + +  stream_putw (obuf, status_old); +  stream_putw (obuf, status_new); + +  /* Set length. */ +  bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP); + +  /* Write to the stream. */ +  fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_all.fp); +  fflush (bgp_dump_all.fp); +} + +void +bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer, +		      struct stream *packet) +{ +  struct stream *obuf; + +  /* If dump file pointer is disabled return immediately. */ +  if (bgp_dump->fp == NULL) +    return; + +  /* Make dump stream. */ +  obuf = bgp_dump_obuf; +  stream_reset (obuf); + +  /* Dump header and common part. */ +  bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE); +  bgp_dump_common (obuf, peer); + +  /* Packet contents. */ +  stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet)); +   +  /* Set length. */ +  bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP); + +  /* Write to the stream. */ +  fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump->fp); +  fflush (bgp_dump->fp); +} + +/* Called from bgp_packet.c when BGP packet is received. */ +void +bgp_dump_packet (struct peer *peer, int type, struct stream *packet) +{ +  /* bgp_dump_all. */ +  bgp_dump_packet_func (&bgp_dump_all, peer, packet); + +  /* bgp_dump_updates. */ +  if (type == BGP_MSG_UPDATE) +    bgp_dump_packet_func (&bgp_dump_updates, peer, packet); +} + +unsigned int +bgp_dump_parse_time (char *str) +{ +  int i; +  int len; +  int seen_h; +  int seen_m; +  int time; +  unsigned int total; + +  time = 0; +  total = 0; +  seen_h = 0; +  seen_m = 0; +  len = strlen (str); + +  for (i = 0; i < len; i++) +    { +      if (isdigit ((int) str[i])) +	{ +	  time *= 10; +	  time += str[i] - '0'; +	} +      else if (str[i] == 'H' || str[i] == 'h') +	{ +	  if (seen_h) +	    return 0; +	  if (seen_m) +	    return 0; +	  total += time * 60 *60; +	  time = 0; +	  seen_h = 1; +	} +      else if (str[i] == 'M' || str[i] == 'm') +	{ +	  if (seen_m) +	    return 0; +	  total += time * 60; +	  time = 0; +	  seen_h = 1; +	} +      else +	return 0; +    } +  return total + time; +} + +int +bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, int type, +	      char *path, char *interval_str) +{ +  if (interval_str) +    { +      unsigned int interval; + +      /* Check interval string. */ +      interval = bgp_dump_parse_time (interval_str); +      if (interval == 0) +	{ +	  vty_out (vty, "Malformed interval string%s", VTY_NEWLINE); +	  return CMD_WARNING; +	} +      /* Set interval. */ +      bgp_dump->interval = interval; +      if (bgp_dump->interval_str) +	free (bgp_dump->interval_str); +      bgp_dump->interval_str = strdup (interval_str); + +      /* Create interval thread. */ +      bgp_dump_interval_add (bgp_dump, interval); +    } + +  /* Set type. */ +  bgp_dump->type = type; + +  /* Set file name. */ +  if (bgp_dump->filename) +    free (bgp_dump->filename); +  bgp_dump->filename = strdup (path); + +  /* This should be called when interval is expired. */ +  bgp_dump_open_file (bgp_dump); + +  return CMD_SUCCESS; +} + +int +bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump) +{ +  /* Set file name. */ +  if (bgp_dump->filename) +    { +      free (bgp_dump->filename); +      bgp_dump->filename = NULL; +    } + +  /* This should be called when interval is expired. */ +  if (bgp_dump->fp) +    { +      fclose (bgp_dump->fp); +      bgp_dump->fp = NULL; +    } + +  /* Create interval thread. */ +  if (bgp_dump->t_interval) +    { +      thread_cancel (bgp_dump->t_interval); +      bgp_dump->t_interval = NULL; +    } + +  bgp_dump->interval = 0; + +  if (bgp_dump->interval_str) +    { +      free (bgp_dump->interval_str); +      bgp_dump->interval_str = NULL; +    } +   + +  return CMD_SUCCESS; +} + +DEFUN (dump_bgp_all, +       dump_bgp_all_cmd, +       "dump bgp all PATH", +       "Dump packet\n" +       "BGP packet dump\n" +       "Dump all BGP packets\n" +       "Output filename\n") +{ +  return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL); +} + +DEFUN (dump_bgp_all_interval, +       dump_bgp_all_interval_cmd, +       "dump bgp all PATH INTERVAL", +       "Dump packet\n" +       "BGP packet dump\n" +       "Dump all BGP packets\n" +       "Output filename\n" +       "Interval of output\n") +{ +  return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]); +} + +DEFUN (no_dump_bgp_all, +       no_dump_bgp_all_cmd, +       "no dump bgp all [PATH] [INTERVAL]", +       NO_STR +       "Dump packet\n" +       "BGP packet dump\n" +       "Dump all BGP packets\n") +{ +  return bgp_dump_unset (vty, &bgp_dump_all); +} + +DEFUN (dump_bgp_updates, +       dump_bgp_updates_cmd, +       "dump bgp updates PATH", +       "Dump packet\n" +       "BGP packet dump\n" +       "Dump BGP updates only\n" +       "Output filename\n") +{ +  return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL); +} + +DEFUN (dump_bgp_updates_interval, +       dump_bgp_updates_interval_cmd, +       "dump bgp updates PATH INTERVAL", +       "Dump packet\n" +       "BGP packet dump\n" +       "Dump BGP updates only\n" +       "Output filename\n" +       "Interval of output\n") +{ +  return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]); +} + +DEFUN (no_dump_bgp_updates, +       no_dump_bgp_updates_cmd, +       "no dump bgp updates [PATH] [INTERVAL]", +       NO_STR +       "Dump packet\n" +       "BGP packet dump\n" +       "Dump BGP updates only\n") +{ +  return bgp_dump_unset (vty, &bgp_dump_updates); +} + +DEFUN (dump_bgp_routes, +       dump_bgp_routes_cmd, +       "dump bgp routes-mrt PATH", +       "Dump packet\n" +       "BGP packet dump\n" +       "Dump whole BGP routing table\n" +       "Output filename\n") +{ +  return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL); +} + +DEFUN (dump_bgp_routes_interval, +       dump_bgp_routes_interval_cmd, +       "dump bgp routes-mrt PATH INTERVAL", +       "Dump packet\n" +       "BGP packet dump\n" +       "Dump whole BGP routing table\n" +       "Output filename\n" +       "Interval of output\n") +{ +  return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]); +} + +DEFUN (no_dump_bgp_routes, +       no_dump_bgp_routes_cmd, +       "no dump bgp routes-mrt [PATH] [INTERVAL]", +       NO_STR +       "Dump packet\n" +       "BGP packet dump\n" +       "Dump whole BGP routing table\n") +{ +  return bgp_dump_unset (vty, &bgp_dump_routes); +} + +/* BGP node structure. */ +struct cmd_node bgp_dump_node = +{ +  DUMP_NODE, +  "", +}; + +#if 0 +char * +config_time2str (unsigned int interval) +{ +  static char buf[BUFSIZ]; + +  buf[0] = '\0'; + +  if (interval / 3600) +    { +      sprintf (buf, "%dh", interval / 3600); +      interval %= 3600; +    } +  if (interval / 60) +    { +      sprintf (buf + strlen (buf), "%dm", interval /60); +      interval %= 60; +    } +  if (interval) +    { +      sprintf (buf + strlen (buf), "%d", interval); +    } +  return buf; +} +#endif + +int +config_write_bgp_dump (struct vty *vty) +{ +  if (bgp_dump_all.filename) +    { +      if (bgp_dump_all.interval_str) +	vty_out (vty, "dump bgp all %s %s%s",  +		 bgp_dump_all.filename, bgp_dump_all.interval_str, +		 VTY_NEWLINE); +      else +	vty_out (vty, "dump bgp all %s%s",  +		 bgp_dump_all.filename, VTY_NEWLINE); +    } +  if (bgp_dump_updates.filename) +    { +      if (bgp_dump_updates.interval_str) +	vty_out (vty, "dump bgp updates %s %s%s",  +		 bgp_dump_updates.filename, bgp_dump_updates.interval_str, +		 VTY_NEWLINE); +      else +	vty_out (vty, "dump bgp updates %s%s",  +		 bgp_dump_updates.filename, VTY_NEWLINE); +    } +  if (bgp_dump_routes.filename) +    { +      if (bgp_dump_routes.interval_str) +	vty_out (vty, "dump bgp routes-mrt %s %s%s",  +		 bgp_dump_routes.filename, bgp_dump_routes.interval_str, +		 VTY_NEWLINE); +      else +	vty_out (vty, "dump bgp routes-mrt %s%s",  +		 bgp_dump_routes.filename, VTY_NEWLINE); +    } +  return 0; +} + +/* Initialize BGP packet dump functionality. */ +void +bgp_dump_init () +{ +  memset (&bgp_dump_all, 0, sizeof (struct bgp_dump)); +  memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump)); +  memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump)); + +  bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_HEADER_SIZE); + +  install_node (&bgp_dump_node, config_write_bgp_dump); + +  install_element (CONFIG_NODE, &dump_bgp_all_cmd); +  install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd); +  install_element (CONFIG_NODE, &no_dump_bgp_all_cmd); +  install_element (CONFIG_NODE, &dump_bgp_updates_cmd); +  install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd); +  install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd); +  install_element (CONFIG_NODE, &dump_bgp_routes_cmd); +  install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd); +  install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd); +} diff --git a/bgpd/bgp_dump.h b/bgpd/bgp_dump.h new file mode 100644 index 0000000000..d2f96a9e55 --- /dev/null +++ b/bgpd/bgp_dump.h @@ -0,0 +1,34 @@ +/* BGP dump routine. +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +/* MRT compatible packet dump values.  */ +/* type value */ +#define MSG_PROTOCOL_BGP4MP  16 +/* subtype value */ +#define BGP4MP_STATE_CHANGE   0 +#define BGP4MP_MESSAGE        1 +#define BGP4MP_ENTRY          2 +#define BGP4MP_SNAPSHOT       3 + +#define BGP_DUMP_HEADER_SIZE 12 + +void bgp_dump_init (); +void bgp_dump_state (struct peer *, int, int); +void bgp_dump_packet (struct peer *, int, struct stream *); diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c new file mode 100644 index 0000000000..2f9cc9459d --- /dev/null +++ b/bgpd/bgp_ecommunity.c @@ -0,0 +1,641 @@ +/* BGP Extended Communities Attribute +   Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org> + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "hash.h" +#include "memory.h" +#include "prefix.h" +#include "command.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_ecommunity.h" + +/* Hash of community attribute. */ +struct hash *ecomhash; + +/* Allocate a new ecommunities.  */ +struct ecommunity * +ecommunity_new () +{ +  return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY, +					sizeof (struct ecommunity)); +} + +/* Allocate ecommunities.  */ +void +ecommunity_free (struct ecommunity *ecom) +{ +  if (ecom->val) +    XFREE (MTYPE_ECOMMUNITY_VAL, ecom->val); +  if (ecom->str) +    XFREE (MTYPE_ECOMMUNITY_STR, ecom->str); +  XFREE (MTYPE_ECOMMUNITY, ecom); +} + +/* Add a new Extended Communities value to Extended Communities +   Attribute structure.  When the value is already exists in the +   structure, we don't add the value.  Newly added value is sorted by +   numerical order.  When the value is added to the structure return 1 +   else return 0.  */ +static int +ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval) +{ +  u_char *p; +  int ret; +  int c; + +  /* When this is fist value, just add it.  */ +  if (ecom->val == NULL) +    { +      ecom->size++; +      ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom)); +      memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE); +      return 1; +    } + +  /* If the value already exists in the structure return 0.  */ +  c = 0; +  for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) +    { +      ret = memcmp (p, eval->val, ECOMMUNITY_SIZE); +      if (ret == 0) +        return 0; +      if (ret > 0) +        break; +    } + +  /* Add the value to the structure with numerical sorting.  */ +  ecom->size++; +  ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom)); + +  memmove (ecom->val + (c + 1) * ECOMMUNITY_SIZE, +	   ecom->val + c * ECOMMUNITY_SIZE, +	   (ecom->size - 1 - c) * ECOMMUNITY_SIZE); +  memcpy (ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE); + +  return 1; +} + +/* This function takes pointer to Extended Communites strucutre then +   create a new Extended Communities structure by uniq and sort each +   Exteneded Communities value.  */ +struct ecommunity * +ecommunity_uniq_sort (struct ecommunity *ecom) +{ +  int i; +  struct ecommunity *new; +  struct ecommunity_val *eval; +   +  if (! ecom) +    return NULL; +   +  new = ecommunity_new ();; +   +  for (i = 0; i < ecom->size; i++) +    { +      eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); +      ecommunity_add_val (new, eval); +    } +  return new; +} + +/* Parse Extended Communites Attribute in BGP packet.  */ +struct ecommunity * +ecommunity_parse (char *pnt, u_short length) +{ +  struct ecommunity tmp; +  struct ecommunity *new; + +  /* Length check.  */ +  if (length % ECOMMUNITY_SIZE) +    return NULL; + +  /* Prepare tmporary structure for making a new Extended Communities +     Attribute.  */ +  tmp.size = length / ECOMMUNITY_SIZE; +  tmp.val = pnt; + +  /* Create a new Extended Communities Attribute by uniq and sort each +     Extended Communities value  */ +  new = ecommunity_uniq_sort (&tmp); + +  return ecommunity_intern (new); +} + +/* Duplicate the Extended Communities Attribute structure.  */ +struct ecommunity * +ecommunity_dup (struct ecommunity *ecom) +{ +  struct ecommunity *new; + +  new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity)); +  new->size = ecom->size; +  if (new->size) +    { +      new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE); +      memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE); +    } +  else +    new->val = NULL; +  return new; +} + +/* Merge two Extended Communities Attribute structure.  */ +struct ecommunity * +ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2) +{ +  if (ecom1->val) +    ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val,  +			   (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE); +  else +    ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, +			  (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE); + +  memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE), +	  ecom2->val, ecom2->size * ECOMMUNITY_SIZE); +  ecom1->size += ecom2->size; + +  return ecom1; +} + +/* Intern Extended Communities Attribute.  */ +struct ecommunity * +ecommunity_intern (struct ecommunity *ecom) +{ +  struct ecommunity *find; + +  assert (ecom->refcnt == 0); + +  find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern); + +  if (find != ecom) +    ecommunity_free (ecom); + +  find->refcnt++; + +  if (! find->str) +    find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY); + +  return find; +} + +/* Unintern Extended Communities Attribute.  */ +void +ecommunity_unintern (struct ecommunity *ecom) +{ +  struct ecommunity *ret; + +  if (ecom->refcnt) +    ecom->refcnt--; + +  /* Pull off from hash.  */ +  if (ecom->refcnt == 0) +    { +      /* Extended community must be in the hash.  */ +      ret = (struct ecommunity *) hash_release (ecomhash, ecom); +      assert (ret != NULL); + +      ecommunity_free (ecom); +    } +} + +/* Utinity function to make hash key.  */ +unsigned int +ecommunity_hash_make (struct ecommunity *ecom) +{ +  int c; +  unsigned int key; +  unsigned char *pnt; + +  key = 0; +  pnt = ecom->val; +   +  for (c = 0; c < ecom->size * ECOMMUNITY_SIZE; c++) +    key += pnt[c]; + +  return key; +} + +/* Compare two Extended Communities Attribute structure.  */ +int +ecommunity_cmp (struct ecommunity *ecom1, struct ecommunity *ecom2) +{ +  if (ecom1->size == ecom2->size +      && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0) +    return 1; +  return 0; +} + +/* Initialize Extended Comminities related hash. */ +void +ecommunity_init () +{ +  ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp); +} + +/* Extended Communities token enum. */ +enum ecommunity_token +{ +  ecommunity_token_rt, +  ecommunity_token_soo, +  ecommunity_token_val, +  ecommunity_token_unknown +}; + +/* Get next Extended Communities token from the string. */ +char * +ecommunity_gettoken (char *str, struct ecommunity_val *eval, +		     enum ecommunity_token *token) +{ +  int ret; +  int dot = 0; +  int digit = 0; +  int separator = 0; +  u_int32_t val_low = 0; +  u_int32_t val_high = 0; +  char *p = str; +  struct in_addr ip; +  char ipstr[INET_ADDRSTRLEN + 1]; + +  /* Skip white space. */ +  while (isspace ((int) *p)) +    { +      p++; +      str++; +    } + +  /* Check the end of the line. */ +  if (*p == '\0') +    return NULL; + +  /* "rt" and "soo" keyword parse. */ +  if (! isdigit ((int) *p))  +    { +      /* "rt" match check.  */ +      if (tolower ((int) *p) == 'r') +	{ +	  p++; + 	  if (tolower ((int) *p) == 't') +	    { +	      p++; +	      *token = ecommunity_token_rt; +	      return p; +	    } +	  if (isspace ((int) *p) || *p == '\0') +	    { +	      *token = ecommunity_token_rt; +	      return p; +	    } +	  goto error; +	} +      /* "soo" match check.  */ +      else if (tolower ((int) *p) == 's') +	{ +	  p++; + 	  if (tolower ((int) *p) == 'o') +	    { +	      p++; +	      if (tolower ((int) *p) == 'o') +		{ +		  p++; +		  *token = ecommunity_token_soo; +		  return p; +		} +	      if (isspace ((int) *p) || *p == '\0') +		{ +		  *token = ecommunity_token_soo; +		  return p; +		} +	      goto error; +	    } +	  if (isspace ((int) *p) || *p == '\0') +	    { +	      *token = ecommunity_token_soo; +	      return p; +	    } +	  goto error; +	} +      goto error; +    } +   +  while (isdigit ((int) *p) || *p == ':' || *p == '.')  +    { +      if (*p == ':')  +	{ +	  if (separator) +	    goto error; + +	  separator = 1; +	  digit = 0; + +	  if (dot) +	    { +	      if ((p - str) > INET_ADDRSTRLEN) +		goto error; + +	      memset (ipstr, 0, INET_ADDRSTRLEN + 1); +	      memcpy (ipstr, str, p - str); + +	      ret = inet_aton (ipstr, &ip); +	      if (ret == 0) +		goto error; +	    } +	  else +	    val_high = val_low; + +	  val_low = 0; +	} +      else if (*p == '.') +	{ +	  if (separator) +	    goto error; +	  dot++; +	  if (dot > 4) +	    goto error; +	} +      else +	{ +	  digit = 1; +	  val_low *= 10; +	  val_low += (*p - '0'); +	} +      p++; +    } + +  /* Low digit part must be there. */ +  if (! digit || ! separator) +    goto error; + +  /* Encode result into routing distinguisher.  */ +  if (dot) +    { +      eval->val[0] = ECOMMUNITY_ENCODE_IP; +      eval->val[1] = 0; +      memcpy (&eval->val[2], &ip, sizeof (struct in_addr)); +      eval->val[6] = (val_low >> 8) & 0xff; +      eval->val[7] = val_low & 0xff; +    } +  else +    { +      eval->val[0] = ECOMMUNITY_ENCODE_AS; +      eval->val[1] = 0; +      eval->val[2] = (val_high >>8) & 0xff; +      eval->val[3] = val_high & 0xff; +      eval->val[4] = (val_low >>24) & 0xff; +      eval->val[5] = (val_low >>16) & 0xff; +      eval->val[6] = (val_low >>8) & 0xff; +      eval->val[7] = val_low & 0xff; +    } +  *token = ecommunity_token_val; +  return p; + + error: +  *token = ecommunity_token_unknown; +  return p; +} + +/* Convert string to extended community attribute.  + +   When type is already known, please specify both str and type.  str +   should not include keyword such as "rt" and "soo".  Type is +   ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN. +   keyword_included should be zero. + +   For example route-map's "set extcommunity" command case: + +   "rt 100:1 100:2 100:3"        -> str = "100:1 100:2 100:3" +                                    type = ECOMMUNITY_ROUTE_TARGET +                                    keyword_included = 0 + +   "soo 100:1"                   -> str = "100:1" +                                    type = ECOMMUNITY_SITE_ORIGIN +                                    keyword_included = 0 + +   When string includes keyword for each extended community value. +   Please specify keyword_included as non-zero value. + +   For example standard extcommunity-list case: + +   "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1" +                                    type = 0 +                                    keyword_include = 1 +*/ +struct ecommunity * +ecommunity_str2com (char *str, int type, int keyword_included) +{ +  struct ecommunity *ecom = NULL; +  enum ecommunity_token token; +  struct ecommunity_val eval; +  int keyword = 0; + +  while ((str = ecommunity_gettoken (str, &eval, &token))) +    { +      switch (token) +	{ +	case ecommunity_token_rt: +	case ecommunity_token_soo: +	  if (! keyword_included || keyword) +	    { +	      if (ecom) +		ecommunity_free (ecom); +	      return NULL; +	    } +	  keyword = 1; + +	  if (token == ecommunity_token_rt) +	    { +	      type = ECOMMUNITY_ROUTE_TARGET; +	    } +	  if (token == ecommunity_token_soo) +	    { +	      type = ECOMMUNITY_SITE_ORIGIN; +	    } +	  break; +	case ecommunity_token_val: +	  if (keyword_included) +	    { +	      if (! keyword) +		{ +		  if (ecom) +		    ecommunity_free (ecom); +		  return NULL; +		} +	      keyword = 0; +	    } +	  if (ecom == NULL) +	    ecom = ecommunity_new (); +	  eval.val[1] = type; +	  ecommunity_add_val (ecom, &eval); +	  break; +	case ecommunity_token_unknown: +	default: +	  if (ecom) +	    ecommunity_free (ecom); +	  return NULL; +	  break; +	} +    } +  return ecom; +} + +/* Convert extended community attribute to string.   + +   Due to historical reason of industry standard implementation, there +   are three types of format. + +   route-map set extcommunity format +        "rt 100:1 100:2" +        "soo 100:3" + +   extcommunity-list +        "rt 100:1 rt 100:2 soo 100:3" + +   "show ip bgp" and extcommunity-list regular expression matching +        "RT:100:1 RT:100:2 SoO:100:3" + +   For each formath please use below definition for format: + +   ECOMMUNITY_FORMAT_ROUTE_MAP +   ECOMMUNITY_FORMAT_COMMUNITY_LIST +   ECOMMUNITY_FORMAT_DISPLAY +*/ +char * +ecommunity_ecom2str (struct ecommunity *ecom, int format) +{ +  int i; +  u_char *pnt; +  int encode = 0; +  int type = 0; +#define ECOMMUNITY_STR_DEFAULT_LEN  26 +  int str_size; +  int str_pnt; +  u_char *str_buf; +  char *prefix; +  int len = 0; +  int first = 1; + +  /* For parse Extended Community attribute tupple. */ +  struct ecommunity_as +  { +    as_t as; +    u_int32_t val; +  } eas; + +  struct ecommunity_ip +  { +    struct in_addr ip; +    u_int16_t val; +  } eip; + +  if (ecom->size == 0) +    { +      str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1); +      str_buf[0] = '\0'; +      return str_buf; +    } + +  /* Prepare buffer.  */ +  str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1); +  str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1; +  str_pnt = 0; + +  for (i = 0; i < ecom->size; i++) +    { +      pnt = ecom->val + (i * 8); + +      /* High-order octet of type. */ +      encode = *pnt++; +      if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP) +	{ +	  if (str_buf) +	    XFREE (MTYPE_ECOMMUNITY_STR, str_buf); +	  return "Unknown"; +	} +       +      /* Low-order octet of type. */ +      type = *pnt++; +      if (type !=  ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN) +	{ +	  if (str_buf) +	    XFREE (MTYPE_ECOMMUNITY_STR, str_buf); +	  return "Unknown"; +	} + +      switch (format) +	{ +	case ECOMMUNITY_FORMAT_COMMUNITY_LIST: +	  prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo "); +	  break; +	case ECOMMUNITY_FORMAT_DISPLAY: +	  prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:"); +	  break; +	case ECOMMUNITY_FORMAT_ROUTE_MAP: +	  prefix = ""; +	  break; +	default: +	  if (str_buf) +	    XFREE (MTYPE_ECOMMUNITY_STR, str_buf); +	  return "Unknown"; +	  break; +	} + +      /* Make it sure size is enough.  */ +      while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) +	{ +	  str_size *= 2; +	  str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size); +	} + +      /* Space between each value.  */ +      if (! first) +	str_buf[str_pnt++] = ' '; + +      /* Put string into buffer.  */ +      if (encode == ECOMMUNITY_ENCODE_AS) +	{ +	  eas.as = (*pnt++ << 8); +	  eas.as |= (*pnt++); + +	  eas.val = (*pnt++ << 24); +	  eas.val |= (*pnt++ << 16); +	  eas.val |= (*pnt++ << 8); +	  eas.val |= (*pnt++); + +	  len = sprintf (str_buf + str_pnt, "%s%d:%d", prefix, +			 eas.as, eas.val); +	  str_pnt += len; +	  first = 0; +	} +      else if (encode == ECOMMUNITY_ENCODE_IP) +	{ +	  memcpy (&eip.ip, pnt, 4); +	  pnt += 4; +	  eip.val = (*pnt++ << 8); +	  eip.val |= (*pnt++); + +	  len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix, +			 inet_ntoa (eip.ip), eip.val); +	  str_pnt += len; +	  first = 0; +	} +    } +  return str_buf; +} diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h new file mode 100644 index 0000000000..678d13082f --- /dev/null +++ b/bgpd/bgp_ecommunity.h @@ -0,0 +1,72 @@ +/* BGP Extended Communities Attribute. +   Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org> + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +/* High-order octet of the Extended Communities type field.  */ +#define ECOMMUNITY_ENCODE_AS                0x00 +#define ECOMMUNITY_ENCODE_IP                0x01 + +/* Low-order octet of the Extended Communityes type field.  */ +#define ECOMMUNITY_ROUTE_TARGET             0x02 +#define ECOMMUNITY_SITE_ORIGIN              0x03 + +/* Extended communities attribute string format.  */ +#define ECOMMUNITY_FORMAT_ROUTE_MAP            0 +#define ECOMMUNITY_FORMAT_COMMUNITY_LIST       1 +#define ECOMMUNITY_FORMAT_DISPLAY              2 + +/* Extended Communities value is eight octet long.  */ +#define ECOMMUNITY_SIZE                        8 + +/* Extended Communities attribute.  */ +struct ecommunity +{ +  /* Reference counter.  */ +  unsigned long refcnt; + +  /* Size of Extended Communities attribute.  */ +  int size; + +  /* Extended Communities value.  */ +  u_char *val; + +  /* Human readable format string.  */ +  char *str; +}; + +/* Extended community value is eight octet.  */ +struct ecommunity_val +{ +  char val[ECOMMUNITY_SIZE]; +}; + +#define ecom_length(X)    ((X)->size * ECOMMUNITY_SIZE) + +void ecommunity_init (void); +void ecommunity_free (struct ecommunity *); +struct ecommunity *ecommunity_new (void); +struct ecommunity *ecommunity_parse (char *, u_short); +struct ecommunity *ecommunity_dup (struct ecommunity *); +struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *); +struct ecommunity *ecommunity_intern (struct ecommunity *); +int ecommunity_cmp (struct ecommunity *, struct ecommunity *); +void ecommunity_unintern (struct ecommunity *); +unsigned int ecommunity_hash_make (struct ecommunity *); +struct ecommunity *ecommunity_str2com (char *, int, int); +char *ecommunity_ecom2str (struct ecommunity *, int); diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c new file mode 100644 index 0000000000..b544c716f7 --- /dev/null +++ b/bgpd/bgp_filter.c @@ -0,0 +1,658 @@ +/* AS path filter list. +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "command.h" +#include "log.h" +#include "memory.h" +#include "buffer.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_filter.h" + +/* List of AS filter list. */ +struct as_list_list +{ +  struct as_list *head; +  struct as_list *tail; +}; + +/* AS path filter master. */ +struct as_list_master +{ +  /* List of access_list which name is number. */ +  struct as_list_list num; + +  /* List of access_list which name is string. */ +  struct as_list_list str; + +  /* Hook function which is executed when new access_list is added. */ +  void (*add_hook) (); + +  /* Hook function which is executed when access_list is deleted. */ +  void (*delete_hook) (); +}; + +/* Element of AS path filter. */ +struct as_filter +{ +  struct as_filter *next; +  struct as_filter *prev; + +  enum as_filter_type type; + +  regex_t *reg; +  char *reg_str; +}; + +enum as_list_type +{ +  ACCESS_TYPE_STRING, +  ACCESS_TYPE_NUMBER +}; + +/* AS path filter list. */ +struct as_list +{ +  char *name; + +  enum as_list_type type; + +  struct as_list *next; +  struct as_list *prev; + +  struct as_filter *head; +  struct as_filter *tail; +}; + +/* ip as-path access-list 10 permit AS1. */ + +static struct as_list_master as_list_master = +{ +  {NULL, NULL}, +  {NULL, NULL}, +  NULL, +  NULL +}; + +/* Allocate new AS filter. */ +struct as_filter * +as_filter_new () +{ +  struct as_filter *new; + +  new = XMALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter)); +  memset (new, 0, sizeof (struct as_filter)); +  return new; +} + +/* Free allocated AS filter. */ +void +as_filter_free (struct as_filter *asfilter) +{ +  if (asfilter->reg) +    bgp_regex_free (asfilter->reg); +  if (asfilter->reg_str) +    XFREE (MTYPE_AS_FILTER_STR, asfilter->reg_str); +  XFREE (MTYPE_AS_FILTER, asfilter); +} + +/* Make new AS filter. */ +struct as_filter * +as_filter_make (regex_t *reg, char *reg_str, enum as_filter_type type) +{ +  struct as_filter *asfilter; + +  asfilter = as_filter_new (); +  asfilter->reg = reg; +  asfilter->type = type; +  asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str); + +  return asfilter; +} + +struct as_filter * +as_filter_lookup (struct as_list *aslist, char *reg_str, +		  enum as_filter_type type) +{ +  struct as_filter *asfilter; + +  for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) +    if (strcmp (reg_str, asfilter->reg_str) == 0) +      return asfilter; +  return NULL; +} + +void +as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter) +{ +  asfilter->next = NULL; +  asfilter->prev = aslist->tail; + +  if (aslist->tail) +    aslist->tail->next = asfilter; +  else +    aslist->head = asfilter; +  aslist->tail = asfilter; +} + +/* Lookup as_list from list of as_list by name. */ +struct as_list * +as_list_lookup (char *name) +{ +  struct as_list *aslist; + +  if (name == NULL) +    return NULL; + +  for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) +    if (strcmp (aslist->name, name) == 0) +      return aslist; + +  for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) +    if (strcmp (aslist->name, name) == 0) +      return aslist; + +  return NULL; +} + +struct as_list * +as_list_new () +{ +  struct as_list *new; + +  new = XMALLOC (MTYPE_AS_LIST, sizeof (struct as_list)); +  memset (new, 0, sizeof (struct as_list)); +  return new; +} + +void +as_list_free (struct as_list *aslist) +{ +  XFREE (MTYPE_AS_LIST, aslist); +} + +/* Insert new AS list to list of as_list.  Each as_list is sorted by +   the name. */ +struct as_list * +as_list_insert (char *name) +{ +  int i; +  long number; +  struct as_list *aslist; +  struct as_list *point; +  struct as_list_list *list; + +  /* Allocate new access_list and copy given name. */ +  aslist = as_list_new (); +  aslist->name = strdup (name); + +  /* If name is made by all digit character.  We treat it as +     number. */ +  for (number = 0, i = 0; i < strlen (name); i++) +    { +      if (isdigit ((int) name[i])) +	number = (number * 10) + (name[i] - '0'); +      else +	break; +    } + +  /* In case of name is all digit character */ +  if (i == strlen (name)) +    { +      aslist->type = ACCESS_TYPE_NUMBER; + +      /* Set access_list to number list. */ +      list = &as_list_master.num; + +      for (point = list->head; point; point = point->next) +	if (atol (point->name) >= number) +	  break; +    } +  else +    { +      aslist->type = ACCESS_TYPE_STRING; + +      /* Set access_list to string list. */ +      list = &as_list_master.str; +   +      /* Set point to insertion point. */ +      for (point = list->head; point; point = point->next) +	if (strcmp (point->name, name) >= 0) +	  break; +    } + +  /* In case of this is the first element of master. */ +  if (list->head == NULL) +    { +      list->head = list->tail = aslist; +      return aslist; +    } + +  /* In case of insertion is made at the tail of access_list. */ +  if (point == NULL) +    { +      aslist->prev = list->tail; +      list->tail->next = aslist; +      list->tail = aslist; +      return aslist; +    } + +  /* In case of insertion is made at the head of access_list. */ +  if (point == list->head) +    { +      aslist->next = list->head; +      list->head->prev = aslist; +      list->head = aslist; +      return aslist; +    } + +  /* Insertion is made at middle of the access_list. */ +  aslist->next = point; +  aslist->prev = point->prev; + +  if (point->prev) +    point->prev->next = aslist; +  point->prev = aslist; + +  return aslist; +} + +struct as_list * +as_list_get (char *name) +{ +  struct as_list *aslist; + +  aslist = as_list_lookup (name); +  if (aslist == NULL) +    { +      aslist = as_list_insert (name); + +      /* Run hook function. */ +      if (as_list_master.add_hook) +	(*as_list_master.add_hook) (); +    } + +  return aslist; +} + +static char * +filter_type_str (enum as_filter_type type) +{ +  switch (type) +    { +    case AS_FILTER_PERMIT: +      return "permit"; +      break; +    case AS_FILTER_DENY: +      return "deny"; +      break; +    default: +      return ""; +      break; +    } +} + +void +as_list_delete (struct as_list *aslist) +{ +  struct as_list_list *list; +  struct as_filter *filter, *next; + +  for (filter = aslist->head; filter; filter = next) +    { +      next = filter->next; +      as_filter_free (filter); +    } + +  if (aslist->type == ACCESS_TYPE_NUMBER) +    list = &as_list_master.num; +  else +    list = &as_list_master.str; + +  if (aslist->next) +    aslist->next->prev = aslist->prev; +  else +    list->tail = aslist->prev; + +  if (aslist->prev) +    aslist->prev->next = aslist->next; +  else +    list->head = aslist->next; + +  as_list_free (aslist); +} + +static int +as_list_empty (struct as_list *aslist) +{ +  if (aslist->head == NULL && aslist->tail == NULL) +    return 1; +  else +    return 0; +} + +void +as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter) +{ +  if (asfilter->next) +    asfilter->next->prev = asfilter->prev; +  else +    aslist->tail = asfilter->prev; + +  if (asfilter->prev) +    asfilter->prev->next = asfilter->next; +  else +    aslist->head = asfilter->next; + +  as_filter_free (asfilter); + +  /* If access_list becomes empty delete it from access_master. */ +  if (as_list_empty (aslist)) +    as_list_delete (aslist); + +  /* Run hook function. */ +  if (as_list_master.delete_hook) +    (*as_list_master.delete_hook) (); +} + +static int +as_filter_match (struct as_filter *asfilter, struct aspath *aspath) +{ +  if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH) +    return 1; +  return 0; +} + +/* Apply AS path filter to AS. */ +enum as_filter_type +as_list_apply (struct as_list *aslist, void *object) +{ +  struct as_filter *asfilter; +  struct aspath *aspath; + +  aspath = (struct aspath *) object; + +  if (aslist == NULL) +    return AS_FILTER_DENY; + +  for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) +    { +      if (as_filter_match (asfilter, aspath)) +	return asfilter->type; +    } +  return AS_FILTER_DENY; +} + +/* Add hook function. */ +void +as_list_add_hook (void (*func) ()) +{ +  as_list_master.add_hook = func; +} + +/* Delete hook function. */ +void +as_list_delete_hook (void (*func) ()) +{ +  as_list_master.delete_hook = func; +} + +int +as_list_dup_check (struct as_list *aslist, struct as_filter *new) +{ +  struct as_filter *asfilter; + +  for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) +    { +      if (asfilter->type == new->type +	  && strcmp (asfilter->reg_str, new->reg_str) == 0) +	return 1; +    } +  return 0; +} + +DEFUN (ip_as_path, ip_as_path_cmd, +       "ip as-path access-list WORD (deny|permit) .LINE", +       IP_STR +       "BGP autonomous system path filter\n" +       "Specify an access list name\n" +       "Regular expression access list name\n" +       "Specify packets to reject\n" +       "Specify packets to forward\n" +       "A regular-expression to match the BGP AS paths\n") +{ +  enum as_filter_type type; +  struct as_filter *asfilter; +  struct as_list *aslist; +  regex_t *regex; +  struct buffer *b; +  int i; +  char *regstr; +  int first = 0; + +  /* Check the filter type. */ +  if (strncmp (argv[1], "p", 1) == 0) +    type = AS_FILTER_PERMIT; +  else if (strncmp (argv[1], "d", 1) == 0) +    type = AS_FILTER_DENY; +  else +    { +      vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* Check AS path regex. */ +  b = buffer_new (1024); +  for (i = 2; i < argc; i++) +    { +      if (first) +	buffer_putc (b, ' '); +      else +	first = 1; + +      buffer_putstr (b, argv[i]); +    } +  buffer_putc (b, '\0'); + +  regstr = buffer_getstr (b); +  buffer_free (b); + +  regex = bgp_regcomp (regstr); +  if (!regex) +    { +      free (regstr); +      vty_out (vty, "can't compile regexp %s%s", argv[0], +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  asfilter = as_filter_make (regex, regstr, type); +   +  free (regstr); + +  /* Install new filter to the access_list. */ +  aslist = as_list_get (argv[0]); + +  /* Duplicate insertion check. */; +  if (as_list_dup_check (aslist, asfilter)) +    as_filter_free (asfilter); +  else +    as_list_filter_add (aslist, asfilter); + +  return CMD_SUCCESS; +} + +DEFUN (no_ip_as_path, +       no_ip_as_path_cmd, +       "no ip as-path access-list WORD (deny|permit) .LINE", +       NO_STR +       IP_STR +       "BGP autonomous system path filter\n" +       "Specify an access list name\n" +       "Regular expression access list name\n" +       "Specify packets to reject\n" +       "Specify packets to forward\n" +       "A regular-expression to match the BGP AS paths\n") +{ +  enum as_filter_type type; +  struct as_filter *asfilter; +  struct as_list *aslist; +  struct buffer *b; +  int i; +  int first = 0; +  char *regstr; +  regex_t *regex; + +  /* Lookup AS list from AS path list. */ +  aslist = as_list_lookup (argv[0]); +  if (aslist == NULL) +    { +      vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0], +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* Check the filter type. */ +  if (strncmp (argv[1], "p", 1) == 0) +    type = AS_FILTER_PERMIT; +  else if (strncmp (argv[1], "d", 1) == 0) +    type = AS_FILTER_DENY; +  else +    { +      vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +   +  /* Compile AS path. */ +  b = buffer_new (1024); +  for (i = 2; i < argc; i++) +    { +      if (first) +	buffer_putc (b, ' '); +      else +	first = 1; + +      buffer_putstr (b, argv[i]); +    } +  buffer_putc (b, '\0'); + +  regstr = buffer_getstr (b); +  buffer_free (b); + +  regex = bgp_regcomp (regstr); +  if (!regex) +    { +      free (regstr); +      vty_out (vty, "can't compile regexp %s%s", argv[0], +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* Lookup asfilter. */ +  asfilter = as_filter_lookup (aslist, regstr, type); + +  free (regstr); +  bgp_regex_free (regex); + +  if (asfilter == NULL) +    { +      vty_out (vty, "%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  as_list_filter_delete (aslist, asfilter); + +  return CMD_SUCCESS; +} + +DEFUN (no_ip_as_path_all, +       no_ip_as_path_all_cmd, +       "no ip as-path access-list WORD", +       NO_STR +       IP_STR +       "BGP autonomous system path filter\n" +       "Specify an access list name\n" +       "Regular expression access list name\n") +{ +  struct as_list *aslist; + +  aslist = as_list_lookup (argv[0]); +  if (aslist == NULL) +    { +      vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0], +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  as_list_delete (aslist); + +  return CMD_SUCCESS; +} + +int +config_write_as_list (struct vty *vty) +{ +  struct as_list *aslist; +  struct as_filter *asfilter; +  int write = 0; + +  for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) +    for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) +      { +	vty_out (vty, "ip as-path access-list %s %s %s%s", +		 aslist->name, filter_type_str (asfilter->type),  +		 asfilter->reg_str, +		 VTY_NEWLINE); +	write++; +      } + +  for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) +    for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) +      { +	vty_out (vty, "ip as-path access-list %s %s %s%s", +		 aslist->name, filter_type_str (asfilter->type),  +		 asfilter->reg_str, +		 VTY_NEWLINE); +	write++; +      } +  return write; +} + +struct cmd_node as_list_node = +{ +  AS_LIST_NODE, +  "", +  1 +}; + +/* Register functions. */ +void +bgp_filter_init () +{ +  install_node (&as_list_node, config_write_as_list); + +  install_element (CONFIG_NODE, &ip_as_path_cmd); +  install_element (CONFIG_NODE, &no_ip_as_path_cmd); +  install_element (CONFIG_NODE, &no_ip_as_path_all_cmd); +} diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h new file mode 100644 index 0000000000..8d55a224cc --- /dev/null +++ b/bgpd/bgp_filter.h @@ -0,0 +1,31 @@ +/* AS path filter list. +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +enum as_filter_type +{ +  AS_FILTER_DENY, +  AS_FILTER_PERMIT +}; + +enum as_filter_type as_list_apply (struct as_list *, void *); + +struct as_list *as_list_lookup (char *); +void as_list_add_hook (void (*func) ()); +void as_list_delete_hook (void (*func) ()); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c new file mode 100644 index 0000000000..64a4c1bd0b --- /dev/null +++ b/bgpd/bgp_fsm.c @@ -0,0 +1,864 @@ +/* BGP-4 Finite State Machine    +   From RFC1771 [A Border Gateway Protocol 4 (BGP-4)] +   Copyright (C) 1996, 97, 98 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "linklist.h" +#include "prefix.h" +#include "vty.h" +#include "sockunion.h" +#include "thread.h" +#include "log.h" +#include "stream.h" +#include "memory.h" +#include "plist.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_network.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_dump.h" +#include "bgpd/bgp_open.h" +#ifdef HAVE_SNMP +#include "bgpd/bgp_snmp.h" +#endif /* HAVE_SNMP */ + +/* BGP FSM (finite state machine) has three types of functions.  Type +   one is thread functions.  Type two is event functions.  Type three +   is FSM functions.  Timer functions are set by bgp_timer_set +   function. */ + +/* BGP event function. */ +int bgp_event (struct thread *); + +/* BGP thread functions. */ +static int bgp_start_timer (struct thread *); +static int bgp_connect_timer (struct thread *); +static int bgp_holdtime_timer (struct thread *); +static int bgp_keepalive_timer (struct thread *); + +/* BGP FSM functions. */ +static int bgp_start (struct peer *); + +/* BGP start timer jitter. */ +int +bgp_start_jitter (int time) +{ +  return ((rand () % (time + 1)) - (time / 2)); +} + +/* Hook function called after bgp event is occered.  And vty's +   neighbor command invoke this function after making neighbor +   structure. */ +void +bgp_timer_set (struct peer *peer) +{ +  int jitter = 0; + +  switch (peer->status) +    { +    case Idle: +      /* First entry point of peer's finite state machine.  In Idle +	 status start timer is on unless peer is shutdown or peer is +	 inactive.  All other timer must be turned off */ +      if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN) +	  || CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW) +	  || ! peer_active (peer)) +	{ +	  BGP_TIMER_OFF (peer->t_start); +	} +      else +	{ +	  jitter = bgp_start_jitter (peer->v_start); +	  BGP_TIMER_ON (peer->t_start, bgp_start_timer, +			peer->v_start + jitter); +	} +      BGP_TIMER_OFF (peer->t_connect); +      BGP_TIMER_OFF (peer->t_holdtime); +      BGP_TIMER_OFF (peer->t_keepalive); +      BGP_TIMER_OFF (peer->t_asorig); +      BGP_TIMER_OFF (peer->t_routeadv); +      break; + +    case Connect: +      /* After start timer is expired, the peer moves to Connnect +         status.  Make sure start timer is off and connect timer is +         on. */ +      BGP_TIMER_OFF (peer->t_start); +      BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect); +      BGP_TIMER_OFF (peer->t_holdtime); +      BGP_TIMER_OFF (peer->t_keepalive); +      BGP_TIMER_OFF (peer->t_asorig); +      BGP_TIMER_OFF (peer->t_routeadv); +      break; + +    case Active: +      /* Active is waiting connection from remote peer.  And if +         connect timer is expired, change status to Connect. */ +      BGP_TIMER_OFF (peer->t_start); +      /* If peer is passive mode, do not set connect timer. */ +      if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)) +	{ +	  BGP_TIMER_OFF (peer->t_connect); +	} +      else +	{ +	  BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect); +	} +      BGP_TIMER_OFF (peer->t_holdtime); +      BGP_TIMER_OFF (peer->t_keepalive); +      BGP_TIMER_OFF (peer->t_asorig); +      BGP_TIMER_OFF (peer->t_routeadv); +      break; + +    case OpenSent: +      /* OpenSent status. */ +      BGP_TIMER_OFF (peer->t_start); +      BGP_TIMER_OFF (peer->t_connect); +      if (peer->v_holdtime != 0) +	{ +	  BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer,  +			peer->v_holdtime); +	} +      else +	{ +	  BGP_TIMER_OFF (peer->t_holdtime); +	} +      BGP_TIMER_OFF (peer->t_keepalive); +      BGP_TIMER_OFF (peer->t_asorig); +      BGP_TIMER_OFF (peer->t_routeadv); +      break; + +    case OpenConfirm: +      /* OpenConfirm status. */ +      BGP_TIMER_OFF (peer->t_start); +      BGP_TIMER_OFF (peer->t_connect); + +      /* If the negotiated Hold Time value is zero, then the Hold Time +         timer and KeepAlive timers are not started. */ +      if (peer->v_holdtime == 0) +	{ +	  BGP_TIMER_OFF (peer->t_holdtime); +	  BGP_TIMER_OFF (peer->t_keepalive); +	} +      else +	{ +	  BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer, +			peer->v_holdtime); +	  BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer,  +			peer->v_keepalive); +	} +      BGP_TIMER_OFF (peer->t_asorig); +      BGP_TIMER_OFF (peer->t_routeadv); +      break; + +    case Established: +      /* In Established status start and connect timer is turned +         off. */ +      BGP_TIMER_OFF (peer->t_start); +      BGP_TIMER_OFF (peer->t_connect); + +      /* Same as OpenConfirm, if holdtime is zero then both holdtime +         and keepalive must be turned off. */ +      if (peer->v_holdtime == 0) +	{ +	  BGP_TIMER_OFF (peer->t_holdtime); +	  BGP_TIMER_OFF (peer->t_keepalive); +	} +      else +	{ +	  BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer, +			peer->v_holdtime); +	  BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer, +			peer->v_keepalive); +	} +      BGP_TIMER_OFF (peer->t_asorig); +      break; +    } +} + +/* BGP start timer.  This function set BGP_Start event to thread value +   and process event. */ +static int +bgp_start_timer (struct thread *thread) +{ +  struct peer *peer; + +  peer = THREAD_ARG (thread); +  peer->t_start = NULL; + +  if (BGP_DEBUG (fsm, FSM)) +    zlog (peer->log, LOG_DEBUG, +	  "%s [FSM] Timer (start timer expire).", peer->host); + +  THREAD_VAL (thread) = BGP_Start; +  bgp_event (thread); + +  return 0; +} + +/* BGP connect retry timer. */ +static int +bgp_connect_timer (struct thread *thread) +{ +  struct peer *peer; + +  peer = THREAD_ARG (thread); +  peer->t_connect = NULL; + +  if (BGP_DEBUG (fsm, FSM)) +    zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (connect timer expire)", +	  peer->host); + +  THREAD_VAL (thread) = ConnectRetry_timer_expired; +  bgp_event (thread); + +  return 0; +} + +/* BGP holdtime timer. */ +static int +bgp_holdtime_timer (struct thread *thread) +{ +  struct peer *peer; + +  peer = THREAD_ARG (thread); +  peer->t_holdtime = NULL; + +  if (BGP_DEBUG (fsm, FSM)) +    zlog (peer->log, LOG_DEBUG, +	  "%s [FSM] Timer (holdtime timer expire)", +	  peer->host); + +  THREAD_VAL (thread) = Hold_Timer_expired; +  bgp_event (thread); + +  return 0; +} + +/* BGP keepalive fire ! */ +static int +bgp_keepalive_timer (struct thread *thread) +{ +  struct peer *peer; + +  peer = THREAD_ARG (thread); +  peer->t_keepalive = NULL; + +  if (BGP_DEBUG (fsm, FSM)) +    zlog (peer->log, LOG_DEBUG, +	  "%s [FSM] Timer (keepalive timer expire)", +	  peer->host); + +  THREAD_VAL (thread) = KeepAlive_timer_expired; +  bgp_event (thread); + +  return 0; +} + +int +bgp_routeadv_timer (struct thread *thread) +{ +  struct peer *peer; + +  peer = THREAD_ARG (thread); +  peer->t_routeadv = NULL; + +  if (BGP_DEBUG (fsm, FSM)) +    zlog (peer->log, LOG_DEBUG, +	  "%s [FSM] Timer (routeadv timer expire)", +	  peer->host); + +  peer->synctime = time (NULL); + +  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + +  BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, +		peer->v_routeadv); + +  return 0; +} + +/* Reset bgp update timer */ +static void +bgp_uptime_reset (struct peer *peer) +{ +  peer->uptime = time (NULL); +} + +/* Administrative BGP peer stop event. */ +int +bgp_stop (struct peer *peer) +{ +  int established = 0; +  afi_t afi; +  safi_t safi; +  char orf_name[BUFSIZ]; + +  /* Increment Dropped count. */ +  if (peer->status == Established) +    { +      established = 1; +      peer->dropped++; +      bgp_fsm_change_status (peer, Idle); +#ifdef HAVE_SNMP +      bgpTrapBackwardTransition (peer); +#endif /* HAVE_SNMP */ +    } + +  /* Reset uptime. */ +  bgp_uptime_reset (peer); + +  /* Need of clear of peer. */ +  if (established) +    bgp_clear_route_all (peer); + +  /* Stop read and write threads when exists. */ +  BGP_READ_OFF (peer->t_read); +  BGP_WRITE_OFF (peer->t_write); + +  /* Stop all timers. */ +  BGP_TIMER_OFF (peer->t_start); +  BGP_TIMER_OFF (peer->t_connect); +  BGP_TIMER_OFF (peer->t_holdtime); +  BGP_TIMER_OFF (peer->t_keepalive); +  BGP_TIMER_OFF (peer->t_asorig); +  BGP_TIMER_OFF (peer->t_routeadv); + +  /* Delete all existing events of the peer. */ +  BGP_EVENT_DELETE (peer); + +  /* Stream reset. */ +  peer->packet_size = 0; + +  /* Clear input and output buffer.  */ +  if (peer->ibuf) +    stream_reset (peer->ibuf); +  if (peer->work) +    stream_reset (peer->work); +  stream_fifo_clean (peer->obuf); + +  /* Close of file descriptor. */ +  if (peer->fd >= 0) +    { +      close (peer->fd); +      peer->fd = -1; +    } + +  /* Connection information. */ +  if (peer->su_local) +    { +      XFREE (MTYPE_SOCKUNION, peer->su_local); +      peer->su_local = NULL; +    } + +  if (peer->su_remote) +    { +      XFREE (MTYPE_SOCKUNION, peer->su_remote); +      peer->su_remote = NULL; +    } + +  /* Clear remote router-id. */ +  peer->remote_id.s_addr = 0; + +  /* Reset all negotiated variables */ +  peer->afc_nego[AFI_IP][SAFI_UNICAST] = 0; +  peer->afc_nego[AFI_IP][SAFI_MULTICAST] = 0; +  peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] = 0; +  peer->afc_nego[AFI_IP6][SAFI_UNICAST] = 0; +  peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = 0; +  peer->afc_adv[AFI_IP][SAFI_UNICAST] = 0; +  peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 0; +  peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 0; +  peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 0; +  peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 0; +  peer->afc_recv[AFI_IP][SAFI_UNICAST] = 0; +  peer->afc_recv[AFI_IP][SAFI_MULTICAST] = 0; +  peer->afc_recv[AFI_IP][SAFI_MPLS_VPN] = 0; +  peer->afc_recv[AFI_IP6][SAFI_UNICAST] = 0; +  peer->afc_recv[AFI_IP6][SAFI_MULTICAST] = 0; + +  /* Reset route refresh flag. */ +  UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV); +  UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); +  UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); +  UNSET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV); +  UNSET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV); + +  for (afi = AFI_IP ; afi < AFI_MAX ; afi++) +    for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) +      { +	/* peer address family capability flags*/ +	peer->af_cap[afi][safi] = 0; +	/* peer address family status flags*/ +	peer->af_sflags[afi][safi] = 0; +	/* Received ORF prefix-filter */ +	peer->orf_plist[afi][safi] = NULL; +        /* ORF received prefix-filter pnt */ +        sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); +        prefix_bgp_orf_remove_all (orf_name); +      } + +  /* Reset keepalive and holdtime */ +  if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) +    { +      peer->v_keepalive = peer->keepalive; +      peer->v_holdtime = peer->holdtime; +    } +  else +    { +      peer->v_keepalive = peer->bgp->default_keepalive; +      peer->v_holdtime = peer->bgp->default_holdtime; +    } + +  peer->update_time = 0; + +  /* Until we are sure that there is no problem about prefix count +     this should be commented out.*/ +#if 0 +  /* Reset prefix count */ +  peer->pcount[AFI_IP][SAFI_UNICAST] = 0; +  peer->pcount[AFI_IP][SAFI_MULTICAST] = 0; +  peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0; +  peer->pcount[AFI_IP6][SAFI_UNICAST] = 0; +  peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0; +#endif /* 0 */ + +  return 0; +} + +/* BGP peer is stoped by the error. */ +int +bgp_stop_with_error (struct peer *peer) +{ +  /* Double start timer. */ +  peer->v_start *= 2; + +  /* Overflow check. */ +  if (peer->v_start >= (60 * 2)) +    peer->v_start = (60 * 2); + +  bgp_stop (peer); + +  return 0; +} + +/* TCP connection open.  Next we send open message to remote peer. And +   add read thread for reading open message. */ +int +bgp_connect_success (struct peer *peer) +{ +  if (peer->fd < 0) +    { +      zlog_err ("bgp_connect_success peer's fd is negative value %d", +		peer->fd); +      return -1; +    } +  BGP_READ_ON (peer->t_read, bgp_read, peer->fd); + +  /* bgp_getsockname (peer); */ + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) +    bgp_open_send (peer); + +  return 0; +} + +/* TCP connect fail */ +int +bgp_connect_fail (struct peer *peer) +{ +  bgp_stop (peer); +  return 0; +} + +/* This function is the first starting point of all BGP connection. It +   try to connect to remote peer with non-blocking IO. */ +int +bgp_start (struct peer *peer) +{ +  int status; + +  /* If the peer is passive mode, force to move to Active mode. */ +  if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)) +    { +      BGP_EVENT_ADD (peer, TCP_connection_open_failed); +      return 0; +    } + +  status = bgp_connect (peer); + +  switch (status) +    { +    case connect_error: +      if (BGP_DEBUG (fsm, FSM)) +	plog_info (peer->log, "%s [FSM] Connect error", peer->host); +      BGP_EVENT_ADD (peer, TCP_connection_open_failed); +      break; +    case connect_success: +      if (BGP_DEBUG (fsm, FSM)) +	plog_info (peer->log, "%s [FSM] Connect immediately success", +		   peer->host); +      BGP_EVENT_ADD (peer, TCP_connection_open); +      break; +    case connect_in_progress: +      /* To check nonblocking connect, we wait until socket is +         readable or writable. */ +      if (BGP_DEBUG (fsm, FSM)) +	plog_info (peer->log, "%s [FSM] Non blocking connect waiting result", +		   peer->host); +      if (peer->fd < 0) +	{ +	  zlog_err ("bgp_start peer's fd is negative value %d", +		    peer->fd); +	  return -1; +	} +      BGP_READ_ON (peer->t_read, bgp_read, peer->fd); +      BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +      break; +    } +  return 0; +} + +/* Connect retry timer is expired when the peer status is Connect. */ +int +bgp_reconnect (struct peer *peer) +{ +  bgp_stop (peer); +  bgp_start (peer); +  return 0; +} + +int +bgp_fsm_open (struct peer *peer) +{ +  /* Send keepalive and make keepalive timer */ +  bgp_keepalive_send (peer); + +  /* Reset holdtimer value. */ +  BGP_TIMER_OFF (peer->t_holdtime); + +  return 0; +} + +/* Called after event occured, this function change status and reset +   read/write and timer thread. */ +void +bgp_fsm_change_status (struct peer *peer, int status) +{ +  bgp_dump_state (peer, peer->status, status); + +  /* Preserve old status and change into new status. */ +  peer->ostatus = peer->status; +  peer->status = status; +} + +/* Keepalive send to peer. */ +int +bgp_fsm_keepalive_expire (struct peer *peer) +{ +  bgp_keepalive_send (peer); +  return 0; +} + +/* Hold timer expire.  This is error of BGP connection. So cut the +   peer and change to Idle status. */ +int +bgp_fsm_holdtime_expire (struct peer *peer) +{ +  if (BGP_DEBUG (fsm, FSM)) +    zlog (peer->log, LOG_DEBUG, "%s [FSM] Hold timer expire", peer->host); + +  /* Send notify to remote peer. */ +  bgp_notify_send (peer, BGP_NOTIFY_HOLD_ERR, 0); + +  /* Sweep if it is temporary peer. */ +  if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) +    { +      zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host); +      peer_delete (peer); +      return -1; +    } + +  return 0; +} + +/* Status goes to Established.  Send keepalive packet then make first +   update information. */ +int +bgp_establish (struct peer *peer) +{ +  struct bgp_notify *notify; +  afi_t afi; +  safi_t safi; + +  /* Reset capability open status flag. */ +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN)) +    SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + +  /* Clear last notification data. */ +  notify = &peer->notify; +  if (notify->data) +    XFREE (MTYPE_TMP, notify->data); +  memset (notify, 0, sizeof (struct bgp_notify)); + +  /* Clear start timer value to default. */ +  peer->v_start = BGP_INIT_START_TIMER; + +  /* Increment established count. */ +  peer->established++; +  bgp_fsm_change_status (peer, Established); +#ifdef HAVE_SNMP +  bgpTrapEstablished (peer); +#endif /* HAVE_SNMP */ + +  /* Reset uptime, send keepalive, send current table. */ +  bgp_uptime_reset (peer); + +  /* Send route-refresh when ORF is enabled */ +  for (afi = AFI_IP ; afi < AFI_MAX ; afi++) +    for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) +      if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)) +	{ +	  if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) +	    bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX, +				    REFRESH_IMMEDIATE, 0); +	  else if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) +	    bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX_OLD, +				    REFRESH_IMMEDIATE, 0); +	} + +  if (peer->v_keepalive) +    bgp_keepalive_send (peer); + +  /* First update is deferred until ORF or ROUTE-REFRESH is received */ +  for (afi = AFI_IP ; afi < AFI_MAX ; afi++) +    for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) +      if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV)) +	if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) +	    || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV)) +	  SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH); + +  bgp_announce_route_all (peer); + +  BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1); + +  return 0; +} + +/* Keepalive packet is received. */ +int +bgp_fsm_keepalive (struct peer *peer) +{ +  /* peer count update */ +  peer->keepalive_in++; + +  BGP_TIMER_OFF (peer->t_holdtime); +  return 0; +} + +/* Update packet is received. */ +int +bgp_fsm_update (struct peer *peer) +{ +  BGP_TIMER_OFF (peer->t_holdtime); +  return 0; +} + +/* This is empty event. */ +int +bgp_ignore (struct peer *peer) +{ +  if (BGP_DEBUG (fsm, FSM)) +    zlog (peer->log, LOG_DEBUG, "%s [FSM] bgp_ignore called", peer->host); +  return 0; +} + +/* Finite State Machine structure */ +struct { +  int (*func) (); +  int next_state; +} FSM [BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] =  +{ +  { +    /* Idle state: In Idle state, all events other than BGP_Start is +       ignored.  With BGP_Start event, finite state machine calls +       bgp_start(). */ +    {bgp_start,  Connect},	/* BGP_Start                    */ +    {bgp_stop,   Idle},		/* BGP_Stop                     */ +    {bgp_stop,   Idle},		/* TCP_connection_open          */ +    {bgp_stop,   Idle},		/* TCP_connection_closed        */ +    {bgp_ignore, Idle},		/* TCP_connection_open_failed   */ +    {bgp_stop,   Idle},		/* TCP_fatal_error              */ +    {bgp_ignore, Idle},		/* ConnectRetry_timer_expired   */ +    {bgp_ignore, Idle},		/* Hold_Timer_expired           */ +    {bgp_ignore, Idle},		/* KeepAlive_timer_expired      */ +    {bgp_ignore, Idle},		/* Receive_OPEN_message         */ +    {bgp_ignore, Idle},		/* Receive_KEEPALIVE_message    */ +    {bgp_ignore, Idle},		/* Receive_UPDATE_message       */ +    {bgp_ignore, Idle},		/* Receive_NOTIFICATION_message */ +  }, +  { +    /* Connect */ +    {bgp_ignore,  Connect},	/* BGP_Start                    */ +    {bgp_stop,    Idle},	/* BGP_Stop                     */ +    {bgp_connect_success, OpenSent}, /* TCP_connection_open          */ +    {bgp_stop, Idle},		/* TCP_connection_closed        */ +    {bgp_connect_fail, Active}, /* TCP_connection_open_failed   */ +    {bgp_connect_fail, Idle},	/* TCP_fatal_error              */ +    {bgp_reconnect, Connect},	/* ConnectRetry_timer_expired   */ +    {bgp_ignore,  Idle},	/* Hold_Timer_expired           */ +    {bgp_ignore,  Idle},	/* KeepAlive_timer_expired      */ +    {bgp_ignore,  Idle},	/* Receive_OPEN_message         */ +    {bgp_ignore,  Idle},	/* Receive_KEEPALIVE_message    */ +    {bgp_ignore,  Idle},	/* Receive_UPDATE_message       */ +    {bgp_stop,    Idle},	/* Receive_NOTIFICATION_message */ +  }, +  { +    /* Active, */ +    {bgp_ignore,  Active},	/* BGP_Start                    */ +    {bgp_stop,    Idle},	/* BGP_Stop                     */ +    {bgp_connect_success, OpenSent}, /* TCP_connection_open          */ +    {bgp_stop,    Idle},	/* TCP_connection_closed        */ +    {bgp_ignore,  Active},	/* TCP_connection_open_failed   */ +    {bgp_ignore,  Idle},	/* TCP_fatal_error              */ +    {bgp_start,   Connect},	/* ConnectRetry_timer_expired   */ +    {bgp_ignore,  Idle},	/* Hold_Timer_expired           */ +    {bgp_ignore,  Idle},	/* KeepAlive_timer_expired      */ +    {bgp_ignore,  Idle},	/* Receive_OPEN_message         */ +    {bgp_ignore,  Idle},	/* Receive_KEEPALIVE_message    */ +    {bgp_ignore,  Idle},	/* Receive_UPDATE_message       */ +    {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ +  }, +  { +    /* OpenSent, */ +    {bgp_ignore,  OpenSent},	/* BGP_Start                    */ +    {bgp_stop,    Idle},	/* BGP_Stop                     */ +    {bgp_stop,    Idle},	/* TCP_connection_open          */ +    {bgp_stop,    Active},	/* TCP_connection_closed        */ +    {bgp_ignore,  Idle},	/* TCP_connection_open_failed   */ +    {bgp_stop,    Idle},	/* TCP_fatal_error              */ +    {bgp_ignore,  Idle},	/* ConnectRetry_timer_expired   */ +    {bgp_fsm_holdtime_expire, Idle},	/* Hold_Timer_expired           */ +    {bgp_ignore,  Idle},	/* KeepAlive_timer_expired      */ +    {bgp_fsm_open,    OpenConfirm},	/* Receive_OPEN_message         */ +    {bgp_ignore,  Idle},	/* Receive_KEEPALIVE_message    */ +    {bgp_ignore,  Idle},	/* Receive_UPDATE_message       */ +    {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ +  }, +  { +    /* OpenConfirm, */ +    {bgp_ignore,  OpenConfirm},	/* BGP_Start                    */ +    {bgp_stop,    Idle},	/* BGP_Stop                     */ +    {bgp_stop,    Idle},	/* TCP_connection_open          */ +    {bgp_stop,    Idle},	/* TCP_connection_closed        */ +    {bgp_stop,    Idle},	/* TCP_connection_open_failed   */ +    {bgp_stop,    Idle},	/* TCP_fatal_error              */ +    {bgp_ignore,  Idle},	/* ConnectRetry_timer_expired   */ +    {bgp_fsm_holdtime_expire, Idle},	/* Hold_Timer_expired           */ +    {bgp_ignore,  OpenConfirm},	/* KeepAlive_timer_expired      */ +    {bgp_ignore,  Idle},	/* Receive_OPEN_message         */ +    {bgp_establish, Established}, /* Receive_KEEPALIVE_message    */ +    {bgp_ignore,  Idle},	/* Receive_UPDATE_message       */ +    {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ +  }, +  { +    /* Established, */ +    {bgp_ignore,  Established},	/* BGP_Start                    */ +    {bgp_stop,    Idle},	/* BGP_Stop                     */ +    {bgp_stop,    Idle},	/* TCP_connection_open          */ +    {bgp_stop,    Idle},	/* TCP_connection_closed        */ +    {bgp_ignore,  Idle},	/* TCP_connection_open_failed   */ +    {bgp_stop,    Idle},	/* TCP_fatal_error              */ +    {bgp_ignore,  Idle},	/* ConnectRetry_timer_expired   */ +    {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired           */ +    {bgp_fsm_keepalive_expire, Established}, /* KeepAlive_timer_expired      */ +    {bgp_stop, Idle},		/* Receive_OPEN_message         */ +    {bgp_fsm_keepalive, Established}, /* Receive_KEEPALIVE_message    */ +    {bgp_fsm_update,   Established}, /* Receive_UPDATE_message       */ +    {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ +  }, +}; + +static char *bgp_event_str[] = +{ +  NULL, +  "BGP_Start", +  "BGP_Stop", +  "TCP_connection_open", +  "TCP_connection_closed", +  "TCP_connection_open_failed", +  "TCP_fatal_error", +  "ConnectRetry_timer_expired", +  "Hold_Timer_expired", +  "KeepAlive_timer_expired", +  "Receive_OPEN_message", +  "Receive_KEEPALIVE_message", +  "Receive_UPDATE_message", +  "Receive_NOTIFICATION_message" +}; + +/* Execute event process. */ +int +bgp_event (struct thread *thread) +{ +  int ret; +  int event; +  int next; +  struct peer *peer; + +  peer = THREAD_ARG (thread); +  event = THREAD_VAL (thread); + +  /* Logging this event. */ +  next = FSM [peer->status -1][event - 1].next_state; + +  if (BGP_DEBUG (fsm, FSM)) +    plog_info (peer->log, "%s [FSM] %s (%s->%s)", peer->host,  +	       bgp_event_str[event], +	       LOOKUP (bgp_status_msg, peer->status), +	       LOOKUP (bgp_status_msg, next)); +  if (BGP_DEBUG (normal, NORMAL) +      && strcmp (LOOKUP (bgp_status_msg, peer->status), LOOKUP (bgp_status_msg, next))) +    zlog_info ("%s went from %s to %s", +	       peer->host, +	       LOOKUP (bgp_status_msg, peer->status), +	       LOOKUP (bgp_status_msg, next)); + +  /* Call function. */ +  ret = (*(FSM [peer->status - 1][event - 1].func))(peer); + +  /* When function do not want proceed next job return -1. */ +  if (ret < 0) +    return ret; +     +  /* If status is changed. */ +  if (next != peer->status) +    bgp_fsm_change_status (peer, next); + +  /* Make sure timer is set. */ +  bgp_timer_set (peer); + +  return 0; +} diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h new file mode 100644 index 0000000000..f051aaa789 --- /dev/null +++ b/bgpd/bgp_fsm.h @@ -0,0 +1,42 @@ +/* BGP-4 Finite State Machine    +   From RFC1771 [A Border Gateway Protocol 4 (BGP-4)] +   Copyright (C) 1998 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +/* Macro for BGP read, write and timer thread.  */ +#define BGP_READ_ON(T,F,V)   THREAD_READ_ON(master,T,F,peer,V) +#define BGP_READ_OFF(X)      THREAD_READ_OFF(X) + +#define BGP_WRITE_ON(T,F,V)  THREAD_WRITE_ON(master,T,F,peer,V) +#define BGP_WRITE_OFF(X)     THREAD_WRITE_OFF(X) + +#define BGP_TIMER_ON(T,F,V)  THREAD_TIMER_ON(master,T,F,peer,V) +#define BGP_TIMER_OFF(X)     THREAD_TIMER_OFF(X) + +#define BGP_EVENT_ADD(P,E) \ +    thread_add_event (master, bgp_event, (P), (E)) + +#define BGP_EVENT_DELETE(P) \ +    thread_cancel_event (master, (P)) + +/* Prototypes. */ +int bgp_event (struct thread *); +int bgp_stop (struct peer *peer); +void bgp_timer_set (struct peer *); +void bgp_fsm_change_status (struct peer *peer, int status); diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c new file mode 100644 index 0000000000..7fc68fa76b --- /dev/null +++ b/bgpd/bgp_main.c @@ -0,0 +1,285 @@ +/* Main routine of bgpd. +   Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "getopt.h" +#include "thread.h" +#include "version.h" +#include "memory.h" +#include "prefix.h" +#include "log.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_mplsvpn.h" + +/* bgpd options, we use GNU getopt library. */ +struct option longopts[] =  +{ +  { "daemon",      no_argument,       NULL, 'd'}, +  { "config_file", required_argument, NULL, 'f'}, +  { "pid_file",    required_argument, NULL, 'i'}, +  { "bgp_port",    required_argument, NULL, 'p'}, +  { "vty_addr",    required_argument, NULL, 'A'}, +  { "vty_port",    required_argument, NULL, 'P'}, +  { "retain",      no_argument,       NULL, 'r'}, +  { "no_kernel",   no_argument,       NULL, 'n'}, +  { "version",     no_argument,       NULL, 'v'}, +  { "help",        no_argument,       NULL, 'h'}, +  { 0 } +}; + +/* Configuration file and directory. */ +char config_current[] = BGP_DEFAULT_CONFIG; +char config_default[] = SYSCONFDIR BGP_DEFAULT_CONFIG; + +/* Route retain mode flag. */ +int retain_mode = 0; + +/* Master of threads. */ +struct thread_master *master; + +/* Manually specified configuration file name.  */ +char *config_file = NULL; + +/* Process ID saved for use by init system */ +char *pid_file = PATH_BGPD_PID; + +/* VTY port number and address.  */ +int vty_port = BGP_VTY_PORT; +char *vty_addr = NULL; + +/* Help information display. */ +static void +usage (char *progname, int status) +{ +  if (status != 0) +    fprintf (stderr, "Try `%s --help' for more information.\n", progname); +  else +    {     +      printf ("Usage : %s [OPTION...]\n\n\ +Daemon which manages kernel routing table management and \ +redistribution between different routing protocols.\n\n\ +-d, --daemon       Runs in daemon mode\n\ +-f, --config_file  Set configuration file name\n\ +-i, --pid_file     Set process identifier file name\n\ +-p, --bgp_port     Set bgp protocol's port number\n\ +-A, --vty_addr     Set vty's bind address\n\ +-P, --vty_port     Set vty's port number\n\ +-r, --retain       When program terminates, retain added route by bgpd.\n\ +-n, --no_kernel    Do not install route to kernel.\n\ +-v, --version      Print program version\n\ +-h, --help         Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); +    } + +  exit (status); +} + +/* SIGHUP handler. */ +void  +sighup (int sig) +{ +  zlog (NULL, LOG_INFO, "SIGHUP received"); + +  /* Terminate all thread. */ +  bgp_terminate (); +  bgp_reset (); +  zlog_info ("bgpd restarting!"); + +  /* Reload config file. */ +  vty_read_config (config_file, config_current, config_default); + +  /* Create VTY's socket */ +  vty_serv_sock (vty_addr, vty_port ? vty_port : BGP_VTY_PORT, BGP_VTYSH_PATH); + +  /* Try to return to normal operation. */ +} + +/* SIGINT handler. */ +void +sigint (int sig) +{ +  zlog (NULL, LOG_INFO, "Terminating on signal"); + +  if (! retain_mode) +    bgp_terminate (); + +  exit (0); +} + +/* SIGUSR1 handler. */ +void +sigusr1 (int sig) +{ +  zlog_rotate (NULL); +} + +/* Signale wrapper. */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ +  int ret; +  struct sigaction sig; +  struct sigaction osig; + +  sig.sa_handler = func; +  sigemptyset (&sig.sa_mask); +  sig.sa_flags = 0; +#ifdef SA_RESTART +  sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + +  ret = sigaction (signo, &sig, &osig); + +  if (ret < 0)  +    return (SIG_ERR); +  else +    return (osig.sa_handler); +} + +/* Initialization of signal handles. */ +void +signal_init () +{ +  signal_set (SIGHUP, sighup); +  signal_set (SIGINT, sigint); +  signal_set (SIGTERM, sigint); +  signal_set (SIGPIPE, SIG_IGN); +  signal_set (SIGUSR1, sigusr1); +} + +/* Main routine of bgpd. Treatment of argument and start bgp finite +   state machine is handled at here. */ +int +main (int argc, char **argv) +{ +  char *p; +  int opt; +  int daemon_mode = 0; +  char *progname; +  struct thread thread; + +  /* Set umask before anything for security */ +  umask (0027); + +  /* Preserve name of myself. */ +  progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + +  zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_BGP, +			   LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + +  /* BGP master init. */ +  bgp_master_init (); + +  /* Command line argument treatment. */ +  while (1)  +    { +      opt = getopt_long (argc, argv, "df:hp:A:P:rnv", longopts, 0); +     +      if (opt == EOF) +	break; + +      switch (opt)  +	{ +	case 0: +	  break; +	case 'd': +	  daemon_mode = 1; +	  break; +	case 'f': +	  config_file = optarg; +	  break; +        case 'i': +          pid_file = optarg; +          break; +	case 'p': +	  bm->port = atoi (optarg); +	  break; +	case 'A': +	  vty_addr = optarg; +	  break; +	case 'P': +	  vty_port = atoi (optarg); +	  break; +	case 'r': +	  retain_mode = 1; +	  break; +	case 'n': +	  bgp_option_set (BGP_OPT_NO_FIB); +	  break; +	case 'v': +	  print_version (progname); +	  exit (0); +	  break; +	case 'h': +	  usage (progname, 0); +	  break; +	default: +	  usage (progname, 1); +	  break; +	} +    } + +  /* Make thread master. */ +  master = bm->master; + +  /* Initializations. */ +  srand (time (NULL)); +  signal_init (); +  cmd_init (1); +  vty_init (); +  memory_init (); + +  /* BGP related initialization.  */ +  bgp_init (); + +  /* Sort CLI commands. */ +  sort_node (); + +  /* Parse config file. */ +  vty_read_config (config_file, config_current, config_default); + +  /* Turn into daemon if daemon_mode is set. */ +  if (daemon_mode) +    daemon (0, 0); + +  /* Process ID file creation. */ +  pid_output (pid_file); + +  /* Make bgp vty socket. */ +  vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH); + +  /* Print banner. */ +  zlog_info ("BGPd %s starting: vty@%d, bgp@%d", ZEBRA_VERSION, +	     vty_port, bm->port); + +  /* Start finite state machine, here we go! */ +  while (thread_fetch (master, &thread)) +    thread_call (&thread); + +  /* Not reached. */ +  exit (0); +} diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c new file mode 100644 index 0000000000..e820cabf62 --- /dev/null +++ b/bgpd/bgp_mplsvpn.c @@ -0,0 +1,741 @@ +/* MPLS-VPN +   Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org> + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "command.h" +#include "prefix.h" +#include "log.h" +#include "memory.h" +#include "stream.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_mplsvpn.h" + +int route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int, safi_t); +int route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t); +void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t); + +u_int16_t +decode_rd_type (u_char *pnt) +{ +  u_int16_t v; +   +  v = ((u_int16_t) *pnt++ << 8); +  v |= (u_int16_t) *pnt; +  return v; +} + +u_int32_t +decode_label (u_char *pnt) +{ +  u_int32_t l; + +  l = ((u_int32_t) *pnt++ << 12); +  l |= (u_int32_t) *pnt++ << 4; +  l |= (u_int32_t) ((*pnt & 0xf0) >> 4); +  return l; +} + +void +decode_rd_as (u_char *pnt, struct rd_as *rd_as) +{ +  rd_as->as = (u_int16_t) *pnt++ << 8; +  rd_as->as |= (u_int16_t) *pnt++; +   +  rd_as->val = ((u_int32_t) *pnt++ << 24); +  rd_as->val |= ((u_int32_t) *pnt++ << 16); +  rd_as->val |= ((u_int32_t) *pnt++ << 8); +  rd_as->val |= (u_int32_t) *pnt; +} + +void +decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) +{ +  memcpy (&rd_ip->ip, pnt, 4); +  pnt += 4; +   +  rd_ip->val = ((u_int16_t) *pnt++ << 8); +  rd_ip->val |= (u_int16_t) *pnt; +} + +int bgp_update (struct peer *, struct prefix *, struct attr *,  +		afi_t, safi_t, int, int, struct prefix_rd *, u_char *); + +int bgp_withdraw (struct peer *, struct prefix *, struct attr *,  +		  int, int, int, int, struct prefix_rd *, u_char *); +int +bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr,  +		      struct bgp_nlri *packet) +{ +  u_char *pnt; +  u_char *lim; +  struct prefix p; +  int psize; +  int prefixlen; +  u_int32_t label; +  u_int16_t type; +  struct rd_as rd_as; +  struct rd_ip rd_ip; +  struct prefix_rd prd; +  u_char *tagpnt; + +  /* Check peer status. */ +  if (peer->status != Established) +    return 0; +   +  /* Make prefix_rd */ +  prd.family = AF_UNSPEC; +  prd.prefixlen = 64; + +  pnt = packet->nlri; +  lim = pnt + packet->length; + +  for (; pnt < lim; pnt += psize) +    { +      /* Clear prefix structure. */ +      memset (&p, 0, sizeof (struct prefix)); + +      /* Fetch prefix length. */ +      prefixlen = *pnt++; +      p.family = AF_INET; +      psize = PSIZE (prefixlen); + +      if (prefixlen < 88) +	{ +	  zlog_err ("prefix length is less than 88: %d", prefixlen); +	  return -1; +	} + +      label = decode_label (pnt); + +      /* Copyr label to prefix. */ +      tagpnt = pnt;; + +      /* Copy routing distinguisher to rd. */ +      memcpy (&prd.val, pnt + 3, 8); + +      /* Decode RD type. */ +      type = decode_rd_type (pnt + 3); + +      /* Decode RD value. */ +      if (type == RD_TYPE_AS) +	decode_rd_as (pnt + 5, &rd_as); +      else if (type == RD_TYPE_IP) +	decode_rd_ip (pnt + 5, &rd_ip); +      else +	{ +	  zlog_err ("Invalid RD type %d", type); +	  return -1; +	} + +      p.prefixlen = prefixlen - 88; +      memcpy (&p.u.prefix, pnt + 11, psize - 11); + +#if 0 +      if (type == RD_TYPE_AS) +	zlog_info ("prefix %ld:%ld:%ld:%s/%d", label, rd_as.as, rd_as.val, +		   inet_ntoa (p.u.prefix4), p.prefixlen); +      else if (type == RD_TYPE_IP) +	zlog_info ("prefix %ld:%s:%ld:%s/%d", label, inet_ntoa (rd_ip.ip), +		   rd_ip.val, inet_ntoa (p.u.prefix4), p.prefixlen); +#endif /* 0 */ + +      if (pnt + psize > lim) +	return -1; + +      if (attr) +	bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, +		    ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); +      else +	bgp_withdraw (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, +		      ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); +    } + +  /* Packet length consistency check. */ +  if (pnt != lim) +    return -1; + +  return 0; +} + +int +str2prefix_rd (u_char *str, struct prefix_rd *prd) +{ +  int ret; +  u_char *p; +  u_char *p2; +  struct stream *s; +  u_char *half; +  struct in_addr addr; + +  s = stream_new (8); + +  prd->family = AF_UNSPEC; +  prd->prefixlen = 64; + +  p = strchr (str, ':'); +  if (! p) +    return 0; + +  if (! all_digit (p + 1)) +    return 0; + +  half = XMALLOC (MTYPE_TMP, (p - str) + 1); +  memcpy (half, str, (p - str)); +  half[p - str] = '\0'; + +  p2 = strchr (str, '.'); + +  if (! p2) +    { +      if (! all_digit (half)) +	{ +	  XFREE (MTYPE_TMP, half); +	  return 0; +	} +      stream_putw (s, RD_TYPE_AS); +      stream_putw (s, atoi (half)); +      stream_putl (s, atol (p + 1)); +    } +  else +    { +      ret = inet_aton (half, &addr); +      if (! ret) +	{ +	  XFREE (MTYPE_TMP, half); +	  return 0; +	} +      stream_putw (s, RD_TYPE_IP); +      stream_put_in_addr (s, &addr); +      stream_putw (s, atol (p + 1)); +    } +  memcpy (prd->val, s->data, 8); + +  return 1; +} + +int +str2tag (u_char *str, u_char *tag) +{ +  u_int32_t l; + +  l = atol (str); + +  tag[0] = (u_char)(l >> 12); +  tag[1] = (u_char)(l >> 4); +  tag[2] = (u_char)(l << 4); + +  return 1; +} + +char * +prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size) +{ +  u_char *pnt; +  u_int16_t type; +  struct rd_as rd_as; +  struct rd_ip rd_ip; + +  if (size < RD_ADDRSTRLEN) +    return NULL; + +  pnt = prd->val; + +  type = decode_rd_type (pnt); + +  if (type == RD_TYPE_AS) +    { +      decode_rd_as (pnt + 2, &rd_as); +      snprintf (buf, size, "%d:%d", rd_as.as, rd_as.val); +      return buf; +    } +  else if (type == RD_TYPE_IP) +    { +      decode_rd_ip (pnt + 2, &rd_ip); +      snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); +      return buf; +    } + +  return NULL; +} + +/* For testing purpose, static route of MPLS-VPN. */ +DEFUN (vpnv4_network, +       vpnv4_network_cmd, +       "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", +       "Specify a network to announce via BGP\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" +       "Specify Route Distinguisher\n" +       "VPN Route Distinguisher\n" +       "BGP tag\n" +       "tag value\n") +{ +  return bgp_static_set_vpnv4 (vty, argv[0], argv[1], argv[2]); +} + +/* For testing purpose, static route of MPLS-VPN. */ +DEFUN (no_vpnv4_network, +       no_vpnv4_network_cmd, +       "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", +       NO_STR +       "Specify a network to announce via BGP\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" +       "Specify Route Distinguisher\n" +       "VPN Route Distinguisher\n" +       "BGP tag\n" +       "tag value\n") +{ +  return bgp_static_unset_vpnv4 (vty, argv[0], argv[1], argv[2]); +} + +int +show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd) +{ +  struct bgp *bgp; +  struct bgp_table *table; +  struct bgp_node *rn; +  struct bgp_node *rm; +  struct attr *attr; +  int rd_header; +  int header = 1; +  char v4_header[] = "   Network          Next Hop            Metric LocPrf Weight Path%s"; + +  bgp = bgp_get_default (); +  if (bgp == NULL) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; +       rn = bgp_route_next (rn)) +    { +      if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) +        continue; + +      if ((table = rn->info) != NULL) +        { +          rd_header = 1; + +          for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) +            if ((attr = rm->info) != NULL) +              { +                if (header) +                  { +                    vty_out (vty, "BGP table version is 0, local router ID is %s%s", +                             inet_ntoa (bgp->router_id), VTY_NEWLINE); +                    vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", +                             VTY_NEWLINE); +                    vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", +                             VTY_NEWLINE, VTY_NEWLINE); +                    vty_out (vty, v4_header, VTY_NEWLINE); +                    header = 0; +                  } + +                if (rd_header) +                  { +                    u_int16_t type; +                    struct rd_as rd_as; +                    struct rd_ip rd_ip; +                    u_char *pnt; + +                    pnt = rn->p.u.val; + +                    /* Decode RD type. */ +                    type = decode_rd_type (pnt); +                    /* Decode RD value. */ +                    if (type == RD_TYPE_AS) +                      decode_rd_as (pnt + 2, &rd_as); +                    else if (type == RD_TYPE_IP) +                      decode_rd_ip (pnt + 2, &rd_ip); + +                    vty_out (vty, "Route Distinguisher: "); + +                    if (type == RD_TYPE_AS) +                      vty_out (vty, "%d:%d", rd_as.as, rd_as.val); +                    else if (type == RD_TYPE_IP) +                      vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + +                    vty_out (vty, "%s", VTY_NEWLINE); +                    rd_header = 0; +                  } +                route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN); +              } +        } +    } +  return CMD_SUCCESS; +} + +enum bgp_show_type +{ +  bgp_show_type_normal, +  bgp_show_type_regexp, +  bgp_show_type_prefix_list, +  bgp_show_type_filter_list, +  bgp_show_type_neighbor, +  bgp_show_type_cidr_only, +  bgp_show_type_prefix_longer, +  bgp_show_type_community_all, +  bgp_show_type_community, +  bgp_show_type_community_exact, +  bgp_show_type_community_list, +  bgp_show_type_community_list_exact +}; + +int +bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type, +		   void *output_arg, int tags) +{ +  struct bgp *bgp; +  struct bgp_table *table; +  struct bgp_node *rn; +  struct bgp_node *rm; +  struct bgp_info *ri; +  int rd_header; +  int header = 1; +  char v4_header[] = "   Network          Next Hop            Metric LocPrf Weight Path%s"; +  char v4_header_tag[] = "   Network          Next Hop      In tag/Out tag%s"; + +  bgp = bgp_get_default (); +  if (bgp == NULL) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +   +  for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) +    { +      if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) +	continue; + +      if ((table = rn->info) != NULL) +	{ +	  rd_header = 1; + +	  for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) +	    for (ri = rm->info; ri; ri = ri->next) +	      { +		if (type == bgp_show_type_neighbor) +		  { +		    union sockunion *su = output_arg; + +		    if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) +		      continue; +		  } +		if (header) +		  { +		    if (tags) +		      vty_out (vty, v4_header_tag, VTY_NEWLINE); +		    else +		      { +			vty_out (vty, "BGP table version is 0, local router ID is %s%s", +				 inet_ntoa (bgp->router_id), VTY_NEWLINE); +			vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", +				 VTY_NEWLINE); +			vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", +				 VTY_NEWLINE, VTY_NEWLINE); +			vty_out (vty, v4_header, VTY_NEWLINE); +		      } +		    header = 0; +		  } + +		if (rd_header) +		  { +		    u_int16_t type; +		    struct rd_as rd_as; +		    struct rd_ip rd_ip; +		    u_char *pnt; + +		    pnt = rn->p.u.val; + +		    /* Decode RD type. */ +		    type = decode_rd_type (pnt); +		    /* Decode RD value. */ +		    if (type == RD_TYPE_AS) +		      decode_rd_as (pnt + 2, &rd_as); +		    else if (type == RD_TYPE_IP) +		      decode_rd_ip (pnt + 2, &rd_ip); + +		    vty_out (vty, "Route Distinguisher: "); + +		    if (type == RD_TYPE_AS) +		      vty_out (vty, "%d:%d", rd_as.as, rd_as.val); +		    else if (type == RD_TYPE_IP) +		      vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); +		   +		    vty_out (vty, "%s", VTY_NEWLINE);		   +		    rd_header = 0; +		  } +	        if (tags) +		  route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_MPLS_VPN); +	        else +		  route_vty_out (vty, &rm->p, ri, 0, SAFI_MPLS_VPN); +	      } +        } +    } +  return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_vpnv4_all, +       show_ip_bgp_vpnv4_all_cmd, +       "show ip bgp vpnv4 all", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information about all VPNv4 NLRIs\n") +{ +  return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 0); +} + +DEFUN (show_ip_bgp_vpnv4_rd, +       show_ip_bgp_vpnv4_rd_cmd, +       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information for a route distinguisher\n" +       "VPN Route Distinguisher\n") +{ +  int ret; +  struct prefix_rd prd; + +  ret = str2prefix_rd (argv[0], &prd); +  if (! ret) +    { +      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 0); +} + +DEFUN (show_ip_bgp_vpnv4_all_tags, +       show_ip_bgp_vpnv4_all_tags_cmd, +       "show ip bgp vpnv4 all tags", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information about all VPNv4 NLRIs\n" +       "Display BGP tags for prefixes\n") +{ +  return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL,  1); +} + +DEFUN (show_ip_bgp_vpnv4_rd_tags, +       show_ip_bgp_vpnv4_rd_tags_cmd, +       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information for a route distinguisher\n" +       "VPN Route Distinguisher\n" +       "Display BGP tags for prefixes\n") +{ +  int ret; +  struct prefix_rd prd; + +  ret = str2prefix_rd (argv[0], &prd); +  if (! ret) +    { +      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_all_neighbor_routes, +       show_ip_bgp_vpnv4_all_neighbor_routes_cmd, +       "show ip bgp vpnv4 all neighbors A.B.C.D routes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information about all VPNv4 NLRIs\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Display routes learned from neighbor\n") +{ +  union sockunion *su; +  struct peer *peer; +   +  su = sockunion_str2su (argv[0]); +  if (su == NULL) +    { +      vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); +               return CMD_WARNING; +    } + +  peer = peer_lookup (NULL, su); +  if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) +    { +      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_neighbor, su, 0); +} + +DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes, +       show_ip_bgp_vpnv4_rd_neighbor_routes_cmd, +       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information for a route distinguisher\n" +       "VPN Route Distinguisher\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Display routes learned from neighbor\n") +{ +  int ret; +  union sockunion *su; +  struct peer *peer; +  struct prefix_rd prd; + +  ret = str2prefix_rd (argv[0], &prd); +  if (! ret) +    { +      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  su = sockunion_str2su (argv[1]); +  if (su == NULL) +    { +      vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); +               return CMD_WARNING; +    } + +  peer = peer_lookup (NULL, su); +  if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) +    { +      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, su, 0); +} + +DEFUN (show_ip_bgp_vpnv4_all_neighbor_advertised_routes, +       show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd, +       "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information about all VPNv4 NLRIs\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Display the routes advertised to a BGP neighbor\n") +{ +  int ret; +  struct peer *peer; +  union sockunion su; + +  ret = str2sockunion (argv[0], &su); +  if (ret < 0) +    { +      vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); +      return CMD_WARNING; +    } +  peer = peer_lookup (NULL, &su); +  if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) +    { +      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return show_adj_route_vpn (vty, peer, NULL); +} + +DEFUN (show_ip_bgp_vpnv4_rd_neighbor_advertised_routes, +       show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd, +       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information for a route distinguisher\n" +       "VPN Route Distinguisher\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Display the routes advertised to a BGP neighbor\n") +{ +  int ret; +  struct peer *peer; +  struct prefix_rd prd; +  union sockunion su; + +  ret = str2sockunion (argv[1], &su); +  if (ret < 0) +    { +      vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); +      return CMD_WARNING; +    } +  peer = peer_lookup (NULL, &su); +  if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) +    { +      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  ret = str2prefix_rd (argv[0], &prd); +  if (! ret) +    { +      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return show_adj_route_vpn (vty, peer, &prd); +} + +void +bgp_mplsvpn_init () +{ +  install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd); +  install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd); + + +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd); + +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd); +} diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h new file mode 100644 index 0000000000..cd861a8737 --- /dev/null +++ b/bgpd/bgp_mplsvpn.h @@ -0,0 +1,45 @@ +/* MPLS-VPN +   Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org> + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#define RD_TYPE_AS      0 +#define RD_TYPE_IP      1 + +#define RD_ADDRSTRLEN  28 + +struct rd_as +{ +  u_int16_t type; +  as_t as; +  u_int32_t val; +}; + +struct rd_ip +{ +  u_int16_t type; +  struct in_addr ip; +  u_int16_t val; +}; + +void bgp_mplsvpn_init (); +int bgp_nlri_parse_vpnv4 (struct peer *, struct attr *, struct bgp_nlri *); +u_int32_t decode_label (u_char *); +int str2prefix_rd (u_char *, struct prefix_rd *); +int str2tag (u_char *, u_char *); +char *prefix_rd2str (struct prefix_rd *, char *, size_t); diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c new file mode 100644 index 0000000000..40e9cdb34b --- /dev/null +++ b/bgpd/bgp_network.c @@ -0,0 +1,381 @@ +/* BGP network related fucntions +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "thread.h" +#include "sockunion.h" +#include "memory.h" +#include "log.h" +#include "if.h" +#include "prefix.h" +#include "command.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_network.h" + +/* Accept bgp connection. */ +static int +bgp_accept (struct thread *thread) +{ +  int bgp_sock; +  int accept_sock; +  union sockunion su; +  struct peer *peer; +  struct peer *peer1; +  struct bgp *bgp; +  char buf[SU_ADDRSTRLEN]; + +  /* Regiser accept thread. */ +  accept_sock = THREAD_FD (thread); +  bgp = THREAD_ARG (thread); + +  if (accept_sock < 0) +    { +      zlog_err ("accept_sock is nevative value %d", accept_sock); +      return -1; +    } +  thread_add_read (master, bgp_accept, bgp, accept_sock); + +  /* Accept client connection. */ +  bgp_sock = sockunion_accept (accept_sock, &su); +  if (bgp_sock < 0) +    { +      zlog_err ("[Error] BGP socket accept failed (%s)", strerror (errno)); +      return -1; +    } + +  if (BGP_DEBUG (events, EVENTS)) +    zlog_info ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); +   +  /* Check remote IP address */ +  peer1 = peer_lookup (bgp, &su); +  if (! peer1 || peer1->status == Idle) +    { +      if (BGP_DEBUG (events, EVENTS)) +	{ +	  if (! peer1) +	    zlog_info ("[Event] BGP connection IP address %s is not configured", +		       inet_sutop (&su, buf)); +	  else +	    zlog_info ("[Event] BGP connection IP address %s is Idle state", +		       inet_sutop (&su, buf)); +	} +      close (bgp_sock); +      return -1; +    } + +  /* In case of peer is EBGP, we should set TTL for this connection.  */ +  if (peer_sort (peer1) == BGP_PEER_EBGP) +    sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl); + +  if (! bgp) +    bgp = peer1->bgp; + +  /* Make dummy peer until read Open packet. */ +  if (BGP_DEBUG (events, EVENTS)) +    zlog_info ("[Event] Make dummy peer structure until read Open packet"); + +  { +    char buf[SU_ADDRSTRLEN + 1]; + +    peer = peer_create_accept (bgp); +    SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); +    peer->su = su; +    peer->fd = bgp_sock; +    peer->status = Active; +    peer->local_id = peer1->local_id; + +    /* Make peer's address string. */ +    sockunion2str (&su, buf, SU_ADDRSTRLEN); +    peer->host = strdup (buf); +  } + +  BGP_EVENT_ADD (peer, TCP_connection_open); + +  return 0; +} + +/* BGP socket bind. */ +int +bgp_bind (struct peer *peer) +{ +#ifdef SO_BINDTODEVICE +  int ret; +  struct ifreq ifreq; + +  if (! peer->ifname) +    return 0; + +  strncpy ((char *)&ifreq.ifr_name, peer->ifname, sizeof (ifreq.ifr_name)); + +  ret = setsockopt (peer->fd, SOL_SOCKET, SO_BINDTODEVICE,  +		    &ifreq, sizeof (ifreq)); +  if (ret < 0) +    { +      zlog (peer->log, LOG_INFO, "bind to interface %s failed", peer->ifname); +      return ret; +    } +#endif /* SO_BINDTODEVICE */ +  return 0; +} + +int +bgp_bind_address (int sock, struct in_addr *addr) +{ +  int ret; +  struct sockaddr_in local; + +  memset (&local, 0, sizeof (struct sockaddr_in)); +  local.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN +  local.sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ +  memcpy (&local.sin_addr, addr, sizeof (struct in_addr)); + +  ret = bind (sock, (struct sockaddr *)&local, sizeof (struct sockaddr_in)); +  if (ret < 0) +    ; +  return 0; +} + +struct in_addr * +bgp_update_address (struct interface *ifp) +{ +  struct prefix_ipv4 *p; +  struct connected *connected; +  listnode node; + +  for (node = listhead (ifp->connected); node; nextnode (node)) +    { +      connected = getdata (node); + +      p = (struct prefix_ipv4 *) connected->address; + +      if (p->family == AF_INET) +	return &p->prefix; +    } +  return NULL; +} + +/* Update source selection.  */ +void +bgp_update_source (struct peer *peer) +{ +  struct interface *ifp; +  struct in_addr *addr; + +  /* Source is specified with interface name.  */ +  if (peer->update_if) +    { +      ifp = if_lookup_by_name (peer->update_if); +      if (! ifp) +	return; + +      addr = bgp_update_address (ifp); +      if (! addr) +	return; + +      bgp_bind_address (peer->fd, addr); +    } + +  /* Source is specified with IP address.  */ +  if (peer->update_source) +    sockunion_bind (peer->fd, peer->update_source, 0, peer->update_source); +} + +/* BGP try to connect to the peer.  */ +int +bgp_connect (struct peer *peer) +{ +  unsigned int ifindex = 0; + +  /* Make socket for the peer. */ +  peer->fd = sockunion_socket (&peer->su); +  if (peer->fd < 0) +    return -1; + +  /* If we can get socket for the peer, adjest TTL and make connection. */ +  if (peer_sort (peer) == BGP_PEER_EBGP) +    sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); + +  sockopt_reuseaddr (peer->fd); +  sockopt_reuseport (peer->fd); + +  /* Bind socket. */ +  bgp_bind (peer); + +  /* Update source bind. */ +  bgp_update_source (peer); + +#ifdef HAVE_IPV6 +  if (peer->ifname) +    ifindex = if_nametoindex (peer->ifname); +#endif /* HAVE_IPV6 */ + +  if (BGP_DEBUG (events, EVENTS)) +    plog_info (peer->log, "%s [Event] Connect start to %s fd %d", +	       peer->host, peer->host, peer->fd); + +  /* Connect to the remote peer. */ +  return sockunion_connect (peer->fd, &peer->su, htons (peer->port), ifindex); +} + +/* After TCP connection is established.  Get local address and port. */ +void +bgp_getsockname (struct peer *peer) +{ +  if (peer->su_local) +    { +      XFREE (MTYPE_TMP, peer->su_local); +      peer->su_local = NULL; +    } + +  if (peer->su_remote) +    { +      XFREE (MTYPE_TMP, peer->su_remote); +      peer->su_remote = NULL; +    } + +  peer->su_local = sockunion_getsockname (peer->fd); +  peer->su_remote = sockunion_getpeername (peer->fd); + +  bgp_nexthop_set (peer->su_local, peer->su_remote, &peer->nexthop, peer); +} + +/* IPv6 supported version of BGP server socket setup.  */ +#if defined (HAVE_IPV6) && ! defined (NRL) +int +bgp_socket (struct bgp *bgp, unsigned short port) +{ +  int ret; +  struct addrinfo req; +  struct addrinfo *ainfo; +  struct addrinfo *ainfo_save; +  int sock = 0; +  char port_str[BUFSIZ]; + +  memset (&req, 0, sizeof (struct addrinfo)); + +  req.ai_flags = AI_PASSIVE; +  req.ai_family = AF_UNSPEC; +  req.ai_socktype = SOCK_STREAM; +  sprintf (port_str, "%d", port); +  port_str[sizeof (port_str) - 1] = '\0'; + +  ret = getaddrinfo (NULL, port_str, &req, &ainfo); +  if (ret != 0) +    { +      zlog_err ("getaddrinfo: %s", gai_strerror (ret)); +      return -1; +    } + +  ainfo_save = ainfo; + +  do +    { +      if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6) +	continue; +      +      sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); +      if (sock < 0) +	{ +	  zlog_err ("socket: %s", strerror (errno)); +	  continue; +	} + +      sockopt_reuseaddr (sock); +      sockopt_reuseport (sock); + +      ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen); +      if (ret < 0) +	{ +	  zlog_err ("bind: %s", strerror (errno)); +	  close (sock); +	  continue; +	} +      ret = listen (sock, 3); +      if (ret < 0)  +	{ +	  zlog_err ("listen: %s", strerror (errno)); +	  close (sock); +	  continue; +	} + +      thread_add_read (master, bgp_accept, bgp, sock); +    } +  while ((ainfo = ainfo->ai_next) != NULL); + +  freeaddrinfo (ainfo_save); + +  return sock; +} +#else +/* Traditional IPv4 only version.  */ +int +bgp_socket (struct bgp *bgp, unsigned short port) +{ +  int sock; +  int socklen; +  struct sockaddr_in sin; +  int ret; + +  sock = socket (AF_INET, SOCK_STREAM, 0); +  if (sock < 0) +    { +      zlog_err ("socket: %s", strerror (errno)); +      return sock; +    } + +  sockopt_reuseaddr (sock); +  sockopt_reuseport (sock); + +  memset (&sin, 0, sizeof (struct sockaddr_in)); + +  sin.sin_family = AF_INET; +  sin.sin_port = htons (port); +  socklen = sizeof (struct sockaddr_in); +#ifdef HAVE_SIN_LEN +  sin.sin_len = socklen; +#endif /* HAVE_SIN_LEN */ + +  ret = bind (sock, (struct sockaddr *) &sin, socklen); +  if (ret < 0) +    { +      zlog_err ("bind: %s", strerror (errno)); +      close (sock); +      return ret; +    } +  ret = listen (sock, 3); +  if (ret < 0)  +    { +      zlog_err ("listen: %s", strerror (errno)); +      close (sock); +      return ret; +    } + +  thread_add_read (bm->master, bgp_accept, bgp, sock); + +  return sock; +} +#endif /* HAVE_IPV6 && !NRL */ diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h new file mode 100644 index 0000000000..b994987366 --- /dev/null +++ b/bgpd/bgp_network.h @@ -0,0 +1,23 @@ +/* BGP network related header +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +int bgp_socket (struct bgp *, unsigned short); +int bgp_connect (struct peer *); +void bgp_getsockname (struct peer *); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c new file mode 100644 index 0000000000..24a113d957 --- /dev/null +++ b/bgpd/bgp_nexthop.c @@ -0,0 +1,1405 @@ +/* BGP nexthop scan +   Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "command.h" +#include "thread.h" +#include "prefix.h" +#include "zclient.h" +#include "stream.h" +#include "network.h" +#include "log.h" +#include "memory.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_damp.h" +#include "zebra/rib.h" +#include "zebra/zserv.h"	/* For ZEBRA_SERV_PATH. */ + +struct bgp_nexthop_cache *zlookup_query (struct in_addr); +#ifdef HAVE_IPV6 +struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *); +#endif /* HAVE_IPV6 */ + +/* Only one BGP scan thread are activated at the same time. */ +struct thread *bgp_scan_thread = NULL; + +/* BGP import thread */ +struct thread *bgp_import_thread = NULL; + +/* BGP scan interval. */ +int bgp_scan_interval; + +/* BGP import interval. */ +int bgp_import_interval; + +/* Route table for next-hop lookup cache. */ +struct bgp_table *bgp_nexthop_cache_ipv4; +struct bgp_table *cache1; +struct bgp_table *cache2; + +/* Route table for next-hop lookup cache. */ +struct bgp_table *bgp_nexthop_cache_ipv6; +struct bgp_table *cache6_1; +struct bgp_table *cache6_2; + +/* Route table for connected route. */ +struct bgp_table *bgp_connected_ipv4; + +/* Route table for connected route. */ +struct bgp_table *bgp_connected_ipv6; + +/* BGP nexthop lookup query client. */ +static struct zclient *zlookup = NULL; + +/* BGP process function. */ +int bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t); + +/* Add nexthop to the end of the list.  */ +void +bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop) +{ +  struct nexthop *last; + +  for (last = bnc->nexthop; last && last->next; last = last->next) +    ; +  if (last) +    last->next = nexthop; +  else +    bnc->nexthop = nexthop; +  nexthop->prev = last; +} + +void +bnc_nexthop_free (struct bgp_nexthop_cache *bnc) +{ +  struct nexthop *nexthop; +  struct nexthop *next = NULL; + +  for (nexthop = bnc->nexthop; nexthop; nexthop = next) +    { +      next = nexthop->next; +      XFREE (MTYPE_NEXTHOP, nexthop); +    } +} + +struct bgp_nexthop_cache * +bnc_new () +{ +  struct bgp_nexthop_cache *new; + +  new = XMALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache)); +  memset (new, 0, sizeof (struct bgp_nexthop_cache)); +  return new; +} + +void +bnc_free (struct bgp_nexthop_cache *bnc) +{ +  bnc_nexthop_free (bnc); +  XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc); +} + +int +bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) +{ +  if (next1->type != next2->type) +    return 0; + +  switch (next1->type) +    { +    case ZEBRA_NEXTHOP_IPV4: +      if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)) +	return 0; +      break; +    case ZEBRA_NEXTHOP_IFINDEX: +    case ZEBRA_NEXTHOP_IFNAME: +      if (next1->ifindex != next2->ifindex) +	return 0; +      break; +#ifdef HAVE_IPV6 +    case ZEBRA_NEXTHOP_IPV6: +      if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) +	return 0; +      break; +    case ZEBRA_NEXTHOP_IPV6_IFINDEX: +    case ZEBRA_NEXTHOP_IPV6_IFNAME: +      if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) +	return 0; +      if (next1->ifindex != next2->ifindex) +	return 0; +      break; +#endif /* HAVE_IPV6 */ +    } +  return 1; +} + +int +bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1, +			   struct bgp_nexthop_cache *bnc2) +{ +  int i; +  struct nexthop *next1, *next2; + +  if (bnc1->nexthop_num != bnc2->nexthop_num) +    return 1; + +  next1 = bnc1->nexthop; +  next2 = bnc2->nexthop; + +  for (i = 0; i < bnc1->nexthop_num; i++) +    { +      if (! bgp_nexthop_same (next1, next2)) +	return 1; + +      next1 = next1->next; +      next2 = next2->next; +    } +  return 0; +} + +/* If nexthop exists on connected network return 1. */ +int +bgp_nexthop_check_ebgp (afi_t afi, struct attr *attr) +{ +  struct bgp_node *rn; + +  /* If zebra is not enabled return */ +  if (zlookup->sock < 0) +    return 1; + +  /* Lookup the address is onlink or not. */ +  if (afi == AFI_IP) +    { +      rn = bgp_node_match_ipv4 (bgp_connected_ipv4, &attr->nexthop); +      if (rn) +	{ +	  bgp_unlock_node (rn); +	  return 1; +	} +    } +#ifdef HAVE_IPV6 +  else if (afi == AFI_IP6) +    { +      if (attr->mp_nexthop_len == 32) +	return 1; +      else if (attr->mp_nexthop_len == 16) +	{ +	  if (IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global)) +	    return 1; + +	  rn = bgp_node_match_ipv6 (bgp_connected_ipv6, +				      &attr->mp_nexthop_global); +	  if (rn) +	    { +	      bgp_unlock_node (rn); +	      return 1; +	    } +	} +    } +#endif /* HAVE_IPV6 */ +  return 0; +} + +#ifdef HAVE_IPV6 +/* Check specified next-hop is reachable or not. */ +int +bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, +			 int *metricchanged) +{ +  struct bgp_node *rn; +  struct prefix p; +  struct bgp_nexthop_cache *bnc; +  struct attr *attr; + +  /* If lookup is not enabled, return valid. */ +  if (zlookup->sock < 0) +    { +      ri->igpmetric = 0; +      return 1; +    } + +  /* Only check IPv6 global address only nexthop. */ +  attr = ri->attr; + +  if (attr->mp_nexthop_len != 16  +      || IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global)) +    return 1; + +  memset (&p, 0, sizeof (struct prefix)); +  p.family = AF_INET6; +  p.prefixlen = IPV6_MAX_BITLEN; +  p.u.prefix6 = attr->mp_nexthop_global; + +  /* IBGP or ebgp-multihop */ +  rn = bgp_node_get (bgp_nexthop_cache_ipv6, &p); + +  if (rn->info) +    { +      bnc = rn->info; +      bgp_unlock_node (rn); +    } +  else +    { +      bnc = zlookup_query_ipv6 (&attr->mp_nexthop_global); +      if (bnc) +	{ +	  struct bgp_table *old; +	  struct bgp_node *oldrn; +	  struct bgp_nexthop_cache *oldbnc; + +	  if (changed) +	    { +	      if (bgp_nexthop_cache_ipv6 == cache6_1) +		old = cache6_2; +	      else +		old = cache6_1; + +	      oldrn = bgp_node_lookup (old, &p); +	      if (oldrn) +		{ +		  oldbnc = oldrn->info; + +		  bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); + +		  if (bnc->metric != oldbnc->metric) +		    bnc->metricchanged = 1; +		} +	    } +	} +      else +	{ +	  bnc = bnc_new (); +	  bnc->valid = 0; +	} +      rn->info = bnc; +    } + +  if (changed) +    *changed = bnc->changed; + +  if (metricchanged) +    *metricchanged = bnc->metricchanged; + +  if (bnc->valid) +    ri->igpmetric = bnc->metric; +  else +    ri->igpmetric = 0; + +  return bnc->valid; +} +#endif /* HAVE_IPV6 */ + +/* Check specified next-hop is reachable or not. */ +int +bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, +		    int *changed, int *metricchanged) +{ +  struct bgp_node *rn; +  struct prefix p; +  struct bgp_nexthop_cache *bnc; +  struct in_addr addr; + +  /* If lookup is not enabled, return valid. */ +  if (zlookup->sock < 0) +    { +      ri->igpmetric = 0; +      return 1; +    } + +#ifdef HAVE_IPV6 +  if (afi == AFI_IP6) +    return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); +#endif /* HAVE_IPV6 */ + +  addr = ri->attr->nexthop; + +  memset (&p, 0, sizeof (struct prefix)); +  p.family = AF_INET; +  p.prefixlen = IPV4_MAX_BITLEN; +  p.u.prefix4 = addr; + +  /* IBGP or ebgp-multihop */ +  rn = bgp_node_get (bgp_nexthop_cache_ipv4, &p); + +  if (rn->info) +    { +      bnc = rn->info; +      bgp_unlock_node (rn); +    } +  else +    { +      bnc = zlookup_query (addr); +      if (bnc) +	{ +	  struct bgp_table *old; +	  struct bgp_node *oldrn; +	  struct bgp_nexthop_cache *oldbnc; + +	  if (changed) +	    { +	      if (bgp_nexthop_cache_ipv4 == cache1) +		old = cache2; +	      else +		old = cache1; + +	      oldrn = bgp_node_lookup (old, &p); +	      if (oldrn) +		{ +		  oldbnc = oldrn->info; + +		  bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); + +		  if (bnc->metric != oldbnc->metric) +		    bnc->metricchanged = 1; +		} +	    } +	} +      else +	{ +	  bnc = bnc_new (); +	  bnc->valid = 0; +	} +      rn->info = bnc; +    } + +  if (changed) +    *changed = bnc->changed; + +  if (metricchanged) +    *metricchanged = bnc->metricchanged; + +  if (bnc->valid) +    ri->igpmetric = bnc->metric; +  else +    ri->igpmetric = 0; + +  return bnc->valid; +} + +/* Reset and free all BGP nexthop cache. */ +void +bgp_nexthop_cache_reset (struct bgp_table *table) +{ +  struct bgp_node *rn; +  struct bgp_nexthop_cache *bnc; + +  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) +    if ((bnc = rn->info) != NULL) +      { +	bnc_free (bnc); +	rn->info = NULL; +	bgp_unlock_node (rn); +      } +} + +void +bgp_scan_ipv4 () +{ +  struct bgp_node *rn; +  struct bgp *bgp; +  struct bgp_info *bi; +  struct bgp_info *next; +  struct peer *peer; +  struct listnode *nn; +  int valid; +  int current; +  int changed; +  int metricchanged; + +  /* Change cache. */ +  if (bgp_nexthop_cache_ipv4 == cache1) +    bgp_nexthop_cache_ipv4 = cache2; +  else +    bgp_nexthop_cache_ipv4 = cache1; + +  /* Get default bgp. */ +  bgp = bgp_get_default (); +  if (bgp == NULL) +    return; + +  /* Maximum prefix check */ +  LIST_LOOP (bgp->peer, peer, nn) +    { +      if (peer->status != Established) +	continue; + +      if (peer->afc[AFI_IP][SAFI_UNICAST]) +	bgp_maximum_prefix_overflow (peer, AFI_IP, SAFI_UNICAST); +      if (peer->afc[AFI_IP][SAFI_MULTICAST]) +	bgp_maximum_prefix_overflow (peer, AFI_IP, SAFI_MULTICAST); +      if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) +	bgp_maximum_prefix_overflow (peer, AFI_IP, SAFI_MPLS_VPN); +    } + +  for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_UNICAST]); rn; +       rn = bgp_route_next (rn)) +    { +      for (bi = rn->info; bi; bi = next) +	{ +	  next = bi->next; + +	  if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL) +	    { +	      changed = 0; +	      metricchanged = 0; + +	      if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1) +		valid = bgp_nexthop_check_ebgp (AFI_IP, bi->attr); +	      else +		valid = bgp_nexthop_lookup (AFI_IP, bi->peer, bi, +					    &changed, &metricchanged); + +	      current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0; + +	      if (changed) +		SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); +	      else +		UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); + +	      if (valid != current) +		{ +		  if (CHECK_FLAG (bi->flags, BGP_INFO_VALID)) +		    { +		      bgp_aggregate_decrement (bgp, &rn->p, bi, +					       AFI_IP, SAFI_UNICAST); +		      UNSET_FLAG (bi->flags, BGP_INFO_VALID); +		    } +		  else +		    { +		      SET_FLAG (bi->flags, BGP_INFO_VALID); +		      bgp_aggregate_increment (bgp, &rn->p, bi, +					       AFI_IP, SAFI_UNICAST); +		    } +		} + +              if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST], +		  BGP_CONFIG_DAMPENING) +                  &&  bi->damp_info ) +                if (bgp_damp_scan (bi, AFI_IP, SAFI_UNICAST)) +		  bgp_aggregate_increment (bgp, &rn->p, bi, +					   AFI_IP, SAFI_UNICAST); +	    } +	} +      bgp_process (bgp, rn, AFI_IP, SAFI_UNICAST); +    } + +  /* Flash old cache. */ +  if (bgp_nexthop_cache_ipv4 == cache1) +    bgp_nexthop_cache_reset (cache2); +  else +    bgp_nexthop_cache_reset (cache1); +} + +#ifdef HAVE_IPV6 +void +bgp_scan_ipv6 () +{ +  struct bgp_node *rn; +  struct bgp *bgp; +  struct bgp_info *bi; +  struct bgp_info *next; +  struct peer *peer; +  struct listnode *nn; +  int valid; +  int current; +  int changed; +  int metricchanged; + +  /* Change cache. */ +  if (bgp_nexthop_cache_ipv6 == cache6_1) +    bgp_nexthop_cache_ipv6 = cache6_2; +  else +    bgp_nexthop_cache_ipv6 = cache6_1; + +  /* Get default bgp. */ +  bgp = bgp_get_default (); +  if (bgp == NULL) +    return; + +  /* Maximum prefix check */ +  LIST_LOOP (bgp->peer, peer, nn) +    { +      if (peer->status != Established) +	continue; + +      if (peer->afc[AFI_IP6][SAFI_UNICAST]) +	bgp_maximum_prefix_overflow (peer, AFI_IP6, SAFI_UNICAST); +      if (peer->afc[AFI_IP6][SAFI_MULTICAST]) +	bgp_maximum_prefix_overflow (peer, AFI_IP6, SAFI_MULTICAST); +    } + +  for (rn = bgp_table_top (bgp->rib[AFI_IP6][SAFI_UNICAST]); rn; +       rn = bgp_route_next (rn)) +    { +      for (bi = rn->info; bi; bi = next) +	{ +	  next = bi->next; + +	  if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL) +	    { +	      changed = 0; +	      metricchanged = 0; + +	      if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1) +		valid = 1; +	      else +		valid = bgp_nexthop_lookup_ipv6 (bi->peer, bi, +						 &changed, &metricchanged); + +	      current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0; + +	      if (changed) +		SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); +	      else +		UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); + +	      if (valid != current) +		{ +		  if (CHECK_FLAG (bi->flags, BGP_INFO_VALID)) +		    { +		      bgp_aggregate_decrement (bgp, &rn->p, bi, +					       AFI_IP6, SAFI_UNICAST); +		      UNSET_FLAG (bi->flags, BGP_INFO_VALID); +		    } +		  else +		    { +		      SET_FLAG (bi->flags, BGP_INFO_VALID); +		      bgp_aggregate_increment (bgp, &rn->p, bi, +					       AFI_IP6, SAFI_UNICAST); +		    } +		} + +              if (CHECK_FLAG (bgp->af_flags[AFI_IP6][SAFI_UNICAST], +		  BGP_CONFIG_DAMPENING) +                  &&  bi->damp_info ) +                if (bgp_damp_scan (bi, AFI_IP6, SAFI_UNICAST)) +		  bgp_aggregate_increment (bgp, &rn->p, bi, +					   AFI_IP6, SAFI_UNICAST); +	    } +	} +      bgp_process (bgp, rn, AFI_IP6, SAFI_UNICAST); +    } + +  /* Flash old cache. */ +  if (bgp_nexthop_cache_ipv6 == cache6_1) +    bgp_nexthop_cache_reset (cache6_2); +  else +    bgp_nexthop_cache_reset (cache6_1); +} +#endif /* HAVE_IPV6 */ + +/* BGP scan thread.  This thread check nexthop reachability. */ +int +bgp_scan (struct thread *t) +{ +  bgp_scan_thread = +    thread_add_timer (master, bgp_scan, NULL, bgp_scan_interval); + +  if (BGP_DEBUG (normal, NORMAL)) +    zlog_info ("Performing BGP general scanning"); + +  bgp_scan_ipv4 (); + +#ifdef HAVE_IPV6 +  bgp_scan_ipv6 (); +#endif /* HAVE_IPV6 */ + +  return 0; +} + +struct bgp_connected +{ +  unsigned int refcnt; +}; + +void +bgp_connected_add (struct connected *ifc) +{ +  struct prefix p; +  struct prefix *addr; +  struct prefix *dest; +  struct interface *ifp; +  struct bgp_node *rn; +  struct bgp_connected *bc; + +  ifp = ifc->ifp; + +  if (! ifp) +    return; + +  if (if_is_loopback (ifp)) +    return; + +  addr = ifc->address; +  dest = ifc->destination; + +  if (addr->family == AF_INET) +    { +      memset (&p, 0, sizeof (struct prefix)); +      p.family = AF_INET; +      p.prefixlen = addr->prefixlen; + +      if (if_is_pointopoint (ifp)) +	p.u.prefix4 = dest->u.prefix4; +      else +	p.u.prefix4 = addr->u.prefix4; + +      apply_mask_ipv4 ((struct prefix_ipv4 *) &p); + +      if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) +	return; + +      rn = bgp_node_get (bgp_connected_ipv4, (struct prefix *) &p); +      if (rn->info) +	{ +	  bc = rn->info; +	  bc->refcnt++; +	} +      else +	{ +	  bc = XMALLOC (0, sizeof (struct bgp_connected)); +	  memset (bc, 0, sizeof (struct bgp_connected)); +	  bc->refcnt = 1; +	  rn->info = bc; +	} +    } +#ifdef HAVE_IPV6 +  if (addr->family == AF_INET6) +    { +      memset (&p, 0, sizeof (struct prefix)); +      p.family = AF_INET6; +      p.prefixlen = addr->prefixlen; + +      if (if_is_pointopoint (ifp)) +	p.u.prefix6 = dest->u.prefix6; +      else +	p.u.prefix6 = addr->u.prefix6; + +      apply_mask_ipv6 ((struct prefix_ipv6 *) &p); + +      if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) +	return; + +      if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) +	return; + +      rn = bgp_node_get (bgp_connected_ipv6, (struct prefix *) &p); +      if (rn->info) +	{ +	  bc = rn->info; +	  bc->refcnt++; +	} +      else +	{ +	  bc = XMALLOC (0, sizeof (struct bgp_connected)); +	  memset (bc, 0, sizeof (struct bgp_connected)); +	  bc->refcnt = 1; +	  rn->info = bc; +	} +    } +#endif /* HAVE_IPV6 */ +} + +void +bgp_connected_delete (struct connected *ifc) +{ +  struct prefix p; +  struct prefix *addr; +  struct prefix *dest; +  struct interface *ifp; +  struct bgp_node *rn; +  struct bgp_connected *bc; + +  ifp = ifc->ifp; + +  if (if_is_loopback (ifp)) +    return; + +  addr = ifc->address; +  dest = ifc->destination; + +  if (addr->family == AF_INET) +    { +      memset (&p, 0, sizeof (struct prefix)); +      p.family = AF_INET; +      p.prefixlen = addr->prefixlen; + +      if (if_is_pointopoint (ifp)) +	p.u.prefix4 = dest->u.prefix4; +      else +	p.u.prefix4 = addr->u.prefix4; + +      apply_mask_ipv4 ((struct prefix_ipv4 *) &p); + +      if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) +	return; + +      rn = bgp_node_lookup (bgp_connected_ipv4, &p); +      if (! rn) +	return; + +      bc = rn->info; +      bc->refcnt--; +      if (bc->refcnt == 0) +	{ +	  XFREE (0, bc); +	  rn->info = NULL; +	} +      bgp_unlock_node (rn); +      bgp_unlock_node (rn); +    } +#ifdef HAVE_IPV6 +  else if (addr->family == AF_INET6) +    { +      memset (&p, 0, sizeof (struct prefix)); +      p.family = AF_INET6; +      p.prefixlen = addr->prefixlen; + +      if (if_is_pointopoint (ifp)) +	p.u.prefix6 = dest->u.prefix6; +      else +	p.u.prefix6 = addr->u.prefix6; + +      apply_mask_ipv6 ((struct prefix_ipv6 *) &p); + +      if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) +	return; + +      if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) +	return; + +      rn = bgp_node_lookup (bgp_connected_ipv6, (struct prefix *) &p); +      if (! rn) +	return; + +      bc = rn->info; +      bc->refcnt--; +      if (bc->refcnt == 0) +	{ +	  XFREE (0, bc); +	  rn->info = NULL; +	} +      bgp_unlock_node (rn); +      bgp_unlock_node (rn); +    } +#endif /* HAVE_IPV6 */ +} + +int +bgp_nexthop_self (afi_t afi, struct attr *attr) +{ +  listnode node; +  listnode node2; +  struct interface *ifp; +  struct connected *ifc; +  struct prefix *p; + +  for (node = listhead (iflist); node; nextnode (node)) +    { +      ifp = getdata (node); + +      for (node2 = listhead (ifp->connected); node2; nextnode (node2)) +	{ +	  ifc = getdata (node2); +	  p = ifc->address; + +	  if (p && p->family == AF_INET  +	      && IPV4_ADDR_SAME (&p->u.prefix4, &attr->nexthop)) +	    return 1; +	} +    } +  return 0; +} + +struct bgp_nexthop_cache * +zlookup_read () +{ +  struct stream *s; +  u_int16_t length; +  u_char command; +  int nbytes; +  struct in_addr raddr; +  u_int32_t metric; +  int i; +  u_char nexthop_num; +  struct nexthop *nexthop; +  struct bgp_nexthop_cache *bnc; + +  s = zlookup->ibuf; +  stream_reset (s); + +  nbytes = stream_read (s, zlookup->sock, 2); +  length = stream_getw (s); + +  nbytes = stream_read (s, zlookup->sock, length - 2); +  command = stream_getc (s); +  raddr.s_addr = stream_get_ipv4 (s); +  metric = stream_getl (s); +  nexthop_num = stream_getc (s); + +  if (nexthop_num) +    { +      bnc = bnc_new (); +      bnc->valid = 1; +      bnc->metric = metric; +      bnc->nexthop_num = nexthop_num; + +      for (i = 0; i < nexthop_num; i++) +	{ +	  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); +	  memset (nexthop, 0, sizeof (struct nexthop)); +	  nexthop->type = stream_getc (s); +	  switch (nexthop->type) +	    { +	    case ZEBRA_NEXTHOP_IPV4: +	      nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); +	      break; +	    case ZEBRA_NEXTHOP_IFINDEX: +	    case ZEBRA_NEXTHOP_IFNAME: +	      nexthop->ifindex = stream_getl (s); +	      break; +	    } +	  bnc_nexthop_add (bnc, nexthop); +	} +    } +  else +    return NULL; + +  return bnc; +} + +struct bgp_nexthop_cache * +zlookup_query (struct in_addr addr) +{ +  int ret; +  struct stream *s; + +  /* Check socket. */ +  if (zlookup->sock < 0) +    return NULL; + +  s = zlookup->obuf; +  stream_reset (s); +  stream_putw (s, 7); +  stream_putc (s, ZEBRA_IPV4_NEXTHOP_LOOKUP); +  stream_put_in_addr (s, &addr); + +  ret = writen (zlookup->sock, s->data, 7); +  if (ret < 0) +    { +      zlog_err ("can't write to zlookup->sock"); +      close (zlookup->sock); +      zlookup->sock = -1; +      return NULL; +    } +  if (ret == 0) +    { +      zlog_err ("zlookup->sock connection closed"); +      close (zlookup->sock); +      zlookup->sock = -1; +      return NULL; +    } + +  return zlookup_read (); +} + +#ifdef HAVE_IPV6 +struct bgp_nexthop_cache * +zlookup_read_ipv6 () +{ +  struct stream *s; +  u_int16_t length; +  u_char command; +  int nbytes; +  struct in6_addr raddr; +  u_int32_t metric; +  int i; +  u_char nexthop_num; +  struct nexthop *nexthop; +  struct bgp_nexthop_cache *bnc; + +  s = zlookup->ibuf; +  stream_reset (s); + +  nbytes = stream_read (s, zlookup->sock, 2); +  length = stream_getw (s); + +  nbytes = stream_read (s, zlookup->sock, length - 2); +  command = stream_getc (s); + +  stream_get (&raddr, s, 16); + +  metric = stream_getl (s); +  nexthop_num = stream_getc (s); + +  if (nexthop_num) +    { +      bnc = bnc_new (); +      bnc->valid = 1; +      bnc->metric = metric; +      bnc->nexthop_num = nexthop_num; + +      for (i = 0; i < nexthop_num; i++) +	{ +	  nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); +	  memset (nexthop, 0, sizeof (struct nexthop)); +	  nexthop->type = stream_getc (s); +	  switch (nexthop->type) +	    { +	    case ZEBRA_NEXTHOP_IPV6: +	      stream_get (&nexthop->gate.ipv6, s, 16); +	      break; +	    case ZEBRA_NEXTHOP_IPV6_IFINDEX: +	    case ZEBRA_NEXTHOP_IPV6_IFNAME: +	      stream_get (&nexthop->gate.ipv6, s, 16); +	      nexthop->ifindex = stream_getl (s); +	      break; +	    case ZEBRA_NEXTHOP_IFINDEX: +	    case ZEBRA_NEXTHOP_IFNAME: +	      nexthop->ifindex = stream_getl (s); +	      break; +	    } +	  bnc_nexthop_add (bnc, nexthop); +	} +    } +  else +    return NULL; + +  return bnc; +} + +struct bgp_nexthop_cache * +zlookup_query_ipv6 (struct in6_addr *addr) +{ +  int ret; +  struct stream *s; + +  /* Check socket. */ +  if (zlookup->sock < 0) +    return NULL; + +  s = zlookup->obuf; +  stream_reset (s); +  stream_putw (s, 19); +  stream_putc (s, ZEBRA_IPV6_NEXTHOP_LOOKUP); +  stream_put (s, addr, 16); + +  ret = writen (zlookup->sock, s->data, 19); +  if (ret < 0) +    { +      zlog_err ("can't write to zlookup->sock"); +      close (zlookup->sock); +      zlookup->sock = -1; +      return NULL; +    } +  if (ret == 0) +    { +      zlog_err ("zlookup->sock connection closed"); +      close (zlookup->sock); +      zlookup->sock = -1; +      return NULL; +    } + +  return zlookup_read_ipv6 (); +} +#endif /* HAVE_IPV6 */ + +int +bgp_import_check (struct prefix *p, u_int32_t *igpmetric, struct in_addr *igpnexthop) +{ +  struct stream *s; +  int ret; +  u_int16_t length; +  u_char command; +  int nbytes; +  struct in_addr addr; +  struct in_addr nexthop; +  u_int32_t metric = 0; +  u_char nexthop_num; +  u_char nexthop_type; + +  /* If lookup connection is not available return valid. */ +  if (zlookup->sock < 0) +    { +      if (igpmetric) +	*igpmetric = 0; +      return 1; +    } + +  /* Send query to the lookup connection */ +  s = zlookup->obuf; +  stream_reset (s); +  stream_putw (s, 8); +  stream_putc (s, ZEBRA_IPV4_IMPORT_LOOKUP); +  stream_putc (s, p->prefixlen); +  stream_put_in_addr (s, &p->u.prefix4); + +  /* Write the packet. */ +  ret = writen (zlookup->sock, s->data, 8); + +  if (ret < 0) +    { +      zlog_err ("can't write to zlookup->sock"); +      close (zlookup->sock); +      zlookup->sock = -1; +      return 1; +    } +  if (ret == 0) +    { +      zlog_err ("zlookup->sock connection closed"); +      close (zlookup->sock); +      zlookup->sock = -1; +      return 1; +    } + +  /* Get result. */ +  stream_reset (s); + +  /* Fetch length. */ +  nbytes = stream_read (s, zlookup->sock, 2); +  length = stream_getw (s); + +  /* Fetch whole data. */ +  nbytes = stream_read (s, zlookup->sock, length - 2); +  command = stream_getc (s); +  addr.s_addr = stream_get_ipv4 (s); +  metric = stream_getl (s); +  nexthop_num = stream_getc (s); + +  /* Set IGP metric value. */ +  if (igpmetric) +    *igpmetric = metric; + +  /* If there is nexthop then this is active route. */ +  if (nexthop_num) +    { +      nexthop.s_addr = 0; +      nexthop_type = stream_getc (s); +      if (nexthop_type == ZEBRA_NEXTHOP_IPV4) +	{ +	  nexthop.s_addr = stream_get_ipv4 (s); +	  if (igpnexthop) +	    *igpnexthop = nexthop; +	} +      else +	*igpnexthop = nexthop; + +      return 1; +    } +  else +    return 0; +} + +/* Scan all configured BGP route then check the route exists in IGP or +   not. */ +int +bgp_import (struct thread *t) +{ +  struct bgp *bgp; +  struct bgp_node *rn; +  struct bgp_static *bgp_static; +  int valid; +  u_int32_t metric; +  struct in_addr nexthop; +  afi_t afi; +  safi_t safi; + +  bgp_import_thread =  +    thread_add_timer (master, bgp_import, NULL, bgp_import_interval); + +  bgp = bgp_get_default (); +  if (! bgp) +    return 0; + +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MPLS_VPN; safi++) +      for (rn = bgp_table_top (bgp->route[afi][safi]); rn; +	   rn = bgp_route_next (rn)) +	if ((bgp_static = rn->info) != NULL) +	  { +	    if (bgp_static->backdoor) +	      continue; + +	    valid = bgp_static->valid; +	    metric = bgp_static->igpmetric; +	    nexthop = bgp_static->igpnexthop; + +	    if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK) +		&& afi == AFI_IP && safi == SAFI_UNICAST) +	      bgp_static->valid = bgp_import_check (&rn->p, &bgp_static->igpmetric, +						    &bgp_static->igpnexthop); +	    else +	      { +		bgp_static->valid = 1; +		bgp_static->igpmetric = 0; +		bgp_static->igpnexthop.s_addr = 0; +	      } + +	    if (bgp_static->valid != valid) +	      { +		if (bgp_static->valid) +		  bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); +		else +		  bgp_static_withdraw (bgp, &rn->p, afi, safi); +	      } +	    else if (bgp_static->valid) +	      { +		if (bgp_static->igpmetric != metric +		    || bgp_static->igpnexthop.s_addr != nexthop.s_addr +		    || bgp_static->rmap.name) +		  bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); +	      } +	  } +  return 0; +} + +/* Connect to zebra for nexthop lookup. */ +int +zlookup_connect (struct thread *t) +{ +  struct zclient *zlookup; + +  zlookup = THREAD_ARG (t); +  zlookup->t_connect = NULL; + +  if (zlookup->sock != -1) +    return 0; + +#ifdef HAVE_TCP_ZEBRA +  zlookup->sock = zclient_socket (); +#else +  zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH); +#endif /* HAVE_TCP_ZEBRA */ +  if (zlookup->sock < 0) +    return -1; + +  /* Make BGP import there. */ +  bgp_import_thread =  +    thread_add_timer (master, bgp_import, NULL, 0); + +  return 0; +} + +/* Check specified multiaccess next-hop. */ +int +bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer) +{ +  struct bgp_node *rn1; +  struct bgp_node *rn2; +  struct prefix p1; +  struct prefix p2; +  struct in_addr addr; +  int ret; + +  ret = inet_aton (peer, &addr); +  if (! ret) +    return 0; + +  memset (&p1, 0, sizeof (struct prefix)); +  p1.family = AF_INET; +  p1.prefixlen = IPV4_MAX_BITLEN; +  p1.u.prefix4 = nexthop; +  memset (&p2, 0, sizeof (struct prefix)); +  p2.family = AF_INET; +  p2.prefixlen = IPV4_MAX_BITLEN; +  p2.u.prefix4 = addr; + +  /* If bgp scan is not enabled, return invalid. */ +  if (zlookup->sock < 0) +    return 0; + +  rn1 = bgp_node_match (bgp_connected_ipv4, &p1); +  if (! rn1) +    return 0; +   +  rn2 = bgp_node_match (bgp_connected_ipv4, &p2); +  if (! rn2) +    return 0; + +  if (rn1 == rn2) +    return 1; + +  return 0; +} + +DEFUN (bgp_scan_time, +       bgp_scan_time_cmd, +       "bgp scan-time <5-60>", +       "BGP specific commands\n" +       "Configure background scanner interval\n" +       "Scanner interval (seconds)\n") +{ +  bgp_scan_interval = atoi (argv[0]); + +  if (bgp_scan_thread) +    { +      thread_cancel (bgp_scan_thread); +      bgp_scan_thread =  +	thread_add_timer (master, bgp_scan, NULL, bgp_scan_interval); +    } + +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_scan_time, +       no_bgp_scan_time_cmd, +       "no bgp scan-time", +       NO_STR +       "BGP specific commands\n" +       "Configure background scanner interval\n") +{ +  bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; + +  if (bgp_scan_thread) +    { +      thread_cancel (bgp_scan_thread); +      bgp_scan_thread =  +	thread_add_timer (master, bgp_scan, NULL, bgp_scan_interval); +    } + +  return CMD_SUCCESS; +} + +ALIAS (no_bgp_scan_time, +       no_bgp_scan_time_val_cmd, +       "no bgp scan-time <5-60>", +       NO_STR +       "BGP specific commands\n" +       "Configure background scanner interval\n" +       "Scanner interval (seconds)\n") + +DEFUN (show_ip_bgp_scan, +       show_ip_bgp_scan_cmd, +       "show ip bgp scan", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP scan status\n") +{ +  struct bgp_node *rn; +  struct bgp_nexthop_cache *bnc; + +  if (bgp_scan_thread) +    vty_out (vty, "BGP scan is running%s", VTY_NEWLINE); +  else +    vty_out (vty, "BGP scan is not running%s", VTY_NEWLINE); +  vty_out (vty, "BGP scan interval is %d%s", bgp_scan_interval, VTY_NEWLINE); + +  vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE); +  for (rn = bgp_table_top (bgp_nexthop_cache_ipv4); rn; rn = bgp_route_next (rn)) +    if ((bnc = rn->info) != NULL) +      { +	if (bnc->valid) +	  vty_out (vty, " %s valid [IGP metric %d]%s", +		   inet_ntoa (rn->p.u.prefix4), bnc->metric, VTY_NEWLINE); +	else +	  vty_out (vty, " %s invalid%s", +		   inet_ntoa (rn->p.u.prefix4), VTY_NEWLINE); +      } + +#ifdef HAVE_IPV6 +  { +    char buf[BUFSIZ]; +    for (rn = bgp_table_top (bgp_nexthop_cache_ipv6); rn; rn = bgp_route_next (rn)) +      if ((bnc = rn->info) != NULL) +	{ +	  if (bnc->valid) +	    vty_out (vty, " %s valid [IGP metric %d]%s", +		     inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), +		     bnc->metric, VTY_NEWLINE); +	  else +	    vty_out (vty, " %s invalid%s", +		     inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), +		     VTY_NEWLINE); +	} +  } +#endif /* HAVE_IPV6 */ + +  vty_out (vty, "BGP connected route:%s", VTY_NEWLINE); +  for (rn = bgp_table_top (bgp_connected_ipv4); rn; rn = bgp_route_next (rn)) +    if (rn->info != NULL) +      vty_out (vty, " %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, +	       VTY_NEWLINE); + +#ifdef HAVE_IPV6 +  { +    char buf[BUFSIZ]; + +    for (rn = bgp_table_top (bgp_connected_ipv6); rn; rn = bgp_route_next (rn)) +      if (rn->info != NULL) +	vty_out (vty, " %s/%d%s", +		 inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), +		 rn->p.prefixlen, +		 VTY_NEWLINE); +  } +#endif /* HAVE_IPV6 */ + +  return CMD_SUCCESS; +} + +int +bgp_config_write_scan_time (struct vty *vty) +{ +  if (bgp_scan_interval != BGP_SCAN_INTERVAL_DEFAULT) +    vty_out (vty, " bgp scan-time %d%s", bgp_scan_interval, VTY_NEWLINE); +  return CMD_SUCCESS; +} + +void +bgp_scan_init () +{ +  zlookup = zclient_new (); +  zlookup->sock = -1; +  zlookup->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); +  zlookup->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); +  zlookup->t_connect = thread_add_event (master, zlookup_connect, zlookup, 0); + +  bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; +  bgp_import_interval = BGP_IMPORT_INTERVAL_DEFAULT; + +  cache1 = bgp_table_init (); +  cache2 = bgp_table_init (); +  bgp_nexthop_cache_ipv4 = cache1; + +  bgp_connected_ipv4 = bgp_table_init (); + +#ifdef HAVE_IPV6 +  cache6_1 = bgp_table_init (); +  cache6_2 = bgp_table_init (); +  bgp_nexthop_cache_ipv6 = cache6_1; +  bgp_connected_ipv6 = bgp_table_init (); +#endif /* HAVE_IPV6 */ + +  /* Make BGP scan thread. */ +  bgp_scan_thread = thread_add_timer (master, bgp_scan, NULL, bgp_scan_interval); + +  install_element (BGP_NODE, &bgp_scan_time_cmd); +  install_element (BGP_NODE, &no_bgp_scan_time_cmd); +  install_element (BGP_NODE, &no_bgp_scan_time_val_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_scan_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd); +} diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h new file mode 100644 index 0000000000..5f4255d894 --- /dev/null +++ b/bgpd/bgp_nexthop.h @@ -0,0 +1,52 @@ +/* BGP nexthop scan +   Copyright (C) 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#define BGP_SCAN_INTERVAL_DEFAULT   60 +#define BGP_IMPORT_INTERVAL_DEFAULT 15 + +/* BGP nexthop cache value structure. */ +struct bgp_nexthop_cache +{ +  /* This nexthop exists in IGP. */ +  u_char valid; + +  /* Nexthop is changed. */ +  u_char changed; + +  /* Nexthop is changed. */ +  u_char metricchanged; + +  /* IGP route's metric. */ +  u_int32_t metric; + +  /* Nexthop number and nexthop linked list.*/ +  u_char nexthop_num; +  struct nexthop *nexthop; +}; + +void bgp_scan_init (); +int bgp_nexthop_lookup (afi_t, struct peer *peer, struct bgp_info *, +			int *, int *); +void bgp_connected_add (struct connected *c); +void bgp_connected_delete (struct connected *c); +int bgp_multiaccess_check_v4 (struct in_addr, char *); +int bgp_config_write_scan_time (struct vty *); +int bgp_nexthop_check_ebgp (afi_t, struct attr *); +int bgp_nexthop_self (afi_t, struct attr *); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c new file mode 100644 index 0000000000..a3e86b06c8 --- /dev/null +++ b/bgpd/bgp_open.c @@ -0,0 +1,793 @@ +/* BGP open message handling +   Copyright (C) 1998, 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "linklist.h" +#include "prefix.h" +#include "stream.h" +#include "thread.h" +#include "log.h" +#include "command.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_open.h" + +/* BGP-4 Multiprotocol Extentions lead us to the complex world. We can +   negotiate remote peer supports extentions or not. But if +   remote-peer doesn't supports negotiation process itself.  We would +   like to do manual configuration. + +   So there is many configurable point.  First of all we want set each +   peer whether we send capability negotiation to the peer or not. +   Next, if we send capability to the peer we want to set my capabilty +   inforation at each peer. */ + +void +bgp_capability_vty_out (struct vty *vty, struct peer *peer) +{ +  u_char *pnt; +  u_char *end; +  struct capability cap; + +  pnt = peer->notify.data; +  end = pnt + peer->notify.length; + +  while (pnt < end) +    { +      memcpy(&cap, pnt, sizeof(struct capability)); + +      if (pnt + 2 > end) +	return; +      if (pnt + (cap.length + 2) > end) +	return; + +      if (cap.code == CAPABILITY_CODE_MP) +	{ +	  vty_out (vty, "  Capability error for: Multi protocol "); + +	  switch (ntohs (cap.mpc.afi)) +	    { +	    case AFI_IP: +	      vty_out (vty, "AFI IPv4, "); +	      break; +	    case AFI_IP6: +	      vty_out (vty, "AFI IPv6, "); +	      break; +	    default: +	      vty_out (vty, "AFI Unknown %d, ", ntohs (cap.mpc.afi)); +	      break; +	    } +	  switch (cap.mpc.safi) +	    { +	    case SAFI_UNICAST: +	      vty_out (vty, "SAFI Unicast"); +	      break; +	    case SAFI_MULTICAST: +	      vty_out (vty, "SAFI Multicast"); +	      break; +	    case SAFI_UNICAST_MULTICAST: +	      vty_out (vty, "SAFI Unicast Multicast"); +	      break; +	    case BGP_SAFI_VPNV4: +	      vty_out (vty, "SAFI MPLS-VPN"); +	      break; +	    default: +	      vty_out (vty, "SAFI Unknown %d ", cap.mpc.safi); +	      break; +	    } +	  vty_out (vty, "%s", VTY_NEWLINE); +	} +      else if (cap.code >= 128) +	vty_out (vty, "  Capability error: vendor specific capability code %d", +		 cap.code); +      else +	vty_out (vty, "  Capability error: unknown capability code %d",  +		 cap.code); + +      pnt += cap.length + 2; +    } +} + +/* Set negotiated capability value. */ +int +bgp_capability_mp (struct peer *peer, struct capability *cap) +{ +  if (ntohs (cap->mpc.afi) == AFI_IP) +    { +      if (cap->mpc.safi == SAFI_UNICAST) +	{ +	  peer->afc_recv[AFI_IP][SAFI_UNICAST] = 1; + +	  if (peer->afc[AFI_IP][SAFI_UNICAST]) +	    peer->afc_nego[AFI_IP][SAFI_UNICAST] = 1; +	  else +	    return -1; +	} +      else if (cap->mpc.safi == SAFI_MULTICAST)  +	{ +	  peer->afc_recv[AFI_IP][SAFI_MULTICAST] = 1; + +	  if (peer->afc[AFI_IP][SAFI_MULTICAST]) +	    peer->afc_nego[AFI_IP][SAFI_MULTICAST] = 1; +	  else +	    return -1; +	} +      else if (cap->mpc.safi == BGP_SAFI_VPNV4) +	{ +	  peer->afc_recv[AFI_IP][SAFI_MPLS_VPN] = 1; + +	  if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) +	    peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] = 1; +	  else +	    return -1; +	} +      else +	return -1; +    } +#ifdef HAVE_IPV6 +  else if (ntohs (cap->mpc.afi) == AFI_IP6) +    { +      if (cap->mpc.safi == SAFI_UNICAST) +	{ +	  peer->afc_recv[AFI_IP6][SAFI_UNICAST] = 1; + +	  if (peer->afc[AFI_IP6][SAFI_UNICAST]) +	    peer->afc_nego[AFI_IP6][SAFI_UNICAST] = 1; +	  else +	    return -1; +	} +      else if (cap->mpc.safi == SAFI_MULTICAST) +	{ +	  peer->afc_recv[AFI_IP6][SAFI_MULTICAST] = 1; + +	  if (peer->afc[AFI_IP6][SAFI_MULTICAST]) +	    peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = 1; +	  else +	    return -1; +	} +      else +	return -1; +    } +#endif /* HAVE_IPV6 */ +  else +    { +      /* Unknown Address Family. */ +      return -1; +    } + +  return 0; +} + +void +bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi, +				u_char type, u_char mode) +{ +  if (BGP_DEBUG (normal, NORMAL)) +    zlog_info ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported", +	       peer->host, afi, safi, type, mode); +} + +int +bgp_capability_orf (struct peer *peer, struct capability *cap, +		    u_char *pnt) +{ +  afi_t afi = ntohs(cap->mpc.afi); +  safi_t safi = cap->mpc.safi; +  u_char number_of_orfs; +  u_char type; +  u_char mode; +  u_int16_t sm_cap = 0; /* capability send-mode receive */ +  u_int16_t rm_cap = 0; /* capability receive-mode receive */  +  int i; + +  /* Check length. */ +  if (cap->length < 7) +    { +      zlog_info ("%s ORF Capability length error %d", +		 peer->host, cap->length); +		 bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +      return -1; +    } + +  if (BGP_DEBUG (normal, NORMAL)) +    zlog_info ("%s OPEN has ORF CAP(%s) for afi/safi: %u/%u", +	       peer->host, (cap->code == CAPABILITY_CODE_ORF ? +                       "new" : "old"), afi, safi); + +  /* Check AFI and SAFI. */ +  if ((afi != AFI_IP && afi != AFI_IP6) +      || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST +	  && safi != BGP_SAFI_VPNV4)) +    { +      zlog_info ("%s Addr-family %d/%d not supported. Ignoring the ORF capability", +                 peer->host, afi, safi); +      return -1; +    } + +  number_of_orfs = *pnt++; + +  for (i = 0 ; i < number_of_orfs ; i++) +    { +      type = *pnt++; +      mode = *pnt++; + +      /* ORF Mode error check */ +      if (mode != ORF_MODE_BOTH && mode != ORF_MODE_SEND +	  && mode != ORF_MODE_RECEIVE) +	{ +	  bgp_capability_orf_not_support (peer, afi, safi, type, mode); +	  continue; +	} + +      /* ORF Type and afi/safi error check */ +      if (cap->code == CAPABILITY_CODE_ORF) +	{ +	  if (type == ORF_TYPE_PREFIX && +	      ((afi == AFI_IP && safi == SAFI_UNICAST) +		|| (afi == AFI_IP && safi == SAFI_MULTICAST) +		|| (afi == AFI_IP6 && safi == SAFI_UNICAST))) +	    { +	      sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV; +	      rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV; +	      if (BGP_DEBUG (normal, NORMAL)) +		zlog_info ("%s OPEN has Prefixlist ORF(%d) capability as %s for afi/safi: %d/%d", +			   peer->host, ORF_TYPE_PREFIX, (mode == ORF_MODE_SEND ? "SEND" : +			   mode == ORF_MODE_RECEIVE ? "RECEIVE" : "BOTH") , afi, safi); +	    } +	  else +	    { +	      bgp_capability_orf_not_support (peer, afi, safi, type, mode); +	      continue; +	    } +	} +      else if (cap->code == CAPABILITY_CODE_ORF_OLD) +	{ +	  if (type == ORF_TYPE_PREFIX_OLD && +	      ((afi == AFI_IP && safi == SAFI_UNICAST) +		|| (afi == AFI_IP && safi == SAFI_MULTICAST) +		|| (afi == AFI_IP6 && safi == SAFI_UNICAST))) +	    { +	      sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV; +	      rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV; +	      if (BGP_DEBUG (normal, NORMAL)) +		zlog_info ("%s OPEN has Prefixlist ORF(%d) capability as %s for afi/safi: %d/%d", +			   peer->host, ORF_TYPE_PREFIX_OLD, (mode == ORF_MODE_SEND ? "SEND" : +			   mode == ORF_MODE_RECEIVE ? "RECEIVE" : "BOTH") , afi, safi); +	    } +	  else +	    { +	      bgp_capability_orf_not_support (peer, afi, safi, type, mode); +	      continue; +	    } +	} +      else +	{ +	  bgp_capability_orf_not_support (peer, afi, safi, type, mode); +	  continue; +	} + +      switch (mode) +	{ +	  case ORF_MODE_BOTH: +	    SET_FLAG (peer->af_cap[afi][safi], sm_cap); +	    SET_FLAG (peer->af_cap[afi][safi], rm_cap); +	    break; +	  case ORF_MODE_SEND: +	    SET_FLAG (peer->af_cap[afi][safi], sm_cap); +	    break; +	  case ORF_MODE_RECEIVE: +	    SET_FLAG (peer->af_cap[afi][safi], rm_cap); +	    break; +	} +    } +  return 0; +} + +/* Parse given capability. */ +int +bgp_capability_parse (struct peer *peer, u_char *pnt, u_char length, +		      u_char **error) +{ +  int ret; +  u_char *end; +  struct capability cap; + +  end = pnt + length; + +  while (pnt < end) +    { +      afi_t afi; +      safi_t safi; + +      /* Fetch structure to the byte stream. */ +      memcpy (&cap, pnt, sizeof (struct capability)); + +      afi = ntohs(cap.mpc.afi); +      safi = cap.mpc.safi; + +      if (BGP_DEBUG (normal, NORMAL)) +	zlog_info ("%s OPEN has CAPABILITY code: %d, length %d", +		   peer->host, cap.code, cap.length); + +      /* We need at least capability code and capability length. */ +      if (pnt + 2 > end) +	{ +	  zlog_info ("%s Capability length error", peer->host); +	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +	  return -1; +	} + +      /* Capability length check. */ +      if (pnt + (cap.length + 2) > end) +	{ +	  zlog_info ("%s Capability length error", peer->host); +	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +	  return -1; +	} + +      /* We know MP Capability Code. */ +      if (cap.code == CAPABILITY_CODE_MP) +	{ +	  if (BGP_DEBUG (normal, NORMAL)) +	    zlog_info ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u", +		       peer->host, afi, safi); + +	  /* Ignore capability when override-capability is set. */ +	  if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) +	    { +	      /* Set negotiated value. */ +	      ret = bgp_capability_mp (peer, &cap); + +	      /* Unsupported Capability. */ +	      if (ret < 0) +		{ +		  /* Store return data. */ +		  memcpy (*error, &cap, cap.length + 2); +		  *error += cap.length + 2; +		} +	    } +	} +      else if (cap.code == CAPABILITY_CODE_REFRESH +	       || cap.code == CAPABILITY_CODE_REFRESH_OLD) +	{ +	  /* Check length. */ +	  if (cap.length != 0) +	    { +	      zlog_info ("%s Route Refresh Capability length error %d", +			 peer->host, cap.length); +	      bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +	      return -1; +	    } + +	  if (BGP_DEBUG (normal, NORMAL)) +	    zlog_info ("%s OPEN has ROUTE-REFRESH capability(%s) for all address-families", +		       peer->host, +		       cap.code == CAPABILITY_CODE_REFRESH_OLD ? "old" : "new"); + +	  /* BGP refresh capability */ +	  if (cap.code == CAPABILITY_CODE_REFRESH_OLD) +	    SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); +	  else +	    SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); +	} +      else if (cap.code == CAPABILITY_CODE_ORF +	       || cap.code == CAPABILITY_CODE_ORF_OLD) +	bgp_capability_orf (peer, &cap, pnt + sizeof (struct capability)); +      else if (cap.code == CAPABILITY_CODE_DYNAMIC) +	{ +	  /* Check length. */ +	  if (cap.length != 0) +	    { +	      zlog_info ("%s Dynamic Capability length error %d", +			 peer->host, cap.length); +	      bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +	      return -1; +	    } + +	  if (BGP_DEBUG (normal, NORMAL)) +	    zlog_info ("%s OPEN has DYNAMIC capability", peer->host); + +	  SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV); +	} +  +      else if (cap.code > 128) +	{ +	  /* We don't send Notification for unknown vendor specific +	     capabilities.  It seems reasonable for now...  */ +	  zlog_warn ("%s Vendor specific capability %d", +		     peer->host, cap.code); +	} +      else +	{ +	  zlog_warn ("%s unrecognized capability code: %d - ignored", +		     peer->host, cap.code); +	  memcpy (*error, &cap, cap.length + 2); +	  *error += cap.length + 2; +	} + +      pnt += cap.length + 2; +    } +  return 0; +} + +int +bgp_auth_parse (struct peer *peer, u_char *pnt, size_t length) +{ +  bgp_notify_send (peer,  +		   BGP_NOTIFY_OPEN_ERR,  +		   BGP_NOTIFY_OPEN_AUTH_FAILURE);  +  return -1; +} + +int +strict_capability_same (struct peer *peer) +{ +  int i, j; + +  for (i = AFI_IP; i < AFI_MAX; i++) +    for (j = SAFI_UNICAST; j < SAFI_MAX; j++) +      if (peer->afc[i][j] != peer->afc_nego[i][j]) +	return 0; +  return 1; +} + +/* Parse open option */ +int +bgp_open_option_parse (struct peer *peer, u_char length, int *capability) +{ +  int ret; +  u_char *end; +  u_char opt_type; +  u_char opt_length; +  u_char *pnt; +  u_char *error; +  u_char error_data[BGP_MAX_PACKET_SIZE]; + +  /* Fetch pointer. */ +  pnt = stream_pnt (peer->ibuf); + +  ret = 0; +  opt_type = 0; +  opt_length = 0; +  end = pnt + length; +  error = error_data; + +  if (BGP_DEBUG (normal, NORMAL)) +    zlog_info ("%s rcv OPEN w/ OPTION parameter len: %u", +	       peer->host, length); +   +  while (pnt < end)  +    { +      /* Check the length. */ +      if (pnt + 2 > end) +	{ +	  zlog_info ("%s Option length error", peer->host); +	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +	  return -1; +	} + +      /* Fetch option type and length. */ +      opt_type = *pnt++; +      opt_length = *pnt++; +       +      /* Option length check. */ +      if (pnt + opt_length > end) +	{ +	  zlog_info ("%s Option length error", peer->host); +	  bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +	  return -1; +	} + +      if (BGP_DEBUG (normal, NORMAL)) +	zlog_info ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u", +		   peer->host, opt_type, +		   opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" : +		   opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown", +		   opt_length); +   +      switch (opt_type) +	{ +	case BGP_OPEN_OPT_AUTH: +	  ret = bgp_auth_parse (peer, pnt, opt_length); +	  break; +	case BGP_OPEN_OPT_CAP: +	  ret = bgp_capability_parse (peer, pnt, opt_length, &error); +	  *capability = 1; +	  break; +	default: +	  bgp_notify_send (peer,  +			   BGP_NOTIFY_OPEN_ERR,  +			   BGP_NOTIFY_OPEN_UNSUP_PARAM);  +	  ret = -1; +	  break; +	} + +      /* Parse error.  To accumulate all unsupported capability codes, +         bgp_capability_parse does not return -1 when encounter +         unsupported capability code.  To detect that, please check +         error and erro_data pointer, like below.  */ +      if (ret < 0) +	return -1; + +      /* Forward pointer. */ +      pnt += opt_length; +    } + +  /* All OPEN option is parsed.  Check capability when strict compare +     flag is enabled.*/ +  if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) +    { +      /* If Unsupported Capability exists. */ +      if (error != error_data) +	{ +	  bgp_notify_send_with_data (peer,  +				     BGP_NOTIFY_OPEN_ERR,  +				     BGP_NOTIFY_OPEN_UNSUP_CAPBL,  +				     error_data, error - error_data); +	  return -1; +	} + +      /* Check local capability does not negotiated with remote +         peer. */ +      if (! strict_capability_same (peer)) +	{ +	  bgp_notify_send (peer,  +			   BGP_NOTIFY_OPEN_ERR,  +			   BGP_NOTIFY_OPEN_UNSUP_CAPBL); +	  return -1; +	} +    } + +  /* Check there is no common capability send Unsupported Capability +     error. */ +  if (*capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) +    { +      if (! peer->afc_nego[AFI_IP][SAFI_UNICAST]  +	  && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST] +	  && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] +	  && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] +	  && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) +	{ +	  plog_err (peer->log, "%s [Error] No common capability", peer->host); + +	  if (error != error_data) + +	    bgp_notify_send_with_data (peer,  +				       BGP_NOTIFY_OPEN_ERR,  +				       BGP_NOTIFY_OPEN_UNSUP_CAPBL,  +				       error_data, error - error_data); +	  else +	    bgp_notify_send (peer,  +			     BGP_NOTIFY_OPEN_ERR,  +			     BGP_NOTIFY_OPEN_UNSUP_CAPBL); +	  return -1; +	} +    } +  return 0; +} + +void +bgp_open_capability_orf (struct stream *s, struct peer *peer, +                         afi_t afi, safi_t safi, u_char code) +{ +  u_char cap_len; +  u_char orf_len; +  unsigned long capp; +  unsigned long orfp; +  unsigned long numberp; +  int number_of_orfs = 0; + +  if (safi == SAFI_MPLS_VPN) +    safi = BGP_SAFI_VPNV4; + +  stream_putc (s, BGP_OPEN_OPT_CAP); +  capp = stream_get_putp (s);           /* Set Capability Len Pointer */ +  stream_putc (s, 0);                   /* Capability Length */ +  stream_putc (s, code);                /* Capability Code */ +  orfp = stream_get_putp (s);           /* Set ORF Len Pointer */ +  stream_putc (s, 0);                   /* ORF Length */ +  stream_putw (s, afi); +  stream_putc (s, 0); +  stream_putc (s, safi); +  numberp = stream_get_putp (s);        /* Set Number Pointer */ +  stream_putc (s, 0);                   /* Number of ORFs */ + +  /* Address Prefix ORF */ +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) +      || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) +    { +      stream_putc (s, (code == CAPABILITY_CODE_ORF ? +		   ORF_TYPE_PREFIX : ORF_TYPE_PREFIX_OLD)); + +      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) +	  && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) +	{ +	  SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV); +	  SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV); +	  stream_putc (s, ORF_MODE_BOTH); +	} +      else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)) +	{ +	  SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV); +	  stream_putc (s, ORF_MODE_SEND); +	} +      else +	{ +	  SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV); +	  stream_putc (s, ORF_MODE_RECEIVE); +	} +      number_of_orfs++; +    } + +  /* Total Number of ORFs. */ +  stream_putc_at (s, numberp, number_of_orfs); + +  /* Total ORF Len. */ +  orf_len = stream_get_putp (s) - orfp - 1; +  stream_putc_at (s, orfp, orf_len); + +  /* Total Capability Len. */ +  cap_len = stream_get_putp (s) - capp - 1; +  stream_putc_at (s, capp, cap_len); +} + +/* Fill in capability open option to the packet. */ +void +bgp_open_capability (struct stream *s, struct peer *peer) +{ +  u_char len; +  unsigned long cp; +  afi_t afi; +  safi_t safi; + +  /* Remember current pointer for Opt Parm Len. */ +  cp = stream_get_putp (s); + +  /* Opt Parm Len. */ +  stream_putc (s, 0); + +  /* Do not send capability. */ +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN)  +      || CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY)) +    return; + +  /* When the peer is IPv4 unicast only, do not send capability. */ +  if (! peer->afc[AFI_IP][SAFI_MULTICAST]  +      && ! peer->afc[AFI_IP][SAFI_MPLS_VPN] +      && ! peer->afc[AFI_IP6][SAFI_UNICAST]  +      && ! peer->afc[AFI_IP6][SAFI_MULTICAST] +      && CHECK_FLAG (peer->flags, PEER_FLAG_NO_ROUTE_REFRESH_CAP) +      && ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], +		       PEER_FLAG_ORF_PREFIX_SM) +      && ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], +		       PEER_FLAG_ORF_PREFIX_RM) +      && ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST], +		       PEER_FLAG_ORF_PREFIX_SM) +      && ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST], +		       PEER_FLAG_ORF_PREFIX_RM) +      && ! CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) +    return; + +  /* IPv4 unicast. */ +  if (peer->afc[AFI_IP][SAFI_UNICAST]) +    { +      peer->afc_adv[AFI_IP][SAFI_UNICAST] = 1; +      stream_putc (s, BGP_OPEN_OPT_CAP); +      stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); +      stream_putc (s, CAPABILITY_CODE_MP); +      stream_putc (s, CAPABILITY_CODE_MP_LEN); +      stream_putw (s, AFI_IP); +      stream_putc (s, 0); +      stream_putc (s, SAFI_UNICAST); +    } +  /* IPv4 multicast. */ +  if (peer->afc[AFI_IP][SAFI_MULTICAST]) +    { +      peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 1; +      stream_putc (s, BGP_OPEN_OPT_CAP); +      stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); +      stream_putc (s, CAPABILITY_CODE_MP); +      stream_putc (s, CAPABILITY_CODE_MP_LEN); +      stream_putw (s, AFI_IP); +      stream_putc (s, 0); +      stream_putc (s, SAFI_MULTICAST); +    } +  /* IPv4 VPN */ +  if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) +    { +      peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 1; +      stream_putc (s, BGP_OPEN_OPT_CAP); +      stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); +      stream_putc (s, CAPABILITY_CODE_MP); +      stream_putc (s, CAPABILITY_CODE_MP_LEN); +      stream_putw (s, AFI_IP); +      stream_putc (s, 0); +      stream_putc (s, BGP_SAFI_VPNV4); +    } +#ifdef HAVE_IPV6 +  /* IPv6 unicast. */ +  if (peer->afc[AFI_IP6][SAFI_UNICAST]) +    { +      peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 1; +      stream_putc (s, BGP_OPEN_OPT_CAP); +      stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); +      stream_putc (s, CAPABILITY_CODE_MP); +      stream_putc (s, CAPABILITY_CODE_MP_LEN); +      stream_putw (s, AFI_IP6); +      stream_putc (s, 0); +      stream_putc (s, SAFI_UNICAST); +    } +  /* IPv6 multicast. */ +  if (peer->afc[AFI_IP6][SAFI_MULTICAST]) +    { +      peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 1; +      stream_putc (s, BGP_OPEN_OPT_CAP); +      stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); +      stream_putc (s, CAPABILITY_CODE_MP); +      stream_putc (s, CAPABILITY_CODE_MP_LEN); +      stream_putw (s, AFI_IP6); +      stream_putc (s, 0); +      stream_putc (s, SAFI_MULTICAST); +    } +#endif /* HAVE_IPV6 */ + +  /* Route refresh. */ +  if (! CHECK_FLAG (peer->flags, PEER_FLAG_NO_ROUTE_REFRESH_CAP)) +    { +      SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV); +      stream_putc (s, BGP_OPEN_OPT_CAP); +      stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2); +      stream_putc (s, CAPABILITY_CODE_REFRESH_OLD); +      stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); +      stream_putc (s, BGP_OPEN_OPT_CAP); +      stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2); +      stream_putc (s, CAPABILITY_CODE_REFRESH); +      stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); +    } + +  /* ORF capability. */ +  for (afi = AFI_IP ; afi < AFI_MAX ; afi++) +    for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) +      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) +	  || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) +	{ +	  bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF_OLD); +	  bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF); +	} + +  /* Dynamic capability. */ +  if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) +    { +      SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV); +      stream_putc (s, BGP_OPEN_OPT_CAP); +      stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN + 2); +      stream_putc (s, CAPABILITY_CODE_DYNAMIC); +      stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN); +    } + +  /* Total Opt Parm Len. */ +  len = stream_get_putp (s) - cp - 1; +  stream_putc_at (s, cp, len); +} diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h new file mode 100644 index 0000000000..af7505a8f6 --- /dev/null +++ b/bgpd/bgp_open.h @@ -0,0 +1,69 @@ +/* BGP open message handling +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +/* MP Capability information. */ +struct capability_mp +{ +  u_int16_t afi; +  u_char reserved; +  u_char safi; +}; + +/* BGP open message capability. */ +struct capability +{ +  u_char code; +  u_char length; +  struct capability_mp mpc; +}; + +/* Multiprotocol Extensions capabilities. */ +#define CAPABILITY_CODE_MP              1 +#define CAPABILITY_CODE_MP_LEN          4 + +/* Route refresh capabilities. */ +#define CAPABILITY_CODE_REFRESH         2 +#define CAPABILITY_CODE_REFRESH_OLD   128 +#define CAPABILITY_CODE_REFRESH_LEN     0 + +/* Cooperative Route Filtering Capability.  */ +#define CAPABILITY_CODE_ORF             3  +#define CAPABILITY_CODE_ORF_OLD       130 + +/* ORF Type.  */ +#define ORF_TYPE_PREFIX                64  +#define ORF_TYPE_PREFIX_OLD           128 + +/* ORF Mode.  */ +#define ORF_MODE_RECEIVE                1  +#define ORF_MODE_SEND                   2  +#define ORF_MODE_BOTH                   3  + +/* Dynamic capability.  */ +#define CAPABILITY_CODE_DYNAMIC        66 +#define CAPABILITY_CODE_DYNAMIC_LEN     0 + +/* Capability Message Action.  */ +#define CAPABILITY_ACTION_SET           0 +#define CAPABILITY_ACTION_UNSET         1 + +int bgp_open_option_parse (struct peer *, u_char, int *); +void bgp_open_capability (struct stream *, struct peer *); +void bgp_capability_vty_out (struct vty *, struct peer *); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c new file mode 100644 index 0000000000..48879f35a5 --- /dev/null +++ b/bgpd/bgp_packet.c @@ -0,0 +1,2240 @@ +/* BGP packet management routine. +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "thread.h" +#include "stream.h" +#include "network.h" +#include "prefix.h" +#include "command.h" +#include "log.h" +#include "memory.h" +#include "sockunion.h"		/* for inet_ntop () */ +#include "linklist.h" +#include "plist.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_dump.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_open.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_network.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_advertise.h" + +int stream_put_prefix (struct stream *, struct prefix *); + +/* Set up BGP packet marker and packet type. */ +static int +bgp_packet_set_marker (struct stream *s, u_char type) +{ +  int i; + +  /* Fill in marker. */ +  for (i = 0; i < BGP_MARKER_SIZE; i++) +    stream_putc (s, 0xff); + +  /* Dummy total length. This field is should be filled in later on. */ +  stream_putw (s, 0); + +  /* BGP packet type. */ +  stream_putc (s, type); + +  /* Return current stream size. */ +  return stream_get_putp (s); +} + +/* Set BGP packet header size entry.  If size is zero then use current +   stream size. */ +static int +bgp_packet_set_size (struct stream *s) +{ +  int cp; + +  /* Preserve current pointer. */ +  cp = stream_get_putp (s); +  stream_set_putp (s, BGP_MARKER_SIZE); +  stream_putw (s, cp); + +  /* Write back current pointer. */ +  stream_set_putp (s, cp); + +  return cp; +} + +/* Add new packet to the peer. */ +void +bgp_packet_add (struct peer *peer, struct stream *s) +{ +  /* Add packet to the end of list. */ +  stream_fifo_push (peer->obuf, s); +} + +/* Free first packet. */ +void +bgp_packet_delete (struct peer *peer) +{ +  stream_free (stream_fifo_pop (peer->obuf)); +} + +/* Duplicate packet. */ +struct stream * +bgp_packet_dup (struct stream *s) +{ +  struct stream *new; + +  new = stream_new (stream_get_endp (s)); + +  new->endp = s->endp; +  new->putp = s->putp; +  new->getp = s->getp; + +  memcpy (new->data, s->data, stream_get_endp (s)); + +  return new; +} + +/* Check file descriptor whether connect is established. */ +static void +bgp_connect_check (struct peer *peer) +{ +  int status; +  int slen; +  int ret; + +  /* Anyway I have to reset read and write thread. */ +  BGP_READ_OFF (peer->t_read); +  BGP_WRITE_OFF (peer->t_write); + +  /* Check file descriptor. */ +  slen = sizeof (status); +  ret = getsockopt(peer->fd, SOL_SOCKET, SO_ERROR, (void *) &status, &slen); + +  /* If getsockopt is fail, this is fatal error. */ +  if (ret < 0) +    { +      zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect"); +      BGP_EVENT_ADD (peer, TCP_fatal_error); +      return; +    }       + +  /* When status is 0 then TCP connection is established. */ +  if (status == 0) +    { +      BGP_EVENT_ADD (peer, TCP_connection_open); +    } +  else +    { +      if (BGP_DEBUG (events, EVENTS)) +	  plog_info (peer->log, "%s [Event] Connect failed (%s)", +		     peer->host, strerror (errno)); +      BGP_EVENT_ADD (peer, TCP_connection_open_failed); +    } +} + +/* Make BGP update packet.  */ +struct stream * +bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) +{ +  struct stream *s; +  struct bgp_adj_out *adj; +  struct bgp_advertise *adv; +  struct stream *packet; +  struct bgp_node *rn = NULL; +  struct bgp_info *binfo = NULL; +  bgp_size_t total_attr_len = 0; +  unsigned long pos; +  char buf[BUFSIZ]; +  struct prefix_rd *prd = NULL; +  char *tag = NULL; + +  s = peer->work; +  stream_reset (s); + +  adv = FIFO_HEAD (&peer->sync[afi][safi]->update); + +  while (adv) +    { +      if (adv->rn) +        rn = adv->rn; +      adj = adv->adj; +      if (adv->binfo) +        binfo = adv->binfo; +#ifdef MPLS_VPN +      if (rn) +        prd = (struct prefix_rd *) &rn->prn->p; +      if (binfo) +        tag = binfo->tag; +#endif /* MPLS_VPN */ + +      /* When remaining space can't include NLRI and it's length.  */ +      if (rn && STREAM_REMAIN (s) <= BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen)) +	break; + +      /* If packet is empty, set attribute. */ +      if (stream_empty (s)) +	{ +	  bgp_packet_set_marker (s, BGP_MSG_UPDATE); +	  stream_putw (s, 0);		 +	  pos = stream_get_putp (s); +	  stream_putw (s, 0); +	  total_attr_len = bgp_packet_attribute (NULL, peer, s, +	                			 adv->baa->attr, +						 &rn->p, afi, safi, +						 binfo->peer, prd, tag); +	  stream_putw_at (s, pos, total_attr_len); +	} + +      if (afi == AFI_IP && safi == SAFI_UNICAST) +	stream_put_prefix (s, &rn->p); +       +      if (BGP_DEBUG (update, UPDATE_OUT)) +	zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d", +	      peer->host, +	      inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ), +	      rn->p.prefixlen); + +      /* Synchnorize attribute.  */ +      if (adj->attr) +	bgp_attr_unintern (adj->attr); +      else +	peer->scount[afi][safi]++; + +      adj->attr = bgp_attr_intern (adv->baa->attr); + +      adv = bgp_advertise_clean (peer, adj, afi, safi); + +      if (! (afi == AFI_IP && safi == SAFI_UNICAST)) +	break; +    } +	  +  if (! stream_empty (s)) +    { +      bgp_packet_set_size (s); +      packet = bgp_packet_dup (s); +      bgp_packet_add (peer, packet); +      BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +      stream_reset (s); +      return packet; +    } +  return NULL; + +} + +/* Make BGP withdraw packet.  */ +struct stream * +bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) +{ +  struct stream *s; +  struct stream *packet; +  struct bgp_adj_out *adj; +  struct bgp_advertise *adv; +  struct bgp_node *rn; +  unsigned long pos; +  bgp_size_t unfeasible_len; +  bgp_size_t total_attr_len; +  char buf[BUFSIZ]; +  struct prefix_rd *prd = NULL; + +  s = peer->work; +  stream_reset (s); + +  while ((adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL) +    { +      adj = adv->adj; +      rn = adv->rn; +#ifdef MPLS_VPN +      prd = (struct prefix_rd *) &rn->prn->p; +#endif /* MPLS_VPN */ + +      if (STREAM_REMAIN (s)  +	  <= (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen))) +	break; + +      if (stream_empty (s)) +	{ +	  bgp_packet_set_marker (s, BGP_MSG_UPDATE); +	  stream_putw (s, 0); +	} + +      if (afi == AFI_IP && safi == SAFI_UNICAST) +	stream_put_prefix (s, &rn->p); +      else +	{ +	  pos = stream_get_putp (s); +	  stream_putw (s, 0); +	  total_attr_len +	    = bgp_packet_withdraw (peer, s, &rn->p, afi, safi, prd, NULL); +       +	  /* Set total path attribute length. */ +	  stream_putw_at (s, pos, total_attr_len); +	} + +      if (BGP_DEBUG (update, UPDATE_OUT)) +	zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d -- unreachable", +	      peer->host, +	      inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ), +	      rn->p.prefixlen); + +      peer->scount[afi][safi]--; + +      bgp_adj_out_remove (rn, adj, peer, afi, safi); +      bgp_unlock_node (rn); + +      if (! (afi == AFI_IP && safi == SAFI_UNICAST)) +	break; +    } + +  if (! stream_empty (s)) +    { +      if (afi == AFI_IP && safi == SAFI_UNICAST) +	{ +	  unfeasible_len  +	    = stream_get_putp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN; +	  stream_putw_at (s, BGP_HEADER_SIZE, unfeasible_len); +	  stream_putw (s, 0); +	} +      bgp_packet_set_size (s); +      packet = bgp_packet_dup (s); +      bgp_packet_add (peer, packet); +      stream_reset (s); +      return packet; +    } + +  return NULL; +} + +void +bgp_default_update_send (struct peer *peer, struct attr *attr, +			 afi_t afi, safi_t safi, struct peer *from) +{ +  struct stream *s; +  struct stream *packet; +  struct prefix p; +  unsigned long pos; +  bgp_size_t total_attr_len; +  char attrstr[BUFSIZ]; +  char buf[BUFSIZ]; + +#ifdef DISABLE_BGP_ANNOUNCE +  return; +#endif /* DISABLE_BGP_ANNOUNCE */ + +  if (afi == AFI_IP) +    str2prefix ("0.0.0.0/0", &p); +#ifdef HAVE_IPV6 +  else  +    str2prefix ("::/0", &p); +#endif /* HAVE_IPV6 */ + +  /* Logging the attribute. */ +  if (BGP_DEBUG (update, UPDATE_OUT)) +    { +      bgp_dump_attr (peer, attr, attrstr, BUFSIZ); +      zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d %s", +	    peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ), +	    p.prefixlen, attrstr); +    } + +  s = stream_new (BGP_MAX_PACKET_SIZE); + +  /* Make BGP update packet. */ +  bgp_packet_set_marker (s, BGP_MSG_UPDATE); + +  /* Unfeasible Routes Length. */ +  stream_putw (s, 0); + +  /* Make place for total attribute length.  */ +  pos = stream_get_putp (s); +  stream_putw (s, 0); +  total_attr_len = bgp_packet_attribute (NULL, peer, s, attr, &p, afi, safi, from, NULL, NULL); + +  /* Set Total Path Attribute Length. */ +  stream_putw_at (s, pos, total_attr_len); + +  /* NLRI set. */ +  if (p.family == AF_INET && safi == SAFI_UNICAST) +    stream_put_prefix (s, &p); + +  /* Set size. */ +  bgp_packet_set_size (s); + +  packet = bgp_packet_dup (s); +  stream_free (s); + +  /* Dump packet if debug option is set. */ +#ifdef DEBUG +  bgp_packet_dump (packet); +#endif /* DEBUG */ + +  /* Add packet to the peer. */ +  bgp_packet_add (peer, packet); + +  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +} + +void +bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) +{ +  struct stream *s; +  struct stream *packet; +  struct prefix p; +  unsigned long pos; +  unsigned long cp; +  bgp_size_t unfeasible_len; +  bgp_size_t total_attr_len; +  char buf[BUFSIZ]; + +#ifdef DISABLE_BGP_ANNOUNCE +  return; +#endif /* DISABLE_BGP_ANNOUNCE */ + +  if (afi == AFI_IP) +    str2prefix ("0.0.0.0/0", &p); +#ifdef HAVE_IPV6 +  else  +    str2prefix ("::/0", &p); +#endif /* HAVE_IPV6 */ + +  total_attr_len = 0; +  pos = 0; + +  if (BGP_DEBUG (update, UPDATE_OUT)) +    zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d -- unreachable", +          peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ), +          p.prefixlen); + +  s = stream_new (BGP_MAX_PACKET_SIZE); + +  /* Make BGP update packet. */ +  bgp_packet_set_marker (s, BGP_MSG_UPDATE); + +  /* Unfeasible Routes Length. */; +  cp = stream_get_putp (s); +  stream_putw (s, 0); + +  /* Withdrawn Routes. */ +  if (p.family == AF_INET && safi == SAFI_UNICAST) +    { +      stream_put_prefix (s, &p); + +      unfeasible_len = stream_get_putp (s) - cp - 2; + +      /* Set unfeasible len.  */ +      stream_putw_at (s, cp, unfeasible_len); + +      /* Set total path attribute length. */ +      stream_putw (s, 0); +    } +  else +    { +      pos = stream_get_putp (s); +      stream_putw (s, 0); +      total_attr_len = bgp_packet_withdraw (peer, s, &p, afi, safi, NULL, NULL); + +      /* Set total path attribute length. */ +      stream_putw_at (s, pos, total_attr_len); +    } + +  bgp_packet_set_size (s); + +  packet = bgp_packet_dup (s); +  stream_free (s); + +  /* Add packet to the peer. */ +  bgp_packet_add (peer, packet); + +  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +} + +/* Get next packet to be written.  */ +struct stream * +bgp_write_packet (struct peer *peer) +{ +  afi_t afi; +  safi_t safi; +  struct stream *s = NULL; +  struct bgp_advertise *adv; + +  s = stream_fifo_head (peer->obuf); +  if (s) +    return s; + +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      { +	adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw); +	if (adv) +	  { +	    s = bgp_withdraw_packet (peer, afi, safi); +	    if (s) +	      return s; +	  } +      } +     +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      { +	adv = FIFO_HEAD (&peer->sync[afi][safi]->update); +	if (adv) +	  { +            if (adv->binfo && adv->binfo->uptime < peer->synctime) +              s = bgp_update_packet (peer, afi, safi); + +	    if (s) +	      return s; +	  } +      } + +  return NULL; +} + +/* Is there partially written packet or updates we can send right +   now.  */ +int +bgp_write_proceed (struct peer *peer) +{ +  afi_t afi; +  safi_t safi; +  struct bgp_advertise *adv; + +  if (stream_fifo_head (peer->obuf)) +    return 1; + +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      if (FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) +	return 1; + +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      if ((adv = FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL) +	if (adv->binfo->uptime < peer->synctime) +	  return 1; + +  return 0; +} + +/* Write packet to the peer. */ +int +bgp_write (struct thread *thread) +{ +  struct peer *peer; +  u_char type; +  struct stream *s;  +  int num; +  int count = 0; +  int write_errno; + +  /* Yes first of all get peer pointer. */ +  peer = THREAD_ARG (thread); +  peer->t_write = NULL; + +  /* For non-blocking IO check. */ +  if (peer->status == Connect) +    { +      bgp_connect_check (peer); +      return 0; +    } + +    /* Nonblocking write until TCP output buffer is full.  */ +  while (1) +    { +      int writenum; + +      s = bgp_write_packet (peer); +      if (! s) +	return 0; + +      /* Number of bytes to be sent.  */ +      writenum = stream_get_endp (s) - stream_get_getp (s); + +      /* Call write() system call.  */ +      num = write (peer->fd, STREAM_PNT (s), writenum); +      write_errno = errno; +      if (num <= 0) +	{ +	  /* Partial write. */ +	  if (write_errno == EWOULDBLOCK || write_errno == EAGAIN) +	      break; + +	  bgp_stop (peer); +	  peer->status = Idle; +	  bgp_timer_set (peer); +	  return 0; +	} +      if (num != writenum) +	{ +	  stream_forward (s, num); + +	  if (write_errno == EAGAIN) +	    break; + +	  continue; +	} + +      /* Retrieve BGP packet type. */ +      stream_set_getp (s, BGP_MARKER_SIZE + 2); +      type = stream_getc (s); + +      switch (type) +	{ +	case BGP_MSG_OPEN: +	  peer->open_out++; +	  break; +	case BGP_MSG_UPDATE: +	  peer->update_out++; +	  break; +	case BGP_MSG_NOTIFY: +	  peer->notify_out++; +	  /* Double start timer. */ +	  peer->v_start *= 2; + +	  /* Overflow check. */ +	  if (peer->v_start >= (60 * 2)) +	    peer->v_start = (60 * 2); + +	  /* BGP_EVENT_ADD (peer, BGP_Stop); */ +	  bgp_stop (peer); +	  peer->status = Idle; +	  bgp_timer_set (peer); +	  return 0; +	  break; +	case BGP_MSG_KEEPALIVE: +	  peer->keepalive_out++; +	  break; +	case BGP_MSG_ROUTE_REFRESH_NEW: +	case BGP_MSG_ROUTE_REFRESH_OLD: +	  peer->refresh_out++; +	  break; +	case BGP_MSG_CAPABILITY: +	  peer->dynamic_cap_out++; +	  break; +	} + +      /* OK we send packet so delete it. */ +      bgp_packet_delete (peer); + +      if (++count >= BGP_WRITE_PACKET_MAX) +	break; +    } +   +  if (bgp_write_proceed (peer)) +    BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +   +  return 0; +} + +/* This is only for sending NOTIFICATION message to neighbor. */ +int +bgp_write_notify (struct peer *peer) +{ +  int ret; +  u_char type; +  struct stream *s;  + +  /* There should be at least one packet. */ +  s = stream_fifo_head (peer->obuf); +  if (!s) +    return 0; +  assert (stream_get_endp (s) >= BGP_HEADER_SIZE); + +  /* I'm not sure fd is writable. */ +  ret = writen (peer->fd, STREAM_DATA (s), stream_get_endp (s)); +  if (ret <= 0) +    { +      bgp_stop (peer); +      peer->status = Idle; +      bgp_timer_set (peer); +      return 0; +    } + +  /* Retrieve BGP packet type. */ +  stream_set_getp (s, BGP_MARKER_SIZE + 2); +  type = stream_getc (s); + +  assert (type == BGP_MSG_NOTIFY); + +  /* Type should be notify. */ +  peer->notify_out++; + +  /* Double start timer. */ +  peer->v_start *= 2; + +  /* Overflow check. */ +  if (peer->v_start >= (60 * 2)) +    peer->v_start = (60 * 2); + +  /* We don't call event manager at here for avoiding other events. */ +  bgp_stop (peer); +  peer->status = Idle; +  bgp_timer_set (peer); + +  return 0; +} + +/* Make keepalive packet and send it to the peer. */ +void +bgp_keepalive_send (struct peer *peer) +{ +  struct stream *s; +  int length; + +  s = stream_new (BGP_MAX_PACKET_SIZE); + +  /* Make keepalive packet. */ +  bgp_packet_set_marker (s, BGP_MSG_KEEPALIVE); + +  /* Set packet size. */ +  length = bgp_packet_set_size (s); + +  /* Dump packet if debug option is set. */ +  /* bgp_packet_dump (s); */ +  +  if (BGP_DEBUG (keepalive, KEEPALIVE))   +    zlog_info ("%s sending KEEPALIVE", peer->host);  +  if (BGP_DEBUG (normal, NORMAL)) +    zlog_info ("%s send message type %d, length (incl. header) %d", +               peer->host, BGP_MSG_KEEPALIVE, length); + +  /* Add packet to the peer. */ +  bgp_packet_add (peer, s); + +  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +} + +/* Make open packet and send it to the peer. */ +void +bgp_open_send (struct peer *peer) +{ +  struct stream *s; +  int length; +  u_int16_t send_holdtime; +  as_t local_as; + +  if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) +    send_holdtime = peer->holdtime; +  else +    send_holdtime = peer->bgp->default_holdtime; + +  /* local-as Change */ +  if (peer->change_local_as) +    local_as = peer->change_local_as;  +  else +    local_as = peer->local_as;  + +  s = stream_new (BGP_MAX_PACKET_SIZE); + +  /* Make open packet. */ +  bgp_packet_set_marker (s, BGP_MSG_OPEN); + +  /* Set open packet values. */ +  stream_putc (s, BGP_VERSION_4);        /* BGP version */ +  stream_putw (s, local_as);		 /* My Autonomous System*/ +  stream_putw (s, send_holdtime);     	 /* Hold Time */ +  stream_put_in_addr (s, &peer->local_id); /* BGP Identifier */ + +  /* Set capability code. */ +  bgp_open_capability (s, peer); + +  /* Set BGP packet length. */ +  length = bgp_packet_set_size (s); + +  if (BGP_DEBUG (normal, NORMAL)) +    zlog_info ("%s sending OPEN, version %d, my as %d, holdtime %d, id %s",  +	       peer->host, BGP_VERSION_4, local_as, +	       send_holdtime, inet_ntoa (peer->local_id)); + +  if (BGP_DEBUG (normal, NORMAL)) +    zlog_info ("%s send message type %d, length (incl. header) %d", +	       peer->host, BGP_MSG_OPEN, length); + +  /* Dump packet if debug option is set. */ +  /* bgp_packet_dump (s); */ + +  /* Add packet to the peer. */ +  bgp_packet_add (peer, s); + +  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +} + +/* Send BGP notify packet with data potion. */ +void +bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code, +			   u_char *data, size_t datalen) +{ +  struct stream *s; +  int length; + +  /* Allocate new stream. */ +  s = stream_new (BGP_MAX_PACKET_SIZE); + +  /* Make nitify packet. */ +  bgp_packet_set_marker (s, BGP_MSG_NOTIFY); + +  /* Set notify packet values. */ +  stream_putc (s, code);        /* BGP notify code */ +  stream_putc (s, sub_code);	/* BGP notify sub_code */ + +  /* If notify data is present. */ +  if (data) +    stream_write (s, data, datalen); +   +  /* Set BGP packet length. */ +  length = bgp_packet_set_size (s); +   +  /* Add packet to the peer. */ +  stream_fifo_clean (peer->obuf); +  bgp_packet_add (peer, s); + +  /* For debug */ +  { +    struct bgp_notify bgp_notify; +    int first = 0; +    int i; +    char c[4]; + +    bgp_notify.code = code; +    bgp_notify.subcode = sub_code; +    bgp_notify.data = NULL; +    bgp_notify.length = length - BGP_MSG_NOTIFY_MIN_SIZE; +     +    if (bgp_notify.length) +      { +	bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3); +	for (i = 0; i < bgp_notify.length; i++) +	  if (first) +	    { +	      sprintf (c, " %02x", data[i]); +	      strcat (bgp_notify.data, c); +	    } +	  else +	    { +	      first = 1; +	      sprintf (c, "%02x", data[i]); +	      strcpy (bgp_notify.data, c); +	    } +      } +    bgp_notify_print (peer, &bgp_notify, "sending"); +    if (bgp_notify.data) +      XFREE (MTYPE_TMP, bgp_notify.data); +  } + +  if (BGP_DEBUG (normal, NORMAL)) +    zlog_info ("%s send message type %d, length (incl. header) %d", +	       peer->host, BGP_MSG_NOTIFY, length); + +  /* Call imidiately. */ +  BGP_WRITE_OFF (peer->t_write); + +  bgp_write_notify (peer); +} + +/* Send BGP notify packet. */ +void +bgp_notify_send (struct peer *peer, u_char code, u_char sub_code) +{ +  bgp_notify_send_with_data (peer, code, sub_code, NULL, 0); +} + +char * +afi2str (afi_t afi) +{ +  if (afi == AFI_IP) +    return "AFI_IP"; +  else if (afi == AFI_IP6) +    return "AFI_IP6"; +  else +    return "Unknown AFI"; +} + +char * +safi2str (safi_t safi) +{ +  if (safi == SAFI_UNICAST) +    return "SAFI_UNICAST"; +  else if (safi == SAFI_MULTICAST) +    return "SAFI_MULTICAST"; +  else if (safi == SAFI_MPLS_VPN || safi == BGP_SAFI_VPNV4) +    return "SAFI_MPLS_VPN"; +  else +    return "Unknown SAFI"; +} + +/* Send route refresh message to the peer. */ +void +bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, +			u_char orf_type, u_char when_to_refresh, int remove) +{ +  struct stream *s; +  struct stream *packet; +  int length; +  struct bgp_filter *filter; +  int orf_refresh = 0; + +#ifdef DISABLE_BGP_ANNOUNCE +  return; +#endif /* DISABLE_BGP_ANNOUNCE */ + +  filter = &peer->filter[afi][safi]; + +  /* Adjust safi code. */ +  if (safi == SAFI_MPLS_VPN) +    safi = BGP_SAFI_VPNV4; +   +  s = stream_new (BGP_MAX_PACKET_SIZE); + +  /* Make BGP update packet. */ +  if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) +    bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_NEW); +  else +    bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_OLD); + +  /* Encode Route Refresh message. */ +  stream_putw (s, afi); +  stream_putc (s, 0); +  stream_putc (s, safi); +  +  if (orf_type == ORF_TYPE_PREFIX +      || orf_type == ORF_TYPE_PREFIX_OLD) +    if (remove || filter->plist[FILTER_IN].plist) +      { +	u_int16_t orf_len; +	unsigned long orfp; + +	orf_refresh = 1;  +	stream_putc (s, when_to_refresh); +	stream_putc (s, orf_type); +	orfp = stream_get_putp (s); +	stream_putw (s, 0); + +	if (remove) +	  { +	    UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); +	    stream_putc (s, ORF_COMMON_PART_REMOVE_ALL); +	    if (BGP_DEBUG (normal, NORMAL)) +	      zlog_info ("%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d",  +			 peer->host, orf_type, +			 (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"), +			 afi, safi); +	  } +	else +	  { +	    SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); +	    prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].plist, +				  ORF_COMMON_PART_ADD, ORF_COMMON_PART_PERMIT, +				  ORF_COMMON_PART_DENY); +	    if (BGP_DEBUG (normal, NORMAL)) +	      zlog_info ("%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d",  +			 peer->host, orf_type, +			 (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"), +			 afi, safi); +	  } + +	/* Total ORF Entry Len. */ +	orf_len = stream_get_putp (s) - orfp - 2; +	stream_putw_at (s, orfp, orf_len); +      } + +  /* Set packet size. */ +  length = bgp_packet_set_size (s); + +  if (BGP_DEBUG (normal, NORMAL)) +    { +      if (! orf_refresh) +	zlog_info ("%s sending REFRESH_REQ for afi/safi: %d/%d",  +		   peer->host, afi, safi); +      zlog_info ("%s send message type %d, length (incl. header) %d", +		 peer->host, CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV) ? +		 BGP_MSG_ROUTE_REFRESH_NEW : BGP_MSG_ROUTE_REFRESH_OLD, length); +    } + +  /* Make real packet. */ +  packet = bgp_packet_dup (s); +  stream_free (s); + +  /* Add packet to the peer. */ +  bgp_packet_add (peer, packet); + +  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +} + +/* Send capability message to the peer. */ +void +bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, +		     int capability_code, int action) +{ +  struct stream *s; +  struct stream *packet; +  int length; + +  /* Adjust safi code. */ +  if (safi == SAFI_MPLS_VPN) +    safi = BGP_SAFI_VPNV4; + +  s = stream_new (BGP_MAX_PACKET_SIZE); + +  /* Make BGP update packet. */ +  bgp_packet_set_marker (s, BGP_MSG_CAPABILITY); + +  /* Encode MP_EXT capability. */ +  if (capability_code == CAPABILITY_CODE_MP) +    { +      stream_putc (s, action); +      stream_putc (s, CAPABILITY_CODE_MP); +      stream_putc (s, CAPABILITY_CODE_MP_LEN); +      stream_putw (s, afi); +      stream_putc (s, 0); +      stream_putc (s, safi); + +      if (BGP_DEBUG (normal, NORMAL)) +        zlog_info ("%s sending CAPABILITY has %s MP_EXT CAP for afi/safi: %d/%d", +		   peer->host, action == CAPABILITY_ACTION_SET ? +		   "Advertising" : "Removing", afi, safi); +    } + +  /* Encode Route Refresh capability. */ +  if (capability_code == CAPABILITY_CODE_REFRESH) +    { +      stream_putc (s, action); +      stream_putc (s, CAPABILITY_CODE_REFRESH); +      stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); +      stream_putc (s, action); +      stream_putc (s, CAPABILITY_CODE_REFRESH_OLD); +      stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); + +      if (BGP_DEBUG (normal, NORMAL)) +        zlog_info ("%s sending CAPABILITY has %s ROUTE-REFRESH capability", +		   peer->host, action == CAPABILITY_ACTION_SET ? +		   "Advertising" : "Removing"); +    } + +  /* Set packet size. */ +  length = bgp_packet_set_size (s); + +  /* Make real packet. */ +  packet = bgp_packet_dup (s); +  stream_free (s); + +  /* Add packet to the peer. */ +  bgp_packet_add (peer, packet); + +  if (BGP_DEBUG (normal, NORMAL)) +    zlog_info ("%s send message type %d, length (incl. header) %d", +	       peer->host, BGP_MSG_CAPABILITY, length); + +  BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); +} + +/* RFC1771 6.8 Connection collision detection. */ +int +bgp_collision_detect (struct peer *new, struct in_addr remote_id) +{ +  struct peer *peer; +  struct listnode *nn; +  struct bgp *bgp; + +  bgp = bgp_get_default (); +  if (! bgp) +    return 0; +   +  /* Upon receipt of an OPEN message, the local system must examine +     all of its connections that are in the OpenConfirm state.  A BGP +     speaker may also examine connections in an OpenSent state if it +     knows the BGP Identifier of the peer by means outside of the +     protocol.  If among these connections there is a connection to a +     remote BGP speaker whose BGP Identifier equals the one in the +     OPEN message, then the local system performs the following +     collision resolution procedure: */ + +  LIST_LOOP (bgp->peer, peer, nn) +    { +      /* Under OpenConfirm status, local peer structure already hold +         remote router ID. */ + +      if (peer != new +	  && (peer->status == OpenConfirm || peer->status == OpenSent) +	  && sockunion_same (&peer->su, &new->su)) +	{ +	  /* 1. The BGP Identifier of the local system is compared to +	     the BGP Identifier of the remote system (as specified in +	     the OPEN message). */ + +	  if (ntohl (peer->local_id.s_addr) < ntohl (remote_id.s_addr)) +	    { +	      /* 2. If the value of the local BGP Identifier is less +		 than the remote one, the local system closes BGP +		 connection that already exists (the one that is +		 already in the OpenConfirm state), and accepts BGP +		 connection initiated by the remote system. */ + +	      if (peer->fd >= 0) +		bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +	      return 1; +	    } +	  else +	    { +	      /* 3. Otherwise, the local system closes newly created +		 BGP connection (the one associated with the newly +		 received OPEN message), and continues to use the +		 existing one (the one that is already in the +		 OpenConfirm state). */ + +	      if (new->fd >= 0) +		bgp_notify_send (new, BGP_NOTIFY_CEASE, 0); +	      return -1; +	    } +	} +    } +  return 0; +} + +int +bgp_open_receive (struct peer *peer, bgp_size_t size) +{ +  int ret; +  u_char version; +  u_char optlen; +  u_int16_t holdtime; +  u_int16_t send_holdtime; +  as_t remote_as; +  struct peer *realpeer; +  struct in_addr remote_id; +  int capability; +  char notify_data_remote_as[2]; +  char notify_data_remote_id[4]; + +  realpeer = NULL; +   +  /* Parse open packet. */ +  version = stream_getc (peer->ibuf); +  memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2); +  remote_as  = stream_getw (peer->ibuf); +  holdtime = stream_getw (peer->ibuf); +  memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4); +  remote_id.s_addr = stream_get_ipv4 (peer->ibuf); + +  /* Receive OPEN message log  */ +  if (BGP_DEBUG (normal, NORMAL)) +    zlog_info ("%s rcv OPEN, version %d, remote-as %d, holdtime %d, id %s", +	       peer->host, version, remote_as, holdtime, +	       inet_ntoa (remote_id)); +	   +  /* Lookup peer from Open packet. */ +  if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) +    { +      int as = 0; + +      realpeer = peer_lookup_with_open (&peer->su, remote_as, &remote_id, &as); + +      if (! realpeer) +	{ +	  /* Peer's source IP address is check in bgp_accept(), so this +	     must be AS number mismatch or remote-id configuration +	     mismatch. */ +	  if (as) +	    { +	      if (BGP_DEBUG (normal, NORMAL)) +		zlog_info ("%s bad OPEN, wrong router identifier %s", +			   peer->host, inet_ntoa (remote_id)); +	      bgp_notify_send_with_data (peer,  +					 BGP_NOTIFY_OPEN_ERR,  +					 BGP_NOTIFY_OPEN_BAD_BGP_IDENT, +					 notify_data_remote_id, 4); +	    } +	  else +	    { +	      if (BGP_DEBUG (normal, NORMAL)) +		zlog_info ("%s bad OPEN, remote AS is %d, expected %d", +			   peer->host, remote_as, peer->as); +	      bgp_notify_send_with_data (peer,  +					 BGP_NOTIFY_OPEN_ERR,  +					 BGP_NOTIFY_OPEN_BAD_PEER_AS, +					 notify_data_remote_as, 2); +	    } +	  return -1; +	} +    } + +  /* When collision is detected and this peer is closed.  Retrun +     immidiately. */ +  ret = bgp_collision_detect (peer, remote_id); +  if (ret < 0) +    return ret; + +  /* Hack part. */ +  if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) +    { +      if (ret == 0 && realpeer->status != Active +	  && realpeer->status != OpenSent +	  && realpeer->status != OpenConfirm) + 	{ + 	  if (BGP_DEBUG (events, EVENTS)) + 	    zlog_info ("%s [Event] peer's status is %s close connection", +		       realpeer->host, LOOKUP (bgp_status_msg, peer->status)); + 	  return -1; + 	} + +      if (BGP_DEBUG (events, EVENTS)) +	zlog_info ("%s [Event] Transfer temporary BGP peer to existing one", +		   peer->host); + +      bgp_stop (realpeer); +       +      /* Transfer file descriptor. */ +      realpeer->fd = peer->fd; +      peer->fd = -1; + +      /* Transfer input buffer. */ +      stream_free (realpeer->ibuf); +      realpeer->ibuf = peer->ibuf; +      realpeer->packet_size = peer->packet_size; +      peer->ibuf = NULL; + +      /* Transfer status. */ +      realpeer->status = peer->status; +      bgp_stop (peer); + +      /* peer pointer change. Open packet send to neighbor. */ +      peer = realpeer; +      bgp_open_send (peer); +      if (peer->fd < 0) +	{ +	  zlog_err ("bgp_open_receive peer's fd is negative value %d", +		    peer->fd); +	  return -1; +	} +      BGP_READ_ON (peer->t_read, bgp_read, peer->fd); +    } + +  /* remote router-id check. */ +  if (remote_id.s_addr == 0 +      || ntohl (remote_id.s_addr) >= 0xe0000000 +      || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr)) +    { +      if (BGP_DEBUG (normal, NORMAL)) +	zlog_info ("%s bad OPEN, wrong router identifier %s", +		   peer->host, inet_ntoa (remote_id)); +      bgp_notify_send_with_data (peer,  +				 BGP_NOTIFY_OPEN_ERR,  +				 BGP_NOTIFY_OPEN_BAD_BGP_IDENT, +				 notify_data_remote_id, 4); +      return -1; +    } + +  /* Set remote router-id */ +  peer->remote_id = remote_id; + +  /* Peer BGP version check. */ +  if (version != BGP_VERSION_4) +    { +      if (BGP_DEBUG (normal, NORMAL)) +	zlog_info ("%s bad protocol version, remote requested %d, local request %d", +		   peer->host, version, BGP_VERSION_4); +      bgp_notify_send_with_data (peer,  +				 BGP_NOTIFY_OPEN_ERR,  +				 BGP_NOTIFY_OPEN_UNSUP_VERSION, +				 "\x04", 1); +      return -1; +    } + +  /* Check neighbor as number. */ +  if (remote_as != peer->as) +    { +      if (BGP_DEBUG (normal, NORMAL)) +	zlog_info ("%s bad OPEN, remote AS is %d, expected %d", +		   peer->host, remote_as, peer->as); +      bgp_notify_send_with_data (peer,  +				 BGP_NOTIFY_OPEN_ERR,  +				 BGP_NOTIFY_OPEN_BAD_PEER_AS, +				 notify_data_remote_as, 2); +      return -1; +    } + +  /* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST +     calculate the value of the Hold Timer by using the smaller of its +     configured Hold Time and the Hold Time received in the OPEN message. +     The Hold Time MUST be either zero or at least three seconds.  An +     implementation may reject connections on the basis of the Hold Time. */ + +  if (holdtime < 3 && holdtime != 0) +    { +      bgp_notify_send (peer, +		       BGP_NOTIFY_OPEN_ERR,  +		       BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); +      return -1; +    } +     +  /* From the rfc: A reasonable maximum time between KEEPALIVE messages +     would be one third of the Hold Time interval.  KEEPALIVE messages +     MUST NOT be sent more frequently than one per second.  An +     implementation MAY adjust the rate at which it sends KEEPALIVE +     messages as a function of the Hold Time interval. */ + +  if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) +    send_holdtime = peer->holdtime; +  else +    send_holdtime = peer->bgp->default_holdtime; + +  if (holdtime < send_holdtime) +    peer->v_holdtime = holdtime; +  else +    peer->v_holdtime = send_holdtime; + +  peer->v_keepalive = peer->v_holdtime / 3; + +  /* Open option part parse. */ +  capability = 0; +  optlen = stream_getc (peer->ibuf); +  if (optlen != 0)  +    { +      ret = bgp_open_option_parse (peer, optlen, &capability); +      if (ret < 0) +	return ret; + +      stream_forward (peer->ibuf, optlen); +    } +  else +    { +      if (BGP_DEBUG (normal, NORMAL)) +	zlog_info ("%s rcvd OPEN w/ OPTION parameter len: 0", +		   peer->host); +    } + +  /* Override capability. */ +  if (! capability || CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) +    { +      peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST]; +      peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST]; +      peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; +      peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST]; +    } + +  /* Get sockname. */ +  bgp_getsockname (peer); + +  BGP_EVENT_ADD (peer, Receive_OPEN_message); + +  peer->packet_size = 0; +  if (peer->ibuf) +    stream_reset (peer->ibuf); + +  return 0; +} + +/* Parse BGP Update packet and make attribute object. */ +int +bgp_update_receive (struct peer *peer, bgp_size_t size) +{ +  int ret; +  u_char *end; +  struct stream *s; +  struct attr attr; +  bgp_size_t attribute_len; +  bgp_size_t update_len; +  bgp_size_t withdraw_len; +  struct bgp_nlri update; +  struct bgp_nlri withdraw; +  struct bgp_nlri mp_update; +  struct bgp_nlri mp_withdraw; +  char attrstr[BUFSIZ]; + +  /* Status must be Established. */ +  if (peer->status != Established)  +    { +      zlog_err ("%s [FSM] Update packet received under status %s", +		peer->host, LOOKUP (bgp_status_msg, peer->status)); +      bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); +      return -1; +    } + +  /* Set initial values. */ +  memset (&attr, 0, sizeof (struct attr)); +  memset (&update, 0, sizeof (struct bgp_nlri)); +  memset (&withdraw, 0, sizeof (struct bgp_nlri)); +  memset (&mp_update, 0, sizeof (struct bgp_nlri)); +  memset (&mp_withdraw, 0, sizeof (struct bgp_nlri)); + +  s = peer->ibuf; +  end = stream_pnt (s) + size; + +  /* RFC1771 6.3 If the Unfeasible Routes Length or Total Attribute +     Length is too large (i.e., if Unfeasible Routes Length + Total +     Attribute Length + 23 exceeds the message Length), then the Error +     Subcode is set to Malformed Attribute List.  */ +  if (stream_pnt (s) + 2 > end) +    { +      zlog_err ("%s [Error] Update packet error" +		" (packet length is short for unfeasible length)", +		peer->host); +      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,  +		       BGP_NOTIFY_UPDATE_MAL_ATTR); +      return -1; +    } + +  /* Unfeasible Route Length. */ +  withdraw_len = stream_getw (s); + +  /* Unfeasible Route Length check. */ +  if (stream_pnt (s) + withdraw_len > end) +    { +      zlog_err ("%s [Error] Update packet error" +		" (packet unfeasible length overflow %d)", +		peer->host, withdraw_len); +      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,  +		       BGP_NOTIFY_UPDATE_MAL_ATTR); +      return -1; +    } + +  /* Unfeasible Route packet format check. */ +  if (withdraw_len > 0) +    { +      ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), withdraw_len); +      if (ret < 0) +	return -1; + +      if (BGP_DEBUG (packet, PACKET_RECV)) +	  zlog_info ("%s [Update:RECV] Unfeasible NLRI received", peer->host); + +      withdraw.afi = AFI_IP; +      withdraw.safi = SAFI_UNICAST; +      withdraw.nlri = stream_pnt (s); +      withdraw.length = withdraw_len; +      stream_forward (s, withdraw_len); +    } +   +  /* Attribute total length check. */ +  if (stream_pnt (s) + 2 > end) +    { +      zlog_warn ("%s [Error] Packet Error" +		 " (update packet is short for attribute length)", +		 peer->host); +      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,  +		       BGP_NOTIFY_UPDATE_MAL_ATTR); +      return -1; +    } + +  /* Fetch attribute total length. */ +  attribute_len = stream_getw (s); + +  /* Attribute length check. */ +  if (stream_pnt (s) + attribute_len > end) +    { +      zlog_warn ("%s [Error] Packet Error" +		 " (update packet attribute length overflow %d)", +		 peer->host, attribute_len); +      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,  +		       BGP_NOTIFY_UPDATE_MAL_ATTR); +      return -1; +    } + +  /* Parse attribute when it exists. */ +  if (attribute_len) +    { +      ret = bgp_attr_parse (peer, &attr, attribute_len,  +			    &mp_update, &mp_withdraw); +      if (ret < 0) +	return -1; +    } + +  /* Logging the attribute. */ +  if (BGP_DEBUG (update, UPDATE_IN)) +    { +      bgp_dump_attr (peer, &attr, attrstr, BUFSIZ); +      zlog (peer->log, LOG_INFO, "%s rcvd UPDATE w/ attr: %s", +	    peer->host, attrstr); +    } + +  /* Network Layer Reachability Information. */ +  update_len = end - stream_pnt (s); + +  if (update_len) +    { +      /* Check NLRI packet format and prefix length. */ +      ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len); +      if (ret < 0) +	return -1; + +      /* Set NLRI portion to structure. */ +      update.afi = AFI_IP; +      update.safi = SAFI_UNICAST; +      update.nlri = stream_pnt (s); +      update.length = update_len; +      stream_forward (s, update_len); +    } + +  /* NLRI is processed only when the peer is configured specific +     Address Family and Subsequent Address Family. */ +  if (peer->afc[AFI_IP][SAFI_UNICAST]) +    { +      if (withdraw.length) +	bgp_nlri_parse (peer, NULL, &withdraw); + +      if (update.length) +	{ +	  /* We check well-known attribute only for IPv4 unicast +	     update. */ +	  ret = bgp_attr_check (peer, &attr); +	  if (ret < 0) +	    return -1; + +	  bgp_nlri_parse (peer, &attr, &update); +	} +    } +  if (peer->afc[AFI_IP][SAFI_MULTICAST]) +    { +      if (mp_update.length +	  && mp_update.afi == AFI_IP  +	  && mp_update.safi == SAFI_MULTICAST) +	bgp_nlri_parse (peer, &attr, &mp_update); + +      if (mp_withdraw.length +	  && mp_withdraw.afi == AFI_IP  +	  && mp_withdraw.safi == SAFI_MULTICAST) +	bgp_nlri_parse (peer, NULL, &mp_withdraw); +    } +  if (peer->afc[AFI_IP6][SAFI_UNICAST]) +    { +      if (mp_update.length  +	  && mp_update.afi == AFI_IP6  +	  && mp_update.safi == SAFI_UNICAST) +	bgp_nlri_parse (peer, &attr, &mp_update); + +      if (mp_withdraw.length  +	  && mp_withdraw.afi == AFI_IP6  +	  && mp_withdraw.safi == SAFI_UNICAST) +	bgp_nlri_parse (peer, NULL, &mp_withdraw); +    } +  if (peer->afc[AFI_IP6][SAFI_MULTICAST]) +    { +      if (mp_update.length  +	  && mp_update.afi == AFI_IP6  +	  && mp_update.safi == SAFI_MULTICAST) +	bgp_nlri_parse (peer, &attr, &mp_update); + +      if (mp_withdraw.length  +	  && mp_withdraw.afi == AFI_IP6  +	  && mp_withdraw.safi == SAFI_MULTICAST) +	bgp_nlri_parse (peer, NULL, &mp_withdraw); +    } +  if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) +    { +      if (mp_update.length  +	  && mp_update.afi == AFI_IP  +	  && mp_update.safi == BGP_SAFI_VPNV4) +	bgp_nlri_parse_vpnv4 (peer, &attr, &mp_update); + +      if (mp_withdraw.length  +	  && mp_withdraw.afi == AFI_IP  +	  && mp_withdraw.safi == BGP_SAFI_VPNV4) +	bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw); +    } + +  /* Everything is done.  We unintern temporary structures which +     interned in bgp_attr_parse(). */ +  if (attr.aspath) +    aspath_unintern (attr.aspath); +  if (attr.community) +    community_unintern (attr.community); +  if (attr.ecommunity) +    ecommunity_unintern (attr.ecommunity); +  if (attr.cluster) +    cluster_unintern (attr.cluster); +  if (attr.transit) +    transit_unintern (attr.transit); + +  /* If peering is stopped due to some reason, do not generate BGP +     event.  */ +  if (peer->status != Established) +    return 0; + +  /* Increment packet counter. */ +  peer->update_in++; +  peer->update_time = time (NULL); + +  /* Generate BGP event. */ +  BGP_EVENT_ADD (peer, Receive_UPDATE_message); + +  return 0; +} + +/* Notify message treatment function. */ +void +bgp_notify_receive (struct peer *peer, bgp_size_t size) +{ +  struct bgp_notify bgp_notify; + +  if (peer->notify.data) +    { +      XFREE (MTYPE_TMP, peer->notify.data); +      peer->notify.data = NULL; +      peer->notify.length = 0; +    } + +  bgp_notify.code = stream_getc (peer->ibuf); +  bgp_notify.subcode = stream_getc (peer->ibuf); +  bgp_notify.length = size - 2; +  bgp_notify.data = NULL; + +  /* Preserv notify code and sub code. */ +  peer->notify.code = bgp_notify.code; +  peer->notify.subcode = bgp_notify.subcode; +  /* For further diagnostic record returned Data. */ +  if (bgp_notify.length) +    { +      peer->notify.length = size - 2; +      peer->notify.data = XMALLOC (MTYPE_TMP, size - 2); +      memcpy (peer->notify.data, stream_pnt (peer->ibuf), size - 2); +    } + +  /* For debug */ +  { +    int i; +    int first = 0; +    char c[4]; + +    if (bgp_notify.length) +      { +	bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3); +	for (i = 0; i < bgp_notify.length; i++) +	  if (first) +	    { +	      sprintf (c, " %02x", stream_getc (peer->ibuf)); +	      strcat (bgp_notify.data, c); +	    } +	  else +	    { +	      first = 1; +	      sprintf (c, "%02x", stream_getc (peer->ibuf)); +	      strcpy (bgp_notify.data, c); +	    } +      } + +    bgp_notify_print(peer, &bgp_notify, "received"); +    if (bgp_notify.data) +      XFREE (MTYPE_TMP, bgp_notify.data); +  } + +  /* peer count update */ +  peer->notify_in++; + +  /* We have to check for Notify with Unsupported Optional Parameter. +     in that case we fallback to open without the capability option. +     But this done in bgp_stop. We just mark it here to avoid changing +     the fsm tables.  */ +  if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR && +      bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM ) +    UNSET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + +  /* Also apply to Unsupported Capability until remote router support +     capability. */ +  if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR && +      bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_CAPBL) +    UNSET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + +  BGP_EVENT_ADD (peer, Receive_NOTIFICATION_message); +} + +/* Keepalive treatment function -- get keepalive send keepalive */ +void +bgp_keepalive_receive (struct peer *peer, bgp_size_t size) +{ +  if (BGP_DEBUG (keepalive, KEEPALIVE))   +    zlog_info ("%s KEEPALIVE rcvd", peer->host);  +   +  BGP_EVENT_ADD (peer, Receive_KEEPALIVE_message); +} + +/* Route refresh message is received. */ +void +bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) +{ +  afi_t afi; +  safi_t safi; +  u_char reserved; +  struct stream *s; + +  /* If peer does not have the capability, send notification. */ +  if (! CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_ADV)) +    { +      plog_err (peer->log, "%s [Error] BGP route refresh is not enabled", +		peer->host); +      bgp_notify_send (peer, +		       BGP_NOTIFY_HEADER_ERR, +		       BGP_NOTIFY_HEADER_BAD_MESTYPE); +      return; +    } + +  /* Status must be Established. */ +  if (peer->status != Established)  +    { +      plog_err (peer->log, +		"%s [Error] Route refresh packet received under status %s", +		peer->host, LOOKUP (bgp_status_msg, peer->status)); +      bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); +      return; +    } + +  s = peer->ibuf; +   +  /* Parse packet. */ +  afi = stream_getw (s); +  reserved = stream_getc (s); +  safi = stream_getc (s); + +  if (BGP_DEBUG (normal, NORMAL)) +    zlog_info ("%s rcvd REFRESH_REQ for afi/safi: %d/%d", +	       peer->host, afi, safi); + +  /* Check AFI and SAFI. */ +  if ((afi != AFI_IP && afi != AFI_IP6) +      || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST +	  && safi != BGP_SAFI_VPNV4)) +    { +      if (BGP_DEBUG (normal, NORMAL)) +	{ +	  zlog_info ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored", +		     peer->host, afi, safi); +	} +      return; +    } + +  /* Adjust safi code. */ +  if (safi == BGP_SAFI_VPNV4) +    safi = SAFI_MPLS_VPN; + +  if (size != BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) +    { +      u_char *end; +      u_char when_to_refresh; +      u_char orf_type; +      u_int16_t orf_len; + +      if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) < 5) +        { +          zlog_info ("%s ORF route refresh length error", peer->host); +          bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +          return; +        } + +      when_to_refresh = stream_getc (s); +      end = stream_pnt (s) + (size - 5); + +      while (stream_pnt (s) < end) +	{ +	  orf_type = stream_getc (s);  +	  orf_len = stream_getw (s); + +	  if (orf_type == ORF_TYPE_PREFIX +	      || orf_type == ORF_TYPE_PREFIX_OLD) +	    { +	      u_char *p_pnt = stream_pnt (s); +	      u_char *p_end = stream_pnt (s) + orf_len; +	      struct orf_prefix orfp; +	      u_char common = 0; +	      u_int32_t seq; +	      int psize; +	      char name[BUFSIZ]; +	      char buf[BUFSIZ]; +	      int ret; + +	      if (BGP_DEBUG (normal, NORMAL)) +		{ +		  zlog_info ("%s rcvd Prefixlist ORF(%d) length %d", +			     peer->host, orf_type, orf_len); +		} + +	      /* ORF prefix-list name */ +	      sprintf (name, "%s.%d.%d", peer->host, afi, safi); + +	      while (p_pnt < p_end) +		{ +		  memset (&orfp, 0, sizeof (struct orf_prefix)); +		  common = *p_pnt++; +		  if (common & ORF_COMMON_PART_REMOVE_ALL) +		    { +		      if (BGP_DEBUG (normal, NORMAL)) +			zlog_info ("%s rcvd Remove-All pfxlist ORF request", peer->host); +		      prefix_bgp_orf_remove_all (name); +		      break; +		    } +		  memcpy (&seq, p_pnt, sizeof (u_int32_t)); +		  p_pnt += sizeof (u_int32_t); +		  orfp.seq = ntohl (seq); +		  orfp.ge = *p_pnt++; +		  orfp.le = *p_pnt++; +		  orfp.p.prefixlen = *p_pnt++; +		  orfp.p.family = afi2family (afi); +		  psize = PSIZE (orfp.p.prefixlen); +		  memcpy (&orfp.p.u.prefix, p_pnt, psize); +		  p_pnt += psize; + +		  if (BGP_DEBUG (normal, NORMAL)) +		    zlog_info ("%s rcvd %s %s seq %u %s/%d ge %d le %d", +			       peer->host, +			       (common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"),  +			       (common & ORF_COMMON_PART_DENY ? "deny" : "permit"), +			       orfp.seq,  +			       inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, BUFSIZ), +			       orfp.p.prefixlen, orfp.ge, orfp.le); + +		  ret = prefix_bgp_orf_set (name, afi, &orfp, +				 (common & ORF_COMMON_PART_DENY ? 0 : 1 ), +				 (common & ORF_COMMON_PART_REMOVE ? 0 : 1)); + +		  if (ret != CMD_SUCCESS) +		    { +		      if (BGP_DEBUG (normal, NORMAL)) +			zlog_info ("%s Received misformatted prefixlist ORF. Remove All pfxlist", peer->host); +		      prefix_bgp_orf_remove_all (name); +		      break; +		    } +		} +	      peer->orf_plist[afi][safi] = +			 prefix_list_lookup (AFI_ORF_PREFIX, name); +	    } +	  stream_forward (s, orf_len); +	} +      if (BGP_DEBUG (normal, NORMAL)) +	zlog_info ("%s rcvd Refresh %s ORF request", peer->host, +		   when_to_refresh == REFRESH_DEFER ? "Defer" : "Immediate"); +      if (when_to_refresh == REFRESH_DEFER) +	return; +    } + +  /* First update is deferred until ORF or ROUTE-REFRESH is received */ +  if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) +    UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH); + +  /* Perform route refreshment to the peer */ +  bgp_announce_route (peer, afi, safi); +} + +int +bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) +{ +  u_char *end; +  struct capability cap; +  u_char action; +  struct bgp *bgp; +  afi_t afi; +  safi_t safi; + +  bgp = peer->bgp; +  end = pnt + length; + +  while (pnt < end) +    { +      /* We need at least action, capability code and capability length. */ +      if (pnt + 3 > end) +        { +          zlog_info ("%s Capability length error", peer->host); +          bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +          return -1; +        } + +      action = *pnt; + +      /* Fetch structure to the byte stream. */ +      memcpy (&cap, pnt + 1, sizeof (struct capability)); + +      /* Action value check.  */ +      if (action != CAPABILITY_ACTION_SET +	  && action != CAPABILITY_ACTION_UNSET) +        { +          zlog_info ("%s Capability Action Value error %d", +		     peer->host, action); +          bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +          return -1; +        } + +      if (BGP_DEBUG (normal, NORMAL)) +	zlog_info ("%s CAPABILITY has action: %d, code: %u, length %u", +		   peer->host, action, cap.code, cap.length); + +      /* Capability length check. */ +      if (pnt + (cap.length + 3) > end) +        { +          zlog_info ("%s Capability length error", peer->host); +          bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +          return -1; +        } + +      /* We know MP Capability Code. */ +      if (cap.code == CAPABILITY_CODE_MP) +        { +	  afi = ntohs (cap.mpc.afi); +	  safi = cap.mpc.safi; + +          /* Ignore capability when override-capability is set. */ +          if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) +	    continue; + +	  /* Address family check.  */ +	  if ((afi == AFI_IP  +	       || afi == AFI_IP6) +	      && (safi == SAFI_UNICAST  +		  || safi == SAFI_MULTICAST  +		  || safi == BGP_SAFI_VPNV4)) +	    { +	      if (BGP_DEBUG (normal, NORMAL)) +		zlog_info ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u", +			   peer->host, +			   action == CAPABILITY_ACTION_SET  +			   ? "Advertising" : "Removing", +			   ntohs(cap.mpc.afi) , cap.mpc.safi); +		   +	      /* Adjust safi code. */ +	      if (safi == BGP_SAFI_VPNV4) +		safi = SAFI_MPLS_VPN; +	       +	      if (action == CAPABILITY_ACTION_SET) +		{ +		  peer->afc_recv[afi][safi] = 1; +		  if (peer->afc[afi][safi]) +		    { +		      peer->afc_nego[afi][safi] = 1; +		      bgp_announce_route (peer, afi, safi); +		    } +		} +	      else +		{ +		  peer->afc_recv[afi][safi] = 0; +		  peer->afc_nego[afi][safi] = 0; + +		  if (peer_active_nego (peer)) +		    bgp_clear_route (peer, afi, safi); +		  else +		    BGP_EVENT_ADD (peer, BGP_Stop); +		}  +	    } +        } +      else if (cap.code == CAPABILITY_CODE_REFRESH +	       || cap.code == CAPABILITY_CODE_REFRESH_OLD) +        { +          /* Check length. */ +          if (cap.length != 0) +            { +              zlog_info ("%s Route Refresh Capability length error %d", +                         peer->host, cap.length); +              bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); +              return -1; +            } +	   +          if (BGP_DEBUG (normal, NORMAL)) +            zlog_info ("%s CAPABILITY has %s ROUTE-REFRESH capability(%s) for all address-families", +		       peer->host, +		       action == CAPABILITY_ACTION_SET +		       ? "Advertising" : "Removing", +		       cap.code == CAPABILITY_CODE_REFRESH_OLD +		       ? "old" : "new"); +	   +          /* BGP refresh capability */ +	  if (action == CAPABILITY_ACTION_SET) +	    { +	      if (cap.code == CAPABILITY_CODE_REFRESH_OLD) +		SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); +	      else +		SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); +	    } +	  else +	    { +	      if (cap.code == CAPABILITY_CODE_REFRESH_OLD) +		UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); +	      else +		UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); +	    } +        } +      else +        { +          zlog_warn ("%s unrecognized capability code: %d - ignored", +                     peer->host, cap.code); +        } +      pnt += cap.length + 3; +    } +  return 0; +} + +/* Dynamic Capability is received. */ +void +bgp_capability_receive (struct peer *peer, bgp_size_t size) +{ +  u_char *pnt; +  int ret; + +  /* Fetch pointer. */ +  pnt = stream_pnt (peer->ibuf); + +  if (BGP_DEBUG (normal, NORMAL)) +    zlog_info ("%s rcv CAPABILITY", peer->host); + +  /* If peer does not have the capability, send notification. */ +  if (! CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV)) +    { +      plog_err (peer->log, "%s [Error] BGP dynamic capability is not enabled", +		peer->host); +      bgp_notify_send (peer, +		       BGP_NOTIFY_HEADER_ERR, +		       BGP_NOTIFY_HEADER_BAD_MESTYPE); +      return; +    } + +  /* Status must be Established. */ +  if (peer->status != Established) +    { +      plog_err (peer->log, +		"%s [Error] Dynamic capability packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); +      bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); +      return; +    } + +  /* Parse packet. */ +  ret = bgp_capability_msg_parse (peer, pnt, size); +} + +/* BGP read utility function. */ +int +bgp_read_packet (struct peer *peer) +{ +  int nbytes; +  int readsize; + +  readsize = peer->packet_size - peer->ibuf->putp; + +  /* If size is zero then return. */ +  if (! readsize) +    return 0; + +  /* Read packet from fd. */ +  nbytes = stream_read_unblock (peer->ibuf, peer->fd, readsize); + +  /* If read byte is smaller than zero then error occured. */ +  if (nbytes < 0)  +    { +      if (errno == EAGAIN) +	return -1; + +      plog_err (peer->log, "%s [Error] bgp_read_packet error: %s", +		 peer->host, strerror (errno)); +      BGP_EVENT_ADD (peer, TCP_fatal_error); +      return -1; +    }   + +  /* When read byte is zero : clear bgp peer and return */ +  if (nbytes == 0)  +    { +      if (BGP_DEBUG (events, EVENTS)) +	plog_info (peer->log, "%s [Event] BGP connection closed fd %d", +		   peer->host, peer->fd); +      BGP_EVENT_ADD (peer, TCP_connection_closed); +      return -1; +    } + +  /* We read partial packet. */ +  if (peer->ibuf->putp != peer->packet_size) +    return -1; + +  return 0; +} + +/* Marker check. */ +int +bgp_marker_all_one (struct stream *s, int length) +{ +  int i; + +  for (i = 0; i < length; i++) +    if (s->data[i] != 0xff) +      return 0; + +  return 1; +} + +/* Starting point of packet process function. */ +int +bgp_read (struct thread *thread) +{ +  int ret; +  u_char type = 0; +  struct peer *peer; +  bgp_size_t size; +  char notify_data_length[2]; + +  /* Yes first of all get peer pointer. */ +  peer = THREAD_ARG (thread); +  peer->t_read = NULL; + +  /* For non-blocking IO check. */ +  if (peer->status == Connect) +    { +      bgp_connect_check (peer); +      goto done; +    } +  else +    { +      if (peer->fd < 0) +	{ +	  zlog_err ("bgp_read peer's fd is negative value %d", peer->fd); +	  return -1; +	} +      BGP_READ_ON (peer->t_read, bgp_read, peer->fd); +    } + +  /* Read packet header to determine type of the packet */ +  if (peer->packet_size == 0) +    peer->packet_size = BGP_HEADER_SIZE; + +  if (peer->ibuf->putp < BGP_HEADER_SIZE) +    { +      ret = bgp_read_packet (peer); + +      /* Header read error or partial read packet. */ +      if (ret < 0)  +	goto done; + +      /* Get size and type. */ +      stream_forward (peer->ibuf, BGP_MARKER_SIZE); +      memcpy (notify_data_length, stream_pnt (peer->ibuf), 2); +      size = stream_getw (peer->ibuf); +      type = stream_getc (peer->ibuf); + +      if (BGP_DEBUG (normal, NORMAL) && type != 2 && type != 0) +	zlog_info ("%s rcv message type %d, length (excl. header) %d", +		   peer->host, type, size - BGP_HEADER_SIZE); + +      /* Marker check */ +      if (type == BGP_MSG_OPEN +	  && ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE)) +	{ +	  bgp_notify_send (peer, +			   BGP_NOTIFY_HEADER_ERR,  +			   BGP_NOTIFY_HEADER_NOT_SYNC); +	  goto done; +	} + +      /* BGP type check. */ +      if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE  +	  && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE  +	  && type != BGP_MSG_ROUTE_REFRESH_NEW +	  && type != BGP_MSG_ROUTE_REFRESH_OLD +	  && type != BGP_MSG_CAPABILITY) +	{ +	  if (BGP_DEBUG (normal, NORMAL)) +	    plog_err (peer->log, +		      "%s unknown message type 0x%02x", +		      peer->host, type); +	  bgp_notify_send_with_data (peer, +				     BGP_NOTIFY_HEADER_ERR, +			 	     BGP_NOTIFY_HEADER_BAD_MESTYPE, +				     &type, 1); +	  goto done; +	} +      /* Mimimum packet length check. */ +      if ((size < BGP_HEADER_SIZE) +	  || (size > BGP_MAX_PACKET_SIZE) +	  || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE) +	  || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE) +	  || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE) +	  || (type == BGP_MSG_KEEPALIVE && size != BGP_MSG_KEEPALIVE_MIN_SIZE) +	  || (type == BGP_MSG_ROUTE_REFRESH_NEW && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) +	  || (type == BGP_MSG_ROUTE_REFRESH_OLD && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) +	  || (type == BGP_MSG_CAPABILITY && size < BGP_MSG_CAPABILITY_MIN_SIZE)) +	{ +	  if (BGP_DEBUG (normal, NORMAL)) +	    plog_err (peer->log, +		      "%s bad message length - %d for %s", +		      peer->host, size,  +		      type == 128 ? "ROUTE-REFRESH" : +		      bgp_type_str[(int) type]); +	  bgp_notify_send_with_data (peer, +				     BGP_NOTIFY_HEADER_ERR, +			  	     BGP_NOTIFY_HEADER_BAD_MESLEN, +				     notify_data_length, 2); +	  goto done; +	} + +      /* Adjust size to message length. */ +      peer->packet_size = size; +    } + +  ret = bgp_read_packet (peer); +  if (ret < 0)  +    goto done; + +  /* Get size and type again. */ +  size = stream_getw_from (peer->ibuf, BGP_MARKER_SIZE); +  type = stream_getc_from (peer->ibuf, BGP_MARKER_SIZE + 2); + +  /* BGP packet dump function. */ +  bgp_dump_packet (peer, type, peer->ibuf); +   +  size = (peer->packet_size - BGP_HEADER_SIZE); + +  /* Read rest of the packet and call each sort of packet routine */ +  switch (type)  +    { +    case BGP_MSG_OPEN: +      peer->open_in++; +      bgp_open_receive (peer, size); +      break; +    case BGP_MSG_UPDATE: +      peer->readtime = time(NULL);    /* Last read timer reset */ +      bgp_update_receive (peer, size); +      break; +    case BGP_MSG_NOTIFY: +      bgp_notify_receive (peer, size); +      break; +    case BGP_MSG_KEEPALIVE: +      peer->readtime = time(NULL);    /* Last read timer reset */ +      bgp_keepalive_receive (peer, size); +      break; +    case BGP_MSG_ROUTE_REFRESH_NEW: +    case BGP_MSG_ROUTE_REFRESH_OLD: +      peer->refresh_in++; +      bgp_route_refresh_receive (peer, size); +      break; +    case BGP_MSG_CAPABILITY: +      peer->dynamic_cap_in++; +      bgp_capability_receive (peer, size); +      break; +    } + +  /* Clear input buffer. */ +  peer->packet_size = 0; +  if (peer->ibuf) +    stream_reset (peer->ibuf); + + done: +  if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) +    { +      if (BGP_DEBUG (events, EVENTS)) +	zlog_info ("%s [Event] Accepting BGP peer delete", peer->host); +      peer_delete (peer); +    } +  return 0; +} diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h new file mode 100644 index 0000000000..c1efc8bd51 --- /dev/null +++ b/bgpd/bgp_packet.h @@ -0,0 +1,49 @@ +/* BGP packet management header. +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#define BGP_NLRI_LENGTH       1 +#define BGP_TOTAL_ATTR_LEN    2 +#define BGP_UNFEASIBLE_LEN    2 +#define BGP_WRITE_PACKET_MAX 10 + +/* When to refresh */ +#define REFRESH_IMMEDIATE 1 +#define REFRESH_DEFER     2  + +/* ORF Common part flag */ +#define ORF_COMMON_PART_ADD        0x00  +#define ORF_COMMON_PART_REMOVE     0x80  +#define ORF_COMMON_PART_REMOVE_ALL 0xC0  +#define ORF_COMMON_PART_PERMIT     0x00  +#define ORF_COMMON_PART_DENY       0x20  + +/* Packet send and receive function prototypes. */ +int bgp_read (struct thread *); +int bgp_write (struct thread *); + +void bgp_keepalive_send (struct peer *); +void bgp_open_send (struct peer *); +void bgp_notify_send (struct peer *, u_char, u_char); +void bgp_notify_send_with_data (struct peer *, u_char, u_char, u_char *, size_t); +void bgp_route_refresh_send (struct peer *, afi_t, safi_t, u_char, u_char, int); +void bgp_capability_send (struct peer *, afi_t, safi_t, int, int); +void bgp_default_update_send (struct peer *, struct attr *, +			      afi_t, safi_t, struct peer *); +void bgp_default_withdraw_send (struct peer *, afi_t, safi_t); diff --git a/bgpd/bgp_regex.c b/bgpd/bgp_regex.c new file mode 100644 index 0000000000..a6b6598429 --- /dev/null +++ b/bgpd/bgp_regex.c @@ -0,0 +1,93 @@ +/* AS regular expression routine +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "log.h" +#include "command.h" +#include "memory.h" + +#include "bgpd.h" +#include "bgp_aspath.h" +#include "bgp_regex.h" + +/* Character `_' has special mean.  It represents [,{}() ] and the +   beginning of the line(^) and the end of the line ($).   + +   (^|[,{}() ]|$) */ + +regex_t * +bgp_regcomp (char *regstr) +{ +  /* Convert _ character to generic regular expression. */ +  int i, j; +  int len; +  int magic = 0; +  char *magic_str; +  char magic_regexp[] = "(^|[,{}() ]|$)"; +  int ret; +  regex_t *regex; + +  len = strlen (regstr); +  for (i = 0; i < len; i++) +    if (regstr[i] == '_') +      magic++; + +  magic_str = XMALLOC (MTYPE_TMP, len + (14 * magic) + 1); +   +  for (i = 0, j = 0; i < len; i++) +    { +      if (regstr[i] == '_') +	{ +	  memcpy (magic_str + j, magic_regexp, strlen (magic_regexp)); +	  j += strlen (magic_regexp); +	} +      else +	magic_str[j++] = regstr[i]; +    } +  magic_str[j] = '\0'; + +  regex = XMALLOC (MTYPE_BGP_REGEXP, sizeof (regex_t)); + +  ret = regcomp (regex, magic_str, REG_EXTENDED); + +  XFREE (MTYPE_TMP, magic_str); + +  if (ret != 0) +    { +      XFREE (MTYPE_BGP_REGEXP, regex); +      return NULL; +    } + +  return regex; +} + +int +bgp_regexec (regex_t *regex, struct aspath *aspath) +{ +  return regexec (regex, aspath->str, 0, NULL, 0); +} + +void +bgp_regex_free (regex_t *regex) +{ +  regfree (regex); +  XFREE (MTYPE_BGP_REGEXP, regex); +} diff --git a/bgpd/bgp_regex.h b/bgpd/bgp_regex.h new file mode 100644 index 0000000000..0829dd9abe --- /dev/null +++ b/bgpd/bgp_regex.h @@ -0,0 +1,31 @@ +/* AS regular expression routine +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#ifdef HAVE_GNU_REGEX +#include <regex.h> +#else +#include "regex-gnu.h" +#endif /* HAVE_GNU_REGEX */ + +void bgp_regex_free (regex_t *regex); +regex_t *bgp_regcomp (char *str); +int bgp_regexec (regex_t *regex, struct aspath *aspath); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c new file mode 100644 index 0000000000..87d305cb7c --- /dev/null +++ b/bgpd/bgp_route.c @@ -0,0 +1,9053 @@ +/* BGP routing information +   Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "prefix.h" +#include "linklist.h" +#include "memory.h" +#include "command.h" +#include "stream.h" +#include "filter.h" +#include "str.h" +#include "log.h" +#include "routemap.h" +#include "buffer.h" +#include "sockunion.h" +#include "plist.h" +#include "thread.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_clist.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_filter.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_damp.h" +#include "bgpd/bgp_advertise.h" +#include "bgpd/bgp_zebra.h" + +/* Extern from bgp_dump.c */ +extern char *bgp_origin_str[]; +extern char *bgp_origin_long_str[]; + +struct bgp_node * +bgp_afi_node_get (struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p, +		  struct prefix_rd *prd) +{ +  struct bgp_node *rn; +  struct bgp_node *prn = NULL; +  struct bgp_table *table; + +  if (safi == SAFI_MPLS_VPN) +    { +      prn = bgp_node_get (bgp->rib[afi][safi], (struct prefix *) prd); + +      if (prn->info == NULL) +	prn->info = bgp_table_init (); +      else +	bgp_unlock_node (prn); +      table = prn->info; +    } +  else +    table = bgp->rib[afi][safi]; + +  rn = bgp_node_get (table, p); + +  if (safi == SAFI_MPLS_VPN) +    rn->prn = prn; + +  return rn; +} + +/* Allocate new bgp info structure. */ +struct bgp_info * +bgp_info_new () +{ +  struct bgp_info *new; + +  new = XMALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info)); +  memset (new, 0, sizeof (struct bgp_info)); + +  return new; +} + +/* Free bgp route information. */ +void +bgp_info_free (struct bgp_info *binfo) +{ +  if (binfo->attr) +    bgp_attr_unintern (binfo->attr); + +  if (binfo->damp_info) +    bgp_damp_info_free (binfo->damp_info, 0); + +  XFREE (MTYPE_BGP_ROUTE, binfo); +} + +void +bgp_info_add (struct bgp_node *rn, struct bgp_info *ri) +{ +  struct bgp_info *top; + +  top = rn->info; + +  ri->next = rn->info; +  ri->prev = NULL; +  if (top) +    top->prev = ri; +  rn->info = ri; +} + +void +bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri) +{ +  if (ri->next) +    ri->next->prev = ri->prev; +  if (ri->prev) +    ri->prev->next = ri->next; +  else +    rn->info = ri->next; +} + +/* Get MED value.  If MED value is missing and "bgp bestpath +   missing-as-worst" is specified, treat it as the worst value. */ +u_int32_t +bgp_med_value (struct attr *attr, struct bgp *bgp) +{ +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) +    return attr->med; +  else +    { +      if (bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST)) +	return 4294967295ul; +      else +	return 0; +    } +} + +/* Compare two bgp route entity.  br is preferable then return 1. */ +int +bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist) +{ +  u_int32_t new_pref; +  u_int32_t exist_pref; +  u_int32_t new_med; +  u_int32_t exist_med; +  struct in_addr new_id; +  struct in_addr exist_id; +  int new_cluster; +  int exist_cluster; +  int internal_as_route = 0; +  int confed_as_route = 0; +  int ret; + +  /* 0. Null check. */ +  if (new == NULL) +    return 0; +  if (exist == NULL) +    return 1; + +  /* 1. Weight check. */ +  if (new->attr->weight > exist->attr->weight) +    return 1; +  if (new->attr->weight < exist->attr->weight) +    return 0; + +  /* 2. Local preference check. */ +  if (new->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) +    new_pref = new->attr->local_pref; +  else +    new_pref = bgp->default_local_pref; + +  if (exist->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) +    exist_pref = exist->attr->local_pref; +  else +    exist_pref = bgp->default_local_pref; +     +  if (new_pref > exist_pref) +    return 1; +  if (new_pref < exist_pref) +    return 0; + +  /* 3. Local route check. */ +  if (new->sub_type == BGP_ROUTE_STATIC) +    return 1; +  if (exist->sub_type == BGP_ROUTE_STATIC) +    return 0; + +  if (new->sub_type == BGP_ROUTE_REDISTRIBUTE) +    return 1; +  if (exist->sub_type == BGP_ROUTE_REDISTRIBUTE) +    return 0; + +  if (new->sub_type == BGP_ROUTE_AGGREGATE) +    return 1; +  if (exist->sub_type == BGP_ROUTE_AGGREGATE) +    return 0; + +  /* 4. AS path length check. */ +  if (! bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE)) +    { +      if (new->attr->aspath->count < exist->attr->aspath->count) +	return 1; +      if (new->attr->aspath->count > exist->attr->aspath->count) +	return 0; +    } + +  /* 5. Origin check. */ +  if (new->attr->origin < exist->attr->origin) +    return 1; +  if (new->attr->origin > exist->attr->origin) +    return 0; + +  /* 6. MED check. */ +  internal_as_route = (new->attr->aspath->length == 0 +		      && exist->attr->aspath->length == 0); +  confed_as_route = (new->attr->aspath->length > 0 +		    && exist->attr->aspath->length > 0 +		    && new->attr->aspath->count == 0 +		    && exist->attr->aspath->count == 0); +   +  if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED) +      || (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED) +	 && confed_as_route) +      || aspath_cmp_left (new->attr->aspath, exist->attr->aspath) +      || aspath_cmp_left_confed (new->attr->aspath, exist->attr->aspath) +      || internal_as_route) +    { +      new_med = bgp_med_value (new->attr, bgp); +      exist_med = bgp_med_value (exist->attr, bgp); + +      if (new_med < exist_med) +	return 1; +      if (new_med > exist_med) +	return 0; +    } + +  /* 7. Peer type check. */ +  if (peer_sort (new->peer) == BGP_PEER_EBGP  +      && peer_sort (exist->peer) == BGP_PEER_IBGP) +    return 1; +  if (peer_sort (new->peer) == BGP_PEER_EBGP  +      && peer_sort (exist->peer) == BGP_PEER_CONFED) +    return 1; +  if (peer_sort (new->peer) == BGP_PEER_IBGP  +      && peer_sort (exist->peer) == BGP_PEER_EBGP) +    return 0; +  if (peer_sort (new->peer) == BGP_PEER_CONFED  +      && peer_sort (exist->peer) == BGP_PEER_EBGP) +    return 0; + +  /* 8. IGP metric check. */ +  if (new->igpmetric < exist->igpmetric) +    return 1; +  if (new->igpmetric > exist->igpmetric) +    return 0; + +  /* 9. Maximum path check. */ + +  /* 10. If both paths are external, prefer the path that was received +     first (the oldest one).  This step minimizes route-flap, since a +     newer path won't displace an older one, even if it was the +     preferred route based on the additional decision criteria below.  */ +  if (! bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID) +      && peer_sort (new->peer) == BGP_PEER_EBGP +      && peer_sort (exist->peer) == BGP_PEER_EBGP) +    { +      if (CHECK_FLAG (new->flags, BGP_INFO_SELECTED)) +	return 1; +      if (CHECK_FLAG (exist->flags, BGP_INFO_SELECTED)) +	return 0; +    } + +  /* 11. Rourter-ID comparision. */ +  if (new->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) +    new_id.s_addr = new->attr->originator_id.s_addr; +  else +    new_id.s_addr = new->peer->remote_id.s_addr; +  if (exist->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) +    exist_id.s_addr = exist->attr->originator_id.s_addr; +  else +    exist_id.s_addr = exist->peer->remote_id.s_addr; + +  if (ntohl (new_id.s_addr) < ntohl (exist_id.s_addr)) +    return 1; +  if (ntohl (new_id.s_addr) > ntohl (exist_id.s_addr)) +    return 0; + +  /* 12. Cluster length comparision. */ +  if (new->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) +    new_cluster = new->attr->cluster->length; +  else +    new_cluster = 0; +  if (exist->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) +    exist_cluster = exist->attr->cluster->length; +  else +    exist_cluster = 0; + +  if (new_cluster < exist_cluster) +    return 1; +  if (new_cluster > exist_cluster) +    return 0; + +  /* 13. Neighbor address comparision. */ +  ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote); + +  if (ret == 1) +    return 0; +  if (ret == -1) +    return 1; + +  return 1; +} + +enum filter_type +bgp_input_filter (struct peer *peer, struct prefix *p, struct attr *attr, +		  afi_t afi, safi_t safi) +{ +  struct bgp_filter *filter; + +  filter = &peer->filter[afi][safi]; + +  if (DISTRIBUTE_IN_NAME (filter)) +    if (access_list_apply (DISTRIBUTE_IN (filter), p) == FILTER_DENY) +      return FILTER_DENY; + +  if (PREFIX_LIST_IN_NAME (filter)) +    if (prefix_list_apply (PREFIX_LIST_IN (filter), p) == PREFIX_DENY) +      return FILTER_DENY; +   +  if (FILTER_LIST_IN_NAME (filter)) +    if (as_list_apply (FILTER_LIST_IN (filter), attr->aspath)== AS_FILTER_DENY) +      return FILTER_DENY; + +  return FILTER_PERMIT; +} + +enum filter_type +bgp_output_filter (struct peer *peer, struct prefix *p, struct attr *attr, +		   afi_t afi, safi_t safi) +{ +  struct bgp_filter *filter; + +  filter = &peer->filter[afi][safi]; + +  if (DISTRIBUTE_OUT_NAME (filter)) +    if (access_list_apply (DISTRIBUTE_OUT (filter), p) == FILTER_DENY) +      return FILTER_DENY; + +  if (PREFIX_LIST_OUT_NAME (filter)) +    if (prefix_list_apply (PREFIX_LIST_OUT (filter), p) == PREFIX_DENY) +      return FILTER_DENY; + +  if (FILTER_LIST_OUT_NAME (filter)) +    if (as_list_apply (FILTER_LIST_OUT (filter), attr->aspath) == AS_FILTER_DENY) +      return FILTER_DENY; + +  return FILTER_PERMIT; +} + +/* If community attribute includes no_export then return 1. */ +int +bgp_community_filter (struct peer *peer, struct attr *attr) +{ +  if (attr->community) +    { +      /* NO_ADVERTISE check. */ +      if (community_include (attr->community, COMMUNITY_NO_ADVERTISE)) +	return 1; + +      /* NO_EXPORT check. */ +      if (peer_sort (peer) == BGP_PEER_EBGP && +	  community_include (attr->community, COMMUNITY_NO_EXPORT)) +	return 1; + +      /* NO_EXPORT_SUBCONFED check. */ +      if (peer_sort (peer) == BGP_PEER_EBGP  +	  || peer_sort (peer) == BGP_PEER_CONFED) +	if (community_include (attr->community, COMMUNITY_NO_EXPORT_SUBCONFED)) +	  return 1; +    } +  return 0; +} + +/* Route reflection loop check.  */ +static int +bgp_cluster_filter (struct peer *peer, struct attr *attr) +{ +  struct in_addr cluster_id; + +  if (attr->cluster) +    { +      if (peer->bgp->config & BGP_CONFIG_CLUSTER_ID) +	cluster_id = peer->bgp->cluster_id; +      else +	cluster_id = peer->bgp->router_id; +       +      if (cluster_loop_check (attr->cluster, cluster_id)) +	return 1; +    } +  return 0; +} + +int +bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr, +		    afi_t afi, safi_t safi) +{ +  struct bgp_filter *filter; +  struct bgp_info info; +  route_map_result_t ret; + +  filter = &peer->filter[afi][safi]; + +  /* Apply default weight value. */ +  attr->weight = peer->weight; + +  /* Route map apply. */ +  if (ROUTE_MAP_IN_NAME (filter)) +    { +      /* Duplicate current value to new strucutre for modification. */ +      info.peer = peer; +      info.attr = attr; + +      /* Apply BGP route map to the attribute. */ +      ret = route_map_apply (ROUTE_MAP_IN (filter), p, RMAP_BGP, &info); +      if (ret == RMAP_DENYMATCH) +	{ +	  /* Free newly generated AS path and community by route-map. */ +	  bgp_attr_flush (attr); +	  return RMAP_DENY; +	} +    } +  return RMAP_PERMIT; +} + +int +bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, +		    struct attr *attr, afi_t afi, safi_t safi) +{ +  int ret; +  char buf[SU_ADDRSTRLEN]; +  struct bgp_filter *filter; +  struct bgp_info info; +  struct peer *from; +  struct bgp *bgp; +  struct attr dummy_attr; +  int transparent; +  int reflect; + +  from = ri->peer; +  filter = &peer->filter[afi][safi]; +  bgp = peer->bgp; +   +#ifdef DISABLE_BGP_ANNOUNCE +  return 0; +#endif + +  /* Do not send back route to sender. */ +  if (from == peer) +    return 0; + +  /* Aggregate-address suppress check. */ +  if (ri->suppress) +    if (! UNSUPPRESS_MAP_NAME (filter)) +      return 0; + +  /* Default route check.  */ +  if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) +    { +      if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY) +	return 0; +#ifdef HAVE_IPV6 +      else if (p->family == AF_INET6 && p->prefixlen == 0) +	return 0; +#endif /* HAVE_IPV6 */ +    } + +  /* If community is not disabled check the no-export and local. */ +  if (bgp_community_filter (peer, ri->attr))  +    return 0; + +  /* If the attribute has originator-id and it is same as remote +     peer's id. */ +  if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) +    { +      if (IPV4_ADDR_SAME (&peer->remote_id, &ri->attr->originator_id)) +	{ +	  if (BGP_DEBUG (filter, FILTER))   +	    zlog (peer->log, LOG_INFO, +		  "%s [Update:SEND] %s/%d originator-id is same as remote router-id", +		  peer->host, +		  inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +		  p->prefixlen); +	  return 0; +	} +    } +  +  /* ORF prefix-list filter check */ +  if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) +      && (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) +	  || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))) +    if (peer->orf_plist[afi][safi]) +      { +	if (prefix_list_apply (peer->orf_plist[afi][safi], p) == PREFIX_DENY) +          return 0; +      } + +  /* Output filter check. */ +  if (bgp_output_filter (peer, p, ri->attr, afi, safi) == FILTER_DENY) +    { +      if (BGP_DEBUG (filter, FILTER)) +	zlog (peer->log, LOG_INFO, +	      "%s [Update:SEND] %s/%d is filtered", +	      peer->host, +	      inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +	      p->prefixlen); +      return 0; +    } + +#ifdef BGP_SEND_ASPATH_CHECK +  /* AS path loop check. */ +  if (aspath_loop_check (ri->attr->aspath, peer->as)) +    { +      if (BGP_DEBUG (filter, FILTER))   +        zlog (peer->log, LOG_INFO,  +	      "%s [Update:SEND] suppress announcement to peer AS %d is AS path.", +	      peer->host, peer->as); +      return 0; +    } +#endif /* BGP_SEND_ASPATH_CHECK */ + +  /* If we're a CONFED we need to loop check the CONFED ID too */ +  if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) +    { +      if (aspath_loop_check(ri->attr->aspath, bgp->confed_id)) +	{ +	  if (BGP_DEBUG (filter, FILTER))   +	    zlog (peer->log, LOG_INFO,  +		  "%s [Update:SEND] suppress announcement to peer AS %d is AS path.", +		  peer->host, +		  bgp->confed_id); +	  return 0; +	}       +    } + +  /* Route-Reflect check. */ +  if (peer_sort (from) == BGP_PEER_IBGP && peer_sort (peer) == BGP_PEER_IBGP) +    reflect = 1; +  else +    reflect = 0; + +  /* IBGP reflection check. */ +  if (reflect) +    { +      /* A route from a Client peer. */ +      if (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) +	{ +	  /* Reflect to all the Non-Client peers and also to the +             Client peers other than the originator.  Originator check +             is already done.  So there is noting to do. */ +	  /* no bgp client-to-client reflection check. */ +	  if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT)) +	    if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) +	      return 0; +	} +      else +	{ +	  /* A route from a Non-client peer. Reflect to all other +	     clients. */ +	  if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) +	    return 0; +	} +    } + +  /* For modify attribute, copy it to temporary structure. */ +  *attr = *ri->attr; + +  /* If local-preference is not set. */ +  if ((peer_sort (peer) == BGP_PEER_IBGP  +       || peer_sort (peer) == BGP_PEER_CONFED)  +      && (! (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))) +    { +      attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); +      attr->local_pref = bgp->default_local_pref; +    } + +  /* Transparency check. */ +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) +      && CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) +    transparent = 1; +  else +    transparent = 0; + +  /* Remove MED if its an EBGP peer - will get overwritten by route-maps */ +  if (peer_sort (peer) == BGP_PEER_EBGP  +      && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) +    { +      if (ri->peer != bgp->peer_self && ! transparent +	  && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) +	attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)); +    } + +  /* next-hop-set */ +  if (transparent || reflect +      || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) +	  && ((p->family == AF_INET && attr->nexthop.s_addr) +	      || (p->family == AF_INET6 && ri->peer != bgp->peer_self)))) +    { +      /* NEXT-HOP Unchanged. */ +    } +  else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF) +	   || (p->family == AF_INET && attr->nexthop.s_addr == 0) +#ifdef HAVE_IPV6 +	   || (p->family == AF_INET6 && ri->peer == bgp->peer_self) +#endif /* HAVE_IPV6 */ +	   || (peer_sort (peer) == BGP_PEER_EBGP +	       && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0)) +    { +      /* Set IPv4 nexthop. */ +      if (p->family == AF_INET) +	{ +	  if (safi == SAFI_MPLS_VPN) +	    memcpy (&attr->mp_nexthop_global_in, &peer->nexthop.v4, IPV4_MAX_BYTELEN); +	  else +	    memcpy (&attr->nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN); +	} +#ifdef HAVE_IPV6 +      /* Set IPv6 nexthop. */ +      if (p->family == AF_INET6) +	{ +	  /* IPv6 global nexthop must be included. */ +	  memcpy (&attr->mp_nexthop_global, &peer->nexthop.v6_global,  +		  IPV6_MAX_BYTELEN); +	  attr->mp_nexthop_len = 16; +	} +#endif /* HAVE_IPV6 */ +    } + +#ifdef HAVE_IPV6 +  if (p->family == AF_INET6) +    { +      /* Link-local address should not be transit to different peer. */ +      attr->mp_nexthop_len = 16; + +      /* Set link-local address for shared network peer. */ +      if (peer->shared_network  +	  && ! IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local)) +	{ +	  memcpy (&attr->mp_nexthop_local, &peer->nexthop.v6_local,  +		  IPV6_MAX_BYTELEN); +	  attr->mp_nexthop_len = 32; +	} + +      /* If bgpd act as BGP-4+ route-reflector, do not send link-local +	 address.*/ +      if (reflect) +	attr->mp_nexthop_len = 16; + +      /* If BGP-4+ link-local nexthop is not link-local nexthop. */ +      if (! IN6_IS_ADDR_LINKLOCAL (&peer->nexthop.v6_local)) +	attr->mp_nexthop_len = 16; +    } +#endif /* HAVE_IPV6 */ + +  /* If this is EBGP peer and remove-private-AS is set.  */ +  if (peer_sort (peer) == BGP_PEER_EBGP +      && peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) +      && aspath_private_as_check (attr->aspath)) +    attr->aspath = aspath_empty_get (); + +  /* Route map & unsuppress-map apply. */ +  if (ROUTE_MAP_OUT_NAME (filter) +      || ri->suppress) +    { +      info.peer = peer; +      info.attr = attr; + +      /* The route reflector is not allowed to modify the attributes +	 of the reflected IBGP routes. */ +      if (peer_sort (from) == BGP_PEER_IBGP  +	  && peer_sort (peer) == BGP_PEER_IBGP) +	{ +	  dummy_attr = *attr; +	  info.attr = &dummy_attr; +	} +  +      if (ri->suppress) +	ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info); +      else +	ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info); + +      if (ret == RMAP_DENYMATCH) +	{ +	  bgp_attr_flush (attr); +	  return 0; +	} +    } +  return 1; +} + +int +bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) +{ +  struct prefix *p; +  struct bgp_info *ri; +  struct bgp_info *new_select; +  struct bgp_info *old_select; +  struct listnode *nn; +  struct peer *peer; +  struct attr attr; +  struct bgp_info *ri1; +  struct bgp_info *ri2; + +  p = &rn->p; + +  /* bgp deterministic-med */ +  new_select = NULL; +  if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) +    for (ri1 = rn->info; ri1; ri1 = ri1->next) +      { +	if (CHECK_FLAG (ri1->flags, BGP_INFO_DMED_CHECK)) +	  continue; +	if (BGP_INFO_HOLDDOWN (ri1)) +	  continue; + +	new_select = ri1; +	if (ri1->next) +	  for (ri2 = ri1->next; ri2; ri2 = ri2->next) +	    { +	      if (CHECK_FLAG (ri2->flags, BGP_INFO_DMED_CHECK)) +		continue; +	      if (BGP_INFO_HOLDDOWN (ri2)) +		continue; + +	      if (aspath_cmp_left (ri1->attr->aspath, ri2->attr->aspath) +		  || aspath_cmp_left_confed (ri1->attr->aspath, +					     ri2->attr->aspath)) +		{ +		  if (bgp_info_cmp (bgp, ri2, new_select)) +		    { +		      UNSET_FLAG (new_select->flags, BGP_INFO_DMED_SELECTED); +		      new_select = ri2; +		    } + +		  SET_FLAG (ri2->flags, BGP_INFO_DMED_CHECK); +		} +	    } +	SET_FLAG (new_select->flags, BGP_INFO_DMED_CHECK); +	SET_FLAG (new_select->flags, BGP_INFO_DMED_SELECTED); +      } + +  /* Check old selected route and new selected route. */ +  old_select = NULL; +  new_select = NULL; +  for (ri = rn->info; ri; ri = ri->next) +    { +      if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) +	old_select = ri; + +      if (BGP_INFO_HOLDDOWN (ri)) +	continue; + +      if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED) +          && (! CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED))) +	{ +	  UNSET_FLAG (ri->flags, BGP_INFO_DMED_CHECK); +	  continue; +        } +      UNSET_FLAG (ri->flags, BGP_INFO_DMED_CHECK); +      UNSET_FLAG (ri->flags, BGP_INFO_DMED_SELECTED); + +      if (bgp_info_cmp (bgp, ri, new_select)) +	new_select = ri; +    } + +  /* Nothing to do. */ +  if (old_select && old_select == new_select) +    { +      if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) +	{ +	  if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED)) +	    bgp_zebra_announce (p, old_select, bgp); +	  return 0; +	} +    } + +  if (old_select) +    UNSET_FLAG (old_select->flags, BGP_INFO_SELECTED); +  if (new_select) +    { +      SET_FLAG (new_select->flags, BGP_INFO_SELECTED); +      UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED); +    } + +  /* Check each BGP peer. */ +  LIST_LOOP (bgp->peer, peer, nn) +    { +      /* Announce route to Established peer. */ +      if (peer->status != Established) +	continue; + +      /* Address family configuration check. */ +      if (! peer->afc_nego[afi][safi]) +	continue; + +      /* First update is deferred until ORF or ROUTE-REFRESH is received */ +      if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) +	continue; + +      /* Announcement to peer->conf.  If the route is filtered, +         withdraw it. */ +      if (new_select  +	  && bgp_announce_check (new_select, peer, p, &attr, afi, safi)) +	bgp_adj_out_set (rn, peer, p, &attr, afi, safi, new_select); +      else +	bgp_adj_out_unset (rn, peer, p, afi, safi); +    } + +  /* FIB update. */ +  if (safi == SAFI_UNICAST && ! bgp->name && +      ! bgp_option_check (BGP_OPT_NO_FIB)) +    { +      if (new_select  +	  && new_select->type == ZEBRA_ROUTE_BGP  +	  && new_select->sub_type == BGP_ROUTE_NORMAL) +	bgp_zebra_announce (p, new_select, bgp); +      else +	{ +	  /* Withdraw the route from the kernel. */ +	  if (old_select  +	      && old_select->type == ZEBRA_ROUTE_BGP +	      && old_select->sub_type == BGP_ROUTE_NORMAL) +	    bgp_zebra_withdraw (p, old_select); +	} +    } +  return 0; +} + +int +bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi, safi_t safi) +{ +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX) +      && peer->pcount[afi][safi] >= peer->pmax[afi][safi]) +    { +      zlog (peer->log, LOG_INFO, +	    "MAXPFXEXCEED: No. of prefix received from %s (afi %d): %ld exceed limit %ld", +	    peer->host, afi, peer->pcount[afi][safi], peer->pmax[afi][safi]); +      if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)) +	{ +	  char ndata[7]; + +	  ndata[0] = (u_char)(afi >>  8); +	  ndata[1] = (u_char) afi; +	  ndata[3] = (u_char)(peer->pmax[afi][safi] >> 24); +	  ndata[4] = (u_char)(peer->pmax[afi][safi] >> 16); +	  ndata[5] = (u_char)(peer->pmax[afi][safi] >> 8); +	  ndata[6] = (u_char)(peer->pmax[afi][safi]); + +	  if (safi == SAFI_MPLS_VPN) +	    safi = BGP_SAFI_VPNV4; +	  ndata[2] = (u_char) safi; + +	  bgp_notify_send_with_data (peer, BGP_NOTIFY_CEASE, +				     BGP_NOTIFY_CEASE_MAX_PREFIX, +				     ndata, 7); +	  SET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); +	  return 1; +	} +    } +  return 0; +} + +void +bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, +		afi_t afi, safi_t safi) +{ +  if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) +    { +      peer->pcount[afi][safi]--; +      bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); +      UNSET_FLAG (ri->flags, BGP_INFO_VALID); +      bgp_process (peer->bgp, rn, afi, safi); +    } +  bgp_info_delete (rn, ri); +  bgp_info_free (ri); +  bgp_unlock_node (rn); +} + +void +bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, +		  afi_t afi, safi_t safi, int force) +{ +  int valid; +  int status = BGP_DAMP_NONE; + +  if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) +    { +      peer->pcount[afi][safi]--; +      bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); +    } + +  if (! force) +    { +      if (CHECK_FLAG (peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) +	  && peer_sort (peer) == BGP_PEER_EBGP) +	status = bgp_damp_withdraw (ri, rn, afi, safi, 0); + +      if (status == BGP_DAMP_SUPPRESSED) +	return; +    } + +  valid = CHECK_FLAG (ri->flags, BGP_INFO_VALID); +  UNSET_FLAG (ri->flags, BGP_INFO_VALID); +  bgp_process (peer->bgp, rn, afi, safi); + +  if (valid) +    SET_FLAG (ri->flags, BGP_INFO_VALID); + +  if (status != BGP_DAMP_USED) +    { +      bgp_info_delete (rn, ri); +      bgp_info_free (ri); +      bgp_unlock_node (rn); +    } +} + +int +bgp_update (struct peer *peer, struct prefix *p, struct attr *attr,  +	    afi_t afi, safi_t safi, int type, int sub_type, +	    struct prefix_rd *prd, u_char *tag, int soft_reconfig) +{ +  int ret; +  int aspath_loop_count = 0; +  struct bgp_node *rn; +  struct bgp *bgp; +  struct attr new_attr; +  struct attr *attr_new; +  struct bgp_info *ri; +  struct bgp_info *new; +  char *reason; +  char buf[SU_ADDRSTRLEN]; + +  bgp = peer->bgp; +  rn = bgp_afi_node_get (bgp, afi, safi, p, prd); + +  /* When peer's soft reconfiguration enabled.  Record input packet in +     Adj-RIBs-In.  */ +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) +      && peer != bgp->peer_self && ! soft_reconfig) +    bgp_adj_in_set (rn, peer, attr); + +  /* Check previously received route. */ +  for (ri = rn->info; ri; ri = ri->next) +    if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) +      break; + +  /* AS path local-as loop check. */ +  if (peer->change_local_as) +    { +      if (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) +	aspath_loop_count = 1; + +      if (aspath_loop_check (attr->aspath, peer->change_local_as) > aspath_loop_count)  +	{ +	  reason = "as-path contains our own AS;"; +	  goto filtered; +	} +    } + +  /* AS path loop check. */ +  if (aspath_loop_check (attr->aspath, bgp->as) > peer->allowas_in[afi][safi] +      || (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) +	  && aspath_loop_check(attr->aspath, bgp->confed_id) +	  > peer->allowas_in[afi][safi])) +    { +      reason = "as-path contains our own AS;"; +      goto filtered; +    } + +  /* Route reflector originator ID check.  */ +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID) +      && IPV4_ADDR_SAME (&bgp->router_id, &attr->originator_id)) +    { +      reason = "originator is us;"; +      goto filtered; +    } + +  /* Route reflector cluster ID check.  */ +  if (bgp_cluster_filter (peer, attr)) +    { +      reason = "reflected from the same cluster;"; +      goto  filtered; +    } + +  /* Apply incoming filter.  */ +  if (bgp_input_filter (peer, p, attr, afi, safi) == FILTER_DENY) +    { +      reason = "filter;"; +      goto filtered; +    } + +  /* Apply incoming route-map. */ +  new_attr = *attr; + +  if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY) +    { +      reason = "route-map;"; +      goto filtered; +    } + +  /* IPv4 unicast next hop check.  */ +  if (afi == AFI_IP && safi == SAFI_UNICAST) +    { +      /* If the peer is EBGP and nexthop is not on connected route, +	 discard it.  */ +      if (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl == 1 +	  && ! bgp_nexthop_check_ebgp (afi, &new_attr) +	  && ! CHECK_FLAG (peer->flags, PEER_FLAG_ENFORCE_MULTIHOP)) +	{ +	  reason = "non-connected next-hop;"; +	  goto filtered; +	} + +      /* Next hop must not be 0.0.0.0 nor Class E address.  Next hop +	 must not be my own address.  */ +      if (bgp_nexthop_self (afi, &new_attr) +	  || new_attr.nexthop.s_addr == 0 +	  || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000) +	{ +	  reason = "martian next-hop;"; +	  goto filtered; +	} +    } + +  attr_new = bgp_attr_intern (&new_attr); + +  /* If the update is implicit withdraw. */ +  if (ri) +    { +      ri->uptime = time (NULL); + +      /* Same attribute comes in. */ +      if (attrhash_cmp (ri->attr, attr_new)) +	{ +	  UNSET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + +	  if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) +	      && peer_sort (peer) == BGP_PEER_EBGP +	      && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) +	    { +	      if (BGP_DEBUG (update, UPDATE_IN))   +		  zlog (peer->log, LOG_INFO, "%s rcvd %s/%d", +		  peer->host, +		  inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +		  p->prefixlen); + +	      peer->pcount[afi][safi]++; +	      ret = bgp_damp_update (ri, rn, afi, safi); +	      if (ret != BGP_DAMP_SUPPRESSED) +		{ +		  bgp_aggregate_increment (bgp, p, ri, afi, safi); +		  bgp_process (bgp, rn, afi, safi); +		} +	    } +	  else +	    { +	      if (BGP_DEBUG (update, UPDATE_IN))   +		zlog (peer->log, LOG_INFO, +		"%s rcvd %s/%d...duplicate ignored", +		peer->host, +		inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +		p->prefixlen); +	    } + +	  bgp_unlock_node (rn); +	  bgp_attr_unintern (attr_new); +	  return 0; +	} + +      /* Received Logging. */ +      if (BGP_DEBUG (update, UPDATE_IN))   +	zlog (peer->log, LOG_INFO, "%s rcvd %s/%d", +	      peer->host, +	      inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +	      p->prefixlen); + +      /* The attribute is changed. */ +      SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + +      /* Update bgp route dampening information.  */ +      if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) +	  && peer_sort (peer) == BGP_PEER_EBGP) +	{ +	  /* This is implicit withdraw so we should update dampening +	     information.  */ +	  if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) +	    bgp_damp_withdraw (ri, rn, afi, safi, 1);   +	  else +	    peer->pcount[afi][safi]++; +	} +	 +      bgp_aggregate_decrement (bgp, p, ri, afi, safi); + +      /* Update to new attribute.  */ +      bgp_attr_unintern (ri->attr); +      ri->attr = attr_new; + +      /* Update MPLS tag.  */ +      if (safi == SAFI_MPLS_VPN) +	memcpy (ri->tag, tag, 3); + +      /* Update bgp route dampening information.  */ +      if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) +	  && peer_sort (peer) == BGP_PEER_EBGP) +	{ +	  /* Now we do normal update dampening.  */ +	  ret = bgp_damp_update (ri, rn, afi, safi); +	  if (ret == BGP_DAMP_SUPPRESSED) +	    { +	      bgp_unlock_node (rn); +	      return 0; +	    } +	} + +      /* Nexthop reachability check. */ +      if ((afi == AFI_IP || afi == AFI_IP6) +	  && safi == SAFI_UNICAST  +	  && (peer_sort (peer) == BGP_PEER_IBGP +	      || (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) +	      || CHECK_FLAG (peer->flags, PEER_FLAG_ENFORCE_MULTIHOP))) +	{ +	  if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL)) +	    SET_FLAG (ri->flags, BGP_INFO_VALID); +	  else +	    UNSET_FLAG (ri->flags, BGP_INFO_VALID); +	} +      else +	SET_FLAG (ri->flags, BGP_INFO_VALID); + +      /* Process change. */ +      bgp_aggregate_increment (bgp, p, ri, afi, safi); + +      bgp_process (bgp, rn, afi, safi); +      bgp_unlock_node (rn); +      return 0; +    } + +  /* Received Logging. */ +  if (BGP_DEBUG (update, UPDATE_IN))   +    { +      zlog (peer->log, LOG_INFO, "%s rcvd %s/%d", +	    peer->host, +	    inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +	    p->prefixlen); +    } + +  /* Increment prefix counter */ +  peer->pcount[afi][safi]++; + +  /* Make new BGP info. */ +  new = bgp_info_new (); +  new->type = type; +  new->sub_type = sub_type; +  new->peer = peer; +  new->attr = attr_new; +  new->uptime = time (NULL); + +  /* Update MPLS tag. */ +  if (safi == SAFI_MPLS_VPN) +    memcpy (new->tag, tag, 3); + +  /* Nexthop reachability check. */ +  if ((afi == AFI_IP || afi == AFI_IP6) +      && safi == SAFI_UNICAST +      && (peer_sort (peer) == BGP_PEER_IBGP +	  || (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) +	  || CHECK_FLAG (peer->flags, PEER_FLAG_ENFORCE_MULTIHOP))) +    { +      if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL)) +	SET_FLAG (new->flags, BGP_INFO_VALID); +      else +	UNSET_FLAG (new->flags, BGP_INFO_VALID); +    } +  else +    SET_FLAG (new->flags, BGP_INFO_VALID); + +  /* Aggregate address increment. */ +  bgp_aggregate_increment (bgp, p, new, afi, safi); +   +  /* Register new BGP information. */ +  bgp_info_add (rn, new); + +  /* If maximum prefix count is configured and current prefix +     count exeed it. */ +  if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)) +    if (bgp_maximum_prefix_overflow (peer, afi, safi)) +      return -1; + +  /* Process change. */ +  bgp_process (bgp, rn, afi, safi); + +  return 0; + +  /* This BGP update is filtered.  Log the reason then update BGP +     entry.  */ + filtered: +  if (BGP_DEBUG (update, UPDATE_IN)) +    zlog (peer->log, LOG_INFO, +	  "%s rcvd UPDATE about %s/%d -- DENIED due to: %s", +	  peer->host, +	  inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +	  p->prefixlen, reason); + +  if (ri) +    bgp_rib_withdraw (rn, ri, peer, afi, safi, 1); + +  bgp_unlock_node (rn); + +  return 0; +} + +int +bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,  +	     int afi, int safi, int type, int sub_type, struct prefix_rd *prd, +	      u_char *tag) +{ +  struct bgp *bgp; +  char buf[SU_ADDRSTRLEN]; +  struct bgp_node *rn; +  struct bgp_info *ri; + +  bgp = peer->bgp; + +  /* Logging. */ +  if (BGP_DEBUG (update, UPDATE_IN))   +    zlog (peer->log, LOG_INFO, "%s rcvd UPDATE about %s/%d -- withdrawn", +	  peer->host, +	  inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +	  p->prefixlen); + +  /* Lookup node. */ +  rn = bgp_afi_node_get (bgp, afi, safi, p, prd); + +  /* If peer is soft reconfiguration enabled.  Record input packet for +     further calculation. */ +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) +      && peer != bgp->peer_self) +    bgp_adj_in_unset (rn, peer); + +  /* Lookup withdrawn route. */ +  for (ri = rn->info; ri; ri = ri->next) +    if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) +      break; + +  /* Withdraw specified route from routing table. */ +  if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) +    bgp_rib_withdraw (rn, ri, peer, afi, safi, 0); +  else if (BGP_DEBUG (update, UPDATE_IN)) +    zlog (peer->log, LOG_INFO,  +	  "%s Can't find the route %s/%d", peer->host, +	  inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +	  p->prefixlen); + +  /* Unlock bgp_node_get() lock. */ +  bgp_unlock_node (rn); + +  return 0; +} + +void +bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) +{ +  struct bgp *bgp; +  struct attr attr; +  struct aspath *aspath; +  struct prefix p; +  struct bgp_info binfo; +  struct peer *from; +  int ret = RMAP_DENYMATCH; + +  bgp = peer->bgp; +  from = bgp->peer_self; + +  bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); +  aspath = attr.aspath; +  attr.local_pref = bgp->default_local_pref; +  memcpy (&attr.nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN); + +  if (afi == AFI_IP) +    str2prefix ("0.0.0.0/0", &p); +#ifdef HAVE_IPV6 +  else if (afi == AFI_IP6) +    { +      str2prefix ("::/0", &p); + +      /* IPv6 global nexthop must be included. */ +      memcpy (&attr.mp_nexthop_global, &peer->nexthop.v6_global,  +	      IPV6_MAX_BYTELEN); +	      attr.mp_nexthop_len = 16; +  +      /* If the peer is on shared nextwork and we have link-local +	 nexthop set it. */ +      if (peer->shared_network  +	  && !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local)) +	{ +	  memcpy (&attr.mp_nexthop_local, &peer->nexthop.v6_local,  +		  IPV6_MAX_BYTELEN); +	  attr.mp_nexthop_len = 32; +	} +    } +#endif /* HAVE_IPV6 */ +  else +    return; + +  if (peer->default_rmap[afi][safi].name) +    { +      binfo.peer = bgp->peer_self; +      binfo.attr = &attr; + +      ret = route_map_apply (peer->default_rmap[afi][safi].map, &p, +			     RMAP_BGP, &binfo); + +      if (ret == RMAP_DENYMATCH) +	{ +	  bgp_attr_flush (&attr); +	  withdraw = 1; +	} +    } + +  if (withdraw) +    { +      if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) +	bgp_default_withdraw_send (peer, afi, safi); +      UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); +    } +  else +    { +      SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); +      bgp_default_update_send (peer, &attr, afi, safi, from); +    } + +  aspath_unintern (aspath); +} + +static void +bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, +		    struct bgp_table *table) +{ +  struct bgp_node *rn; +  struct bgp_info *ri; +  struct attr attr; + +  if (! table) +    table = peer->bgp->rib[afi][safi]; + +  if (safi != SAFI_MPLS_VPN +      && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) +    bgp_default_originate (peer, afi, safi, 0); + +  for (rn = bgp_table_top (table); rn; rn = bgp_route_next(rn)) +    for (ri = rn->info; ri; ri = ri->next) +      if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->peer != peer) +	{ +	  if (bgp_announce_check (ri, peer, &rn->p, &attr, afi, safi)) +	    bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri); +	  else +	    bgp_adj_out_unset (rn, peer, &rn->p, afi, safi); +	} +} + +void +bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi) +{ +  struct bgp_node *rn; +  struct bgp_table *table; + +  if (peer->status != Established) +    return; + +  if (! peer->afc_nego[afi][safi]) +    return; + +  /* First update is deferred until ORF or ROUTE-REFRESH is received */ +  if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) +    return; + +  if (safi != SAFI_MPLS_VPN) +    bgp_announce_table (peer, afi, safi, NULL); +  else +    for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; +	 rn = bgp_route_next(rn)) +      if ((table = (rn->info)) != NULL) +	bgp_announce_table (peer, afi, safi, table); +} + +void +bgp_announce_route_all (struct peer *peer) +{ +  afi_t afi; +  safi_t safi; +   +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      bgp_announce_route (peer, afi, safi); +} + +static void +bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi, +			 struct bgp_table *table) +{ +  int ret; +  struct bgp_node *rn; +  struct bgp_adj_in *ain; + +  if (! table) +    table = peer->bgp->rib[afi][safi]; + +  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) +    for (ain = rn->adj_in; ain; ain = ain->next) +      { +	if (ain->peer == peer) +	  { +	    ret = bgp_update (peer, &rn->p, ain->attr, afi, safi, +			      ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, +			      NULL, NULL, 1); +	    if (ret < 0) +	      { +		bgp_unlock_node (rn); +		return; +	      } +	    continue; +	  } +      } +} + +void +bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi) +{ +  struct bgp_node *rn; +  struct bgp_table *table; + +  if (peer->status != Established) +    return; + +  if (safi != SAFI_MPLS_VPN) +    bgp_soft_reconfig_table (peer, afi, safi, NULL); +  else +    for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; +	 rn = bgp_route_next (rn)) +      if ((table = rn->info) != NULL) +	bgp_soft_reconfig_table (peer, afi, safi, table); +} + +static void +bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, +		       struct bgp_table *table) +{ +  struct bgp_node *rn; +  struct bgp_adj_in *ain; +  struct bgp_adj_out *aout; +  struct bgp_info *ri; + +  if (! table) +    table = peer->bgp->rib[afi][safi]; + +  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) +    { +      for (ri = rn->info; ri; ri = ri->next) +	if (ri->peer == peer) +	  { +	    bgp_rib_remove (rn, ri, peer, afi, safi); +	    break; +	  } +      for (ain = rn->adj_in; ain; ain = ain->next) +	if (ain->peer == peer) +	  { +	    bgp_adj_in_remove (rn, ain); +	    bgp_unlock_node (rn); +	    break; +	  } +      for (aout = rn->adj_out; aout; aout = aout->next) +	if (aout->peer == peer) +	  { +	    bgp_adj_out_remove (rn, aout, peer, afi, safi); +	    bgp_unlock_node (rn); +	    break; +	  } +    } +} + +void +bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi) +{ +  struct bgp_node *rn; +  struct bgp_table *table; + +  if (! peer->afc[afi][safi]) +    return; + +  if (safi != SAFI_MPLS_VPN) +    bgp_clear_route_table (peer, afi, safi, NULL); +  else +    for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; +	 rn = bgp_route_next (rn)) +      if ((table = rn->info) != NULL) +	bgp_clear_route_table (peer, afi, safi, table); +} +   +void +bgp_clear_route_all (struct peer *peer) +{ +  afi_t afi; +  safi_t safi; + +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      bgp_clear_route (peer, afi, safi); +} + +void +bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi) +{ +  struct bgp_table *table; +  struct bgp_node *rn; +  struct bgp_adj_in *ain; + +  table = peer->bgp->rib[afi][safi]; + +  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) +    for (ain = rn->adj_in; ain ; ain = ain->next) +      if (ain->peer == peer) +	{ +          bgp_adj_in_remove (rn, ain); +          bgp_unlock_node (rn); +          break; +	} +} + +/* Delete all kernel routes. */ +void +bgp_terminate () +{ +  struct bgp *bgp; +  struct listnode *nn; +  struct bgp_node *rn; +  struct bgp_table *table; +  struct bgp_info *ri; + +  LIST_LOOP (bm->bgp, bgp, nn) +    { +      table = bgp->rib[AFI_IP][SAFI_UNICAST]; + +      for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) +	for (ri = rn->info; ri; ri = ri->next) +	  if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) +	      && ri->type == ZEBRA_ROUTE_BGP  +	      && ri->sub_type == BGP_ROUTE_NORMAL) +	    bgp_zebra_withdraw (&rn->p, ri); + +      table = bgp->rib[AFI_IP6][SAFI_UNICAST]; + +      for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) +	for (ri = rn->info; ri; ri = ri->next) +	  if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) +	      && ri->type == ZEBRA_ROUTE_BGP  +	      && ri->sub_type == BGP_ROUTE_NORMAL) +	    bgp_zebra_withdraw (&rn->p, ri); +    } +} + +void +bgp_reset () +{ +  vty_reset (); +  bgp_zclient_reset (); +  access_list_reset (); +  prefix_list_reset (); +} + +/* Parse NLRI stream.  Withdraw NLRI is recognized by NULL attr +   value. */ +int +bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) +{ +  u_char *pnt; +  u_char *lim; +  struct prefix p; +  int psize; +  int ret; + +  /* Check peer status. */ +  if (peer->status != Established) +    return 0; +   +  pnt = packet->nlri; +  lim = pnt + packet->length; + +  for (; pnt < lim; pnt += psize) +    { +      /* Clear prefix structure. */ +      memset (&p, 0, sizeof (struct prefix)); + +      /* Fetch prefix length. */ +      p.prefixlen = *pnt++; +      p.family = afi2family (packet->afi); +       +      /* Already checked in nlri_sanity_check().  We do double check +         here. */ +      if ((packet->afi == AFI_IP && p.prefixlen > 32) +	  || (packet->afi == AFI_IP6 && p.prefixlen > 128)) +	return -1; + +      /* Packet size overflow check. */ +      psize = PSIZE (p.prefixlen); + +      /* When packet overflow occur return immediately. */ +      if (pnt + psize > lim) +	return -1; + +      /* Fetch prefix from NLRI packet. */ +      memcpy (&p.u.prefix, pnt, psize); + +      /* Check address. */ +      if (packet->afi == AFI_IP && packet->safi == SAFI_UNICAST) +	{ +	  if (IN_CLASSD (ntohl (p.u.prefix4.s_addr))) +	    { +	      zlog (peer->log, LOG_ERR,  +		    "IPv4 unicast NLRI is multicast address %s", +		    inet_ntoa (p.u.prefix4)); +	      bgp_notify_send (peer,  +			       BGP_NOTIFY_UPDATE_ERR,  +			       BGP_NOTIFY_UPDATE_INVAL_NETWORK); +	      return -1; +	    } +	} + +#ifdef HAVE_IPV6 +      /* Check address. */ +      if (packet->afi == AFI_IP6 && packet->safi == SAFI_UNICAST) +	{ +	  if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) +	    { +	      char buf[BUFSIZ]; + +	      zlog (peer->log, LOG_WARNING,  +		    "IPv6 link-local NLRI received %s ignore this NLRI", +		    inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ)); + +	      continue; +	    } +	} +#endif /* HAVE_IPV6 */ + +      /* Normal process. */ +      if (attr) +	ret = bgp_update (peer, &p, attr, packet->afi, packet->safi,  +			  ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0); +      else +	ret = bgp_withdraw (peer, &p, attr, packet->afi, packet->safi,  +			    ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL); + +      /* Address family configuration mismatch or maximum-prefix count +         overflow. */ +      if (ret < 0) +	return -1; +    } + +  /* Packet length consistency check. */ +  if (pnt != lim) +    return -1; + +  return 0; +} + +/* NLRI encode syntax check routine. */ +int +bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt, +		       bgp_size_t length) +{ +  u_char *end; +  u_char prefixlen; +  int psize; + +  end = pnt + length; + +  /* RFC1771 6.3 The NLRI field in the UPDATE message is checked for +     syntactic validity.  If the field is syntactically incorrect, +     then the Error Subcode is set to Invalid Network Field. */ + +  while (pnt < end) +    { +      prefixlen = *pnt++; +       +      /* Prefix length check. */ +      if ((afi == AFI_IP && prefixlen > 32) +	  || (afi == AFI_IP6 && prefixlen > 128)) +	{ +	  plog_err (peer->log,  +		    "%s [Error] Update packet error (wrong prefix length %d)", +		    peer->host, prefixlen); +	  bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,  +			   BGP_NOTIFY_UPDATE_INVAL_NETWORK); +	  return -1; +	} + +      /* Packet size overflow check. */ +      psize = PSIZE (prefixlen); + +      if (pnt + psize > end) +	{ +	  plog_err (peer->log,  +		    "%s [Error] Update packet error" +		    " (prefix data overflow prefix size is %d)", +		    peer->host, psize); +	  bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,  +			   BGP_NOTIFY_UPDATE_INVAL_NETWORK); +	  return -1; +	} + +      pnt += psize; +    } + +  /* Packet length consistency check. */ +  if (pnt != end) +    { +      plog_err (peer->log, +		"%s [Error] Update packet error" +		" (prefix length mismatch with total length)", +		peer->host); +      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,  +		       BGP_NOTIFY_UPDATE_INVAL_NETWORK); +      return -1; +    } +  return 0; +} + +struct bgp_static * +bgp_static_new () +{ +  struct bgp_static *new; +  new = XMALLOC (MTYPE_BGP_STATIC, sizeof (struct bgp_static)); +  memset (new, 0, sizeof (struct bgp_static)); +  return new; +} + +void +bgp_static_free (struct bgp_static *bgp_static) +{ +  if (bgp_static->rmap.name) +    free (bgp_static->rmap.name); +  XFREE (MTYPE_BGP_STATIC, bgp_static); +} + +void +bgp_static_update (struct bgp *bgp, struct prefix *p, +		   struct bgp_static *bgp_static, afi_t afi, safi_t safi) +{ +  struct bgp_node *rn; +  struct bgp_info *ri; +  struct bgp_info *new; +  struct bgp_info info; +  struct attr attr; +  struct attr *attr_new; +  int ret; + +  rn = bgp_afi_node_get (bgp, afi, safi, p, NULL); + +  bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); +  if (bgp_static) +    { +      attr.nexthop = bgp_static->igpnexthop; +      attr.med = bgp_static->igpmetric; +      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); +    } + +  /* Apply route-map. */ +  if (bgp_static->rmap.name) +    { +      info.peer = bgp->peer_self; +      info.attr = &attr; + +      ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); +      if (ret == RMAP_DENYMATCH) +	{     +	  /* Free uninterned attribute. */ +	  bgp_attr_flush (&attr); + +	  /* Unintern original. */ +	  aspath_unintern (attr.aspath); +	  bgp_static_withdraw (bgp, p, afi, safi); +	  return; +	} +    } + +  attr_new = bgp_attr_intern (&attr); + +  for (ri = rn->info; ri; ri = ri->next) +    if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP +	&& ri->sub_type == BGP_ROUTE_STATIC) +      break; + +  if (ri) +    { +      if (attrhash_cmp (ri->attr, attr_new)) +	{ +	  bgp_unlock_node (rn); +	  bgp_attr_unintern (attr_new); +	  aspath_unintern (attr.aspath); +	  return; +	} +      else +	{ +	  /* The attribute is changed. */ +	  SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + +	  /* Rewrite BGP route information. */ +	  bgp_aggregate_decrement (bgp, p, ri, afi, safi); +	  bgp_attr_unintern (ri->attr); +	  ri->attr = attr_new; +	  ri->uptime = time (NULL); + +	  /* Process change. */ +	  bgp_aggregate_increment (bgp, p, ri, afi, safi); +	  bgp_process (bgp, rn, afi, safi); +	  bgp_unlock_node (rn); +	  aspath_unintern (attr.aspath); +	  return; +	} +    } + +  /* Make new BGP info. */ +  new = bgp_info_new (); +  new->type = ZEBRA_ROUTE_BGP; +  new->sub_type = BGP_ROUTE_STATIC; +  new->peer = bgp->peer_self; +  SET_FLAG (new->flags, BGP_INFO_VALID); +  new->attr = attr_new; +  new->uptime = time (NULL); + +  /* Aggregate address increment. */ +  bgp_aggregate_increment (bgp, p, new, afi, safi); +   +  /* Register new BGP information. */ +  bgp_info_add (rn, new); + +  /* Process change. */ +  bgp_process (bgp, rn, afi, safi); + +  /* Unintern original. */ +  aspath_unintern (attr.aspath); +} + +void +bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi, +			 u_char safi, struct prefix_rd *prd, u_char *tag) +{ +  struct bgp_node *rn; +  struct bgp_info *new; + +  rn = bgp_afi_node_get (bgp, afi, safi, p, prd); + +  /* Make new BGP info. */ +  new = bgp_info_new (); +  new->type = ZEBRA_ROUTE_BGP; +  new->sub_type = BGP_ROUTE_STATIC; +  new->peer = bgp->peer_self; +  new->attr = bgp_attr_default_intern (BGP_ORIGIN_IGP); +  SET_FLAG (new->flags, BGP_INFO_VALID); +  new->uptime = time (NULL); +  memcpy (new->tag, tag, 3); + +  /* Aggregate address increment. */ +  bgp_aggregate_increment (bgp, p, (struct bgp_info *) new, afi, safi); +   +  /* Register new BGP information. */ +  bgp_info_add (rn, (struct bgp_info *) new); + +  /* Process change. */ +  bgp_process (bgp, rn, afi, safi); +} + +void +bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi, +		     safi_t safi) +{ +  struct bgp_node *rn; +  struct bgp_info *ri; + +  rn = bgp_afi_node_get (bgp, afi, safi, p, NULL); + +  /* Check selected route and self inserted route. */ +  for (ri = rn->info; ri; ri = ri->next) +    if (ri->peer == bgp->peer_self  +	&& ri->type == ZEBRA_ROUTE_BGP +	&& ri->sub_type == BGP_ROUTE_STATIC) +      break; + +  /* Withdraw static BGP route from routing table. */ +  if (ri) +    { +      bgp_aggregate_decrement (bgp, p, ri, afi, safi); +      UNSET_FLAG (ri->flags, BGP_INFO_VALID); +      bgp_process (bgp, rn, afi, safi); +      bgp_info_delete (rn, ri); +      bgp_info_free (ri); +      bgp_unlock_node (rn); +    } + +  /* Unlock bgp_node_lookup. */ +  bgp_unlock_node (rn); +} + +void +bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi, +			   u_char safi, struct prefix_rd *prd, u_char *tag) +{ +  struct bgp_node *rn; +  struct bgp_info *ri; + +  rn = bgp_afi_node_get (bgp, afi, safi, p, prd); + +  /* Check selected route and self inserted route. */ +  for (ri = rn->info; ri; ri = ri->next) +    if (ri->peer == bgp->peer_self  +	&& ri->type == ZEBRA_ROUTE_BGP +	&& ri->sub_type == BGP_ROUTE_STATIC) +      break; + +  /* Withdraw static BGP route from routing table. */ +  if (ri) +    { +      bgp_aggregate_decrement (bgp, p, ri, afi, safi); +      UNSET_FLAG (ri->flags, BGP_INFO_VALID); +      bgp_process (bgp, rn, afi, safi); +      bgp_info_delete (rn, ri); +      bgp_info_free (ri); +      bgp_unlock_node (rn); +    } + +  /* Unlock bgp_node_lookup. */ +  bgp_unlock_node (rn); +} + +/* Configure static BGP network.  When user don't run zebra, static +   route should be installed as valid.  */ +int +bgp_static_set (struct vty *vty, struct bgp *bgp, char *ip_str, u_int16_t afi, +		u_char safi, char *rmap, int backdoor) +{ +  int ret; +  struct prefix p; +  struct bgp_static *bgp_static; +  struct bgp_node *rn; +  int need_update = 0; + +  /* Convert IP prefix string to struct prefix. */ +  ret = str2prefix (ip_str, &p); +  if (! ret) +    { +      vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +#ifdef HAVE_IPV6 +  if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) +    { +      vty_out (vty, "%% Malformed prefix (link-local address)%s", +	       VTY_NEWLINE); +      return CMD_WARNING; +    } +#endif /* HAVE_IPV6 */ + +  apply_mask (&p); + +  /* Set BGP static route configuration. */ +  rn = bgp_node_get (bgp->route[afi][safi], &p); + +  if (rn->info) +    { +      /* Configuration change. */ +      bgp_static = rn->info; + +      /* Check previous routes are installed into BGP.  */ +      if (! bgp_static->backdoor && bgp_static->valid) +	need_update = 1; + +      bgp_static->backdoor = backdoor; +      if (rmap) +	{ +	  if (bgp_static->rmap.name) +	    free (bgp_static->rmap.name); +	  bgp_static->rmap.name = strdup (rmap); +	  bgp_static->rmap.map = route_map_lookup_by_name (rmap); +	} +      else +	{ +	  if (bgp_static->rmap.name) +	    free (bgp_static->rmap.name); +	  bgp_static->rmap.name = NULL; +	  bgp_static->rmap.map = NULL; +	  bgp_static->valid = 0; +	} +      bgp_unlock_node (rn); +    } +  else +    { +      /* New configuration. */ +      bgp_static = bgp_static_new (); +      bgp_static->backdoor = backdoor; +      bgp_static->valid = 0; +      bgp_static->igpmetric = 0; +      bgp_static->igpnexthop.s_addr = 0; +      if (rmap) +	{ +	  if (bgp_static->rmap.name) +	    free (bgp_static->rmap.name); +	  bgp_static->rmap.name = strdup (rmap); +	  bgp_static->rmap.map = route_map_lookup_by_name (rmap); +	} +      rn->info = bgp_static; +    } + +  /* If BGP scan is not enabled, we should install this route here.  */ +  if (! bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) +    { +      bgp_static->valid = 1; + +      if (need_update) +	bgp_static_withdraw (bgp, &p, afi, safi); + +      if (! bgp_static->backdoor) +	bgp_static_update (bgp, &p, bgp_static, afi, safi); +    } + +  return CMD_SUCCESS; +} + +/* Configure static BGP network. */ +int +bgp_static_unset (struct vty *vty, struct bgp *bgp, char *ip_str, +		  u_int16_t afi, u_char safi) +{ +  int ret; +  struct prefix p; +  struct bgp_static *bgp_static; +  struct bgp_node *rn; + +  /* Convert IP prefix string to struct prefix. */ +  ret = str2prefix (ip_str, &p); +  if (! ret) +    { +      vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +#ifdef HAVE_IPV6 +  if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) +    { +      vty_out (vty, "%% Malformed prefix (link-local address)%s", +	       VTY_NEWLINE); +      return CMD_WARNING; +    } +#endif /* HAVE_IPV6 */ + +  apply_mask (&p); + +  rn = bgp_node_lookup (bgp->route[afi][safi], &p); +  if (! rn) +    { +      vty_out (vty, "%% Can't find specified static route configuration.%s", +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_static = rn->info; + +  /* Update BGP RIB. */ +  if (! bgp_static->backdoor) +    bgp_static_withdraw (bgp, &p, afi, safi); + +  /* Clear configuration. */ +  bgp_static_free (bgp_static); +  rn->info = NULL; +  bgp_unlock_node (rn); +  bgp_unlock_node (rn); + +  return CMD_SUCCESS; +} + +/* Called from bgp_delete().  Delete all static routes from the BGP +   instance. */ +void +bgp_static_delete (struct bgp *bgp) +{ +  afi_t afi; +  safi_t safi; +  struct bgp_node *rn; +  struct bgp_node *rm; +  struct bgp_table *table; +  struct bgp_static *bgp_static; + +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) +	if (rn->info != NULL) +	  {       +	    if (safi == SAFI_MPLS_VPN) +	      { +		table = rn->info; + +		for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) +		  { +		    bgp_static = rn->info; +		    bgp_static_withdraw_vpnv4 (bgp, &rm->p, +					       AFI_IP, SAFI_MPLS_VPN, +					       (struct prefix_rd *)&rn->p, +					       bgp_static->tag); +		    bgp_static_free (bgp_static); +		    rn->info = NULL; +		    bgp_unlock_node (rn); +		  } +	      } +	    else +	      { +		bgp_static = rn->info; +		bgp_static_withdraw (bgp, &rn->p, afi, safi); +		bgp_static_free (bgp_static); +		rn->info = NULL; +		bgp_unlock_node (rn); +	      } +	  } +} + +int +bgp_static_set_vpnv4 (struct vty *vty, char *ip_str, char *rd_str, +		      char *tag_str) +{ +  int ret; +  struct prefix p; +  struct prefix_rd prd; +  struct bgp *bgp; +  struct bgp_node *prn; +  struct bgp_node *rn; +  struct bgp_table *table; +  struct bgp_static *bgp_static; +  u_char tag[3]; + +  bgp = vty->index; + +  ret = str2prefix (ip_str, &p); +  if (! ret) +    { +      vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  apply_mask (&p); + +  ret = str2prefix_rd (rd_str, &prd); +  if (! ret) +    { +      vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  ret = str2tag (tag_str, tag); +  if (! ret) +    { +      vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN], +			(struct prefix *)&prd); +  if (prn->info == NULL) +    prn->info = bgp_table_init (); +  else +    bgp_unlock_node (prn); +  table = prn->info; + +  rn = bgp_node_get (table, &p); + +  if (rn->info) +    { +      vty_out (vty, "%% Same network configuration exists%s", VTY_NEWLINE); +      bgp_unlock_node (rn); +    } +  else +    { +      /* New configuration. */ +      bgp_static = bgp_static_new (); +      bgp_static->valid = 1; +      memcpy (bgp_static->tag, tag, 3); +      rn->info = bgp_static; + +      bgp_static_update_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag); +    } + +  return CMD_SUCCESS; +} + +/* Configure static BGP network. */ +int +bgp_static_unset_vpnv4 (struct vty *vty, char *ip_str, char *rd_str, +			char *tag_str) +{ +  int ret; +  struct bgp *bgp; +  struct prefix p; +  struct prefix_rd prd; +  struct bgp_node *prn; +  struct bgp_node *rn; +  struct bgp_table *table; +  struct bgp_static *bgp_static; +  u_char tag[3]; + +  bgp = vty->index; + +  /* Convert IP prefix string to struct prefix. */ +  ret = str2prefix (ip_str, &p); +  if (! ret) +    { +      vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  apply_mask (&p); + +  ret = str2prefix_rd (rd_str, &prd); +  if (! ret) +    { +      vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  ret = str2tag (tag_str, tag); +  if (! ret) +    { +      vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN], +			(struct prefix *)&prd); +  if (prn->info == NULL) +    prn->info = bgp_table_init (); +  else +    bgp_unlock_node (prn); +  table = prn->info; + +  rn = bgp_node_lookup (table, &p); + +  if (rn) +    { +      bgp_static_withdraw_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag); + +      bgp_static = rn->info; +      bgp_static_free (bgp_static); +      rn->info = NULL; +      bgp_unlock_node (rn); +      bgp_unlock_node (rn); +    } +  else +    vty_out (vty, "%% Can't find the route%s", VTY_NEWLINE); + +  return CMD_SUCCESS; +} + +DEFUN (bgp_network, +       bgp_network_cmd, +       "network A.B.C.D/M", +       "Specify a network to announce via BGP\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +{ +  return bgp_static_set (vty, vty->index, argv[0], +			 AFI_IP, bgp_node_safi (vty), NULL, 0); +} + +DEFUN (bgp_network_route_map, +       bgp_network_route_map_cmd, +       "network A.B.C.D/M route-map WORD", +       "Specify a network to announce via BGP\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" +       "Route-map to modify the attributes\n" +       "Name of the route map\n") +{ +  return bgp_static_set (vty, vty->index, argv[0], +			 AFI_IP, bgp_node_safi (vty), argv[1], 0); +} + +DEFUN (bgp_network_backdoor, +       bgp_network_backdoor_cmd, +       "network A.B.C.D/M backdoor", +       "Specify a network to announce via BGP\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" +       "Specify a BGP backdoor route\n") +{ +  return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (bgp_network_mask, +       bgp_network_mask_cmd, +       "network A.B.C.D mask A.B.C.D", +       "Specify a network to announce via BGP\n" +       "Network number\n" +       "Network mask\n" +       "Network mask\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_static_set (vty, vty->index, prefix_str, +			 AFI_IP, bgp_node_safi (vty), NULL, 0); +} + +DEFUN (bgp_network_mask_route_map, +       bgp_network_mask_route_map_cmd, +       "network A.B.C.D mask A.B.C.D route-map WORD", +       "Specify a network to announce via BGP\n" +       "Network number\n" +       "Network mask\n" +       "Network mask\n" +       "Route-map to modify the attributes\n" +       "Name of the route map\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_static_set (vty, vty->index, prefix_str, +			 AFI_IP, bgp_node_safi (vty), argv[2], 0); +} + +DEFUN (bgp_network_mask_backdoor, +       bgp_network_mask_backdoor_cmd, +       "network A.B.C.D mask A.B.C.D backdoor", +       "Specify a network to announce via BGP\n" +       "Network number\n" +       "Network mask\n" +       "Network mask\n" +       "Specify a BGP backdoor route\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (bgp_network_mask_natural, +       bgp_network_mask_natural_cmd, +       "network A.B.C.D", +       "Specify a network to announce via BGP\n" +       "Network number\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_static_set (vty, vty->index, prefix_str, +			 AFI_IP, bgp_node_safi (vty), NULL, 0); +} + +DEFUN (bgp_network_mask_natural_route_map, +       bgp_network_mask_natural_route_map_cmd, +       "network A.B.C.D route-map WORD", +       "Specify a network to announce via BGP\n" +       "Network number\n" +       "Route-map to modify the attributes\n" +       "Name of the route map\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_static_set (vty, vty->index, prefix_str, +			 AFI_IP, bgp_node_safi (vty), argv[1], 0); +} + +DEFUN (bgp_network_mask_natural_backdoor, +       bgp_network_mask_natural_backdoor_cmd, +       "network A.B.C.D backdoor", +       "Specify a network to announce via BGP\n" +       "Network number\n" +       "Specify a BGP backdoor route\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (no_bgp_network, +       no_bgp_network_cmd, +       "no network A.B.C.D/M", +       NO_STR +       "Specify a network to announce via BGP\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +{ +  return bgp_static_unset (vty, vty->index, argv[0], AFI_IP,  +			   bgp_node_safi (vty)); +} + +ALIAS (no_bgp_network, +       no_bgp_network_route_map_cmd, +       "no network A.B.C.D/M route-map WORD", +       NO_STR +       "Specify a network to announce via BGP\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" +       "Route-map to modify the attributes\n" +       "Name of the route map\n") + +ALIAS (no_bgp_network, +       no_bgp_network_backdoor_cmd, +       "no network A.B.C.D/M backdoor", +       NO_STR +       "Specify a network to announce via BGP\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" +       "Specify a BGP backdoor route\n") + +DEFUN (no_bgp_network_mask, +       no_bgp_network_mask_cmd, +       "no network A.B.C.D mask A.B.C.D", +       NO_STR +       "Specify a network to announce via BGP\n" +       "Network number\n" +       "Network mask\n" +       "Network mask\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP,  +			   bgp_node_safi (vty)); +} + +ALIAS (no_bgp_network_mask, +       no_bgp_network_mask_route_map_cmd, +       "no network A.B.C.D mask A.B.C.D route-map WORD", +       NO_STR +       "Specify a network to announce via BGP\n" +       "Network number\n" +       "Network mask\n" +       "Network mask\n" +       "Route-map to modify the attributes\n" +       "Name of the route map\n") + +ALIAS (no_bgp_network_mask, +       no_bgp_network_mask_backdoor_cmd, +       "no network A.B.C.D mask A.B.C.D backdoor", +       NO_STR +       "Specify a network to announce via BGP\n" +       "Network number\n" +       "Network mask\n" +       "Network mask\n" +       "Specify a BGP backdoor route\n") + +DEFUN (no_bgp_network_mask_natural, +       no_bgp_network_mask_natural_cmd, +       "no network A.B.C.D", +       NO_STR +       "Specify a network to announce via BGP\n" +       "Network number\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP,  +			   bgp_node_safi (vty)); +} + +ALIAS (no_bgp_network_mask_natural, +       no_bgp_network_mask_natural_route_map_cmd, +       "no network A.B.C.D route-map WORD", +       NO_STR +       "Specify a network to announce via BGP\n" +       "Network number\n" +       "Route-map to modify the attributes\n" +       "Name of the route map\n") + +ALIAS (no_bgp_network_mask_natural, +       no_bgp_network_mask_natural_backdoor_cmd, +       "no network A.B.C.D backdoor", +       NO_STR +       "Specify a network to announce via BGP\n" +       "Network number\n" +       "Specify a BGP backdoor route\n") + +#ifdef HAVE_IPV6 +DEFUN (ipv6_bgp_network, +       ipv6_bgp_network_cmd, +       "network X:X::X:X/M", +       "Specify a network to announce via BGP\n" +       "IPv6 prefix <network>/<length>\n") +{ +  return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +DEFUN (ipv6_bgp_network_route_map, +       ipv6_bgp_network_route_map_cmd, +       "network X:X::X:X/M route-map WORD", +       "Specify a network to announce via BGP\n" +       "IPv6 prefix <network>/<length>\n" +       "Route-map to modify the attributes\n" +       "Name of the route map\n") +{ +  return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, +			 bgp_node_safi (vty), argv[1], 0); +} + +DEFUN (no_ipv6_bgp_network, +       no_ipv6_bgp_network_cmd, +       "no network X:X::X:X/M", +       NO_STR +       "Specify a network to announce via BGP\n" +       "IPv6 prefix <network>/<length>\n") +{ +  return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST); +} + +ALIAS (no_ipv6_bgp_network, +       no_ipv6_bgp_network_route_map_cmd, +       "no network X:X::X:X/M route-map WORD", +       NO_STR +       "Specify a network to announce via BGP\n" +       "IPv6 prefix <network>/<length>\n" +       "Route-map to modify the attributes\n" +       "Name of the route map\n") + +ALIAS (ipv6_bgp_network, +       old_ipv6_bgp_network_cmd, +       "ipv6 bgp network X:X::X:X/M", +       IPV6_STR +       BGP_STR +       "Specify a network to announce via BGP\n" +       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n") + +ALIAS (no_ipv6_bgp_network, +       old_no_ipv6_bgp_network_cmd, +       "no ipv6 bgp network X:X::X:X/M", +       NO_STR +       IPV6_STR +       BGP_STR +       "Specify a network to announce via BGP\n" +       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n") +#endif /* HAVE_IPV6 */ + +/* Aggreagete address: + +  advertise-map  Set condition to advertise attribute +  as-set         Generate AS set path information +  attribute-map  Set attributes of aggregate +  route-map      Set parameters of aggregate +  summary-only   Filter more specific routes from updates +  suppress-map   Conditionally filter more specific routes from updates +  <cr> + */ +struct bgp_aggregate +{ +  /* Summary-only flag. */ +  u_char summary_only; + +  /* AS set generation. */ +  u_char as_set; + +  /* Route-map for aggregated route. */ +  struct route_map *map; + +  /* Suppress-count. */ +  unsigned long count; + +  /* SAFI configuration. */ +  safi_t safi; +}; + +struct bgp_aggregate * +bgp_aggregate_new () +{ +  struct bgp_aggregate *new; +  new = XMALLOC (MTYPE_BGP_AGGREGATE, sizeof (struct bgp_aggregate)); +  memset (new, 0, sizeof (struct bgp_aggregate)); +  return new; +} + +void +bgp_aggregate_free (struct bgp_aggregate *aggregate) +{ +  XFREE (MTYPE_BGP_AGGREGATE, aggregate); +}      + +void +bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, +		     afi_t afi, safi_t safi, struct bgp_info *del,  +		     struct bgp_aggregate *aggregate) +{ +  struct bgp_table *table; +  struct bgp_node *top; +  struct bgp_node *rn; +  u_char origin; +  struct aspath *aspath = NULL; +  struct aspath *asmerge = NULL; +  struct community *community = NULL; +  struct community *commerge = NULL; +  struct in_addr nexthop; +  u_int32_t med = 0; +  struct bgp_info *ri; +  struct bgp_info *new; +  int first = 1; +  unsigned long match = 0; + +  /* Record adding route's nexthop and med. */ +  if (rinew) +    { +      nexthop = rinew->attr->nexthop; +      med = rinew->attr->med; +    } + +  /* ORIGIN attribute: If at least one route among routes that are +     aggregated has ORIGIN with the value INCOMPLETE, then the +     aggregated route must have the ORIGIN attribute with the value +     INCOMPLETE. Otherwise, if at least one route among routes that +     are aggregated has ORIGIN with the value EGP, then the aggregated +     route must have the origin attribute with the value EGP. In all +     other case the value of the ORIGIN attribute of the aggregated +     route is INTERNAL. */ +  origin = BGP_ORIGIN_IGP; + +  table = bgp->rib[afi][safi]; + +  top = bgp_node_get (table, p); +  for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) +    if (rn->p.prefixlen > p->prefixlen) +      { +	match = 0; + +	for (ri = rn->info; ri; ri = ri->next) +	  { +	    if (BGP_INFO_HOLDDOWN (ri)) +	      continue; + +	    if (del && ri == del) +	      continue; + +	    if (! rinew && first) +	      { +		nexthop = ri->attr->nexthop; +		med = ri->attr->med; +		first = 0; +	      } + +#ifdef AGGREGATE_NEXTHOP_CHECK +	    if (! IPV4_ADDR_SAME (&ri->attr->nexthop, &nexthop) +		|| ri->attr->med != med) +	      { +		if (aspath) +		  aspath_free (aspath); +		if (community) +		  community_free (community); +		bgp_unlock_node (rn); +		bgp_unlock_node (top); +		return; +	      } +#endif /* AGGREGATE_NEXTHOP_CHECK */ + +	    if (ri->sub_type != BGP_ROUTE_AGGREGATE) +	      { +		if (aggregate->summary_only) +		  { +		    ri->suppress++; +		    SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); +		    match++; +		  } + +		aggregate->count++; + +		if (aggregate->as_set) +		  { +		    if (origin < ri->attr->origin) +		      origin = ri->attr->origin; + +		    if (aspath) +		      { +			asmerge = aspath_aggregate (aspath, ri->attr->aspath); +			aspath_free (aspath); +			aspath = asmerge; +		      } +		    else +		      aspath = aspath_dup (ri->attr->aspath); + +		    if (ri->attr->community) +		      { +			if (community) +			  { +			    commerge = community_merge (community, +							ri->attr->community); +			    community = community_uniq_sort (commerge); +			    community_free (commerge); +			  } +			else +			  community = community_dup (ri->attr->community); +		      } +		  } +	      } +	  } +	if (match) +	  bgp_process (bgp, rn, afi, safi); +      } +  bgp_unlock_node (top); + +  if (rinew) +    { +      aggregate->count++; +       +      if (aggregate->summary_only) +	rinew->suppress++; + +      if (aggregate->as_set) +	{ +	  if (origin < rinew->attr->origin) +	    origin = rinew->attr->origin; + +	  if (aspath) +	    { +	      asmerge = aspath_aggregate (aspath, rinew->attr->aspath); +	      aspath_free (aspath); +	      aspath = asmerge; +	    } +	  else +	    aspath = aspath_dup (rinew->attr->aspath); + +	  if (rinew->attr->community) +	    { +	      if (community) +		{ +		  commerge = community_merge (community, +					      rinew->attr->community); +		  community = community_uniq_sort (commerge); +		  community_free (commerge); +		} +	      else +		community = community_dup (rinew->attr->community); +	    } +	} +    } + +  if (aggregate->count > 0) +    { +      rn = bgp_node_get (table, p); +      new = bgp_info_new (); +      new->type = ZEBRA_ROUTE_BGP; +      new->sub_type = BGP_ROUTE_AGGREGATE; +      new->peer = bgp->peer_self; +      SET_FLAG (new->flags, BGP_INFO_VALID); +      new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set); +      new->uptime = time (NULL); + +      bgp_info_add (rn, new); +      bgp_process (bgp, rn, afi, safi); +    } +  else +    { +      if (aspath) +	aspath_free (aspath); +      if (community) +	community_free (community); +    } +} + +void bgp_aggregate_delete (struct bgp *, struct prefix *, afi_t, safi_t, +			   struct bgp_aggregate *); + +void +bgp_aggregate_increment (struct bgp *bgp, struct prefix *p, +			 struct bgp_info *ri, afi_t afi, safi_t safi) +{ +  struct bgp_node *child; +  struct bgp_node *rn; +  struct bgp_aggregate *aggregate; + +  /* MPLS-VPN aggregation is not yet supported. */ +  if (safi == SAFI_MPLS_VPN) +    return; + +  if (p->prefixlen == 0) +    return; + +  if (BGP_INFO_HOLDDOWN (ri)) +    return; + +  child = bgp_node_get (bgp->aggregate[afi][safi], p); + +  /* Aggregate address configuration check. */ +  for (rn = child; rn; rn = rn->parent) +    if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen) +      { +	bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate); +	bgp_aggregate_route (bgp, &rn->p, ri, safi, safi, NULL, aggregate); +      } +  bgp_unlock_node (child); +} + +void +bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p,  +			 struct bgp_info *del, afi_t afi, safi_t safi) +{ +  struct bgp_node *child; +  struct bgp_node *rn; +  struct bgp_aggregate *aggregate; + +  /* MPLS-VPN aggregation is not yet supported. */ +  if (safi == SAFI_MPLS_VPN) +    return; + +  if (p->prefixlen == 0) +    return; + +  child = bgp_node_get (bgp->aggregate[afi][safi], p); + +  /* Aggregate address configuration check. */ +  for (rn = child; rn; rn = rn->parent) +    if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen) +      { +	bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate); +	bgp_aggregate_route (bgp, &rn->p, NULL, safi, safi, del, aggregate); +      } +  bgp_unlock_node (child); +} + +void +bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, +		   struct bgp_aggregate *aggregate) +{ +  struct bgp_table *table; +  struct bgp_node *top; +  struct bgp_node *rn; +  struct bgp_info *new; +  struct bgp_info *ri; +  unsigned long match; +  u_char origin = BGP_ORIGIN_IGP; +  struct aspath *aspath = NULL; +  struct aspath *asmerge = NULL; +  struct community *community = NULL; +  struct community *commerge = NULL; + +  table = bgp->rib[afi][safi]; + +  /* Sanity check. */ +  if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN) +    return; +  if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN) +    return; +     +  /* If routes exists below this node, generate aggregate routes. */ +  top = bgp_node_get (table, p); +  for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) +    if (rn->p.prefixlen > p->prefixlen) +      { +	match = 0; + +	for (ri = rn->info; ri; ri = ri->next) +	  { +	    if (BGP_INFO_HOLDDOWN (ri)) +	      continue; + +	    if (ri->sub_type != BGP_ROUTE_AGGREGATE) +	      { +		/* summary-only aggregate route suppress aggregated +		   route announcement.  */ +		if (aggregate->summary_only) +		  { +		    ri->suppress++; +		    SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); +		    match++; +		  } +		/* as-set aggregate route generate origin, as path, +		   community aggregation.  */ +		if (aggregate->as_set) +		  { +		    if (origin < ri->attr->origin) +		      origin = ri->attr->origin; + +		    if (aspath) +		      { +			asmerge = aspath_aggregate (aspath, ri->attr->aspath); +			aspath_free (aspath); +			aspath = asmerge; +		      } +		    else +		      aspath = aspath_dup (ri->attr->aspath); + +		    if (ri->attr->community) +		      { +			if (community) +			  { +			    commerge = community_merge (community, +							ri->attr->community); +			    community = community_uniq_sort (commerge); +			    community_free (commerge); +			  } +			else +			  community = community_dup (ri->attr->community); +		      } +		  } +		aggregate->count++; +	      } +	  } +	 +	/* If this node is suppressed, process the change. */ +	if (match) +	  bgp_process (bgp, rn, afi, safi); +      } +  bgp_unlock_node (top); + +  /* Add aggregate route to BGP table. */ +  if (aggregate->count) +    { +      rn = bgp_node_get (table, p); + +      new = bgp_info_new (); +      new->type = ZEBRA_ROUTE_BGP; +      new->sub_type = BGP_ROUTE_AGGREGATE; +      new->peer = bgp->peer_self; +      SET_FLAG (new->flags, BGP_INFO_VALID); +      new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set); +      new->uptime = time (NULL); + +      bgp_info_add (rn, new); + +      /* Process change. */ +      bgp_process (bgp, rn, afi, safi); +    } +} + +void +bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi,  +		      safi_t safi, struct bgp_aggregate *aggregate) +{ +  struct bgp_table *table; +  struct bgp_node *top; +  struct bgp_node *rn; +  struct bgp_info *ri; +  unsigned long match; + +  table = bgp->rib[afi][safi]; + +  if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN) +    return; +  if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN) +    return; + +  /* If routes exists below this node, generate aggregate routes. */ +  top = bgp_node_get (table, p); +  for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) +    if (rn->p.prefixlen > p->prefixlen) +      { +	match = 0; + +	for (ri = rn->info; ri; ri = ri->next) +	  { +	    if (BGP_INFO_HOLDDOWN (ri)) +	      continue; + +	    if (ri->sub_type != BGP_ROUTE_AGGREGATE) +	      { +		if (aggregate->summary_only) +		  { +		    ri->suppress--; + +		    if (ri->suppress == 0) +		      { +			SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); +			match++; +		      } +		  } +		aggregate->count--; +	      } +	  } + +	/* If this node is suppressed, process the change. */ +	if (match) +	  bgp_process (bgp, rn, afi, safi); +      } +  bgp_unlock_node (top); + +  /* Delete aggregate route from BGP table. */ +  rn = bgp_node_get (table, p); + +  for (ri = rn->info; ri; ri = ri->next) +    if (ri->peer == bgp->peer_self  +	&& ri->type == ZEBRA_ROUTE_BGP +	&& ri->sub_type == BGP_ROUTE_AGGREGATE) +      break; + +  /* Withdraw static BGP route from routing table. */ +  if (ri) +    { +      UNSET_FLAG (ri->flags, BGP_INFO_VALID); +      bgp_process (bgp, rn, afi, safi); +      bgp_info_delete (rn, ri); +      bgp_info_free (ri); +      bgp_unlock_node (rn); +    } + +  /* Unlock bgp_node_lookup. */ +  bgp_unlock_node (rn); +} + +/* Aggregate route attribute. */ +#define AGGREGATE_SUMMARY_ONLY 1 +#define AGGREGATE_AS_SET       1 + +int +bgp_aggregate_set (struct vty *vty, char *prefix_str, afi_t afi, safi_t safi, +		   u_char summary_only, u_char as_set) +{ +  int ret; +  struct prefix p; +  struct bgp_node *rn; +  struct bgp *bgp; +  struct bgp_aggregate *aggregate; + +  /* Convert string to prefix structure. */ +  ret = str2prefix (prefix_str, &p); +  if (!ret) +    { +      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  apply_mask (&p); + +  /* Get BGP structure. */ +  bgp = vty->index; + +  /* Old configuration check. */ +  rn = bgp_node_get (bgp->aggregate[afi][safi], &p); + +  if (rn->info) +    { +      vty_out (vty, "There is already same aggregate network.%s", VTY_NEWLINE); +      bgp_unlock_node (rn); +      return CMD_WARNING; +    } + +  /* Make aggregate address structure. */ +  aggregate = bgp_aggregate_new (); +  aggregate->summary_only = summary_only; +  aggregate->as_set = as_set; +  aggregate->safi = safi; +  rn->info = aggregate; + +  /* Aggregate address insert into BGP routing table. */ +  if (safi & SAFI_UNICAST) +    bgp_aggregate_add (bgp, &p, afi, SAFI_UNICAST, aggregate); +  if (safi & SAFI_MULTICAST) +    bgp_aggregate_add (bgp, &p, afi, SAFI_MULTICAST, aggregate); + +  return CMD_SUCCESS; +} + +int +bgp_aggregate_unset (struct vty *vty, char *prefix_str, afi_t afi, safi_t safi) +{ +  int ret; +  struct prefix p; +  struct bgp_node *rn; +  struct bgp *bgp; +  struct bgp_aggregate *aggregate; + +  /* Convert string to prefix structure. */ +  ret = str2prefix (prefix_str, &p); +  if (!ret) +    { +      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  apply_mask (&p); + +  /* Get BGP structure. */ +  bgp = vty->index; + +  /* Old configuration check. */ +  rn = bgp_node_lookup (bgp->aggregate[afi][safi], &p); +  if (! rn) +    { +      vty_out (vty, "%% There is no aggregate-address configuration.%s", +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  aggregate = rn->info; +  if (aggregate->safi & SAFI_UNICAST) +    bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate); +  if (aggregate->safi & SAFI_MULTICAST) +    bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate); + +  /* Unlock aggregate address configuration. */ +  rn->info = NULL; +  bgp_aggregate_free (aggregate); +  bgp_unlock_node (rn); +  bgp_unlock_node (rn); + +  return CMD_SUCCESS; +} + +DEFUN (aggregate_address, +       aggregate_address_cmd, +       "aggregate-address A.B.C.D/M", +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n") +{ +  return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), 0, 0); +} + +DEFUN (aggregate_address_mask, +       aggregate_address_mask_cmd, +       "aggregate-address A.B.C.D A.B.C.D", +       "Configure BGP aggregate entries\n" +       "Aggregate address\n" +       "Aggregate mask\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty), +			    0, 0); +} + +DEFUN (aggregate_address_summary_only, +       aggregate_address_summary_only_cmd, +       "aggregate-address A.B.C.D/M summary-only", +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n" +       "Filter more specific routes from updates\n") +{ +  return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), +			    AGGREGATE_SUMMARY_ONLY, 0); +} + +DEFUN (aggregate_address_mask_summary_only, +       aggregate_address_mask_summary_only_cmd, +       "aggregate-address A.B.C.D A.B.C.D summary-only", +       "Configure BGP aggregate entries\n" +       "Aggregate address\n" +       "Aggregate mask\n" +       "Filter more specific routes from updates\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty), +			    AGGREGATE_SUMMARY_ONLY, 0); +} + +DEFUN (aggregate_address_as_set, +       aggregate_address_as_set_cmd, +       "aggregate-address A.B.C.D/M as-set", +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n" +       "Generate AS set path information\n") +{ +  return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), +			    0, AGGREGATE_AS_SET); +} + +DEFUN (aggregate_address_mask_as_set, +       aggregate_address_mask_as_set_cmd, +       "aggregate-address A.B.C.D A.B.C.D as-set", +       "Configure BGP aggregate entries\n" +       "Aggregate address\n" +       "Aggregate mask\n" +       "Generate AS set path information\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty), +			    0, AGGREGATE_AS_SET); +} + + +DEFUN (aggregate_address_as_set_summary, +       aggregate_address_as_set_summary_cmd, +       "aggregate-address A.B.C.D/M as-set summary-only", +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n" +       "Generate AS set path information\n" +       "Filter more specific routes from updates\n") +{ +  return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), +			    AGGREGATE_SUMMARY_ONLY, AGGREGATE_AS_SET); +} + +ALIAS (aggregate_address_as_set_summary, +       aggregate_address_summary_as_set_cmd, +       "aggregate-address A.B.C.D/M summary-only as-set", +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n" +       "Filter more specific routes from updates\n" +       "Generate AS set path information\n") + +DEFUN (aggregate_address_mask_as_set_summary, +       aggregate_address_mask_as_set_summary_cmd, +       "aggregate-address A.B.C.D A.B.C.D as-set summary-only", +       "Configure BGP aggregate entries\n" +       "Aggregate address\n" +       "Aggregate mask\n" +       "Generate AS set path information\n" +       "Filter more specific routes from updates\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty), +			    AGGREGATE_SUMMARY_ONLY, AGGREGATE_AS_SET); +} + +ALIAS (aggregate_address_mask_as_set_summary, +       aggregate_address_mask_summary_as_set_cmd, +       "aggregate-address A.B.C.D A.B.C.D summary-only as-set", +       "Configure BGP aggregate entries\n" +       "Aggregate address\n" +       "Aggregate mask\n" +       "Filter more specific routes from updates\n" +       "Generate AS set path information\n") + +DEFUN (no_aggregate_address, +       no_aggregate_address_cmd, +       "no aggregate-address A.B.C.D/M", +       NO_STR +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n") +{ +  return bgp_aggregate_unset (vty, argv[0], AFI_IP, bgp_node_safi (vty)); +} + +ALIAS (no_aggregate_address, +       no_aggregate_address_summary_only_cmd, +       "no aggregate-address A.B.C.D/M summary-only", +       NO_STR +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n" +       "Filter more specific routes from updates\n") + +ALIAS (no_aggregate_address, +       no_aggregate_address_as_set_cmd, +       "no aggregate-address A.B.C.D/M as-set", +       NO_STR +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n" +       "Generate AS set path information\n") + +ALIAS (no_aggregate_address, +       no_aggregate_address_as_set_summary_cmd, +       "no aggregate-address A.B.C.D/M as-set summary-only", +       NO_STR +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n" +       "Generate AS set path information\n" +       "Filter more specific routes from updates\n") + +ALIAS (no_aggregate_address, +       no_aggregate_address_summary_as_set_cmd, +       "no aggregate-address A.B.C.D/M summary-only as-set", +       NO_STR +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n" +       "Filter more specific routes from updates\n" +       "Generate AS set path information\n") + +DEFUN (no_aggregate_address_mask, +       no_aggregate_address_mask_cmd, +       "no aggregate-address A.B.C.D A.B.C.D", +       NO_STR +       "Configure BGP aggregate entries\n" +       "Aggregate address\n" +       "Aggregate mask\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); + +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_aggregate_unset (vty, prefix_str, AFI_IP, bgp_node_safi (vty)); +} + +ALIAS (no_aggregate_address_mask, +       no_aggregate_address_mask_summary_only_cmd, +       "no aggregate-address A.B.C.D A.B.C.D summary-only", +       NO_STR +       "Configure BGP aggregate entries\n" +       "Aggregate address\n" +       "Aggregate mask\n" +       "Filter more specific routes from updates\n") + +ALIAS (no_aggregate_address_mask, +       no_aggregate_address_mask_as_set_cmd, +       "no aggregate-address A.B.C.D A.B.C.D as-set", +       NO_STR +       "Configure BGP aggregate entries\n" +       "Aggregate address\n" +       "Aggregate mask\n" +       "Generate AS set path information\n") + +ALIAS (no_aggregate_address_mask, +       no_aggregate_address_mask_as_set_summary_cmd, +       "no aggregate-address A.B.C.D A.B.C.D as-set summary-only", +       NO_STR +       "Configure BGP aggregate entries\n" +       "Aggregate address\n" +       "Aggregate mask\n" +       "Generate AS set path information\n" +       "Filter more specific routes from updates\n") + +ALIAS (no_aggregate_address_mask, +       no_aggregate_address_mask_summary_as_set_cmd, +       "no aggregate-address A.B.C.D A.B.C.D summary-only as-set", +       NO_STR +       "Configure BGP aggregate entries\n" +       "Aggregate address\n" +       "Aggregate mask\n" +       "Filter more specific routes from updates\n" +       "Generate AS set path information\n") + +#ifdef HAVE_IPV6 +DEFUN (ipv6_aggregate_address, +       ipv6_aggregate_address_cmd, +       "aggregate-address X:X::X:X/M", +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n") +{ +  return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST, 0, 0); +} + +DEFUN (ipv6_aggregate_address_summary_only, +       ipv6_aggregate_address_summary_only_cmd, +       "aggregate-address X:X::X:X/M summary-only", +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n" +       "Filter more specific routes from updates\n") +{ +  return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST,  +			    AGGREGATE_SUMMARY_ONLY, 0); +} + +DEFUN (no_ipv6_aggregate_address, +       no_ipv6_aggregate_address_cmd, +       "no aggregate-address X:X::X:X/M", +       NO_STR +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n") +{ +  return bgp_aggregate_unset (vty, argv[0], AFI_IP6, SAFI_UNICAST); +} + +DEFUN (no_ipv6_aggregate_address_summary_only, +       no_ipv6_aggregate_address_summary_only_cmd, +       "no aggregate-address X:X::X:X/M summary-only", +       NO_STR +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n" +       "Filter more specific routes from updates\n") +{ +  return bgp_aggregate_unset (vty, argv[0], AFI_IP6, SAFI_UNICAST); +} + +ALIAS (ipv6_aggregate_address, +       old_ipv6_aggregate_address_cmd, +       "ipv6 bgp aggregate-address X:X::X:X/M", +       IPV6_STR +       BGP_STR +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n") + +ALIAS (ipv6_aggregate_address_summary_only, +       old_ipv6_aggregate_address_summary_only_cmd, +       "ipv6 bgp aggregate-address X:X::X:X/M summary-only", +       IPV6_STR +       BGP_STR +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n" +       "Filter more specific routes from updates\n") + +ALIAS (no_ipv6_aggregate_address, +       old_no_ipv6_aggregate_address_cmd, +       "no ipv6 bgp aggregate-address X:X::X:X/M", +       NO_STR +       IPV6_STR +       BGP_STR +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n") + +ALIAS (no_ipv6_aggregate_address_summary_only, +       old_no_ipv6_aggregate_address_summary_only_cmd, +       "no ipv6 bgp aggregate-address X:X::X:X/M summary-only", +       NO_STR +       IPV6_STR +       BGP_STR +       "Configure BGP aggregate entries\n" +       "Aggregate prefix\n" +       "Filter more specific routes from updates\n") +#endif /* HAVE_IPV6 */ + +/* Redistribute route treatment. */ +void +bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, +		      u_int32_t metric, u_char type) +{ +  struct bgp *bgp; +  struct listnode *nn; +  struct bgp_info *new; +  struct bgp_info *bi; +  struct bgp_info info; +  struct bgp_node *bn; +  struct attr attr; +  struct attr attr_new; +  struct attr *new_attr; +  afi_t afi; +  int ret; + +  /* Make default attribute. */ +  bgp_attr_default_set (&attr, BGP_ORIGIN_INCOMPLETE); +  if (nexthop) +    attr.nexthop = *nexthop; + +  attr.med = metric; +  attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + +  LIST_LOOP (bm->bgp, bgp, nn) +    { +      afi = family2afi (p->family); + +      if (bgp->redist[afi][type]) +	{ +	  /* Copy attribute for modification. */ +	  attr_new = attr; + +	  if (bgp->redist_metric_flag[afi][type]) +	    attr_new.med = bgp->redist_metric[afi][type]; + +	  /* Apply route-map. */ +	  if (bgp->rmap[afi][type].map) +	    { +	      info.peer = bgp->peer_self; +	      info.attr = &attr_new; + +	      ret = route_map_apply (bgp->rmap[afi][type].map, p, RMAP_BGP, +				     &info); +	      if (ret == RMAP_DENYMATCH) +		{ +		  /* Free uninterned attribute. */ +		  bgp_attr_flush (&attr_new); + +		  /* Unintern original. */ +		  aspath_unintern (attr.aspath); +		  bgp_redistribute_delete (p, type); +		  return; +		} +	    } + +	  bn = bgp_afi_node_get (bgp, afi, SAFI_UNICAST, p, NULL); +	  new_attr = bgp_attr_intern (&attr_new); +  + 	  for (bi = bn->info; bi; bi = bi->next) + 	    if (bi->peer == bgp->peer_self + 		&& bi->sub_type == BGP_ROUTE_REDISTRIBUTE) + 	      break; +  + 	  if (bi) + 	    { + 	      if (attrhash_cmp (bi->attr, new_attr)) + 		{ + 		  bgp_attr_unintern (new_attr); + 		  aspath_unintern (attr.aspath); + 		  bgp_unlock_node (bn); + 		  return; + 		} + 	      else + 		{ + 		  /* The attribute is changed. */ + 		  SET_FLAG (bi->flags, BGP_INFO_ATTR_CHANGED); +  + 		  /* Rewrite BGP route information. */ + 		  bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST); + 		  bgp_attr_unintern (bi->attr); + 		  bi->attr = new_attr; + 		  bi->uptime = time (NULL); +  + 		  /* Process change. */ + 		  bgp_aggregate_increment (bgp, p, bi, afi, SAFI_UNICAST); + 		  bgp_process (bgp, bn, afi, SAFI_UNICAST); + 		  bgp_unlock_node (bn); + 		  aspath_unintern (attr.aspath); + 		  return; + 		}  + 	    } + +	  new = bgp_info_new (); +	  new->type = type; +	  new->sub_type = BGP_ROUTE_REDISTRIBUTE; +	  new->peer = bgp->peer_self; +	  SET_FLAG (new->flags, BGP_INFO_VALID); +	  new->attr = new_attr; +	  new->uptime = time (NULL); + +	  bgp_aggregate_increment (bgp, p, new, afi, SAFI_UNICAST); +	  bgp_info_add (bn, new); +	  bgp_process (bgp, bn, afi, SAFI_UNICAST); +	} +    } + +  /* Unintern original. */ +  aspath_unintern (attr.aspath); +} + +void +bgp_redistribute_delete (struct prefix *p, u_char type) +{ +  struct bgp *bgp; +  struct listnode *nn; +  afi_t afi; +  struct bgp_node *rn; +  struct bgp_info *ri; + +  LIST_LOOP (bm->bgp, bgp, nn) +    { +      afi = family2afi (p->family); + +      if (bgp->redist[afi][type]) +	{ +	  rn = bgp_afi_node_get (bgp, afi, SAFI_UNICAST, p, NULL); + +	  for (ri = rn->info; ri; ri = ri->next) +	    if (ri->peer == bgp->peer_self +		&& ri->type == type) +	      break; + +	  if (ri) +	    { +	      bgp_aggregate_decrement (bgp, p, ri, afi, SAFI_UNICAST); +	      UNSET_FLAG (ri->flags, BGP_INFO_VALID); +	      bgp_process (bgp, rn, afi, SAFI_UNICAST); +	      bgp_info_delete (rn, ri); +	      bgp_info_free (ri); +	      bgp_unlock_node (rn); +	    } +	  bgp_unlock_node (rn); +	} +    } +} + +/* Withdraw specified route type's route. */ +void +bgp_redistribute_withdraw (struct bgp *bgp, afi_t afi, int type) +{ +  struct bgp_node *rn; +  struct bgp_info *ri; +  struct bgp_table *table; + +  table = bgp->rib[afi][SAFI_UNICAST]; + +  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) +    { +      for (ri = rn->info; ri; ri = ri->next) +	if (ri->peer == bgp->peer_self +	    && ri->type == type) +	  break; + +      if (ri) +	{ +	  bgp_aggregate_decrement (bgp, &rn->p, ri, afi, SAFI_UNICAST); +	  UNSET_FLAG (ri->flags, BGP_INFO_VALID); +	  bgp_process (bgp, rn, afi, SAFI_UNICAST); +	  bgp_info_delete (rn, ri); +	  bgp_info_free (ri); +	  bgp_unlock_node (rn); +	} +    } +} + +/* Static function to display route. */ +void +route_vty_out_route (struct prefix *p, struct vty *vty) +{ +  int len; +  u_int32_t destination;  +  char buf[BUFSIZ]; + +  if (p->family == AF_INET) +    { +      len = vty_out (vty, "%s", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ)); +      destination = ntohl (p->u.prefix4.s_addr); + +      if ((IN_CLASSC (destination) && p->prefixlen == 24) +	  || (IN_CLASSB (destination) && p->prefixlen == 16) +	  || (IN_CLASSA (destination) && p->prefixlen == 8) +	  || p->u.prefix4.s_addr == 0) +	{ +	  /* When mask is natural, mask is not displayed. */ +	} +      else +	len += vty_out (vty, "/%d", p->prefixlen); +    } +  else +    len = vty_out (vty, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), +		   p->prefixlen); + +  len = 17 - len; +  if (len < 1) +    vty_out (vty, "%s%*s", VTY_NEWLINE, 20, " "); +  else +    vty_out (vty, "%*s", len, " "); +} + +/* Calculate line number of output data. */ +int +vty_calc_line (struct vty *vty, unsigned long length) +{ +  return vty->width ? (((vty->obuf->length - length) / vty->width) + 1) : 1; +} + +enum bgp_display_type +{ +  normal_list, +}; + +/* called from terminal list command */ +int +route_vty_out (struct vty *vty, struct prefix *p, +	       struct bgp_info *binfo, int display, safi_t safi) +{ +  struct attr *attr; +  unsigned long length = 0; + +  length = vty->obuf->length; + +  /* Route status display. */ +  if (binfo->suppress) +    vty_out (vty, "s"); +  else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) +    vty_out (vty, "*"); +  else +    vty_out (vty, " "); + +  /* Selected */ +  if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) +    vty_out (vty, "h"); +  else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) +    vty_out (vty, "d"); +  else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) +    vty_out (vty, ">"); +  else +    vty_out (vty, " "); + +  /* Internal route. */ +    if ((binfo->peer->as) && (binfo->peer->as == binfo->peer->local_as)) +      vty_out (vty, "i"); +    else +      vty_out (vty, " "); +   +  /* print prefix and mask */ +  if (! display) +    route_vty_out_route (p, vty); +  else +    vty_out (vty, "%*s", 17, " "); + +  /* Print attribute */ +  attr = binfo->attr; +  if (attr)  +    { +      if (p->family == AF_INET) +	{ +	  if (safi == SAFI_MPLS_VPN) +	    vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in)); +	  else +	    vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); +	} +#ifdef HAVE_IPV6       +      else if (p->family == AF_INET6) +	{ +	  int len; +	  char buf[BUFSIZ]; + +	  len = vty_out (vty, "%s",  +			 inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ)); +	  len = 16 - len; +	  if (len < 1) +	    vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " "); +	  else +	    vty_out (vty, "%*s", len, " "); +	} +#endif /* HAVE_IPV6 */ + +      if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) +	vty_out (vty, "%10d", attr->med); +      else +	vty_out (vty, "          "); + +      if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) +	vty_out (vty, "%7d", attr->local_pref); +      else +	vty_out (vty, "       "); + +      vty_out (vty, "%7u ",attr->weight); +     +    /* Print aspath */ +    if (attr->aspath) +      aspath_print_vty (vty, attr->aspath); + +    /* Print origin */ +    if (strlen (attr->aspath->str) == 0) +      vty_out (vty, "%s", bgp_origin_str[attr->origin]); +    else +      vty_out (vty, " %s", bgp_origin_str[attr->origin]); +  } +  vty_out (vty, "%s", VTY_NEWLINE); + +  return vty_calc_line (vty, length); +}   + +/* called from terminal list command */ +void +route_vty_out_tmp (struct vty *vty, struct prefix *p, +		   struct attr *attr, safi_t safi) +{ +  /* Route status display. */ +  vty_out (vty, "*"); +  vty_out (vty, ">"); +  vty_out (vty, " "); + +  /* print prefix and mask */ +  route_vty_out_route (p, vty); + +  /* Print attribute */ +  if (attr)  +    { +      if (p->family == AF_INET) +	{ +	  if (safi == SAFI_MPLS_VPN) +	    vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in)); +	  else +	    vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); +	} +#ifdef HAVE_IPV6 +      else if (p->family == AF_INET6) +        { +          int len; +          char buf[BUFSIZ]; + +          len = vty_out (vty, "%s", +                         inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ)); +          len = 16 - len; +          if (len < 1) +            vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " "); +          else +            vty_out (vty, "%*s", len, " "); +        } +#endif /* HAVE_IPV6 */ + +      if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) +	vty_out (vty, "%10d", attr->med); +      else +	vty_out (vty, "          "); + +      if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) +	vty_out (vty, "%7d", attr->local_pref); +      else +	vty_out (vty, "       "); + +      vty_out (vty, "%7d ",attr->weight); +     +    /* Print aspath */ +    if (attr->aspath) +      aspath_print_vty (vty, attr->aspath); + +    /* Print origin */ +    if (strlen (attr->aspath->str) == 0) +      vty_out (vty, "%s", bgp_origin_str[attr->origin]); +    else +      vty_out (vty, " %s", bgp_origin_str[attr->origin]); +  } + +  vty_out (vty, "%s", VTY_NEWLINE); +}   + +int +route_vty_out_tag (struct vty *vty, struct prefix *p, +		   struct bgp_info *binfo, int display, safi_t safi) +{ +  struct attr *attr; +  unsigned long length = 0; +  u_int32_t label = 0; + +  length = vty->obuf->length; + +  /* Route status display. */ +  if (binfo->suppress) +    vty_out (vty, "s"); +  else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) +    vty_out (vty, "*"); +  else +    vty_out (vty, " "); + +  /* Selected */ +  if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) +    vty_out (vty, "h"); +  else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) +    vty_out (vty, "d"); +  else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) +    vty_out (vty, ">"); +  else +    vty_out (vty, " "); + +  /* Internal route. */ +    if ((binfo->peer->as) && (binfo->peer->as == binfo->peer->local_as)) +      vty_out (vty, "i"); +    else +      vty_out (vty, " "); + +  /* print prefix and mask */ +  if (! display) +    route_vty_out_route (p, vty); +  else +    vty_out (vty, "%*s", 17, " "); + +  /* Print attribute */ +  attr = binfo->attr; +  if (attr)  +    { +      if (p->family == AF_INET) +	{ +	  if (safi == SAFI_MPLS_VPN) +	    vty_out (vty, "%-16s", inet_ntoa (attr->mp_nexthop_global_in)); +	  else +	    vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); +	} +#ifdef HAVE_IPV6       +      else if (p->family == AF_INET6) +	{ +	  char buf[BUFSIZ]; +	  char buf1[BUFSIZ]; +	  if (attr->mp_nexthop_len == 16) +	    vty_out (vty, "%s",  +		     inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ)); +	  else if (attr->mp_nexthop_len == 32) +	    vty_out (vty, "%s(%s)", +		     inet_ntop (AF_INET6, &attr->mp_nexthop_global, buf, BUFSIZ), +		     inet_ntop (AF_INET6, &attr->mp_nexthop_local, buf1, BUFSIZ)); +	   +	} +#endif /* HAVE_IPV6 */ +    } + +  label = decode_label (binfo->tag); + +  vty_out (vty, "notag/%d", label); + +  vty_out (vty, "%s", VTY_NEWLINE); + +  return vty_calc_line (vty, length); +}   + +/* dampening route */ +int +damp_route_vty_out (struct vty *vty, struct prefix *p, +		    struct bgp_info *binfo, int display, safi_t safi) +{ +  struct attr *attr; +  unsigned long length = 0; +  int len; + +  length = vty->obuf->length; + +  /* Route status display. */ +  if (binfo->suppress) +    vty_out (vty, "s"); +  else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) +    vty_out (vty, "*"); +  else +    vty_out (vty, " "); + +  /* Selected */ +  if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) +    vty_out (vty, "h"); +  else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) +    vty_out (vty, "d"); +  else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) +    vty_out (vty, ">"); +  else +    vty_out (vty, " "); + +  vty_out (vty, " "); + +  /* print prefix and mask */ +  if (! display) +    route_vty_out_route (p, vty); +  else +    vty_out (vty, "%*s", 17, " "); + +  len = vty_out (vty, "%s", binfo->peer->host); +  len = 17 - len; +  if (len < 1) +    vty_out (vty, "%s%*s", VTY_NEWLINE, 34, " "); +  else +    vty_out (vty, "%*s", len, " "); + +  vty_out (vty, "%s ", bgp_damp_reuse_time_vty (vty, binfo)); + +  /* Print attribute */ +  attr = binfo->attr; +  if (attr) +    { +      /* Print aspath */ +      if (attr->aspath) +	aspath_print_vty (vty, attr->aspath); + +      /* Print origin */ +      if (strlen (attr->aspath->str) == 0) +	vty_out (vty, "%s", bgp_origin_str[attr->origin]); +      else +	vty_out (vty, " %s", bgp_origin_str[attr->origin]); +    } +  vty_out (vty, "%s", VTY_NEWLINE); + +  return vty_calc_line (vty, length); +} + +#define BGP_UPTIME_LEN 25 + +/* flap route */ +int +flap_route_vty_out (struct vty *vty, struct prefix *p, +		    struct bgp_info *binfo, int display, safi_t safi) +{ +  struct attr *attr; +  struct bgp_damp_info *bdi; +  unsigned long length = 0; +  char timebuf[BGP_UPTIME_LEN]; +  int len; + +  length = vty->obuf->length; +  bdi = binfo->damp_info; + +  /* Route status display. */ +  if (binfo->suppress) +    vty_out (vty, "s"); +  else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) +    vty_out (vty, "*"); +  else +    vty_out (vty, " "); + +  /* Selected */ +  if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) +    vty_out (vty, "h"); +  else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) +    vty_out (vty, "d"); +  else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) +    vty_out (vty, ">"); +  else +    vty_out (vty, " "); + +  vty_out (vty, " "); + +  /* print prefix and mask */ +  if (! display) +    route_vty_out_route (p, vty); +  else +    vty_out (vty, "%*s", 17, " "); + +  len = vty_out (vty, "%s", binfo->peer->host); +  len = 16 - len; +  if (len < 1) +    vty_out (vty, "%s%*s", VTY_NEWLINE, 33, " "); +  else +    vty_out (vty, "%*s", len, " "); + +  len = vty_out (vty, "%d", bdi->flap); +  len = 5 - len; +  if (len < 1) +    vty_out (vty, " "); +  else +    vty_out (vty, "%*s ", len, " "); +     +  vty_out (vty, "%s ", peer_uptime (bdi->start_time, +	   timebuf, BGP_UPTIME_LEN)); + +  if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED) +      && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) +    vty_out (vty, "%s ", bgp_damp_reuse_time_vty (vty, binfo)); +  else +    vty_out (vty, "%*s ", 8, " "); + +  /* Print attribute */ +  attr = binfo->attr; +  if (attr) +    { +      /* Print aspath */ +      if (attr->aspath) +	aspath_print_vty (vty, attr->aspath); + +      /* Print origin */ +      if (strlen (attr->aspath->str) == 0) +	vty_out (vty, "%s", bgp_origin_str[attr->origin]); +      else +	vty_out (vty, " %s", bgp_origin_str[attr->origin]); +    } +  vty_out (vty, "%s", VTY_NEWLINE); + +  return vty_calc_line (vty, length); +} + +void +route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,  +		      struct bgp_info *binfo, afi_t afi, safi_t safi) +{ +  char buf[INET6_ADDRSTRLEN]; +  char buf1[BUFSIZ]; +  struct attr *attr; +  int sockunion_vty_out (struct vty *, union sockunion *); +	 +  attr = binfo->attr; + +  if (attr) +    { +      /* Line1 display AS-path, Aggregator */ +      if (attr->aspath) +	{ +	  vty_out (vty, "  "); +	  if (attr->aspath->length == 0) +	    vty_out (vty, "Local"); +	  else +	    aspath_print_vty (vty, attr->aspath); +	} + +      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR) +	  || CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT) +	  || CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) +	  || CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY) +	  || CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) +	{ +	  vty_out (vty, ","); + +	  if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) +	    vty_out (vty, " (aggregated by %d %s)", attr->aggregator_as, +		     inet_ntoa (attr->aggregator_addr)); +	  if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) +	    vty_out (vty, " (Received from a RR-client)"); +	  if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) +	    vty_out (vty, " (Received from a RS-client)"); +	  if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) +	    vty_out (vty, " (history entry)"); +	  else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) +	    vty_out (vty, " (suppressed due to dampening)"); +	} +      vty_out (vty, "%s", VTY_NEWLINE); +	   +      /* Line2 display Next-hop, Neighbor, Router-id */ +      if (p->family == AF_INET) +	{ +	  vty_out (vty, "    %s", safi == SAFI_MPLS_VPN ? +		   inet_ntoa (attr->mp_nexthop_global_in) : +		   inet_ntoa (attr->nexthop)); +	} +#ifdef HAVE_IPV6 +      else +	{ +	  vty_out (vty, "    %s", +		   inet_ntop (AF_INET6, &attr->mp_nexthop_global, +			      buf, INET6_ADDRSTRLEN)); +	} +#endif /* HAVE_IPV6 */ + +      if (binfo->peer == bgp->peer_self) +	{ +	  vty_out (vty, " from %s ",  +		   p->family == AF_INET ? "0.0.0.0" : "::"); +	  vty_out (vty, "(%s)", inet_ntoa(bgp->router_id)); +	} +      else +	{ +	  if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) +	    vty_out (vty, " (inaccessible)");  +	  else if (binfo->igpmetric) +	    vty_out (vty, " (metric %d)", binfo->igpmetric); +	  vty_out (vty, " from %s", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN)); +	  if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) +	    vty_out (vty, " (%s)", inet_ntoa (attr->originator_id)); +	  else +	    vty_out (vty, " (%s)", inet_ntop (AF_INET, &binfo->peer->remote_id, buf1, BUFSIZ)); +	} +      vty_out (vty, "%s", VTY_NEWLINE); + +#ifdef HAVE_IPV6 +      /* display nexthop local */ +      if (attr->mp_nexthop_len == 32) +	{ +	  vty_out (vty, "    (%s)%s", +		   inet_ntop (AF_INET6, &attr->mp_nexthop_local, +			      buf, INET6_ADDRSTRLEN), +		   VTY_NEWLINE); +	} +#endif /* HAVE_IPV6 */ + +      /* Line 3 display Origin, Med, Locpref, Weight, valid, Int/Ext/Local, Atomic, best */ +      vty_out (vty, "      Origin %s", bgp_origin_long_str[attr->origin]); +	   +      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) +	vty_out (vty, ", metric %d", attr->med); +	   +      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) +	vty_out (vty, ", localpref %d", attr->local_pref); +      else +	vty_out (vty, ", localpref %d", bgp->default_local_pref); + +      if (attr->weight != 0) +	vty_out (vty, ", weight %d", attr->weight); +	 +      if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) +	vty_out (vty, ", valid"); + +      if (binfo->peer != bgp->peer_self) +	{ +	  if (binfo->peer->as == binfo->peer->local_as) +	    vty_out (vty, ", internal"); +	  else  +	    vty_out (vty, ", %s",  +		     (bgp_confederation_peers_check(bgp, binfo->peer->as) ? "confed-external" : "external")); +	} +      else if (binfo->sub_type == BGP_ROUTE_AGGREGATE) +	vty_out (vty, ", aggregated, local"); +      else if (binfo->type != ZEBRA_ROUTE_BGP) +	vty_out (vty, ", sourced"); +      else +	vty_out (vty, ", sourced, local"); + +      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) +	vty_out (vty, ", atomic-aggregate"); +	   +      if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) +	vty_out (vty, ", best"); + +      vty_out (vty, "%s", VTY_NEWLINE); +	   +      /* Line 4 display Community */ +      if (attr->community) +	vty_out (vty, "      Community: %s%s", attr->community->str, +		 VTY_NEWLINE); +	   +      /* Line 5 display Extended-community */ +      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) +	vty_out (vty, "      Extended Community: %s%s", attr->ecommunity->str, +		 VTY_NEWLINE); +	   +      /* Line 6 display Originator, Cluster-id */ +      if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) || +	  (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) +	{ +	  if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) +	    vty_out (vty, "      Originator: %s", inet_ntoa (attr->originator_id)); + +	  if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) +	    { +	      int i; +	      vty_out (vty, ", Cluster list: "); +	      for (i = 0; i < attr->cluster->length / 4; i++) +		vty_out (vty, "%s ", inet_ntoa (attr->cluster->list[i])); +	    } +	  vty_out (vty, "%s", VTY_NEWLINE); +	} + +      if (binfo->damp_info) +	bgp_damp_info_vty (vty, binfo); + +      /* Line 7 display Uptime */ +      vty_out (vty, "      Last update: %s", ctime (&binfo->uptime)); +    } +  vty_out (vty, "%s", VTY_NEWLINE); +}   + +#define BGP_SHOW_HEADER "   Network          Next Hop            Metric LocPrf Weight Path%s" +#define BGP_SHOW_DAMP_HEADER "   Network          From             Reuse    Path%s" +#define BGP_SHOW_FLAP_HEADER "   Network          From            Flaps Duration Reuse    Path%s" + +enum bgp_show_type +{ +  bgp_show_type_normal, +  bgp_show_type_regexp, +  bgp_show_type_prefix_list, +  bgp_show_type_filter_list, +  bgp_show_type_route_map, +  bgp_show_type_neighbor, +  bgp_show_type_cidr_only, +  bgp_show_type_prefix_longer, +  bgp_show_type_community_all, +  bgp_show_type_community, +  bgp_show_type_community_exact, +  bgp_show_type_community_list, +  bgp_show_type_community_list_exact, +  bgp_show_type_flap_statistics, +  bgp_show_type_flap_address, +  bgp_show_type_flap_prefix, +  bgp_show_type_flap_cidr_only, +  bgp_show_type_flap_regexp, +  bgp_show_type_flap_filter_list, +  bgp_show_type_flap_prefix_list, +  bgp_show_type_flap_prefix_longer, +  bgp_show_type_flap_route_map, +  bgp_show_type_flap_neighbor, +  bgp_show_type_dampend_paths, +  bgp_show_type_damp_neighbor +}; + +int +bgp_show_callback (struct vty *vty, int unlock) +{ +  struct bgp_node *rn; +  struct bgp_info *ri; +  int count; +  int limit; +  int display; + +  rn = vty->output_rn; +  count = 0; +  limit = ((vty->lines == 0)  +	   ? 10 : (vty->lines > 0  +		   ? vty->lines : vty->height - 2)); +  limit = limit > 0 ? limit : 2; + +  /* Quit of display. */ +  if (unlock && rn) +    { +      bgp_unlock_node (rn); +      if (vty->output_clean) +	(*vty->output_clean) (vty); +      vty->output_rn = NULL; +      vty->output_func = NULL; +      vty->output_clean = NULL; +      vty->output_arg = NULL; +      return 0; +    } + +  for (; rn; rn = bgp_route_next (rn))  +    if (rn->info != NULL) +      { +	display = 0; + +	for (ri = rn->info; ri; ri = ri->next) +	  { +	    if (vty->output_type == bgp_show_type_flap_statistics +		|| vty->output_type == bgp_show_type_flap_address +		|| vty->output_type == bgp_show_type_flap_prefix +		|| vty->output_type == bgp_show_type_flap_cidr_only +		|| vty->output_type == bgp_show_type_flap_regexp +		|| vty->output_type == bgp_show_type_flap_filter_list +		|| vty->output_type == bgp_show_type_flap_prefix_list +		|| vty->output_type == bgp_show_type_flap_prefix_longer +		|| vty->output_type == bgp_show_type_flap_route_map +		|| vty->output_type == bgp_show_type_flap_neighbor +		|| vty->output_type == bgp_show_type_dampend_paths +		|| vty->output_type == bgp_show_type_damp_neighbor) +	      { +		if (! ri->damp_info) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_regexp +		|| vty->output_type == bgp_show_type_flap_regexp) +	      { +		regex_t *regex = vty->output_arg; + +		if (bgp_regexec (regex, ri->attr->aspath) == REG_NOMATCH) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_prefix_list +		|| vty->output_type == bgp_show_type_flap_prefix_list) +	      { +		struct prefix_list *plist = vty->output_arg; + +		if (prefix_list_apply (plist, &rn->p) != PREFIX_PERMIT) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_filter_list +		|| vty->output_type == bgp_show_type_flap_filter_list) +	      { +		struct as_list *as_list = vty->output_arg; + +		if (as_list_apply (as_list, ri->attr->aspath) != AS_FILTER_PERMIT) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_route_map +		|| vty->output_type == bgp_show_type_flap_route_map) +	      { +		struct route_map *rmap = vty->output_arg; +		struct bgp_info binfo; +		struct attr dummy_attr;  +		int ret; + +		dummy_attr = *ri->attr; +		binfo.peer = ri->peer; +		binfo.attr = &dummy_attr; + +		ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &binfo); + +		if (ret == RMAP_DENYMATCH) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_neighbor +		|| vty->output_type == bgp_show_type_flap_neighbor +		|| vty->output_type == bgp_show_type_damp_neighbor) +	      { +		union sockunion *su = vty->output_arg; + +		if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_cidr_only +		|| vty->output_type == bgp_show_type_flap_cidr_only) +	      { +		u_int32_t destination; + +		destination = ntohl (rn->p.u.prefix4.s_addr); +		if (IN_CLASSC (destination) && rn->p.prefixlen == 24) +		  continue; +		if (IN_CLASSB (destination) && rn->p.prefixlen == 16) +		  continue; +		if (IN_CLASSA (destination) && rn->p.prefixlen == 8) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_prefix_longer +		|| vty->output_type == bgp_show_type_flap_prefix_longer) +	      { +		struct prefix *p = vty->output_arg; + +		if (! prefix_match (p, &rn->p)) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_community_all) +	      { +		if (! ri->attr->community) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_community) +	      { +		struct community *com = vty->output_arg; + +		if (! ri->attr->community || +		    ! community_match (ri->attr->community, com)) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_community_exact) +	      { +		struct community *com = vty->output_arg; + +		if (! ri->attr->community || +		    ! community_cmp (ri->attr->community, com)) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_community_list) +	      { +		struct community_list *list = vty->output_arg; + +		if (! community_list_match (ri->attr->community, list)) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_community_list_exact) +	      { +		struct community_list *list = vty->output_arg; + +		if (! community_list_exact_match (ri->attr->community, list)) +		  continue; +	      } +	    if (vty->output_type == bgp_show_type_flap_address +		|| vty->output_type == bgp_show_type_flap_prefix) +	      { +		struct prefix *p = vty->output_arg; + +		if (! prefix_match (&rn->p, p)) +		  continue; + +		if (vty->output_type == bgp_show_type_flap_prefix) +		  if (p->prefixlen != rn->p.prefixlen) +		    continue; +	      } +	    if (vty->output_type == bgp_show_type_dampend_paths +		|| vty->output_type == bgp_show_type_damp_neighbor) +	      { +		if (! CHECK_FLAG (ri->flags, BGP_INFO_DAMPED) +		    || CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) +		  continue; +	      } + +	    if (vty->output_type == bgp_show_type_dampend_paths +		|| vty->output_type == bgp_show_type_damp_neighbor) +	      count += damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); +	    else if (vty->output_type == bgp_show_type_flap_statistics +		     || vty->output_type == bgp_show_type_flap_address +		     || vty->output_type == bgp_show_type_flap_prefix +		     || vty->output_type == bgp_show_type_flap_cidr_only +		     || vty->output_type == bgp_show_type_flap_regexp +		     || vty->output_type == bgp_show_type_flap_filter_list +		     || vty->output_type == bgp_show_type_flap_prefix_list +		     || vty->output_type == bgp_show_type_flap_prefix_longer +		     || vty->output_type == bgp_show_type_flap_route_map +		     || vty->output_type == bgp_show_type_flap_neighbor) +	      count += flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); +	    else +	      count += route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); +	    display++; +	  } + +	if (display) +	  vty->output_count++; + +	/* Remember current pointer then suspend output. */ +	if (count >= limit) +	  { +	    vty->status = VTY_CONTINUE; +	    vty->output_rn = bgp_route_next (rn);; +	    vty->output_func = bgp_show_callback; +	    return 0; +	  } +      } + +  /* Total line display. */ +  if (vty->output_count) +    vty_out (vty, "%sTotal number of prefixes %ld%s", +	     VTY_NEWLINE, vty->output_count, VTY_NEWLINE); + +  if (vty->output_clean) +    (*vty->output_clean) (vty); + +  vty->status = VTY_CONTINUE; +  vty->output_rn = NULL; +  vty->output_func = NULL; +  vty->output_clean = NULL; +  vty->output_arg = NULL; + +  return 0; +} + +int +bgp_show (struct vty *vty, char *view_name, afi_t afi, safi_t safi, +	  enum bgp_show_type type) +{ +  struct bgp *bgp; +  struct bgp_info *ri; +  struct bgp_node *rn; +  struct bgp_table *table; +  int header = 1; +  int count; +  int limit; +  int display; + +  limit = ((vty->lines == 0)  +	   ? 10 : (vty->lines > 0  +		   ? vty->lines : vty->height - 2)); +  limit = limit > 0 ? limit : 2; + +  /* BGP structure lookup. */ +  if (view_name) +    { +      bgp = bgp_lookup_by_name (view_name); +      if (bgp == NULL) +	{ +	  vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } +  else +    { +      bgp = bgp_get_default (); +      if (bgp == NULL) +	{ +	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } + +  count = 0; + +  /* This is first entry point, so reset total line. */ +  vty->output_count = 0; +  vty->output_type = type; + +  table = bgp->rib[afi][safi]; + +  /* Start processing of routes. */ +  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))  +    if (rn->info != NULL) +      { +	display = 0; + +	for (ri = rn->info; ri; ri = ri->next) +	  { +	    if (vty->output_type == bgp_show_type_flap_statistics +		|| type == bgp_show_type_flap_address +		|| type == bgp_show_type_flap_prefix +		|| type == bgp_show_type_flap_cidr_only +		|| type == bgp_show_type_flap_regexp +		|| type == bgp_show_type_flap_filter_list +		|| type == bgp_show_type_flap_prefix_list +		|| type == bgp_show_type_flap_prefix_longer +		|| type == bgp_show_type_flap_route_map +		|| type == bgp_show_type_flap_neighbor +		|| type == bgp_show_type_dampend_paths +		|| type == bgp_show_type_damp_neighbor) +	      { +		if (! ri->damp_info) +		  continue; +	      } +	    if (type == bgp_show_type_regexp +		|| type == bgp_show_type_flap_regexp) +	      { +		regex_t *regex = vty->output_arg; +		     +		if (bgp_regexec (regex, ri->attr->aspath) == REG_NOMATCH) +		  continue; +	      } +	    if (type == bgp_show_type_prefix_list +		|| type == bgp_show_type_flap_prefix_list) +	      { +		struct prefix_list *plist = vty->output_arg; +		     +		if (prefix_list_apply (plist, &rn->p) != PREFIX_PERMIT) +		  continue; +	      } +	    if (type == bgp_show_type_filter_list +		|| type == bgp_show_type_flap_filter_list) +	      { +		struct as_list *as_list = vty->output_arg; + +		if (as_list_apply (as_list, ri->attr->aspath) != AS_FILTER_PERMIT) +		  continue; +	      } +	    if (type == bgp_show_type_route_map +		|| type == bgp_show_type_flap_route_map) +	      { +		struct route_map *rmap = vty->output_arg; +		struct bgp_info binfo; +		struct attr dummy_attr;  +		int ret; + +		dummy_attr = *ri->attr; +		binfo.peer = ri->peer; +		binfo.attr = &dummy_attr; + +		ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &binfo); + +		if (ret == RMAP_DENYMATCH) +		  continue; +	      } +	    if (type == bgp_show_type_neighbor +		|| type == bgp_show_type_flap_neighbor +		|| type == bgp_show_type_damp_neighbor) +	      { +		union sockunion *su = vty->output_arg; + +		if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) +		  continue; +	      } +	    if (type == bgp_show_type_cidr_only +		|| type == bgp_show_type_flap_cidr_only) +	      { +		u_int32_t destination; + +		destination = ntohl (rn->p.u.prefix4.s_addr); +		if (IN_CLASSC (destination) && rn->p.prefixlen == 24) +		  continue; +		if (IN_CLASSB (destination) && rn->p.prefixlen == 16) +		  continue; +		if (IN_CLASSA (destination) && rn->p.prefixlen == 8) +		  continue; +	      } +	    if (type == bgp_show_type_prefix_longer +		|| type == bgp_show_type_flap_prefix_longer) +	      { +		struct prefix *p = vty->output_arg; + +		if (! prefix_match (p, &rn->p)) +		  continue; +	      } +	    if (type == bgp_show_type_community_all) +	      { +		if (! ri->attr->community) +		  continue; +	      } +	    if (type == bgp_show_type_community) +	      { +		struct community *com = vty->output_arg; + +		if (! ri->attr->community || +		    ! community_match (ri->attr->community, com)) +		  continue; +	      } +	    if (type == bgp_show_type_community_exact) +	      { +		struct community *com = vty->output_arg; + +		if (! ri->attr->community || +		    ! community_cmp (ri->attr->community, com)) +		  continue; +	      } +	    if (type == bgp_show_type_community_list) +	      { +		struct community_list *list = vty->output_arg; + +		if (! community_list_match (ri->attr->community, list)) +		  continue; +	      } +	    if (type == bgp_show_type_community_list_exact) +	      { +		struct community_list *list = vty->output_arg; + +		if (! community_list_exact_match (ri->attr->community, list)) +		  continue; +	      } +	    if (type == bgp_show_type_flap_address +		|| type == bgp_show_type_flap_prefix) +	      { +		struct prefix *p = vty->output_arg; + +		if (! prefix_match (&rn->p, p)) +		  continue; + +		if (type == bgp_show_type_flap_prefix) +		  if (p->prefixlen != rn->p.prefixlen) +		    continue; +	      } +	    if (type == bgp_show_type_dampend_paths +		|| type == bgp_show_type_damp_neighbor) +	      { +		if (! CHECK_FLAG (ri->flags, BGP_INFO_DAMPED) +		    || CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) +		  continue; +	      } + +	    if (header) +	      { +		vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); +		vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE); +		vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE); +		if (type == bgp_show_type_dampend_paths +		    || type == bgp_show_type_damp_neighbor) +		  vty_out (vty, BGP_SHOW_DAMP_HEADER, VTY_NEWLINE); +		else if (type == bgp_show_type_flap_statistics +			 || type == bgp_show_type_flap_address +			 || type == bgp_show_type_flap_prefix +			 || type == bgp_show_type_flap_cidr_only +			 || type == bgp_show_type_flap_regexp +			 || type == bgp_show_type_flap_filter_list +			 || type == bgp_show_type_flap_prefix_list +			 || type == bgp_show_type_flap_prefix_longer +			 || type == bgp_show_type_flap_route_map +			 || type == bgp_show_type_flap_neighbor) +		  vty_out (vty, BGP_SHOW_FLAP_HEADER, VTY_NEWLINE); +		else +		  vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); +		count += 5; +		header = 0; +	      } + +	    if (type == bgp_show_type_dampend_paths +		|| type == bgp_show_type_damp_neighbor) +	      count += damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); +	    else if (type == bgp_show_type_flap_statistics +		     || type == bgp_show_type_flap_address +		     || type == bgp_show_type_flap_prefix +		     || type == bgp_show_type_flap_cidr_only +		     || type == bgp_show_type_flap_regexp +		     || type == bgp_show_type_flap_filter_list +		     || type == bgp_show_type_flap_prefix_list +		     || type == bgp_show_type_flap_prefix_longer +		     || type == bgp_show_type_flap_route_map +		     || type == bgp_show_type_flap_neighbor) +	      count += flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); +	    else +	      count += route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); +	    display++; +	  } +	if (display) +	  vty->output_count++; + +	/* Remember current pointer then suspend output. */ +	if (count >= limit  && vty->type != VTY_SHELL_SERV) +	  { +	    vty->status = VTY_START; +	    vty->output_rn = bgp_route_next (rn); +	    vty->output_func = bgp_show_callback; +	    vty->output_type = type; + +	    return CMD_SUCCESS; +	  } +      } + +  /* No route is displayed */ +  if (vty->output_count == 0) +    { +      if (type == bgp_show_type_normal) +	vty_out (vty, "No BGP network exists%s", VTY_NEWLINE); +    } +  else +    vty_out (vty, "%sTotal number of prefixes %ld%s", +	     VTY_NEWLINE, vty->output_count, VTY_NEWLINE); + +  /* Clean up allocated resources. */ +  if (vty->output_clean) +    (*vty->output_clean) (vty); + +  vty->status = VTY_START; +  vty->output_rn = NULL; +  vty->output_func = NULL; +  vty->output_clean = NULL; +  vty->output_arg = NULL; + +  return CMD_SUCCESS; +} + +/* Header of detailed BGP route information */ +void +route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, +			     struct bgp_node *rn, +                             struct prefix_rd *prd, afi_t afi, safi_t safi) +{ +  struct bgp_info *ri; +  struct prefix *p; +  struct peer *peer; +  struct listnode *nn; +  char buf1[INET6_ADDRSTRLEN]; +  char buf2[INET6_ADDRSTRLEN]; +  int count = 0; +  int best = 0; +  int suppress = 0; +  int no_export = 0; +  int no_advertise = 0; +  int local_as = 0; +  int first = 0; + +  p = &rn->p; +  vty_out (vty, "BGP routing table entry for %s%s%s/%d%s", +	   (safi == SAFI_MPLS_VPN ? +	   prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""), +	   safi == SAFI_MPLS_VPN ? ":" : "", +	   inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN), +	   p->prefixlen, VTY_NEWLINE); + +  for (ri = rn->info; ri; ri = ri->next) +    { +      count++; +      if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) +	{ +	  best = count; +	  if (ri->suppress) +	    suppress = 1; +	  if (ri->attr->community != NULL) +	    { +	      if (community_include (ri->attr->community, COMMUNITY_NO_ADVERTISE)) +		no_advertise = 1; +	      if (community_include (ri->attr->community, COMMUNITY_NO_EXPORT)) +		no_export = 1; +	      if (community_include (ri->attr->community, COMMUNITY_LOCAL_AS)) +		local_as = 1; +	    } +	} +    } + +  vty_out (vty, "Paths: (%d available", count); +  if (best) +    { +      vty_out (vty, ", best #%d", best); +      if (safi == SAFI_UNICAST) +	vty_out (vty, ", table Default-IP-Routing-Table"); +    } +  else +    vty_out (vty, ", no best path"); +  if (no_advertise) +    vty_out (vty, ", not advertised to any peer"); +  else if (no_export) +    vty_out (vty, ", not advertised to EBGP peer"); +  else if (local_as) +    vty_out (vty, ", not advertised outside local AS"); +  if (suppress) +    vty_out (vty, ", Advertisements suppressed by an aggregate."); +  vty_out (vty, ")%s", VTY_NEWLINE); + +  /* advertised peer */ +  LIST_LOOP (bgp->peer, peer, nn) +    { +      if (bgp_adj_out_lookup (peer, p, afi, safi, rn)) +	{ +	  if (! first) +	    vty_out (vty, "  Advertised to non peer-group peers:%s ", VTY_NEWLINE); +	  vty_out (vty, " %s", sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN)); +	  first = 1; +	} +    } +  if (! first) +    vty_out (vty, "  Not advertised to any peer"); +  vty_out (vty, "%s", VTY_NEWLINE); +} + +/* Display specified route of BGP table. */ +int +bgp_show_route (struct vty *vty, char *view_name, char *ip_str, +		afi_t afi, safi_t safi, struct prefix_rd *prd, +		int prefix_check) +{ +  int ret; +  int header; +  int display = 0; +  struct prefix match; +  struct bgp_node *rn; +  struct bgp_node *rm; +  struct bgp_info *ri; +  struct bgp *bgp; +  struct bgp_table *table; + +  /* BGP structure lookup. */ +  if (view_name) +    { +      bgp = bgp_lookup_by_name (view_name); +      if (bgp == NULL) +	{ +	  vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } +  else +    { +      bgp = bgp_get_default (); +      if (bgp == NULL) +	{ +	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } + +  /* Check IP address argument. */ +  ret = str2prefix (ip_str, &match); +  if (! ret) +    { +      vty_out (vty, "address is malformed%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  match.family = afi2family (afi); + +  if (safi == SAFI_MPLS_VPN) +    { +      for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) +        { +          if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) +            continue; + +          if ((table = rn->info) != NULL) +            { +              header = 1; + +              if ((rm = bgp_node_match (table, &match)) != NULL) +                { +                  if (prefix_check && rm->p.prefixlen != match.prefixlen) +                    continue; + +                  for (ri = rm->info; ri; ri = ri->next) +                    { +                      if (header) +                        { +                          route_vty_out_detail_header (vty, bgp, rm, (struct prefix_rd *)&rn->p, +                                                       AFI_IP, SAFI_MPLS_VPN); + +                          header = 0; +                        } +                      display++; +                      route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, SAFI_MPLS_VPN); +                    } +                } +            } +        } +    } +  else +    { +      header = 1; + +      if ((rn = bgp_node_match (bgp->rib[afi][safi], &match)) != NULL) +        { +          if (! prefix_check || rn->p.prefixlen == match.prefixlen) +            { +              for (ri = rn->info; ri; ri = ri->next) +                { +                  if (header) +                    { +                      route_vty_out_detail_header (vty, bgp, rn, NULL, afi, safi); +                      header = 0; +                    } +                  display++; +                  route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi); +                } +            } +        } +    } + +  if (! display) +    { +      vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return CMD_SUCCESS; +} + +/* BGP route print out function. */ +DEFUN (show_ip_bgp, +       show_ip_bgp_cmd, +       "show ip bgp", +       SHOW_STR +       IP_STR +       BGP_STR) +{ +  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal); +} + +DEFUN (show_ip_bgp_ipv4, +       show_ip_bgp_ipv4_cmd, +       "show ip bgp ipv4 (unicast|multicast)", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_normal); +  +  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal); +} + +DEFUN (show_ip_bgp_route, +       show_ip_bgp_route_cmd, +       "show ip bgp A.B.C.D", +       SHOW_STR +       IP_STR +       BGP_STR +       "Network in the BGP routing table to display\n") +{ +  return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_ip_bgp_ipv4_route, +       show_ip_bgp_ipv4_route_cmd, +       "show ip bgp ipv4 (unicast|multicast) A.B.C.D", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Network in the BGP routing table to display\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0); + +  return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_ip_bgp_vpnv4_all_route, +       show_ip_bgp_vpnv4_all_route_cmd, +       "show ip bgp vpnv4 all A.B.C.D", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information about all VPNv4 NLRIs\n" +       "Network in the BGP routing table to display\n") +{ +  return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0); +} + +DEFUN (show_ip_bgp_vpnv4_rd_route, +       show_ip_bgp_vpnv4_rd_route_cmd, +       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information for a route distinguisher\n" +       "VPN Route Distinguisher\n" +       "Network in the BGP routing table to display\n") +{ +  int ret; +  struct prefix_rd prd; + +  ret = str2prefix_rd (argv[0], &prd); +  if (! ret) +    { +      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0); +} + +DEFUN (show_ip_bgp_prefix, +       show_ip_bgp_prefix_cmd, +       "show ip bgp A.B.C.D/M", +       SHOW_STR +       IP_STR +       BGP_STR +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +{ +  return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (show_ip_bgp_ipv4_prefix, +       show_ip_bgp_ipv4_prefix_cmd, +       "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1); + +  return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_all_prefix, +       show_ip_bgp_vpnv4_all_prefix_cmd, +       "show ip bgp vpnv4 all A.B.C.D/M", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information about all VPNv4 NLRIs\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +{ +  return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1); +} + +DEFUN (show_ip_bgp_vpnv4_rd_prefix, +       show_ip_bgp_vpnv4_rd_prefix_cmd, +       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information for a route distinguisher\n" +       "VPN Route Distinguisher\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +{ +  int ret; +  struct prefix_rd prd; + +  ret = str2prefix_rd (argv[0], &prd); +  if (! ret) +    { +      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1); +} + +DEFUN (show_ip_bgp_view, +       show_ip_bgp_view_cmd, +       "show ip bgp view WORD", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "BGP view name\n") +{ +  return bgp_show (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_normal); +} + +DEFUN (show_ip_bgp_view_route, +       show_ip_bgp_view_route_cmd, +       "show ip bgp view WORD A.B.C.D", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "BGP view name\n" +       "Network in the BGP routing table to display\n") +{ +  return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_ip_bgp_view_prefix, +       show_ip_bgp_view_prefix_cmd, +       "show ip bgp view WORD A.B.C.D/M", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "BGP view name\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +{ +  return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp, +       show_bgp_cmd, +       "show bgp", +       SHOW_STR +       BGP_STR) +{ +  return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal); +} + +ALIAS (show_bgp, +       show_bgp_ipv6_cmd, +       "show bgp ipv6", +       SHOW_STR +       BGP_STR +       "Address family\n") + +/* old command */ +DEFUN (show_ipv6_bgp, +       show_ipv6_bgp_cmd, +       "show ipv6 bgp", +       SHOW_STR +       IP_STR +       BGP_STR) +{ +  return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal); +} + +DEFUN (show_bgp_route, +       show_bgp_route_cmd, +       "show bgp X:X::X:X", +       SHOW_STR +       BGP_STR +       "Network in the BGP routing table to display\n") +{ +  return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +ALIAS (show_bgp_route, +       show_bgp_ipv6_route_cmd, +       "show bgp ipv6 X:X::X:X", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Network in the BGP routing table to display\n") + +/* old command */ +DEFUN (show_ipv6_bgp_route, +       show_ipv6_bgp_route_cmd, +       "show ipv6 bgp X:X::X:X", +       SHOW_STR +       IP_STR +       BGP_STR +       "Network in the BGP routing table to display\n") +{ +  return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +DEFUN (show_bgp_prefix, +       show_bgp_prefix_cmd, +       "show bgp X:X::X:X/M", +       SHOW_STR +       BGP_STR +       "IPv6 prefix <network>/<length>\n") +{ +  return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); +} + +ALIAS (show_bgp_prefix, +       show_bgp_ipv6_prefix_cmd, +       "show bgp ipv6 X:X::X:X/M", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "IPv6 prefix <network>/<length>\n") + +/* old command */ +DEFUN (show_ipv6_bgp_prefix, +       show_ipv6_bgp_prefix_cmd, +       "show ipv6 bgp X:X::X:X/M", +       SHOW_STR +       IP_STR +       BGP_STR +       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n") +{ +  return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); +} + +/* old command */ +DEFUN (show_ipv6_mbgp, +       show_ipv6_mbgp_cmd, +       "show ipv6 mbgp", +       SHOW_STR +       IP_STR +       MBGP_STR) +{ +  return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_route, +       show_ipv6_mbgp_route_cmd, +       "show ipv6 mbgp X:X::X:X", +       SHOW_STR +       IP_STR +       MBGP_STR +       "Network in the MBGP routing table to display\n") +{ +  return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 0); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_prefix, +       show_ipv6_mbgp_prefix_cmd, +       "show ipv6 mbgp X:X::X:X/M", +       SHOW_STR +       IP_STR +       MBGP_STR +       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n") +{ +  return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1); +} +#endif + +void +bgp_show_regexp_clean (struct vty *vty) +{ +  bgp_regex_free (vty->output_arg); +} + +int +bgp_show_regexp (struct vty *vty, int argc, char **argv, afi_t afi, +		 safi_t safi, enum bgp_show_type type) +{ +  int i; +  struct buffer *b; +  char *regstr; +  int first; +  regex_t *regex; +   +  first = 0; +  b = buffer_new (1024); +  for (i = 0; i < argc; i++) +    { +      if (first) +	buffer_putc (b, ' '); +      else +	{ +	  if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0)) +	    continue; +	  first = 1; +	} + +      buffer_putstr (b, argv[i]); +    } +  buffer_putc (b, '\0'); + +  regstr = buffer_getstr (b); +  buffer_free (b); + +  regex = bgp_regcomp (regstr); +  if (! regex) +    { +      vty_out (vty, "Can't compile regexp %s%s", argv[0], +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  vty->output_arg = regex; +  vty->output_clean = bgp_show_regexp_clean; + +  return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_regexp,  +       show_ip_bgp_regexp_cmd, +       "show ip bgp regexp .LINE", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the AS path regular expression\n" +       "A regular-expression to match the BGP AS paths\n") +{ +  return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, +			  bgp_show_type_regexp); +} + +DEFUN (show_ip_bgp_flap_regexp,  +       show_ip_bgp_flap_regexp_cmd, +       "show ip bgp flap-statistics regexp .LINE", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display flap statistics of routes\n" +       "Display routes matching the AS path regular expression\n" +       "A regular-expression to match the BGP AS paths\n") +{ +  return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, +			  bgp_show_type_flap_regexp); +} + +DEFUN (show_ip_bgp_ipv4_regexp,  +       show_ip_bgp_ipv4_regexp_cmd, +       "show ip bgp ipv4 (unicast|multicast) regexp .LINE", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the AS path regular expression\n" +       "A regular-expression to match the BGP AS paths\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_MULTICAST, +			    bgp_show_type_regexp); + +  return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, +			  bgp_show_type_regexp); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_regexp,  +       show_bgp_regexp_cmd, +       "show bgp regexp .LINE", +       SHOW_STR +       BGP_STR +       "Display routes matching the AS path regular expression\n" +       "A regular-expression to match the BGP AS paths\n") +{ +  return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, +			  bgp_show_type_regexp); +} + +ALIAS (show_bgp_regexp,  +       show_bgp_ipv6_regexp_cmd, +       "show bgp ipv6 regexp .LINE", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the AS path regular expression\n" +       "A regular-expression to match the BGP AS paths\n") + +/* old command */ +DEFUN (show_ipv6_bgp_regexp,  +       show_ipv6_bgp_regexp_cmd, +       "show ipv6 bgp regexp .LINE", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the AS path regular expression\n" +       "A regular-expression to match the BGP AS paths\n") +{ +  return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, +			  bgp_show_type_regexp); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_regexp,  +       show_ipv6_mbgp_regexp_cmd, +       "show ipv6 mbgp regexp .LINE", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the AS path regular expression\n" +       "A regular-expression to match the MBGP AS paths\n") +{ +  return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_MULTICAST, +			  bgp_show_type_regexp); +} +#endif /* HAVE_IPV6 */ + +int +bgp_show_prefix_list (struct vty *vty, char *prefix_list_str, afi_t afi, +		      safi_t safi, enum bgp_show_type type) +{ +  struct prefix_list *plist; + +  plist = prefix_list_lookup (afi, prefix_list_str); +  if (plist == NULL) +    { +      vty_out (vty, "%% %s is not a valid prefix-list name%s", +               prefix_list_str, VTY_NEWLINE);	     +      return CMD_WARNING; +    } + +  vty->output_arg = plist; + +  return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_prefix_list,  +       show_ip_bgp_prefix_list_cmd, +       "show ip bgp prefix-list WORD", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes conforming to the prefix-list\n" +       "IP prefix-list name\n") +{ +  return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST, +			       bgp_show_type_prefix_list); +} + +DEFUN (show_ip_bgp_flap_prefix_list,  +       show_ip_bgp_flap_prefix_list_cmd, +       "show ip bgp flap-statistics prefix-list WORD", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display flap statistics of routes\n" +       "Display routes conforming to the prefix-list\n" +       "IP prefix-list name\n") +{ +  return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST, +			       bgp_show_type_flap_prefix_list); +} + +DEFUN (show_ip_bgp_ipv4_prefix_list,  +       show_ip_bgp_ipv4_prefix_list_cmd, +       "show ip bgp ipv4 (unicast|multicast) prefix-list WORD", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes conforming to the prefix-list\n" +       "IP prefix-list name\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, +			         bgp_show_type_prefix_list); + +  return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_UNICAST, +			       bgp_show_type_prefix_list); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_prefix_list,  +       show_bgp_prefix_list_cmd, +       "show bgp prefix-list WORD", +       SHOW_STR +       BGP_STR +       "Display routes conforming to the prefix-list\n" +       "IPv6 prefix-list name\n") +{ +  return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, +			       bgp_show_type_prefix_list); +} + +ALIAS (show_bgp_prefix_list,  +       show_bgp_ipv6_prefix_list_cmd, +       "show bgp ipv6 prefix-list WORD", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes conforming to the prefix-list\n" +       "IPv6 prefix-list name\n") + +/* old command */ +DEFUN (show_ipv6_bgp_prefix_list,  +       show_ipv6_bgp_prefix_list_cmd, +       "show ipv6 bgp prefix-list WORD", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes matching the prefix-list\n" +       "IPv6 prefix-list name\n") +{ +  return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, +			       bgp_show_type_prefix_list); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_prefix_list,  +       show_ipv6_mbgp_prefix_list_cmd, +       "show ipv6 mbgp prefix-list WORD", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes matching the prefix-list\n" +       "IPv6 prefix-list name\n") +{ +  return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, +			       bgp_show_type_prefix_list); +} +#endif /* HAVE_IPV6 */ + +int +bgp_show_filter_list (struct vty *vty, char *filter, afi_t afi, +		      safi_t safi, enum bgp_show_type type) +{ +  struct as_list *as_list; + +  as_list = as_list_lookup (filter); +  if (as_list == NULL) +    { +      vty_out (vty, "%% %s is not a valid AS-path access-list name%s", filter, VTY_NEWLINE);	     +      return CMD_WARNING; +    } + +  vty->output_arg = as_list; + +  return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_filter_list,  +       show_ip_bgp_filter_list_cmd, +       "show ip bgp filter-list WORD", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes conforming to the filter-list\n" +       "Regular expression access list name\n") +{ +  return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST, +			       bgp_show_type_filter_list); +} + +DEFUN (show_ip_bgp_flap_filter_list,  +       show_ip_bgp_flap_filter_list_cmd, +       "show ip bgp flap-statistics filter-list WORD", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display flap statistics of routes\n" +       "Display routes conforming to the filter-list\n" +       "Regular expression access list name\n") +{ +  return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST, +			       bgp_show_type_flap_filter_list); +} + +DEFUN (show_ip_bgp_ipv4_filter_list,  +       show_ip_bgp_ipv4_filter_list_cmd, +       "show ip bgp ipv4 (unicast|multicast) filter-list WORD", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes conforming to the filter-list\n" +       "Regular expression access list name\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, +			         bgp_show_type_filter_list); +   +  return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_UNICAST, +			       bgp_show_type_filter_list); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_filter_list,  +       show_bgp_filter_list_cmd, +       "show bgp filter-list WORD", +       SHOW_STR +       BGP_STR +       "Display routes conforming to the filter-list\n" +       "Regular expression access list name\n") +{ +  return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, +			       bgp_show_type_filter_list); +} + +ALIAS (show_bgp_filter_list,  +       show_bgp_ipv6_filter_list_cmd, +       "show bgp ipv6 filter-list WORD", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes conforming to the filter-list\n" +       "Regular expression access list name\n") + +/* old command */ +DEFUN (show_ipv6_bgp_filter_list,  +       show_ipv6_bgp_filter_list_cmd, +       "show ipv6 bgp filter-list WORD", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes conforming to the filter-list\n" +       "Regular expression access list name\n") +{ +  return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, +			       bgp_show_type_filter_list); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_filter_list,  +       show_ipv6_mbgp_filter_list_cmd, +       "show ipv6 mbgp filter-list WORD", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes conforming to the filter-list\n" +       "Regular expression access list name\n") +{ +  return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, +			       bgp_show_type_filter_list); +} +#endif /* HAVE_IPV6 */ + +int +bgp_show_route_map (struct vty *vty, char *rmap_str, afi_t afi, +		    safi_t safi, enum bgp_show_type type) +{ +  struct route_map *rmap; + +  rmap = route_map_lookup_by_name (rmap_str); +  if (! rmap) +    { +      vty_out (vty, "%% %s is not a valid route-map name%s", +	       rmap_str, VTY_NEWLINE);	     +      return CMD_WARNING; +    } + +  vty->output_arg = rmap; + +  return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_route_map,  +       show_ip_bgp_route_map_cmd, +       "show ip bgp route-map WORD", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the route-map\n" +       "A route-map to match on\n") +{ +  return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST, +			     bgp_show_type_route_map); +} + +DEFUN (show_ip_bgp_flap_route_map,  +       show_ip_bgp_flap_route_map_cmd, +       "show ip bgp flap-statistics route-map WORD", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display flap statistics of routes\n" +       "Display routes matching the route-map\n" +       "A route-map to match on\n") +{ +  return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST, +			     bgp_show_type_flap_route_map); +} + +DEFUN (show_ip_bgp_ipv4_route_map,  +       show_ip_bgp_ipv4_route_map_cmd, +       "show ip bgp ipv4 (unicast|multicast) route-map WORD", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the route-map\n" +       "A route-map to match on\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_MULTICAST, +			       bgp_show_type_route_map); + +  return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_UNICAST, +			     bgp_show_type_route_map); +} + +DEFUN (show_bgp_route_map,  +       show_bgp_route_map_cmd, +       "show bgp route-map WORD", +       SHOW_STR +       BGP_STR +       "Display routes matching the route-map\n" +       "A route-map to match on\n") +{ +  return bgp_show_route_map (vty, argv[0], AFI_IP6, SAFI_UNICAST, +			     bgp_show_type_route_map); +} + +ALIAS (show_bgp_route_map,  +       show_bgp_ipv6_route_map_cmd, +       "show bgp ipv6 route-map WORD", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the route-map\n" +       "A route-map to match on\n") + +DEFUN (show_ip_bgp_cidr_only, +       show_ip_bgp_cidr_only_cmd, +       "show ip bgp cidr-only", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display only routes with non-natural netmasks\n") +{ +    return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, +		     bgp_show_type_cidr_only); +} + +DEFUN (show_ip_bgp_flap_cidr_only, +       show_ip_bgp_flap_cidr_only_cmd, +       "show ip bgp flap-statistics cidr-only", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display flap statistics of routes\n" +       "Display only routes with non-natural netmasks\n") +{ +  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, +		   bgp_show_type_flap_cidr_only); +} + +DEFUN (show_ip_bgp_ipv4_cidr_only, +       show_ip_bgp_ipv4_cidr_only_cmd, +       "show ip bgp ipv4 (unicast|multicast) cidr-only", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display only routes with non-natural netmasks\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, +		     bgp_show_type_cidr_only); + +  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, +		     bgp_show_type_cidr_only); +} + +DEFUN (show_ip_bgp_community_all, +       show_ip_bgp_community_all_cmd, +       "show ip bgp community", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the communities\n") +{ +  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, +		     bgp_show_type_community_all); +} + +DEFUN (show_ip_bgp_ipv4_community_all, +       show_ip_bgp_ipv4_community_all_cmd, +       "show ip bgp ipv4 (unicast|multicast) community", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the communities\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, +		     bgp_show_type_community_all); +  +  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, +		   bgp_show_type_community_all); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_community_all, +       show_bgp_community_all_cmd, +       "show bgp community", +       SHOW_STR +       BGP_STR +       "Display routes matching the communities\n") +{ +  return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, +		   bgp_show_type_community_all); +} + +ALIAS (show_bgp_community_all, +       show_bgp_ipv6_community_all_cmd, +       "show bgp ipv6 community", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the communities\n") + +/* old command */ +DEFUN (show_ipv6_bgp_community_all, +       show_ipv6_bgp_community_all_cmd, +       "show ipv6 bgp community", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes matching the communities\n") +{ +  return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, +		   bgp_show_type_community_all); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_community_all, +       show_ipv6_mbgp_community_all_cmd, +       "show ipv6 mbgp community", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes matching the communities\n") +{ +  return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, +		   bgp_show_type_community_all); +} +#endif /* HAVE_IPV6 */ + +int +bgp_show_community (struct vty *vty, int argc, char **argv, int exact, +		                          u_int16_t afi, u_char safi) +{ +  struct community *com; +  struct buffer *b; +  int i; +  char *str; +  int first = 0; + +  b = buffer_new (1024); +  for (i = 0; i < argc; i++) +    { +      if (first) +        buffer_putc (b, ' '); +      else +	{ +	  if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0)) +	    continue; +	  first = 1; +	} +       +      buffer_putstr (b, argv[i]); +    } +  buffer_putc (b, '\0'); + +  str = buffer_getstr (b); +  buffer_free (b); + +  com = community_str2com (str); +  free (str); +  if (! com) +    { +      vty_out (vty, "%% Community malformed: %s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  vty->output_arg = com; + +  if (exact) +    return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_exact); + +  return bgp_show (vty, NULL, afi, safi, bgp_show_type_community); +} + +DEFUN (show_ip_bgp_community, +       show_ip_bgp_community_cmd, +       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") +{ +  return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_community, +       show_ip_bgp_community2_cmd, +       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") +	 +ALIAS (show_ip_bgp_community, +       show_ip_bgp_community3_cmd, +       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") +	 +ALIAS (show_ip_bgp_community, +       show_ip_bgp_community4_cmd, +       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +DEFUN (show_ip_bgp_ipv4_community, +       show_ip_bgp_ipv4_community_cmd, +       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_MULTICAST); +  +  return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_ipv4_community, +       show_ip_bgp_ipv4_community2_cmd, +       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") +	 +ALIAS (show_ip_bgp_ipv4_community, +       show_ip_bgp_ipv4_community3_cmd, +       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") +	 +ALIAS (show_ip_bgp_ipv4_community, +       show_ip_bgp_ipv4_community4_cmd, +       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +DEFUN (show_ip_bgp_community_exact, +       show_ip_bgp_community_exact_cmd, +       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") +{ +  return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_community_exact, +       show_ip_bgp_community2_exact_cmd, +       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +ALIAS (show_ip_bgp_community_exact, +       show_ip_bgp_community3_exact_cmd, +       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +ALIAS (show_ip_bgp_community_exact, +       show_ip_bgp_community4_exact_cmd, +       "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +DEFUN (show_ip_bgp_ipv4_community_exact, +       show_ip_bgp_ipv4_community_exact_cmd, +       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_MULTICAST); +  +  return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST); +} + +ALIAS (show_ip_bgp_ipv4_community_exact, +       show_ip_bgp_ipv4_community2_exact_cmd, +       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +ALIAS (show_ip_bgp_ipv4_community_exact, +       show_ip_bgp_ipv4_community3_exact_cmd, +       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") +        +ALIAS (show_ip_bgp_ipv4_community_exact, +       show_ip_bgp_ipv4_community4_exact_cmd, +       "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_community, +       show_bgp_community_cmd, +       "show bgp community (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") +{ +  return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_community, +       show_bgp_ipv6_community_cmd, +       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, +       show_bgp_community2_cmd, +       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, +       show_bgp_ipv6_community2_cmd, +       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") +	 +ALIAS (show_bgp_community, +       show_bgp_community3_cmd, +       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, +       show_bgp_ipv6_community3_cmd, +       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, +       show_bgp_community4_cmd, +       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_community, +       show_bgp_ipv6_community4_cmd, +       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +/* old command */ +DEFUN (show_ipv6_bgp_community, +       show_ipv6_bgp_community_cmd, +       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") +{ +  return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +ALIAS (show_ipv6_bgp_community, +       show_ipv6_bgp_community2_cmd, +       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +/* old command */ +ALIAS (show_ipv6_bgp_community, +       show_ipv6_bgp_community3_cmd, +       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +/* old command */ +ALIAS (show_ipv6_bgp_community, +       show_ipv6_bgp_community4_cmd, +       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +DEFUN (show_bgp_community_exact, +       show_bgp_community_exact_cmd, +       "show bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") +{ +  return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_community_exact, +       show_bgp_ipv6_community_exact_cmd, +       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +ALIAS (show_bgp_community_exact, +       show_bgp_community2_exact_cmd, +       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +ALIAS (show_bgp_community_exact, +       show_bgp_ipv6_community2_exact_cmd, +       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +ALIAS (show_bgp_community_exact, +       show_bgp_community3_exact_cmd, +       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +ALIAS (show_bgp_community_exact, +       show_bgp_ipv6_community3_exact_cmd, +       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +ALIAS (show_bgp_community_exact, +       show_bgp_community4_exact_cmd, +       "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") +  +ALIAS (show_bgp_community_exact, +       show_bgp_ipv6_community4_exact_cmd, +       "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +/* old command */ +DEFUN (show_ipv6_bgp_community_exact, +       show_ipv6_bgp_community_exact_cmd, +       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") +{ +  return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +ALIAS (show_ipv6_bgp_community_exact, +       show_ipv6_bgp_community2_exact_cmd, +       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +/* old command */ +ALIAS (show_ipv6_bgp_community_exact, +       show_ipv6_bgp_community3_exact_cmd, +       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +/* old command */ +ALIAS (show_ipv6_bgp_community_exact, +       show_ipv6_bgp_community4_exact_cmd, +       "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") +  +/* old command */ +DEFUN (show_ipv6_mbgp_community, +       show_ipv6_mbgp_community_cmd, +       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") +{ +  return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_MULTICAST); +} + +/* old command */ +ALIAS (show_ipv6_mbgp_community, +       show_ipv6_mbgp_community2_cmd, +       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +/* old command */ +ALIAS (show_ipv6_mbgp_community, +       show_ipv6_mbgp_community3_cmd, +       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +/* old command */ +ALIAS (show_ipv6_mbgp_community, +       show_ipv6_mbgp_community4_cmd, +       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n") + +/* old command */ +DEFUN (show_ipv6_mbgp_community_exact, +       show_ipv6_mbgp_community_exact_cmd, +       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") +{ +  return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_MULTICAST); +} + +/* old command */ +ALIAS (show_ipv6_mbgp_community_exact, +       show_ipv6_mbgp_community2_exact_cmd, +       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +/* old command */ +ALIAS (show_ipv6_mbgp_community_exact, +       show_ipv6_mbgp_community3_exact_cmd, +       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") + +/* old command */ +ALIAS (show_ipv6_mbgp_community_exact, +       show_ipv6_mbgp_community4_exact_cmd, +       "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes matching the communities\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "community number\n" +       "Do not send outside local AS (well-known community)\n" +       "Do not advertise to any peer (well-known community)\n" +       "Do not export to next AS (well-known community)\n" +       "Exact match of the communities") +#endif /* HAVE_IPV6 */ + +int +bgp_show_community_list (struct vty *vty, char *com, int exact, +			 u_int16_t afi, u_char safi) +{ +  struct community_list *list; + +  list = community_list_lookup (bgp_clist, com, COMMUNITY_LIST_AUTO); +  if (list == NULL) +    { +      vty_out (vty, "%% %s is not a valid community-list name%s", com, +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  vty->output_arg = list; + +  if (exact) +    return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_list_exact); + +  return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_list); +} + +DEFUN (show_ip_bgp_community_list, +       show_ip_bgp_community_list_cmd, +       "show ip bgp community-list WORD", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the community-list\n" +       "community-list name\n") +{ +  return bgp_show_community_list (vty, argv[0], 0, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_community_list, +       show_ip_bgp_ipv4_community_list_cmd, +       "show ip bgp ipv4 (unicast|multicast) community-list WORD", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the community-list\n" +       "community-list name\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_MULTICAST); +   +  return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_community_list_exact, +       show_ip_bgp_community_list_exact_cmd, +       "show ip bgp community-list WORD exact-match", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display routes matching the community-list\n" +       "community-list name\n" +       "Exact match of the communities\n") +{ +  return bgp_show_community_list (vty, argv[0], 1, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_community_list_exact, +       show_ip_bgp_ipv4_community_list_exact_cmd, +       "show ip bgp ipv4 (unicast|multicast) community-list WORD exact-match", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the community-list\n" +       "community-list name\n" +       "Exact match of the communities\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_MULTICAST); +  +  return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_UNICAST); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_community_list, +       show_bgp_community_list_cmd, +       "show bgp community-list WORD", +       SHOW_STR +       BGP_STR +       "Display routes matching the community-list\n" +       "community-list name\n") +{ +  return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_community_list, +       show_bgp_ipv6_community_list_cmd, +       "show bgp ipv6 community-list WORD", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the community-list\n" +       "community-list name\n") + +/* old command */ +DEFUN (show_ipv6_bgp_community_list, +       show_ipv6_bgp_community_list_cmd, +       "show ipv6 bgp community-list WORD", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes matching the community-list\n" +       "community-list name\n") +{ +  return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_community_list, +       show_ipv6_mbgp_community_list_cmd, +       "show ipv6 mbgp community-list WORD", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes matching the community-list\n" +       "community-list name\n") +{ +  return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_MULTICAST); +} + +DEFUN (show_bgp_community_list_exact, +       show_bgp_community_list_exact_cmd, +       "show bgp community-list WORD exact-match", +       SHOW_STR +       BGP_STR +       "Display routes matching the community-list\n" +       "community-list name\n" +       "Exact match of the communities\n") +{ +  return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_community_list_exact, +       show_bgp_ipv6_community_list_exact_cmd, +       "show bgp ipv6 community-list WORD exact-match", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Display routes matching the community-list\n" +       "community-list name\n" +       "Exact match of the communities\n") + +/* old command */ +DEFUN (show_ipv6_bgp_community_list_exact, +       show_ipv6_bgp_community_list_exact_cmd, +       "show ipv6 bgp community-list WORD exact-match", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Display routes matching the community-list\n" +       "community-list name\n" +       "Exact match of the communities\n") +{ +  return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_community_list_exact, +       show_ipv6_mbgp_community_list_exact_cmd, +       "show ipv6 mbgp community-list WORD exact-match", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Display routes matching the community-list\n" +       "community-list name\n" +       "Exact match of the communities\n") +{ +  return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_MULTICAST); +} +#endif /* HAVE_IPV6 */ + +void +bgp_show_prefix_longer_clean (struct vty *vty) +{ +  struct prefix *p; + +  p = vty->output_arg; +  prefix_free (p); +} + +int +bgp_show_prefix_longer (struct vty *vty, char *prefix, afi_t afi, +			safi_t safi, enum bgp_show_type type) +{ +  int ret; +  struct prefix *p; + +  p = prefix_new(); + +  ret = str2prefix (prefix, p); +  if (! ret) +    { +      vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  vty->output_arg = p; +  vty->output_clean = bgp_show_prefix_longer_clean; + +  return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_prefix_longer, +       show_ip_bgp_prefix_longer_cmd, +       "show ip bgp A.B.C.D/M longer-prefixes", +       SHOW_STR +       IP_STR +       BGP_STR +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" +       "Display route and more specific routes\n") +{ +  return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, +				 bgp_show_type_prefix_longer); +} + +DEFUN (show_ip_bgp_flap_prefix_longer, +       show_ip_bgp_flap_prefix_longer_cmd, +       "show ip bgp flap-statistics A.B.C.D/M longer-prefixes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display flap statistics of routes\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" +       "Display route and more specific routes\n") +{ +  return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, +				 bgp_show_type_flap_prefix_longer); +} + +DEFUN (show_ip_bgp_ipv4_prefix_longer, +       show_ip_bgp_ipv4_prefix_longer_cmd, +       "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" +       "Display route and more specific routes\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_MULTICAST, +				   bgp_show_type_prefix_longer); + +  return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_UNICAST, +				 bgp_show_type_prefix_longer); +} + +DEFUN (show_ip_bgp_flap_address, +       show_ip_bgp_flap_address_cmd, +       "show ip bgp flap-statistics A.B.C.D", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display flap statistics of routes\n" +       "Network in the BGP routing table to display\n") +{ +  return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, +				 bgp_show_type_flap_address); +} + +DEFUN (show_ip_bgp_flap_prefix, +       show_ip_bgp_flap_prefix_cmd, +       "show ip bgp flap-statistics A.B.C.D/M", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display flap statistics of routes\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +{ +  return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, +				 bgp_show_type_flap_prefix); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_prefix_longer, +       show_bgp_prefix_longer_cmd, +       "show bgp X:X::X:X/M longer-prefixes", +       SHOW_STR +       BGP_STR +       "IPv6 prefix <network>/<length>\n" +       "Display route and more specific routes\n") +{ +  return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, +				 bgp_show_type_prefix_longer); +} + +ALIAS (show_bgp_prefix_longer, +       show_bgp_ipv6_prefix_longer_cmd, +       "show bgp ipv6 X:X::X:X/M longer-prefixes", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "IPv6 prefix <network>/<length>\n" +       "Display route and more specific routes\n") + +/* old command */ +DEFUN (show_ipv6_bgp_prefix_longer, +       show_ipv6_bgp_prefix_longer_cmd, +       "show ipv6 bgp X:X::X:X/M longer-prefixes", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n" +       "Display route and more specific routes\n") +{ +  return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, +				 bgp_show_type_prefix_longer); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_prefix_longer, +       show_ipv6_mbgp_prefix_longer_cmd, +       "show ipv6 mbgp X:X::X:X/M longer-prefixes", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n" +       "Display route and more specific routes\n") +{ +  return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_MULTICAST, +				 bgp_show_type_prefix_longer); +} +#endif /* HAVE_IPV6 */ + +void +show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, +		int in) +{ +  struct bgp_table *table; +  struct bgp_adj_in *ain; +  struct bgp_adj_out *adj; +  unsigned long output_count; +  struct bgp_node *rn; +  int header1 = 1; +  struct bgp *bgp; +  int header2 = 1; + +  bgp = bgp_get_default (); + +  if (! bgp) +    return; + +  table = bgp->rib[afi][safi]; + +  output_count = 0; +	 +  if (! in && CHECK_FLAG (peer->af_sflags[afi][safi], +			  PEER_STATUS_DEFAULT_ORIGINATE)) +    { +      vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); +      vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE); +      vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE); + +      vty_out (vty, "Originating default network 0.0.0.0%s%s", +	       VTY_NEWLINE, VTY_NEWLINE); +      header1 = 0; +    } + +  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) +    if (in) +      { +	for (ain = rn->adj_in; ain; ain = ain->next) +	  if (ain->peer == peer) +	    { +	      if (header1) +		{ +		  vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); +		  vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE); +		  vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE); +		  header1 = 0; +		} +	      if (header2) +		{ +		  vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); +		  header2 = 0; +		} +	      if (ain->attr) +		{  +		  route_vty_out_tmp (vty, &rn->p, ain->attr, safi); +		  output_count++; +		} +	    } +      } +    else +      { +	for (adj = rn->adj_out; adj; adj = adj->next) +	  if (adj->peer == peer) +	    { +	      if (header1) +		{ +		  vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); +		  vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE); +		  vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE); +		  header1 = 0; +		} +	      if (header2) +		{ +		  vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); +		  header2 = 0; +		} +	      if (adj->attr) +		{	 +		  route_vty_out_tmp (vty, &rn->p, adj->attr, safi); +		  output_count++; +		} +	    } +      } +   +  if (output_count != 0) +    vty_out (vty, "%sTotal number of prefixes %ld%s", +	     VTY_NEWLINE, output_count, VTY_NEWLINE); +} + +int +peer_adj_routes (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, int in) +{ +  int ret; +  struct peer *peer; +  union sockunion su; + +  ret = str2sockunion (ip_str, &su); +  if (ret < 0) +    { +      vty_out (vty, "Malformed address: %s%s", ip_str, VTY_NEWLINE); +      return CMD_WARNING; +    } +  peer = peer_lookup (NULL, &su); +  if (! peer || ! peer->afc[afi][safi]) +    { +      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  if (in && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) +    { +      vty_out (vty, "%% Inbound soft reconfiguration not enabled%s", +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  show_adj_route (vty, peer, afi, safi, in); + +  return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_neighbor_advertised_route, +       show_ip_bgp_neighbor_advertised_route_cmd, +       "show ip bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the routes advertised to a BGP neighbor\n") +{ +  return peer_adj_routes (vty, argv[0], AFI_IP, SAFI_UNICAST, 0); +} + +DEFUN (show_ip_bgp_ipv4_neighbor_advertised_route, +       show_ip_bgp_ipv4_neighbor_advertised_route_cmd, +       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the routes advertised to a BGP neighbor\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_MULTICAST, 0); + +  return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_UNICAST, 0); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_neighbor_advertised_route, +       show_bgp_neighbor_advertised_route_cmd, +       "show bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", +       SHOW_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the routes advertised to a BGP neighbor\n") +{ +  return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 0); +} + +ALIAS (show_bgp_neighbor_advertised_route, +       show_bgp_ipv6_neighbor_advertised_route_cmd, +       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the routes advertised to a BGP neighbor\n") + +/* old command */ +DEFUN (ipv6_bgp_neighbor_advertised_route, +       ipv6_bgp_neighbor_advertised_route_cmd, +       "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the routes advertised to a BGP neighbor\n") +{ +  return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 0); +} + +/* old command */ +DEFUN (ipv6_mbgp_neighbor_advertised_route, +       ipv6_mbgp_neighbor_advertised_route_cmd, +       "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the routes advertised to a BGP neighbor\n") +{ +  return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_MULTICAST, 0); +} +#endif /* HAVE_IPV6 */ + +DEFUN (show_ip_bgp_neighbor_received_routes, +       show_ip_bgp_neighbor_received_routes_cmd, +       "show ip bgp neighbors (A.B.C.D|X:X::X:X) received-routes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the received routes from neighbor\n") +{ +  return peer_adj_routes (vty, argv[0], AFI_IP, SAFI_UNICAST, 1); +} + +DEFUN (show_ip_bgp_ipv4_neighbor_received_routes, +       show_ip_bgp_ipv4_neighbor_received_routes_cmd, +       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received-routes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the received routes from neighbor\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_MULTICAST, 1); + +  return peer_adj_routes (vty, argv[1], AFI_IP, SAFI_UNICAST, 1); +} + +DEFUN (show_ip_bgp_neighbor_received_prefix_filter, +       show_ip_bgp_neighbor_received_prefix_filter_cmd, +       "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", +       SHOW_STR +       IP_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display information received from a BGP neighbor\n" +       "Display the prefixlist filter\n") +{ +  char name[BUFSIZ]; +  union sockunion *su; +  struct peer *peer; +  int count; + +  su = sockunion_str2su (argv[0]); +  if (su == NULL) +    return CMD_WARNING; + +  peer = peer_lookup (NULL, su); +  if (! peer) +    return CMD_WARNING; + +  sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST); +  count =  prefix_bgp_show_prefix_list (NULL, AFI_IP, name); +  if (count) +    { +      vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE); +      prefix_bgp_show_prefix_list (vty, AFI_IP, name); +    } + +  return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter, +       show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd, +       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display information received from a BGP neighbor\n" +       "Display the prefixlist filter\n") +{ +  char name[BUFSIZ]; +  union sockunion *su; +  struct peer *peer; +  int count; + +  su = sockunion_str2su (argv[1]); +  if (su == NULL) +    return CMD_WARNING; + +  peer = peer_lookup (NULL, su); +  if (! peer) +    return CMD_WARNING; + +  if (strncmp (argv[0], "m", 1) == 0) +    { +      sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_MULTICAST); +      count =  prefix_bgp_show_prefix_list (NULL, AFI_IP, name); +      if (count) +	{ +	  vty_out (vty, "Address family: IPv4 Multicast%s", VTY_NEWLINE); +	  prefix_bgp_show_prefix_list (vty, AFI_IP, name); +	} +    } +  else  +    { +      sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST); +      count =  prefix_bgp_show_prefix_list (NULL, AFI_IP, name); +      if (count) +	{ +	  vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE); +	  prefix_bgp_show_prefix_list (vty, AFI_IP, name); +	} +    } + +  return CMD_SUCCESS; +} + + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_neighbor_received_routes, +       show_bgp_neighbor_received_routes_cmd, +       "show bgp neighbors (A.B.C.D|X:X::X:X) received-routes", +       SHOW_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the received routes from neighbor\n") +{ +  return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 1); +} + +ALIAS (show_bgp_neighbor_received_routes, +       show_bgp_ipv6_neighbor_received_routes_cmd, +       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the received routes from neighbor\n") + +DEFUN (show_bgp_neighbor_received_prefix_filter, +       show_bgp_neighbor_received_prefix_filter_cmd, +       "show bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", +       SHOW_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display information received from a BGP neighbor\n" +       "Display the prefixlist filter\n") +{ +  char name[BUFSIZ]; +  union sockunion *su; +  struct peer *peer; +  int count; + +  su = sockunion_str2su (argv[0]); +  if (su == NULL) +    return CMD_WARNING; + +  peer = peer_lookup (NULL, su); +  if (! peer) +    return CMD_WARNING; + +  sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); +  count =  prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); +  if (count) +    { +      vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); +      prefix_bgp_show_prefix_list (vty, AFI_IP6, name); +    } + +  return CMD_SUCCESS; +} + +ALIAS (show_bgp_neighbor_received_prefix_filter, +       show_bgp_ipv6_neighbor_received_prefix_filter_cmd, +       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display information received from a BGP neighbor\n" +       "Display the prefixlist filter\n") + +/* old command */ +DEFUN (ipv6_bgp_neighbor_received_routes, +       ipv6_bgp_neighbor_received_routes_cmd, +       "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) received-routes", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the received routes from neighbor\n") +{ +  return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_UNICAST, 1); +} + +/* old command */ +DEFUN (ipv6_mbgp_neighbor_received_routes, +       ipv6_mbgp_neighbor_received_routes_cmd, +       "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) received-routes", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the received routes from neighbor\n") +{ +  return peer_adj_routes (vty, argv[0], AFI_IP6, SAFI_MULTICAST, 1); +} +#endif /* HAVE_IPV6 */ + +void +bgp_show_neighbor_route_clean (struct vty *vty) +{ +  union sockunion *su; + +  su = vty->output_arg; +  XFREE (MTYPE_SOCKUNION, su); +} + +int +bgp_show_neighbor_route (struct vty *vty, char *ip_str, afi_t afi, +			 safi_t safi, enum bgp_show_type type) +{ +  union sockunion *su; +  struct peer *peer; + +  su = sockunion_str2su (ip_str); +  if (su == NULL) +    { +      vty_out (vty, "Malformed address: %s%s", ip_str, VTY_NEWLINE); +	       return CMD_WARNING; +    } + +  peer = peer_lookup (NULL, su); +  if (! peer || ! peer->afc[afi][safi]) +    { +      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); +      XFREE (MTYPE_SOCKUNION, su); +      return CMD_WARNING; +    } +  +  vty->output_arg = su; +  vty->output_clean = bgp_show_neighbor_route_clean; + +  return bgp_show (vty, NULL, afi, safi, type); +} + +DEFUN (show_ip_bgp_neighbor_routes, +       show_ip_bgp_neighbor_routes_cmd, +       "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display routes learned from neighbor\n") +{ +  return bgp_show_neighbor_route (vty, argv[0], AFI_IP, SAFI_UNICAST, +				  bgp_show_type_neighbor); +} + +DEFUN (show_ip_bgp_neighbor_flap, +       show_ip_bgp_neighbor_flap_cmd, +       "show ip bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", +       SHOW_STR +       IP_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display flap statistics of the routes learned from neighbor\n") +{ +  return bgp_show_neighbor_route (vty, argv[0], AFI_IP, SAFI_UNICAST, +				  bgp_show_type_flap_neighbor); +} + +DEFUN (show_ip_bgp_neighbor_damp, +       show_ip_bgp_neighbor_damp_cmd, +       "show ip bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display the dampened routes received from neighbor\n") +{ +  return bgp_show_neighbor_route (vty, argv[0], AFI_IP, SAFI_UNICAST, +				  bgp_show_type_damp_neighbor); +} + +DEFUN (show_ip_bgp_ipv4_neighbor_routes, +       show_ip_bgp_ipv4_neighbor_routes_cmd, +       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display routes learned from neighbor\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_neighbor_route (vty, argv[1], AFI_IP, SAFI_MULTICAST, +				    bgp_show_type_neighbor); + +  return bgp_show_neighbor_route (vty, argv[1], AFI_IP, SAFI_UNICAST, +				  bgp_show_type_neighbor); +} +#ifdef HAVE_IPV6 +DEFUN (show_bgp_neighbor_routes, +       show_bgp_neighbor_routes_cmd, +       "show bgp neighbors (A.B.C.D|X:X::X:X) routes", +       SHOW_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display routes learned from neighbor\n") +{ +  return bgp_show_neighbor_route (vty, argv[0], AFI_IP6, SAFI_UNICAST, +				  bgp_show_type_neighbor); +} + +ALIAS (show_bgp_neighbor_routes, +       show_bgp_ipv6_neighbor_routes_cmd, +       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) routes", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display routes learned from neighbor\n") + +/* old command */ +DEFUN (ipv6_bgp_neighbor_routes, +       ipv6_bgp_neighbor_routes_cmd, +       "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display routes learned from neighbor\n") +{ +  return bgp_show_neighbor_route (vty, argv[0], AFI_IP6, SAFI_UNICAST, +				  bgp_show_type_neighbor); +} + +/* old command */ +DEFUN (ipv6_mbgp_neighbor_routes, +       ipv6_mbgp_neighbor_routes_cmd, +       "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n" +       "Display routes learned from neighbor\n") +{ +  return bgp_show_neighbor_route (vty, argv[0], AFI_IP6, SAFI_MULTICAST, +				  bgp_show_type_neighbor); +} +#endif /* HAVE_IPV6 */ + +struct bgp_table *bgp_distance_table; + +struct bgp_distance +{ +  /* Distance value for the IP source prefix. */ +  u_char distance; + +  /* Name of the access-list to be matched. */ +  char *access_list; +}; + +struct bgp_distance * +bgp_distance_new () +{ +  struct bgp_distance *new; +  new = XMALLOC (MTYPE_BGP_DISTANCE, sizeof (struct bgp_distance)); +  memset (new, 0, sizeof (struct bgp_distance)); +  return new; +} + +void +bgp_distance_free (struct bgp_distance *bdistance) +{ +  XFREE (MTYPE_BGP_DISTANCE, bdistance); +} + +int +bgp_distance_set (struct vty *vty, char *distance_str, char *ip_str, +		  char *access_list_str) +{ +  int ret; +  struct prefix_ipv4 p; +  u_char distance; +  struct bgp_node *rn; +  struct bgp_distance *bdistance; + +  ret = str2prefix_ipv4 (ip_str, &p); +  if (ret == 0) +    { +      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  distance = atoi (distance_str); + +  /* Get BGP distance node. */ +  rn = bgp_node_get (bgp_distance_table, (struct prefix *) &p); +  if (rn->info) +    { +      bdistance = rn->info; +      bgp_unlock_node (rn); +    } +  else +    { +      bdistance = bgp_distance_new (); +      rn->info = bdistance; +    } + +  /* Set distance value. */ +  bdistance->distance = distance; + +  /* Reset access-list configuration. */ +  if (bdistance->access_list) +    { +      free (bdistance->access_list); +      bdistance->access_list = NULL; +    } +  if (access_list_str) +    bdistance->access_list = strdup (access_list_str); + +  return CMD_SUCCESS; +} + +int +bgp_distance_unset (struct vty *vty, char *distance_str, char *ip_str, +		    char *access_list_str) +{ +  int ret; +  struct prefix_ipv4 p; +  u_char distance; +  struct bgp_node *rn; +  struct bgp_distance *bdistance; + +  ret = str2prefix_ipv4 (ip_str, &p); +  if (ret == 0) +    { +      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  distance = atoi (distance_str); + +  rn = bgp_node_lookup (bgp_distance_table, (struct prefix *)&p); +  if (! rn) +    { +      vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bdistance = rn->info; + +  if (bdistance->access_list) +    free (bdistance->access_list); +  bgp_distance_free (bdistance); + +  rn->info = NULL; +  bgp_unlock_node (rn); +  bgp_unlock_node (rn); + +  return CMD_SUCCESS; +} + +void +bgp_distance_reset () +{ +  struct bgp_node *rn; +  struct bgp_distance *bdistance; + +  for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) +    if ((bdistance = rn->info) != NULL) +      { +	if (bdistance->access_list) +	  free (bdistance->access_list); +	bgp_distance_free (bdistance); +	rn->info = NULL; +	bgp_unlock_node (rn); +      } +} + +/* Apply BGP information to distance method. */ +u_char +bgp_distance_apply (struct prefix *p, struct bgp_info *rinfo, struct bgp *bgp) +{ +  struct bgp_node *rn; +  struct prefix_ipv4 q; +  struct peer *peer; +  struct bgp_distance *bdistance; +  struct access_list *alist; +  struct bgp_static *bgp_static; + +  if (! bgp) +    return 0; + +  if (p->family != AF_INET) +    return 0; + +  peer = rinfo->peer; + +  if (peer->su.sa.sa_family != AF_INET) +    return 0; + +  memset (&q, 0, sizeof (struct prefix_ipv4)); +  q.family = AF_INET; +  q.prefix = peer->su.sin.sin_addr; +  q.prefixlen = IPV4_MAX_BITLEN; + +  /* Check source address. */ +  rn = bgp_node_match (bgp_distance_table, (struct prefix *) &q); +  if (rn) +    { +      bdistance = rn->info; +      bgp_unlock_node (rn); + +      if (bdistance->access_list) +	{ +	  alist = access_list_lookup (AFI_IP, bdistance->access_list); +	  if (alist && access_list_apply (alist, p) == FILTER_PERMIT) +	    return bdistance->distance; +	} +      else +	return bdistance->distance; +    } + +  /* Backdoor check. */ +  rn = bgp_node_lookup (bgp->route[AFI_IP][SAFI_UNICAST], p); +  if (rn) +    { +      bgp_static = rn->info; +      bgp_unlock_node (rn); + +      if (bgp_static->backdoor) +	{ +	  if (bgp->distance_local) +	    return bgp->distance_local; +	  else +	    return ZEBRA_IBGP_DISTANCE_DEFAULT; +	} +    } + +  if (peer_sort (peer) == BGP_PEER_EBGP) +    { +      if (bgp->distance_ebgp) +	return bgp->distance_ebgp; +      return ZEBRA_EBGP_DISTANCE_DEFAULT; +    } +  else +    { +      if (bgp->distance_ibgp) +	return bgp->distance_ibgp; +      return ZEBRA_IBGP_DISTANCE_DEFAULT; +    } +} + +DEFUN (bgp_distance, +       bgp_distance_cmd, +       "distance bgp <1-255> <1-255> <1-255>", +       "Define an administrative distance\n" +       "BGP distance\n" +       "Distance for routes external to the AS\n" +       "Distance for routes internal to the AS\n" +       "Distance for local routes\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; + +  bgp->distance_ebgp = atoi (argv[0]); +  bgp->distance_ibgp = atoi (argv[1]); +  bgp->distance_local = atoi (argv[2]); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_distance, +       no_bgp_distance_cmd, +       "no distance bgp <1-255> <1-255> <1-255>", +       NO_STR +       "Define an administrative distance\n" +       "BGP distance\n" +       "Distance for routes external to the AS\n" +       "Distance for routes internal to the AS\n" +       "Distance for local routes\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; + +  bgp->distance_ebgp= 0; +  bgp->distance_ibgp = 0; +  bgp->distance_local = 0; +  return CMD_SUCCESS; +} + +ALIAS (no_bgp_distance, +       no_bgp_distance2_cmd, +       "no distance bgp", +       NO_STR +       "Define an administrative distance\n" +       "BGP distance\n") + +DEFUN (bgp_distance_source, +       bgp_distance_source_cmd, +       "distance <1-255> A.B.C.D/M", +       "Define an administrative distance\n" +       "Administrative distance\n" +       "IP source prefix\n") +{ +  bgp_distance_set (vty, argv[0], argv[1], NULL); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_distance_source, +       no_bgp_distance_source_cmd, +       "no distance <1-255> A.B.C.D/M", +       NO_STR +       "Define an administrative distance\n" +       "Administrative distance\n" +       "IP source prefix\n") +{ +  bgp_distance_unset (vty, argv[0], argv[1], NULL); +  return CMD_SUCCESS; +} + +DEFUN (bgp_distance_source_access_list, +       bgp_distance_source_access_list_cmd, +       "distance <1-255> A.B.C.D/M WORD", +       "Define an administrative distance\n" +       "Administrative distance\n" +       "IP source prefix\n" +       "Access list name\n") +{ +  bgp_distance_set (vty, argv[0], argv[1], argv[2]); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_distance_source_access_list, +       no_bgp_distance_source_access_list_cmd, +       "no distance <1-255> A.B.C.D/M WORD", +       NO_STR +       "Define an administrative distance\n" +       "Administrative distance\n" +       "IP source prefix\n" +       "Access list name\n") +{ +  bgp_distance_unset (vty, argv[0], argv[1], argv[2]); +  return CMD_SUCCESS; +} + +DEFUN (bgp_damp_set, +       bgp_damp_set_cmd, +       "bgp dampening <1-45> <1-20000> <1-20000> <1-255>", +       "BGP Specific commands\n" +       "Enable route-flap dampening\n" +       "Half-life time for the penalty\n" +       "Value to start reusing a route\n" +       "Value to start suppressing a route\n" +       "Maximum duration to suppress a stable route\n") +{ +  struct bgp *bgp; +  int half = DEFAULT_HALF_LIFE * 60; +  int reuse = DEFAULT_REUSE; +  int suppress = DEFAULT_SUPPRESS; +  int max = 4 * half; + +  if (argc == 4) +    { +      half = atoi (argv[0]) * 60; +      reuse = atoi (argv[1]); +      suppress = atoi (argv[2]); +      max = atoi (argv[3]) * 60; +    } +  else if (argc == 1) +    { +      half = atoi (argv[0]) * 60; +      max = 4 * half; +    } + +  bgp = vty->index; +  return bgp_damp_enable (bgp, bgp_node_afi (vty), bgp_node_safi (vty), +			  half, reuse, suppress, max); +} + +ALIAS (bgp_damp_set, +       bgp_damp_set2_cmd, +       "bgp dampening <1-45>", +       "BGP Specific commands\n" +       "Enable route-flap dampening\n" +       "Half-life time for the penalty\n") + +ALIAS (bgp_damp_set, +       bgp_damp_set3_cmd, +       "bgp dampening", +       "BGP Specific commands\n" +       "Enable route-flap dampening\n") + +DEFUN (bgp_damp_unset, +       bgp_damp_unset_cmd, +       "no bgp dampening", +       NO_STR +       "BGP Specific commands\n" +       "Enable route-flap dampening\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  return bgp_damp_disable (bgp, bgp_node_afi (vty), bgp_node_safi (vty)); +} + +ALIAS (bgp_damp_unset, +       bgp_damp_unset2_cmd, +       "no bgp dampening <1-45> <1-20000> <1-20000> <1-255>", +       NO_STR +       "BGP Specific commands\n" +       "Enable route-flap dampening\n" +       "Half-life time for the penalty\n" +       "Value to start reusing a route\n" +       "Value to start suppressing a route\n" +       "Maximum duration to suppress a stable route\n") + +DEFUN (show_ip_bgp_dampened_paths, +       show_ip_bgp_dampened_paths_cmd, +       "show ip bgp dampened-paths", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display paths suppressed due to dampening\n") +{ +  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_dampend_paths); +} + +DEFUN (show_ip_bgp_flap_statistics, +       show_ip_bgp_flap_statistics_cmd, +       "show ip bgp flap-statistics", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display flap statistics of routes\n") +{ +  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_flap_statistics); +} + +/* Display specified route of BGP table. */ +int +bgp_clear_damp_route (struct vty *vty, char *view_name, char *ip_str, +		      afi_t afi, safi_t safi, struct prefix_rd *prd, +		      int prefix_check) +{ +  int ret; +  struct prefix match; +  struct bgp_node *rn; +  struct bgp_node *rm; +  struct bgp_info *ri; +  struct bgp_info *ri_temp; +  struct bgp *bgp; +  struct bgp_table *table; + +  /* BGP structure lookup. */ +  if (view_name) +    { +      bgp = bgp_lookup_by_name (view_name); +      if (bgp == NULL) +	{ +	  vty_out (vty, "%% Can't find BGP view %s%s", view_name, VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } +  else +    { +      bgp = bgp_get_default (); +      if (bgp == NULL) +	{ +	  vty_out (vty, "%% No BGP process is configured%s", VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } + +  /* Check IP address argument. */ +  ret = str2prefix (ip_str, &match); +  if (! ret) +    { +      vty_out (vty, "%% address is malformed%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  match.family = afi2family (afi); + +  if (safi == SAFI_MPLS_VPN) +    { +      for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) +        { +          if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) +            continue; + +	  if ((table = rn->info) != NULL) +	    if ((rm = bgp_node_match (table, &match)) != NULL) +	      if (! prefix_check || rm->p.prefixlen == match.prefixlen) +		{ +		  ri = rm->info; +		  while (ri) +		    { +		      if (ri->damp_info) +			{ +			  ri_temp = ri->next; +			  bgp_damp_info_free (ri->damp_info, 1); +			  ri = ri_temp; +			} +		      else +			ri = ri->next; +		    } +		} +        } +    } +  else +    { +      if ((rn = bgp_node_match (bgp->rib[afi][safi], &match)) != NULL) +	if (! prefix_check || rn->p.prefixlen == match.prefixlen) +	  { +	    ri = rn->info; +	    while (ri) +	      { +		if (ri->damp_info) +		  { +		    ri_temp = ri->next; +		    bgp_damp_info_free (ri->damp_info, 1); +		    ri = ri_temp; +		  } +		else +		  ri = ri->next; +	      } +	  } +    } + +  return CMD_SUCCESS; +} + +DEFUN (clear_ip_bgp_dampening, +       clear_ip_bgp_dampening_cmd, +       "clear ip bgp dampening", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear route flap dampening information\n") +{ +  bgp_damp_info_clean (); +  return CMD_SUCCESS; +} + +DEFUN (clear_ip_bgp_dampening_prefix, +       clear_ip_bgp_dampening_prefix_cmd, +       "clear ip bgp dampening A.B.C.D/M", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear route flap dampening information\n" +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +{ +  return bgp_clear_damp_route (vty, NULL, argv[0], AFI_IP, +			       SAFI_UNICAST, NULL, 1); +} + +DEFUN (clear_ip_bgp_dampening_address, +       clear_ip_bgp_dampening_address_cmd, +       "clear ip bgp dampening A.B.C.D", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear route flap dampening information\n" +       "Network to clear damping information\n") +{ +  return bgp_clear_damp_route (vty, NULL, argv[0], AFI_IP, +			       SAFI_UNICAST, NULL, 0); +} + +DEFUN (clear_ip_bgp_dampening_address_mask, +       clear_ip_bgp_dampening_address_mask_cmd, +       "clear ip bgp dampening A.B.C.D A.B.C.D", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear route flap dampening information\n" +       "Network to clear damping information\n" +       "Network mask\n") +{ +  int ret; +  char prefix_str[BUFSIZ]; + +  ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); +  if (! ret) +    { +      vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_clear_damp_route (vty, NULL, prefix_str, AFI_IP, +			       SAFI_UNICAST, NULL, 0); +} + +int +bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp, +				afi_t afi, safi_t safi, int *write) +{ +  struct bgp_node *prn; +  struct bgp_node *rn; +  struct bgp_table *table; +  struct prefix *p; +  struct prefix_rd *prd; +  struct bgp_static *bgp_static; +  u_int32_t label; +  char buf[SU_ADDRSTRLEN]; +  char rdbuf[RD_ADDRSTRLEN]; +   +  /* Network configuration. */ +  for (prn = bgp_table_top (bgp->route[afi][safi]); prn; prn = bgp_route_next (prn)) +    if ((table = prn->info) != NULL) +      for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))  +	if ((bgp_static = rn->info) != NULL) +	  { +	    p = &rn->p; +	    prd = (struct prefix_rd *) &prn->p; + +	    /* "address-family" display.  */ +	    bgp_config_write_family_header (vty, afi, safi, write); + +	    /* "network" configuration display.  */ +	    prefix_rd2str (prd, rdbuf, RD_ADDRSTRLEN); +	    label = decode_label (bgp_static->tag); + +	    vty_out (vty, " network %s/%d rd %s tag %d", +		     inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),  +		     p->prefixlen, +		     rdbuf, label); +	    vty_out (vty, "%s", VTY_NEWLINE); +	  } +  return 0; +} + +/* Configuration of static route announcement and aggregate +   information. */ +int +bgp_config_write_network (struct vty *vty, struct bgp *bgp, +			  afi_t afi, safi_t safi, int *write) +{ +  struct bgp_node *rn; +  struct prefix *p; +  struct bgp_static *bgp_static; +  struct bgp_aggregate *bgp_aggregate; +  char buf[SU_ADDRSTRLEN]; +   +  if (afi == AFI_IP && safi == SAFI_MPLS_VPN) +    return bgp_config_write_network_vpnv4 (vty, bgp, afi, safi, write); + +  /* Network configuration. */ +  for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))  +    if ((bgp_static = rn->info) != NULL) +      { +	p = &rn->p; + +	/* "address-family" display.  */ +	bgp_config_write_family_header (vty, afi, safi, write); + +	/* "network" configuration display.  */ +	if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) +	  { +	    u_int32_t destination;  +	    struct in_addr netmask; + +	    destination = ntohl (p->u.prefix4.s_addr); +	    masklen2ip (p->prefixlen, &netmask); +	    vty_out (vty, " network %s", +		     inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN)); + +	    if ((IN_CLASSC (destination) && p->prefixlen == 24) +		|| (IN_CLASSB (destination) && p->prefixlen == 16) +		|| (IN_CLASSA (destination) && p->prefixlen == 8) +		|| p->u.prefix4.s_addr == 0) +	      { +		/* Natural mask is not display. */ +	      } +	    else +	      vty_out (vty, " mask %s", inet_ntoa (netmask)); +	  } +	else +	  { +	    vty_out (vty, " network %s/%d", +		     inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),  +		     p->prefixlen); +	  } + +	if (bgp_static->rmap.name) +	  vty_out (vty, " route-map %s", bgp_static->rmap.name); +	else if (bgp_static->backdoor) +	  vty_out (vty, " backdoor"); + +	vty_out (vty, "%s", VTY_NEWLINE); +      } + +  /* Aggregate-address configuration. */ +  for (rn = bgp_table_top (bgp->aggregate[afi][safi]); rn; rn = bgp_route_next (rn)) +    if ((bgp_aggregate = rn->info) != NULL) +      { +	p = &rn->p; + +	/* "address-family" display.  */ +	bgp_config_write_family_header (vty, afi, safi, write); + +	if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) +	  { +	    struct in_addr netmask; + +	    masklen2ip (p->prefixlen, &netmask); +	    vty_out (vty, " aggregate-address %s %s", +		     inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +		     inet_ntoa (netmask)); +	  } +	else +	  { +	    vty_out (vty, " aggregate-address %s/%d", +		     inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +		     p->prefixlen); +	  } + +	if (bgp_aggregate->as_set) +	  vty_out (vty, " as-set"); +	 +	if (bgp_aggregate->summary_only) +	  vty_out (vty, " summary-only"); + +	vty_out (vty, "%s", VTY_NEWLINE); +      } + +  return 0; +} + +int +bgp_config_write_distance (struct vty *vty, struct bgp *bgp) +{ +  struct bgp_node *rn; +  struct bgp_distance *bdistance; + +  /* Distance configuration. */ +  if (bgp->distance_ebgp +      && bgp->distance_ibgp +      && bgp->distance_local +      && (bgp->distance_ebgp != ZEBRA_EBGP_DISTANCE_DEFAULT +	  || bgp->distance_ibgp != ZEBRA_IBGP_DISTANCE_DEFAULT +	  || bgp->distance_local != ZEBRA_IBGP_DISTANCE_DEFAULT)) +    vty_out (vty, " distance bgp %d %d %d%s", +	     bgp->distance_ebgp, bgp->distance_ibgp, bgp->distance_local, +	     VTY_NEWLINE); +   +  for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) +    if ((bdistance = rn->info) != NULL) +      { +	vty_out (vty, " distance %d %s/%d %s%s", bdistance->distance, +		 inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, +		 bdistance->access_list ? bdistance->access_list : "", +		 VTY_NEWLINE); +      } + +  return 0; +} + +/* Allocate routing table structure and install commands. */ +void +bgp_route_init () +{ +  /* Init BGP distance table. */ +  bgp_distance_table = bgp_table_init (); + +  /* IPv4 BGP commands. */ +  install_element (BGP_NODE, &bgp_network_cmd); +  install_element (BGP_NODE, &bgp_network_mask_cmd); +  install_element (BGP_NODE, &bgp_network_mask_natural_cmd); +  install_element (BGP_NODE, &bgp_network_route_map_cmd); +  install_element (BGP_NODE, &bgp_network_mask_route_map_cmd); +  install_element (BGP_NODE, &bgp_network_mask_natural_route_map_cmd); +  install_element (BGP_NODE, &bgp_network_backdoor_cmd); +  install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd); +  install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd); +  install_element (BGP_NODE, &no_bgp_network_cmd); +  install_element (BGP_NODE, &no_bgp_network_mask_cmd); +  install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd); +  install_element (BGP_NODE, &no_bgp_network_route_map_cmd); +  install_element (BGP_NODE, &no_bgp_network_mask_route_map_cmd); +  install_element (BGP_NODE, &no_bgp_network_mask_natural_route_map_cmd); +  install_element (BGP_NODE, &no_bgp_network_backdoor_cmd); +  install_element (BGP_NODE, &no_bgp_network_mask_backdoor_cmd); +  install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_cmd); + +  install_element (BGP_NODE, &aggregate_address_cmd); +  install_element (BGP_NODE, &aggregate_address_mask_cmd); +  install_element (BGP_NODE, &aggregate_address_summary_only_cmd); +  install_element (BGP_NODE, &aggregate_address_mask_summary_only_cmd); +  install_element (BGP_NODE, &aggregate_address_as_set_cmd); +  install_element (BGP_NODE, &aggregate_address_mask_as_set_cmd); +  install_element (BGP_NODE, &aggregate_address_as_set_summary_cmd); +  install_element (BGP_NODE, &aggregate_address_mask_as_set_summary_cmd); +  install_element (BGP_NODE, &aggregate_address_summary_as_set_cmd); +  install_element (BGP_NODE, &aggregate_address_mask_summary_as_set_cmd); +  install_element (BGP_NODE, &no_aggregate_address_cmd); +  install_element (BGP_NODE, &no_aggregate_address_summary_only_cmd); +  install_element (BGP_NODE, &no_aggregate_address_as_set_cmd); +  install_element (BGP_NODE, &no_aggregate_address_as_set_summary_cmd); +  install_element (BGP_NODE, &no_aggregate_address_summary_as_set_cmd); +  install_element (BGP_NODE, &no_aggregate_address_mask_cmd); +  install_element (BGP_NODE, &no_aggregate_address_mask_summary_only_cmd); +  install_element (BGP_NODE, &no_aggregate_address_mask_as_set_cmd); +  install_element (BGP_NODE, &no_aggregate_address_mask_as_set_summary_cmd); +  install_element (BGP_NODE, &no_aggregate_address_mask_summary_as_set_cmd); + +  /* IPv4 unicast configuration.  */ +  install_element (BGP_IPV4_NODE, &bgp_network_cmd); +  install_element (BGP_IPV4_NODE, &bgp_network_mask_cmd); +  install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_cmd); +  install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd); +  install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd); +  install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd); +  install_element (BGP_IPV4_NODE, &no_bgp_network_cmd); +  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd); +  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd); +  install_element (BGP_IPV4_NODE, &no_bgp_network_route_map_cmd); +  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_route_map_cmd); +  install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_route_map_cmd); +  install_element (BGP_IPV4_NODE, &aggregate_address_cmd); +  install_element (BGP_IPV4_NODE, &aggregate_address_mask_cmd); +  install_element (BGP_IPV4_NODE, &aggregate_address_summary_only_cmd); +  install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_only_cmd); +  install_element (BGP_IPV4_NODE, &aggregate_address_as_set_cmd); +  install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_cmd); +  install_element (BGP_IPV4_NODE, &aggregate_address_as_set_summary_cmd); +  install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_summary_cmd); +  install_element (BGP_IPV4_NODE, &aggregate_address_summary_as_set_cmd); +  install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_as_set_cmd); +  install_element (BGP_IPV4_NODE, &no_aggregate_address_cmd); +  install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_only_cmd); +  install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_cmd); +  install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_summary_cmd); +  install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_as_set_cmd); +  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_cmd); +  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_only_cmd); +  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_cmd); +  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_summary_cmd); +  install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_as_set_cmd); + +  /* IPv4 multicast configuration.  */ +  install_element (BGP_IPV4M_NODE, &bgp_network_cmd); +  install_element (BGP_IPV4M_NODE, &bgp_network_mask_cmd); +  install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd); +  install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd); +  install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd); +  install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd); +  install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd); +  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd); +  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd); +  install_element (BGP_IPV4M_NODE, &no_bgp_network_route_map_cmd); +  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_route_map_cmd); +  install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_route_map_cmd); +  install_element (BGP_IPV4M_NODE, &aggregate_address_cmd); +  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd); +  install_element (BGP_IPV4M_NODE, &aggregate_address_summary_only_cmd); +  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_only_cmd); +  install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_cmd); +  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_cmd); +  install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_summary_cmd); +  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_summary_cmd); +  install_element (BGP_IPV4M_NODE, &aggregate_address_summary_as_set_cmd); +  install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_as_set_cmd); +  install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd); +  install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_only_cmd); +  install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_cmd); +  install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_summary_cmd); +  install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_as_set_cmd); +  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd); +  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_only_cmd); +  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_cmd); +  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_summary_cmd); +  install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_as_set_cmd); + +  install_element (VIEW_NODE, &show_ip_bgp_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_route_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_view_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_community_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_community2_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_community3_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_community4_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd); + +  install_element (ENABLE_NODE, &show_ip_bgp_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_route_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_view_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_community_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd); + + /* BGP dampening clear commands */ +  install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd); + +#ifdef HAVE_IPV6 +  /* New config IPv6 BGP commands.  */ +  install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd); +  install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd); +  install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd); +  install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd); + +  install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd); +  install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd); +  install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd); +  install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd); + +  /* Old config IPv6 BGP commands.  */ +  install_element (BGP_NODE, &old_ipv6_bgp_network_cmd); +  install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd); + +  install_element (BGP_NODE, &old_ipv6_aggregate_address_cmd); +  install_element (BGP_NODE, &old_ipv6_aggregate_address_summary_only_cmd); +  install_element (BGP_NODE, &old_no_ipv6_aggregate_address_cmd); +  install_element (BGP_NODE, &old_no_ipv6_aggregate_address_summary_only_cmd); + +  install_element (VIEW_NODE, &show_bgp_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_cmd); +  install_element (VIEW_NODE, &show_bgp_route_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd); +  install_element (VIEW_NODE, &show_bgp_prefix_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd); +  install_element (VIEW_NODE, &show_bgp_regexp_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd); +  install_element (VIEW_NODE, &show_bgp_prefix_list_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd); +  install_element (VIEW_NODE, &show_bgp_filter_list_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd); +  install_element (VIEW_NODE, &show_bgp_route_map_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd); +  install_element (VIEW_NODE, &show_bgp_community_all_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd); +  install_element (VIEW_NODE, &show_bgp_community_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd); +  install_element (VIEW_NODE, &show_bgp_community2_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd); +  install_element (VIEW_NODE, &show_bgp_community3_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd); +  install_element (VIEW_NODE, &show_bgp_community4_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd); +  install_element (VIEW_NODE, &show_bgp_community_exact_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd); +  install_element (VIEW_NODE, &show_bgp_community2_exact_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd); +  install_element (VIEW_NODE, &show_bgp_community3_exact_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd); +  install_element (VIEW_NODE, &show_bgp_community4_exact_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd); +  install_element (VIEW_NODE, &show_bgp_community_list_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd); +  install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd); +  install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd); +  install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); +  install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); +  install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd); +  install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); + +  install_element (ENABLE_NODE, &show_bgp_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_cmd); +  install_element (ENABLE_NODE, &show_bgp_route_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd); +  install_element (ENABLE_NODE, &show_bgp_prefix_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd); +  install_element (ENABLE_NODE, &show_bgp_regexp_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd); +  install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd); +  install_element (ENABLE_NODE, &show_bgp_filter_list_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd); +  install_element (ENABLE_NODE, &show_bgp_route_map_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd); +  install_element (ENABLE_NODE, &show_bgp_community_all_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd); +  install_element (ENABLE_NODE, &show_bgp_community_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd); +  install_element (ENABLE_NODE, &show_bgp_community2_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd); +  install_element (ENABLE_NODE, &show_bgp_community3_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd); +  install_element (ENABLE_NODE, &show_bgp_community4_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd); +  install_element (ENABLE_NODE, &show_bgp_community_exact_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd); +  install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd); +  install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd); +  install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd); +  install_element (ENABLE_NODE, &show_bgp_community_list_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd); +  install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd); +  install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd); +  install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); +  install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); +  install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd); +  install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); + +  /* old command */ +  install_element (VIEW_NODE, &show_ipv6_bgp_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd); +  install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd); + +  /* old command */ +  install_element (ENABLE_NODE, &show_ipv6_bgp_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd); + +  /* old command */ +  install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); +  install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); +  install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); +  install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); + +  /* old command */ +  install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd); +  install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd); +  install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); +  install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); + +  /* old command */ +  install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd); +  install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd); +  install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd); +  install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd); +#endif /* HAVE_IPV6 */ + +  install_element (BGP_NODE, &bgp_distance_cmd); +  install_element (BGP_NODE, &no_bgp_distance_cmd); +  install_element (BGP_NODE, &no_bgp_distance2_cmd); +  install_element (BGP_NODE, &bgp_distance_source_cmd); +  install_element (BGP_NODE, &no_bgp_distance_source_cmd); +  install_element (BGP_NODE, &bgp_distance_source_access_list_cmd); +  install_element (BGP_NODE, &no_bgp_distance_source_access_list_cmd); + +  install_element (BGP_NODE, &bgp_damp_set_cmd); +  install_element (BGP_NODE, &bgp_damp_set2_cmd); +  install_element (BGP_NODE, &bgp_damp_set3_cmd); +  install_element (BGP_NODE, &bgp_damp_unset_cmd); +  install_element (BGP_NODE, &bgp_damp_unset2_cmd); +  install_element (BGP_IPV4_NODE, &bgp_damp_set_cmd); +  install_element (BGP_IPV4_NODE, &bgp_damp_set2_cmd); +  install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd); +  install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd); +  install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd); +} diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h new file mode 100644 index 0000000000..a11aa143a2 --- /dev/null +++ b/bgpd/bgp_route.h @@ -0,0 +1,159 @@ +/* BGP routing information base +   Copyright (C) 1996, 97, 98, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +struct bgp_info +{ +  /* For linked list. */ +  struct bgp_info *next; +  struct bgp_info *prev; + +  /* BGP route type.  This can be static, RIP, OSPF, BGP etc.  */ +  u_char type; + +  /* When above type is BGP.  This sub type specify BGP sub type +     information.  */ +  u_char sub_type; +#define BGP_ROUTE_NORMAL       0 +#define BGP_ROUTE_STATIC       1 +#define BGP_ROUTE_AGGREGATE    2 +#define BGP_ROUTE_REDISTRIBUTE 3  + +  /* BGP information status.  */ +  u_char flags; +#define BGP_INFO_IGP_CHANGED    (1 << 0) +#define BGP_INFO_DAMPED         (1 << 1) +#define BGP_INFO_HISTORY        (1 << 2) +#define BGP_INFO_SELECTED       (1 << 3) +#define BGP_INFO_VALID          (1 << 4) +#define BGP_INFO_ATTR_CHANGED   (1 << 5) +#define BGP_INFO_DMED_CHECK     (1 << 6) +#define BGP_INFO_DMED_SELECTED  (1 << 7) + +  /* Peer structure.  */ +  struct peer *peer; + +  /* Attribute structure.  */ +  struct attr *attr; + +  /* This route is suppressed with aggregation.  */ +  int suppress; +   +  /* Nexthop reachability check.  */ +  u_int32_t igpmetric; + +  /* Uptime.  */ +  time_t uptime; + +  /* Pointer to dampening structure.  */ +  struct bgp_damp_info *damp_info; + +  /* MPLS label.  */ +  u_char tag[3]; +}; + +/* BGP static route configuration. */ +struct bgp_static +{ +  /* Backdoor configuration.  */ +  int backdoor; + +  /* Import check status.  */ +  u_char valid; + +  /* IGP metric. */ +  u_int32_t igpmetric; + +  /* IGP nexthop. */ +  struct in_addr igpnexthop; + +  /* BGP redistribute route-map.  */ +  struct +  { +    char *name; +    struct route_map *map; +  } rmap; + +  /* MPLS label.  */ +  u_char tag[3]; +}; + +#define DISTRIBUTE_IN_NAME(F)   ((F)->dlist[FILTER_IN].name) +#define DISTRIBUTE_IN(F)        ((F)->dlist[FILTER_IN].alist) +#define DISTRIBUTE_OUT_NAME(F)  ((F)->dlist[FILTER_OUT].name) +#define DISTRIBUTE_OUT(F)       ((F)->dlist[FILTER_OUT].alist) + +#define PREFIX_LIST_IN_NAME(F)  ((F)->plist[FILTER_IN].name) +#define PREFIX_LIST_IN(F)       ((F)->plist[FILTER_IN].plist) +#define PREFIX_LIST_OUT_NAME(F) ((F)->plist[FILTER_OUT].name) +#define PREFIX_LIST_OUT(F)      ((F)->plist[FILTER_OUT].plist) + +#define FILTER_LIST_IN_NAME(F)  ((F)->aslist[FILTER_IN].name) +#define FILTER_LIST_IN(F)       ((F)->aslist[FILTER_IN].aslist) +#define FILTER_LIST_OUT_NAME(F) ((F)->aslist[FILTER_OUT].name) +#define FILTER_LIST_OUT(F)      ((F)->aslist[FILTER_OUT].aslist) + +#define ROUTE_MAP_IN_NAME(F)    ((F)->map[FILTER_IN].name) +#define ROUTE_MAP_IN(F)         ((F)->map[FILTER_IN].map) +#define ROUTE_MAP_OUT_NAME(F)   ((F)->map[FILTER_OUT].name) +#define ROUTE_MAP_OUT(F)        ((F)->map[FILTER_OUT].map) + +#define UNSUPPRESS_MAP_NAME(F)  ((F)->usmap.name) +#define UNSUPPRESS_MAP(F)       ((F)->usmap.map) + +/* Prototypes. */ +void bgp_route_init (); +void bgp_announce_route (struct peer *, afi_t, safi_t); +void bgp_announce_route_all (struct peer *); +void bgp_default_originate (struct peer *, afi_t, safi_t, int); +void bgp_soft_reconfig_in (struct peer *, afi_t, safi_t); +void bgp_clear_route (struct peer *, afi_t, safi_t); +void bgp_clear_route_all (struct peer *); +void bgp_clear_adj_in (struct peer *, afi_t, safi_t); + +int bgp_nlri_sanity_check (struct peer *, int, u_char *, bgp_size_t); +int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); + +int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t); + +void bgp_redistribute_add (struct prefix *, struct in_addr *, u_int32_t, u_char); +void bgp_redistribute_delete (struct prefix *, u_char); +void bgp_redistribute_withdraw (struct bgp *, afi_t, int); + +void bgp_static_delete (struct bgp *); +void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static *, +			afi_t, safi_t); +void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t); +                      +int bgp_static_set_vpnv4 (struct vty *vty, char *, char *, char *); + +int bgp_static_unset_vpnv4 (struct vty *, char *, char *, char *); + +int bgp_config_write_network (struct vty *, struct bgp *, afi_t, safi_t, int *); +int bgp_config_write_distance (struct vty *, struct bgp *); + +void bgp_aggregate_increment (struct bgp *, struct prefix *, struct bgp_info *, +			      afi_t, safi_t); +void bgp_aggregate_decrement (struct bgp *, struct prefix *, struct bgp_info *, +			      afi_t, safi_t); + +u_char bgp_distance_apply (struct prefix *, struct bgp_info *, struct bgp *); + +afi_t bgp_node_afi (struct vty *); +safi_t bgp_node_safi (struct vty *); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c new file mode 100644 index 0000000000..498a600552 --- /dev/null +++ b/bgpd/bgp_routemap.c @@ -0,0 +1,3207 @@ +/* Route map function of bgpd. +   Copyright (C) 1998, 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "prefix.h" +#include "filter.h" +#include "routemap.h" +#include "command.h" +#include "linklist.h" +#include "plist.h" +#include "memory.h" +#include "log.h" +#ifdef HAVE_GNU_REGEX +#include <regex.h> +#else +#include "regex-gnu.h" +#endif /* HAVE_GNU_REGEX */ +#include "buffer.h" +#include "sockunion.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_clist.h" +#include "bgpd/bgp_filter.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_ecommunity.h" + +/* Memo of route-map commands. + +o Cisco route-map + + match as-path          :  Done +       community        :  Done +       interface        :  Not yet +       ip address       :  Done +       ip next-hop      :  Done +       ip route-source  :  (This will not be implemented by bgpd) +       ip prefix-list   :  Done +       ipv6 address     :  Done +       ipv6 next-hop    :  Done +       ipv6 route-source:  (This will not be implemented by bgpd) +       ipv6 prefix-list :  Done +       length           :  (This will not be implemented by bgpd) +       metric           :  Done +       route-type       :  (This will not be implemented by bgpd) +       tag              :  (This will not be implemented by bgpd) + + set  as-path prepend   :  Done +      as-path tag       :  Not yet +      automatic-tag     :  (This will not be implemented by bgpd) +      community         :  Done +      comm-list         :  Not yet +      dampning          :  Not yet +      default           :  (This will not be implemented by bgpd) +      interface         :  (This will not be implemented by bgpd) +      ip default        :  (This will not be implemented by bgpd) +      ip next-hop       :  Done +      ip precedence     :  (This will not be implemented by bgpd) +      ip tos            :  (This will not be implemented by bgpd) +      level             :  (This will not be implemented by bgpd) +      local-preference  :  Done +      metric            :  Done +      metric-type       :  Not yet +      origin            :  Done +      tag               :  (This will not be implemented by bgpd) +      weight            :  Done + +o Local extention + +  set ipv6 next-hop global: Done +  set ipv6 next-hop local : Done + +*/  + +/* `match ip address IP_ACCESS_LIST' */ + +/* Match function should return 1 if match is success else return +   zero. */ +route_map_result_t +route_match_ip_address (void *rule, struct prefix *prefix,  +			route_map_object_t type, void *object) +{ +  struct access_list *alist; +  /* struct prefix_ipv4 match; */ + +  if (type == RMAP_BGP) +    { +      alist = access_list_lookup (AFI_IP, (char *) rule); +      if (alist == NULL) +	return RMAP_NOMATCH; +     +      return (access_list_apply (alist, prefix) == FILTER_DENY ? +	      RMAP_NOMATCH : RMAP_MATCH); +    } +  return RMAP_NOMATCH; +} + +/* Route map `ip address' match statement.  `arg' should be +   access-list name. */ +void * +route_match_ip_address_compile (char *arg) +{ +  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_address_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_ip_address_cmd = +{ +  "ip address", +  route_match_ip_address, +  route_match_ip_address_compile, +  route_match_ip_address_free +}; + +/* `match ip next-hop IP_ADDRESS' */ + +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_ip_next_hop (void *rule, struct prefix *prefix,  +			 route_map_object_t type, void *object) +{ +  struct access_list *alist; +  struct bgp_info *bgp_info; +  struct prefix_ipv4 p; + +  if (type == RMAP_BGP) +    { +      bgp_info = object; +      p.family = AF_INET; +      p.prefix = bgp_info->attr->nexthop; +      p.prefixlen = IPV4_MAX_BITLEN; + +      alist = access_list_lookup (AFI_IP, (char *) rule); +      if (alist == NULL) +	return RMAP_NOMATCH; + +      return (access_list_apply (alist, &p) == FILTER_DENY ? +              RMAP_NOMATCH : RMAP_MATCH); +    } +  return RMAP_NOMATCH; +} + +/* Route map `ip next-hop' match statement. `arg' is +   access-list name. */ +void * +route_match_ip_next_hop_compile (char *arg) +{ +  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_ip_next_hop_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip next-hop matching. */ +struct route_map_rule_cmd route_match_ip_next_hop_cmd = +{ +  "ip next-hop", +  route_match_ip_next_hop, +  route_match_ip_next_hop_compile, +  route_match_ip_next_hop_free +}; + +/* `match ip address prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_address_prefix_list (void *rule, struct prefix *prefix,  +				    route_map_object_t type, void *object) +{ +  struct prefix_list *plist; + +  if (type == RMAP_BGP) +    { +      plist = prefix_list_lookup (AFI_IP, (char *) rule); +      if (plist == NULL) +	return RMAP_NOMATCH; +     +      return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? +	      RMAP_NOMATCH : RMAP_MATCH); +    } +  return RMAP_NOMATCH; +} + +void * +route_match_ip_address_prefix_list_compile (char *arg) +{ +  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_address_prefix_list_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = +{ +  "ip address prefix-list", +  route_match_ip_address_prefix_list, +  route_match_ip_address_prefix_list_compile, +  route_match_ip_address_prefix_list_free +}; + +/* `match ip next-hop prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, +                                    route_map_object_t type, void *object) +{ +  struct prefix_list *plist; +  struct bgp_info *bgp_info; +  struct prefix_ipv4 p; + +  if (type == RMAP_BGP) +    { +      bgp_info = object; +      p.family = AF_INET; +      p.prefix = bgp_info->attr->nexthop; +      p.prefixlen = IPV4_MAX_BITLEN; + +      plist = prefix_list_lookup (AFI_IP, (char *) rule); +      if (plist == NULL) +        return RMAP_NOMATCH; + +      return (prefix_list_apply (plist, &p) == PREFIX_DENY ? +              RMAP_NOMATCH : RMAP_MATCH); +    } +  return RMAP_NOMATCH; +} + +void * +route_match_ip_next_hop_prefix_list_compile (char *arg) +{ +  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ip_next_hop_prefix_list_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = +{ +  "ip next-hop prefix-list", +  route_match_ip_next_hop_prefix_list, +  route_match_ip_next_hop_prefix_list_compile, +  route_match_ip_next_hop_prefix_list_free +}; + +/* `match metric METRIC' */ + +/* Match function return 1 if match is success else return zero. */ +route_map_result_t +route_match_metric (void *rule, struct prefix *prefix,  +		    route_map_object_t type, void *object) +{ +  u_int32_t *med; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      med = rule; +      bgp_info = object; +     +      if (bgp_info->attr->med == *med) +	return RMAP_MATCH; +      else +	return RMAP_NOMATCH; +    } +  return RMAP_NOMATCH; +} + +/* Route map `match metric' match statement. `arg' is MED value */ +void * +route_match_metric_compile (char *arg) +{ +  u_int32_t *med; +  char *endptr = NULL; + +  med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); +  *med = strtoul (arg, &endptr, 10); +  if (*endptr != '\0' || *med == ULONG_MAX) +    { +      XFREE (MTYPE_ROUTE_MAP_COMPILED, med); +      return NULL; +    } +  return med; +} + +/* Free route map's compiled `match metric' value. */ +void +route_match_metric_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for metric matching. */ +struct route_map_rule_cmd route_match_metric_cmd = +{ +  "metric", +  route_match_metric, +  route_match_metric_compile, +  route_match_metric_free +}; + +/* `match as-path ASPATH' */ + +/* Match function for as-path match.  I assume given object is */ +route_map_result_t +route_match_aspath (void *rule, struct prefix *prefix,  +		    route_map_object_t type, void *object) +{ +   +  struct as_list *as_list; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      as_list = as_list_lookup ((char *) rule); +      if (as_list == NULL) +	return RMAP_NOMATCH; +     +      bgp_info = object; +     +      /* Perform match. */ +      return ((as_list_apply (as_list, bgp_info->attr->aspath) == AS_FILTER_DENY) ? RMAP_NOMATCH : RMAP_MATCH); +    } +  return RMAP_NOMATCH; +} + +/* Compile function for as-path match. */ +void * +route_match_aspath_compile (char *arg) +{ +  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Compile function for as-path match. */ +void +route_match_aspath_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for aspath matching. */ +struct route_map_rule_cmd route_match_aspath_cmd =  +{ +  "as-path", +  route_match_aspath, +  route_match_aspath_compile, +  route_match_aspath_free +}; + +#if ROUTE_MATCH_ASPATH_OLD +/* `match as-path ASPATH' */ + +/* Match function for as-path match.  I assume given object is */ +int +route_match_aspath (void *rule, struct prefix *prefix, void *object) +{ +  regex_t *regex; +  struct bgp_info *bgp_info; + +  regex = rule; +  bgp_info = object; +   +  /* Perform match. */ +  return bgp_regexec (regex, bgp_info->attr->aspath); +} + +/* Compile function for as-path match. */ +void * +route_match_aspath_compile (char *arg) +{ +  regex_t *regex; + +  regex = bgp_regcomp (arg); +  if (! regex) +    return NULL; + +  return regex; +} + +/* Compile function for as-path match. */ +void +route_match_aspath_free (void *rule) +{ +  regex_t *regex = rule; + +  bgp_regex_free (regex); +} + +/* Route map commands for aspath matching. */ +struct route_map_rule_cmd route_match_aspath_cmd =  +{ +  "as-path", +  route_match_aspath, +  route_match_aspath_compile, +  route_match_aspath_free +}; +#endif /* ROUTE_MATCH_ASPATH_OLD */ + +/* `match community COMMUNIY' */ +struct rmap_community +{ +  char *name; +  int exact; +}; + +/* Match function for community match. */ +route_map_result_t +route_match_community (void *rule, struct prefix *prefix,  +		       route_map_object_t type, void *object) +{ +  struct community_list *list; +  struct bgp_info *bgp_info; +  struct rmap_community *rcom; + +  if (type == RMAP_BGP)  +    { +      bgp_info = object; +      rcom = rule; + +      list = community_list_lookup (bgp_clist, rcom->name, COMMUNITY_LIST_AUTO); +      if (! list) +	return RMAP_NOMATCH; + +      if (rcom->exact) +	{ +	  if (community_list_exact_match (bgp_info->attr->community, list)) +	    return RMAP_MATCH; +	} +      else +	{ +	  if (community_list_match (bgp_info->attr->community, list)) +	    return RMAP_MATCH; +	} +    } +  return RMAP_NOMATCH; +} + +/* Compile function for community match. */ +void * +route_match_community_compile (char *arg) +{ +  struct rmap_community *rcom; +  int len; +  char *p; + +  rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community)); + +  p = strchr (arg, ' '); +  if (p) +    { +      len = p - arg; +      rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); +      memcpy (rcom->name, arg, len); +      rcom->exact = 1; +    } +  else +    { +      rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +      rcom->exact = 0; +    } +  return rcom; +} + +/* Compile function for community match. */ +void +route_match_community_free (void *rule) +{ +  struct rmap_community *rcom = rule; + +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name);  +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom); +} + +/* Route map commands for community matching. */ +struct route_map_rule_cmd route_match_community_cmd =  +{ +  "community", +  route_match_community, +  route_match_community_compile, +  route_match_community_free +}; + +/* `match nlri` and `set nlri` are replaced by `address-family ipv4` +   and `address-family vpnv4'.  */ + +/* `match origin' */ +route_map_result_t +route_match_origin (void *rule, struct prefix *prefix,  +		    route_map_object_t type, void *object) +{ +  u_char *origin; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      origin = rule; +      bgp_info = object; +     +      if (bgp_info->attr->origin == *origin) +	return RMAP_MATCH; +    } + +  return RMAP_NOMATCH; +} + +void * +route_match_origin_compile (char *arg) +{ +  u_char *origin; + +  origin = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_char)); + +  if (strcmp (arg, "igp") == 0) +    *origin = 0; +  else if (strcmp (arg, "egp") == 0) +    *origin = 1; +  else +    *origin = 2; + +  return origin; +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_origin_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for origin matching. */ +struct route_map_rule_cmd route_match_origin_cmd = +{ +  "origin", +  route_match_origin, +  route_match_origin_compile, +  route_match_origin_free +}; +/* `set ip next-hop IP_ADDRESS' */ + +/* Set nexthop to object.  ojbect must be pointer to struct attr. */ +route_map_result_t +route_set_ip_nexthop (void *rule, struct prefix *prefix, +		      route_map_object_t type, void *object) +{ +  struct in_addr *address; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      /* Fetch routemap's rule information. */ +      address = rule; +      bgp_info = object; +     +      /* Set next hop value. */  +      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); +      bgp_info->attr->nexthop = *address; +    } + +  return RMAP_OKAY; +} + +/* Route map `ip nexthop' compile function.  Given string is converted +   to struct in_addr structure. */ +void * +route_set_ip_nexthop_compile (char *arg) +{ +  int ret; +  struct in_addr *address; + +  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); + +  ret = inet_aton (arg, address); + +  if (ret == 0) +    { +      XFREE (MTYPE_ROUTE_MAP_COMPILED, address); +      return NULL; +    } + +  return address; +} + +/* Free route map's compiled `ip nexthop' value. */ +void +route_set_ip_nexthop_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_ip_nexthop_cmd = +{ +  "ip next-hop", +  route_set_ip_nexthop, +  route_set_ip_nexthop_compile, +  route_set_ip_nexthop_free +}; + +/* `set local-preference LOCAL_PREF' */ + +/* Set local preference. */ +route_map_result_t +route_set_local_pref (void *rule, struct prefix *prefix, +		      route_map_object_t type, void *object) +{ +  u_int32_t *local_pref; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      /* Fetch routemap's rule information. */ +      local_pref = rule; +      bgp_info = object; +     +      /* Set local preference value. */  +      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); +      bgp_info->attr->local_pref = *local_pref; +    } + +  return RMAP_OKAY; +} + +/* set local preference compilation. */ +void * +route_set_local_pref_compile (char *arg) +{ +  u_int32_t *local_pref; +  char *endptr = NULL; + +  /* Local preference value shoud be integer. */ +  if (! all_digit (arg)) +    return NULL; + +  local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); +  *local_pref = strtoul (arg, &endptr, 10); +  if (*endptr != '\0' || *local_pref == ULONG_MAX) +    { +      XFREE (MTYPE_ROUTE_MAP_COMPILED, local_pref); +      return NULL; +    } +  return local_pref; +} + +/* Free route map's local preference value. */ +void +route_set_local_pref_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set local preference rule structure. */ +struct route_map_rule_cmd route_set_local_pref_cmd =  +{ +  "local-preference", +  route_set_local_pref, +  route_set_local_pref_compile, +  route_set_local_pref_free, +}; + +/* `set weight WEIGHT' */ + +/* Set weight. */ +route_map_result_t +route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type, +		  void *object) +{ +  u_int32_t *weight; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      /* Fetch routemap's rule information. */ +      weight = rule; +      bgp_info = object; +     +      /* Set weight value. */  +      bgp_info->attr->weight = *weight; +    } + +  return RMAP_OKAY; +} + +/* set local preference compilation. */ +void * +route_set_weight_compile (char *arg) +{ +  u_int32_t *weight; +  char *endptr = NULL; + +  /* Local preference value shoud be integer. */ +  if (! all_digit (arg)) +    return NULL; + +  weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); +  *weight = strtoul (arg, &endptr, 10); +  if (*endptr != '\0' || *weight == ULONG_MAX) +    { +      XFREE (MTYPE_ROUTE_MAP_COMPILED, weight); +      return NULL; +    } +  return weight; +} + +/* Free route map's local preference value. */ +void +route_set_weight_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set local preference rule structure. */ +struct route_map_rule_cmd route_set_weight_cmd =  +{ +  "weight", +  route_set_weight, +  route_set_weight_compile, +  route_set_weight_free, +}; + +/* `set metric METRIC' */ + +/* Set metric to attribute. */ +route_map_result_t +route_set_metric (void *rule, struct prefix *prefix,  +		  route_map_object_t type, void *object) +{ +  char *metric; +  u_int32_t metric_val; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      /* Fetch routemap's rule information. */ +      metric = rule; +      bgp_info = object; + +      if (! (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) +	bgp_info->attr->med = 0; +      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + +      if (all_digit (metric)) +	{ +	  metric_val = strtoul (metric, (char **)NULL, 10); +	  bgp_info->attr->med = metric_val; +	} +      else +	{ +	  metric_val = strtoul (metric+1, (char **)NULL, 10); + +	  if (strncmp (metric, "+", 1) == 0) +	    { +	      if (bgp_info->attr->med/2 + metric_val/2 > ULONG_MAX/2) +		bgp_info->attr->med = ULONG_MAX-1; +	      else +		bgp_info->attr->med += metric_val; +	    } +	  else if (strncmp (metric, "-", 1) == 0) +	    { +	      if (bgp_info->attr->med <= metric_val)  +		bgp_info->attr->med = 0; +	      else +		bgp_info->attr->med -= metric_val; +	    } +	} +    } +  return RMAP_OKAY; +} + +/* set metric compilation. */ +void * +route_set_metric_compile (char *arg) +{ +  u_int32_t metric; +  char *endptr = NULL; + +  if (all_digit (arg)) +    { +      /* set metric value check*/ +      metric = strtoul (arg, &endptr, 10); +      if (*endptr != '\0' || metric == ULONG_MAX) +        return NULL; +    } +  else +    { +      /* set metric +/-value check */ +      if ((strncmp (arg, "+", 1) != 0 +	   && strncmp (arg, "-", 1) != 0) +	   || (! all_digit (arg+1))) +	return NULL; + +      metric = strtoul (arg+1, &endptr, 10); +      if (*endptr != '\0' || metric == ULONG_MAX) +	return NULL; +    } + +  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `set metric' value. */ +void +route_set_metric_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_metric_cmd =  +{ +  "metric", +  route_set_metric, +  route_set_metric_compile, +  route_set_metric_free, +}; + +/* `set as-path prepend ASPATH' */ + +/* For AS path prepend mechanism. */ +route_map_result_t +route_set_aspath_prepend (void *rule, struct prefix *prefix, route_map_object_t type, void *object) +{ +  struct aspath *aspath; +  struct aspath *new; +  struct bgp_info *binfo; + +  if (type == RMAP_BGP) +    { +      aspath = rule; +      binfo = object; +     +      if (binfo->attr->aspath->refcnt) +	new = aspath_dup (binfo->attr->aspath); +      else +	new = binfo->attr->aspath; + +      aspath_prepend (aspath, new); +      binfo->attr->aspath = new; +    } + +  return RMAP_OKAY; +} + +/* Compile function for as-path prepend. */ +void * +route_set_aspath_prepend_compile (char *arg) +{ +  struct aspath *aspath; + +  aspath = aspath_str2aspath (arg); +  if (! aspath) +    return NULL; +  return aspath; +} + +/* Compile function for as-path prepend. */ +void +route_set_aspath_prepend_free (void *rule) +{ +  struct aspath *aspath = rule; +  aspath_free (aspath); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_aspath_prepend_cmd =  +{ +  "as-path prepend", +  route_set_aspath_prepend, +  route_set_aspath_prepend_compile, +  route_set_aspath_prepend_free, +}; + +/* `set community COMMUNITY' */ +struct rmap_com_set +{ +  struct community *com; +  int additive; +  int none; +}; + +/* For community set mechanism. */ +route_map_result_t +route_set_community (void *rule, struct prefix *prefix, +		     route_map_object_t type, void *object) +{ +  struct rmap_com_set *rcs; +  struct bgp_info *binfo; +  struct attr *attr; +  struct community *new = NULL; +  struct community *old; +  struct community *merge; + +  if (type == RMAP_BGP) +    { +      rcs = rule; +      binfo = object; +      attr = binfo->attr; +      old = attr->community; + +      /* "none" case.  */ +      if (rcs->none) +	{ +	  attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)); +	  attr->community = NULL; +	  return RMAP_OKAY; +	} + +      /* "additive" case.  */ +      if (rcs->additive && old) +	{ +	  merge = community_merge (community_dup (old), rcs->com); +	  new = community_uniq_sort (merge); +	  community_free (merge); +	} +      else +	new = community_dup (rcs->com); + +      attr->community = new; +      attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); +    } + +  return RMAP_OKAY; +} + +/* Compile function for set community. */ +void * +route_set_community_compile (char *arg) +{ +  struct rmap_com_set *rcs; +  struct community *com = NULL; +  char *sp; +  int additive = 0; +  int none = 0; +   +  if (strcmp (arg, "none") == 0) +    none = 1; +  else +    { +      sp = strstr (arg, "additive"); + +      if (sp && sp > arg) +  	{ +	  /* "additive" keyworkd is included.  */ +	  additive = 1; +	  *(sp - 1) = '\0'; +	} + +      com = community_str2com (arg); + +      if (additive) +	*(sp - 1) = ' '; + +      if (! com) +	return NULL; +    } +   +  rcs = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set)); +  memset (rcs, 0, sizeof (struct rmap_com_set)); +   +  rcs->com = com; +  rcs->additive = additive; +  rcs->none = none; +   +  return rcs; +} + +/* Free function for set community. */ +void +route_set_community_free (void *rule) +{ +  struct rmap_com_set *rcs = rule; + +  if (rcs->com) +    community_free (rcs->com); +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_community_cmd =  +{ +  "community", +  route_set_community, +  route_set_community_compile, +  route_set_community_free, +}; + +/* `set comm-list (<1-99>|<100-199>|WORD) delete' */ + +/* For community set mechanism. */ +route_map_result_t +route_set_community_delete (void *rule, struct prefix *prefix, +			    route_map_object_t type, void *object) +{ +  struct community_list *list; +  struct community *merge; +  struct community *new; +  struct community *old; +  struct bgp_info *binfo; + +  if (type == RMAP_BGP) +    { +      if (! rule) +	return RMAP_OKAY; + +      binfo = object; +      list = community_list_lookup (bgp_clist, rule, COMMUNITY_LIST_AUTO); +      old = binfo->attr->community; + +      if (list && old) +	{ +	  merge = community_list_match_delete (community_dup (old), list); +	  new = community_uniq_sort (merge); +	  community_free (merge); + +	  if (new->size == 0) +	    { +	      binfo->attr->community = NULL; +	      binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); +	      community_free (new); +	    } +	  else +	    { +	      binfo->attr->community = new; +	      binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); +	    } +	} +    } + +  return RMAP_OKAY; +} + +/* Compile function for set community. */ +void * +route_set_community_delete_compile (char *arg) +{ +  char *p; +  char *str; +  int len; + +  p = strchr (arg, ' '); +  if (p) +    { +      len = p - arg; +      str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); +      memcpy (str, arg, len); +    } +  else +    str = NULL; + +  return str; +} + +/* Free function for set community. */ +void +route_set_community_delete_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_community_delete_cmd = +{ +  "comm-list", +  route_set_community_delete, +  route_set_community_delete_compile, +  route_set_community_delete_free, +}; + +/* `set extcommunity rt COMMUNITY' */ + +/* For community set mechanism. */ +route_map_result_t +route_set_ecommunity_rt (void *rule, struct prefix *prefix,  +			 route_map_object_t type, void *object) +{ +  struct ecommunity *ecom; +  struct ecommunity *new_ecom; +  struct ecommunity *old_ecom; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      ecom = rule; +      bgp_info = object; +     +      if (! ecom) +	return RMAP_OKAY; +     +      /* We assume additive for Extended Community. */ +      old_ecom = bgp_info->attr->ecommunity; + +      if (old_ecom) +	new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); +      else +	new_ecom = ecommunity_dup (ecom); + +      bgp_info->attr->ecommunity = new_ecom; + +      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); +    } +  return RMAP_OKAY; +} + +/* Compile function for set community. */ +void * +route_set_ecommunity_rt_compile (char *arg) +{ +  struct ecommunity *ecom; + +  ecom = ecommunity_str2com (arg, ECOMMUNITY_ROUTE_TARGET, 0); +  if (! ecom) +    return NULL; +  return ecom; +} + +/* Free function for set community. */ +void +route_set_ecommunity_rt_free (void *rule) +{ +  struct ecommunity *ecom = rule; +  ecommunity_free (ecom); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_ecommunity_rt_cmd =  +{ +  "extcommunity rt", +  route_set_ecommunity_rt, +  route_set_ecommunity_rt_compile, +  route_set_ecommunity_rt_free, +}; + +/* `set extcommunity soo COMMUNITY' */ + +/* For community set mechanism. */ +route_map_result_t +route_set_ecommunity_soo (void *rule, struct prefix *prefix,  +			 route_map_object_t type, void *object) +{ +  struct ecommunity *ecom; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      ecom = rule; +      bgp_info = object; +     +      if (! ecom) +	return RMAP_OKAY; +     +      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); +      bgp_info->attr->ecommunity = ecommunity_dup (ecom); +    } +  return RMAP_OKAY; +} + +/* Compile function for set community. */ +void * +route_set_ecommunity_soo_compile (char *arg) +{ +  struct ecommunity *ecom; + +  ecom = ecommunity_str2com (arg, ECOMMUNITY_SITE_ORIGIN, 0); +  if (! ecom) +    return NULL; +   +  return ecom; +} + +/* Free function for set community. */ +void +route_set_ecommunity_soo_free (void *rule) +{ +  struct ecommunity *ecom = rule; +  ecommunity_free (ecom); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_ecommunity_soo_cmd =  +{ +  "extcommunity soo", +  route_set_ecommunity_soo, +  route_set_ecommunity_soo_compile, +  route_set_ecommunity_soo_free, +}; + +/* `set origin ORIGIN' */ + +/* For origin set. */ +route_map_result_t +route_set_origin (void *rule, struct prefix *prefix, route_map_object_t type, void *object) +{ +  u_char *origin; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      origin = rule; +      bgp_info = object; +     +      bgp_info->attr->origin = *origin; +    } + +  return RMAP_OKAY; +} + +/* Compile function for origin set. */ +void * +route_set_origin_compile (char *arg) +{ +  u_char *origin; + +  origin = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_char)); + +  if (strcmp (arg, "igp") == 0) +    *origin = 0; +  else if (strcmp (arg, "egp") == 0) +    *origin = 1; +  else +    *origin = 2; + +  return origin; +} + +/* Compile function for origin set. */ +void +route_set_origin_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_origin_cmd =  +{ +  "origin", +  route_set_origin, +  route_set_origin_compile, +  route_set_origin_free, +}; + +/* `set atomic-aggregate' */ + +/* For atomic aggregate set. */ +route_map_result_t +route_set_atomic_aggregate (void *rule, struct prefix *prefix, +			    route_map_object_t type, void *object) +{ +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      bgp_info = object; +      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); +    } + +  return RMAP_OKAY; +} + +/* Compile function for atomic aggregate. */ +void * +route_set_atomic_aggregate_compile (char *arg) +{ +  return (void *)1; +} + +/* Compile function for atomic aggregate. */ +void +route_set_atomic_aggregate_free (void *rule) +{ +  return; +} + +/* Set atomic aggregate rule structure. */ +struct route_map_rule_cmd route_set_atomic_aggregate_cmd =  +{ +  "atomic-aggregate", +  route_set_atomic_aggregate, +  route_set_atomic_aggregate_compile, +  route_set_atomic_aggregate_free, +}; + +/* `set aggregator as AS A.B.C.D' */ +struct aggregator +{ +  as_t as; +  struct in_addr address; +}; + +route_map_result_t +route_set_aggregator_as (void *rule, struct prefix *prefix,  +			 route_map_object_t type, void *object) +{ +  struct bgp_info *bgp_info; +  struct aggregator *aggregator; + +  if (type == RMAP_BGP) +    { +      bgp_info = object; +      aggregator = rule; +     +      bgp_info->attr->aggregator_as = aggregator->as; +      bgp_info->attr->aggregator_addr = aggregator->address; +      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); +    } + +  return RMAP_OKAY; +} + +void * +route_set_aggregator_as_compile (char *arg) +{ +  struct aggregator *aggregator; +  char as[10]; +  char address[20]; + +  aggregator = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct aggregator)); +  memset (aggregator, 0, sizeof (struct aggregator)); + +  sscanf (arg, "%s %s", as, address); + +  aggregator->as = strtoul (as, NULL, 10); +  inet_aton (address, &aggregator->address); + +  return aggregator; +} + +void +route_set_aggregator_as_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_set_aggregator_as_cmd =  +{ +  "aggregator as", +  route_set_aggregator_as, +  route_set_aggregator_as_compile, +  route_set_aggregator_as_free, +}; + +#ifdef HAVE_IPV6 +/* `match ipv6 address IP_ACCESS_LIST' */ + +route_map_result_t +route_match_ipv6_address (void *rule, struct prefix *prefix,  +			  route_map_object_t type, void *object) +{ +  struct access_list *alist; + +  if (type == RMAP_BGP) +    { +      alist = access_list_lookup (AFI_IP6, (char *) rule); +      if (alist == NULL) +	return RMAP_NOMATCH; +     +      return (access_list_apply (alist, prefix) == FILTER_DENY ? +	      RMAP_NOMATCH : RMAP_MATCH); +    } +  return RMAP_NOMATCH; +} + +void * +route_match_ipv6_address_compile (char *arg) +{ +  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ipv6_address_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_ipv6_address_cmd = +{ +  "ipv6 address", +  route_match_ipv6_address, +  route_match_ipv6_address_compile, +  route_match_ipv6_address_free +}; + +/* `match ipv6 next-hop IP_ADDRESS' */ + +route_map_result_t +route_match_ipv6_next_hop (void *rule, struct prefix *prefix,  +			   route_map_object_t type, void *object) +{ +  struct in6_addr *addr; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      addr = rule; +      bgp_info = object; +     +      if (IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_global, rule)) +	return RMAP_MATCH; + +      if (bgp_info->attr->mp_nexthop_len == 32 && +	  IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_local, rule)) +	return RMAP_MATCH; + +      return RMAP_NOMATCH; +    } + +  return RMAP_NOMATCH; +} + +void * +route_match_ipv6_next_hop_compile (char *arg) +{ +  struct in6_addr *address; +  int ret; + +  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); + +  ret = inet_pton (AF_INET6, arg, address); +  if (!ret) +    { +      XFREE (MTYPE_ROUTE_MAP_COMPILED, address); +      return NULL; +    } + +  return address; +} + +void +route_match_ipv6_next_hop_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = +{ +  "ipv6 next-hop", +  route_match_ipv6_next_hop, +  route_match_ipv6_next_hop_compile, +  route_match_ipv6_next_hop_free +}; + +/* `match ipv6 address prefix-list PREFIX_LIST' */ + +route_map_result_t +route_match_ipv6_address_prefix_list (void *rule, struct prefix *prefix,  +			      route_map_object_t type, void *object) +{ +  struct prefix_list *plist; + +  if (type == RMAP_BGP) +    { +      plist = prefix_list_lookup (AFI_IP6, (char *) rule); +      if (plist == NULL) +	return RMAP_NOMATCH; +     +      return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? +	      RMAP_NOMATCH : RMAP_MATCH); +    } +  return RMAP_NOMATCH; +} + +void * +route_match_ipv6_address_prefix_list_compile (char *arg) +{ +  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +void +route_match_ipv6_address_prefix_list_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = +{ +  "ipv6 address prefix-list", +  route_match_ipv6_address_prefix_list, +  route_match_ipv6_address_prefix_list_compile, +  route_match_ipv6_address_prefix_list_free +}; + +/* `set ipv6 nexthop global IP_ADDRESS' */ + +/* Set nexthop to object.  ojbect must be pointer to struct attr. */ +route_map_result_t +route_set_ipv6_nexthop_global (void *rule, struct prefix *prefix,  +			       route_map_object_t type, void *object) +{ +  struct in6_addr *address; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      /* Fetch routemap's rule information. */ +      address = rule; +      bgp_info = object; +     +      /* Set next hop value. */  +      bgp_info->attr->mp_nexthop_global = *address; +     +      /* Set nexthop length. */ +      if (bgp_info->attr->mp_nexthop_len == 0) +	bgp_info->attr->mp_nexthop_len = 16; +    } + +  return RMAP_OKAY; +} + +/* Route map `ip next-hop' compile function.  Given string is converted +   to struct in_addr structure. */ +void * +route_set_ipv6_nexthop_global_compile (char *arg) +{ +  int ret; +  struct in6_addr *address; + +  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); + +  ret = inet_pton (AF_INET6, arg, address); + +  if (ret == 0) +    { +      XFREE (MTYPE_ROUTE_MAP_COMPILED, address); +      return NULL; +    } + +  return address; +} + +/* Free route map's compiled `ip next-hop' value. */ +void +route_set_ipv6_nexthop_global_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = +{ +  "ipv6 next-hop global", +  route_set_ipv6_nexthop_global, +  route_set_ipv6_nexthop_global_compile, +  route_set_ipv6_nexthop_global_free +}; + +/* `set ipv6 nexthop local IP_ADDRESS' */ + +/* Set nexthop to object.  ojbect must be pointer to struct attr. */ +route_map_result_t +route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix,  +			      route_map_object_t type, void *object) +{ +  struct in6_addr *address; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      /* Fetch routemap's rule information. */ +      address = rule; +      bgp_info = object; +     +      /* Set next hop value. */  +      bgp_info->attr->mp_nexthop_local = *address; +     +      /* Set nexthop length. */ +      if (bgp_info->attr->mp_nexthop_len != 32) +	bgp_info->attr->mp_nexthop_len = 32; +    } + +  return RMAP_OKAY; +} + +/* Route map `ip nexthop' compile function.  Given string is converted +   to struct in_addr structure. */ +void * +route_set_ipv6_nexthop_local_compile (char *arg) +{ +  int ret; +  struct in6_addr *address; + +  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); + +  ret = inet_pton (AF_INET6, arg, address); + +  if (ret == 0) +    { +      XFREE (MTYPE_ROUTE_MAP_COMPILED, address); +      return NULL; +    } + +  return address; +} + +/* Free route map's compiled `ip nexthop' value. */ +void +route_set_ipv6_nexthop_local_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = +{ +  "ipv6 next-hop local", +  route_set_ipv6_nexthop_local, +  route_set_ipv6_nexthop_local_compile, +  route_set_ipv6_nexthop_local_free +}; +#endif /* HAVE_IPV6 */ + +/* `set vpnv4 nexthop A.B.C.D' */ + +route_map_result_t +route_set_vpnv4_nexthop (void *rule, struct prefix *prefix,  +			 route_map_object_t type, void *object) +{ +  struct in_addr *address; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP) +    { +      /* Fetch routemap's rule information. */ +      address = rule; +      bgp_info = object; +     +      /* Set next hop value. */  +      bgp_info->attr->mp_nexthop_global_in = *address; +    } + +  return RMAP_OKAY; +} + +void * +route_set_vpnv4_nexthop_compile (char *arg) +{ +  int ret; +  struct in_addr *address; + +  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); + +  ret = inet_aton (arg, address); + +  if (ret == 0) +    { +      XFREE (MTYPE_ROUTE_MAP_COMPILED, address); +      return NULL; +    } + +  return address; +} + +void +route_set_vpnv4_nexthop_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_vpnv4_nexthop_cmd = +{ +  "vpnv4 next-hop", +  route_set_vpnv4_nexthop, +  route_set_vpnv4_nexthop_compile, +  route_set_vpnv4_nexthop_free +}; + +/* `set originator-id' */ + +/* For origin set. */ +route_map_result_t +route_set_originator_id (void *rule, struct prefix *prefix, route_map_object_t type, void *object) +{ +  struct in_addr *address; +  struct bgp_info *bgp_info; + +  if (type == RMAP_BGP)  +    { +      address = rule; +      bgp_info = object; +     +      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); +      bgp_info->attr->originator_id = *address; +    } + +  return RMAP_OKAY; +} + +/* Compile function for originator-id set. */ +void * +route_set_originator_id_compile (char *arg) +{ +  int ret; +  struct in_addr *address; + +  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); + +  ret = inet_aton (arg, address); + +  if (ret == 0) +    { +      XFREE (MTYPE_ROUTE_MAP_COMPILED, address); +      return NULL; +    } + +  return address; +} + +/* Compile function for originator_id set. */ +void +route_set_originator_id_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +struct route_map_rule_cmd route_set_originator_id_cmd =  +{ +  "originator-id", +  route_set_originator_id, +  route_set_originator_id_compile, +  route_set_originator_id_free, +}; + +/* Add bgp route map rule. */ +int +bgp_route_match_add (struct vty *vty, struct route_map_index *index, +		    char *command, char *arg) +{ +  int ret; + +  ret = route_map_add_match (index, command, arg); +  if (ret) +    { +      switch (ret) +	{ +	case RMAP_RULE_MISSING: +	  vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); +	  return CMD_WARNING; +	  break; +	case RMAP_COMPILE_ERROR: +	  vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); +	  return CMD_WARNING; +	  break; +	} +    } +  return CMD_SUCCESS; +} + +/* Delete bgp route map rule. */ +int +bgp_route_match_delete (struct vty *vty, struct route_map_index *index, +			char *command, char *arg) +{ +  int ret; + +  ret = route_map_delete_match (index, command, arg); +  if (ret) +    { +      switch (ret) +	{ +	case RMAP_RULE_MISSING: +	  vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); +	  return CMD_WARNING; +	  break; +	case RMAP_COMPILE_ERROR: +	  vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); +	  return CMD_WARNING; +	  break; +	} +    } +  return CMD_SUCCESS; +} + +/* Add bgp route map rule. */ +int +bgp_route_set_add (struct vty *vty, struct route_map_index *index, +		   char *command, char *arg) +{ +  int ret; + +  ret = route_map_add_set (index, command, arg); +  if (ret) +    { +      switch (ret) +	{ +	case RMAP_RULE_MISSING: +	  vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); +	  return CMD_WARNING; +	  break; +	case RMAP_COMPILE_ERROR: +	  vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); +	  return CMD_WARNING; +	  break; +	} +    } +  return CMD_SUCCESS; +} + +/* Delete bgp route map rule. */ +int +bgp_route_set_delete (struct vty *vty, struct route_map_index *index, +		      char *command, char *arg) +{ +  int ret; + +  ret = route_map_delete_set (index, command, arg); +  if (ret) +    { +      switch (ret) +	{ +	case RMAP_RULE_MISSING: +	  vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); +	  return CMD_WARNING; +	  break; +	case RMAP_COMPILE_ERROR: +	  vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); +	  return CMD_WARNING; +	  break; +	} +    } +  return CMD_SUCCESS; +} + +/* Hook function for updating route_map assignment. */ +void +bgp_route_map_update () +{ +  int i; +  afi_t afi; +  safi_t safi; +  int direct; +  struct listnode *nn, *nm; +  struct bgp *bgp; +  struct peer *peer; +  struct peer_group *group; +  struct bgp_filter *filter; +  struct bgp_node *bn; +  struct bgp_static *bgp_static; + +  /* For neighbor route-map updates. */ +  LIST_LOOP (bm->bgp, bgp, nn) +    { +      LIST_LOOP (bgp->peer, peer, nm) +	{ +	  for (afi = AFI_IP; afi < AFI_MAX; afi++) +	    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +	      { +		filter = &peer->filter[afi][safi]; +	   +		for (direct = FILTER_IN; direct < FILTER_MAX; direct++) +		  { +		    if (filter->map[direct].name) +		      filter->map[direct].map =  +			route_map_lookup_by_name (filter->map[direct].name); +		    else +		      filter->map[direct].map = NULL; +		  } + +		if (filter->usmap.name) +		  filter->usmap.map = route_map_lookup_by_name (filter->usmap.name); +		else +		  filter->usmap.map = NULL; +	      } +	} +      LIST_LOOP (bgp->group, group, nm) +	{ +	  for (afi = AFI_IP; afi < AFI_MAX; afi++) +	    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +	      { +		filter = &group->conf->filter[afi][safi]; +	   +		for (direct = FILTER_IN; direct < FILTER_MAX; direct++) +		  { +		    if (filter->map[direct].name) +		      filter->map[direct].map =  +			route_map_lookup_by_name (filter->map[direct].name); +		    else +		      filter->map[direct].map = NULL; +		  } + +		if (filter->usmap.name) +		  filter->usmap.map = route_map_lookup_by_name (filter->usmap.name); +		else +		  filter->usmap.map = NULL; +	      } +	} +    } + +  /* For default-originate route-map updates. */ +  LIST_LOOP (bm->bgp, bgp, nn) +    { +      LIST_LOOP (bgp->peer, peer, nm) +	{ +	  for (afi = AFI_IP; afi < AFI_MAX; afi++) +	    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +	      { +		if (peer->default_rmap[afi][safi].name) +		  peer->default_rmap[afi][safi].map = +		    route_map_lookup_by_name (peer->default_rmap[afi][safi].name); +		else +		  peer->default_rmap[afi][safi].map = NULL; +	      } +	} +    } + +  /* For network route-map updates. */ +  LIST_LOOP (bm->bgp, bgp, nn) +    { +      for (afi = AFI_IP; afi < AFI_MAX; afi++) +	for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +	  for (bn = bgp_table_top (bgp->route[afi][safi]); bn; +	       bn = bgp_route_next (bn)) +	    if ((bgp_static = bn->info) != NULL) +	      { +		if (bgp_static->rmap.name) +		  bgp_static->rmap.map = +			 route_map_lookup_by_name (bgp_static->rmap.name); +		else +		  bgp_static->rmap.map = NULL; +	      } +    } + +  /* For redistribute route-map updates. */ +  LIST_LOOP (bm->bgp, bgp, nn) +    { +      for (i = 0; i < ZEBRA_ROUTE_MAX; i++) +	{ +	  if (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name) +	    bgp->rmap[ZEBRA_FAMILY_IPV4][i].map =  +	      route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name); +#ifdef HAVE_IPV6 +	  if (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name) +	    bgp->rmap[ZEBRA_FAMILY_IPV6][i].map = +	      route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name); +#endif /* HAVE_IPV6 */ +	} +    } +} + +DEFUN (match_ip_address,  +       match_ip_address_cmd, +       "match ip address (<1-199>|<1300-2699>|WORD)", +       MATCH_STR +       IP_STR +       "Match address of route\n" +       "IP access-list number\n" +       "IP access-list number (expanded range)\n" +       "IP Access-list name\n") +{ +  return bgp_route_match_add (vty, vty->index, "ip address", argv[0]); +} + +DEFUN (no_match_ip_address,  +       no_match_ip_address_cmd, +       "no match ip address", +       NO_STR +       MATCH_STR +       IP_STR +       "Match address of route\n") +{ +  if (argc == 0) +    return bgp_route_match_delete (vty, vty->index, "ip address", NULL); + +  return bgp_route_match_delete (vty, vty->index, "ip address", argv[0]); +} + +ALIAS (no_match_ip_address,  +       no_match_ip_address_val_cmd, +       "no match ip address (<1-199>|<1300-2699>|WORD)", +       NO_STR +       MATCH_STR +       IP_STR +       "Match address of route\n" +       "IP access-list number\n" +       "IP access-list number (expanded range)\n" +       "IP Access-list name\n") + +DEFUN (match_ip_next_hop,  +       match_ip_next_hop_cmd, +       "match ip next-hop (<1-199>|<1300-2699>|WORD)", +       MATCH_STR +       IP_STR +       "Match next-hop address of route\n" +       "IP access-list number\n" +       "IP access-list number (expanded range)\n" +       "IP Access-list name\n") +{ +  return bgp_route_match_add (vty, vty->index, "ip next-hop", argv[0]); +} + +DEFUN (no_match_ip_next_hop, +       no_match_ip_next_hop_cmd, +       "no match ip next-hop", +       NO_STR +       MATCH_STR +       IP_STR +       "Match next-hop address of route\n") +{ +  if (argc == 0) +    return bgp_route_match_delete (vty, vty->index, "ip next-hop", NULL); + +  return bgp_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); +} + +ALIAS (no_match_ip_next_hop, +       no_match_ip_next_hop_val_cmd, +       "no match ip next-hop (<1-199>|<1300-2699>|WORD)", +       NO_STR +       MATCH_STR +       IP_STR +       "Match next-hop address of route\n" +       "IP access-list number\n" +       "IP access-list number (expanded range)\n" +       "IP Access-list name\n") + +DEFUN (match_ip_address_prefix_list,  +       match_ip_address_prefix_list_cmd, +       "match ip address prefix-list WORD", +       MATCH_STR +       IP_STR +       "Match address of route\n" +       "Match entries of prefix-lists\n" +       "IP prefix-list name\n") +{ +  return bgp_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]); +} + +DEFUN (no_match_ip_address_prefix_list, +       no_match_ip_address_prefix_list_cmd, +       "no match ip address prefix-list", +       NO_STR +       MATCH_STR +       IP_STR +       "Match address of route\n" +       "Match entries of prefix-lists\n") +{ +  if (argc == 0) +    return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); + +  return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]); +} + +ALIAS (no_match_ip_address_prefix_list, +       no_match_ip_address_prefix_list_val_cmd, +       "no match ip address prefix-list WORD", +       NO_STR +       MATCH_STR +       IP_STR +       "Match address of route\n" +       "Match entries of prefix-lists\n" +       "IP prefix-list name\n") + +DEFUN (match_ip_next_hop_prefix_list,  +       match_ip_next_hop_prefix_list_cmd, +       "match ip next-hop prefix-list WORD", +       MATCH_STR +       IP_STR +       "Match next-hop address of route\n" +       "Match entries of prefix-lists\n" +       "IP prefix-list name\n") +{ +  return bgp_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]); +} + +DEFUN (no_match_ip_next_hop_prefix_list, +       no_match_ip_next_hop_prefix_list_cmd, +       "no match ip next-hop prefix-list", +       NO_STR +       MATCH_STR +       IP_STR +       "Match next-hop address of route\n" +       "Match entries of prefix-lists\n") +{ +  if (argc == 0) +    return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); + +  return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]); +} + +ALIAS (no_match_ip_next_hop_prefix_list, +       no_match_ip_next_hop_prefix_list_val_cmd, +       "no match ip next-hop prefix-list WORD", +       NO_STR +       MATCH_STR +       IP_STR +       "Match next-hop address of route\n" +       "Match entries of prefix-lists\n" +       "IP prefix-list name\n") + +DEFUN (match_metric,  +       match_metric_cmd, +       "match metric <0-4294967295>", +       MATCH_STR +       "Match metric of route\n" +       "Metric value\n") +{ +  return bgp_route_match_add (vty, vty->index, "metric", argv[0]); +} + +DEFUN (no_match_metric, +       no_match_metric_cmd, +       "no match metric", +       NO_STR +       MATCH_STR +       "Match metric of route\n") +{ +  if (argc == 0) +    return bgp_route_match_delete (vty, vty->index, "metric", NULL); + +  return bgp_route_match_delete (vty, vty->index, "metric", argv[0]); +} + +ALIAS (no_match_metric, +       no_match_metric_val_cmd, +       "no match metric <0-4294967295>", +       NO_STR +       MATCH_STR +       "Match metric of route\n" +       "Metric value\n") + +DEFUN (match_community,  +       match_community_cmd, +       "match community (<1-99>|<100-199>|WORD)", +       MATCH_STR +       "Match BGP community list\n" +       "Community-list number (standard)\n" +       "Community-list number (expanded)\n" +       "Community-list name\n") +{ +  return bgp_route_match_add (vty, vty->index, "community", argv[0]); +} + +DEFUN (match_community_exact,  +       match_community_exact_cmd, +       "match community (<1-99>|<100-199>|WORD) exact-match", +       MATCH_STR +       "Match BGP community list\n" +       "Community-list number (standard)\n" +       "Community-list number (expanded)\n" +       "Community-list name\n" +       "Do exact matching of communities\n") +{ +  int ret; +  char *argstr; + +  argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, +		    strlen (argv[0]) + strlen ("exact-match") + 2); + +  sprintf (argstr, "%s exact-match", argv[0]); + +  ret = bgp_route_match_add (vty, vty->index, "community", argstr); + +  XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr); + +  return ret; +} + +DEFUN (no_match_community, +       no_match_community_cmd, +       "no match community", +       NO_STR +       MATCH_STR +       "Match BGP community list\n") +{ +  return bgp_route_match_delete (vty, vty->index, "community", NULL); +} + +ALIAS (no_match_community, +       no_match_community_val_cmd, +       "no match community (<1-99>|<100-199>|WORD)", +       NO_STR +       MATCH_STR +       "Match BGP community list\n" +       "Community-list number (standard)\n" +       "Community-list number (expanded)\n" +       "Community-list name\n") + +ALIAS (no_match_community, +       no_match_community_exact_cmd, +       "no match community (<1-99>|<100-199>|WORD) exact-match", +       NO_STR +       MATCH_STR +       "Match BGP community list\n" +       "Community-list number (standard)\n" +       "Community-list number (expanded)\n" +       "Community-list name\n" +       "Do exact matching of communities\n") + +DEFUN (match_aspath, +       match_aspath_cmd, +       "match as-path WORD", +       MATCH_STR +       "Match BGP AS path list\n" +       "AS path access-list name\n") +{ +  return bgp_route_match_add (vty, vty->index, "as-path", argv[0]); +} + +DEFUN (no_match_aspath, +       no_match_aspath_cmd, +       "no match as-path", +       NO_STR +       MATCH_STR +       "Match BGP AS path list\n") +{ +  return bgp_route_match_delete (vty, vty->index, "as-path", NULL); +} + +ALIAS (no_match_aspath, +       no_match_aspath_val_cmd, +       "no match as-path WORD", +       NO_STR +       MATCH_STR +       "Match BGP AS path list\n" +       "AS path access-list name\n") + +DEFUN (match_origin, +       match_origin_cmd, +       "match origin (egp|igp|incomplete)", +       MATCH_STR +       "BGP origin code\n" +       "remote EGP\n" +       "local IGP\n" +       "unknown heritage\n") +{ +  if (strncmp (argv[0], "igp", 2) == 0) +    return bgp_route_match_add (vty, vty->index, "origin", "igp"); +  if (strncmp (argv[0], "egp", 1) == 0) +    return bgp_route_match_add (vty, vty->index, "origin", "egp"); +  if (strncmp (argv[0], "incomplete", 2) == 0) +    return bgp_route_match_add (vty, vty->index, "origin", "incomplete"); + +  return CMD_WARNING; +} + +DEFUN (no_match_origin, +       no_match_origin_cmd, +       "no match origin", +       NO_STR +       MATCH_STR +       "BGP origin code\n") +{ +  return bgp_route_match_delete (vty, vty->index, "origin", NULL); +} + +ALIAS (no_match_origin, +       no_match_origin_val_cmd, +       "no match origin (egp|igp|incomplete)", +       NO_STR +       MATCH_STR +       "BGP origin code\n" +       "remote EGP\n" +       "local IGP\n" +       "unknown heritage\n") + +DEFUN (set_ip_nexthop, +       set_ip_nexthop_cmd, +       "set ip next-hop A.B.C.D", +       SET_STR +       IP_STR +       "Next hop address\n" +       "IP address of next hop\n") +{ +  union sockunion su; +  int ret; + +  ret = str2sockunion (argv[0], &su); +  if (ret < 0) +    { +      vty_out (vty, "%% Malformed Next-hop address%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  +  return bgp_route_set_add (vty, vty->index, "ip next-hop", argv[0]); +} + +DEFUN (no_set_ip_nexthop, +       no_set_ip_nexthop_cmd, +       "no set ip next-hop", +       NO_STR +       SET_STR +       IP_STR +       "Next hop address\n") +{ +  if (argc == 0) +    return bgp_route_set_delete (vty, vty->index, "ip next-hop", NULL); + +  return bgp_route_set_delete (vty, vty->index, "ip next-hop", argv[0]); +} + +ALIAS (no_set_ip_nexthop, +       no_set_ip_nexthop_val_cmd, +       "no set ip next-hop A.B.C.D", +       NO_STR +       SET_STR +       IP_STR +       "Next hop address\n" +       "IP address of next hop\n") + +DEFUN (set_metric, +       set_metric_cmd, +       "set metric (<0-4294967295>|<+/-metric>)", +       SET_STR +       "Metric value for destination routing protocol\n" +       "Metric value\n" +       "Add or subtract metric\n") +{ +  return bgp_route_set_add (vty, vty->index, "metric", argv[0]); +} + +DEFUN (no_set_metric, +       no_set_metric_cmd, +       "no set metric", +       NO_STR +       SET_STR +       "Metric value for destination routing protocol\n") +{ +  if (argc == 0) +    return bgp_route_set_delete (vty, vty->index, "metric", NULL); + +  return bgp_route_set_delete (vty, vty->index, "metric", argv[0]); +} + +ALIAS (no_set_metric, +       no_set_metric_val_cmd, +       "no set metric <0-4294967295>", +       NO_STR +       SET_STR +       "Metric value for destination routing protocol\n" +       "Metric value\n") + +DEFUN (set_local_pref, +       set_local_pref_cmd, +       "set local-preference <0-4294967295>", +       SET_STR +       "BGP local preference path attribute\n" +       "Preference value\n") +{ +  return bgp_route_set_add (vty, vty->index, "local-preference", argv[0]); +} + +DEFUN (no_set_local_pref, +       no_set_local_pref_cmd, +       "no set local-preference", +       NO_STR +       SET_STR +       "BGP local preference path attribute\n") +{ +  if (argc == 0) +    return bgp_route_set_delete (vty, vty->index, "local-preference", NULL); + +  return bgp_route_set_delete (vty, vty->index, "local-preference", argv[0]); +} + +ALIAS (no_set_local_pref, +       no_set_local_pref_val_cmd, +       "no set local-preference <0-4294967295>", +       NO_STR +       SET_STR +       "BGP local preference path attribute\n" +       "Preference value\n") + +DEFUN (set_weight, +       set_weight_cmd, +       "set weight <0-4294967295>", +       SET_STR +       "BGP weight for routing table\n" +       "Weight value\n") +{ +  return bgp_route_set_add (vty, vty->index, "weight", argv[0]); +} + +DEFUN (no_set_weight, +       no_set_weight_cmd, +       "no set weight", +       NO_STR +       SET_STR +       "BGP weight for routing table\n") +{ +  if (argc == 0) +    return bgp_route_set_delete (vty, vty->index, "weight", NULL); +   +  return bgp_route_set_delete (vty, vty->index, "weight", argv[0]); +} + +ALIAS (no_set_weight, +       no_set_weight_val_cmd, +       "no set weight <0-4294967295>", +       NO_STR +       SET_STR +       "BGP weight for routing table\n" +       "Weight value\n") + +DEFUN (set_aspath_prepend, +       set_aspath_prepend_cmd, +       "set as-path prepend .<1-65535>", +       SET_STR +       "Prepend string for a BGP AS-path attribute\n" +       "Prepend to the as-path\n" +       "AS number\n") +{ +  int ret; +  char *str; + +  str = argv_concat (argv, argc, 0); +  ret = bgp_route_set_add (vty, vty->index, "as-path prepend", str); +  XFREE (MTYPE_TMP, str); + +  return ret; +} + +DEFUN (no_set_aspath_prepend, +       no_set_aspath_prepend_cmd, +       "no set as-path prepend", +       NO_STR +       SET_STR +       "Prepend string for a BGP AS-path attribute\n" +       "Prepend to the as-path\n") +{ +  return bgp_route_set_delete (vty, vty->index, "as-path prepend", NULL); +} + +ALIAS (no_set_aspath_prepend, +       no_set_aspath_prepend_val_cmd, +       "no set as-path prepend .<1-65535>", +       NO_STR +       SET_STR +       "Prepend string for a BGP AS-path attribute\n" +       "Prepend to the as-path\n" +       "AS number\n") + +DEFUN (set_community, +       set_community_cmd, +       "set community .AA:NN", +       SET_STR +       "BGP community attribute\n" +       "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n") +{ +  int i; +  int first = 0; +  int additive = 0; +  struct buffer *b; +  struct community *com = NULL; +  char *str; +  char *argstr; +  int ret; + +  b = buffer_new (1024); + +  for (i = 0; i < argc; i++) +    { +      if (strncmp (argv[i], "additive", strlen (argv[i])) == 0) + 	{ + 	  additive = 1; + 	  continue; + 	} + +      if (first) +	buffer_putc (b, ' '); +      else +	first = 1; + +      if (strncmp (argv[i], "internet", strlen (argv[i])) == 0) + 	{ +	  buffer_putstr (b, "internet"); + 	  continue; + 	} +      if (strncmp (argv[i], "local-AS", strlen (argv[i])) == 0) + 	{ +	  buffer_putstr (b, "local-AS"); + 	  continue; + 	} +      if (strncmp (argv[i], "no-a", strlen ("no-a")) == 0 +	  && strncmp (argv[i], "no-advertise", strlen (argv[i])) == 0) + 	{ +	  buffer_putstr (b, "no-advertise"); + 	  continue; + 	} +      if (strncmp (argv[i], "no-e", strlen ("no-e"))== 0 +	  && strncmp (argv[i], "no-export", strlen (argv[i])) == 0) + 	{ +	  buffer_putstr (b, "no-export"); + 	  continue; + 	} +      buffer_putstr (b, argv[i]); +    } +  buffer_putc (b, '\0'); + +  /* Fetch result string then compile it to communities attribute.  */ +  str = buffer_getstr (b); +  buffer_free (b); + +  if (str) +    { +      com = community_str2com (str); +      free (str); +    } + +  /* Can't compile user input into communities attribute.  */ +  if (! com) +    { +      vty_out (vty, "%% Malformed communities attribute%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* Set communites attribute string.  */ +  str = community_str (com); + +  if (additive) +    { +      argstr = XCALLOC (MTYPE_TMP, strlen (str) + strlen (" additive") + 1); +      strcpy (argstr, str); +      strcpy (argstr + strlen (str), " additive"); +      ret =  bgp_route_set_add (vty, vty->index, "community", argstr); +      XFREE (MTYPE_TMP, argstr); +    } +  else +    ret =  bgp_route_set_add (vty, vty->index, "community", str); + +  community_free (com); + +  return ret; +} + +DEFUN (set_community_none, +       set_community_none_cmd, +       "set community none", +       SET_STR +       "BGP community attribute\n" +       "No community attribute\n") +{ +  return bgp_route_set_add (vty, vty->index, "community", "none"); +} + +DEFUN (no_set_community, +       no_set_community_cmd, +       "no set community", +       NO_STR +       SET_STR +       "BGP community attribute\n") +{ +  return bgp_route_set_delete (vty, vty->index, "community", NULL); +} + +ALIAS (no_set_community, +       no_set_community_val_cmd, +       "no set community .AA:NN", +       NO_STR +       SET_STR +       "BGP community attribute\n" +       "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n") + +ALIAS (no_set_community, +       no_set_community_none_cmd, +       "no set community none", +       NO_STR +       SET_STR +       "BGP community attribute\n" +       "No community attribute\n") + +DEFUN (set_community_delete, +       set_community_delete_cmd, +       "set comm-list (<1-99>|<100-199>|WORD) delete", +       SET_STR +       "set BGP community list (for deletion)\n" +       "Community-list number (standard)\n" +       "Communitly-list number (expanded)\n" +       "Community-list name\n" +       "Delete matching communities\n") +{ +  char *str; + +  str = XCALLOC (MTYPE_TMP, strlen (argv[0]) + strlen (" delete") + 1); +  strcpy (str, argv[0]); +  strcpy (str + strlen (argv[0]), " delete"); + +  bgp_route_set_add (vty, vty->index, "comm-list", str); + +  XFREE (MTYPE_TMP, str); +  return CMD_SUCCESS; +} + +DEFUN (no_set_community_delete, +       no_set_community_delete_cmd, +       "no set comm-list", +       NO_STR +       SET_STR +       "set BGP community list (for deletion)\n") +{ +  return bgp_route_set_delete (vty, vty->index, "comm-list", NULL); +} + +ALIAS (no_set_community_delete, +       no_set_community_delete_val_cmd, +       "no set comm-list (<1-99>|<100-199>|WORD) delete", +       NO_STR +       SET_STR +       "set BGP community list (for deletion)\n" +       "Community-list number (standard)\n" +       "Communitly-list number (expanded)\n" +       "Community-list name\n" +       "Delete matching communities\n") + +DEFUN (set_ecommunity_rt, +       set_ecommunity_rt_cmd, +       "set extcommunity rt .ASN:nn_or_IP-address:nn", +       SET_STR +       "BGP extended community attribute\n" +       "Route Target extened communityt\n" +       "VPN extended community\n") +{ +  int ret; +  char *str; + +  str = argv_concat (argv, argc, 0); +  ret = bgp_route_set_add (vty, vty->index, "extcommunity rt", str); +  XFREE (MTYPE_TMP, str); + +  return ret; +} + +DEFUN (no_set_ecommunity_rt, +       no_set_ecommunity_rt_cmd, +       "no set extcommunity rt", +       NO_STR +       SET_STR +       "BGP extended community attribute\n" +       "Route Target extened communityt\n") +{ +  return bgp_route_set_delete (vty, vty->index, "extcommunity rt", NULL); +} + +ALIAS (no_set_ecommunity_rt, +       no_set_ecommunity_rt_val_cmd, +       "no set extcommunity rt .ASN:nn_or_IP-address:nn", +       NO_STR +       SET_STR +       "BGP extended community attribute\n" +       "Route Target extened communityt\n" +       "VPN extended community\n") + +DEFUN (set_ecommunity_soo, +       set_ecommunity_soo_cmd, +       "set extcommunity soo .ASN:nn_or_IP-address:nn", +       SET_STR +       "BGP extended community attribute\n" +       "Site-of-Origin extended community\n" +       "VPN extended community\n") +{ +  int ret; +  char *str; + +  str = argv_concat (argv, argc, 0); +  ret = bgp_route_set_add (vty, vty->index, "extcommunity soo", str); +  XFREE (MTYPE_TMP, str); +  return ret; +} + +DEFUN (no_set_ecommunity_soo, +       no_set_ecommunity_soo_cmd, +       "no set extcommunity soo", +       NO_STR +       SET_STR +       "BGP extended community attribute\n" +       "Site-of-Origin extended community\n") +{ +  return bgp_route_set_delete (vty, vty->index, "extcommunity soo", NULL); +} + +ALIAS (no_set_ecommunity_soo, +       no_set_ecommunity_soo_val_cmd, +       "no set extcommunity soo .ASN:nn_or_IP-address:nn", +       NO_STR +       SET_STR +       "BGP extended community attribute\n" +       "Site-of-Origin extended community\n" +       "VPN extended community\n") + +DEFUN (set_origin, +       set_origin_cmd, +       "set origin (egp|igp|incomplete)", +       SET_STR +       "BGP origin code\n" +       "remote EGP\n" +       "local IGP\n" +       "unknown heritage\n") +{ +  if (strncmp (argv[0], "igp", 2) == 0) +    return bgp_route_set_add (vty, vty->index, "origin", "igp"); +  if (strncmp (argv[0], "egp", 1) == 0) +    return bgp_route_set_add (vty, vty->index, "origin", "egp"); +  if (strncmp (argv[0], "incomplete", 2) == 0) +    return bgp_route_set_add (vty, vty->index, "origin", "incomplete"); + +  return CMD_WARNING; +} + +DEFUN (no_set_origin, +       no_set_origin_cmd, +       "no set origin", +       NO_STR +       SET_STR +       "BGP origin code\n") +{ +  return bgp_route_set_delete (vty, vty->index, "origin", NULL); +} + +ALIAS (no_set_origin, +       no_set_origin_val_cmd, +       "no set origin (egp|igp|incomplete)", +       NO_STR +       SET_STR +       "BGP origin code\n" +       "remote EGP\n" +       "local IGP\n" +       "unknown heritage\n") + +DEFUN (set_atomic_aggregate, +       set_atomic_aggregate_cmd, +       "set atomic-aggregate", +       SET_STR +       "BGP atomic aggregate attribute\n" ) +{ +  return bgp_route_set_add (vty, vty->index, "atomic-aggregate", NULL); +} + +DEFUN (no_set_atomic_aggregate, +       no_set_atomic_aggregate_cmd, +       "no set atomic-aggregate", +       NO_STR +       SET_STR +       "BGP atomic aggregate attribute\n" ) +{ +  return bgp_route_set_delete (vty, vty->index, "atomic-aggregate", NULL); +} + +DEFUN (set_aggregator_as, +       set_aggregator_as_cmd, +       "set aggregator as <1-65535> A.B.C.D", +       SET_STR +       "BGP aggregator attribute\n" +       "AS number of aggregator\n" +       "AS number\n" +       "IP address of aggregator\n") +{ +  int ret; +  as_t as; +  struct in_addr address; +  char *endptr = NULL; +  char *argstr; + +  as = strtoul (argv[0], &endptr, 10); +  if (as == 0 || as == ULONG_MAX || *endptr != '\0') +    { +      vty_out (vty, "AS path value malformed%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  ret = inet_aton (argv[1], &address); +  if (ret == 0) +    { +      vty_out (vty, "Aggregator IP address is invalid%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, +		    strlen (argv[0]) + strlen (argv[1]) + 2); + +  sprintf (argstr, "%s %s", argv[0], argv[1]); + +  ret = bgp_route_set_add (vty, vty->index, "aggregator as", argstr); + +  XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr); + +  return ret; +} + +DEFUN (no_set_aggregator_as, +       no_set_aggregator_as_cmd, +       "no set aggregator as", +       NO_STR +       SET_STR +       "BGP aggregator attribute\n" +       "AS number of aggregator\n") +{ +  int ret; +  as_t as; +  struct in_addr address; +  char *endptr = NULL; +  char *argstr; + +  if (argv == 0) +    return bgp_route_set_delete (vty, vty->index, "aggregator as", NULL); +   +  as = strtoul (argv[0], &endptr, 10); +  if (as == 0 || as == ULONG_MAX || *endptr != '\0') +    { +      vty_out (vty, "AS path value malformed%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  ret = inet_aton (argv[1], &address); +  if (ret == 0) +    { +      vty_out (vty, "Aggregator IP address is invalid%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, +		    strlen (argv[0]) + strlen (argv[1]) + 2); + +  sprintf (argstr, "%s %s", argv[0], argv[1]); + +  ret = bgp_route_set_delete (vty, vty->index, "aggregator as", argstr); + +  XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr); + +  return ret; +} + +ALIAS (no_set_aggregator_as, +       no_set_aggregator_as_val_cmd, +       "no set aggregator as <1-65535> A.B.C.D", +       NO_STR +       SET_STR +       "BGP aggregator attribute\n" +       "AS number of aggregator\n" +       "AS number\n" +       "IP address of aggregator\n") + + +#ifdef HAVE_IPV6 +DEFUN (match_ipv6_address,  +       match_ipv6_address_cmd, +       "match ipv6 address WORD", +       MATCH_STR +       IPV6_STR +       "Match IPv6 address of route\n" +       "IPv6 access-list name\n") +{ +  return bgp_route_match_add (vty, vty->index, "ipv6 address", argv[0]); +} + +DEFUN (no_match_ipv6_address,  +       no_match_ipv6_address_cmd, +       "no match ipv6 address WORD", +       NO_STR +       MATCH_STR +       IPV6_STR +       "Match IPv6 address of route\n" +       "IPv6 access-list name\n") +{ +  return bgp_route_match_delete (vty, vty->index, "ipv6 address", argv[0]); +} + +DEFUN (match_ipv6_next_hop,  +       match_ipv6_next_hop_cmd, +       "match ipv6 next-hop X:X::X:X", +       MATCH_STR +       IPV6_STR +       "Match IPv6 next-hop address of route\n" +       "IPv6 address of next hop\n") +{ +  return bgp_route_match_add (vty, vty->index, "ipv6 next-hop", argv[0]); +} + +DEFUN (no_match_ipv6_next_hop, +       no_match_ipv6_next_hop_cmd, +       "no match ipv6 next-hop X:X::X:X", +       NO_STR +       MATCH_STR +       IPV6_STR +       "Match IPv6 next-hop address of route\n" +       "IPv6 address of next hop\n") +{ +  return bgp_route_match_delete (vty, vty->index, "ipv6 next-hop", argv[0]); +} + +DEFUN (match_ipv6_address_prefix_list,  +       match_ipv6_address_prefix_list_cmd, +       "match ipv6 address prefix-list WORD", +       MATCH_STR +       IPV6_STR +       "Match address of route\n" +       "Match entries of prefix-lists\n" +       "IP prefix-list name\n") +{ +  return bgp_route_match_add (vty, vty->index, "ipv6 address prefix-list", argv[0]); +} + +DEFUN (no_match_ipv6_address_prefix_list, +       no_match_ipv6_address_prefix_list_cmd, +       "no match ipv6 address prefix-list WORD", +       NO_STR +       MATCH_STR +       IPV6_STR +       "Match address of route\n" +       "Match entries of prefix-lists\n" +       "IP prefix-list name\n") +{ +  return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]); +} + +DEFUN (set_ipv6_nexthop_global, +       set_ipv6_nexthop_global_cmd, +       "set ipv6 next-hop global X:X::X:X", +       SET_STR +       IPV6_STR +       "IPv6 next-hop address\n" +       "IPv6 global address\n" +       "IPv6 address of next hop\n") +{ +  return bgp_route_set_add (vty, vty->index, "ipv6 next-hop global", argv[0]); +} + +DEFUN (no_set_ipv6_nexthop_global, +       no_set_ipv6_nexthop_global_cmd, +       "no set ipv6 next-hop global", +       NO_STR +       SET_STR +       IPV6_STR +       "IPv6 next-hop address\n" +       "IPv6 global address\n") +{ +  if (argc == 0) +    return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", NULL); + +  return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", argv[0]); +} + +ALIAS (no_set_ipv6_nexthop_global, +       no_set_ipv6_nexthop_global_val_cmd, +       "no set ipv6 next-hop global X:X::X:X", +       NO_STR +       SET_STR +       IPV6_STR +       "IPv6 next-hop address\n" +       "IPv6 global address\n" +       "IPv6 address of next hop\n") + +DEFUN (set_ipv6_nexthop_local, +       set_ipv6_nexthop_local_cmd, +       "set ipv6 next-hop local X:X::X:X", +       SET_STR +       IPV6_STR +       "IPv6 next-hop address\n" +       "IPv6 local address\n" +       "IPv6 address of next hop\n") +{ +  return bgp_route_set_add (vty, vty->index, "ipv6 next-hop local", argv[0]); +} + +DEFUN (no_set_ipv6_nexthop_local, +       no_set_ipv6_nexthop_local_cmd, +       "no set ipv6 next-hop local", +       NO_STR +       SET_STR +       IPV6_STR +       "IPv6 next-hop address\n" +       "IPv6 local address\n") +{ +  if (argc == 0) +    return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", NULL); +   +  return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", argv[0]); +} + +ALIAS (no_set_ipv6_nexthop_local, +       no_set_ipv6_nexthop_local_val_cmd, +       "no set ipv6 next-hop local X:X::X:X", +       NO_STR +       SET_STR +       IPV6_STR +       "IPv6 next-hop address\n" +       "IPv6 local address\n" +       "IPv6 address of next hop\n") +#endif /* HAVE_IPV6 */ + +DEFUN (set_vpnv4_nexthop, +       set_vpnv4_nexthop_cmd, +       "set vpnv4 next-hop A.B.C.D", +       SET_STR +       "VPNv4 information\n" +       "VPNv4 next-hop address\n" +       "IP address of next hop\n") +{ +  return bgp_route_set_add (vty, vty->index, "vpnv4 next-hop", argv[0]); +} + +DEFUN (no_set_vpnv4_nexthop, +       no_set_vpnv4_nexthop_cmd, +       "no set vpnv4 next-hop", +       NO_STR +       SET_STR +       "VPNv4 information\n" +       "VPNv4 next-hop address\n") +{ +  if (argc == 0) +    return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", NULL); + +  return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", argv[0]); +} + +ALIAS (no_set_vpnv4_nexthop, +       no_set_vpnv4_nexthop_val_cmd, +       "no set vpnv4 next-hop A.B.C.D", +       NO_STR +       SET_STR +       "VPNv4 information\n" +       "VPNv4 next-hop address\n" +       "IP address of next hop\n") + +DEFUN (set_originator_id, +       set_originator_id_cmd, +       "set originator-id A.B.C.D", +       SET_STR +       "BGP originator ID attribute\n" +       "IP address of originator\n") +{ +  return bgp_route_set_add (vty, vty->index, "originator-id", argv[0]); +} + +DEFUN (no_set_originator_id, +       no_set_originator_id_cmd, +       "no set originator-id", +       NO_STR +       SET_STR +       "BGP originator ID attribute\n") +{ +  if (argc == 0) +    return bgp_route_set_delete (vty, vty->index, "originator-id", NULL); +   +  return bgp_route_set_delete (vty, vty->index, "originator-id", argv[0]); +} + +ALIAS (no_set_originator_id, +       no_set_originator_id_val_cmd, +       "no set originator-id A.B.C.D", +       NO_STR +       SET_STR +       "BGP originator ID attribute\n" +       "IP address of originator\n") + + +/* Initialization of route map. */ +void +bgp_route_map_init () +{ +  route_map_init (); +  route_map_init_vty (); +  route_map_add_hook (bgp_route_map_update); +  route_map_delete_hook (bgp_route_map_update); + +  route_map_install_match (&route_match_ip_address_cmd); +  route_map_install_match (&route_match_ip_next_hop_cmd); +  route_map_install_match (&route_match_ip_address_prefix_list_cmd); +  route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); +  route_map_install_match (&route_match_aspath_cmd); +  route_map_install_match (&route_match_community_cmd); +  route_map_install_match (&route_match_metric_cmd); +  route_map_install_match (&route_match_origin_cmd); + +  route_map_install_set (&route_set_ip_nexthop_cmd); +  route_map_install_set (&route_set_local_pref_cmd); +  route_map_install_set (&route_set_weight_cmd); +  route_map_install_set (&route_set_metric_cmd); +  route_map_install_set (&route_set_aspath_prepend_cmd); +  route_map_install_set (&route_set_origin_cmd); +  route_map_install_set (&route_set_atomic_aggregate_cmd); +  route_map_install_set (&route_set_aggregator_as_cmd); +  route_map_install_set (&route_set_community_cmd); +  route_map_install_set (&route_set_community_delete_cmd); +  route_map_install_set (&route_set_vpnv4_nexthop_cmd); +  route_map_install_set (&route_set_originator_id_cmd); +  route_map_install_set (&route_set_ecommunity_rt_cmd); +  route_map_install_set (&route_set_ecommunity_soo_cmd); + +  install_element (RMAP_NODE, &match_ip_address_cmd); +  install_element (RMAP_NODE, &no_match_ip_address_cmd); +  install_element (RMAP_NODE, &no_match_ip_address_val_cmd); +  install_element (RMAP_NODE, &match_ip_next_hop_cmd); +  install_element (RMAP_NODE, &no_match_ip_next_hop_cmd); +  install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd); + +  install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); +  install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); +  install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); +  install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); +  install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); +  install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); + +  install_element (RMAP_NODE, &match_aspath_cmd); +  install_element (RMAP_NODE, &no_match_aspath_cmd); +  install_element (RMAP_NODE, &no_match_aspath_val_cmd); +  install_element (RMAP_NODE, &match_metric_cmd); +  install_element (RMAP_NODE, &no_match_metric_cmd); +  install_element (RMAP_NODE, &no_match_metric_val_cmd); +  install_element (RMAP_NODE, &match_community_cmd); +  install_element (RMAP_NODE, &match_community_exact_cmd); +  install_element (RMAP_NODE, &no_match_community_cmd); +  install_element (RMAP_NODE, &no_match_community_val_cmd); +  install_element (RMAP_NODE, &no_match_community_exact_cmd); +  install_element (RMAP_NODE, &match_origin_cmd); +  install_element (RMAP_NODE, &no_match_origin_cmd); +  install_element (RMAP_NODE, &no_match_origin_val_cmd); + +  install_element (RMAP_NODE, &set_ip_nexthop_cmd); +  install_element (RMAP_NODE, &no_set_ip_nexthop_cmd); +  install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd); +  install_element (RMAP_NODE, &set_local_pref_cmd); +  install_element (RMAP_NODE, &no_set_local_pref_cmd); +  install_element (RMAP_NODE, &no_set_local_pref_val_cmd); +  install_element (RMAP_NODE, &set_weight_cmd); +  install_element (RMAP_NODE, &no_set_weight_cmd); +  install_element (RMAP_NODE, &no_set_weight_val_cmd); +  install_element (RMAP_NODE, &set_metric_cmd); +  install_element (RMAP_NODE, &no_set_metric_cmd); +  install_element (RMAP_NODE, &no_set_metric_val_cmd); +  install_element (RMAP_NODE, &set_aspath_prepend_cmd); +  install_element (RMAP_NODE, &no_set_aspath_prepend_cmd); +  install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd); +  install_element (RMAP_NODE, &set_origin_cmd); +  install_element (RMAP_NODE, &no_set_origin_cmd); +  install_element (RMAP_NODE, &no_set_origin_val_cmd); +  install_element (RMAP_NODE, &set_atomic_aggregate_cmd); +  install_element (RMAP_NODE, &no_set_atomic_aggregate_cmd); +  install_element (RMAP_NODE, &set_aggregator_as_cmd); +  install_element (RMAP_NODE, &no_set_aggregator_as_cmd); +  install_element (RMAP_NODE, &no_set_aggregator_as_val_cmd); +  install_element (RMAP_NODE, &set_community_cmd); +  install_element (RMAP_NODE, &set_community_none_cmd); +  install_element (RMAP_NODE, &no_set_community_cmd); +  install_element (RMAP_NODE, &no_set_community_val_cmd); +  install_element (RMAP_NODE, &no_set_community_none_cmd); +  install_element (RMAP_NODE, &set_community_delete_cmd); +  install_element (RMAP_NODE, &no_set_community_delete_cmd); +  install_element (RMAP_NODE, &no_set_community_delete_val_cmd); +  install_element (RMAP_NODE, &set_ecommunity_rt_cmd); +  install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd); +  install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd); +  install_element (RMAP_NODE, &set_ecommunity_soo_cmd); +  install_element (RMAP_NODE, &no_set_ecommunity_soo_cmd); +  install_element (RMAP_NODE, &no_set_ecommunity_soo_val_cmd); +  install_element (RMAP_NODE, &set_vpnv4_nexthop_cmd); +  install_element (RMAP_NODE, &no_set_vpnv4_nexthop_cmd); +  install_element (RMAP_NODE, &no_set_vpnv4_nexthop_val_cmd); +  install_element (RMAP_NODE, &set_originator_id_cmd); +  install_element (RMAP_NODE, &no_set_originator_id_cmd); +  install_element (RMAP_NODE, &no_set_originator_id_val_cmd); + +#ifdef HAVE_IPV6 +  route_map_install_match (&route_match_ipv6_address_cmd); +  route_map_install_match (&route_match_ipv6_next_hop_cmd); +  route_map_install_match (&route_match_ipv6_address_prefix_list_cmd); +  route_map_install_set (&route_set_ipv6_nexthop_global_cmd); +  route_map_install_set (&route_set_ipv6_nexthop_local_cmd); + +  install_element (RMAP_NODE, &match_ipv6_address_cmd); +  install_element (RMAP_NODE, &no_match_ipv6_address_cmd); +  install_element (RMAP_NODE, &match_ipv6_next_hop_cmd); +  install_element (RMAP_NODE, &no_match_ipv6_next_hop_cmd); +  install_element (RMAP_NODE, &match_ipv6_address_prefix_list_cmd); +  install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd); +  install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd); +  install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd); +  install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd); +  install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd); +  install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); +  install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd); +#endif /* HAVE_IPV6 */ +} diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c new file mode 100644 index 0000000000..bf9c7f879c --- /dev/null +++ b/bgpd/bgp_snmp.c @@ -0,0 +1,875 @@ +/* BGP4 SNMP support +   Copyright (C) 1999, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#ifdef HAVE_SNMP +#include <asn1.h> +#include <snmp.h> +#include <snmp_impl.h> + +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "command.h" +#include "thread.h" +#include "smux.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_fsm.h" + +/* BGP4-MIB described in RFC1657. */ +#define BGP4MIB 1,3,6,1,2,1,15 + +/* Zebra enterprise BGP MIB.  This variable is used for register +   OSPF MIB to SNMP agent under SMUX protocol.  */ +#define BGPDMIB 1,3,6,1,4,1,3317,1,2,2 + +/* BGP MIB bgpVersion. */ +#define BGPVERSION			      0 + +/* BGP MIB bgpLocalAs. */ +#define BGPLOCALAS			      0 + +/* BGP MIB bgpPeerTable. */ +#define BGPPEERIDENTIFIER                     1 +#define BGPPEERSTATE                          2 +#define BGPPEERADMINSTATUS                    3 +#define BGPPEERNEGOTIATEDVERSION              4 +#define BGPPEERLOCALADDR                      5 +#define BGPPEERLOCALPORT                      6 +#define BGPPEERREMOTEADDR                     7 +#define BGPPEERREMOTEPORT                     8 +#define BGPPEERREMOTEAS                       9 +#define BGPPEERINUPDATES                     10 +#define BGPPEEROUTUPDATES                    11 +#define BGPPEERINTOTALMESSAGES               12 +#define BGPPEEROUTTOTALMESSAGES              13 +#define BGPPEERLASTERROR                     14 +#define BGPPEERFSMESTABLISHEDTRANSITIONS     15 +#define BGPPEERFSMESTABLISHEDTIME            16 +#define BGPPEERCONNECTRETRYINTERVAL          17 +#define BGPPEERHOLDTIME                      18 +#define BGPPEERKEEPALIVE                     19 +#define BGPPEERHOLDTIMECONFIGURED            20 +#define BGPPEERKEEPALIVECONFIGURED           21 +#define BGPPEERMINASORIGINATIONINTERVAL      22 +#define BGPPEERMINROUTEADVERTISEMENTINTERVAL 23 +#define BGPPEERINUPDATEELAPSEDTIME           24 + +/* BGP MIB bgpIdentifier. */ +#define BGPIDENTIFIER                         0 + +/* BGP MIB bgpRcvdPathAttrTable */ +#define BGPPATHATTRPEER                       1 +#define BGPPATHATTRDESTNETWORK                2 +#define BGPPATHATTRORIGIN                     3 +#define BGPPATHATTRASPATH                     4 +#define BGPPATHATTRNEXTHOP                    5 +#define BGPPATHATTRINTERASMETRIC              6 + +/* BGP MIB bgp4PathAttrTable. */ +#define BGP4PATHATTRPEER                      1 +#define BGP4PATHATTRIPADDRPREFIXLEN           2 +#define BGP4PATHATTRIPADDRPREFIX              3 +#define BGP4PATHATTRORIGIN                    4 +#define BGP4PATHATTRASPATHSEGMENT             5 +#define BGP4PATHATTRNEXTHOP                   6 +#define BGP4PATHATTRMULTIEXITDISC             7 +#define BGP4PATHATTRLOCALPREF                 8 +#define BGP4PATHATTRATOMICAGGREGATE           9 +#define BGP4PATHATTRAGGREGATORAS             10 +#define BGP4PATHATTRAGGREGATORADDR           11 +#define BGP4PATHATTRCALCLOCALPREF            12 +#define BGP4PATHATTRBEST                     13 +#define BGP4PATHATTRUNKNOWN                  14 + +/* SNMP value hack. */ +#define INTEGER ASN_INTEGER +#define INTEGER32 ASN_INTEGER +#define COUNTER32 ASN_COUNTER +#define OCTET_STRING ASN_OCTET_STR +#define IPADDRESS ASN_IPADDRESS +#define GAUGE32 ASN_UNSIGNED + +/* Declare static local variables for convenience. */ +SNMP_LOCAL_VARIABLES + +/* BGP-MIB instances. */ +oid bgp_oid [] = { BGP4MIB }; +oid bgpd_oid [] = { BGPDMIB }; + +/* IP address 0.0.0.0. */ +static struct in_addr bgp_empty_addr = {0}; + +/* Hook functions. */ +static u_char *bgpVersion (); +static u_char *bgpLocalAs (); +static u_char *bgpPeerTable (); +static u_char *bgpRcvdPathAttrTable (); +static u_char *bgpIdentifier (); +static u_char *bgp4PathAttrTable (); +/* static u_char *bgpTraps (); */ + +struct variable bgp_variables[] =  +{ +  /* BGP version. */ +  {BGPVERSION,                OCTET_STRING, RONLY, bgpVersion, +   1, {1}}, +  /* BGP local AS. */ +  {BGPLOCALAS,                INTEGER, RONLY, bgpLocalAs, +   1, {2}}, +  /* BGP peer table. */ +  {BGPPEERIDENTIFIER,         IPADDRESS, RONLY, bgpPeerTable, +   3, {3, 1, 1}}, +  {BGPPEERSTATE,              INTEGER, RONLY, bgpPeerTable, +   3, {3, 1, 2}}, +  {BGPPEERADMINSTATUS,        INTEGER, RWRITE, bgpPeerTable, +   3, {3, 1, 3}}, +  {BGPPEERNEGOTIATEDVERSION,  INTEGER32, RONLY, bgpPeerTable, +   3, {3, 1, 4}}, +  {BGPPEERLOCALADDR,          IPADDRESS, RONLY, bgpPeerTable, +   3, {3, 1, 5}}, +  {BGPPEERLOCALPORT,          INTEGER, RONLY, bgpPeerTable, +   3, {3, 1, 6}}, +  {BGPPEERREMOTEADDR,         IPADDRESS, RONLY, bgpPeerTable, +   3, {3, 1, 7}}, +  {BGPPEERREMOTEPORT,         INTEGER, RONLY, bgpPeerTable, +   3, {3, 1, 8}}, +  {BGPPEERREMOTEAS,           INTEGER, RONLY, bgpPeerTable, +   3, {3, 1, 9}}, +  {BGPPEERINUPDATES,          COUNTER32, RONLY, bgpPeerTable, +   3, {3, 1, 10}}, +  {BGPPEEROUTUPDATES,         COUNTER32, RONLY, bgpPeerTable, +   3, {3, 1, 11}}, +  {BGPPEERINTOTALMESSAGES,    COUNTER32, RONLY, bgpPeerTable, +   3, {3, 1, 12}}, +  {BGPPEEROUTTOTALMESSAGES,   COUNTER32, RONLY, bgpPeerTable, +   3, {3, 1, 13}}, +  {BGPPEERLASTERROR,          OCTET_STRING, RONLY, bgpPeerTable, +   3, {3, 1, 14}}, +  {BGPPEERFSMESTABLISHEDTRANSITIONS, COUNTER32, RONLY, bgpPeerTable, +   3, {3, 1, 15}}, +  {BGPPEERFSMESTABLISHEDTIME, GAUGE32, RONLY, bgpPeerTable, +   3, {3, 1, 16}}, +  {BGPPEERCONNECTRETRYINTERVAL, INTEGER, RWRITE, bgpPeerTable, +   3, {3, 1, 17}}, +  {BGPPEERHOLDTIME,           INTEGER, RONLY, bgpPeerTable, +   3, {3, 1, 18}}, +  {BGPPEERKEEPALIVE,          INTEGER, RONLY, bgpPeerTable, +   3, {3, 1, 19}}, +  {BGPPEERHOLDTIMECONFIGURED, INTEGER, RWRITE, bgpPeerTable, +   3, {3, 1, 20}}, +  {BGPPEERKEEPALIVECONFIGURED, INTEGER, RWRITE, bgpPeerTable, +   3, {3, 1, 21}}, +  {BGPPEERMINASORIGINATIONINTERVAL, INTEGER, RWRITE, bgpPeerTable, +   3, {3, 1, 22}}, +  {BGPPEERMINROUTEADVERTISEMENTINTERVAL, INTEGER, RWRITE, bgpPeerTable, +   3, {3, 1, 23}}, +  {BGPPEERINUPDATEELAPSEDTIME, GAUGE32, RONLY, bgpPeerTable, +   3, {3, 1, 24}}, +  /* BGP identifier. */ +  {BGPIDENTIFIER,             IPADDRESS, RONLY, bgpIdentifier, +   1, {4}}, +  /* BGP received path attribute table. */ +  {BGPPATHATTRPEER,           IPADDRESS, RONLY, bgpRcvdPathAttrTable, +   3, {5, 1, 1}}, +  {BGPPATHATTRDESTNETWORK,    IPADDRESS, RONLY, bgpRcvdPathAttrTable, +   3, {5, 1, 2}}, +  {BGPPATHATTRORIGIN,         INTEGER, RONLY, bgpRcvdPathAttrTable, +   3, {5, 1, 3}}, +  {BGPPATHATTRASPATH,         OCTET_STRING, RONLY, bgpRcvdPathAttrTable, +   3, {5, 1, 4}}, +  {BGPPATHATTRNEXTHOP,        IPADDRESS, RONLY, bgpRcvdPathAttrTable, +   3, {5, 1, 5}}, +  {BGPPATHATTRINTERASMETRIC,  INTEGER32, RONLY, bgpRcvdPathAttrTable, +   3, {5, 1, 6}}, +  /* BGP-4 received path attribute table. */ +  {BGP4PATHATTRPEER, IPADDRESS, RONLY, bgp4PathAttrTable, +   3, {6, 1, 1}}, +  {BGP4PATHATTRIPADDRPREFIXLEN, INTEGER, RONLY, bgp4PathAttrTable, +   3, {6, 1, 2}}, +  {BGP4PATHATTRIPADDRPREFIX,  IPADDRESS, RONLY, bgp4PathAttrTable, +   3, {6, 1, 3}}, +  {BGP4PATHATTRORIGIN,        INTEGER, RONLY, bgp4PathAttrTable, +   3, {6, 1, 4}}, +  {BGP4PATHATTRASPATHSEGMENT, OCTET_STRING, RONLY, bgp4PathAttrTable, +   3, {6, 1, 5}}, +  {BGP4PATHATTRNEXTHOP,       IPADDRESS, RONLY, bgp4PathAttrTable, +   3, {6, 1, 6}}, +  {BGP4PATHATTRMULTIEXITDISC, INTEGER, RONLY, bgp4PathAttrTable, +   3, {6, 1, 7}}, +  {BGP4PATHATTRLOCALPREF,     INTEGER, RONLY, bgp4PathAttrTable, +   3, {6, 1, 8}}, +  {BGP4PATHATTRATOMICAGGREGATE, INTEGER, RONLY, bgp4PathAttrTable, +   3, {6, 1, 9}}, +  {BGP4PATHATTRAGGREGATORAS,  INTEGER, RONLY, bgp4PathAttrTable, +   3, {6, 1, 10}}, +  {BGP4PATHATTRAGGREGATORADDR, IPADDRESS, RONLY, bgp4PathAttrTable, +   3, {6, 1, 11}}, +  {BGP4PATHATTRCALCLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable, +   3, {6, 1, 12}}, +  {BGP4PATHATTRBEST,          INTEGER, RONLY, bgp4PathAttrTable, +   3, {6, 1, 13}}, +  {BGP4PATHATTRUNKNOWN,       OCTET_STRING, RONLY, bgp4PathAttrTable, +   3, {6, 1, 14}}, +}; + +static u_char * +bgpVersion (struct variable *v, oid name[], size_t *length, int exact, +	    size_t *var_len, WriteMethod **write_method) +{ +  static u_char version; + +  if (smux_header_generic(v, name, length, exact, var_len, write_method) +      == MATCH_FAILED) +    return NULL; + +  /* Retrun BGP version.  Zebra bgpd only support version 4. */ +  version = (0x80 >> (BGP_VERSION_4 - 1)); + +  /* Return octet string length 1. */ +  *var_len = 1; +  return (u_char *)&version; +} + +static u_char * +bgpLocalAs (struct variable *v, oid name[], size_t *length, +	    int exact, size_t *var_len, WriteMethod **write_method) +{ +  struct bgp *bgp; + +  if (smux_header_generic(v, name, length, exact, var_len, write_method) +      == MATCH_FAILED) +    return NULL; + +  /* Get BGP structure. */ +  bgp = bgp_get_default (); +  if (! bgp) +    return NULL; + +  return SNMP_INTEGER (bgp->as); +} + +struct peer * +peer_lookup_addr_ipv4 (struct in_addr *src) +{ +  struct bgp *bgp; +  struct peer *peer; +  struct listnode *nn; +  struct in_addr addr; +  int ret; + +  bgp = bgp_get_default (); +  if (! bgp) +    return NULL; + +  LIST_LOOP (bgp->peer, peer, nn) +    { +      ret = inet_pton (AF_INET, peer->host, &addr); +      if (ret > 0) +	{ +	  if (IPV4_ADDR_SAME (&addr, src)) +	    return peer; +	} +    } +  return NULL; +} + +struct peer * +bgp_peer_lookup_next (struct in_addr *src) +{ +  struct bgp *bgp; +  struct peer *peer; +  struct listnode *nn; +  struct in_addr *p; +  union sockunion su; +  int ret; + +  memset (&su, 0, sizeof (union sockunion)); + +  bgp = bgp_get_default (); +  if (! bgp) +    return NULL; + +  LIST_LOOP (bgp->peer, peer, nn) +    { +      ret = inet_pton (AF_INET, peer->host, &su.sin.sin_addr); +      if (ret > 0) +	{ +	  p = &su.sin.sin_addr; + +	  if (ntohl (p->s_addr) > ntohl (src->s_addr)) +	    { +	      src->s_addr = p->s_addr; +	      return peer; +	    } +	} +    } +  return NULL; +} + +struct peer * +bgpPeerTable_lookup (struct variable *v, oid name[], size_t *length,  +		     struct in_addr *addr, int exact) +{ +  struct peer *peer = NULL; +  int len; + +  if (exact) +    { +      /* Check the length. */ +      if (*length - v->namelen != sizeof (struct in_addr)) +	return NULL; + +      oid2in_addr (name + v->namelen, IN_ADDR_SIZE, addr); + +      peer = peer_lookup_addr_ipv4 (addr); +      return peer; +    } +  else +    { +      len = *length - v->namelen; +      if (len > 4) len = 4; +       +      oid2in_addr (name + v->namelen, len, addr); +       +      peer = bgp_peer_lookup_next (addr); + +      if (peer == NULL) +	return NULL; + +      oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); +      *length = sizeof (struct in_addr) + v->namelen; + +      return peer; +    } +  return NULL; +} + +/* BGP write methods. */ +int +write_bgpPeerTable (int action, u_char *var_val, +		    u_char var_val_type, size_t var_val_len, +		    u_char *statP, oid *name, size_t length, +		    struct variable *v) +{ +  struct in_addr addr; +  struct peer *peer; +  long intval; +  int bigsize = SNMP_MAX_LEN; +   +  if (var_val_type != ASN_INTEGER)  +    { +      return SNMP_ERR_WRONGTYPE; +    } +  if (var_val_len != sizeof (long))  +    { +      return SNMP_ERR_WRONGLENGTH; +    } + +  if (! asn_parse_int(var_val, &bigsize, &var_val_type, +                      &intval, sizeof(long))) +    { +      return SNMP_ERR_WRONGENCODING; +    } + +  memset (&addr, 0, sizeof (struct in_addr)); + +  peer = bgpPeerTable_lookup (v, name, &length, &addr, 1); +  if (! peer) +    return SNMP_ERR_NOSUCHNAME; + +  printf ("val: %ld\n", intval); + +  switch (v->magic) +    { +    case BGPPEERADMINSTATUS: +#define BGP_PeerAdmin_stop  1 +#define BGP_PeerAdmin_start 2 +      /* When the peer is established,   */ +      if (intval == BGP_PeerAdmin_stop) +	BGP_EVENT_ADD (peer, BGP_Stop); +      else if (intval == BGP_PeerAdmin_start) +	;			/* Do nothing. */ +      else +	return SNMP_ERR_NOSUCHNAME; +      break; +    case BGPPEERCONNECTRETRYINTERVAL: +      SET_FLAG (peer->config, PEER_CONFIG_CONNECT); +      peer->connect = intval; +      peer->v_connect = intval; +      break; +    case BGPPEERHOLDTIMECONFIGURED: +      SET_FLAG (peer->config, PEER_CONFIG_TIMER); +      peer->holdtime = intval; +      peer->v_holdtime = intval; +      break; +    case BGPPEERKEEPALIVECONFIGURED: +      SET_FLAG (peer->config, PEER_CONFIG_TIMER); +      peer->keepalive = intval; +      peer->v_keepalive = intval; +      break; +    case BGPPEERMINASORIGINATIONINTERVAL: +      peer->v_asorig = intval; +      break; +    case BGPPEERMINROUTEADVERTISEMENTINTERVAL: +      peer->v_routeadv = intval; +      break; +    } +  return SNMP_ERR_NOERROR; +} + +u_char * +bgpPeerTable (struct variable *v, oid name[], size_t *length, +	      int exact, size_t *var_len, WriteMethod **write_method) +{ +  static struct in_addr addr; +  struct peer *peer; + +  *write_method = NULL; +  memset (&addr, 0, sizeof (struct in_addr)); + +  peer = bgpPeerTable_lookup (v, name, length, &addr, exact); +  if (! peer) +    return NULL; + +  switch (v->magic) +    { +    case BGPPEERIDENTIFIER: +      return SNMP_IPADDRESS (peer->remote_id); +      break; +    case BGPPEERSTATE: +      return SNMP_INTEGER (peer->status); +      break; +    case BGPPEERADMINSTATUS: +      *write_method = write_bgpPeerTable; +#define BGP_PeerAdmin_stop  1 +#define BGP_PeerAdmin_start 2 +      if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) +	return SNMP_INTEGER (BGP_PeerAdmin_stop); +      else +	return SNMP_INTEGER (BGP_PeerAdmin_start); +      break; +    case BGPPEERNEGOTIATEDVERSION: +      return SNMP_INTEGER (peer->version); +      break; +    case BGPPEERLOCALADDR: +      if (peer->su_local) +	return SNMP_IPADDRESS (peer->su_local->sin.sin_addr); +      else +	return SNMP_IPADDRESS (bgp_empty_addr); +      break; +    case BGPPEERLOCALPORT: +      if (peer->su_local) +	return SNMP_INTEGER (ntohs (peer->su_local->sin.sin_port)); +      else +	return SNMP_INTEGER (0); +      break; +    case BGPPEERREMOTEADDR: +      if (peer->su_remote) +	return SNMP_IPADDRESS (peer->su_remote->sin.sin_addr); +      else +	return SNMP_IPADDRESS (bgp_empty_addr); +      break; +    case BGPPEERREMOTEPORT: +      if (peer->su_remote) +	return SNMP_INTEGER (ntohs (peer->su_remote->sin.sin_port)); +      else +	return SNMP_INTEGER (0); +      break; +    case BGPPEERREMOTEAS: +      return SNMP_INTEGER (peer->as); +      break; +    case BGPPEERINUPDATES: +      return SNMP_INTEGER (peer->update_in); +      break; +    case BGPPEEROUTUPDATES: +      return SNMP_INTEGER (peer->update_out); +      break; +    case BGPPEERINTOTALMESSAGES: +      return SNMP_INTEGER (peer->open_in + peer->update_in +			   + peer->keepalive_in + peer->notify_in +			   + peer->refresh_in + peer->dynamic_cap_in); +      break; +    case BGPPEEROUTTOTALMESSAGES: +      return SNMP_INTEGER (peer->open_out + peer->update_out +			   + peer->keepalive_out + peer->notify_out +			   + peer->refresh_out, peer->dynamic_cap_out); +      break; +    case BGPPEERLASTERROR: +      { +	static u_char lasterror[2]; +	lasterror[0] = peer->notify.code; +	lasterror[1] = peer->notify.subcode; +	*var_len = 2; +	return (u_char *)&lasterror; +      } +      break; +    case BGPPEERFSMESTABLISHEDTRANSITIONS: +      return SNMP_INTEGER (peer->established); +      break; +    case BGPPEERFSMESTABLISHEDTIME: +      if (peer->uptime == 0) +	return SNMP_INTEGER (0); +      else +	return SNMP_INTEGER (time (NULL) - peer->uptime); +      break; +    case BGPPEERCONNECTRETRYINTERVAL: +      *write_method = write_bgpPeerTable; +      return SNMP_INTEGER (peer->v_connect); +      break; +    case BGPPEERHOLDTIME: +      return SNMP_INTEGER (peer->v_holdtime); +      break; +    case BGPPEERKEEPALIVE: +      return SNMP_INTEGER (peer->v_keepalive); +      break; +    case BGPPEERHOLDTIMECONFIGURED: +      *write_method = write_bgpPeerTable; +      if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) +	return SNMP_INTEGER (peer->holdtime); +      else +	return SNMP_INTEGER (peer->v_holdtime); +      break; +    case BGPPEERKEEPALIVECONFIGURED: +      *write_method = write_bgpPeerTable; +      if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) +	return SNMP_INTEGER (peer->keepalive); +      else +	return SNMP_INTEGER (peer->v_keepalive); +      break; +    case BGPPEERMINASORIGINATIONINTERVAL: +      *write_method = write_bgpPeerTable; +      return SNMP_INTEGER (peer->v_asorig); +      break; +    case BGPPEERMINROUTEADVERTISEMENTINTERVAL: +      *write_method = write_bgpPeerTable; +      return SNMP_INTEGER (peer->v_routeadv); +      break; +    case BGPPEERINUPDATEELAPSEDTIME: +      if (peer->update_time == 0) +	return SNMP_INTEGER (0); +      else +	return SNMP_INTEGER (time (NULL) - peer->update_time); +      break; +    default: +      return NULL; +      break; +    }   +  return NULL; +} + +u_char * +bgpIdentifier (struct variable *v, oid name[], size_t *length, +	       int exact, size_t *var_len, WriteMethod **write_method) +{ +  struct bgp *bgp; + +  if (smux_header_generic(v, name, length, exact, var_len, write_method) +      == MATCH_FAILED) +    return NULL; + +  bgp = bgp_get_default (); +  if (!bgp) +    return NULL; + +  return SNMP_IPADDRESS (bgp->router_id); +} + +u_char * +bgpRcvdPathAttrTable (struct variable *v, oid name[], size_t *length, +		      int exact, size_t *var_len, WriteMethod **write_method) +{ +  /* Received Path Attribute Table.  This table contains, one entry +     per path to a network, path attributes received from all peers +     running BGP version 3 or less.  This table is obsolete, having +     been replaced in functionality with the bgp4PathAttrTable.  */ +  return NULL; +} + +struct bgp_info * +bgp4PathAttrLookup (struct variable *v, oid name[], size_t *length, +		    struct bgp *bgp, struct prefix_ipv4 *addr, int exact) +{ +  oid *offset; +  int offsetlen; +  struct bgp_info *binfo; +  struct bgp_info *min; +  struct bgp_node *rn; +  union sockunion su; +  int len; +  struct in_addr paddr; + +#define BGP_PATHATTR_ENTRY_OFFSET \ +          (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE) + +  if (exact) +    { +      if (*length - v->namelen != BGP_PATHATTR_ENTRY_OFFSET) +	return NULL; + +      /* Set OID offset for prefix. */ +      offset = name + v->namelen; +      oid2in_addr (offset, IN_ADDR_SIZE, &addr->prefix); +      offset += IN_ADDR_SIZE; + +      /* Prefix length. */ +      addr->prefixlen = *offset; +      offset++; + +      /* Peer address. */ +      su.sin.sin_family = AF_INET; +      oid2in_addr (offset, IN_ADDR_SIZE, &su.sin.sin_addr); + +      /* Lookup node. */ +      rn = bgp_node_lookup (bgp->rib[AFI_IP][SAFI_UNICAST],  +			      (struct prefix *) addr); +      if (rn) +	{ +	  bgp_unlock_node (rn); + +	  for (binfo = rn->info; binfo; binfo = binfo->next) +	    if (sockunion_same (&binfo->peer->su, &su)) +	      return binfo; +	} +    } +  else +    { +      offset = name + v->namelen; +      offsetlen = *length - v->namelen; +      len = offsetlen; + +      if (offsetlen == 0) +	rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_UNICAST]); +      else +	{ +	  if (len > IN_ADDR_SIZE) +	    len = IN_ADDR_SIZE; +       +	  oid2in_addr (offset, len, &addr->prefix); + +	  offset += IN_ADDR_SIZE; +	  offsetlen -= IN_ADDR_SIZE; + +	  if (offsetlen > 0) +	    addr->prefixlen = *offset; +	  else +	    addr->prefixlen = len * 8; + +	  rn = bgp_node_get (bgp->rib[AFI_IP][SAFI_UNICAST], +			       (struct prefix *) addr); + +	  offset++; +	  offsetlen--; +	} + +      if (offsetlen > 0) +	{ +	  len = offsetlen; +	  if (len > IN_ADDR_SIZE) +	    len = IN_ADDR_SIZE; + +	  oid2in_addr (offset, len, &paddr); +	} +      else +	paddr.s_addr = 0; + +      if (! rn) +	return NULL; + +      do +	{ +	  min = NULL; + +	  for (binfo = rn->info; binfo; binfo = binfo->next) +	    { +	      if (binfo->peer->su.sin.sin_family == AF_INET +		  && ntohl (paddr.s_addr)  +		  < ntohl (binfo->peer->su.sin.sin_addr.s_addr)) +		{ +		  if (min) +		    { +		      if (ntohl (binfo->peer->su.sin.sin_addr.s_addr)  +			  < ntohl (min->peer->su.sin.sin_addr.s_addr)) +			min = binfo; +		    } +		  else +		    min = binfo; +		} +	    } + +	  if (min) +	    { +	      *length = v->namelen + BGP_PATHATTR_ENTRY_OFFSET; + +	      offset = name + v->namelen; +	      oid_copy_addr (offset, &rn->p.u.prefix4, IN_ADDR_SIZE); +	      offset += IN_ADDR_SIZE; +	      *offset = rn->p.prefixlen; +	      offset++; +	      oid_copy_addr (offset, &min->peer->su.sin.sin_addr,  +			     IN_ADDR_SIZE); +	      addr->prefix = rn->p.u.prefix4; +	      addr->prefixlen = rn->p.prefixlen; + +	      bgp_unlock_node (rn); + +	      return min; +	    } + +	  paddr.s_addr = 0; +	} +      while ((rn = bgp_route_next (rn)) != NULL); +    } +  return NULL; +} + +u_char * +bgp4PathAttrTable (struct variable *v, oid name[], size_t *length, +		   int exact, size_t *var_len, WriteMethod **write_method) +{ +  struct bgp *bgp; +  struct bgp_info *binfo; +  struct prefix_ipv4 addr; +   +  bgp = bgp_get_default (); +  if (! bgp) +    return NULL; + +  memset (&addr, 0, sizeof (struct prefix_ipv4)); + +  binfo = bgp4PathAttrLookup (v, name, length, bgp, &addr, exact); +  if (! binfo) +    return NULL; + +  switch (v->magic) +    { +    case BGP4PATHATTRPEER:	/* 1 */ +      return SNMP_IPADDRESS (binfo->peer->su.sin.sin_addr); +      break; +    case BGP4PATHATTRIPADDRPREFIXLEN: /* 2 */ +      return SNMP_INTEGER (addr.prefixlen); +      break; +    case BGP4PATHATTRIPADDRPREFIX: /* 3 */ +      return SNMP_IPADDRESS (addr.prefix); +      break; +    case BGP4PATHATTRORIGIN:	/* 4 */ +      return SNMP_INTEGER (binfo->attr->origin); +      break; +    case BGP4PATHATTRASPATHSEGMENT: /* 5 */ +      *var_len = binfo->attr->aspath->length; +      return (u_char *) binfo->attr->aspath->data; +      break; +    case BGP4PATHATTRNEXTHOP:	/* 6 */ +      return SNMP_IPADDRESS (binfo->attr->nexthop); +      break; +    case BGP4PATHATTRMULTIEXITDISC: /* 7 */ +      return SNMP_INTEGER (binfo->attr->med); +      break; +    case BGP4PATHATTRLOCALPREF:	/* 8 */ +      return SNMP_INTEGER (binfo->attr->local_pref); +      break; +    case BGP4PATHATTRATOMICAGGREGATE: /* 9 */ +      return SNMP_INTEGER (1); +      break; +    case BGP4PATHATTRAGGREGATORAS: /* 10 */ +      return SNMP_INTEGER (binfo->attr->aggregator_as); +      break; +    case BGP4PATHATTRAGGREGATORADDR: /* 11 */ +      return SNMP_IPADDRESS (binfo->attr->aggregator_addr); +      break; +    case BGP4PATHATTRCALCLOCALPREF: /* 12 */ +      return SNMP_INTEGER (-1); +      break; +    case BGP4PATHATTRBEST:	/* 13 */ +#define BGP4_PathAttrBest_false 1 +#define BGP4_PathAttrBest_true  2 +      if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) +	return SNMP_INTEGER (BGP4_PathAttrBest_true); +      else +	return SNMP_INTEGER (BGP4_PathAttrBest_false); +      break; +    case BGP4PATHATTRUNKNOWN:	/* 14 */ +      *var_len = 0; +      return NULL; +      break; +    } +  return NULL; +} + +/* BGP Traps. */ +struct trap_object bgpTrapList[] = +{ +  {bgpPeerTable, 3, {3, 1, BGPPEERREMOTEADDR}}, +  {bgpPeerTable, 3, {3, 1, BGPPEERLASTERROR}}, +  {bgpPeerTable, 3, {3, 1, BGPPEERSTATE}} +}; + +void +bgpTrapEstablished (struct peer *peer) +{ +  int ret; +  struct in_addr addr; +  oid index[sizeof (oid) * IN_ADDR_SIZE]; + +  ret = inet_aton (peer->host, &addr); +  if (ret == 0) +    return; + +  oid_copy_addr (index, &addr, IN_ADDR_SIZE); + +  smux_trap (bgp_oid, sizeof bgp_oid / sizeof (oid), +	     index, IN_ADDR_SIZE, +	     bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), +	     bm->start_time - time (NULL)); +} + +void +bgpTrapBackwardTransition (struct peer *peer) +{ +  int ret; +  struct in_addr addr; +  oid index[sizeof (oid) * IN_ADDR_SIZE]; + +  ret = inet_aton (peer->host, &addr); +  if (ret == 0) +    return; + +  oid_copy_addr (index, &addr, IN_ADDR_SIZE); + +  smux_trap (bgp_oid, sizeof bgp_oid / sizeof (oid), +	     index, IN_ADDR_SIZE, +	     bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), +	     bm->start_time - time (NULL)); +} + +void +bgp_snmp_init () +{ +  smux_init (bgpd_oid, sizeof bgpd_oid / sizeof (oid)); +  REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid); +  smux_start (); +} +#endif /* HAVE_SNMP */ diff --git a/bgpd/bgp_snmp.h b/bgpd/bgp_snmp.h new file mode 100644 index 0000000000..a8af032986 --- /dev/null +++ b/bgpd/bgp_snmp.h @@ -0,0 +1,23 @@ +/* BGP4 SNMP support +   Copyright (C) 1999, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +void bgp_snmp_init (); +void bgpTrapEstablished (struct peer *); +void bgpTrapBackwardTransition (struct peer *); diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c new file mode 100644 index 0000000000..a2a3c97b18 --- /dev/null +++ b/bgpd/bgp_table.c @@ -0,0 +1,489 @@ +/* BGP routing table +   Copyright (C) 1998, 2001 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "prefix.h" +#include "memory.h" +#include "sockunion.h" +#include "vty.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" + +void bgp_node_delete (struct bgp_node *); +void bgp_table_free (struct bgp_table *); + +struct bgp_table * +bgp_table_init (void) +{ +  struct bgp_table *rt; + +  rt = XMALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table)); +  memset (rt, 0, sizeof (struct bgp_table)); +  return rt; +} + +void +bgp_table_finish (struct bgp_table *rt) +{ +  bgp_table_free (rt); +} + +struct bgp_node * +bgp_node_create () +{ +  struct bgp_node *rn; + +  rn = (struct bgp_node *) XMALLOC (MTYPE_BGP_NODE, sizeof (struct bgp_node)); +  memset (rn, 0, sizeof (struct bgp_node)); +  return rn; +} + +/* Allocate new route node with prefix set. */ +struct bgp_node * +bgp_node_set (struct bgp_table *table, struct prefix *prefix) +{ +  struct bgp_node *node; +   +  node = bgp_node_create (); + +  prefix_copy (&node->p, prefix); +  node->table = table; + +  return node; +} + +/* Free route node. */ +void +bgp_node_free (struct bgp_node *node) +{ +  XFREE (MTYPE_BGP_NODE, node); +} + +/* Free route table. */ +void +bgp_table_free (struct bgp_table *rt) +{ +  struct bgp_node *tmp_node; +  struct bgp_node *node; +  +  if (rt == NULL) +    return; + +  node = rt->top; + +  while (node) +    { +      if (node->l_left) +	{ +	  node = node->l_left; +	  continue; +	} + +      if (node->l_right) +	{ +	  node = node->l_right; +	  continue; +	} + +      tmp_node = node; +      node = node->parent; + +      if (node != NULL) +	{ +	  if (node->l_left == tmp_node) +	    node->l_left = NULL; +	  else +	    node->l_right = NULL; + +	  bgp_node_free (tmp_node); +	} +      else +	{ +	  bgp_node_free (tmp_node); +	  break; +	} +    } +  +  XFREE (MTYPE_BGP_TABLE, rt); +  return; +} + +/* Utility mask array. */ +static u_char maskbit[] =  +{ +  0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff +}; + +/* Common prefix route genaration. */ +static void +route_common (struct prefix *n, struct prefix *p, struct prefix *new) +{ +  int i; +  u_char diff; +  u_char mask; + +  u_char *np = (u_char *)&n->u.prefix; +  u_char *pp = (u_char *)&p->u.prefix; +  u_char *newp = (u_char *)&new->u.prefix; + +  for (i = 0; i < p->prefixlen / 8; i++) +    { +      if (np[i] == pp[i]) +	newp[i] = np[i]; +      else +	break; +    } + +  new->prefixlen = i * 8; + +  if (new->prefixlen != p->prefixlen) +    { +      diff = np[i] ^ pp[i]; +      mask = 0x80; +      while (new->prefixlen < p->prefixlen && !(mask & diff)) +	{ +	  mask >>= 1; +	  new->prefixlen++; +	} +      newp[i] = np[i] & maskbit[new->prefixlen % 8]; +    } +} + +/* Macro version of check_bit (). */ +#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1) + +/* Check bit of the prefix. */ +static int +check_bit (u_char *prefix, u_char prefixlen) +{ +  int offset; +  int shift; +  u_char *p = (u_char *)prefix; + +  assert (prefixlen <= 128); + +  offset = prefixlen / 8; +  shift = 7 - (prefixlen % 8); +   +  return (p[offset] >> shift & 1); +} + +/* Macro version of set_link (). */ +#define SET_LINK(X,Y) (X)->link[CHECK_BIT(&(Y)->prefix,(X)->prefixlen)] = (Y);\ +                      (Y)->parent = (X) + +static void +set_link (struct bgp_node *node, struct bgp_node *new) +{ +  int bit; +     +  bit = check_bit (&new->p.u.prefix, node->p.prefixlen); + +  assert (bit == 0 || bit == 1); + +  node->link[bit] = new; +  new->parent = node; +} + +/* Lock node. */ +struct bgp_node * +bgp_lock_node (struct bgp_node *node) +{ +  node->lock++; +  return node; +} + +/* Unlock node. */ +void +bgp_unlock_node (struct bgp_node *node) +{ +  node->lock--; + +  if (node->lock == 0) +    bgp_node_delete (node); +} + +/* Find matched prefix. */ +struct bgp_node * +bgp_node_match (struct bgp_table *table, struct prefix *p) +{ +  struct bgp_node *node; +  struct bgp_node *matched; + +  matched = NULL; +  node = table->top; + +  /* Walk down tree.  If there is matched route then store it to +     matched. */ +  while (node && node->p.prefixlen <= p->prefixlen &&  +	 prefix_match (&node->p, p)) +    { +      if (node->info) +	matched = node; +      node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; +    } + +  /* If matched route found, return it. */ +  if (matched) +    return bgp_lock_node (matched); + +  return NULL; +} + +struct bgp_node * +bgp_node_match_ipv4 (struct bgp_table *table, struct in_addr *addr) +{ +  struct prefix_ipv4 p; + +  memset (&p, 0, sizeof (struct prefix_ipv4)); +  p.family = AF_INET; +  p.prefixlen = IPV4_MAX_PREFIXLEN; +  p.prefix = *addr; + +  return bgp_node_match (table, (struct prefix *) &p); +} + +#ifdef HAVE_IPV6 +struct bgp_node * +bgp_node_match_ipv6 (struct bgp_table *table, struct in6_addr *addr) +{ +  struct prefix_ipv6 p; + +  memset (&p, 0, sizeof (struct prefix_ipv6)); +  p.family = AF_INET6; +  p.prefixlen = IPV6_MAX_PREFIXLEN; +  p.prefix = *addr; + +  return bgp_node_match (table, (struct prefix *) &p); +} +#endif /* HAVE_IPV6 */ + +/* Lookup same prefix node.  Return NULL when we can't find route. */ +struct bgp_node * +bgp_node_lookup (struct bgp_table *table, struct prefix *p) +{ +  struct bgp_node *node; + +  node = table->top; + +  while (node && node->p.prefixlen <= p->prefixlen &&  +	 prefix_match (&node->p, p)) +    { +      if (node->p.prefixlen == p->prefixlen && node->info) +	return bgp_lock_node (node); + +      node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; +    } + +  return NULL; +} + +/* Add node to routing table. */ +struct bgp_node * +bgp_node_get (struct bgp_table *table, struct prefix *p) +{ +  struct bgp_node *new; +  struct bgp_node *node; +  struct bgp_node *match; + +  match = NULL; +  node = table->top; +  while (node && node->p.prefixlen <= p->prefixlen &&  +	 prefix_match (&node->p, p)) +    { +      if (node->p.prefixlen == p->prefixlen) +	{ +	  bgp_lock_node (node); +	  return node; +	} +      match = node; +      node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; +    } + +  if (node == NULL) +    { +      new = bgp_node_set (table, p); +      if (match) +	set_link (match, new); +      else +	table->top = new; +    } +  else +    { +      new = bgp_node_create (); +      route_common (&node->p, p, &new->p); +      new->p.family = p->family; +      new->table = table; +      set_link (new, node); + +      if (match) +	set_link (match, new); +      else +	table->top = new; + +      if (new->p.prefixlen != p->prefixlen) +	{ +	  match = new; +	  new = bgp_node_set (table, p); +	  set_link (match, new); +	} +    } +  bgp_lock_node (new); +   +  return new; +} + +/* Delete node from the routing table. */ +void +bgp_node_delete (struct bgp_node *node) +{ +  struct bgp_node *child; +  struct bgp_node *parent; + +  assert (node->lock == 0); +  assert (node->info == NULL); + +  if (node->l_left && node->l_right) +    return; + +  if (node->l_left) +    child = node->l_left; +  else +    child = node->l_right; + +  parent = node->parent; + +  if (child) +    child->parent = parent; + +  if (parent) +    { +      if (parent->l_left == node) +	parent->l_left = child; +      else +	parent->l_right = child; +    } +  else +    node->table->top = child; + +  bgp_node_free (node); + +  /* If parent node is stub then delete it also. */ +  if (parent && parent->lock == 0) +    bgp_node_delete (parent); +} + +/* Get fist node and lock it.  This function is useful when one want +   to lookup all the node exist in the routing table. */ +struct bgp_node * +bgp_table_top (struct bgp_table *table) +{ +  /* If there is no node in the routing table return NULL. */ +  if (table->top == NULL) +    return NULL; + +  /* Lock the top node and return it. */ +  bgp_lock_node (table->top); +  return table->top; +} + +/* Unlock current node and lock next node then return it. */ +struct bgp_node * +bgp_route_next (struct bgp_node *node) +{ +  struct bgp_node *next; +  struct bgp_node *start; + +  /* Node may be deleted from bgp_unlock_node so we have to preserve +     next node's pointer. */ + +  if (node->l_left) +    { +      next = node->l_left; +      bgp_lock_node (next); +      bgp_unlock_node (node); +      return next; +    } +  if (node->l_right) +    { +      next = node->l_right; +      bgp_lock_node (next); +      bgp_unlock_node (node); +      return next; +    } + +  start = node; +  while (node->parent) +    { +      if (node->parent->l_left == node && node->parent->l_right) +	{ +	  next = node->parent->l_right; +	  bgp_lock_node (next); +	  bgp_unlock_node (start); +	  return next; +	} +      node = node->parent; +    } +  bgp_unlock_node (start); +  return NULL; +} + +/* Unlock current node and lock next node until limit. */ +struct bgp_node * +bgp_route_next_until (struct bgp_node *node, struct bgp_node *limit) +{ +  struct bgp_node *next; +  struct bgp_node *start; + +  /* Node may be deleted from bgp_unlock_node so we have to preserve +     next node's pointer. */ + +  if (node->l_left) +    { +      next = node->l_left; +      bgp_lock_node (next); +      bgp_unlock_node (node); +      return next; +    } +  if (node->l_right) +    { +      next = node->l_right; +      bgp_lock_node (next); +      bgp_unlock_node (node); +      return next; +    } + +  start = node; +  while (node->parent && node != limit) +    { +      if (node->parent->l_left == node && node->parent->l_right) +	{ +	  next = node->parent->l_right; +	  bgp_lock_node (next); +	  bgp_unlock_node (start); +	  return next; +	} +      node = node->parent; +    } +  bgp_unlock_node (start); +  return NULL; +} diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h new file mode 100644 index 0000000000..52eb6a49a1 --- /dev/null +++ b/bgpd/bgp_table.h @@ -0,0 +1,65 @@ +/* BGP routing table +   Copyright (C) 1998, 2001 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +struct bgp_table +{ +  struct bgp_node *top; +}; + +struct bgp_node +{ +  struct prefix p; + +  struct bgp_table *table; +  struct bgp_node *parent; +  struct bgp_node *link[2]; +#define l_left   link[0] +#define l_right  link[1] + +  unsigned int lock; + +  void *info; + +  struct bgp_adj_out *adj_out; + +  struct bgp_adj_in *adj_in; + +  void *aggregate; + +  struct bgp_node *prn; +}; + +struct bgp_table *bgp_table_init (void); +void bgp_table_finish (struct bgp_table *); +void bgp_unlock_node (struct bgp_node *node); +void bgp_node_delete (struct bgp_node *node); +struct bgp_node *bgp_table_top (struct bgp_table *); +struct bgp_node *bgp_route_next (struct bgp_node *); +struct bgp_node *bgp_route_next_until (struct bgp_node *, struct bgp_node *); +struct bgp_node *bgp_node_get (struct bgp_table *, struct prefix *); +struct bgp_node *bgp_node_lookup (struct bgp_table *, struct prefix *); +struct bgp_node *bgp_lock_node (struct bgp_node *node); +struct bgp_node *bgp_node_match (struct bgp_table *, struct prefix *); +struct bgp_node *bgp_node_match_ipv4 (struct bgp_table *, +					  struct in_addr *); +#ifdef HAVE_IPV6 +struct bgp_node *bgp_node_match_ipv6 (struct bgp_table *, +					  struct in6_addr *); +#endif /* HAVE_IPV6 */ diff --git a/bgpd/bgp_view.c b/bgpd/bgp_view.c new file mode 100644 index 0000000000..795d155131 --- /dev/null +++ b/bgpd/bgp_view.c @@ -0,0 +1,258 @@ +/* + * $Id: bgp_view.c,v 1.1 2002/12/13 20:15:29 paul Exp $ + * + * Multiple view function for route server. + * Copyright (C) 1997 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING.  If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA.   + */ + +#include <zebra.h> + +#include "linklist.h" +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "prefix.h" +#include "zebra/zebra.h" +#include "table.h" +#include "log.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_dump.h" +#include "bgpd/bgp_aspath.h" + +/* Static configuration of BGP annoucement. */ +struct route_table *bgp_static_ipv4; +#ifdef HAVE_IPV6 +struct route_table *bgp_static_ipv6; +#endif /* HAVE_IPV6 */ + +/* Static annoucement peer. */ +struct peer *static_peer; + +/* Default value setting flag */ +#define VAL_LOCAL_PREF 0x01 +#define VAL_MED        0x02 +#define VAL_NEXT_HOP   0x04 + +DEFUN (default_attr_localpref, +       default_attr_localpref_cmd, +       "default-attr local-pref NUMBER", +       "Set default local preference value\n" +       "Set default local preference value\n" +       "Value\n") +{ +  struct bgp *bgp; +  long lpref; + +  bgp = (struct bgp *) vty->index; + +  lpref = strtol (argv[0], NULL, 10); + +  bgp->def |= VAL_LOCAL_PREF; +  bgp->localpref = lpref; + +  return CMD_SUCCESS; +} + +DEFUN (no_default_attr_localpref, +       no_default_attr_localpref_cmd, +       "no default-attr local-pref NUMBER", +       NO_STR +       "Unset default local preference value\n" +       "Unset default local preference value\n" +       "Value\n") +{ +  struct bgp *bgp; + +  bgp = (struct bgp *) vty->index; + +  bgp->def &= ~DEFAULT_LOCAL_PREF; +  bgp->localpref = 0; + +  return CMD_SUCCESS; +} + +#ifdef HAVE_IPV6 +/* Network configuration for IPv6. */ +int +bgp_network_config_ipv6 (struct vty *vty, char *address_str) +{ +  int ret; +  struct prefix p; +  struct route_node *node; +  struct bgp_info *bgp_info; + +  ret = str2prefix_ipv6 (address_str, (struct prefix_ipv6 *) &p); +  if (!ret) +    { +      vty_out (vty, "Please specify valid address\r\n"); +      return CMD_WARNING; +    } + +  apply_mask_ipv6 ((struct prefix_ipv6 *) &p); +   +  node = route_node_get (bgp_static_ipv6, &p); +  if (node->info) +    { +      vty_out (vty, "There is already same static announcement.\r\n"); +      route_unlock_node (node); +      return CMD_WARNING; +    } + +  bgp_info = bgp_info_new (); +  bgp_info->type = ZEBRA_ROUTE_STATIC; +  bgp_info->peer = static_peer; +  bgp_info->attr = bgp_attr_make_default (); +  node->info = bgp_info; + +  nlri_process (&p, bgp_info); + +  return CMD_SUCCESS; +} +#endif + +/* Configure static BGP network. */ +DEFUN (bgp_network, +       bgp_network_cmd, +       "network PREFIX", +       "Announce network setup\n" +       "Static network for bgp announcement\n") +{ +  int ret; +  struct bgp *bgp; +  struct prefix p; +  struct route_node *node; +  struct bgp_info *bgp_info; + +  bgp = (struct bgp *) vty->index; + +  ret = str2prefix_ipv4 (argv[0], (struct prefix_ipv4 *) &p); +  if (!ret) +    { +#ifdef HAVE_IPV6 +      return bgp_network_config_ipv6 (vty, argv[0]); +#endif /* HAVE_IPV6 */ + +      vty_out (vty, "Please specify address by a.b.c.d/mask\r\n"); +      return CMD_WARNING; +    } + +  /* Make sure mask is applied. */ +  apply_mask ((struct prefix_ipv4 *) &p); + +  node = route_node_get (bgp_static_ipv4, &p); +  if (node->info) +    { +      vty_out (vty, "There is already same static announcement.\r\n"); +      route_unlock_node (node); +      return CMD_WARNING; +    } + +  bgp_info = bgp_info_new (); +  bgp_info->type = ZEBRA_ROUTE_STATIC; +  bgp_info->peer = static_peer; +  bgp_info->attr = bgp_attr_make_default (); +  node->info = bgp_info; + +  nlri_process (&p, bgp_info); + +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_network, +       no_bgp_network_cmd, +       "no network PREFIX", +       NO_STR +       "Announce network setup\n" +       "Delete static network for bgp announcement\n") +{ +  int ret; +  struct bgp *bgp; +  struct route_node *np; +  struct prefix_ipv4 p; + +  bgp = (struct bgp *) vty->index; + +  ret = str2prefix_ipv4 (argv[0], &p); +  if (!ret) +    { +      vty_out (vty, "Please specify address by a.b.c.d/mask\r\n"); +      return CMD_WARNING; +    } + +  apply_mask (&p); + +  np = route_node_get (bgp_static_ipv4, (struct prefix *) &p); +  if (!np->info) +    { +      vty_out (vty, "Can't find specified static route configuration.\r\n"); +      route_unlock_node (np); +      return CMD_WARNING; +    } +  nlri_delete (static_peer, (struct prefix *) &p); + +  /* bgp_attr_free (np->info); */ +  np->info = NULL; + +  route_unlock_node (np); + +  return CMD_SUCCESS; +} + +int +config_write_network (struct vty *vty, struct bgp *bgp) +{ +  struct route_node *node; +  struct bgp_route *route; +  char buf[BUFSIZ]; +   +  for (node = route_top (bgp_static_ipv4); node; node = route_next (node))  +    for (route = node->info; route; route = route->next) +      vty_out (vty, " network %s/%d%s",  +	       inet_ntoa (node->p.u.prefix4), node->p.prefixlen, VTY_NEWLINE); +#ifdef HAVE_IPV6 +  for (node = route_top (bgp_static_ipv6); node; node = route_next (node))  +    for (route = node->info; route; route = route->next) +      vty_out (vty, " network %s/%d%s",  +	       inet_ntop (AF_INET6, &node->p.u.prefix6, buf, BUFSIZ), +	       node->p.prefixlen, VTY_NEWLINE); +#endif /* HAVE_IPV6 */ + +  return 0; +} + +void +view_init () +{ +  bgp_static_ipv4 = route_table_init (); +#ifdef HAVE_IPV6 +  bgp_static_ipv6 = route_table_init (); +#endif /* HAVE_IPV6 */ + +  static_peer = peer_new (); +  static_peer->host = "Static annucement"; + +  install_element (BGP_NODE, &bgp_network_cmd); +  install_element (BGP_NODE, &no_bgp_network_cmd); +  install_element (BGP_NODE, &default_attr_localpref_cmd); +  install_element (BGP_NODE, &no_default_attr_localpref_cmd); +} diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c new file mode 100644 index 0000000000..c1bae93ef9 --- /dev/null +++ b/bgpd/bgp_vty.c @@ -0,0 +1,9416 @@ +/* BGP VTY interface. +   Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "command.h" +#include "prefix.h" +#include "plist.h" +#include "buffer.h" +#include "linklist.h" +#include "stream.h" +#include "thread.h" +#include "log.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_open.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_zebra.h" + +/* Utility function to get address family from current node.  */ +afi_t +bgp_node_afi (struct vty *vty) +{ +  if (vty->node == BGP_IPV6_NODE) +    return AFI_IP6; +  return AFI_IP; +} + +/* Utility function to get subsequent address family from current +   node.  */ +safi_t +bgp_node_safi (struct vty *vty) +{ +  if (vty->node == BGP_VPNV4_NODE) +    return SAFI_MPLS_VPN; +  if (vty->node == BGP_IPV4M_NODE) +    return SAFI_MULTICAST; +  return SAFI_UNICAST; +} + +int +peer_address_self_check (union sockunion *su) +{ +  struct interface *ifp = NULL; + +  if (su->sa.sa_family == AF_INET) +    ifp = if_lookup_by_ipv4_exact (&su->sin.sin_addr); +#ifdef HAVE_IPV6 +  else if (su->sa.sa_family == AF_INET6) +    ifp = if_lookup_by_ipv6_exact (&su->sin6.sin6_addr); +#endif /* HAVE IPV6 */ + +  if (ifp) +    return 1; + +  return 0; +} + +/* Utility function for looking up peer from VTY.  */ +struct peer * +peer_lookup_vty (struct vty *vty, char *ip_str) +{ +  int ret; +  struct bgp *bgp; +  union sockunion su; +  struct peer *peer; + +  bgp = vty->index; + +  ret = str2sockunion (ip_str, &su); +  if (ret < 0) +    { +      vty_out (vty, "%% Malformed address: %s%s", ip_str, VTY_NEWLINE); +      return NULL; +    } + +  peer = peer_lookup (bgp, &su); +  if (! peer) +    { +      vty_out (vty, "%% Specify remote-as or peer-group commands first%s", VTY_NEWLINE); +      return NULL; +    } +  return peer; +} + +/* Utility function for looking up peer or peer group.  */ +struct peer * +peer_and_group_lookup_vty (struct vty *vty, char *peer_str) +{ +  int ret; +  struct bgp *bgp; +  union sockunion su; +  struct peer *peer; +  struct peer_group *group; + +  bgp = vty->index; + +  ret = str2sockunion (peer_str, &su); +  if (ret == 0) +    { +      peer = peer_lookup (bgp, &su); +      if (peer) +	return peer; +    } +  else +    { +      group = peer_group_lookup (bgp, peer_str); +      if (group) +	return group->conf; +    } + +  vty_out (vty, "%% Specify remote-as or peer-group commands first%s", +	   VTY_NEWLINE); + +  return NULL; +} + +int +bgp_vty_return (struct vty *vty, int ret) +{ +  char *str = NULL; + +  switch (ret) +    { +    case BGP_ERR_INVALID_VALUE: +      str = "Invalid value"; +      break; +    case BGP_ERR_INVALID_FLAG: +      str = "Invalid flag"; +      break; +    case BGP_ERR_PEER_INACTIVE: +      str = "Activate the neighbor for the address family first"; +      break; +    case BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER: +      str = "Invalid command for a peer-group member"; +      break; +    case BGP_ERR_PEER_GROUP_SHUTDOWN: +      str = "Peer-group has been shutdown. Activate the peer-group first"; +      break; +    case BGP_ERR_PEER_GROUP_HAS_THE_FLAG: +      str = "This peer is a peer-group member.  Please change peer-group configuration"; +      break; +    case BGP_ERR_PEER_FLAG_CONFLICT: +      str = "Can't set override-capability and strict-capability-match at the same time"; +      break; +    case BGP_ERR_PEER_GROUP_MEMBER_EXISTS: +      str = "No activate for peergroup can be given only if peer-group has no members"; +      break; +    case BGP_ERR_PEER_BELONGS_TO_GROUP: +      str = "No activate for an individual peer-group member is invalid"; +      break; +    case BGP_ERR_PEER_GROUP_AF_UNCONFIGURED: +      str = "Activate the peer-group for the address family first"; +      break; +    case BGP_ERR_PEER_GROUP_NO_REMOTE_AS: +      str = "Specify remote-as or peer-group remote AS first"; +      break; +    case BGP_ERR_PEER_GROUP_CANT_CHANGE: +      str = "Cannot change the peer-group. Deconfigure first"; +      break; +    case BGP_ERR_PEER_GROUP_MISMATCH: +      str = "Cannot have different peer-group for the neighbor"; +      break; +    case BGP_ERR_PEER_FILTER_CONFLICT: +      str = "Prefix/distribute list can not co-exist"; +      break; +    case BGP_ERR_NOT_INTERNAL_PEER: +      str = "Invalid command. Not an internal neighbor"; +      break; +    case BGP_ERR_REMOVE_PRIVATE_AS: +      str = "Private AS cannot be removed for IBGP peers"; +      break; +    case BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP: +      str = "Local-AS allowed only for EBGP peers"; +      break; +    case BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS: +      str = "Cannot have local-as same as BGP AS number"; +      break; +    } +  if (str) +    { +      vty_out (vty, "%% %s%s", str, VTY_NEWLINE); +      return CMD_WARNING; +    } +  return CMD_SUCCESS; +} + +/* BGP global configuration.  */ + +DEFUN (bgp_multiple_instance_func, +       bgp_multiple_instance_cmd, +       "bgp multiple-instance", +       BGP_STR +       "Enable bgp multiple instance\n") +{ +  bgp_option_set (BGP_OPT_MULTIPLE_INSTANCE); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_multiple_instance, +       no_bgp_multiple_instance_cmd, +       "no bgp multiple-instance", +       NO_STR +       BGP_STR +       "BGP multiple instance\n") +{ +  int ret; + +  ret = bgp_option_unset (BGP_OPT_MULTIPLE_INSTANCE); +  if (ret < 0) +    { +      vty_out (vty, "%% There are more than two BGP instances%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  return CMD_SUCCESS; +} + +DEFUN (bgp_config_type, +       bgp_config_type_cmd, +       "bgp config-type (cisco|zebra)", +       BGP_STR +       "Configuration type\n" +       "cisco\n" +       "zebra\n") +{ +  if (strncmp (argv[0], "c", 1) == 0) +    bgp_option_set (BGP_OPT_CONFIG_CISCO); +  else +    bgp_option_unset (BGP_OPT_CONFIG_CISCO); + +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_config_type, +       no_bgp_config_type_cmd, +       "no bgp config-type", +       NO_STR +       BGP_STR +       "Display configuration type\n") +{ +  bgp_option_unset (BGP_OPT_CONFIG_CISCO); +  return CMD_SUCCESS; +} + +DEFUN (no_synchronization, +       no_synchronization_cmd, +       "no synchronization", +       NO_STR +       "Perform IGP synchronization\n") +{ +  return CMD_SUCCESS; +} + +DEFUN (no_auto_summary, +       no_auto_summary_cmd, +       "no auto-summary", +       NO_STR +       "Enable automatic network number summarization\n") +{ +  return CMD_SUCCESS; +} + +/* "router bgp" commands. */ +DEFUN (router_bgp,  +       router_bgp_cmd,  +       "router bgp <1-65535>", +       ROUTER_STR +       BGP_STR +       AS_STR) +{ +  int ret; +  as_t as; +  struct bgp *bgp; +  char *name = NULL; + +  VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, 65535); + +  if (argc == 2) +    name = argv[1]; + +  ret = bgp_get (&bgp, &as, name); +  switch (ret) +    { +    case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET: +      vty_out (vty, "Please specify 'bgp multiple-instance' first%s",  +	       VTY_NEWLINE); +      return CMD_WARNING; +      break; +    case BGP_ERR_AS_MISMATCH: +      vty_out (vty, "BGP is already running; AS is %d%s", as, VTY_NEWLINE); +      return CMD_WARNING; +      break; +    case BGP_ERR_INSTANCE_MISMATCH: +      vty_out (vty, "BGP view name and AS number mismatch%s", VTY_NEWLINE); +      vty_out (vty, "BGP instance is already running; AS is %d%s", +	       as, VTY_NEWLINE); +      return CMD_WARNING; +      break; +    } + +  vty->node = BGP_NODE; +  vty->index = bgp; + +  return CMD_SUCCESS; +} + +ALIAS (router_bgp, +       router_bgp_view_cmd, +       "router bgp <1-65535> view WORD", +       ROUTER_STR +       BGP_STR +       AS_STR +       "BGP view\n" +       "view name\n") + +/* "no router bgp" commands. */ +DEFUN (no_router_bgp, +       no_router_bgp_cmd, +       "no router bgp <1-65535>", +       NO_STR +       ROUTER_STR +       BGP_STR +       AS_STR) +{ +  as_t as; +  struct bgp *bgp; +  char *name = NULL; + +  VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, 65535); + +  if (argc == 2) +    name = argv[1]; + +  /* Lookup bgp structure. */ +  bgp = bgp_lookup (as, name); +  if (! bgp) +    { +      vty_out (vty, "%% Can't find BGP instance%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_delete (bgp); + +  return CMD_SUCCESS; +} + +ALIAS (no_router_bgp, +       no_router_bgp_view_cmd, +       "no router bgp <1-65535> view WORD", +       NO_STR +       ROUTER_STR +       BGP_STR +       AS_STR +       "BGP view\n" +       "view name\n") + +/* BGP router-id.  */ + +DEFUN (bgp_router_id, +       bgp_router_id_cmd, +       "bgp router-id A.B.C.D", +       BGP_STR +       "Override configured router identifier\n" +       "Manually configured router identifier\n") +{ +  int ret; +  struct in_addr id; +  struct bgp *bgp; + +  bgp = vty->index; + +  ret = inet_aton (argv[0], &id); +  if (! ret) +    { +      vty_out (vty, "%% Malformed bgp router identifier%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_router_id_set (bgp, &id); + +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_router_id, +       no_bgp_router_id_cmd, +       "no bgp router-id", +       NO_STR +       BGP_STR +       "Override configured router identifier\n") +{ +  int ret; +  struct in_addr id; +  struct bgp *bgp; + +  bgp = vty->index; + +  if (argc == 1) +    { +      ret = inet_aton (argv[0], &id); +      if (! ret) +	{ +	  vty_out (vty, "%% Malformed BGP router identifier%s", VTY_NEWLINE); +	  return CMD_WARNING; +	} + +      if (! IPV4_ADDR_SAME (&bgp->router_id, &id)) +	{ +	  vty_out (vty, "%% BGP router-id doesn't match%s", VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } + +  bgp_router_id_unset (bgp); + +  return CMD_SUCCESS; +} + +ALIAS (no_bgp_router_id, +       no_bgp_router_id_val_cmd, +       "no bgp router-id A.B.C.D", +       NO_STR +       BGP_STR +       "Override configured router identifier\n" +       "Manually configured router identifier\n") + +/* BGP Cluster ID.  */ + +DEFUN (bgp_cluster_id, +       bgp_cluster_id_cmd, +       "bgp cluster-id A.B.C.D", +       BGP_STR +       "Configure Route-Reflector Cluster-id\n" +       "Route-Reflector Cluster-id in IP address format\n") +{ +  int ret; +  struct bgp *bgp; +  struct in_addr cluster; + +  bgp = vty->index; + +  ret = inet_aton (argv[0], &cluster); +  if (! ret) +    { +      vty_out (vty, "%% Malformed bgp cluster identifier%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_cluster_id_set (bgp, &cluster); + +  return CMD_SUCCESS; +} + +ALIAS (bgp_cluster_id, +       bgp_cluster_id32_cmd, +       "bgp cluster-id <1-4294967295>", +       BGP_STR +       "Configure Route-Reflector Cluster-id\n" +       "Route-Reflector Cluster-id as 32 bit quantity\n") + +DEFUN (no_bgp_cluster_id, +       no_bgp_cluster_id_cmd, +       "no bgp cluster-id", +       NO_STR +       BGP_STR +       "Configure Route-Reflector Cluster-id\n") +{ +  int ret; +  struct bgp *bgp; +  struct in_addr cluster; + +  bgp = vty->index; + +  if (argc == 1) +    { +      ret = inet_aton (argv[0], &cluster); +      if (! ret) +	{ +	  vty_out (vty, "%% Malformed bgp cluster identifier%s", VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } + +  bgp_cluster_id_unset (bgp); + +  return CMD_SUCCESS; +} + +ALIAS (no_bgp_cluster_id, +       no_bgp_cluster_id_arg_cmd, +       "no bgp cluster-id A.B.C.D", +       NO_STR +       BGP_STR +       "Configure Route-Reflector Cluster-id\n" +       "Route-Reflector Cluster-id in IP address format\n") + +DEFUN (bgp_confederation_identifier, +       bgp_confederation_identifier_cmd, +       "bgp confederation identifier <1-65535>", +       "BGP specific commands\n" +       "AS confederation parameters\n" +       "AS number\n" +       "Set routing domain confederation AS\n") +{ +  struct bgp *bgp; +  as_t as; + +  bgp = vty->index; + +  VTY_GET_INTEGER ("AS", as, argv[0]); + +  bgp_confederation_id_set (bgp, as); + +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_confederation_identifier, +       no_bgp_confederation_identifier_cmd, +       "no bgp confederation identifier", +       NO_STR +       "BGP specific commands\n" +       "AS confederation parameters\n" +       "AS number\n") +{ +  struct bgp *bgp; +  as_t as; + +  bgp = vty->index; + +  if (argc == 1) +    VTY_GET_INTEGER ("AS", as, argv[0]); + +  bgp_confederation_id_unset (bgp); + +  return CMD_SUCCESS; +} + +ALIAS (no_bgp_confederation_identifier, +       no_bgp_confederation_identifier_arg_cmd, +       "no bgp confederation identifier <1-65535>", +       NO_STR +       "BGP specific commands\n" +       "AS confederation parameters\n" +       "AS number\n" +       "Set routing domain confederation AS\n") + +DEFUN (bgp_confederation_peers, +       bgp_confederation_peers_cmd, +       "bgp confederation peers .<1-65535>", +       "BGP specific commands\n" +       "AS confederation parameters\n" +       "Peer ASs in BGP confederation\n" +       AS_STR) +{ +  struct bgp *bgp; +  as_t as; +  int i; + +  bgp = vty->index; + +  for (i = 0; i < argc; i++) +    { +      VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, 65535); + +      if (bgp->as == as) +	{ +	  vty_out (vty, "%% Local member-AS not allowed in confed peer list%s", +		   VTY_NEWLINE); +	  continue; +	} + +      bgp_confederation_peers_add (bgp, as); +    } +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_confederation_peers, +       no_bgp_confederation_peers_cmd, +       "no bgp confederation peers .<1-65535>", +       NO_STR +       "BGP specific commands\n" +       "AS confederation parameters\n" +       "Peer ASs in BGP confederation\n" +       AS_STR) +{ +  struct bgp *bgp; +  as_t as; +  int i; + +  bgp = vty->index; + +  for (i = 0; i < argc; i++) +    { +      VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, 65535); +       +      bgp_confederation_peers_remove (bgp, as); +    } +  return CMD_SUCCESS; +} + +/* BGP timers.  */ + +DEFUN (bgp_timers, +       bgp_timers_cmd, +       "timers bgp <0-65535> <0-65535>", +       "Adjust routing timers\n" +       "BGP timers\n" +       "Keepalive interval\n" +       "Holdtime\n") +{ +  struct bgp *bgp; +  unsigned long keepalive = 0; +  unsigned long holdtime = 0; + +  bgp = vty->index; + +  VTY_GET_INTEGER ("keepalive", keepalive, argv[0]); +  VTY_GET_INTEGER ("holdtime", holdtime, argv[1]); + +  /* Holdtime value check. */ +  if (holdtime < 3 && holdtime != 0) +    { +      vty_out (vty, "%% hold time value must be either 0 or greater than 3%s", +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_timers_set (bgp, keepalive, holdtime); + +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_timers, +       no_bgp_timers_cmd, +       "no timers bgp", +       NO_STR +       "Adjust routing timers\n" +       "BGP timers\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_timers_unset (bgp); + +  return CMD_SUCCESS; +} + +ALIAS (no_bgp_timers, +       no_bgp_timers_arg_cmd, +       "no timers bgp <0-65535> <0-65535>", +       NO_STR +       "Adjust routing timers\n" +       "BGP timers\n" +       "Keepalive interval\n" +       "Holdtime\n") + +DEFUN (bgp_client_to_client_reflection, +       bgp_client_to_client_reflection_cmd, +       "bgp client-to-client reflection", +       "BGP specific commands\n" +       "Configure client to client route reflection\n" +       "reflection of routes allowed\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_unset (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_client_to_client_reflection, +       no_bgp_client_to_client_reflection_cmd, +       "no bgp client-to-client reflection", +       NO_STR +       "BGP specific commands\n" +       "Configure client to client route reflection\n" +       "reflection of routes allowed\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_set (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT); +  return CMD_SUCCESS; +} + +/* "bgp always-compare-med" configuration. */ +DEFUN (bgp_always_compare_med, +       bgp_always_compare_med_cmd, +       "bgp always-compare-med", +       "BGP specific commands\n" +       "Allow comparing MED from different neighbors\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_set (bgp, BGP_FLAG_ALWAYS_COMPARE_MED); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_always_compare_med, +       no_bgp_always_compare_med_cmd, +       "no bgp always-compare-med", +       NO_STR +       "BGP specific commands\n" +       "Allow comparing MED from different neighbors\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_unset (bgp, BGP_FLAG_ALWAYS_COMPARE_MED); +  return CMD_SUCCESS; +} + +/* "bgp deterministic-med" configuration. */ +DEFUN (bgp_deterministic_med, +       bgp_deterministic_med_cmd, +       "bgp deterministic-med", +       "BGP specific commands\n" +       "Pick the best-MED path among paths advertised from the neighboring AS\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_set (bgp, BGP_FLAG_DETERMINISTIC_MED); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_deterministic_med, +       no_bgp_deterministic_med_cmd, +       "no bgp deterministic-med", +       NO_STR +       "BGP specific commands\n" +       "Pick the best-MED path among paths advertised from the neighboring AS\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_unset (bgp, BGP_FLAG_DETERMINISTIC_MED); +  return CMD_SUCCESS; +} + +/* "bgp fast-external-failover" configuration. */ +DEFUN (bgp_fast_external_failover, +       bgp_fast_external_failover_cmd, +       "bgp fast-external-failover", +       BGP_STR +       "Immediately reset session if a link to a directly connected external peer goes down\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_unset (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_fast_external_failover, +       no_bgp_fast_external_failover_cmd, +       "no bgp fast-external-failover", +       NO_STR +       BGP_STR +       "Immediately reset session if a link to a directly connected external peer goes down\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_set (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER); +  return CMD_SUCCESS; +} + +/* "bgp enforce-first-as" configuration. */ +DEFUN (bgp_enforce_first_as, +       bgp_enforce_first_as_cmd, +       "bgp enforce-first-as", +       BGP_STR +       "Enforce the first AS for EBGP routes\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_set (bgp, BGP_FLAG_ENFORCE_FIRST_AS); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_enforce_first_as, +       no_bgp_enforce_first_as_cmd, +       "no bgp enforce-first-as", +       NO_STR +       BGP_STR +       "Enforce the first AS for EBGP routes\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_unset (bgp, BGP_FLAG_ENFORCE_FIRST_AS); +  return CMD_SUCCESS; +} + +/* "bgp bestpath compare-routerid" configuration.  */ +DEFUN (bgp_bestpath_compare_router_id, +       bgp_bestpath_compare_router_id_cmd, +       "bgp bestpath compare-routerid", +       "BGP specific commands\n" +       "Change the default bestpath selection\n" +       "Compare router-id for identical EBGP paths\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_set (bgp, BGP_FLAG_COMPARE_ROUTER_ID); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_bestpath_compare_router_id, +       no_bgp_bestpath_compare_router_id_cmd, +       "no bgp bestpath compare-routerid", +       NO_STR +       "BGP specific commands\n" +       "Change the default bestpath selection\n" +       "Compare router-id for identical EBGP paths\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_unset (bgp, BGP_FLAG_COMPARE_ROUTER_ID); +  return CMD_SUCCESS; +} + +/* "bgp bestpath as-path ignore" configuration.  */ +DEFUN (bgp_bestpath_aspath_ignore, +       bgp_bestpath_aspath_ignore_cmd, +       "bgp bestpath as-path ignore", +       "BGP specific commands\n" +       "Change the default bestpath selection\n" +       "AS-path attribute\n" +       "Ignore as-path length in selecting a route\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_set (bgp, BGP_FLAG_ASPATH_IGNORE); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_bestpath_aspath_ignore, +       no_bgp_bestpath_aspath_ignore_cmd, +       "no bgp bestpath as-path ignore", +       NO_STR +       "BGP specific commands\n" +       "Change the default bestpath selection\n" +       "AS-path attribute\n" +       "Ignore as-path length in selecting a route\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_unset (bgp, BGP_FLAG_ASPATH_IGNORE); +  return CMD_SUCCESS; +} + +/* "bgp bestpath med" configuration. */ +DEFUN (bgp_bestpath_med, +       bgp_bestpath_med_cmd, +       "bgp bestpath med (confed|missing-as-worst)", +       "BGP specific commands\n" +       "Change the default bestpath selection\n" +       "MED attribute\n" +       "Compare MED among confederation paths\n" +       "Treat missing MED as the least preferred one\n") +{ +  struct bgp *bgp; +   +  bgp = vty->index; + +  if (strncmp (argv[0], "confed", 1) == 0) +    bgp_flag_set (bgp, BGP_FLAG_MED_CONFED); +  else +    bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST); + +  return CMD_SUCCESS; +} + +DEFUN (bgp_bestpath_med2, +       bgp_bestpath_med2_cmd, +       "bgp bestpath med confed missing-as-worst", +       "BGP specific commands\n" +       "Change the default bestpath selection\n" +       "MED attribute\n" +       "Compare MED among confederation paths\n" +       "Treat missing MED as the least preferred one\n") +{ +  struct bgp *bgp; +   +  bgp = vty->index; +  bgp_flag_set (bgp, BGP_FLAG_MED_CONFED); +  bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST); +  return CMD_SUCCESS; +} + +ALIAS (bgp_bestpath_med2, +       bgp_bestpath_med3_cmd, +       "bgp bestpath med missing-as-worst confed", +       "BGP specific commands\n" +       "Change the default bestpath selection\n" +       "MED attribute\n" +       "Treat missing MED as the least preferred one\n" +       "Compare MED among confederation paths\n") + +DEFUN (no_bgp_bestpath_med, +       no_bgp_bestpath_med_cmd, +       "no bgp bestpath med (confed|missing-as-worst)", +       NO_STR +       "BGP specific commands\n" +       "Change the default bestpath selection\n" +       "MED attribute\n" +       "Compare MED among confederation paths\n" +       "Treat missing MED as the least preferred one\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +   +  if (strncmp (argv[0], "confed", 1) == 0) +    bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED); +  else +    bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST); + +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_bestpath_med2, +       no_bgp_bestpath_med2_cmd, +       "no bgp bestpath med confed missing-as-worst", +       NO_STR +       "BGP specific commands\n" +       "Change the default bestpath selection\n" +       "MED attribute\n" +       "Compare MED among confederation paths\n" +       "Treat missing MED as the least preferred one\n") +{ +  struct bgp *bgp; +   +  bgp = vty->index; +  bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED); +  bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST); +  return CMD_SUCCESS; +} + +ALIAS (no_bgp_bestpath_med2, +       no_bgp_bestpath_med3_cmd, +       "no bgp bestpath med missing-as-worst confed", +       NO_STR +       "BGP specific commands\n" +       "Change the default bestpath selection\n" +       "MED attribute\n" +       "Treat missing MED as the least preferred one\n" +       "Compare MED among confederation paths\n") + +/* "no bgp default ipv4-unicast". */ +DEFUN (no_bgp_default_ipv4_unicast, +       no_bgp_default_ipv4_unicast_cmd, +       "no bgp default ipv4-unicast", +       NO_STR +       "BGP specific commands\n" +       "Configure BGP defaults\n" +       "Activate ipv4-unicast for a peer by default\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_set (bgp, BGP_FLAG_NO_DEFAULT_IPV4); +  return CMD_SUCCESS; +} + +DEFUN (bgp_default_ipv4_unicast, +       bgp_default_ipv4_unicast_cmd, +       "bgp default ipv4-unicast", +       "BGP specific commands\n" +       "Configure BGP defaults\n" +       "Activate ipv4-unicast for a peer by default\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_unset (bgp, BGP_FLAG_NO_DEFAULT_IPV4); +  return CMD_SUCCESS; +} + +/* "bgp import-check" configuration.  */ +DEFUN (bgp_network_import_check, +       bgp_network_import_check_cmd, +       "bgp network import-check", +       "BGP specific commands\n" +       "BGP network command\n" +       "Check BGP network route exists in IGP\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_network_import_check, +       no_bgp_network_import_check_cmd, +       "no bgp network import-check", +       NO_STR +       "BGP specific commands\n" +       "BGP network command\n" +       "Check BGP network route exists in IGP\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK); +  return CMD_SUCCESS; +} + +DEFUN (bgp_default_local_preference, +       bgp_default_local_preference_cmd, +       "bgp default local-preference <0-4294967295>", +       "BGP specific commands\n" +       "Configure BGP defaults\n" +       "local preference (higher=more preferred)\n" +       "Configure default local preference value\n") +{ +  struct bgp *bgp; +  u_int32_t local_pref; + +  bgp = vty->index; + +  VTY_GET_INTEGER ("local preference", local_pref, argv[0]); + +  bgp_default_local_preference_set (bgp, local_pref); + +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_default_local_preference, +       no_bgp_default_local_preference_cmd, +       "no bgp default local-preference", +       NO_STR +       "BGP specific commands\n" +       "Configure BGP defaults\n" +       "local preference (higher=more preferred)\n") +{ +  struct bgp *bgp; + +  bgp = vty->index; +  bgp_default_local_preference_unset (bgp); +  return CMD_SUCCESS; +} + +ALIAS (no_bgp_default_local_preference, +       no_bgp_default_local_preference_val_cmd, +       "no bgp default local-preference <0-4294967295>", +       NO_STR +       "BGP specific commands\n" +       "Configure BGP defaults\n" +       "local preference (higher=more preferred)\n" +       "Configure default local preference value\n") + +static int +peer_remote_as_vty (struct vty *vty, char *peer_str, char *as_str, afi_t afi, +		    safi_t safi) +{ +  int ret; +  struct bgp *bgp; +  as_t as; +  union sockunion su; + +  bgp = vty->index; + +  /* Get AS number.  */ +  VTY_GET_INTEGER_RANGE ("AS", as, as_str, 1, 65535); + +  /* If peer is peer group, call proper function.  */ +  ret = str2sockunion (peer_str, &su); +  if (ret < 0) +    { +      ret = peer_group_remote_as (bgp, peer_str, &as); +      if (ret < 0) +	{ +	  vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); +	  return CMD_WARNING; +	} +      return CMD_SUCCESS; +    } + +  if (peer_address_self_check (&su)) +    { +      vty_out (vty, "%% Can not configure the local system as neighbor%s", +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  ret = peer_remote_as (bgp, &su, &as, afi, safi); + +  /* This peer belongs to peer group.  */ +  switch (ret) +    { +    case BGP_ERR_PEER_GROUP_MEMBER: +      vty_out (vty, "%% Peer-group AS %d. Cannot configure remote-as for member%s", as, VTY_NEWLINE); +      return CMD_WARNING; +      break; +    case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT: +      vty_out (vty, "%% The AS# can not be changed from %d to %s, peer-group members must be all internal or all external%s", as, as_str, VTY_NEWLINE); +      return CMD_WARNING; +      break; +    } +  return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_remote_as, +       neighbor_remote_as_cmd, +       NEIGHBOR_CMD2 "remote-as <1-65535>", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Specify a BGP neighbor\n" +       AS_STR) +{ +  return peer_remote_as_vty (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST); +} + +DEFUN (neighbor_peer_group, +       neighbor_peer_group_cmd, +       "neighbor WORD peer-group", +       NEIGHBOR_STR +       "Neighbor tag\n" +       "Configure peer-group\n") +{ +  struct bgp *bgp; +  struct peer_group *group; + +  bgp = vty->index; + +  group = peer_group_get (bgp, argv[0]); +  if (! group) +    return CMD_WARNING; + +  return CMD_SUCCESS; +} + +DEFUN (no_neighbor, +       no_neighbor_cmd, +       NO_NEIGHBOR_CMD2, +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2) +{ +  int ret; +  union sockunion su; +  struct peer_group *group; +  struct peer *peer; + +  ret = str2sockunion (argv[0], &su); +  if (ret < 0) +    { +      group = peer_group_lookup (vty->index, argv[0]); +      if (group) +	peer_group_delete (group); +      else +	{ +	  vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } +  else +    { +      peer = peer_lookup (vty->index, &su); +      if (peer) +	peer_delete (peer); +    } + +  return CMD_SUCCESS; +} + +ALIAS (no_neighbor, +       no_neighbor_remote_as_cmd, +       NO_NEIGHBOR_CMD "remote-as <1-65535>", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Specify a BGP neighbor\n" +       AS_STR) + +DEFUN (no_neighbor_peer_group, +       no_neighbor_peer_group_cmd, +       "no neighbor WORD peer-group", +       NO_STR +       NEIGHBOR_STR +       "Neighbor tag\n" +       "Configure peer-group\n") +{ +  struct peer_group *group; + +  group = peer_group_lookup (vty->index, argv[0]); +  if (group) +    peer_group_delete (group); +  else +    { +      vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  return CMD_SUCCESS; +} + +DEFUN (no_neighbor_peer_group_remote_as, +       no_neighbor_peer_group_remote_as_cmd, +       "no neighbor WORD remote-as <1-65535>", +       NO_STR +       NEIGHBOR_STR +       "Neighbor tag\n" +       "Specify a BGP neighbor\n" +       AS_STR) +{ +  struct peer_group *group; + +  group = peer_group_lookup (vty->index, argv[0]); +  if (group) +    peer_group_remote_as_delete (group); +  else +    { +      vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  return CMD_SUCCESS; +} + +DEFUN (neighbor_local_as, +       neighbor_local_as_cmd, +       NEIGHBOR_CMD2 "local-as <1-65535>", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Specify a local-as number\n" +       "AS number used as local AS\n") +{ +  struct peer *peer; +  int ret; + +  peer = peer_and_group_lookup_vty (vty, argv[0]); +  if (! peer) +    return CMD_WARNING; + +  ret = peer_local_as_set (peer, atoi (argv[1]), 0); +  return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_local_as_no_prepend, +       neighbor_local_as_no_prepend_cmd, +       NEIGHBOR_CMD2 "local-as <1-65535> no-prepend", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Specify a local-as number\n" +       "AS number used as local AS\n" +       "Do not prepend local-as to updates from ebgp peers\n") +{ +  struct peer *peer; +  int ret; + +  peer = peer_and_group_lookup_vty (vty, argv[0]); +  if (! peer) +    return CMD_WARNING; + +  ret = peer_local_as_set (peer, atoi (argv[1]), 1); +  return bgp_vty_return (vty, ret); +} + +DEFUN (no_neighbor_local_as, +       no_neighbor_local_as_cmd, +       NO_NEIGHBOR_CMD2 "local-as", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Specify a local-as number\n") +{ +  struct peer *peer; +  int ret; + +  peer = peer_and_group_lookup_vty (vty, argv[0]); +  if (! peer) +    return CMD_WARNING; + +  ret = peer_local_as_unset (peer); +  return bgp_vty_return (vty, ret); +} + +ALIAS (no_neighbor_local_as, +       no_neighbor_local_as_val_cmd, +       NO_NEIGHBOR_CMD2 "local-as <1-65535>", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Specify a local-as number\n" +       "AS number used as local AS\n") + +ALIAS (no_neighbor_local_as, +       no_neighbor_local_as_val2_cmd, +       NO_NEIGHBOR_CMD2 "local-as <1-65535> no-prepend", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Specify a local-as number\n" +       "AS number used as local AS\n" +       "Do not prepend local-as to updates from ebgp peers\n") + +DEFUN (neighbor_activate, +       neighbor_activate_cmd, +       NEIGHBOR_CMD2 "activate", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Enable the Address Family for this Neighbor\n") +{ +  struct peer *peer; + +  peer = peer_and_group_lookup_vty (vty, argv[0]); +  if (! peer) +    return CMD_WARNING; + +  peer_activate (peer, bgp_node_afi (vty), bgp_node_safi (vty)); + +  return CMD_SUCCESS; +} + +DEFUN (no_neighbor_activate, +       no_neighbor_activate_cmd, +       NO_NEIGHBOR_CMD2 "activate", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Enable the Address Family for this Neighbor\n") +{ +  int ret; +  struct peer *peer; + +  /* Lookup peer. */ +  peer = peer_and_group_lookup_vty (vty, argv[0]); +  if (! peer) +    return CMD_WARNING; + +  ret = peer_deactivate (peer, bgp_node_afi (vty), bgp_node_safi (vty)); + +  return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_set_peer_group, +       neighbor_set_peer_group_cmd, +       NEIGHBOR_CMD "peer-group WORD", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Member of the peer-group\n" +       "peer-group name\n") +{ +  int ret; +  as_t as; +  union sockunion su; +  struct bgp *bgp; +  struct peer_group *group; + +  bgp = vty->index; + +  ret = str2sockunion (argv[0], &su); +  if (ret < 0) +    { +      vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); +      return CMD_WARNING; +    } + +  group = peer_group_lookup (bgp, argv[1]); +  if (! group) +    { +      vty_out (vty, "%% Configure the peer-group first%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  if (peer_address_self_check (&su)) +    { +      vty_out (vty, "%% Can not configure the local system as neighbor%s", +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  ret = peer_group_bind (bgp, &su, group, bgp_node_afi (vty),  +			 bgp_node_safi (vty), &as); + +  if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT) +    { +      vty_out (vty, "%% Peer with AS %d cannot be in this peer-group, members must be all internal or all external%s", as, VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_vty_return (vty, ret); +} + +DEFUN (no_neighbor_set_peer_group, +       no_neighbor_set_peer_group_cmd, +       NO_NEIGHBOR_CMD "peer-group WORD", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Member of the peer-group\n" +       "peer-group name\n") +{ +  int ret; +  struct bgp *bgp; +  struct peer *peer; +  struct peer_group *group; + +  bgp = vty->index; + +  peer = peer_lookup_vty (vty, argv[0]); +  if (! peer) +    return CMD_WARNING; + +  group = peer_group_lookup (bgp, argv[1]); +  if (! group) +    { +      vty_out (vty, "%% Configure the peer-group first%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  ret = peer_group_unbind (bgp, peer, group, bgp_node_afi (vty), +			   bgp_node_safi (vty)); + +  return bgp_vty_return (vty, ret); +} + +int +peer_flag_modify_vty (struct vty *vty, char *ip_str, u_int16_t flag, int set) +{ +  int ret; +  struct peer *peer; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  if (set) +    ret = peer_flag_set (peer, flag); +  else +    ret = peer_flag_unset (peer, flag); + +  return bgp_vty_return (vty, ret); +} + +int +peer_flag_set_vty (struct vty *vty, char *ip_str, u_int16_t flag) +{ +  return peer_flag_modify_vty (vty, ip_str, flag, 1); +} + +int +peer_flag_unset_vty (struct vty *vty, char *ip_str, u_int16_t flag) +{ +  return peer_flag_modify_vty (vty, ip_str, flag, 0); +} + +/* neighbor passive. */ +DEFUN (neighbor_passive, +       neighbor_passive_cmd, +       NEIGHBOR_CMD2 "passive", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Don't send open messages to this neighbor\n") +{ +  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_PASSIVE); +} + +DEFUN (no_neighbor_passive, +       no_neighbor_passive_cmd, +       NO_NEIGHBOR_CMD2 "passive", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Don't send open messages to this neighbor\n") +{ +  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_PASSIVE); +} + +/* neighbor shutdown. */ +DEFUN (neighbor_shutdown, +       neighbor_shutdown_cmd, +       NEIGHBOR_CMD2 "shutdown", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Administratively shut down this neighbor\n") +{ +  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_SHUTDOWN); +} + +DEFUN (no_neighbor_shutdown, +       no_neighbor_shutdown_cmd, +       NO_NEIGHBOR_CMD2 "shutdown", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Administratively shut down this neighbor\n") +{ +  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_SHUTDOWN); +} + +/* neighbor capability route-refresh. */ +DEFUN (neighbor_capability_route_refresh, +       neighbor_capability_route_refresh_cmd, +       NEIGHBOR_CMD2 "capability route-refresh", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Advertise capability to the peer\n" +       "Advertise route-refresh capability to this neighbor\n") +{ +  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_NO_ROUTE_REFRESH_CAP); +} + +DEFUN (no_neighbor_capability_route_refresh, +       no_neighbor_capability_route_refresh_cmd, +       NO_NEIGHBOR_CMD2 "capability route-refresh", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Advertise capability to the peer\n" +       "Advertise route-refresh capability to this neighbor\n") +{ +  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_NO_ROUTE_REFRESH_CAP); +} + +/* neighbor capability dynamic. */ +DEFUN (neighbor_capability_dynamic, +       neighbor_capability_dynamic_cmd, +       NEIGHBOR_CMD2 "capability dynamic", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Advertise capability to the peer\n" +       "Advertise dynamic capability to this neighbor\n") +{ +  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_DYNAMIC_CAPABILITY); +} + +DEFUN (no_neighbor_capability_dynamic, +       no_neighbor_capability_dynamic_cmd, +       NO_NEIGHBOR_CMD2 "capability dynamic", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Advertise capability to the peer\n" +       "Advertise dynamic capability to this neighbor\n") +{ +  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DYNAMIC_CAPABILITY); +} + +/* neighbor dont-capability-negotiate */ +DEFUN (neighbor_dont_capability_negotiate, +       neighbor_dont_capability_negotiate_cmd, +       NEIGHBOR_CMD2 "dont-capability-negotiate", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Do not perform capability negotiation\n") +{ +  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY); +} + +DEFUN (no_neighbor_dont_capability_negotiate, +       no_neighbor_dont_capability_negotiate_cmd, +       NO_NEIGHBOR_CMD2 "dont-capability-negotiate", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Do not perform capability negotiation\n") +{ +  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY); +} + +int +peer_af_flag_modify_vty (struct vty *vty, char *peer_str, afi_t afi, +			 safi_t safi, u_int16_t flag, int set) +{ +  int ret; +  struct peer *peer; + +  peer = peer_and_group_lookup_vty (vty, peer_str); +  if (! peer) +    return CMD_WARNING; + +  if (set) +    ret = peer_af_flag_set (peer, afi, safi, flag); +  else +    ret = peer_af_flag_unset (peer, afi, safi, flag); + +  return bgp_vty_return (vty, ret); +} + +int +peer_af_flag_set_vty (struct vty *vty, char *peer_str, afi_t afi, +		      safi_t safi, u_int16_t flag) +{ +  return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 1); +} + +int +peer_af_flag_unset_vty (struct vty *vty, char *peer_str, afi_t afi, +			safi_t safi, u_int16_t flag) +{ +  return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 0); +} + +/* neighbor capability orf prefix-list. */ +DEFUN (neighbor_capability_orf_prefix, +       neighbor_capability_orf_prefix_cmd, +       NEIGHBOR_CMD2 "capability orf prefix-list (both|send|receive)", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Advertise capability to the peer\n" +       "Advertise ORF capability to the peer\n" +       "Advertise prefixlist ORF capability to this neighbor\n" +       "Capability to SEND and RECEIVE the ORF to/from this neighbor\n" +       "Capability to RECEIVE the ORF from this neighbor\n" +       "Capability to SEND the ORF to this neighbor\n") +{ +  u_int16_t flag = 0; + +  if (strncmp (argv[1], "s", 1) == 0) +    flag = PEER_FLAG_ORF_PREFIX_SM; +  else if (strncmp (argv[1], "r", 1) == 0) +    flag = PEER_FLAG_ORF_PREFIX_RM; +  else if (strncmp (argv[1], "b", 1) == 0) +    flag = PEER_FLAG_ORF_PREFIX_SM|PEER_FLAG_ORF_PREFIX_RM; +  else +    return CMD_WARNING; + +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), flag); +} + +DEFUN (no_neighbor_capability_orf_prefix, +       no_neighbor_capability_orf_prefix_cmd, +       NO_NEIGHBOR_CMD2 "capability orf prefix-list (both|send|receive)", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Advertise capability to the peer\n" +       "Advertise ORF capability to the peer\n" +       "Advertise prefixlist ORF capability to this neighbor\n" +       "Capability to SEND and RECEIVE the ORF to/from this neighbor\n" +       "Capability to RECEIVE the ORF from this neighbor\n" +       "Capability to SEND the ORF to this neighbor\n") +{ +  u_int16_t flag = 0; + +  if (strncmp (argv[1], "s", 1) == 0) +    flag = PEER_FLAG_ORF_PREFIX_SM; +  else if (strncmp (argv[1], "r", 1) == 0) +    flag = PEER_FLAG_ORF_PREFIX_RM; +  else if (strncmp (argv[1], "b", 1) == 0) +    flag = PEER_FLAG_ORF_PREFIX_SM|PEER_FLAG_ORF_PREFIX_RM; +  else +    return CMD_WARNING; + +  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), flag); +} + +/* neighbor next-hop-self. */ +DEFUN (neighbor_nexthop_self, +       neighbor_nexthop_self_cmd, +       NEIGHBOR_CMD2 "next-hop-self", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Disable the next hop calculation for this neighbor\n") +{ +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF); +} + +DEFUN (no_neighbor_nexthop_self, +       no_neighbor_nexthop_self_cmd, +       NO_NEIGHBOR_CMD2 "next-hop-self", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Disable the next hop calculation for this neighbor\n") +{ +  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF); +} + +/* neighbor remove-private-AS. */ +DEFUN (neighbor_remove_private_as, +       neighbor_remove_private_as_cmd, +       NEIGHBOR_CMD2 "remove-private-AS", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Remove private AS number from outbound updates\n") +{ +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), +			       PEER_FLAG_REMOVE_PRIVATE_AS); +} + +DEFUN (no_neighbor_remove_private_as, +       no_neighbor_remove_private_as_cmd, +       NO_NEIGHBOR_CMD2 "remove-private-AS", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Remove private AS number from outbound updates\n") +{ +  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), +				 PEER_FLAG_REMOVE_PRIVATE_AS); +} + +/* neighbor send-community. */ +DEFUN (neighbor_send_community, +       neighbor_send_community_cmd, +       NEIGHBOR_CMD2 "send-community", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Send Community attribute to this neighbor\n") +{ +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), +			       PEER_FLAG_SEND_COMMUNITY); +} + +DEFUN (no_neighbor_send_community, +       no_neighbor_send_community_cmd, +       NO_NEIGHBOR_CMD2 "send-community", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Send Community attribute to this neighbor\n") +{ +  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), +				 PEER_FLAG_SEND_COMMUNITY); +} + +/* neighbor send-community extended. */ +DEFUN (neighbor_send_community_type, +       neighbor_send_community_type_cmd, +       NEIGHBOR_CMD2 "send-community (both|extended|standard)", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Send Community attribute to this neighbor\n" +       "Send Standard and Extended Community attributes\n" +       "Send Extended Community attributes\n" +       "Send Standard Community attributes\n") +{ +  if (strncmp (argv[1], "s", 1) == 0) +    return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), +				 PEER_FLAG_SEND_COMMUNITY); +  if (strncmp (argv[1], "e", 1) == 0) +    return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), +				 PEER_FLAG_SEND_EXT_COMMUNITY); + +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), +			       (PEER_FLAG_SEND_COMMUNITY| +				PEER_FLAG_SEND_EXT_COMMUNITY)); +} + +DEFUN (no_neighbor_send_community_type, +       no_neighbor_send_community_type_cmd, +       NO_NEIGHBOR_CMD2 "send-community (both|extended|standard)", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Send Community attribute to this neighbor\n" +       "Send Standard and Extended Community attributes\n" +       "Send Extended Community attributes\n" +       "Send Standard Community attributes\n") +{ +  if (strncmp (argv[1], "s", 1) == 0) +    return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +				   bgp_node_safi (vty), +				   PEER_FLAG_SEND_COMMUNITY); +  if (strncmp (argv[1], "e", 1) == 0) +    return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +				   bgp_node_safi (vty), +				   PEER_FLAG_SEND_EXT_COMMUNITY); + +  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), +				 (PEER_FLAG_SEND_COMMUNITY | +				  PEER_FLAG_SEND_EXT_COMMUNITY)); +} + +/* neighbor soft-reconfig. */ +DEFUN (neighbor_soft_reconfiguration, +       neighbor_soft_reconfiguration_cmd, +       NEIGHBOR_CMD2 "soft-reconfiguration inbound", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Per neighbor soft reconfiguration\n" +       "Allow inbound soft reconfiguration for this neighbor\n") +{ +  return peer_af_flag_set_vty (vty, argv[0], +			       bgp_node_afi (vty), bgp_node_safi (vty), +			       PEER_FLAG_SOFT_RECONFIG); +} + +DEFUN (no_neighbor_soft_reconfiguration, +       no_neighbor_soft_reconfiguration_cmd, +       NO_NEIGHBOR_CMD2 "soft-reconfiguration inbound", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Per neighbor soft reconfiguration\n" +       "Allow inbound soft reconfiguration for this neighbor\n") +{ +  return peer_af_flag_unset_vty (vty, argv[0], +				 bgp_node_afi (vty), bgp_node_safi (vty), +				 PEER_FLAG_SOFT_RECONFIG); +} + +DEFUN (neighbor_route_reflector_client, +       neighbor_route_reflector_client_cmd, +       NEIGHBOR_CMD2 "route-reflector-client", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Configure a neighbor as Route Reflector client\n") +{ +  struct peer *peer; + + +  peer = peer_and_group_lookup_vty (vty, argv[0]); +  if (! peer) +    return CMD_WARNING; + +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), +			       PEER_FLAG_REFLECTOR_CLIENT); +} + +DEFUN (no_neighbor_route_reflector_client, +       no_neighbor_route_reflector_client_cmd, +       NO_NEIGHBOR_CMD2 "route-reflector-client", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Configure a neighbor as Route Reflector client\n") +{ +  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), +				 PEER_FLAG_REFLECTOR_CLIENT); +} + +/* neighbor route-server-client. */ +DEFUN (neighbor_route_server_client, +       neighbor_route_server_client_cmd, +       NEIGHBOR_CMD2 "route-server-client", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Configure a neighbor as Route Server client\n") +{ +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), +			       PEER_FLAG_RSERVER_CLIENT); +} + +DEFUN (no_neighbor_route_server_client, +       no_neighbor_route_server_client_cmd, +       NO_NEIGHBOR_CMD2 "route-server-client", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Configure a neighbor as Route Server client\n") +{ +  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), +				 PEER_FLAG_RSERVER_CLIENT); +} + +DEFUN (neighbor_attr_unchanged, +       neighbor_attr_unchanged_cmd, +       NEIGHBOR_CMD2 "attribute-unchanged", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n") +{ +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), +			       (PEER_FLAG_AS_PATH_UNCHANGED | +				PEER_FLAG_NEXTHOP_UNCHANGED | +				PEER_FLAG_MED_UNCHANGED)); +} + +DEFUN (neighbor_attr_unchanged1, +       neighbor_attr_unchanged1_cmd, +       NEIGHBOR_CMD2 "attribute-unchanged (as-path|next-hop|med)", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "As-path attribute\n" +       "Nexthop attribute\n" +       "Med attribute\n") +{ +  u_int16_t flags = 0; + +  if (strncmp (argv[1], "as-path", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); +  else if (strncmp (argv[1], "next-hop", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); +  else if (strncmp (argv[1], "med", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), flags); +} + +DEFUN (neighbor_attr_unchanged2, +       neighbor_attr_unchanged2_cmd, +       NEIGHBOR_CMD2 "attribute-unchanged as-path (next-hop|med)", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "As-path attribute\n" +       "Nexthop attribute\n" +       "Med attribute\n") +{ +  u_int16_t flags = PEER_FLAG_AS_PATH_UNCHANGED; + +  if (strncmp (argv[1], "next-hop", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); +  else if (strncmp (argv[1], "med", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), flags); + +} + +DEFUN (neighbor_attr_unchanged3, +       neighbor_attr_unchanged3_cmd, +       NEIGHBOR_CMD2 "attribute-unchanged next-hop (as-path|med)", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "Nexthop attribute\n" +       "As-path attribute\n" +       "Med attribute\n") +{ +  u_int16_t flags = PEER_FLAG_NEXTHOP_UNCHANGED; + +  if (strncmp (argv[1], "as-path", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); +  else if (strncmp (argv[1], "med", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), flags); +} + +DEFUN (neighbor_attr_unchanged4, +       neighbor_attr_unchanged4_cmd, +       NEIGHBOR_CMD2 "attribute-unchanged med (as-path|next-hop)", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "Med attribute\n" +       "As-path attribute\n" +       "Nexthop attribute\n") +{ +  u_int16_t flags = PEER_FLAG_MED_UNCHANGED; + +  if (strncmp (argv[1], "as-path", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); +  else if (strncmp (argv[1], "next-hop", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), flags); +} + +ALIAS (neighbor_attr_unchanged, +       neighbor_attr_unchanged5_cmd, +       NEIGHBOR_CMD2 "attribute-unchanged as-path next-hop med", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "As-path attribute\n" +       "Nexthop attribute\n" +       "Med attribute\n") + +ALIAS (neighbor_attr_unchanged, +       neighbor_attr_unchanged6_cmd, +       NEIGHBOR_CMD2 "attribute-unchanged as-path med next-hop", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "As-path attribute\n" +       "Med attribute\n" +       "Nexthop attribute\n") + +ALIAS (neighbor_attr_unchanged, +       neighbor_attr_unchanged7_cmd, +       NEIGHBOR_CMD2 "attribute-unchanged next-hop med as-path", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "Nexthop attribute\n" +       "Med attribute\n" +       "As-path attribute\n") + +ALIAS (neighbor_attr_unchanged, +       neighbor_attr_unchanged8_cmd, +       NEIGHBOR_CMD2 "attribute-unchanged next-hop as-path med", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "Nexthop attribute\n" +       "As-path attribute\n" +       "Med attribute\n") + +ALIAS (neighbor_attr_unchanged, +       neighbor_attr_unchanged9_cmd, +       NEIGHBOR_CMD2 "attribute-unchanged med next-hop as-path", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "Med attribute\n" +       "Nexthop attribute\n" +       "As-path attribute\n") + +ALIAS (neighbor_attr_unchanged, +       neighbor_attr_unchanged10_cmd, +       NEIGHBOR_CMD2 "attribute-unchanged med as-path next-hop", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "Med attribute\n" +       "As-path attribute\n" +       "Nexthop attribute\n") + +DEFUN (no_neighbor_attr_unchanged, +       no_neighbor_attr_unchanged_cmd, +       NO_NEIGHBOR_CMD2 "attribute-unchanged", +       NO_STR	  +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n") +{ +  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), +				 (PEER_FLAG_AS_PATH_UNCHANGED | +				  PEER_FLAG_NEXTHOP_UNCHANGED | +				  PEER_FLAG_MED_UNCHANGED)); +} + +DEFUN (no_neighbor_attr_unchanged1, +       no_neighbor_attr_unchanged1_cmd, +       NO_NEIGHBOR_CMD2 "attribute-unchanged (as-path|next-hop|med)", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "As-path attribute\n" +       "Nexthop attribute\n" +       "Med attribute\n") +{ +  u_int16_t flags = 0; + +  if (strncmp (argv[1], "as-path", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); +  else if (strncmp (argv[1], "next-hop", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); +  else if (strncmp (argv[1], "med", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + +  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), flags); +} + +DEFUN (no_neighbor_attr_unchanged2, +       no_neighbor_attr_unchanged2_cmd, +       NO_NEIGHBOR_CMD2 "attribute-unchanged as-path (next-hop|med)", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "As-path attribute\n" +       "Nexthop attribute\n" +       "Med attribute\n") +{ +  u_int16_t flags = PEER_FLAG_AS_PATH_UNCHANGED; + +  if (strncmp (argv[1], "next-hop", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); +  else if (strncmp (argv[1], "med", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + +  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), flags); +} + +DEFUN (no_neighbor_attr_unchanged3, +       no_neighbor_attr_unchanged3_cmd, +       NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop (as-path|med)", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "Nexthop attribute\n" +       "As-path attribute\n" +       "Med attribute\n") +{ +  u_int16_t flags = PEER_FLAG_NEXTHOP_UNCHANGED; + +  if (strncmp (argv[1], "as-path", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); +  else if (strncmp (argv[1], "med", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); + +  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), flags); +} + +DEFUN (no_neighbor_attr_unchanged4, +       no_neighbor_attr_unchanged4_cmd, +       NO_NEIGHBOR_CMD2 "attribute-unchanged med (as-path|next-hop)", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "Med attribute\n" +       "As-path attribute\n" +       "Nexthop attribute\n") +{ +  u_int16_t flags = PEER_FLAG_MED_UNCHANGED; + +  if (strncmp (argv[1], "as-path", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); +  else if (strncmp (argv[1], "next-hop", 1) == 0) +    SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); + +  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), flags); +} + +ALIAS (no_neighbor_attr_unchanged, +       no_neighbor_attr_unchanged5_cmd, +       NO_NEIGHBOR_CMD2 "attribute-unchanged as-path next-hop med", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "As-path attribute\n" +       "Nexthop attribute\n" +       "Med attribute\n") + +ALIAS (no_neighbor_attr_unchanged, +       no_neighbor_attr_unchanged6_cmd, +       NO_NEIGHBOR_CMD2 "attribute-unchanged as-path med next-hop", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "As-path attribute\n" +       "Med attribute\n" +       "Nexthop attribute\n") + +ALIAS (no_neighbor_attr_unchanged, +       no_neighbor_attr_unchanged7_cmd, +       NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop med as-path", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "Nexthop attribute\n" +       "Med attribute\n" +       "As-path attribute\n") + +ALIAS (no_neighbor_attr_unchanged, +       no_neighbor_attr_unchanged8_cmd, +       NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop as-path med", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "Nexthop attribute\n" +       "As-path attribute\n" +       "Med attribute\n") + +ALIAS (no_neighbor_attr_unchanged, +       no_neighbor_attr_unchanged9_cmd, +       NO_NEIGHBOR_CMD2 "attribute-unchanged med next-hop as-path", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "Med attribute\n" +       "Nexthop attribute\n" +       "As-path attribute\n") + +ALIAS (no_neighbor_attr_unchanged, +       no_neighbor_attr_unchanged10_cmd, +       NO_NEIGHBOR_CMD2 "attribute-unchanged med as-path next-hop", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP attribute is propagated unchanged to this neighbor\n" +       "Med attribute\n" +       "As-path attribute\n" +       "Nexthop attribute\n") + +/* For old version Zebra compatibility.  */ +DEFUN (neighbor_transparent_as, +       neighbor_transparent_as_cmd, +       NEIGHBOR_CMD "transparent-as", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Do not append my AS number even peer is EBGP peer\n") +{ +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), +			       PEER_FLAG_AS_PATH_UNCHANGED); +} + +DEFUN (neighbor_transparent_nexthop, +       neighbor_transparent_nexthop_cmd, +       NEIGHBOR_CMD "transparent-nexthop", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Do not change nexthop even peer is EBGP peer\n") +{ +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +			       bgp_node_safi (vty), +			       PEER_FLAG_NEXTHOP_UNCHANGED); +} + +/* EBGP multihop configuration. */ +int +peer_ebgp_multihop_set_vty (struct vty *vty, char *ip_str, char *ttl_str) +{ +  struct peer *peer; +  int ttl; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  if (! ttl_str) +    ttl = TTL_MAX; +  else +    VTY_GET_INTEGER_RANGE ("TTL", ttl, ttl_str, 1, 255); + +  peer_ebgp_multihop_set (peer, ttl); + +  return CMD_SUCCESS; +} + +int +peer_ebgp_multihop_unset_vty (struct vty *vty, char *ip_str)  +{ +  struct peer *peer; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  peer_ebgp_multihop_unset (peer); + +  return CMD_SUCCESS; +} + +/* neighbor ebgp-multihop. */ +DEFUN (neighbor_ebgp_multihop, +       neighbor_ebgp_multihop_cmd, +       NEIGHBOR_CMD2 "ebgp-multihop", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Allow EBGP neighbors not on directly connected networks\n") +{ +  return peer_ebgp_multihop_set_vty (vty, argv[0], NULL); +} + +DEFUN (neighbor_ebgp_multihop_ttl, +       neighbor_ebgp_multihop_ttl_cmd, +       NEIGHBOR_CMD2 "ebgp-multihop <1-255>", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Allow EBGP neighbors not on directly connected networks\n" +       "maximum hop count\n") +{ +  return peer_ebgp_multihop_set_vty (vty, argv[0], argv[1]); +} + +DEFUN (no_neighbor_ebgp_multihop, +       no_neighbor_ebgp_multihop_cmd, +       NO_NEIGHBOR_CMD2 "ebgp-multihop", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Allow EBGP neighbors not on directly connected networks\n") +{ +  return peer_ebgp_multihop_unset_vty (vty, argv[0]); +} + +ALIAS (no_neighbor_ebgp_multihop, +       no_neighbor_ebgp_multihop_ttl_cmd, +       NO_NEIGHBOR_CMD2 "ebgp-multihop <1-255>", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Allow EBGP neighbors not on directly connected networks\n" +       "maximum hop count\n") + +/* Enforce multihop.  */ +DEFUN (neighbor_enforce_multihop, +       neighbor_enforce_multihop_cmd, +       NEIGHBOR_CMD2 "enforce-multihop", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Enforce EBGP neighbors perform multihop\n") +{ +  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_ENFORCE_MULTIHOP); +} + +DEFUN (no_neighbor_enforce_multihop, +       no_neighbor_enforce_multihop_cmd, +       NO_NEIGHBOR_CMD2 "enforce-multihop", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Enforce EBGP neighbors perform multihop\n") +{ +  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_ENFORCE_MULTIHOP); +} + +DEFUN (neighbor_description, +       neighbor_description_cmd, +       NEIGHBOR_CMD2 "description .LINE", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Neighbor specific description\n" +       "Up to 80 characters describing this neighbor\n") +{ +  struct peer *peer; +  struct buffer *b; +  char *str; +  int i; + +  peer = peer_and_group_lookup_vty (vty, argv[0]); +  if (! peer) +    return CMD_WARNING; + +  if (argc == 1) +    return CMD_SUCCESS; + +  /* Make string from buffer.  This function should be provided by +     buffer.c. */ +  b = buffer_new (1024); +  for (i = 1; i < argc; i++) +    { +      buffer_putstr (b, (u_char *)argv[i]); +      buffer_putc (b, ' '); +    } +  buffer_putc (b, '\0'); +  str = buffer_getstr (b); +  buffer_free (b); + +  peer_description_set (peer, str); + +  free (str); + +  return CMD_SUCCESS; +} + +DEFUN (no_neighbor_description, +       no_neighbor_description_cmd, +       NO_NEIGHBOR_CMD2 "description", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Neighbor specific description\n") +{ +  struct peer *peer; + +  peer = peer_and_group_lookup_vty (vty, argv[0]); +  if (! peer) +    return CMD_WARNING; + +  peer_description_unset (peer); + +  return CMD_SUCCESS; +} + +ALIAS (no_neighbor_description, +       no_neighbor_description_val_cmd, +       NO_NEIGHBOR_CMD2 "description .LINE", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Neighbor specific description\n" +       "Up to 80 characters describing this neighbor\n") + +/* Neighbor update-source. */ +int +peer_update_source_vty (struct vty *vty, char *peer_str, char *source_str) +{ +  struct peer *peer; +  union sockunion *su; + +  peer = peer_and_group_lookup_vty (vty, peer_str); +  if (! peer) +    return CMD_WARNING; + +  if (source_str) +    { +      su = sockunion_str2su (source_str); +      if (su) +	{ +	  peer_update_source_addr_set (peer, su); +	  sockunion_free (su); +	} +      else +	peer_update_source_if_set (peer, source_str); +    } +  else +    peer_update_source_unset (peer); + +  return CMD_SUCCESS; +} + +DEFUN (neighbor_update_source, +       neighbor_update_source_cmd, +       NEIGHBOR_CMD2 "update-source WORD", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Source of routing updates\n" +       "Interface name\n") +{ +  return peer_update_source_vty (vty, argv[0], argv[1]); +} + +DEFUN (no_neighbor_update_source, +       no_neighbor_update_source_cmd, +       NO_NEIGHBOR_CMD2 "update-source", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Source of routing updates\n" +       "Interface name\n") +{ +  return peer_update_source_vty (vty, argv[0], NULL); +} + +int +peer_default_originate_set_vty (struct vty *vty, char *peer_str, afi_t afi, +				safi_t safi, char *rmap, int set) +{ +  int ret; +  struct peer *peer; + +  peer = peer_and_group_lookup_vty (vty, peer_str); +  if (! peer) +    return CMD_WARNING; + +  if (set) +    ret = peer_default_originate_set (peer, afi, safi, rmap); +  else +    ret = peer_default_originate_unset (peer, afi, safi); + +  return bgp_vty_return (vty, ret); +} + +/* neighbor default-originate. */ +DEFUN (neighbor_default_originate, +       neighbor_default_originate_cmd, +       NEIGHBOR_CMD2 "default-originate", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Originate default route to this neighbor\n") +{ +  return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty), +					 bgp_node_safi (vty), NULL, 1); +} + +DEFUN (neighbor_default_originate_rmap, +       neighbor_default_originate_rmap_cmd, +       NEIGHBOR_CMD2 "default-originate route-map WORD", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Originate default route to this neighbor\n" +       "Route-map to specify criteria to originate default\n" +       "route-map name\n") +{ +  return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty), +					 bgp_node_safi (vty), argv[1], 1); +} + +DEFUN (no_neighbor_default_originate, +       no_neighbor_default_originate_cmd, +       NO_NEIGHBOR_CMD2 "default-originate", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Originate default route to this neighbor\n") +{ +  return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty), +					 bgp_node_safi (vty), NULL, 0); +} + +ALIAS (no_neighbor_default_originate, +       no_neighbor_default_originate_rmap_cmd, +       NO_NEIGHBOR_CMD2 "default-originate route-map WORD", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Originate default route to this neighbor\n" +       "Route-map to specify criteria to originate default\n" +       "route-map name\n") + +/* Set neighbor's BGP port.  */ +int +peer_port_vty (struct vty *vty, char *ip_str, int afi, char *port_str) +{ +  struct peer *peer; +  u_int16_t port; +  struct servent *sp; + +  peer = peer_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  if (! port_str) +    {  +      sp = getservbyname ("bgp", "tcp"); +      port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port); +    } +  else +    { +      VTY_GET_INTEGER("port", port, port_str); +    } + +  peer_port_set (peer, port); + +  return CMD_SUCCESS; +} + +/* Set specified peer's BGP version.  */ +DEFUN (neighbor_port, +       neighbor_port_cmd, +       NEIGHBOR_CMD "port <0-65535>", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Neighbor's BGP port\n" +       "TCP port number\n") +{ +  return peer_port_vty (vty, argv[0], AFI_IP, argv[1]); +} + +DEFUN (no_neighbor_port, +       no_neighbor_port_cmd, +       NO_NEIGHBOR_CMD "port", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Neighbor's BGP port\n") +{ +  return peer_port_vty (vty, argv[0], AFI_IP, NULL); +} + +ALIAS (no_neighbor_port, +       no_neighbor_port_val_cmd, +       NO_NEIGHBOR_CMD "port <0-65535>", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Neighbor's BGP port\n" +       "TCP port number\n") + +/* neighbor weight. */ +int +peer_weight_set_vty (struct vty *vty, char *ip_str, char *weight_str) +{ +  int ret; +  struct peer *peer; +  unsigned long weight; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  VTY_GET_INTEGER_RANGE("weight", weight, weight_str, 0, 65535); + +  ret = peer_weight_set (peer, weight); + +  return CMD_SUCCESS; +} + +int +peer_weight_unset_vty (struct vty *vty, char *ip_str) +{ +  struct peer *peer; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  peer_weight_unset (peer); + +  return CMD_SUCCESS; +} + +DEFUN (neighbor_weight, +       neighbor_weight_cmd, +       NEIGHBOR_CMD2 "weight <0-65535>", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Set default weight for routes from this neighbor\n" +       "default weight\n") +{ +  return peer_weight_set_vty (vty, argv[0], argv[1]); +} + +DEFUN (no_neighbor_weight, +       no_neighbor_weight_cmd, +       NO_NEIGHBOR_CMD2 "weight", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Set default weight for routes from this neighbor\n") +{ +  return peer_weight_unset_vty (vty, argv[0]); +} + +ALIAS (no_neighbor_weight, +       no_neighbor_weight_val_cmd, +       NO_NEIGHBOR_CMD2 "weight <0-65535>", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Set default weight for routes from this neighbor\n" +       "default weight\n") + +/* Override capability negotiation. */ +DEFUN (neighbor_override_capability, +       neighbor_override_capability_cmd, +       NEIGHBOR_CMD2 "override-capability", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Override capability negotiation result\n") +{ +  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_OVERRIDE_CAPABILITY); +} + +DEFUN (no_neighbor_override_capability, +       no_neighbor_override_capability_cmd, +       NO_NEIGHBOR_CMD2 "override-capability", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Override capability negotiation result\n") +{ +  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_OVERRIDE_CAPABILITY); +} + +DEFUN (neighbor_strict_capability, +       neighbor_strict_capability_cmd, +       NEIGHBOR_CMD "strict-capability-match", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Strict capability negotiation match\n") +{ +  return peer_flag_set_vty (vty, argv[0], PEER_FLAG_STRICT_CAP_MATCH); +} + +DEFUN (no_neighbor_strict_capability, +       no_neighbor_strict_capability_cmd, +       NO_NEIGHBOR_CMD "strict-capability-match", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Strict capability negotiation match\n") +{ +  return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_STRICT_CAP_MATCH); +} + +int +peer_timers_set_vty (struct vty *vty, char *ip_str, char *keep_str, +		     char *hold_str) +{ +  int ret; +  struct peer *peer; +  u_int32_t keepalive; +  u_int32_t holdtime; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  VTY_GET_INTEGER_RANGE ("Keepalive", keepalive, keep_str, 0, 65535); +  VTY_GET_INTEGER_RANGE ("Holdtime", holdtime, hold_str, 0, 65535); + +  ret = peer_timers_set (peer, keepalive, holdtime); + +  return bgp_vty_return (vty, ret); +} + +int +peer_timers_unset_vty (struct vty *vty, char *ip_str) +{ +  int ret; +  struct peer *peer; + +  peer = peer_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  ret = peer_timers_unset (peer); + +  return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_timers, +       neighbor_timers_cmd, +       NEIGHBOR_CMD2 "timers <0-65535> <0-65535>", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP per neighbor timers\n" +       "Keepalive interval\n" +       "Holdtime\n") +{ +  return peer_timers_set_vty (vty, argv[0], argv[1], argv[2]); +} + +DEFUN (no_neighbor_timers, +       no_neighbor_timers_cmd, +       NO_NEIGHBOR_CMD2 "timers", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "BGP per neighbor timers\n") +{ +  return peer_timers_unset_vty (vty, argv[0]); +} + +int +peer_timers_connect_set_vty (struct vty *vty, char *ip_str, char *time_str) +{ +  int ret; +  struct peer *peer; +  u_int32_t connect; + +  peer = peer_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  VTY_GET_INTEGER_RANGE ("Connect time", connect, time_str, 0, 65535); + +  ret = peer_timers_connect_set (peer, connect); + +  return CMD_SUCCESS; +} + +int +peer_timers_connect_unset_vty (struct vty *vty, char *ip_str) +{ +  int ret; +  struct peer *peer; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  ret = peer_timers_connect_unset (peer); + +  return CMD_SUCCESS; +} + +DEFUN (neighbor_timers_connect, +       neighbor_timers_connect_cmd, +       NEIGHBOR_CMD "timers connect <0-65535>", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "BGP per neighbor timers\n" +       "BGP connect timer\n" +       "Connect timer\n") +{ +  return peer_timers_connect_set_vty (vty, argv[0], argv[1]); +} + +DEFUN (no_neighbor_timers_connect, +       no_neighbor_timers_connect_cmd, +       NO_NEIGHBOR_CMD "timers connect", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "BGP per neighbor timers\n" +       "BGP connect timer\n") +{ +  return peer_timers_connect_unset_vty (vty, argv[0]); +} + +ALIAS (no_neighbor_timers_connect, +       no_neighbor_timers_connect_val_cmd, +       NO_NEIGHBOR_CMD "timers connect <0-65535>", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "BGP per neighbor timers\n" +       "BGP connect timer\n" +       "Connect timer\n") + +int +peer_advertise_interval_vty (struct vty *vty, char *ip_str, char *time_str, +			     int set)   +{ +  int ret; +  struct peer *peer; +  u_int32_t routeadv = 0; + +  peer = peer_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  if (time_str) +    VTY_GET_INTEGER_RANGE ("advertise interval", routeadv, time_str, 0, 600); + +  if (set) +    ret = peer_advertise_interval_set (peer, routeadv); +  else +    ret = peer_advertise_interval_unset (peer); + +  return CMD_SUCCESS; +} + +DEFUN (neighbor_advertise_interval, +       neighbor_advertise_interval_cmd, +       NEIGHBOR_CMD "advertisement-interval <0-600>", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Minimum interval between sending BGP routing updates\n" +       "time in seconds\n") +{ +  return peer_advertise_interval_vty (vty, argv[0], argv[1], 1); +} + +DEFUN (no_neighbor_advertise_interval, +       no_neighbor_advertise_interval_cmd, +       NO_NEIGHBOR_CMD "advertisement-interval", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Minimum interval between sending BGP routing updates\n") +{ +  return peer_advertise_interval_vty (vty, argv[0], NULL, 0); +} + +ALIAS (no_neighbor_advertise_interval, +       no_neighbor_advertise_interval_val_cmd, +       NO_NEIGHBOR_CMD "advertisement-interval <0-600>", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Minimum interval between sending BGP routing updates\n" +       "time in seconds\n") + +int +peer_version_vty (struct vty *vty, char *ip_str, char *str) +{ +  int ret; +  struct peer *peer; +  int version = BGP_VERSION_4; + +  peer = peer_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  /* BGP version string check. */ +  if (str) +    { +      if (strcmp (str, "4") == 0) +	version = BGP_VERSION_4; +      else if (strcmp (str, "4-") == 0) +	version = BGP_VERSION_MP_4_DRAFT_00; + +      ret = peer_version_set (peer, version); +    } +  else +    ret = peer_version_unset (peer); + +  return CMD_SUCCESS; +} + +DEFUN (neighbor_version, +       neighbor_version_cmd, +       NEIGHBOR_CMD "version (4|4-)", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Neighbor's BGP version\n" +       "Border Gateway Protocol 4\n" +       "Multiprotocol Extensions for BGP-4(Old Draft)\n") +{ +  return peer_version_vty (vty, argv[0], argv[1]); +} + +DEFUN (no_neighbor_version, +       no_neighbor_version_cmd, +       NO_NEIGHBOR_CMD "version", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Neighbor's BGP version\n") +{ +  return peer_version_vty (vty, argv[0], NULL); +} + +/* neighbor interface */ +int +peer_interface_vty (struct vty *vty, char *ip_str, char *str) +{ +  int ret; +  struct peer *peer; + +  peer = peer_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  if (str) +    ret = peer_interface_set (peer, str); +  else +    ret = peer_interface_unset (peer); + +  return CMD_SUCCESS; +} + +DEFUN (neighbor_interface, +       neighbor_interface_cmd, +       NEIGHBOR_CMD "interface WORD", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Interface\n" +       "Interface name\n") +{ +  return peer_interface_vty (vty, argv[0], argv[1]); +} + +DEFUN (no_neighbor_interface, +       no_neighbor_interface_cmd, +       NO_NEIGHBOR_CMD "interface WORD", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR +       "Interface\n" +       "Interface name\n") +{ +  return peer_interface_vty (vty, argv[0], NULL); +} + +/* Set distribute list to the peer. */ +int +peer_distribute_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, +			 char *name_str, char *direct_str) +{ +  int ret; +  struct peer *peer; +  int direct = FILTER_IN; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  /* Check filter direction. */ +  if (strncmp (direct_str, "i", 1) == 0) +    direct = FILTER_IN; +  else if (strncmp (direct_str, "o", 1) == 0) +    direct = FILTER_OUT; + +  ret = peer_distribute_set (peer, afi, safi, direct, name_str); + +  return bgp_vty_return (vty, ret); +} + +int +peer_distribute_unset_vty (struct vty *vty, char *ip_str, afi_t afi, +			   safi_t safi, char *direct_str) +{ +  int ret; +  struct peer *peer; +  int direct = FILTER_IN; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  /* Check filter direction. */ +  if (strncmp (direct_str, "i", 1) == 0) +    direct = FILTER_IN; +  else if (strncmp (direct_str, "o", 1) == 0) +    direct = FILTER_OUT; + +  ret = peer_distribute_unset (peer, afi, safi, direct); + +  return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_distribute_list, +       neighbor_distribute_list_cmd, +       NEIGHBOR_CMD2 "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Filter updates to/from this neighbor\n" +       "IP access-list number\n" +       "IP access-list number (expanded range)\n" +       "IP Access-list name\n" +       "Filter incoming updates\n" +       "Filter outgoing updates\n") +{ +  return peer_distribute_set_vty (vty, argv[0], bgp_node_afi (vty), +				  bgp_node_safi (vty), argv[1], argv[2]); +} + +DEFUN (no_neighbor_distribute_list, +       no_neighbor_distribute_list_cmd, +       NO_NEIGHBOR_CMD2 "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Filter updates to/from this neighbor\n" +       "IP access-list number\n" +       "IP access-list number (expanded range)\n" +       "IP Access-list name\n" +       "Filter incoming updates\n" +       "Filter outgoing updates\n") +{ +  return peer_distribute_unset_vty (vty, argv[0], bgp_node_afi (vty), +				    bgp_node_safi (vty), argv[2]); +} + +/* Set prefix list to the peer. */ +int +peer_prefix_list_set_vty (struct vty *vty, char *ip_str, afi_t afi, +			  safi_t safi, char *name_str, char *direct_str) +{ +  int ret; +  struct peer *peer; +  int direct = FILTER_IN; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  /* Check filter direction. */ +  if (strncmp (direct_str, "i", 1) == 0) +    direct = FILTER_IN; +  else if (strncmp (direct_str, "o", 1) == 0) +    direct = FILTER_OUT; + +  ret = peer_prefix_list_set (peer, afi, safi, direct, name_str); + +  return bgp_vty_return (vty, ret); +} + +int +peer_prefix_list_unset_vty (struct vty *vty, char *ip_str, afi_t afi, +			    safi_t safi, char *direct_str) +{ +  int ret; +  struct peer *peer; +  int direct = FILTER_IN; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; +   +  /* Check filter direction. */ +  if (strncmp (direct_str, "i", 1) == 0) +    direct = FILTER_IN; +  else if (strncmp (direct_str, "o", 1) == 0) +    direct = FILTER_OUT; + +  ret = peer_prefix_list_unset (peer, afi, safi, direct); + +  return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_prefix_list, +       neighbor_prefix_list_cmd, +       NEIGHBOR_CMD2 "prefix-list WORD (in|out)", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Filter updates to/from this neighbor\n" +       "Name of a prefix list\n" +       "Filter incoming updates\n" +       "Filter outgoing updates\n") +{ +  return peer_prefix_list_set_vty (vty, argv[0], bgp_node_afi (vty), +				   bgp_node_safi (vty), argv[1], argv[2]); +} + +DEFUN (no_neighbor_prefix_list, +       no_neighbor_prefix_list_cmd, +       NO_NEIGHBOR_CMD2 "prefix-list WORD (in|out)", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Filter updates to/from this neighbor\n" +       "Name of a prefix list\n" +       "Filter incoming updates\n" +       "Filter outgoing updates\n") +{ +  return peer_prefix_list_unset_vty (vty, argv[0], bgp_node_afi (vty), +				     bgp_node_safi (vty), argv[2]); +} + +int +peer_aslist_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, +		     char *name_str, char *direct_str) +{ +  int ret; +  struct peer *peer; +  int direct = FILTER_IN; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  /* Check filter direction. */ +  if (strncmp (direct_str, "i", 1) == 0) +    direct = FILTER_IN; +  else if (strncmp (direct_str, "o", 1) == 0) +    direct = FILTER_OUT; + +  ret = peer_aslist_set (peer, afi, safi, direct, name_str); + +  return bgp_vty_return (vty, ret); +} + +int +peer_aslist_unset_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, +		       char *direct_str) +{ +  int ret; +  struct peer *peer; +  int direct = FILTER_IN; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  /* Check filter direction. */ +  if (strncmp (direct_str, "i", 1) == 0) +    direct = FILTER_IN; +  else if (strncmp (direct_str, "o", 1) == 0) +    direct = FILTER_OUT; + +  ret = peer_aslist_unset (peer, afi, safi, direct); + +  return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_filter_list, +       neighbor_filter_list_cmd, +       NEIGHBOR_CMD2 "filter-list WORD (in|out)", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Establish BGP filters\n" +       "AS path access-list name\n" +       "Filter incoming routes\n" +       "Filter outgoing routes\n") +{ +  return peer_aslist_set_vty (vty, argv[0], bgp_node_afi (vty), +			      bgp_node_safi (vty), argv[1], argv[2]); +} + +DEFUN (no_neighbor_filter_list, +       no_neighbor_filter_list_cmd, +       NO_NEIGHBOR_CMD2 "filter-list WORD (in|out)", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Establish BGP filters\n" +       "AS path access-list name\n" +       "Filter incoming routes\n" +       "Filter outgoing routes\n") +{ +  return peer_aslist_unset_vty (vty, argv[0], bgp_node_afi (vty), +				bgp_node_safi (vty), argv[2]); +} + +/* Set route-map to the peer. */ +int +peer_route_map_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, +			char *name_str, char *direct_str) +{ +  int ret; +  struct peer *peer; +  int direct = FILTER_IN; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  /* Check filter direction. */ +  if (strncmp (direct_str, "i", 1) == 0) +    direct = FILTER_IN; +  else if (strncmp (direct_str, "o", 1) == 0) +    direct = FILTER_OUT; + +  ret = peer_route_map_set (peer, afi, safi, direct, name_str); + +  return bgp_vty_return (vty, ret); +} + +int +peer_route_map_unset_vty (struct vty *vty, char *ip_str, afi_t afi, +			  safi_t safi, char *direct_str) +{ +  int ret; +  struct peer *peer; +  int direct = FILTER_IN; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  /* Check filter direction. */ +  if (strncmp (direct_str, "i", 1) == 0) +    direct = FILTER_IN; +  else if (strncmp (direct_str, "o", 1) == 0) + +    direct = FILTER_OUT; + +  ret = peer_route_map_unset (peer, afi, safi, direct); + +  return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_route_map, +       neighbor_route_map_cmd, +       NEIGHBOR_CMD2 "route-map WORD (in|out)", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Apply route map to neighbor\n" +       "Name of route map\n" +       "Apply map to incoming routes\n" +       "Apply map to outbound routes\n") +{ +  return peer_route_map_set_vty (vty, argv[0], bgp_node_afi (vty), +				 bgp_node_safi (vty), argv[1], argv[2]); +} + +DEFUN (no_neighbor_route_map, +       no_neighbor_route_map_cmd, +       NO_NEIGHBOR_CMD2 "route-map WORD (in|out)", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Apply route map to neighbor\n" +       "Name of route map\n" +       "Apply map to incoming routes\n" +       "Apply map to outbound routes\n") +{ +  return peer_route_map_unset_vty (vty, argv[0], bgp_node_afi (vty), +				   bgp_node_safi (vty), argv[2]); +} + +/* Set unsuppress-map to the peer. */ +int +peer_unsuppress_map_set_vty (struct vty *vty, char *ip_str, afi_t afi, +			     safi_t safi, char *name_str) +{ +  int ret; +  struct peer *peer; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  ret = peer_unsuppress_map_set (peer, afi, safi, name_str); + +  return bgp_vty_return (vty, ret); +} + +/* Unset route-map from the peer. */ +int +peer_unsuppress_map_unset_vty (struct vty *vty, char *ip_str, afi_t afi, +			       safi_t safi) +{ +  int ret; +  struct peer *peer; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  ret = peer_unsuppress_map_unset (peer, afi, safi); + +  return bgp_vty_return (vty, ret); +} + +DEFUN (neighbor_unsuppress_map, +       neighbor_unsuppress_map_cmd, +       NEIGHBOR_CMD2 "unsuppress-map WORD", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Route-map to selectively unsuppress suppressed routes\n" +       "Name of route map\n") +{ +  return peer_unsuppress_map_set_vty (vty, argv[0], bgp_node_afi (vty), +				      bgp_node_safi (vty), argv[1]); +} + +DEFUN (no_neighbor_unsuppress_map, +       no_neighbor_unsuppress_map_cmd, +       NO_NEIGHBOR_CMD2 "unsuppress-map WORD", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Route-map to selectively unsuppress suppressed routes\n" +       "Name of route map\n") +{ +  return peer_unsuppress_map_unset_vty (vty, argv[0], bgp_node_afi (vty), +					bgp_node_safi (vty)); +} + +int +peer_maximum_prefix_set_vty (struct vty *vty, char *ip_str, afi_t afi, +			     safi_t safi, char *num_str, int warning) +{ +  int ret; +  struct peer *peer; +  u_int32_t max; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  VTY_GET_INTEGER ("maxmum number", max, num_str); + +  ret = peer_maximum_prefix_set (peer, afi, safi, max, warning); + +  return bgp_vty_return (vty, ret); +} + +int +peer_maximum_prefix_unset_vty (struct vty *vty, char *ip_str, afi_t afi, +			       safi_t safi) +{ +  int ret; +  struct peer *peer; + +  peer = peer_and_group_lookup_vty (vty, ip_str); +  if (! peer) +    return CMD_WARNING; + +  ret = peer_maximum_prefix_unset (peer, afi, safi); + +  return bgp_vty_return (vty, ret); +} + +/* Maximum number of prefix configuration.  prefix count is different +   for each peer configuration.  So this configuration can be set for +   each peer configuration. */ +DEFUN (neighbor_maximum_prefix, +       neighbor_maximum_prefix_cmd, +       NEIGHBOR_CMD2 "maximum-prefix <1-4294967295>", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Maximum number of prefix accept from this peer\n" +       "maximum no. of prefix limit\n") +{ +  return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), +				      bgp_node_safi (vty), argv[1], 0); +} + +DEFUN (neighbor_maximum_prefix_warning, +       neighbor_maximum_prefix_warning_cmd, +       NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> warning-only", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Maximum number of prefix accept from this peer\n" +       "maximum no. of prefix limit\n" +       "Only give warning message when limit is exceeded\n") +{ +  return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), +				      bgp_node_safi (vty), argv[1], 1); +} + +DEFUN (no_neighbor_maximum_prefix, +       no_neighbor_maximum_prefix_cmd, +       NO_NEIGHBOR_CMD2 "maximum-prefix", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Maximum number of prefix accept from this peer\n") +{ +  return peer_maximum_prefix_unset_vty (vty, argv[0], bgp_node_afi (vty), +					bgp_node_safi (vty)); +} +  +ALIAS (no_neighbor_maximum_prefix, +       no_neighbor_maximum_prefix_val_cmd, +       NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295>", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Maximum number of prefix accept from this peer\n" +       "maximum no. of prefix limit\n") + +ALIAS (no_neighbor_maximum_prefix, +       no_neighbor_maximum_prefix_val2_cmd, +       NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> warning-only", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Maximum number of prefix accept from this peer\n" +       "maximum no. of prefix limit\n" +       "Only give warning message when limit is exceeded\n") + +/* "neighbor allowas-in" */ +DEFUN (neighbor_allowas_in, +       neighbor_allowas_in_cmd, +       NEIGHBOR_CMD2 "allowas-in", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Accept as-path with my AS present in it\n") +{ +  int ret; +  struct peer *peer; +  int allow_num; + +  peer = peer_and_group_lookup_vty (vty, argv[0]); +  if (! peer) +    return CMD_WARNING; + +  if (argc == 1) +    allow_num = 3; +  else +    VTY_GET_INTEGER_RANGE ("AS number", allow_num, argv[1], 1, 10); + +  ret = peer_allowas_in_set (peer, bgp_node_afi (vty), bgp_node_safi (vty), +			     allow_num); + +  return bgp_vty_return (vty, ret); +} + +ALIAS (neighbor_allowas_in, +       neighbor_allowas_in_arg_cmd, +       NEIGHBOR_CMD2 "allowas-in <1-10>", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Accept as-path with my AS present in it\n" +       "Number of occurances of AS number\n") + +DEFUN (no_neighbor_allowas_in, +       no_neighbor_allowas_in_cmd, +       NO_NEIGHBOR_CMD2 "allowas-in", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "allow local ASN appears in aspath attribute\n") +{ +  int ret; +  struct peer *peer; + +  peer = peer_and_group_lookup_vty (vty, argv[0]); +  if (! peer) +    return CMD_WARNING; + +  ret = peer_allowas_in_unset (peer, bgp_node_afi (vty), bgp_node_safi (vty)); + +  return bgp_vty_return (vty, ret); +} + +/* Address family configuration.  */ +DEFUN (address_family_ipv4, +       address_family_ipv4_cmd, +       "address-family ipv4", +       "Enter Address Family command mode\n" +       "Address family\n") +{ +  vty->node = BGP_IPV4_NODE; +  return CMD_SUCCESS; +} + +DEFUN (address_family_ipv4_safi, +       address_family_ipv4_safi_cmd, +       "address-family ipv4 (unicast|multicast)", +       "Enter Address Family command mode\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    vty->node = BGP_IPV4M_NODE; +  else +    vty->node = BGP_IPV4_NODE; + +  return CMD_SUCCESS; +} + +DEFUN (address_family_ipv6_unicast, +       address_family_ipv6_unicast_cmd, +       "address-family ipv6 unicast", +       "Enter Address Family command mode\n" +       "Address family\n" +       "unicast\n") +{ +  vty->node = BGP_IPV6_NODE; +  return CMD_SUCCESS; +} + +ALIAS (address_family_ipv6_unicast, +       address_family_ipv6_cmd, +       "address-family ipv6", +       "Enter Address Family command mode\n" +       "Address family\n") + +DEFUN (address_family_vpnv4, +       address_family_vpnv4_cmd, +       "address-family vpnv4", +       "Enter Address Family command mode\n" +       "Address family\n") +{ +  vty->node = BGP_VPNV4_NODE; +  return CMD_SUCCESS; +} + +ALIAS (address_family_vpnv4, +       address_family_vpnv4_unicast_cmd, +       "address-family vpnv4 unicast", +       "Enter Address Family command mode\n" +       "Address family\n" +       "Address Family Modifier\n") + +DEFUN (exit_address_family, +       exit_address_family_cmd, +       "exit-address-family", +       "Exit from Address Family configuration mode\n") +{ +  if (vty->node == BGP_IPV4M_NODE +      || vty->node == BGP_VPNV4_NODE +      || vty->node == BGP_IPV6_NODE) +    vty->node = BGP_NODE; +  return CMD_SUCCESS; +} + +/* BGP clear sort. */ +enum clear_sort +{ +  clear_all, +  clear_peer, +  clear_group, +  clear_external, +  clear_as +}; + +void +bgp_clear_vty_error (struct vty *vty, struct peer *peer, afi_t afi, +		     safi_t safi, int error) +{ +  switch (error) +    { +    case BGP_ERR_AF_UNCONFIGURED: +      vty_out (vty, +	       "%%BGP: Enable %s %s address family for the neighbor %s%s", +	       afi == AFI_IP6 ? "IPv6" : safi == SAFI_MPLS_VPN ? "VPNv4" : "IPv4", +	       safi == SAFI_MULTICAST ? "Multicast" : "Unicast", +	       peer->host, VTY_NEWLINE); +      break; +    case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED: +      vty_out (vty, "%%BGP: Inbound soft reconfig for %s not possible as it%s      has neither refresh capability, nor inbound soft reconfig%s", peer->host, VTY_NEWLINE, VTY_NEWLINE); +      break; +    default: +      break; +    } +} + +/* `clear ip bgp' functions. */ +int +bgp_clear (struct vty *vty, struct bgp *bgp,  afi_t afi, safi_t safi, +           enum clear_sort sort,enum bgp_clear_type stype, char *arg) +{ +  int ret; +  struct peer *peer; +  struct listnode *nn; + +  /* Clear all neighbors. */ +  if (sort == clear_all) +    { +      LIST_LOOP (bgp->peer, peer, nn) +	{ +	  if (stype == BGP_CLEAR_SOFT_NONE) +	    ret = peer_clear (peer); +	  else +	    ret = peer_clear_soft (peer, afi, safi, stype); + +	  if (ret < 0) +	    bgp_clear_vty_error (vty, peer, afi, safi, ret); +	} +      return 0; +    } + +  /* Clear specified neighbors. */ +  if (sort == clear_peer) +    { +      union sockunion su; +      int ret; + +      /* Make sockunion for lookup. */ +      ret = str2sockunion (arg, &su); +      if (ret < 0) +	{ +	  vty_out (vty, "Malformed address: %s%s", arg, VTY_NEWLINE); +	  return -1; +	} +      peer = peer_lookup (bgp, &su); +      if (! peer) +	{ +	  vty_out (vty, "%%BGP: Unknown neighbor - \"%s\"%s", arg, VTY_NEWLINE); +	  return -1; +	} + +      if (stype == BGP_CLEAR_SOFT_NONE) +	ret = peer_clear (peer); +      else +	ret = peer_clear_soft (peer, afi, safi, stype); + +      if (ret < 0) +	bgp_clear_vty_error (vty, peer, afi, safi, ret); + +      return 0; +    } + +  /* Clear all peer-group members. */ +  if (sort == clear_group) +    { +      struct peer_group *group; + +      group = peer_group_lookup (bgp, arg); +      if (! group) +	{ +	  vty_out (vty, "%%BGP: No such peer-group %s%s", arg, VTY_NEWLINE); +	  return -1;  +	} + +      LIST_LOOP (group->peer, peer, nn) +	{ +	  if (stype == BGP_CLEAR_SOFT_NONE) +	    { +	      ret = peer_clear (peer); +	      continue; +	    } + +	  if (! peer->af_group[afi][safi]) +	    continue; + +	  ret = peer_clear_soft (peer, afi, safi, stype); + +	  if (ret < 0) +	    bgp_clear_vty_error (vty, peer, afi, safi, ret); +	} +      return 0; +    } + +  if (sort == clear_external) +    { +      LIST_LOOP (bgp->peer, peer, nn) +	{ +	  if (peer_sort (peer) == BGP_PEER_IBGP)  +	    continue; + +	  if (stype == BGP_CLEAR_SOFT_NONE) +	    ret = peer_clear (peer); +	  else +	    ret = peer_clear_soft (peer, afi, safi, stype); + +	  if (ret < 0) +	    bgp_clear_vty_error (vty, peer, afi, safi, ret); +	} +      return 0; +    } + +  if (sort == clear_as) +    { +      as_t as; +      unsigned long as_ul; +      char *endptr = NULL; +      int find = 0; + +      as_ul = strtoul(arg, &endptr, 10); + +      if ((as_ul == ULONG_MAX) || (*endptr != '\0') || (as_ul > USHRT_MAX)) +	{ +	  vty_out (vty, "Invalid AS number%s", VTY_NEWLINE);  +	  return -1; +	} +      as = (as_t) as_ul; + +      LIST_LOOP (bgp->peer, peer, nn) +	{ +	  if (peer->as != as)  +	    continue; + +	  find = 1; +	  if (stype == BGP_CLEAR_SOFT_NONE) +	    ret = peer_clear (peer); +	  else +	    ret = peer_clear_soft (peer, afi, safi, stype); + +	  if (ret < 0) +	    bgp_clear_vty_error (vty, peer, afi, safi, ret); +	} +      if (! find) +	vty_out (vty, "%%BGP: No peer is configured with AS %s%s", arg, +		 VTY_NEWLINE); +      return 0; +    } + +  return 0; +} + +int +bgp_clear_vty (struct vty *vty, char *name, afi_t afi, safi_t safi, +               enum clear_sort sort, enum bgp_clear_type stype, char *arg)   +{ +  int ret; +  struct bgp *bgp; + +  /* BGP structure lookup. */ +  if (name) +    { +      bgp = bgp_lookup_by_name (name); +      if (bgp == NULL) +        { +          vty_out (vty, "Can't find BGP view %s%s", name, VTY_NEWLINE); +          return CMD_WARNING; +        } +    } +  else +    { +      bgp = bgp_get_default (); +      if (bgp == NULL) +        { +          vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +          return CMD_WARNING; +        } +    } + +  ret =  bgp_clear (vty, bgp, afi, safi, sort, stype, arg); +  if (ret < 0) +    return CMD_WARNING; + +  return CMD_SUCCESS; +} +   +DEFUN (clear_ip_bgp_all, +       clear_ip_bgp_all_cmd, +       "clear ip bgp *", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n") +{ +  if (argc == 1) +    return bgp_clear_vty (vty, argv[0], 0, 0, clear_all, BGP_CLEAR_SOFT_NONE, NULL);     + +  return bgp_clear_vty (vty, NULL, 0, 0, clear_all, BGP_CLEAR_SOFT_NONE, NULL); +} + +ALIAS (clear_ip_bgp_all, +       clear_bgp_all_cmd, +       "clear bgp *", +       CLEAR_STR +       BGP_STR +       "Clear all peers\n") + +ALIAS (clear_ip_bgp_all, +       clear_bgp_ipv6_all_cmd, +       "clear bgp ipv6 *", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all peers\n") + +ALIAS (clear_ip_bgp_all, +       clear_ip_bgp_instance_all_cmd, +       "clear ip bgp view WORD *", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n") + +ALIAS (clear_ip_bgp_all, +       clear_bgp_instance_all_cmd, +       "clear bgp view WORD *", +       CLEAR_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n") + +DEFUN (clear_ip_bgp_peer, +       clear_ip_bgp_peer_cmd,  +       "clear ip bgp (A.B.C.D|X:X::X:X)", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor IP address to clear\n" +       "BGP IPv6 neighbor to clear\n") +{ +  return bgp_clear_vty (vty, NULL, 0, 0, clear_peer, BGP_CLEAR_SOFT_NONE, argv[0]); +} + +ALIAS (clear_ip_bgp_peer, +       clear_bgp_peer_cmd,  +       "clear bgp (A.B.C.D|X:X::X:X)", +       CLEAR_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n") + +ALIAS (clear_ip_bgp_peer, +       clear_bgp_ipv6_peer_cmd,  +       "clear bgp ipv6 (A.B.C.D|X:X::X:X)", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n") + +DEFUN (clear_ip_bgp_peer_group, +       clear_ip_bgp_peer_group_cmd,  +       "clear ip bgp peer-group WORD", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n") +{ +  return bgp_clear_vty (vty, NULL, 0, 0, clear_group, BGP_CLEAR_SOFT_NONE, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group, +       clear_bgp_peer_group_cmd,  +       "clear bgp peer-group WORD", +       CLEAR_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n") + +ALIAS (clear_ip_bgp_peer_group, +       clear_bgp_ipv6_peer_group_cmd,  +       "clear bgp ipv6 peer-group WORD", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all members of peer-group\n" +       "BGP peer-group name\n") + +DEFUN (clear_ip_bgp_external, +       clear_ip_bgp_external_cmd, +       "clear ip bgp external", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n") +{ +  return bgp_clear_vty (vty, NULL, 0, 0, clear_external, BGP_CLEAR_SOFT_NONE, NULL); +} + +ALIAS (clear_ip_bgp_external, +       clear_bgp_external_cmd,  +       "clear bgp external", +       CLEAR_STR +       BGP_STR +       "Clear all external peers\n") + +ALIAS (clear_ip_bgp_external, +       clear_bgp_ipv6_external_cmd,  +       "clear bgp ipv6 external", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all external peers\n") + +DEFUN (clear_ip_bgp_as, +       clear_ip_bgp_as_cmd, +       "clear ip bgp <1-65535>", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n") +{ +  return bgp_clear_vty (vty, NULL, 0, 0, clear_as, BGP_CLEAR_SOFT_NONE, argv[0]); +}        + +ALIAS (clear_ip_bgp_as, +       clear_bgp_as_cmd, +       "clear bgp <1-65535>", +       CLEAR_STR +       BGP_STR +       "Clear peers with the AS number\n") + +ALIAS (clear_ip_bgp_as, +       clear_bgp_ipv6_as_cmd, +       "clear bgp ipv6 <1-65535>", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear peers with the AS number\n") + +/* Outbound soft-reconfiguration */ +DEFUN (clear_ip_bgp_all_soft_out, +       clear_ip_bgp_all_soft_out_cmd, +       "clear ip bgp * soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  if (argc == 1) +    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, +                          BGP_CLEAR_SOFT_OUT, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, +			BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_all_soft_out, +       clear_ip_bgp_all_out_cmd, +       "clear ip bgp * out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig outbound update\n") + +ALIAS (clear_ip_bgp_all_soft_out, +       clear_ip_bgp_instance_all_soft_out_cmd, +       "clear ip bgp view WORD * soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_all_ipv4_soft_out, +       clear_ip_bgp_all_ipv4_soft_out_cmd, +       "clear ip bgp * ipv4 (unicast|multicast) soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, +			  BGP_CLEAR_SOFT_OUT, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, +			BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_all_ipv4_soft_out, +       clear_ip_bgp_all_ipv4_out_cmd, +       "clear ip bgp * ipv4 (unicast|multicast) out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_instance_all_ipv4_soft_out, +       clear_ip_bgp_instance_all_ipv4_soft_out_cmd, +       "clear ip bgp view WORD * ipv4 (unicast|multicast) soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig outbound update\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, +                          BGP_CLEAR_SOFT_OUT, NULL); + +  return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, +                        BGP_CLEAR_SOFT_OUT, NULL); +} + +DEFUN (clear_ip_bgp_all_vpnv4_soft_out, +       clear_ip_bgp_all_vpnv4_soft_out_cmd, +       "clear ip bgp * vpnv4 unicast soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, +			BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_all_vpnv4_soft_out, +       clear_ip_bgp_all_vpnv4_out_cmd, +       "clear ip bgp * vpnv4 unicast out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_bgp_all_soft_out, +       clear_bgp_all_soft_out_cmd, +       "clear bgp * soft out", +       CLEAR_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  if (argc == 1) +    return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, +                          BGP_CLEAR_SOFT_OUT, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, +			BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_bgp_all_soft_out, +       clear_bgp_instance_all_soft_out_cmd, +       "clear bgp view WORD * soft out", +       CLEAR_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_all_soft_out, +       clear_bgp_all_out_cmd, +       "clear bgp * out", +       CLEAR_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_all_soft_out, +       clear_bgp_ipv6_all_soft_out_cmd, +       "clear bgp ipv6 * soft out", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all peers\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_all_soft_out, +       clear_bgp_ipv6_all_out_cmd, +       "clear bgp ipv6 * out", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all peers\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_peer_soft_out, +       clear_ip_bgp_peer_soft_out_cmd, +       "clear ip bgp A.B.C.D soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, +			BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_soft_out, +       clear_ip_bgp_peer_out_cmd, +       "clear ip bgp A.B.C.D out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_peer_ipv4_soft_out, +       clear_ip_bgp_peer_ipv4_soft_out_cmd, +       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, +			  BGP_CLEAR_SOFT_OUT, argv[0]); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, +			BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_ipv4_soft_out, +       clear_ip_bgp_peer_ipv4_out_cmd, +       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_peer_vpnv4_soft_out, +       clear_ip_bgp_peer_vpnv4_soft_out_cmd, +       "clear ip bgp A.B.C.D vpnv4 unicast soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, +			BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_vpnv4_soft_out, +       clear_ip_bgp_peer_vpnv4_out_cmd, +       "clear ip bgp A.B.C.D vpnv4 unicast out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_bgp_peer_soft_out, +       clear_bgp_peer_soft_out_cmd, +       "clear bgp (A.B.C.D|X:X::X:X) soft out", +       CLEAR_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, +			BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_bgp_peer_soft_out, +       clear_bgp_ipv6_peer_soft_out_cmd, +       "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft out", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_peer_soft_out, +       clear_bgp_peer_out_cmd, +       "clear bgp (A.B.C.D|X:X::X:X) out", +       CLEAR_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_peer_soft_out, +       clear_bgp_ipv6_peer_out_cmd, +       "clear bgp ipv6 (A.B.C.D|X:X::X:X) out", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_peer_group_soft_out, +       clear_ip_bgp_peer_group_soft_out_cmd,  +       "clear ip bgp peer-group WORD soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, +			BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group_soft_out, +       clear_ip_bgp_peer_group_out_cmd,  +       "clear ip bgp peer-group WORD out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_peer_group_ipv4_soft_out, +       clear_ip_bgp_peer_group_ipv4_soft_out_cmd, +       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, +			  BGP_CLEAR_SOFT_OUT, argv[0]); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, +			BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group_ipv4_soft_out, +       clear_ip_bgp_peer_group_ipv4_out_cmd, +       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_bgp_peer_group_soft_out, +       clear_bgp_peer_group_soft_out_cmd, +       "clear bgp peer-group WORD soft out", +       CLEAR_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, +			BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_bgp_peer_group_soft_out, +       clear_bgp_ipv6_peer_group_soft_out_cmd, +       "clear bgp ipv6 peer-group WORD soft out", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_peer_group_soft_out, +       clear_bgp_peer_group_out_cmd, +       "clear bgp peer-group WORD out", +       CLEAR_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_peer_group_soft_out, +       clear_bgp_ipv6_peer_group_out_cmd, +       "clear bgp ipv6 peer-group WORD out", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_external_soft_out, +       clear_ip_bgp_external_soft_out_cmd,  +       "clear ip bgp external soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, +			BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_external_soft_out, +       clear_ip_bgp_external_out_cmd,  +       "clear ip bgp external out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_external_ipv4_soft_out, +       clear_ip_bgp_external_ipv4_soft_out_cmd, +       "clear ip bgp external ipv4 (unicast|multicast) soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, +			  BGP_CLEAR_SOFT_OUT, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, +			BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_ip_bgp_external_ipv4_soft_out, +       clear_ip_bgp_external_ipv4_out_cmd, +       "clear ip bgp external ipv4 (unicast|multicast) out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_bgp_external_soft_out, +       clear_bgp_external_soft_out_cmd, +       "clear bgp external soft out", +       CLEAR_STR +       BGP_STR +       "Clear all external peers\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, +			BGP_CLEAR_SOFT_OUT, NULL); +} + +ALIAS (clear_bgp_external_soft_out, +       clear_bgp_ipv6_external_soft_out_cmd, +       "clear bgp ipv6 external soft out", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all external peers\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_external_soft_out, +       clear_bgp_external_out_cmd, +       "clear bgp external out", +       CLEAR_STR +       BGP_STR +       "Clear all external peers\n" +       "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_external_soft_out, +       clear_bgp_ipv6_external_out_cmd, +       "clear bgp ipv6 external WORD out", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all external peers\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_as_soft_out, +       clear_ip_bgp_as_soft_out_cmd, +       "clear ip bgp <1-65535> soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, +			BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_as_soft_out, +       clear_ip_bgp_as_out_cmd, +       "clear ip bgp <1-65535> out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_as_ipv4_soft_out, +       clear_ip_bgp_as_ipv4_soft_out_cmd, +       "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, +			  BGP_CLEAR_SOFT_OUT, argv[0]); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, +			BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_as_ipv4_soft_out, +       clear_ip_bgp_as_ipv4_out_cmd, +       "clear ip bgp <1-65535> ipv4 (unicast|multicast) out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_ip_bgp_as_vpnv4_soft_out, +       clear_ip_bgp_as_vpnv4_soft_out_cmd, +       "clear ip bgp <1-65535> vpnv4 unicast soft out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Address family\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, +			BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_ip_bgp_as_vpnv4_soft_out, +       clear_ip_bgp_as_vpnv4_out_cmd, +       "clear ip bgp <1-65535> vpnv4 unicast out", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Address family\n" +       "Address Family modifier\n" +       "Soft reconfig outbound update\n") + +DEFUN (clear_bgp_as_soft_out, +       clear_bgp_as_soft_out_cmd, +       "clear bgp <1-65535> soft out", +       CLEAR_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, +			BGP_CLEAR_SOFT_OUT, argv[0]); +} + +ALIAS (clear_bgp_as_soft_out, +       clear_bgp_ipv6_as_soft_out_cmd, +       "clear bgp ipv6 <1-65535> soft out", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear peers with the AS number\n" +       "Soft reconfig\n" +       "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_as_soft_out, +       clear_bgp_as_out_cmd, +       "clear bgp <1-65535> out", +       CLEAR_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Soft reconfig outbound update\n") + +ALIAS (clear_bgp_as_soft_out, +       clear_bgp_ipv6_as_out_cmd, +       "clear bgp ipv6 <1-65535> out", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear peers with the AS number\n" +       "Soft reconfig outbound update\n") + +/* Inbound soft-reconfiguration */ +DEFUN (clear_ip_bgp_all_soft_in, +       clear_ip_bgp_all_soft_in_cmd, +       "clear ip bgp * soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  if (argc == 1) +    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, +                          BGP_CLEAR_SOFT_IN, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, +			BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_all_soft_in, +       clear_ip_bgp_instance_all_soft_in_cmd, +       "clear ip bgp view WORD * soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") + +ALIAS (clear_ip_bgp_all_soft_in, +       clear_ip_bgp_all_in_cmd, +       "clear ip bgp * in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_all_in_prefix_filter, +       clear_ip_bgp_all_in_prefix_filter_cmd, +       "clear ip bgp * in prefix-filter", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  if (argc== 1) +    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, +                          BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +ALIAS (clear_ip_bgp_all_in_prefix_filter, +       clear_ip_bgp_instance_all_in_prefix_filter_cmd, +       "clear ip bgp view WORD * in prefix-filter", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") + + +DEFUN (clear_ip_bgp_all_ipv4_soft_in, +       clear_ip_bgp_all_ipv4_soft_in_cmd, +       "clear ip bgp * ipv4 (unicast|multicast) soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, +			  BGP_CLEAR_SOFT_IN, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, +			BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_all_ipv4_soft_in, +       clear_ip_bgp_all_ipv4_in_cmd, +       "clear ip bgp * ipv4 (unicast|multicast) in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_instance_all_ipv4_soft_in, +       clear_ip_bgp_instance_all_ipv4_soft_in_cmd, +       "clear ip bgp view WORD * ipv4 (unicast|multicast) soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, +                          BGP_CLEAR_SOFT_IN, NULL); + +  return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, +                        BGP_CLEAR_SOFT_IN, NULL); +} + +DEFUN (clear_ip_bgp_all_ipv4_in_prefix_filter, +       clear_ip_bgp_all_ipv4_in_prefix_filter_cmd, +       "clear ip bgp * ipv4 (unicast|multicast) in prefix-filter", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, +			  BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +DEFUN (clear_ip_bgp_instance_all_ipv4_in_prefix_filter, +       clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd, +       "clear ip bgp view WORD * ipv4 (unicast|multicast) in prefix-filter", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, +                          BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); + +  return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, +                        BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +DEFUN (clear_ip_bgp_all_vpnv4_soft_in, +       clear_ip_bgp_all_vpnv4_soft_in_cmd, +       "clear ip bgp * vpnv4 unicast soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, +			BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_all_vpnv4_soft_in, +       clear_ip_bgp_all_vpnv4_in_cmd, +       "clear ip bgp * vpnv4 unicast in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_all_soft_in, +       clear_bgp_all_soft_in_cmd, +       "clear bgp * soft in", +       CLEAR_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  if (argc == 1) +    return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, +                        BGP_CLEAR_SOFT_IN, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, +			BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_bgp_all_soft_in, +       clear_bgp_instance_all_soft_in_cmd, +       "clear bgp view WORD * soft in", +       CLEAR_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_all_soft_in, +       clear_bgp_ipv6_all_soft_in_cmd, +       "clear bgp ipv6 * soft in", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all peers\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_all_soft_in, +       clear_bgp_all_in_cmd, +       "clear bgp * in", +       CLEAR_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_all_soft_in, +       clear_bgp_ipv6_all_in_cmd, +       "clear bgp ipv6 * in", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all peers\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_all_in_prefix_filter, +       clear_bgp_all_in_prefix_filter_cmd, +       "clear bgp * in prefix-filter", +       CLEAR_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +ALIAS (clear_bgp_all_in_prefix_filter, +       clear_bgp_ipv6_all_in_prefix_filter_cmd, +       "clear bgp ipv6 * in prefix-filter", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all peers\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFUN (clear_ip_bgp_peer_soft_in, +       clear_ip_bgp_peer_soft_in_cmd, +       "clear ip bgp A.B.C.D soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, +			BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_soft_in, +       clear_ip_bgp_peer_in_cmd, +       "clear ip bgp A.B.C.D in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Soft reconfig inbound update\n") +        +DEFUN (clear_ip_bgp_peer_in_prefix_filter, +       clear_ip_bgp_peer_in_prefix_filter_cmd, +       "clear ip bgp A.B.C.D in prefix-filter", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Soft reconfig inbound update\n" +       "Push out the existing ORF prefix-list\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_ipv4_soft_in, +       clear_ip_bgp_peer_ipv4_soft_in_cmd, +       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, +			  BGP_CLEAR_SOFT_IN, argv[0]); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, +			BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_ipv4_soft_in, +       clear_ip_bgp_peer_ipv4_in_cmd, +       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_peer_ipv4_in_prefix_filter, +       clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd, +       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in prefix-filter", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig inbound update\n" +       "Push out the existing ORF prefix-list\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, +			  BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_vpnv4_soft_in, +       clear_ip_bgp_peer_vpnv4_soft_in_cmd, +       "clear ip bgp A.B.C.D vpnv4 unicast soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, +			BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_vpnv4_soft_in, +       clear_ip_bgp_peer_vpnv4_in_cmd, +       "clear ip bgp A.B.C.D vpnv4 unicast in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_peer_soft_in, +       clear_bgp_peer_soft_in_cmd, +       "clear bgp (A.B.C.D|X:X::X:X) soft in", +       CLEAR_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, +			BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_bgp_peer_soft_in, +       clear_bgp_ipv6_peer_soft_in_cmd, +       "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft in", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_peer_soft_in, +       clear_bgp_peer_in_cmd, +       "clear bgp (A.B.C.D|X:X::X:X) in", +       CLEAR_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_peer_soft_in, +       clear_bgp_ipv6_peer_in_cmd, +       "clear bgp ipv6 (A.B.C.D|X:X::X:X) in", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_peer_in_prefix_filter, +       clear_bgp_peer_in_prefix_filter_cmd, +       "clear bgp (A.B.C.D|X:X::X:X) in prefix-filter", +       CLEAR_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig inbound update\n" +       "Push out the existing ORF prefix-list\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +ALIAS (clear_bgp_peer_in_prefix_filter, +       clear_bgp_ipv6_peer_in_prefix_filter_cmd, +       "clear bgp ipv6 (A.B.C.D|X:X::X:X) in prefix-filter", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig inbound update\n" +       "Push out the existing ORF prefix-list\n") + +DEFUN (clear_ip_bgp_peer_group_soft_in, +       clear_ip_bgp_peer_group_soft_in_cmd, +       "clear ip bgp peer-group WORD soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, +			BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group_soft_in, +       clear_ip_bgp_peer_group_in_cmd, +       "clear ip bgp peer-group WORD in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_peer_group_in_prefix_filter, +       clear_ip_bgp_peer_group_in_prefix_filter_cmd, +       "clear ip bgp peer-group WORD in prefix-filter", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_group_ipv4_soft_in, +       clear_ip_bgp_peer_group_ipv4_soft_in_cmd, +       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, +			  BGP_CLEAR_SOFT_IN, argv[0]); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, +			BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_group_ipv4_soft_in, +       clear_ip_bgp_peer_group_ipv4_in_cmd, +       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_peer_group_ipv4_in_prefix_filter, +       clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd, +       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in prefix-filter", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, +			  BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_bgp_peer_group_soft_in, +       clear_bgp_peer_group_soft_in_cmd, +       "clear bgp peer-group WORD soft in", +       CLEAR_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, +			BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_bgp_peer_group_soft_in, +       clear_bgp_ipv6_peer_group_soft_in_cmd, +       "clear bgp ipv6 peer-group WORD soft in", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_peer_group_soft_in, +       clear_bgp_peer_group_in_cmd, +       "clear bgp peer-group WORD in", +       CLEAR_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_peer_group_soft_in, +       clear_bgp_ipv6_peer_group_in_cmd, +       "clear bgp ipv6 peer-group WORD in", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_peer_group_in_prefix_filter, +       clear_bgp_peer_group_in_prefix_filter_cmd, +       "clear bgp peer-group WORD in prefix-filter", +       CLEAR_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +ALIAS (clear_bgp_peer_group_in_prefix_filter, +       clear_bgp_ipv6_peer_group_in_prefix_filter_cmd, +       "clear bgp ipv6 peer-group WORD in prefix-filter", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFUN (clear_ip_bgp_external_soft_in, +       clear_ip_bgp_external_soft_in_cmd, +       "clear ip bgp external soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, +			BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_external_soft_in, +       clear_ip_bgp_external_in_cmd, +       "clear ip bgp external in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_external_in_prefix_filter, +       clear_ip_bgp_external_in_prefix_filter_cmd, +       "clear ip bgp external in prefix-filter", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +DEFUN (clear_ip_bgp_external_ipv4_soft_in, +       clear_ip_bgp_external_ipv4_soft_in_cmd, +       "clear ip bgp external ipv4 (unicast|multicast) soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, +			  BGP_CLEAR_SOFT_IN, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, +			BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_ip_bgp_external_ipv4_soft_in, +       clear_ip_bgp_external_ipv4_in_cmd, +       "clear ip bgp external ipv4 (unicast|multicast) in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_external_ipv4_in_prefix_filter, +       clear_ip_bgp_external_ipv4_in_prefix_filter_cmd, +       "clear ip bgp external ipv4 (unicast|multicast) in prefix-filter", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, +			  BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +DEFUN (clear_bgp_external_soft_in, +       clear_bgp_external_soft_in_cmd, +       "clear bgp external soft in", +       CLEAR_STR +       BGP_STR +       "Clear all external peers\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, +			BGP_CLEAR_SOFT_IN, NULL); +} + +ALIAS (clear_bgp_external_soft_in, +       clear_bgp_ipv6_external_soft_in_cmd, +       "clear bgp ipv6 external soft in", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all external peers\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_external_soft_in, +       clear_bgp_external_in_cmd, +       "clear bgp external in", +       CLEAR_STR +       BGP_STR +       "Clear all external peers\n" +       "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_external_soft_in, +       clear_bgp_ipv6_external_in_cmd, +       "clear bgp ipv6 external WORD in", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all external peers\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_external_in_prefix_filter, +       clear_bgp_external_in_prefix_filter_cmd, +       "clear bgp external in prefix-filter", +       CLEAR_STR +       BGP_STR +       "Clear all external peers\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); +} + +ALIAS (clear_bgp_external_in_prefix_filter, +       clear_bgp_ipv6_external_in_prefix_filter_cmd, +       "clear bgp ipv6 external in prefix-filter", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all external peers\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") + +DEFUN (clear_ip_bgp_as_soft_in, +       clear_ip_bgp_as_soft_in_cmd, +       "clear ip bgp <1-65535> soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, +			BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_as_soft_in, +       clear_ip_bgp_as_in_cmd, +       "clear ip bgp <1-65535> in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_as_in_prefix_filter, +       clear_ip_bgp_as_in_prefix_filter_cmd, +       "clear ip bgp <1-65535> in prefix-filter", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_as_ipv4_soft_in, +       clear_ip_bgp_as_ipv4_soft_in_cmd, +       "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, +			  BGP_CLEAR_SOFT_IN, argv[0]); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, +			BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_as_ipv4_soft_in, +       clear_ip_bgp_as_ipv4_in_cmd, +       "clear ip bgp <1-65535> ipv4 (unicast|multicast) in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter, +       clear_ip_bgp_as_ipv4_in_prefix_filter_cmd, +       "clear ip bgp <1-65535> ipv4 (unicast|multicast) in prefix-filter", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, +			  BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +DEFUN (clear_ip_bgp_as_vpnv4_soft_in, +       clear_ip_bgp_as_vpnv4_soft_in_cmd, +       "clear ip bgp <1-65535> vpnv4 unicast soft in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Address family\n" +       "Address Family modifier\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, +			BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_ip_bgp_as_vpnv4_soft_in, +       clear_ip_bgp_as_vpnv4_in_cmd, +       "clear ip bgp <1-65535> vpnv4 unicast in", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Address family\n" +       "Address Family modifier\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_as_soft_in, +       clear_bgp_as_soft_in_cmd, +       "clear bgp <1-65535> soft in", +       CLEAR_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, +			BGP_CLEAR_SOFT_IN, argv[0]); +} + +ALIAS (clear_bgp_as_soft_in, +       clear_bgp_ipv6_as_soft_in_cmd, +       "clear bgp ipv6 <1-65535> soft in", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear peers with the AS number\n" +       "Soft reconfig\n" +       "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_as_soft_in, +       clear_bgp_as_in_cmd, +       "clear bgp <1-65535> in", +       CLEAR_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Soft reconfig inbound update\n") + +ALIAS (clear_bgp_as_soft_in, +       clear_bgp_ipv6_as_in_cmd, +       "clear bgp ipv6 <1-65535> in", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear peers with the AS number\n" +       "Soft reconfig inbound update\n") + +DEFUN (clear_bgp_as_in_prefix_filter, +       clear_bgp_as_in_prefix_filter_cmd, +       "clear bgp <1-65535> in prefix-filter", +       CLEAR_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, +			BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); +} + +ALIAS (clear_bgp_as_in_prefix_filter, +       clear_bgp_ipv6_as_in_prefix_filter_cmd, +       "clear bgp ipv6 <1-65535> in prefix-filter", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear peers with the AS number\n" +       "Soft reconfig inbound update\n" +       "Push out prefix-list ORF and do inbound soft reconfig\n") + +/* Both soft-reconfiguration */ +DEFUN (clear_ip_bgp_all_soft, +       clear_ip_bgp_all_soft_cmd, +       "clear ip bgp * soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig\n") +{ +  if (argc == 1) +    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, +                        BGP_CLEAR_SOFT_BOTH, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, +			BGP_CLEAR_SOFT_BOTH, NULL); +} + +ALIAS (clear_ip_bgp_all_soft, +       clear_ip_bgp_instance_all_soft_cmd, +       "clear ip bgp view WORD * soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Soft reconfig\n") + + +DEFUN (clear_ip_bgp_all_ipv4_soft, +       clear_ip_bgp_all_ipv4_soft_cmd, +       "clear ip bgp * ipv4 (unicast|multicast) soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Address Family Modifier\n" +       "Soft reconfig\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, +			  BGP_CLEAR_SOFT_BOTH, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, +			BGP_CLEAR_SOFT_BOTH, NULL); +} + +DEFUN (clear_ip_bgp_instance_all_ipv4_soft, +       clear_ip_bgp_instance_all_ipv4_soft_cmd, +       "clear ip bgp view WORD * ipv4 (unicast|multicast) soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Address Family Modifier\n" +       "Soft reconfig\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, +                          BGP_CLEAR_SOFT_BOTH, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, +                        BGP_CLEAR_SOFT_BOTH, NULL); +} + +DEFUN (clear_ip_bgp_all_vpnv4_soft, +       clear_ip_bgp_all_vpnv4_soft_cmd, +       "clear ip bgp * vpnv4 unicast soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_bgp_all_soft, +       clear_bgp_all_soft_cmd, +       "clear bgp * soft", +       CLEAR_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig\n") +{ +  if (argc == 1) +    return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, +                        BGP_CLEAR_SOFT_BOTH, argv[0]); +  +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +ALIAS (clear_bgp_all_soft, +       clear_bgp_instance_all_soft_cmd, +       "clear bgp view WORD * soft", +       CLEAR_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Soft reconfig\n") + +ALIAS (clear_bgp_all_soft, +       clear_bgp_ipv6_all_soft_cmd, +       "clear bgp ipv6 * soft", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all peers\n" +       "Soft reconfig\n") + +DEFUN (clear_ip_bgp_peer_soft, +       clear_ip_bgp_peer_soft_cmd, +       "clear ip bgp A.B.C.D soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_ipv4_soft, +       clear_ip_bgp_peer_ipv4_soft_cmd, +       "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Address Family Modifier\n" +       "Soft reconfig\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, +			  BGP_CLEAR_SOFT_BOTH, argv[0]); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_vpnv4_soft, +       clear_ip_bgp_peer_vpnv4_soft_cmd, +       "clear ip bgp A.B.C.D vpnv4 unicast soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_bgp_peer_soft, +       clear_bgp_peer_soft_cmd, +       "clear bgp (A.B.C.D|X:X::X:X) soft", +       CLEAR_STR +       BGP_STR +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +ALIAS (clear_bgp_peer_soft, +       clear_bgp_ipv6_peer_soft_cmd, +       "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "BGP neighbor address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig\n") + +DEFUN (clear_ip_bgp_peer_group_soft, +       clear_ip_bgp_peer_group_soft_cmd, +       "clear ip bgp peer-group WORD soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_peer_group_ipv4_soft, +       clear_ip_bgp_peer_group_ipv4_soft_cmd, +       "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, +			  BGP_CLEAR_SOFT_BOTH, argv[0]); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_bgp_peer_group_soft, +       clear_bgp_peer_group_soft_cmd, +       "clear bgp peer-group WORD soft", +       CLEAR_STR +       BGP_STR +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +ALIAS (clear_bgp_peer_group_soft, +       clear_bgp_ipv6_peer_group_soft_cmd, +       "clear bgp ipv6 peer-group WORD soft", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all members of peer-group\n" +       "BGP peer-group name\n" +       "Soft reconfig\n") + +DEFUN (clear_ip_bgp_external_soft, +       clear_ip_bgp_external_soft_cmd, +       "clear ip bgp external soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n" +       "Soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, +			BGP_CLEAR_SOFT_BOTH, NULL); +} + +DEFUN (clear_ip_bgp_external_ipv4_soft, +       clear_ip_bgp_external_ipv4_soft_cmd, +       "clear ip bgp external ipv4 (unicast|multicast) soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all external peers\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Soft reconfig\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, +			  BGP_CLEAR_SOFT_BOTH, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, +			BGP_CLEAR_SOFT_BOTH, NULL); +} + +DEFUN (clear_bgp_external_soft, +       clear_bgp_external_soft_cmd, +       "clear bgp external soft", +       CLEAR_STR +       BGP_STR +       "Clear all external peers\n" +       "Soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, +			BGP_CLEAR_SOFT_BOTH, NULL); +} + +ALIAS (clear_bgp_external_soft, +       clear_bgp_ipv6_external_soft_cmd, +       "clear bgp ipv6 external soft", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all external peers\n" +       "Soft reconfig\n") + +DEFUN (clear_ip_bgp_as_soft, +       clear_ip_bgp_as_soft_cmd, +       "clear ip bgp <1-65535> soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_as_ipv4_soft, +       clear_ip_bgp_as_ipv4_soft_cmd, +       "clear ip bgp <1-65535> ipv4 (unicast|multicast) soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Address Family Modifier\n" +       "Soft reconfig\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, +			  BGP_CLEAR_SOFT_BOTH, argv[0]); + +  return bgp_clear_vty (vty, NULL,AFI_IP, SAFI_UNICAST, clear_as, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_ip_bgp_as_vpnv4_soft, +       clear_ip_bgp_as_vpnv4_soft_cmd, +       "clear ip bgp <1-65535> vpnv4 unicast soft", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Address family\n" +       "Address Family Modifier\n" +       "Soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +DEFUN (clear_bgp_as_soft, +       clear_bgp_as_soft_cmd, +       "clear bgp <1-65535> soft", +       CLEAR_STR +       BGP_STR +       "Clear peers with the AS number\n" +       "Soft reconfig\n") +{ +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, +			BGP_CLEAR_SOFT_BOTH, argv[0]); +} + +ALIAS (clear_bgp_as_soft, +       clear_bgp_ipv6_as_soft_cmd, +       "clear bgp ipv6 <1-65535> soft", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear peers with the AS number\n" +       "Soft reconfig\n") + +/* Show BGP peer's summary information. */ +int +bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) +{ +  struct peer *peer; +  struct listnode *nn; +  int count = 0; +  char timebuf[BGP_UPTIME_LEN]; +  int len; + +  /* Header string for each address family. */ +  static char header[] = "Neighbor        V    AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd"; + +  LIST_LOOP (bgp->peer, peer, nn) +    { +      if (peer->afc[afi][safi]) +	{ +	  if (! count) +	    { +	      vty_out (vty, +		       "BGP router identifier %s, local AS number %d%s", +		       inet_ntoa (bgp->router_id), bgp->as, VTY_NEWLINE); +	      vty_out (vty,  +		       "%ld BGP AS-PATH entries%s", aspath_count (), +		       VTY_NEWLINE); +	      vty_out (vty,  +		       "%ld BGP community entries%s", community_count (), +		       VTY_NEWLINE); + +	      if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) +		vty_out (vty, "Dampening enabled.%s", VTY_NEWLINE); +	      vty_out (vty, "%s", VTY_NEWLINE); +	      vty_out (vty, "%s%s", header, VTY_NEWLINE); +	    } +	  count++; + +	  len = vty_out (vty, "%s", peer->host); +	  len = 16 - len; +	  if (len < 1) +	    vty_out (vty, "%s%*s", VTY_NEWLINE, 16, " "); +	  else +	    vty_out (vty, "%*s", len, " "); + +	  switch (peer->version)  +	    { +	    case BGP_VERSION_4: +	      vty_out (vty, "4 "); +	      break; +	    case BGP_VERSION_MP_4_DRAFT_00: +	      vty_out (vty, "4-"); +	      break; +	    } + +	  vty_out (vty, "%5d %7d %7d %8d %4d %4ld ", +		   peer->as, +		   peer->open_in + peer->update_in + peer->keepalive_in +		   + peer->notify_in + peer->refresh_in + peer->dynamic_cap_in, +		   peer->open_out + peer->update_out + peer->keepalive_out +		   + peer->notify_out + peer->refresh_out +		   + peer->dynamic_cap_out, +		   0, 0, peer->obuf->count); + +	  vty_out (vty, "%8s",  +		   peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN)); + +	  if (peer->status == Established) +	    { +	      vty_out (vty, " %8ld", peer->pcount[afi][safi]); +	    } +	  else +	    { +	      if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) +		vty_out (vty, " Idle (Admin)"); +	      else if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) +		vty_out (vty, " Idle (PfxCt)"); +	      else +		vty_out (vty, " %-11s", LOOKUP(bgp_status_msg, peer->status)); +	    } + +	  vty_out (vty, "%s", VTY_NEWLINE); +	} +    } + +  if (count) +    vty_out (vty, "%sTotal number of neighbors %d%s", VTY_NEWLINE, +	     count, VTY_NEWLINE); +  else +    vty_out (vty, "No %s neighbor is configured%s", +	     afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE); +  return CMD_SUCCESS; +} + +int  +bgp_show_summary_vty (struct vty *vty, char *name, afi_t afi, safi_t safi) +{ +  struct bgp *bgp; + +  if (name) +    { +      bgp = bgp_lookup_by_name (name); +       +      if (! bgp) +	{ +	  vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE);  +	  return CMD_WARNING; +	} + +      bgp_show_summary (vty, bgp, afi, safi); +      return CMD_SUCCESS; +    } +   +  bgp = bgp_get_default (); + +  if (bgp) +    bgp_show_summary (vty, bgp, afi, safi);     +  +  return CMD_SUCCESS; +} + +/* `show ip bgp summary' commands. */ +DEFUN (show_ip_bgp_summary,  +       show_ip_bgp_summary_cmd, +       "show ip bgp summary", +       SHOW_STR +       IP_STR +       BGP_STR +       "Summary of BGP neighbor status\n") +{ +  return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_instance_summary, +       show_ip_bgp_instance_summary_cmd, +       "show ip bgp view WORD summary", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "View name\n" +       "Summary of BGP neighbor status\n") +{ +  return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST);   +} + +DEFUN (show_ip_bgp_ipv4_summary,  +       show_ip_bgp_ipv4_summary_cmd, +       "show ip bgp ipv4 (unicast|multicast) summary", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Summary of BGP neighbor status\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); + +  return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_instance_ipv4_summary, +       show_ip_bgp_instance_ipv4_summary_cmd, +       "show ip bgp view WORD ipv4 (unicast|multicast) summary", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "View name\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Summary of BGP neighbor status\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); +  else +    return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_vpnv4_all_summary, +       show_ip_bgp_vpnv4_all_summary_cmd, +       "show ip bgp vpnv4 all summary", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information about all VPNv4 NLRIs\n" +       "Summary of BGP neighbor status\n") +{ +  return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); +} + +DEFUN (show_ip_bgp_vpnv4_rd_summary, +       show_ip_bgp_vpnv4_rd_summary_cmd, +       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn summary", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information for a route distinguisher\n" +       "VPN Route Distinguisher\n" +       "Summary of BGP neighbor status\n") +{ +  int ret; +  struct prefix_rd prd; + +  ret = str2prefix_rd (argv[0], &prd); +  if (! ret) +    { +      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_summary,  +       show_bgp_summary_cmd, +       "show bgp summary", +       SHOW_STR +       BGP_STR +       "Summary of BGP neighbor status\n") +{ +  return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); +} + +DEFUN (show_bgp_instance_summary, +       show_bgp_instance_summary_cmd, +       "show bgp view WORD summary", +       SHOW_STR +       BGP_STR +       "BGP view\n" +       "View name\n" +       "Summary of BGP neighbor status\n") +{ +  return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_summary,  +       show_bgp_ipv6_summary_cmd, +       "show bgp ipv6 summary", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Summary of BGP neighbor status\n") + +ALIAS (show_bgp_instance_summary, +       show_bgp_instance_ipv6_summary_cmd, +       "show bgp view WORD ipv6 summary", +       SHOW_STR +       BGP_STR +       "BGP view\n" +       "View name\n" +       "Address family\n" +       "Summary of BGP neighbor status\n") + +/* old command */ +DEFUN (show_ipv6_bgp_summary,  +       show_ipv6_bgp_summary_cmd, +       "show ipv6 bgp summary", +       SHOW_STR +       IPV6_STR +       BGP_STR +       "Summary of BGP neighbor status\n") +{ +  return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); +} + +/* old command */ +DEFUN (show_ipv6_mbgp_summary,  +       show_ipv6_mbgp_summary_cmd, +       "show ipv6 mbgp summary", +       SHOW_STR +       IPV6_STR +       MBGP_STR +       "Summary of BGP neighbor status\n") +{ +  return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); +} +#endif /* HAVE_IPV6 */ + +/* Show BGP peer's information. */ +enum show_type +{ +  show_all, +  show_peer +}; + +void +bgp_show_peer_afi_orf_cap (struct vty *vty, struct peer *p, +			   afi_t afi, safi_t safi, +			   u_int16_t adv_smcap, u_int16_t adv_rmcap, +			   u_int16_t rcv_smcap, u_int16_t rcv_rmcap) +{ +  /* Send-Mode */ +  if (CHECK_FLAG (p->af_cap[afi][safi], adv_smcap) +      || CHECK_FLAG (p->af_cap[afi][safi], rcv_smcap)) +    { +      vty_out (vty, "      Send-mode: "); +      if (CHECK_FLAG (p->af_cap[afi][safi], adv_smcap)) +	vty_out (vty, "advertised"); +      if (CHECK_FLAG (p->af_cap[afi][safi], rcv_smcap)) +	vty_out (vty, "%sreceived", +		 CHECK_FLAG (p->af_cap[afi][safi], adv_smcap) ? +		 ", " : ""); +      vty_out (vty, "%s", VTY_NEWLINE); +    } + +  /* Receive-Mode */ +  if (CHECK_FLAG (p->af_cap[afi][safi], adv_rmcap) +      || CHECK_FLAG (p->af_cap[afi][safi], rcv_rmcap)) +    { +      vty_out (vty, "      Receive-mode: "); +      if (CHECK_FLAG (p->af_cap[afi][safi], adv_rmcap)) +	vty_out (vty, "advertised"); +      if (CHECK_FLAG (p->af_cap[afi][safi], rcv_rmcap)) +	vty_out (vty, "%sreceived", +		 CHECK_FLAG (p->af_cap[afi][safi], adv_rmcap) ? +		 ", " : ""); +      vty_out (vty, "%s", VTY_NEWLINE); +    } +} + +void +bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi) +{ +  struct bgp_filter *filter; +  char orf_pfx_name[BUFSIZ]; +  int orf_pfx_count; + +  filter = &p->filter[afi][safi]; + +  vty_out (vty, " For address family: %s %s%s", +	   afi == AFI_IP6 ? "IPv6" : +	   safi == SAFI_MPLS_VPN ? "VPNv4" : "IPv4", +	   safi == SAFI_MULTICAST ? "Multicast" : "Unicast", +	   VTY_NEWLINE); +  if (p->af_group[afi][safi]) +    vty_out (vty, "  %s peer-group member%s", p->group->name, VTY_NEWLINE); + +  if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) +      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) +      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV) +      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) +      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV) +      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) +    vty_out (vty, "  AF-dependant capabilities:%s", VTY_NEWLINE); + +  if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) +      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) +      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) +      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) +    { +      vty_out (vty, "    Outbound Route Filter (ORF) type (%d) Prefix-list:%s", +	       ORF_TYPE_PREFIX, VTY_NEWLINE); +      bgp_show_peer_afi_orf_cap (vty, p, afi, safi, +				 PEER_CAP_ORF_PREFIX_SM_ADV, +				 PEER_CAP_ORF_PREFIX_RM_ADV, +				 PEER_CAP_ORF_PREFIX_SM_RCV, +				 PEER_CAP_ORF_PREFIX_RM_RCV); +    } +  if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) +      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV) +      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) +      || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) +    { +      vty_out (vty, "    Outbound Route Filter (ORF) type (%d) Prefix-list:%s", +	       ORF_TYPE_PREFIX_OLD, VTY_NEWLINE); +      bgp_show_peer_afi_orf_cap (vty, p, afi, safi, +				 PEER_CAP_ORF_PREFIX_SM_ADV, +				 PEER_CAP_ORF_PREFIX_RM_ADV, +				 PEER_CAP_ORF_PREFIX_SM_OLD_RCV, +				 PEER_CAP_ORF_PREFIX_RM_OLD_RCV); +    } + +  sprintf (orf_pfx_name, "%s.%d.%d", p->host, afi, safi); +  orf_pfx_count =  prefix_bgp_show_prefix_list (NULL, afi, orf_pfx_name); + +  if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND) +      || orf_pfx_count) +    { +      vty_out (vty, "  Outbound Route Filter (ORF):"); +      if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND)) +	  vty_out (vty, " sent;"); +      if (orf_pfx_count) +	vty_out (vty, " received (%d entries)", orf_pfx_count); +      vty_out (vty, "%s", VTY_NEWLINE); +    } +  if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) +      vty_out (vty, "  First update is deferred until ORF or ROUTE-REFRESH is received%s", VTY_NEWLINE); + +  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) +    vty_out (vty, "  Route-Reflector Client%s", VTY_NEWLINE); +  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) +    vty_out (vty, "  Route-Server Client%s", VTY_NEWLINE); +  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) +    vty_out (vty, "  Inbound soft reconfiguration allowed%s", VTY_NEWLINE); +  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REMOVE_PRIVATE_AS)) +    vty_out (vty, "  Private AS number removed from updates to this neighbor%s", VTY_NEWLINE); +  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF)) +    vty_out (vty, "  NEXT_HOP is always this router%s", VTY_NEWLINE); +  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)) +    vty_out (vty, "  AS_PATH is propagated unchanged to this neighbor%s", VTY_NEWLINE); +  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)) +    vty_out (vty, "  NEXT_HOP is propagated unchanged to this neighbor%s", VTY_NEWLINE); +  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) +    vty_out (vty, "  MED is propagated unchanged to this neighbor%s", VTY_NEWLINE); +  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) +      || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) +    { +      vty_out (vty, "  Community attribute sent to this neighbor"); +      if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) +	&& CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) +	vty_out (vty, " (both)%s", VTY_NEWLINE); +      else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) +	vty_out (vty, " (extended)%s", VTY_NEWLINE); +      else  +	vty_out (vty, " (standard)%s", VTY_NEWLINE); +    } +  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) +    { +      vty_out (vty, "  Default information originate,"); + +      if (p->default_rmap[afi][safi].name) +	vty_out (vty, " default route-map %s%s,", +		 p->default_rmap[afi][safi].map ? "*" : "", +		 p->default_rmap[afi][safi].name); +      if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) +	vty_out (vty, " default sent%s", VTY_NEWLINE); +      else +	vty_out (vty, " default not sent%s", VTY_NEWLINE); +    } + +  if (filter->plist[FILTER_IN].name +      || filter->dlist[FILTER_IN].name +      || filter->aslist[FILTER_IN].name +      || filter->map[FILTER_IN].name) +    vty_out (vty, "  Inbound path policy configured%s", VTY_NEWLINE); +  if (filter->plist[FILTER_OUT].name +      || filter->dlist[FILTER_OUT].name +      || filter->aslist[FILTER_OUT].name +      || filter->map[FILTER_OUT].name +      || filter->usmap.name) +    vty_out (vty, "  Outbound path policy configured%s", VTY_NEWLINE); + +  /* prefix-list */ +  if (filter->plist[FILTER_IN].name) +    vty_out (vty, "  Incoming update prefix filter list is %s%s%s", +	     filter->plist[FILTER_IN].plist ? "*" : "", +	     filter->plist[FILTER_IN].name, +	     VTY_NEWLINE); +  if (filter->plist[FILTER_OUT].name) +    vty_out (vty, "  Outgoing update prefix filter list is %s%s%s", +	     filter->plist[FILTER_OUT].plist ? "*" : "", +	     filter->plist[FILTER_OUT].name, +	     VTY_NEWLINE); + +  /* distribute-list */ +  if (filter->dlist[FILTER_IN].name) +    vty_out (vty, "  Incoming update network filter list is %s%s%s", +	     filter->dlist[FILTER_IN].alist ? "*" : "", +	     filter->dlist[FILTER_IN].name, +	     VTY_NEWLINE); +  if (filter->dlist[FILTER_OUT].name) +    vty_out (vty, "  Outgoing update network filter list is %s%s%s", +	     filter->dlist[FILTER_OUT].alist ? "*" : "", +	     filter->dlist[FILTER_OUT].name, +	     VTY_NEWLINE); + +  /* filter-list. */ +  if (filter->aslist[FILTER_IN].name) +    vty_out (vty, "  Incoming update AS path filter list is %s%s%s", +	     filter->aslist[FILTER_IN].aslist ? "*" : "", +	     filter->aslist[FILTER_IN].name, +	     VTY_NEWLINE); +  if (filter->aslist[FILTER_OUT].name) +    vty_out (vty, "  Outgoing update AS path filter list is %s%s%s", +	     filter->aslist[FILTER_OUT].aslist ? "*" : "", +	     filter->aslist[FILTER_OUT].name, +	     VTY_NEWLINE); + +  /* route-map. */ +  if (filter->map[FILTER_IN].name) +    vty_out (vty, "  Route map for incoming advertisements is %s%s%s", +	     filter->map[FILTER_IN].map ? "*" : "", +	     filter->map[FILTER_IN].name, +	     VTY_NEWLINE); +  if (filter->map[FILTER_OUT].name) +    vty_out (vty, "  Route map for outgoing advertisements is %s%s%s", +	     filter->map[FILTER_OUT].map ? "*" : "", +	     filter->map[FILTER_OUT].name, +	     VTY_NEWLINE); + +  /* unsuppress-map */ +  if (filter->usmap.name) +    vty_out (vty, "  Route map for selective unsuppress is %s%s%s", +	     filter->usmap.map ? "*" : "", +	     filter->usmap.name, VTY_NEWLINE); + +  /* Receive prefix count */ +  vty_out (vty, "  %ld accepted prefixes", +	   p->pcount[afi][safi]); +  /* Maximum prefix */ +  if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) +    { +      vty_out (vty, ", maximum limit %ld%s", +	       p->pmax[afi][safi], +	       CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING) +	       ? " (warning-only)" : ""); +    } +  vty_out (vty, "%s", VTY_NEWLINE); + +  vty_out (vty, "%s", VTY_NEWLINE); +} + +void +bgp_show_peer (struct vty *vty, struct peer *p) +{ +  struct bgp *bgp; +  char buf1[BUFSIZ]; +  char timebuf[BGP_UPTIME_LEN]; + +  bgp = p->bgp; + +  /* Configured IP address. */ +  vty_out (vty, "BGP neighbor is %s, ", p->host); +  vty_out (vty, "remote AS %d, ", p->as); +  vty_out (vty, "local AS %d%s, ", +	   p->change_local_as ? p->change_local_as : p->local_as, +	   CHECK_FLAG (p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ? +	   " no-prepend" : ""); +  vty_out (vty, "%s link%s", +	   p->as == p->local_as ? "internal" : "external", +	   VTY_NEWLINE); + +  /* Description. */ +  if (p->desc) +    vty_out (vty, " Description: %s%s", p->desc, VTY_NEWLINE); +   +  /* Peer-group */ +  if (p->group) +    vty_out (vty, " Member of peer-group %s for session parameters%s", +	     p->group->name, VTY_NEWLINE); + +  /* Administrative shutdown. */ +  if (CHECK_FLAG (p->flags, PEER_FLAG_SHUTDOWN)) +    vty_out (vty, " Administratively shut down%s", VTY_NEWLINE); + +  /* BGP Version. */ +  vty_out (vty, "  BGP version 4"); +  if (p->version == BGP_VERSION_MP_4_DRAFT_00) +    vty_out (vty, "(with draft-00 verion of multiporotocol extension)"); +  vty_out (vty, ", remote router ID %s%s",  +	   inet_ntop (AF_INET, &p->remote_id, buf1, BUFSIZ), +	   VTY_NEWLINE); + +  /* Confederation */ +  if (bgp_confederation_peers_check (bgp, p->as))  +    vty_out (vty, "  Neighbor under common administration%s", VTY_NEWLINE); +   +  /* Status. */ +  vty_out (vty, "  BGP state = %s",   +	   LOOKUP (bgp_status_msg, p->status)); +  if (p->status == Established)  +    vty_out (vty, ", up for %8s",  +	     peer_uptime (p->uptime, timebuf, BGP_UPTIME_LEN)); +  vty_out (vty, "%s", VTY_NEWLINE); +   +  /* read timer */ +  vty_out (vty, "  Last read %s", peer_uptime (p->readtime, timebuf, BGP_UPTIME_LEN)); + +  /* Configured timer values. */ +  vty_out (vty, ", hold time is %d, keepalive interval is %d seconds%s", +	   p->v_holdtime, p->v_keepalive, VTY_NEWLINE); +  if (CHECK_FLAG (p->config, PEER_CONFIG_TIMER)) +    { +      vty_out (vty, "  Configured hold time is %d", p->holdtime); +      vty_out (vty, ", keepalive interval is %d seconds%s", +	       p->keepalive, VTY_NEWLINE); +    } +   +  /* Capability. */ +  if (p->status == Established)  +    { +      if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV) +	  || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV) +	  || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV) +	  || CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV) +	  || CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV) +	  || p->afc_adv[AFI_IP][SAFI_UNICAST] +	  || p->afc_recv[AFI_IP][SAFI_UNICAST] +	  || p->afc_adv[AFI_IP][SAFI_MULTICAST] +	  || p->afc_recv[AFI_IP][SAFI_MULTICAST] +#ifdef HAVE_IPV6 +	  || p->afc_adv[AFI_IP6][SAFI_UNICAST] +	  || p->afc_recv[AFI_IP6][SAFI_UNICAST] +	  || p->afc_adv[AFI_IP6][SAFI_MULTICAST] +	  || p->afc_recv[AFI_IP6][SAFI_MULTICAST] +#endif /* HAVE_IPV6 */ +	  || p->afc_adv[AFI_IP][SAFI_MPLS_VPN] +	  || p->afc_recv[AFI_IP][SAFI_MPLS_VPN]) +	{ +	  vty_out (vty, "  Neighbor capabilities:%s", VTY_NEWLINE); + +	  /* Dynamic */ +	  if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV) +	      || CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV)) +	    { +	      vty_out (vty, "    Dynamic:"); +	      if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV)) +		vty_out (vty, " advertised"); +	      if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV)) +		{ +		  if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV)) +		    vty_out (vty, " and"); +		  vty_out (vty, " received"); +		} +	      vty_out (vty, "%s", VTY_NEWLINE); +	    } + +	  /* Route Refresh */ +	  if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV) +	      || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV) +	      || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV)) +	    { +	      vty_out (vty, "    Route refresh:"); + 	      if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV)) +		vty_out (vty, " advertised"); +	      if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV) +		  || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV)) +		{ +		  if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV)) +		    vty_out (vty, " and"); +		  vty_out (vty, " received"); +		  if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV) +		      && CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV)) +		    vty_out (vty, " (old and new)"); +		  else if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV)) +		    vty_out (vty, " (old)"); +		  else  +		    vty_out (vty, " (new)"); +		} +	      vty_out (vty, "%s", VTY_NEWLINE); +	    } + +	  /* IPv4 */ +	  if (p->afc_adv[AFI_IP][SAFI_UNICAST] +	      || p->afc_recv[AFI_IP][SAFI_UNICAST])  +	    { +	      vty_out (vty, "    Address family IPv4 Unicast:"); +	      if (p->afc_adv[AFI_IP][SAFI_UNICAST])  +		vty_out (vty, " advertised"); +	      if (p->afc_recv[AFI_IP][SAFI_UNICAST]) +		{ +		  if (p->afc_adv[AFI_IP][SAFI_UNICAST]) +		    vty_out (vty, " and"); +		  vty_out (vty, " received"); +		} +	      vty_out (vty, "%s", VTY_NEWLINE); +	    } +	  if (p->afc_adv[AFI_IP][SAFI_MULTICAST] || p->afc_recv[AFI_IP][SAFI_MULTICAST])  +	    { +	      vty_out (vty, "    Address family IPv4 Multicast:"); +	      if (p->afc_adv[AFI_IP][SAFI_MULTICAST])  +		vty_out (vty, " advertised"); +	      if (p->afc_recv[AFI_IP][SAFI_MULTICAST]) +		{ +		  if (p->afc_adv[AFI_IP][SAFI_MULTICAST]) +		    vty_out (vty, " and"); +		  vty_out (vty, " received"); +		} +	      vty_out (vty, "%s", VTY_NEWLINE); +	    } +	  if (p->afc_adv[AFI_IP][SAFI_MPLS_VPN] || p->afc_recv[AFI_IP][SAFI_MPLS_VPN])  +	    { +	      vty_out (vty, "    Address family VPNv4 Unicast:"); +	      if (p->afc_adv[AFI_IP][SAFI_MPLS_VPN])  +		vty_out (vty, " advertised"); +	      if (p->afc_recv[AFI_IP][SAFI_MPLS_VPN]) +		{ +		  if (p->afc_adv[AFI_IP][SAFI_MPLS_VPN]) +		    vty_out (vty, " and"); +		  vty_out (vty, " received"); +		} +	      vty_out (vty, "%s", VTY_NEWLINE); +	    } +	  /* IPv6 */ +#ifdef HAVE_IPV6 +	  if (p->afc_adv[AFI_IP6][SAFI_UNICAST] || p->afc_recv[AFI_IP6][SAFI_UNICAST])  +	    { +	      vty_out (vty, "    Address family IPv6 Unicast:"); +	      if (p->afc_adv[AFI_IP6][SAFI_UNICAST])  +		vty_out (vty, " advertised"); +	      if (p->afc_recv[AFI_IP6][SAFI_UNICAST]) +		{ +		  if (p->afc_adv[AFI_IP6][SAFI_UNICAST]) +		    vty_out (vty, " and"); +		  vty_out (vty, " received"); +		} +	      vty_out (vty, "%s", VTY_NEWLINE); +	    } +	  if (p->afc_adv[AFI_IP6][SAFI_MULTICAST] || p->afc_recv[AFI_IP6][SAFI_MULTICAST])  +	    { +	      vty_out (vty, "    Address family IPv6 Multicast:"); +	      if (p->afc_adv[AFI_IP6][SAFI_MULTICAST])  +		vty_out (vty, " advertised"); +	      if (p->afc_recv[AFI_IP6][SAFI_MULTICAST]) +		{ +		  if (p->afc_adv[AFI_IP6][SAFI_MULTICAST]) +		    vty_out (vty, " and"); +		  vty_out (vty, " received"); +		} +	      vty_out (vty, "%s", VTY_NEWLINE); +	    } +#endif /* HAVE_IPV6 */ +	} +    } + +  /* Packet counts. */ +  vty_out(vty, "  Received %d messages, %d notifications, %d in queue%s", +	  p->open_in + p->update_in + p->keepalive_in + p->refresh_in +	  + p->dynamic_cap_in, p->notify_in, 0, VTY_NEWLINE); +  vty_out(vty, "  Sent %d messages, %d notifications, %ld in queue%s", +	  p->open_out + p->update_out + p->keepalive_out + p->refresh_out +	  + p->dynamic_cap_out, p->notify_out, p->obuf->count, VTY_NEWLINE); +  vty_out(vty, "  Route refresh request: received %d, sent %d%s", +	  p->refresh_in, p->refresh_out, VTY_NEWLINE); + +  /* advertisement-interval */ +  vty_out (vty, "  Minimum time between advertisement runs is %d seconds%s", +	   p->v_routeadv, VTY_NEWLINE); + +  /* Update-source. */ +  if (p->update_if || p->update_source) +    { +      vty_out (vty, "  Update source is "); +      if (p->update_if) +	vty_out (vty, "%s", p->update_if); +      else if (p->update_source) +	vty_out (vty, "%s", +		 sockunion2str (p->update_source, buf1, SU_ADDRSTRLEN)); +      vty_out (vty, "%s", VTY_NEWLINE); +    } + +  /* Default weight */ +  if (CHECK_FLAG (p->config, PEER_CONFIG_WEIGHT)) +    vty_out (vty, "  Default weight %d%s", p->weight, +	     VTY_NEWLINE); + +  vty_out (vty, "%s", VTY_NEWLINE); + +  /* Address Family Information */ +  if (p->afc[AFI_IP][SAFI_UNICAST]) +    bgp_show_peer_afi (vty, p, AFI_IP, SAFI_UNICAST); +  if (p->afc[AFI_IP][SAFI_MULTICAST]) +    bgp_show_peer_afi (vty, p, AFI_IP, SAFI_MULTICAST); +  if (p->afc[AFI_IP][SAFI_MPLS_VPN]) +    bgp_show_peer_afi (vty, p, AFI_IP, SAFI_MPLS_VPN); +#ifdef HAVE_IPV6 +  if (p->afc[AFI_IP6][SAFI_UNICAST]) +    bgp_show_peer_afi (vty, p, AFI_IP6, SAFI_UNICAST); +  if (p->afc[AFI_IP6][SAFI_MULTICAST]) +    bgp_show_peer_afi (vty, p, AFI_IP6, SAFI_MULTICAST); +#endif /* HAVE_IPV6 */ + +  vty_out (vty, "  Connections established %d; dropped %d%s", +	   p->established, p->dropped, +	   VTY_NEWLINE); + +  if (CHECK_FLAG (p->sflags, PEER_STATUS_PREFIX_OVERFLOW)) +    { +      vty_out (vty, "  Peer had exceeded the max. no. of prefixes configured.%s", VTY_NEWLINE); +      vty_out (vty, "  Reduce the no. of prefix and clear ip bgp %s to restore peering%s", +	       p->host, VTY_NEWLINE); +    } + +  /* EBGP Multihop */ +  if (peer_sort (p) != BGP_PEER_IBGP && p->ttl > 1) +    vty_out (vty, "  External BGP neighbor may be up to %d hops away.%s", +	     p->ttl, VTY_NEWLINE); + +  /* Local address. */ +  if (p->su_local) +    { +      vty_out (vty, "Local host: %s, Local port: %d%s%s", +	       sockunion2str (p->su_local, buf1, SU_ADDRSTRLEN), +	       ntohs (p->su_local->sin.sin_port), +	       CHECK_FLAG (p->flags, PEER_FLAG_PASSIVE) ? +	       ", passive-mode" : "",  +	       VTY_NEWLINE); +    } +       +  /* Remote address. */ +  if (p->su_remote) +    { +      vty_out (vty, "Foreign host: %s, Foreign port: %d%s", +	       sockunion2str (p->su_remote, buf1, SU_ADDRSTRLEN), +	       ntohs (p->su_remote->sin.sin_port), +	       VTY_NEWLINE); +    } + +  /* Nexthop display. */ +  if (p->su_local) +    { +      vty_out (vty, "Nexthop: %s%s",  +	       inet_ntop (AF_INET, &p->nexthop.v4, buf1, BUFSIZ), +	       VTY_NEWLINE); +#ifdef HAVE_IPV6 +      vty_out (vty, "Nexthop global: %s%s",  +	       inet_ntop (AF_INET6, &p->nexthop.v6_global, buf1, BUFSIZ), +	       VTY_NEWLINE); +      vty_out (vty, "Nexthop local: %s%s", +	       inet_ntop (AF_INET6, &p->nexthop.v6_local, buf1, BUFSIZ), +	       VTY_NEWLINE); +      vty_out (vty, "BGP connection: %s%s", +	       p->shared_network ? "shared network" : "non shared network", +	       VTY_NEWLINE); +#endif /* HAVE_IPV6 */ +    } + +  /* Timer information. */ +  if (p->t_start) +    vty_out (vty, "Next start timer due in %ld seconds%s", +	     thread_timer_remain_second (p->t_start), VTY_NEWLINE); +  if (p->t_connect) +    vty_out (vty, "Next connect timer due in %ld seconds%s", +	     thread_timer_remain_second (p->t_connect), VTY_NEWLINE); +   +  vty_out (vty, "Read thread: %s  Write thread: %s%s",  +	   p->t_read ? "on" : "off", +	   p->t_write ? "on" : "off", +	   VTY_NEWLINE); + +  if (p->notify.code == BGP_NOTIFY_OPEN_ERR +      && p->notify.subcode == BGP_NOTIFY_OPEN_UNSUP_CAPBL) +    bgp_capability_vty_out (vty, p); +  +  vty_out (vty, "%s", VTY_NEWLINE); +} + +int +bgp_show_neighbor (struct vty *vty, struct bgp *bgp, +		   enum show_type type, union sockunion *su) +{ +  struct listnode *nn; +  struct peer *peer; +  int find = 0; + +  LIST_LOOP (bgp->peer, peer, nn) +    { +      switch (type) +	{ +	case show_all: +	  bgp_show_peer (vty, peer); +	  break; +	case show_peer: +	  if (sockunion_same (&peer->su, su)) +	    { +	      find = 1; +	      bgp_show_peer (vty, peer); +	    } +	  break; +	} +    } + +  if (type == show_peer && ! find) +    vty_out (vty, "%% No such neighbor%s", VTY_NEWLINE); +   +  return CMD_SUCCESS; +} + +int  +bgp_show_neighbor_vty (struct vty *vty, char *name, enum show_type type, +		       char *ip_str) +{ +  int ret; +  struct bgp *bgp; +  union sockunion su; + +  if (ip_str) +    { +      ret = str2sockunion (ip_str, &su); +      if (ret < 0) +        { +          vty_out (vty, "%% Malformed address: %s%s", ip_str, VTY_NEWLINE); +          return CMD_WARNING; +        } +    } + +  if (name) +    { +      bgp = bgp_lookup_by_name (name); +       +      if (! bgp) +        { +          vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE);  +          return CMD_WARNING; +        } + +      bgp_show_neighbor (vty, bgp, type, &su); + +      return CMD_SUCCESS; +    } + +  bgp = bgp_get_default (); + +  if (bgp) +    bgp_show_neighbor (vty, bgp, type, &su); + +  return CMD_SUCCESS; +} + +/* "show ip bgp neighbors" commands.  */ +DEFUN (show_ip_bgp_neighbors, +       show_ip_bgp_neighbors_cmd, +       "show ip bgp neighbors", +       SHOW_STR +       IP_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n") +{ +  return bgp_show_neighbor_vty (vty, NULL, show_all, NULL); +} + +ALIAS (show_ip_bgp_neighbors, +       show_ip_bgp_ipv4_neighbors_cmd, +       "show ip bgp ipv4 (unicast|multicast) neighbors", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Detailed information on TCP and BGP neighbor connections\n") + +ALIAS (show_ip_bgp_neighbors, +       show_ip_bgp_vpnv4_all_neighbors_cmd, +       "show ip bgp vpnv4 all neighbors", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information about all VPNv4 NLRIs\n" +       "Detailed information on TCP and BGP neighbor connections\n") + +ALIAS (show_ip_bgp_neighbors, +       show_ip_bgp_vpnv4_rd_neighbors_cmd, +       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information for a route distinguisher\n" +       "VPN Route Distinguisher\n" +       "Detailed information on TCP and BGP neighbor connections\n") + +ALIAS (show_ip_bgp_neighbors, +       show_bgp_neighbors_cmd, +       "show bgp neighbors", +       SHOW_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n") + +ALIAS (show_ip_bgp_neighbors, +       show_bgp_ipv6_neighbors_cmd, +       "show bgp ipv6 neighbors", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Detailed information on TCP and BGP neighbor connections\n") + +DEFUN (show_ip_bgp_neighbors_peer, +       show_ip_bgp_neighbors_peer_cmd, +       "show ip bgp neighbors (A.B.C.D|X:X::X:X)", +       SHOW_STR +       IP_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n") +{ +  return bgp_show_neighbor_vty (vty, NULL, show_peer, argv[argc - 1]); +} + +ALIAS (show_ip_bgp_neighbors_peer, +       show_ip_bgp_ipv4_neighbors_peer_cmd, +       "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X)", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n") + +ALIAS (show_ip_bgp_neighbors_peer, +       show_ip_bgp_vpnv4_all_neighbors_peer_cmd, +       "show ip bgp vpnv4 all neighbors A.B.C.D", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information about all VPNv4 NLRIs\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n") + +ALIAS (show_ip_bgp_neighbors_peer, +       show_ip_bgp_vpnv4_rd_neighbors_peer_cmd, +       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D", +       SHOW_STR +       IP_STR +       BGP_STR +       "Display VPNv4 NLRI specific information\n" +       "Display information about all VPNv4 NLRIs\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n") + +ALIAS (show_ip_bgp_neighbors_peer, +       show_bgp_neighbors_peer_cmd, +       "show bgp neighbors (A.B.C.D|X:X::X:X)", +       SHOW_STR +       BGP_STR +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n") + +ALIAS (show_ip_bgp_neighbors_peer, +       show_bgp_ipv6_neighbors_peer_cmd, +       "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X)", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n") + +DEFUN (show_ip_bgp_instance_neighbors, +       show_ip_bgp_instance_neighbors_cmd, +       "show ip bgp view WORD neighbors", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "View name\n" +       "Detailed information on TCP and BGP neighbor connections\n") +{ +  return bgp_show_neighbor_vty (vty, argv[0], show_all, NULL); +} + +DEFUN (show_ip_bgp_instance_neighbors_peer, +       show_ip_bgp_instance_neighbors_peer_cmd, +       "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X)", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "View name\n" +       "Detailed information on TCP and BGP neighbor connections\n" +       "Neighbor to display information about\n" +       "Neighbor to display information about\n") +{ +  return bgp_show_neighbor_vty (vty, argv[0], show_peer, argv[1]); +} + +/* Show BGP's AS paths internal data.  There are both `show ip bgp +   paths' and `show ip mbgp paths'.  Those functions results are the +   same.*/ +DEFUN (show_ip_bgp_paths,  +       show_ip_bgp_paths_cmd, +       "show ip bgp paths", +       SHOW_STR +       IP_STR +       BGP_STR +       "Path information\n") +{ +  vty_out (vty, "Address Refcnt Path%s", VTY_NEWLINE); +  aspath_print_all_vty (vty); +  return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_ipv4_paths,  +       show_ip_bgp_ipv4_paths_cmd, +       "show ip bgp ipv4 (unicast|multicast) paths", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Path information\n") +{ +  vty_out (vty, "Address Refcnt Path\r\n"); +  aspath_print_all_vty (vty); + +  return CMD_SUCCESS; +} + +#include "hash.h" + +void +community_show_all_iterator (struct hash_backet *backet, struct vty *vty) +{ +  struct community *com; + +  com = (struct community *) backet->data; +  vty_out (vty, "[%p] (%ld) %s%s", backet, com->refcnt, +	   community_str (com), VTY_NEWLINE); +} + +/* Show BGP's community internal data. */ +DEFUN (show_ip_bgp_community_info,  +       show_ip_bgp_community_info_cmd, +       "show ip bgp community-info", +       SHOW_STR +       IP_STR +       BGP_STR +       "List all bgp community information\n") +{ +  vty_out (vty, "Address Refcnt Community%s", VTY_NEWLINE); + +  hash_iterate (community_hash (),  +		(void (*) (struct hash_backet *, void *)) +		community_show_all_iterator, +		vty); + +  return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_attr_info,  +       show_ip_bgp_attr_info_cmd, +       "show ip bgp attribute-info", +       SHOW_STR +       IP_STR +       BGP_STR +       "List all bgp attribute information\n") +{ +  attr_show_all (vty); +  return CMD_SUCCESS; +} + +/* Redistribute VTY commands.  */ + +/* Utility function to convert user input route type string to route +   type.  */ +static int +bgp_str2route_type (int afi, char *str) +{ +  if (! str) +    return 0; + +  if (afi == AFI_IP) +    { +      if (strncmp (str, "k", 1) == 0) +	return ZEBRA_ROUTE_KERNEL; +      else if (strncmp (str, "c", 1) == 0) +	return ZEBRA_ROUTE_CONNECT; +      else if (strncmp (str, "s", 1) == 0) +	return ZEBRA_ROUTE_STATIC; +      else if (strncmp (str, "r", 1) == 0) +	return ZEBRA_ROUTE_RIP; +      else if (strncmp (str, "o", 1) == 0) +	return ZEBRA_ROUTE_OSPF; +    } +  if (afi == AFI_IP6) +    { +      if (strncmp (str, "k", 1) == 0) +	return ZEBRA_ROUTE_KERNEL; +      else if (strncmp (str, "c", 1) == 0) +	return ZEBRA_ROUTE_CONNECT; +      else if (strncmp (str, "s", 1) == 0) +	return ZEBRA_ROUTE_STATIC; +      else if (strncmp (str, "r", 1) == 0) +	return ZEBRA_ROUTE_RIPNG; +      else if (strncmp (str, "o", 1) == 0) +	return ZEBRA_ROUTE_OSPF6; +    } +  return 0; +} + +DEFUN (bgp_redistribute_ipv4, +       bgp_redistribute_ipv4_cmd, +       "redistribute (connected|kernel|ospf|rip|static)", +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPF)\n" +       "Routing Information Protocol (RIP)\n" +       "Static routes\n") +{ +  int type; + +  type = bgp_str2route_type (AFI_IP, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (bgp_redistribute_ipv4_rmap, +       bgp_redistribute_ipv4_rmap_cmd, +       "redistribute (connected|kernel|ospf|rip|static) route-map WORD", +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPF)\n" +       "Routing Information Protocol (RIP)\n" +       "Static routes\n" +       "Route map reference\n" +       "Pointer to route-map entries\n") +{ +  int type; + +  type = bgp_str2route_type (AFI_IP, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[1]); +  return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (bgp_redistribute_ipv4_metric, +       bgp_redistribute_ipv4_metric_cmd, +       "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPF)\n" +       "Routing Information Protocol (RIP)\n" +       "Static routes\n" +       "Metric for redistributed routes\n" +       "Default metric\n") +{ +  int type; +  u_int32_t metric; + +  type = bgp_str2route_type (AFI_IP, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  VTY_GET_INTEGER ("metric", metric, argv[1]); + +  bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric); +  return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (bgp_redistribute_ipv4_rmap_metric, +       bgp_redistribute_ipv4_rmap_metric_cmd, +       "redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPF)\n" +       "Routing Information Protocol (RIP)\n" +       "Static routes\n" +       "Route map reference\n" +       "Pointer to route-map entries\n" +       "Metric for redistributed routes\n" +       "Default metric\n") +{ +  int type; +  u_int32_t metric; + +  type = bgp_str2route_type (AFI_IP, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  VTY_GET_INTEGER ("metric", metric, argv[2]); + +  bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[1]); +  bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric); +  return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (bgp_redistribute_ipv4_metric_rmap, +       bgp_redistribute_ipv4_metric_rmap_cmd, +       "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPF)\n" +       "Routing Information Protocol (RIP)\n" +       "Static routes\n" +       "Metric for redistributed routes\n" +       "Default metric\n" +       "Route map reference\n" +       "Pointer to route-map entries\n") +{ +  int type; +  u_int32_t metric; + +  type = bgp_str2route_type (AFI_IP, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  VTY_GET_INTEGER ("metric", metric, argv[1]); + +  bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric); +  bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[2]); +  return bgp_redistribute_set (vty->index, AFI_IP, type); +} + +DEFUN (no_bgp_redistribute_ipv4, +       no_bgp_redistribute_ipv4_cmd, +       "no redistribute (connected|kernel|ospf|rip|static)", +       NO_STR +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPF)\n" +       "Routing Information Protocol (RIP)\n" +       "Static routes\n") +{ +  int type; + +  type = bgp_str2route_type (AFI_IP, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_redistribute_unset (vty->index, AFI_IP, type); +} + +DEFUN (no_bgp_redistribute_ipv4_rmap, +       no_bgp_redistribute_ipv4_rmap_cmd, +       "no redistribute (connected|kernel|ospf|rip|static) route-map WORD", +       NO_STR +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPF)\n" +       "Routing Information Protocol (RIP)\n" +       "Static routes\n" +       "Route map reference\n" +       "Pointer to route-map entries\n") +{ +  int type; + +  type = bgp_str2route_type (AFI_IP, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_redistribute_routemap_unset (vty->index, AFI_IP, type); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_redistribute_ipv4_metric, +       no_bgp_redistribute_ipv4_metric_cmd, +       "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", +       NO_STR +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPF)\n" +       "Routing Information Protocol (RIP)\n" +       "Static routes\n" +       "Metric for redistributed routes\n" +       "Default metric\n") +{ +  int type; + +  type = bgp_str2route_type (AFI_IP, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_redistribute_metric_unset (vty->index, AFI_IP, type); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_redistribute_ipv4_rmap_metric, +       no_bgp_redistribute_ipv4_rmap_metric_cmd, +       "no redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", +       NO_STR +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPF)\n" +       "Routing Information Protocol (RIP)\n" +       "Static routes\n" +       "Route map reference\n" +       "Pointer to route-map entries\n" +       "Metric for redistributed routes\n" +       "Default metric\n") +{ +  int type; + +  type = bgp_str2route_type (AFI_IP, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_redistribute_metric_unset (vty->index, AFI_IP, type); +  bgp_redistribute_routemap_unset (vty->index, AFI_IP, type); +  return CMD_SUCCESS; +} + +ALIAS (no_bgp_redistribute_ipv4_rmap_metric, +       no_bgp_redistribute_ipv4_metric_rmap_cmd, +       "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", +       NO_STR +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPF)\n" +       "Routing Information Protocol (RIP)\n" +       "Static routes\n" +       "Metric for redistributed routes\n" +       "Default metric\n" +       "Route map reference\n" +       "Pointer to route-map entries\n") + +#ifdef HAVE_IPV6 +DEFUN (bgp_redistribute_ipv6, +       bgp_redistribute_ipv6_cmd, +       "redistribute (connected|kernel|ospf6|ripng|static)", +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPFv3)\n" +       "Routing Information Protocol (RIPng)\n" +       "Static routes\n") +{ +  int type; + +  type = bgp_str2route_type (AFI_IP6, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (bgp_redistribute_ipv6_rmap, +       bgp_redistribute_ipv6_rmap_cmd, +       "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPFv3)\n" +       "Routing Information Protocol (RIPng)\n" +       "Static routes\n" +       "Route map reference\n" +       "Pointer to route-map entries\n") +{ +  int type; + +  type = bgp_str2route_type (AFI_IP6, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[1]); +  return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (bgp_redistribute_ipv6_metric, +       bgp_redistribute_ipv6_metric_cmd, +       "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPFv3)\n" +       "Routing Information Protocol (RIPng)\n" +       "Static routes\n" +       "Metric for redistributed routes\n" +       "Default metric\n") +{ +  int type; +  u_int32_t metric; + +  type = bgp_str2route_type (AFI_IP6, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  VTY_GET_INTEGER ("metric", metric, argv[1]); + +  bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric); +  return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (bgp_redistribute_ipv6_rmap_metric, +       bgp_redistribute_ipv6_rmap_metric_cmd, +       "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPFv3)\n" +       "Routing Information Protocol (RIPng)\n" +       "Static routes\n" +       "Route map reference\n" +       "Pointer to route-map entries\n" +       "Metric for redistributed routes\n" +       "Default metric\n") +{ +  int type; +  u_int32_t metric; + +  type = bgp_str2route_type (AFI_IP6, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  VTY_GET_INTEGER ("metric", metric, argv[2]); + +  bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[1]); +  bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric); +  return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (bgp_redistribute_ipv6_metric_rmap, +       bgp_redistribute_ipv6_metric_rmap_cmd, +       "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPFv3)\n" +       "Routing Information Protocol (RIPng)\n" +       "Static routes\n" +       "Metric for redistributed routes\n" +       "Default metric\n" +       "Route map reference\n" +       "Pointer to route-map entries\n") +{ +  int type; +  u_int32_t metric; + +  type = bgp_str2route_type (AFI_IP6, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  VTY_GET_INTEGER ("metric", metric, argv[1]); + +  bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric); +  bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[2]); +  return bgp_redistribute_set (vty->index, AFI_IP6, type); +} + +DEFUN (no_bgp_redistribute_ipv6, +       no_bgp_redistribute_ipv6_cmd, +       "no redistribute (connected|kernel|ospf6|ripng|static)", +       NO_STR +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPFv3)\n" +       "Routing Information Protocol (RIPng)\n" +       "Static routes\n") +{ +  int type; + +  type = bgp_str2route_type (AFI_IP6, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_redistribute_unset (vty->index, AFI_IP6, type); +} + +DEFUN (no_bgp_redistribute_ipv6_rmap, +       no_bgp_redistribute_ipv6_rmap_cmd, +       "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", +       NO_STR +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPFv3)\n" +       "Routing Information Protocol (RIPng)\n" +       "Static routes\n" +       "Route map reference\n" +       "Pointer to route-map entries\n") +{ +  int type; + +  type = bgp_str2route_type (AFI_IP6, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_redistribute_ipv6_metric, +       no_bgp_redistribute_ipv6_metric_cmd, +       "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", +       NO_STR +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPFv3)\n" +       "Routing Information Protocol (RIPng)\n" +       "Static routes\n" +       "Metric for redistributed routes\n" +       "Default metric\n") +{ +  int type; + +  type = bgp_str2route_type (AFI_IP6, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_redistribute_metric_unset (vty->index, AFI_IP6, type); +  return CMD_SUCCESS; +} + +DEFUN (no_bgp_redistribute_ipv6_rmap_metric, +       no_bgp_redistribute_ipv6_rmap_metric_cmd, +       "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", +       NO_STR +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPFv3)\n" +       "Routing Information Protocol (RIPng)\n" +       "Static routes\n" +       "Route map reference\n" +       "Pointer to route-map entries\n" +       "Metric for redistributed routes\n" +       "Default metric\n") +{ +  int type; + +  type = bgp_str2route_type (AFI_IP6, argv[0]); +  if (! type) +    { +      vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  bgp_redistribute_metric_unset (vty->index, AFI_IP6, type); +  bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type); +  return CMD_SUCCESS; +} + +ALIAS (no_bgp_redistribute_ipv6_rmap_metric, +       no_bgp_redistribute_ipv6_metric_rmap_cmd, +       "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", +       NO_STR +       "Redistribute information from another routing protocol\n" +       "Connected\n" +       "Kernel routes\n" +       "Open Shurtest Path First (OSPFv3)\n" +       "Routing Information Protocol (RIPng)\n" +       "Static routes\n" +       "Metric for redistributed routes\n" +       "Default metric\n" +       "Route map reference\n" +       "Pointer to route-map entries\n") +#endif /* HAVE_IPV6 */ + +int +bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi, +			       safi_t safi, int *write) +{ +  int i; +  char *str[] = { "system", "kernel", "connected", "static", "rip", +		  "ripng", "ospf", "ospf6", "bgp"}; + +  /* Unicast redistribution only.  */ +  if (safi != SAFI_UNICAST) +    return 0; + +  for (i = 0; i < ZEBRA_ROUTE_MAX; i++) +    { +      /* Redistribute BGP does not make sense.  */ +      if (bgp->redist[afi][i] && i != ZEBRA_ROUTE_BGP) +	{ +	  /* Display "address-family" when it is not yet diplayed.  */ +	  bgp_config_write_family_header (vty, afi, safi, write); + +	  /* "redistribute" configuration.  */ +	  vty_out (vty, " redistribute %s", str[i]); + +	  if (bgp->redist_metric_flag[afi][i]) +	    vty_out (vty, " metric %d", bgp->redist_metric[afi][i]); + +	  if (bgp->rmap[afi][i].name) +	    vty_out (vty, " route-map %s", bgp->rmap[afi][i].name); + +	  vty_out (vty, "%s", VTY_NEWLINE); +	} +    } +  return *write; +} + +/* BGP node structure. */ +struct cmd_node bgp_node = +{ +  BGP_NODE, +  "%s(config-router)# ", +  1, +}; + +struct cmd_node bgp_ipv4_unicast_node = +{ +  BGP_IPV4_NODE, +  "%s(config-router-af)# ", +  1, +}; + +struct cmd_node bgp_ipv4_multicast_node = +{ +  BGP_IPV4M_NODE, +  "%s(config-router-af)# ", +  1, +}; + +struct cmd_node bgp_ipv6_unicast_node =  +{ +  BGP_IPV6_NODE, +  "%s(config-router-af)# ", +  1, +}; + +struct cmd_node bgp_vpnv4_node = +{ +  BGP_VPNV4_NODE, +  "%s(config-router-af)# ", +  1 +}; + +void +bgp_vty_init () +{ +  int bgp_config_write (struct vty *); +  void community_list_vty (); + +  /* Install bgp top node. */ +  install_node (&bgp_node, bgp_config_write); +  install_node (&bgp_ipv4_unicast_node, NULL); +  install_node (&bgp_ipv4_multicast_node, NULL); +  install_node (&bgp_ipv6_unicast_node, NULL); +  install_node (&bgp_vpnv4_node, NULL); + +  /* Install default VTY commands to new nodes.  */ +  install_default (BGP_NODE); +  install_default (BGP_IPV4_NODE); +  install_default (BGP_IPV4M_NODE); +  install_default (BGP_IPV6_NODE); +  install_default (BGP_VPNV4_NODE); +   +  /* "bgp multiple-instance" commands. */ +  install_element (CONFIG_NODE, &bgp_multiple_instance_cmd); +  install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd); + +  /* "bgp config-type" commands. */ +  install_element (CONFIG_NODE, &bgp_config_type_cmd); +  install_element (CONFIG_NODE, &no_bgp_config_type_cmd); + +  /* Dummy commands (Currently not supported) */ +  install_element (BGP_NODE, &no_synchronization_cmd); +  install_element (BGP_NODE, &no_auto_summary_cmd); + +  /* "router bgp" commands. */ +  install_element (CONFIG_NODE, &router_bgp_cmd); +  install_element (CONFIG_NODE, &router_bgp_view_cmd); + +  /* "no router bgp" commands. */ +  install_element (CONFIG_NODE, &no_router_bgp_cmd); +  install_element (CONFIG_NODE, &no_router_bgp_view_cmd); + +  /* "bgp router-id" commands. */ +  install_element (BGP_NODE, &bgp_router_id_cmd); +  install_element (BGP_NODE, &no_bgp_router_id_cmd); +  install_element (BGP_NODE, &no_bgp_router_id_val_cmd); + +  /* "bgp cluster-id" commands. */ +  install_element (BGP_NODE, &bgp_cluster_id_cmd); +  install_element (BGP_NODE, &bgp_cluster_id32_cmd); +  install_element (BGP_NODE, &no_bgp_cluster_id_cmd); +  install_element (BGP_NODE, &no_bgp_cluster_id_arg_cmd); + +  /* "bgp confederation" commands. */ +  install_element (BGP_NODE, &bgp_confederation_identifier_cmd); +  install_element (BGP_NODE, &no_bgp_confederation_identifier_cmd); +  install_element (BGP_NODE, &no_bgp_confederation_identifier_arg_cmd); + +  /* "bgp confederation peers" commands. */ +  install_element (BGP_NODE, &bgp_confederation_peers_cmd); +  install_element (BGP_NODE, &no_bgp_confederation_peers_cmd); + +  /* "timers bgp" commands. */ +  install_element (BGP_NODE, &bgp_timers_cmd); +  install_element (BGP_NODE, &no_bgp_timers_cmd); +  install_element (BGP_NODE, &no_bgp_timers_arg_cmd); + +  /* "bgp client-to-client reflection" commands */ +  install_element (BGP_NODE, &no_bgp_client_to_client_reflection_cmd); +  install_element (BGP_NODE, &bgp_client_to_client_reflection_cmd); + +  /* "bgp always-compare-med" commands */ +  install_element (BGP_NODE, &bgp_always_compare_med_cmd); +  install_element (BGP_NODE, &no_bgp_always_compare_med_cmd); +   +  /* "bgp deterministic-med" commands */ +  install_element (BGP_NODE, &bgp_deterministic_med_cmd); +  install_element (BGP_NODE, &no_bgp_deterministic_med_cmd); +  +  /* "bgp fast-external-failover" commands */ +  install_element (BGP_NODE, &bgp_fast_external_failover_cmd); +  install_element (BGP_NODE, &no_bgp_fast_external_failover_cmd); + +  /* "bgp enforce-first-as" commands */ +  install_element (BGP_NODE, &bgp_enforce_first_as_cmd); +  install_element (BGP_NODE, &no_bgp_enforce_first_as_cmd); + +  /* "bgp bestpath compare-routerid" commands */ +  install_element (BGP_NODE, &bgp_bestpath_compare_router_id_cmd); +  install_element (BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd); + +  /* "bgp bestpath as-path ignore" commands */ +  install_element (BGP_NODE, &bgp_bestpath_aspath_ignore_cmd); +  install_element (BGP_NODE, &no_bgp_bestpath_aspath_ignore_cmd); + +  /* "bgp bestpath med" commands */ +  install_element (BGP_NODE, &bgp_bestpath_med_cmd); +  install_element (BGP_NODE, &bgp_bestpath_med2_cmd); +  install_element (BGP_NODE, &bgp_bestpath_med3_cmd); +  install_element (BGP_NODE, &no_bgp_bestpath_med_cmd); +  install_element (BGP_NODE, &no_bgp_bestpath_med2_cmd); +  install_element (BGP_NODE, &no_bgp_bestpath_med3_cmd); + +  /* "no bgp default ipv4-unicast" commands. */ +  install_element (BGP_NODE, &no_bgp_default_ipv4_unicast_cmd); +  install_element (BGP_NODE, &bgp_default_ipv4_unicast_cmd); +   +  /* "bgp network import-check" commands. */ +  install_element (BGP_NODE, &bgp_network_import_check_cmd); +  install_element (BGP_NODE, &no_bgp_network_import_check_cmd); + +  /* "bgp default local-preference" commands. */ +  install_element (BGP_NODE, &bgp_default_local_preference_cmd); +  install_element (BGP_NODE, &no_bgp_default_local_preference_cmd); +  install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd); + +  /* "neighbor remote-as" commands. */ +  install_element (BGP_NODE, &neighbor_remote_as_cmd); +  install_element (BGP_NODE, &no_neighbor_cmd); +  install_element (BGP_NODE, &no_neighbor_remote_as_cmd); + +  /* "neighbor peer-group" commands. */ +  install_element (BGP_NODE, &neighbor_peer_group_cmd); +  install_element (BGP_NODE, &no_neighbor_peer_group_cmd); +  install_element (BGP_NODE, &no_neighbor_peer_group_remote_as_cmd); + +  /* "neighbor local-as" commands. */ +  install_element (BGP_NODE, &neighbor_local_as_cmd); +  install_element (BGP_NODE, &neighbor_local_as_no_prepend_cmd); +  install_element (BGP_NODE, &no_neighbor_local_as_cmd); +  install_element (BGP_NODE, &no_neighbor_local_as_val_cmd); +  install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd); + +  /* "neighbor activate" commands. */ +  install_element (BGP_NODE, &neighbor_activate_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_activate_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_activate_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd); + +  /* "no neighbor activate" commands. */ +  install_element (BGP_NODE, &no_neighbor_activate_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd); + +  /* "neighbor peer-group set" commands. */ +  install_element (BGP_NODE, &neighbor_set_peer_group_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd); + +  /* "no neighbor peer-group unset" commands. */ +  install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd); + +  /* "neighbor softreconfiguration inbound" commands.*/ +  install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd); +  install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd); + +  /* "neighbor attribute-unchanged" commands.  */ +  install_element (BGP_NODE, &neighbor_attr_unchanged_cmd); +  install_element (BGP_NODE, &neighbor_attr_unchanged1_cmd); +  install_element (BGP_NODE, &neighbor_attr_unchanged2_cmd); +  install_element (BGP_NODE, &neighbor_attr_unchanged3_cmd); +  install_element (BGP_NODE, &neighbor_attr_unchanged4_cmd); +  install_element (BGP_NODE, &neighbor_attr_unchanged5_cmd); +  install_element (BGP_NODE, &neighbor_attr_unchanged6_cmd); +  install_element (BGP_NODE, &neighbor_attr_unchanged7_cmd); +  install_element (BGP_NODE, &neighbor_attr_unchanged8_cmd); +  install_element (BGP_NODE, &neighbor_attr_unchanged9_cmd); +  install_element (BGP_NODE, &neighbor_attr_unchanged10_cmd); +  install_element (BGP_NODE, &no_neighbor_attr_unchanged_cmd); +  install_element (BGP_NODE, &no_neighbor_attr_unchanged1_cmd); +  install_element (BGP_NODE, &no_neighbor_attr_unchanged2_cmd); +  install_element (BGP_NODE, &no_neighbor_attr_unchanged3_cmd); +  install_element (BGP_NODE, &no_neighbor_attr_unchanged4_cmd); +  install_element (BGP_NODE, &no_neighbor_attr_unchanged5_cmd); +  install_element (BGP_NODE, &no_neighbor_attr_unchanged6_cmd); +  install_element (BGP_NODE, &no_neighbor_attr_unchanged7_cmd); +  install_element (BGP_NODE, &no_neighbor_attr_unchanged8_cmd); +  install_element (BGP_NODE, &no_neighbor_attr_unchanged9_cmd); +  install_element (BGP_NODE, &no_neighbor_attr_unchanged10_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged1_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged2_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged3_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged4_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged5_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged6_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged7_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged8_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged9_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged10_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged1_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged2_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged3_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged4_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged5_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged6_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged7_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged8_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged9_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged10_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged1_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged2_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged3_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged4_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged5_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged6_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged7_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged8_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged9_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged10_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged1_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged2_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged3_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged4_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged5_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged6_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged7_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged8_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged9_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged10_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged1_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged2_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged3_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged4_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged5_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged6_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged7_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged8_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged9_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged10_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged1_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged2_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged3_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged4_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged5_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged6_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged7_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged8_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged9_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged10_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged1_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged2_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged3_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged4_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged5_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged6_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged7_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged8_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged9_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged10_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged1_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged2_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged3_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged4_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged5_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged6_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged7_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged8_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged9_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged10_cmd); + +  /* "transparent-as" and "transparent-nexthop" for old version +     compatibility.  */ +  install_element (BGP_NODE, &neighbor_transparent_as_cmd); +  install_element (BGP_NODE, &neighbor_transparent_nexthop_cmd); + +  /* "neighbor next-hop-self" commands. */ +  install_element (BGP_NODE, &neighbor_nexthop_self_cmd); +  install_element (BGP_NODE, &no_neighbor_nexthop_self_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_nexthop_self_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd); + +  /* "neighbor remove-private-AS" commands. */ +  install_element (BGP_NODE, &neighbor_remove_private_as_cmd); +  install_element (BGP_NODE, &no_neighbor_remove_private_as_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_remove_private_as_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd); + +  /* "neighbor send-community" commands.*/ +  install_element (BGP_NODE, &neighbor_send_community_cmd); +  install_element (BGP_NODE, &neighbor_send_community_type_cmd); +  install_element (BGP_NODE, &no_neighbor_send_community_cmd); +  install_element (BGP_NODE, &no_neighbor_send_community_type_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_send_community_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_send_community_type_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_send_community_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_send_community_type_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_send_community_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_send_community_type_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_type_cmd); + +  /* "neighbor route-reflector" commands.*/ +  install_element (BGP_NODE, &neighbor_route_reflector_client_cmd); +  install_element (BGP_NODE, &no_neighbor_route_reflector_client_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_route_reflector_client_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd); + +  /* "neighbor route-server" commands.*/ +  install_element (BGP_NODE, &neighbor_route_server_client_cmd); +  install_element (BGP_NODE, &no_neighbor_route_server_client_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_route_server_client_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd); + +  /* "neighbor passive" commands. */ +  install_element (BGP_NODE, &neighbor_passive_cmd); +  install_element (BGP_NODE, &no_neighbor_passive_cmd); + +  /* "neighbor shutdown" commands. */ +  install_element (BGP_NODE, &neighbor_shutdown_cmd); +  install_element (BGP_NODE, &no_neighbor_shutdown_cmd); + +  /* "neighbor capability route-refresh" commands.*/ +  install_element (BGP_NODE, &neighbor_capability_route_refresh_cmd); +  install_element (BGP_NODE, &no_neighbor_capability_route_refresh_cmd); + +  /* "neighbor capability orf prefix-list" commands.*/ +  install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd); +  install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_capability_orf_prefix_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd); + +  /* "neighbor capability dynamic" commands.*/ +  install_element (BGP_NODE, &neighbor_capability_dynamic_cmd); +  install_element (BGP_NODE, &no_neighbor_capability_dynamic_cmd); + +  /* "neighbor dont-capability-negotiate" commands. */ +  install_element (BGP_NODE, &neighbor_dont_capability_negotiate_cmd); +  install_element (BGP_NODE, &no_neighbor_dont_capability_negotiate_cmd); + +  /* "neighbor ebgp-multihop" commands. */ +  install_element (BGP_NODE, &neighbor_ebgp_multihop_cmd); +  install_element (BGP_NODE, &neighbor_ebgp_multihop_ttl_cmd); +  install_element (BGP_NODE, &no_neighbor_ebgp_multihop_cmd); +  install_element (BGP_NODE, &no_neighbor_ebgp_multihop_ttl_cmd); + +  /* "neighbor enforce-multihop" commands.  */ +  install_element (BGP_NODE, &neighbor_enforce_multihop_cmd); +  install_element (BGP_NODE, &no_neighbor_enforce_multihop_cmd); + +  /* "neighbor description" commands. */ +  install_element (BGP_NODE, &neighbor_description_cmd); +  install_element (BGP_NODE, &no_neighbor_description_cmd); +  install_element (BGP_NODE, &no_neighbor_description_val_cmd); + +  /* "neighbor update-source" commands. "*/ +  install_element (BGP_NODE, &neighbor_update_source_cmd); +  install_element (BGP_NODE, &no_neighbor_update_source_cmd); + +  /* "neighbor default-originate" commands. */ +  install_element (BGP_NODE, &neighbor_default_originate_cmd); +  install_element (BGP_NODE, &neighbor_default_originate_rmap_cmd); +  install_element (BGP_NODE, &no_neighbor_default_originate_cmd); +  install_element (BGP_NODE, &no_neighbor_default_originate_rmap_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_default_originate_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_default_originate_rmap_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_rmap_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_rmap_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_rmap_cmd); + +  /* "neighbor port" commands. */ +  install_element (BGP_NODE, &neighbor_port_cmd); +  install_element (BGP_NODE, &no_neighbor_port_cmd); +  install_element (BGP_NODE, &no_neighbor_port_val_cmd); + +  /* "neighbor weight" commands. */ +  install_element (BGP_NODE, &neighbor_weight_cmd); +  install_element (BGP_NODE, &no_neighbor_weight_cmd); +  install_element (BGP_NODE, &no_neighbor_weight_val_cmd); + +  /* "neighbor override-capability" commands. */ +  install_element (BGP_NODE, &neighbor_override_capability_cmd); +  install_element (BGP_NODE, &no_neighbor_override_capability_cmd); + +  /* "neighbor strict-capability-match" commands. */ +  install_element (BGP_NODE, &neighbor_strict_capability_cmd); +  install_element (BGP_NODE, &no_neighbor_strict_capability_cmd); + +  /* "neighbor timers" commands. */ +  install_element (BGP_NODE, &neighbor_timers_cmd); +  install_element (BGP_NODE, &no_neighbor_timers_cmd); + +  /* "neighbor timers connect" commands. */ +  install_element (BGP_NODE, &neighbor_timers_connect_cmd); +  install_element (BGP_NODE, &no_neighbor_timers_connect_cmd); +  install_element (BGP_NODE, &no_neighbor_timers_connect_val_cmd); + +  /* "neighbor advertisement-interval" commands. */ +  install_element (BGP_NODE, &neighbor_advertise_interval_cmd); +  install_element (BGP_NODE, &no_neighbor_advertise_interval_cmd); +  install_element (BGP_NODE, &no_neighbor_advertise_interval_val_cmd); + +  /* "neighbor version" commands. */ +  install_element (BGP_NODE, &neighbor_version_cmd); +  install_element (BGP_NODE, &no_neighbor_version_cmd); + +  /* "neighbor interface" commands. */ +  install_element (BGP_NODE, &neighbor_interface_cmd); +  install_element (BGP_NODE, &no_neighbor_interface_cmd); + +  /* "neighbor distribute" commands. */ +  install_element (BGP_NODE, &neighbor_distribute_list_cmd); +  install_element (BGP_NODE, &no_neighbor_distribute_list_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_distribute_list_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd); + +  /* "neighbor prefix-list" commands. */ +  install_element (BGP_NODE, &neighbor_prefix_list_cmd); +  install_element (BGP_NODE, &no_neighbor_prefix_list_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_prefix_list_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd); + +  /* "neighbor filter-list" commands. */ +  install_element (BGP_NODE, &neighbor_filter_list_cmd); +  install_element (BGP_NODE, &no_neighbor_filter_list_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_filter_list_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd); + +  /* "neighbor route-map" commands. */ +  install_element (BGP_NODE, &neighbor_route_map_cmd); +  install_element (BGP_NODE, &no_neighbor_route_map_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_route_map_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd); + +  /* "neighbor unsuppress-map" commands. */ +  install_element (BGP_NODE, &neighbor_unsuppress_map_cmd); +  install_element (BGP_NODE, &no_neighbor_unsuppress_map_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_unsuppress_map_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd); + +  /* "neighbor maximum-prefix" commands. */ +  install_element (BGP_NODE, &neighbor_maximum_prefix_cmd); +  install_element (BGP_NODE, &neighbor_maximum_prefix_warning_cmd); +  install_element (BGP_NODE, &no_neighbor_maximum_prefix_cmd); +  install_element (BGP_NODE, &no_neighbor_maximum_prefix_val_cmd); +  install_element (BGP_NODE, &no_neighbor_maximum_prefix_val2_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_warning_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val2_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_warning_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val2_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val2_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val2_cmd); + +  /* "neighbor allowas-in" */ +  install_element (BGP_NODE, &neighbor_allowas_in_cmd); +  install_element (BGP_NODE, &neighbor_allowas_in_arg_cmd); +  install_element (BGP_NODE, &no_neighbor_allowas_in_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_allowas_in_cmd); +  install_element (BGP_IPV4_NODE, &neighbor_allowas_in_arg_cmd); +  install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd); +  install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_arg_cmd); +  install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd); +  install_element (BGP_IPV6_NODE, &neighbor_allowas_in_arg_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd); +  install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_arg_cmd); +  install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd); + +  /* address-family commands. */ +  install_element (BGP_NODE, &address_family_ipv4_cmd); +  install_element (BGP_NODE, &address_family_ipv4_safi_cmd); +#ifdef HAVE_IPV6 +  install_element (BGP_NODE, &address_family_ipv6_cmd); +  install_element (BGP_NODE, &address_family_ipv6_unicast_cmd); +#endif /* HAVE_IPV6 */ +  install_element (BGP_NODE, &address_family_vpnv4_cmd); +  install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd); + +  /* "exit-address-family" command. */ +  install_element (BGP_IPV4_NODE, &exit_address_family_cmd); +  install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); +  install_element (BGP_IPV6_NODE, &exit_address_family_cmd); +  install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); + +  /* "clear ip bgp commands" */ +  install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_cmd); +#ifdef HAVE_IPV6 +  install_element (ENABLE_NODE, &clear_bgp_all_cmd); +  install_element (ENABLE_NODE, &clear_bgp_instance_all_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_group_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_cmd); +  install_element (ENABLE_NODE, &clear_bgp_external_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_cmd); +  install_element (ENABLE_NODE, &clear_bgp_as_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_cmd); +#endif /* HAVE_IPV6 */ + +  /* "clear ip bgp neighbor soft in" */ +  install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_in_cmd); +#ifdef HAVE_IPV6 +  install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_all_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_all_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_group_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_group_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_bgp_external_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_external_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_external_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_bgp_as_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_as_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_as_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_prefix_filter_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd); +#endif /* HAVE_IPV6 */ + +  /* "clear ip bgp neighbor soft out" */ +  install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_out_cmd); +#ifdef HAVE_IPV6 +  install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_all_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_group_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_external_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_external_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_as_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_as_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_out_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_out_cmd); +#endif /* HAVE_IPV6 */ + +  /* "clear ip bgp neighbor soft" */ +  install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_cmd); +#ifdef HAVE_IPV6 +  install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd); +  install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_soft_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_cmd); +  install_element (ENABLE_NODE, &clear_bgp_external_soft_cmd); +  install_element (ENABLE_NODE, &clear_bgp_as_soft_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd); +#endif /* HAVE_IPV6 */ + +  /* "show ip bgp summary" commands. */ +  install_element (VIEW_NODE, &show_ip_bgp_summary_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); +#ifdef HAVE_IPV6 +  install_element (VIEW_NODE, &show_bgp_summary_cmd); +  install_element (VIEW_NODE, &show_bgp_instance_summary_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd); +  install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd); +#endif /* HAVE_IPV6 */ +  install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); +#ifdef HAVE_IPV6 +  install_element (ENABLE_NODE, &show_bgp_summary_cmd); +  install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd); +  install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd); +#endif /* HAVE_IPV6 */ + +  /* "show ip bgp neighbors" commands. */ +  install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_neighbors_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_neighbors_peer_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); + +#ifdef HAVE_IPV6 +  install_element (VIEW_NODE, &show_bgp_neighbors_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd); +  install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd); +  install_element (ENABLE_NODE, &show_bgp_neighbors_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_cmd); +  install_element (ENABLE_NODE, &show_bgp_neighbors_peer_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_peer_cmd); + +  /* Old commands.  */ +  install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd); +  install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd); +  install_element (ENABLE_NODE, &show_ipv6_bgp_summary_cmd); +  install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd); +#endif /* HAVE_IPV6 */ + +  /* "show ip bgp paths" commands. */ +  install_element (VIEW_NODE, &show_ip_bgp_paths_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_paths_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_paths_cmd); + +  /* "show ip bgp community" commands. */ +  install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_community_info_cmd); + +  /* "show ip bgp attribute-info" commands. */ +  install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_attr_info_cmd); + +  /* "redistribute" commands.  */ +  install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd); +  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_cmd); +  install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_cmd); +  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_cmd); +  install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_cmd); +  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_cmd); +  install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd); +  install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd); +  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd); +  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd); +#ifdef HAVE_IPV6 +  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_cmd); +  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_cmd); +  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_cmd); +  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_cmd); +  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd); +  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_cmd); +  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd); +  install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd); +  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_metric_cmd); +  install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd); +#endif /* HAVE_IPV6 */ + +  /* Community-list. */ +  community_list_vty (); +} + +#include "memory.h" +#include "bgp_regex.h" +#include "bgp_clist.h" +#include "bgp_ecommunity.h" + +/* VTY functions.  */ + +/* Direction value to string conversion.  */ +char * +community_direct_str (int direct) +{ +  switch (direct) +    { +    case COMMUNITY_DENY: +      return "deny"; +      break; +    case COMMUNITY_PERMIT: +      return "permit"; +      break; +    default: +      return "unknown"; +      break; +    } +} + +/* Display error string.  */ +void +community_list_perror (struct vty *vty, int ret) +{ +  switch (ret) +    { +    case COMMUNITY_LIST_ERR_CANT_FIND_LIST: +      vty_out (vty, "%% Can't find communit-list%s", VTY_NEWLINE); +      break; +    case COMMUNITY_LIST_ERR_MALFORMED_VAL: +      vty_out (vty, "%% Malformed community-list value%s", VTY_NEWLINE); +      break; +    case COMMUNITY_LIST_ERR_STANDARD_CONFLICT: +      vty_out (vty, "%% Community name conflict, previously defined as standard community%s", VTY_NEWLINE); +      break; +    case COMMUNITY_LIST_ERR_EXPANDED_CONFLICT: +      vty_out (vty, "%% Community name conflict, previously defined as expanded community%s", VTY_NEWLINE); +      break; +    } +} + +/* VTY interface for community_set() function.  */ +int +community_list_set_vty (struct vty *vty, int argc, char **argv, int style, +			int reject_all_digit_name) +{ +  int ret; +  int direct; +  char *str; + +  /* Check the list type. */ +  if (strncmp (argv[1], "p", 1) == 0) +    direct = COMMUNITY_PERMIT; +  else if (strncmp (argv[1], "d", 1) == 0) +    direct = COMMUNITY_DENY; +  else +    { +      vty_out (vty, "%% Matching condition must be permit or deny%s", +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* All digit name check.  */ +  if (reject_all_digit_name && all_digit (argv[0])) +    { +      vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* Concat community string argument.  */ +  if (argc > 1) +    str = argv_concat (argv, argc, 2); +  else +    str = NULL; + +  /* When community_list_set() return nevetive value, it means +     malformed community string.  */ +  ret = community_list_set (bgp_clist, argv[0], str, direct, style); + +  /* Free temporary community list string allocated by +     argv_concat().  */ +  if (str) +    XFREE (MTYPE_TMP, str); + +  if (ret < 0) +    { +      /* Display error string.  */ +      community_list_perror (vty, ret); +      return CMD_WARNING; +    } + +  return CMD_SUCCESS; +} + +/* Community-list delete with name.  */ +int +community_list_unset_all_vty (struct vty *vty, char *name) +{ +  int ret; + +  ret = community_list_unset (bgp_clist, name, NULL, 0, COMMUNITY_LIST_AUTO); + +  if (ret < 0) +    { +      community_list_perror (vty, ret); +      return CMD_WARNING; +    } +  return CMD_SUCCESS; +} + +/* Communiyt-list entry delete.  */ +int +community_list_unset_vty (struct vty *vty, int argc, char **argv, int style) +{ +  int ret; +  int direct; +  char *str; + +  /* Check the list direct. */ +  if (strncmp (argv[1], "p", 1) == 0) +    direct = COMMUNITY_PERMIT; +  else if (strncmp (argv[1], "d", 1) == 0) +    direct = COMMUNITY_DENY; +  else +    { +      vty_out (vty, "%% Matching condition must be permit or deny%s", +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* Concat community string argument.  */ +  str = argv_concat (argv, argc, 2); + +  /* Unset community list.  */ +  ret = community_list_unset (bgp_clist, argv[0], str, direct, style); + +  /* Free temporary community list string allocated by +     argv_concat().  */ +  XFREE (MTYPE_TMP, str); + +  if (ret < 0) +    { +      community_list_perror (vty, ret); +      return CMD_WARNING; +    } + +  return CMD_SUCCESS; +} + +/* "community-list" keyword help string.  */ +#define COMMUNITY_LIST_STR "Add a community list entry\n" +#define COMMUNITY_VAL_STR  "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n" + +DEFUN (ip_community_list, +       ip_community_list_cmd, +       "ip community-list WORD (deny|permit) .AA:NN", +       IP_STR +       COMMUNITY_LIST_STR +       "Community list name\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       COMMUNITY_VAL_STR) +{ +  return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_AUTO, 1); +} + +DEFUN (ip_community_list_standard, +       ip_community_list_standard_cmd, +       "ip community-list <1-99> (deny|permit) .AA:NN", +       IP_STR +       COMMUNITY_LIST_STR +       "Community list number (standard)\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       COMMUNITY_VAL_STR) +{ +  return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD, 0); +} + +ALIAS (ip_community_list_standard, +       ip_community_list_standard2_cmd, +       "ip community-list <1-99> (deny|permit)", +       IP_STR +       COMMUNITY_LIST_STR +       "Community list number (standard)\n" +       "Specify community to reject\n" +       "Specify community to accept\n") + +DEFUN (ip_community_list_expanded, +       ip_community_list_expanded_cmd, +       "ip community-list <100-199> (deny|permit) .LINE", +       IP_STR +       COMMUNITY_LIST_STR +       "Community list number (expanded)\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       "An ordered list as a regular-expression\n") +{ +  return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED, 0); +} + +DEFUN (ip_community_list_name_standard, +       ip_community_list_name_standard_cmd, +       "ip community-list standard WORD (deny|permit) .AA:NN", +       IP_STR +       COMMUNITY_LIST_STR +       "Add a standard community-list entry\n" +       "Community list name\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       COMMUNITY_VAL_STR) +{ +  return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD, 1); +} + +ALIAS (ip_community_list_name_standard, +       ip_community_list_name_standard2_cmd, +       "ip community-list standard WORD (deny|permit)", +       IP_STR +       COMMUNITY_LIST_STR +       "Add a standard community-list entry\n" +       "Community list name\n" +       "Specify community to reject\n" +       "Specify community to accept\n") + +DEFUN (ip_community_list_name_expanded, +       ip_community_list_name_expanded_cmd, +       "ip community-list expanded WORD (deny|permit) .LINE", +       IP_STR +       COMMUNITY_LIST_STR +       "Add an expanded community-list entry\n" +       "Community list name\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       "An ordered list as a regular-expression\n") +{ +  return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED, 1); +} + +DEFUN (no_ip_community_list_all, +       no_ip_community_list_all_cmd, +       "no ip community-list (WORD|<1-99>|<100-199>)", +       NO_STR +       IP_STR +       COMMUNITY_LIST_STR +       "Community list name\n" +       "Community list number (standard)\n" +       "Community list number (expanded)\n") +{ +  return community_list_unset_all_vty (vty, argv[0]); +} + +DEFUN (no_ip_community_list_name_all, +       no_ip_community_list_name_all_cmd, +       "no ip community-list (standard|expanded) WORD", +       NO_STR +       IP_STR +       COMMUNITY_LIST_STR +       "Add a standard community-list entry\n" +       "Add an expanded community-list entry\n" +       "Community list name\n") +{ +  return community_list_unset_all_vty (vty, argv[1]); +} + +DEFUN (no_ip_community_list, +       no_ip_community_list_cmd, +       "no ip community-list WORD (deny|permit) .AA:NN", +       NO_STR +       IP_STR +       COMMUNITY_LIST_STR +       "Community list name\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       COMMUNITY_VAL_STR) +{ +  return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_AUTO); +} + +DEFUN (no_ip_community_list_standard, +       no_ip_community_list_standard_cmd, +       "no ip community-list <1-99> (deny|permit) .AA:NN", +       NO_STR +       IP_STR +       COMMUNITY_LIST_STR +       "Community list number (standard)\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       COMMUNITY_VAL_STR) +{ +  return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_community_list_expanded, +       no_ip_community_list_expanded_cmd, +       "no ip community-list <100-199> (deny|permit) .LINE", +       NO_STR +       IP_STR +       COMMUNITY_LIST_STR +       "Community list number (expanded)\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       "An ordered list as a regular-expression\n") +{ +  return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_community_list_name_standard, +       no_ip_community_list_name_standard_cmd, +       "no ip community-list standard WORD (deny|permit) .AA:NN", +       NO_STR +       IP_STR +       COMMUNITY_LIST_STR +       "Specify a standard community-list\n" +       "Community list name\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       COMMUNITY_VAL_STR) +{ +  return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_community_list_name_expanded, +       no_ip_community_list_name_expanded_cmd, +       "no ip community-list expanded WORD (deny|permit) .LINE", +       NO_STR +       IP_STR +       COMMUNITY_LIST_STR +       "Specify an expanded community-list\n" +       "Community list name\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       "An ordered list as a regular-expression\n") +{ +  return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED); +} + +void +community_list_show (struct vty *vty, struct community_list *list) +{ +  struct community_entry *entry; + +  for (entry = list->head; entry; entry = entry->next) +    { +      if (entry == list->head) +	{ +	  if (all_digit (list->name)) +	    vty_out (vty, "Community %s list %s%s", +		     entry->style == COMMUNITY_LIST_STANDARD ? +		     "standard" : "(expanded) access", +		     list->name, VTY_NEWLINE); +	  else +	    vty_out (vty, "Named Community %s list %s%s", +		     entry->style == COMMUNITY_LIST_STANDARD ? +		     "standard" : "expanded", +		     list->name, VTY_NEWLINE); +	} +      if (entry->any) +	vty_out (vty, "    %s%s", +		 community_direct_str (entry->direct), VTY_NEWLINE); +      else +	vty_out (vty, "    %s %s%s", +		 community_direct_str (entry->direct), +		 entry->style == COMMUNITY_LIST_STANDARD +		 ? community_str (entry->u.com) : entry->config, +		 VTY_NEWLINE); +    } +} + +DEFUN (show_ip_community_list, +       show_ip_community_list_cmd, +       "show ip community-list", +       SHOW_STR +       IP_STR +       "List community-list\n") +{ +  struct community_list *list; +  struct community_list_master *cm; + +  cm = community_list_master_lookup (bgp_clist, COMMUNITY_LIST_AUTO); +  if (! cm) +    return CMD_SUCCESS; + +  for (list = cm->num.head; list; list = list->next) +    community_list_show (vty, list); + +  for (list = cm->str.head; list; list = list->next) +    community_list_show (vty, list); + +  return CMD_SUCCESS; +} + +DEFUN (show_ip_community_list_arg, +       show_ip_community_list_arg_cmd, +       "show ip community-list (<1-199>|WORD)", +       SHOW_STR +       IP_STR +       "List community-list\n" +       "Community-list number\n" +       "Community-list name\n") +{ +  struct community_list *list; + +  list = community_list_lookup (bgp_clist, argv[0], COMMUNITY_LIST_AUTO); +  if (! list) +    { +      vty_out (vty, "%% Can't find communit-list%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  community_list_show (vty, list); + +  return CMD_SUCCESS; +} + +int +extcommunity_list_set_vty (struct vty *vty, int argc, char **argv, int style, +			   int reject_all_digit_name) +{ +  int ret; +  int direct; +  char *str; + +  /* Check the list type. */ +  if (strncmp (argv[1], "p", 1) == 0) +    direct = COMMUNITY_PERMIT; +  else if (strncmp (argv[1], "d", 1) == 0) +    direct = COMMUNITY_DENY; +  else +    { +      vty_out (vty, "%% Matching condition must be permit or deny%s", +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* All digit name check.  */ +  if (reject_all_digit_name && all_digit (argv[0])) +    { +      vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* Concat community string argument.  */ +  if (argc > 1) +    str = argv_concat (argv, argc, 2); +  else +    str = NULL; + +  ret = extcommunity_list_set (bgp_clist, argv[0], str, direct, style); + +  /* Free temporary community list string allocated by +     argv_concat().  */ +  if (str) +    XFREE (MTYPE_TMP, str); + +  if (ret < 0) +    { +      community_list_perror (vty, ret); +      return CMD_WARNING; +    } +  return CMD_SUCCESS; +} + +int +extcommunity_list_unset_all_vty (struct vty *vty, char *name) +{ +  int ret; + +  ret = extcommunity_list_unset (bgp_clist, name, NULL, 0, EXTCOMMUNITY_LIST_AUTO); + +  if (ret < 0) +    { +      community_list_perror (vty, ret); +      return CMD_WARNING; +    } +  return CMD_SUCCESS; +} + +int +extcommunity_list_unset_vty (struct vty *vty, int argc, char **argv, int style) +{ +  int ret; +  int direct; +  char *str; + +  /* Check the list direct. */ +  if (strncmp (argv[1], "p", 1) == 0) +    direct = COMMUNITY_PERMIT; +  else if (strncmp (argv[1], "d", 1) == 0) +    direct = COMMUNITY_DENY; +  else +    { +      vty_out (vty, "%% Matching condition must be permit or deny%s", +	       VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* Concat community string argument.  */ +  str = argv_concat (argv, argc, 2); + +  /* Unset community list.  */ +  ret = extcommunity_list_unset (bgp_clist, argv[0], str, direct, style); + +  /* Free temporary community list string allocated by +     argv_concat().  */ +  XFREE (MTYPE_TMP, str); + +  if (ret < 0) +    { +      community_list_perror (vty, ret); +      return CMD_WARNING; +    } + +  return CMD_SUCCESS; +} + +/* "extcommunity-list" keyword help string.  */ +#define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n" +#define EXTCOMMUNITY_VAL_STR  "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n" + +DEFUN (ip_extcommunity_list_standard, +       ip_extcommunity_list_standard_cmd, +       "ip extcommunity-list <1-99> (deny|permit) .AA:NN", +       IP_STR +       EXTCOMMUNITY_LIST_STR +       "Extended Community list number (standard)\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       EXTCOMMUNITY_VAL_STR) +{ +  return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD, 0); +} + +ALIAS (ip_extcommunity_list_standard, +       ip_extcommunity_list_standard2_cmd, +       "ip extcommunity-list <1-99> (deny|permit)", +       IP_STR +       EXTCOMMUNITY_LIST_STR +       "Extended Community list number (standard)\n" +       "Specify community to reject\n" +       "Specify community to accept\n") + +DEFUN (ip_extcommunity_list_expanded, +       ip_extcommunity_list_expanded_cmd, +       "ip extcommunity-list <100-199> (deny|permit) .LINE", +       IP_STR +       EXTCOMMUNITY_LIST_STR +       "Extended Community list number (expanded)\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       "An ordered list as a regular-expression\n") +{ +  return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED, 0); +} + +DEFUN (ip_extcommunity_list_name_standard, +       ip_extcommunity_list_name_standard_cmd, +       "ip extcommunity-list standard WORD (deny|permit) .AA:NN", +       IP_STR +       EXTCOMMUNITY_LIST_STR +       "Specify standard extcommunity-list\n" +       "Extended Community list name\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       EXTCOMMUNITY_VAL_STR) +{ +  return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD, 1); +} + +ALIAS (ip_extcommunity_list_name_standard, +       ip_extcommunity_list_name_standard2_cmd, +       "ip extcommunity-list standard WORD (deny|permit)", +       IP_STR +       EXTCOMMUNITY_LIST_STR +       "Specify standard extcommunity-list\n" +       "Extended Community list name\n" +       "Specify community to reject\n" +       "Specify community to accept\n") + +DEFUN (ip_extcommunity_list_name_expanded, +       ip_extcommunity_list_name_expanded_cmd, +       "ip extcommunity-list expanded WORD (deny|permit) .LINE", +       IP_STR +       EXTCOMMUNITY_LIST_STR +       "Specify expanded extcommunity-list\n" +       "Extended Community list name\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       "An ordered list as a regular-expression\n") +{ +  return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED, 1); +} + +DEFUN (no_ip_extcommunity_list_all, +       no_ip_extcommunity_list_all_cmd, +       "no ip extcommunity-list (<1-99>|<100-199>)", +       NO_STR +       IP_STR +       EXTCOMMUNITY_LIST_STR +       "Extended Community list number (standard)\n" +       "Extended Community list number (expanded)\n") +{ +  return extcommunity_list_unset_all_vty (vty, argv[0]); +} + +DEFUN (no_ip_extcommunity_list_name_all, +       no_ip_extcommunity_list_name_all_cmd, +       "no ip extcommunity-list (standard|expanded) WORD", +       NO_STR +       IP_STR +       EXTCOMMUNITY_LIST_STR +       "Specify standard extcommunity-list\n" +       "Specify expanded extcommunity-list\n" +       "Extended Community list name\n") +{ +  return extcommunity_list_unset_all_vty (vty, argv[1]); +} + +DEFUN (no_ip_extcommunity_list_standard, +       no_ip_extcommunity_list_standard_cmd, +       "no ip extcommunity-list <1-99> (deny|permit) .AA:NN", +       NO_STR +       IP_STR +       EXTCOMMUNITY_LIST_STR +       "Extended Community list number (standard)\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       EXTCOMMUNITY_VAL_STR) +{ +  return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_extcommunity_list_expanded, +       no_ip_extcommunity_list_expanded_cmd, +       "no ip extcommunity-list <100-199> (deny|permit) .LINE", +       NO_STR +       IP_STR +       EXTCOMMUNITY_LIST_STR +       "Extended Community list number (expanded)\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       "An ordered list as a regular-expression\n") +{ +  return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_extcommunity_list_name_standard, +       no_ip_extcommunity_list_name_standard_cmd, +       "no ip extcommunity-list standard WORD (deny|permit) .AA:NN", +       NO_STR +       IP_STR +       EXTCOMMUNITY_LIST_STR +       "Specify standard extcommunity-list\n" +       "Extended Community list name\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       EXTCOMMUNITY_VAL_STR) +{ +  return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_extcommunity_list_name_expanded, +       no_ip_extcommunity_list_name_expanded_cmd, +       "no ip extcommunity-list expanded WORD (deny|permit) .LINE", +       NO_STR +       IP_STR +       EXTCOMMUNITY_LIST_STR +       "Specify expanded extcommunity-list\n" +       "Community list name\n" +       "Specify community to reject\n" +       "Specify community to accept\n" +       "An ordered list as a regular-expression\n") +{ +  return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED); +} + +void +extcommunity_list_show (struct vty *vty, struct community_list *list) +{ +  struct community_entry *entry; + +  for (entry = list->head; entry; entry = entry->next) +    { +      if (entry == list->head) +	{ +	  if (all_digit (list->name)) +	    vty_out (vty, "Extended community %s list %s%s", +		     entry->style == EXTCOMMUNITY_LIST_STANDARD ? +		     "standard" : "(expanded) access", +		     list->name, VTY_NEWLINE); +	  else +	    vty_out (vty, "Named extended community %s list %s%s", +		     entry->style == EXTCOMMUNITY_LIST_STANDARD ? +		     "standard" : "expanded", +		     list->name, VTY_NEWLINE); +	} +      if (entry->any) +	vty_out (vty, "    %s%s", +		 community_direct_str (entry->direct), VTY_NEWLINE); +      else +	vty_out (vty, "    %s %s%s", +		 community_direct_str (entry->direct), +		 entry->style == EXTCOMMUNITY_LIST_STANDARD ? +		 entry->u.ecom->str : entry->config, +		 VTY_NEWLINE); +    } +} + +DEFUN (show_ip_extcommunity_list, +       show_ip_extcommunity_list_cmd, +       "show ip extcommunity-list", +       SHOW_STR +       IP_STR +       "List extended-community list\n") +{ +  struct community_list *list; +  struct community_list_master *cm; + +  cm = community_list_master_lookup (bgp_clist, EXTCOMMUNITY_LIST_AUTO); +  if (! cm) +    return CMD_SUCCESS; + +  for (list = cm->num.head; list; list = list->next) +    extcommunity_list_show (vty, list); + +  for (list = cm->str.head; list; list = list->next) +    extcommunity_list_show (vty, list); + +  return CMD_SUCCESS; +} + +DEFUN (show_ip_extcommunity_list_arg, +       show_ip_extcommunity_list_arg_cmd, +       "show ip extcommunity-list (<1-199>|WORD)", +       SHOW_STR +       IP_STR +       "List extended-community list\n" +       "Extcommunity-list number\n" +       "Extcommunity-list name\n") +{ +  struct community_list *list; + +  list = community_list_lookup (bgp_clist, argv[0], EXTCOMMUNITY_LIST_AUTO); +  if (! list) +    { +      vty_out (vty, "%% Can't find extcommunit-list%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  extcommunity_list_show (vty, list); + +  return CMD_SUCCESS; +} + +/* Return configuration string of community-list entry.  */ +static char * +community_list_config_str (struct community_entry *entry) +{ +  char *str; + +  if (entry->any) +    str = ""; +  else +    { +      if (entry->style == COMMUNITY_LIST_STANDARD) +	str = community_str (entry->u.com); +      else +	str = entry->config; +    } +  return str; +} + +/* Display community-list and extcommunity-list configuration.  */ +int +community_list_config_write (struct vty *vty) +{ +  struct community_list *list; +  struct community_entry *entry; +  struct community_list_master *cm; +  int write = 0; + +  /* Community-list.  */ +  cm = community_list_master_lookup (bgp_clist, COMMUNITY_LIST_AUTO); + +  for (list = cm->num.head; list; list = list->next) +    for (entry = list->head; entry; entry = entry->next) +      { +	if (atol (list->name) < 200) +	  vty_out (vty, "ip community-list %s %s %s%s", +		   list->name, community_direct_str (entry->direct), +		   community_list_config_str (entry), +		   VTY_NEWLINE); +	else +	  vty_out (vty, "ip community-list %s %s %s %s%s", +		   entry->style == COMMUNITY_LIST_STANDARD +		   ? "standard" : "expanded", +		   list->name, community_direct_str (entry->direct), +		   community_list_config_str (entry), +		   VTY_NEWLINE); +	write++; +      } +  for (list = cm->str.head; list; list = list->next) +    for (entry = list->head; entry; entry = entry->next) +      { +	vty_out (vty, "ip community-list %s %s %s %s%s", +		 entry->style == COMMUNITY_LIST_STANDARD +		 ? "standard" : "expanded", +		 list->name, community_direct_str (entry->direct), +		 community_list_config_str (entry), +		 VTY_NEWLINE); +	write++; +      } + +  /* Extcommunity-list.  */ +  cm = community_list_master_lookup (bgp_clist, EXTCOMMUNITY_LIST_AUTO); + +  for (list = cm->num.head; list; list = list->next) +    for (entry = list->head; entry; entry = entry->next) +      { +	if (atol (list->name) < 200) +	  vty_out (vty, "ip extcommunity-list %s %s %s%s", +		   list->name, community_direct_str (entry->direct), +		   community_list_config_str (entry), VTY_NEWLINE); +	else +	  vty_out (vty, "ip extcommunity-list %s %s %s %s%s", +		   entry->style == EXTCOMMUNITY_LIST_STANDARD +		   ? "standard" : "expanded", +		   list->name, community_direct_str (entry->direct), +		   community_list_config_str (entry), VTY_NEWLINE); +	write++; +      } +  for (list = cm->str.head; list; list = list->next) +    for (entry = list->head; entry; entry = entry->next) +      { +	vty_out (vty, "ip extcommunity-list %s %s %s %s%s", +		 entry->style == EXTCOMMUNITY_LIST_STANDARD +		 ? "standard" : "expanded", +		 list->name, community_direct_str (entry->direct), +		 community_list_config_str (entry), VTY_NEWLINE); +	write++; +      } +  return write; +} + +struct cmd_node community_list_node = +{ +  COMMUNITY_LIST_NODE, +  "", +  1				/* Export to vtysh.  */ +}; + +void +community_list_vty () +{ +  install_node (&community_list_node, community_list_config_write); + +  /* Community-list.  */ +  install_element (CONFIG_NODE, &ip_community_list_cmd); +  install_element (CONFIG_NODE, &ip_community_list_standard_cmd); +  install_element (CONFIG_NODE, &ip_community_list_standard2_cmd); +  install_element (CONFIG_NODE, &ip_community_list_expanded_cmd); +  install_element (CONFIG_NODE, &ip_community_list_name_standard_cmd); +  install_element (CONFIG_NODE, &ip_community_list_name_standard2_cmd); +  install_element (CONFIG_NODE, &ip_community_list_name_expanded_cmd); +  install_element (CONFIG_NODE, &no_ip_community_list_all_cmd); +  install_element (CONFIG_NODE, &no_ip_community_list_name_all_cmd); +  install_element (CONFIG_NODE, &no_ip_community_list_cmd); +  install_element (CONFIG_NODE, &no_ip_community_list_standard_cmd); +  install_element (CONFIG_NODE, &no_ip_community_list_expanded_cmd); +  install_element (CONFIG_NODE, &no_ip_community_list_name_standard_cmd); +  install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_cmd); +  install_element (VIEW_NODE, &show_ip_community_list_cmd); +  install_element (VIEW_NODE, &show_ip_community_list_arg_cmd); +  install_element (ENABLE_NODE, &show_ip_community_list_cmd); +  install_element (ENABLE_NODE, &show_ip_community_list_arg_cmd); + +  /* Extcommunity-list.  */ +  install_element (CONFIG_NODE, &ip_extcommunity_list_standard_cmd); +  install_element (CONFIG_NODE, &ip_extcommunity_list_standard2_cmd); +  install_element (CONFIG_NODE, &ip_extcommunity_list_expanded_cmd); +  install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard_cmd); +  install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard2_cmd); +  install_element (CONFIG_NODE, &ip_extcommunity_list_name_expanded_cmd); +  install_element (CONFIG_NODE, &no_ip_extcommunity_list_all_cmd); +  install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_all_cmd); +  install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_cmd); +  install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_cmd); +  install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_cmd); +  install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd); +  install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd); +  install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd); +  install_element (ENABLE_NODE, &show_ip_extcommunity_list_cmd); +  install_element (ENABLE_NODE, &show_ip_extcommunity_list_arg_cmd); +} diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h new file mode 100644 index 0000000000..15ad58105a --- /dev/null +++ b/bgpd/bgp_vty.h @@ -0,0 +1,21 @@ +/* BGP VTY interface. +   Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +void bgp_vty_init (); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c new file mode 100644 index 0000000000..3e5cdd2a13 --- /dev/null +++ b/bgpd/bgp_zebra.c @@ -0,0 +1,1001 @@ +/* zebra client +   Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA.  */ + +#include <zebra.h> + +#include "command.h" +#include "stream.h" +#include "network.h" +#include "prefix.h" +#include "log.h" +#include "sockunion.h" +#include "zclient.h" +#include "routemap.h" +#include "thread.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_zebra.h" +#include "bgpd/bgp_fsm.h" + +/* All information about zebra. */ +static struct zclient *zclient = NULL; + +/* Update default router id. */ +int +bgp_if_update (struct interface *ifp) +{ +  struct bgp *bgp; +  listnode cn; +  struct listnode *nn; +  struct listnode *nm; +  struct peer *peer; + +  for (cn = listhead (ifp->connected); cn; nextnode (cn)) +    { +      struct connected *co; +      struct in_addr addr; + +      co = getdata (cn); + +      if (co->address->family == AF_INET) +	{ +	  addr = co->address->u.prefix4; + +	  /* Ignore NET127. */ +	  if (IPV4_NET127 (ntohl (addr.s_addr))) +	    continue; + +	  LIST_LOOP (bm->bgp, bgp, nn) +	    { +	      /* Respect configured router id */ +	      if (! (bgp->config & BGP_CONFIG_ROUTER_ID)) +		if (ntohl (bgp->router_id.s_addr) < ntohl (addr.s_addr)) +		  { +		    bgp->router_id = addr; +		    LIST_LOOP (bgp->peer, peer, nm) +		      { +			peer->local_id = addr; +		      } +		  } +	    } +	} +    } +  return 0; +} + +int +bgp_if_update_all () +{ +  listnode node; +  struct interface *ifp; + +  for (node = listhead (iflist); node; node = nextnode (node)) +    { +      ifp = getdata (node); +      bgp_if_update (ifp); +    } +  return 0; +} + +/* Inteface addition message from zebra. */ +int +bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length) +{ +  struct interface *ifp; + +  ifp = zebra_interface_add_read (zclient->ibuf); +  bgp_if_update (ifp); + +  return 0; +} + +int +bgp_interface_delete (int command, struct zclient *zclient, +		      zebra_size_t length) +{ +  struct stream *s; +  struct interface *ifp; + +  s = zclient->ibuf; +  ifp = zebra_interface_state_read (s); + +  return 0; +} + +int +bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length) +{ +  struct stream *s; +  struct interface *ifp; +  struct connected *c; +  listnode node; + +  s = zclient->ibuf; +  ifp = zebra_interface_state_read (s); + +  if (! ifp) +    return 0; + +  for (node = listhead (ifp->connected); node; nextnode (node)) +    { +      c = getdata (node); +      bgp_connected_add (c); +    } + +  return 0; +} + +int +bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) +{ +  struct stream *s; +  struct interface *ifp; +  struct connected *c; +  listnode node; + +  s = zclient->ibuf; +  ifp = zebra_interface_state_read (s); +  if (! ifp) +    return 0; + +  for (node = listhead (ifp->connected); node; nextnode (node)) +    { +      c = getdata (node); +      bgp_connected_delete (c); +    } + +  /* Fast external-failover (Currently IPv4 only) */ +  { +    struct listnode *nn, *nm; +    struct bgp *bgp; +    struct peer *peer; +    struct interface *peer_if; + +    LIST_LOOP (bm->bgp, bgp, nn) +      { +	if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) +	  continue; + +	LIST_LOOP (bgp->peer, peer, nm) +	  { +	    if (peer->ttl != 1) +	      continue; + +	    if (peer->su.sa.sa_family == AF_INET) +	      peer_if = if_lookup_by_ipv4 (&peer->su.sin.sin_addr); +	    else +	      continue; + +	    if (ifp == peer_if) +	      BGP_EVENT_ADD (peer, BGP_Stop); +	  } +      } +  } + +  return 0; +} + +int +bgp_interface_address_add (int command, struct zclient *zclient, +			   zebra_size_t length) +{ +  struct connected *ifc; + +  ifc = zebra_interface_address_add_read (zclient->ibuf); + +  if (ifc == NULL) +    return 0; + +  bgp_if_update (ifc->ifp); + +  if (if_is_up (ifc->ifp)) +    bgp_connected_add (ifc); + +  return 0; +} + +int +bgp_interface_address_delete (int command, struct zclient *zclient, +			      zebra_size_t length) +{ +  struct connected *ifc; + +  ifc = zebra_interface_address_delete_read (zclient->ibuf); + +  if (ifc == NULL) +    return 0; + +  bgp_if_update (ifc->ifp); + +  if (if_is_up (ifc->ifp)) +    bgp_connected_delete (ifc); + +  connected_free (ifc); + +  return 0; +} + +/* Zebra route add and delete treatment. */ +int +zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) +{ +  struct stream *s; +  struct zapi_ipv4 api; +  unsigned long ifindex; +  struct in_addr nexthop; +  struct prefix_ipv4 p; + +  s = zclient->ibuf; +  ifindex = 0; +  nexthop.s_addr = 0; + +  /* Type, flags, message. */ +  api.type = stream_getc (s); +  api.flags = stream_getc (s); +  api.message = stream_getc (s); + +  /* IPv4 prefix. */ +  memset (&p, 0, sizeof (struct prefix_ipv4)); +  p.family = AF_INET; +  p.prefixlen = stream_getc (s); +  stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + +  /* Nexthop, ifindex, distance, metric. */ +  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) +    { +      api.nexthop_num = stream_getc (s); +      nexthop.s_addr = stream_get_ipv4 (s); +    } +  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) +    { +      api.ifindex_num = stream_getc (s); +      ifindex = stream_getl (s); +    } +  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) +    api.distance = stream_getc (s); +  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) +    api.metric = stream_getl (s); +  else +    api.metric = 0; + +  if (command == ZEBRA_IPV4_ROUTE_ADD) +    bgp_redistribute_add ((struct prefix *)&p, &nexthop, api.metric, api.type); +  else +    bgp_redistribute_delete ((struct prefix *)&p, api.type); + +  return 0; +} + +#ifdef HAVE_IPV6 +/* Zebra route add and delete treatment. */ +int +zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) +{ +  struct stream *s; +  struct zapi_ipv6 api; +  unsigned long ifindex; +  struct in6_addr nexthop; +  struct prefix_ipv6 p; + +  s = zclient->ibuf; +  ifindex = 0; +  memset (&nexthop, 0, sizeof (struct in6_addr)); + +  /* Type, flags, message. */ +  api.type = stream_getc (s); +  api.flags = stream_getc (s); +  api.message = stream_getc (s); + +  /* IPv6 prefix. */ +  memset (&p, 0, sizeof (struct prefix_ipv6)); +  p.family = AF_INET6; +  p.prefixlen = stream_getc (s); +  stream_get (&p.prefix, s, PSIZE (p.prefixlen)); + +  /* Nexthop, ifindex, distance, metric. */ +  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) +    { +      api.nexthop_num = stream_getc (s); +      stream_get (&nexthop, s, 16); +    } +  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) +    { +      api.ifindex_num = stream_getc (s); +      ifindex = stream_getl (s); +    } +  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) +    api.distance = stream_getc (s); +  else +    api.distance = 0; +  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) +    api.metric = stream_getl (s); +  else +    api.metric = 0; + +  /* Simply ignore link-local address. */ +  if (IN6_IS_ADDR_LINKLOCAL (&p.prefix)) +    return 0; + +  if (command == ZEBRA_IPV6_ROUTE_ADD) +    bgp_redistribute_add ((struct prefix *)&p, NULL, api.metric, api.type); +  else +    bgp_redistribute_delete ((struct prefix *) &p, api.type); +   +  return 0; +} +#endif /* HAVE_IPV6 */ + +struct interface * +if_lookup_by_ipv4 (struct in_addr *addr) +{ +  listnode ifnode; +  listnode cnode; +  struct interface *ifp; +  struct connected *connected; +  struct prefix_ipv4 p; +  struct prefix *cp;  +   +  p.family = AF_INET; +  p.prefix = *addr; +  p.prefixlen = IPV4_MAX_BITLEN; + +  for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) +    { +      ifp = getdata (ifnode); + +      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) +	{ +	  connected = getdata (cnode); +	  cp = connected->address; +	     +	  if (cp->family == AF_INET) +	    if (prefix_match (cp, (struct prefix *)&p)) +	      return ifp; +	} +    } +  return NULL; +} + +struct interface * +if_lookup_by_ipv4_exact (struct in_addr *addr) +{ +  listnode ifnode; +  listnode cnode; +  struct interface *ifp; +  struct connected *connected; +  struct prefix *cp;  +   +  for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) +    { +      ifp = getdata (ifnode); + +      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) +	{ +	  connected = getdata (cnode); +	  cp = connected->address; +	     +	  if (cp->family == AF_INET) +	    if (IPV4_ADDR_SAME (&cp->u.prefix4, addr)) +	      return ifp; +	} +    } +  return NULL; +} + +#ifdef HAVE_IPV6 +struct interface * +if_lookup_by_ipv6 (struct in6_addr *addr) +{ +  listnode ifnode; +  listnode cnode; +  struct interface *ifp; +  struct connected *connected; +  struct prefix_ipv6 p; +  struct prefix *cp;  +   +  p.family = AF_INET6; +  p.prefix = *addr; +  p.prefixlen = IPV6_MAX_BITLEN; + +  for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) +    { +      ifp = getdata (ifnode); + +      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) +	{ +	  connected = getdata (cnode); +	  cp = connected->address; +	     +	  if (cp->family == AF_INET6) +	    if (prefix_match (cp, (struct prefix *)&p)) +	      return ifp; +	} +    } +  return NULL; +} + +struct interface * +if_lookup_by_ipv6_exact (struct in6_addr *addr) +{ +  listnode ifnode; +  listnode cnode; +  struct interface *ifp; +  struct connected *connected; +  struct prefix *cp;  + +  for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) +    { +      ifp = getdata (ifnode); + +      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) +	{ +	  connected = getdata (cnode); +	  cp = connected->address; +	     +	  if (cp->family == AF_INET6) +	    if (IPV6_ADDR_SAME (&cp->u.prefix6, addr)) +	      return ifp; +	} +    } +  return NULL; +} + +int +if_get_ipv6_global (struct interface *ifp, struct in6_addr *addr) +{ +  listnode cnode; +  struct connected *connected; +  struct prefix *cp;  +   +  for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) +    { +      connected = getdata (cnode); +      cp = connected->address; +	     +      if (cp->family == AF_INET6) +	if (! IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6)) +	  { +	    memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN); +	    return 1; +	  } +    } +  return 0; +} + +int +if_get_ipv6_local (struct interface *ifp, struct in6_addr *addr) +{ +  listnode cnode; +  struct connected *connected; +  struct prefix *cp;  +   +  for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) +    { +      connected = getdata (cnode); +      cp = connected->address; +	     +      if (cp->family == AF_INET6) +	if (IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6)) +	  { +	    memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN); +	    return 1; +	  } +    } +  return 0; +} +#endif /* HAVE_IPV6 */ + +int +bgp_nexthop_set (union sockunion *local, union sockunion *remote,  +		 struct bgp_nexthop *nexthop, struct peer *peer) +{ +  int ret = 0; +  struct interface *ifp = NULL; + +  memset (nexthop, 0, sizeof (struct bgp_nexthop)); + +  if (!local) +    return -1; +  if (!remote) +    return -1; + +  if (local->sa.sa_family == AF_INET) +    { +      nexthop->v4 = local->sin.sin_addr; +      ifp = if_lookup_by_ipv4 (&local->sin.sin_addr); +    } +#ifdef HAVE_IPV6 +  if (local->sa.sa_family == AF_INET6) +    { +      if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) +	{ +	  if (peer->ifname) +	    ifp = if_lookup_by_index (if_nametoindex (peer->ifname)); +	} +      else +	ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr); +    } +#endif /* HAVE_IPV6 */ + +  if (!ifp) +    return -1; + +  nexthop->ifp = ifp; + +  /* IPv4 connection. */ +  if (local->sa.sa_family == AF_INET) +    { +#ifdef HAVE_IPV6 +      /* IPv6 nexthop*/ +      ret = if_get_ipv6_global (ifp, &nexthop->v6_global); + +      /* There is no global nexthop. */ +      if (!ret) +	if_get_ipv6_local (ifp, &nexthop->v6_global); +      else +	if_get_ipv6_local (ifp, &nexthop->v6_local); +#endif /* HAVE_IPV6 */ +    } + +#ifdef HAVE_IPV6 +  /* IPv6 connection. */ +  if (local->sa.sa_family == AF_INET6) +    { +      struct interface *direct = NULL; + +      /* IPv4 nexthop.  I don't care about it. */ +      if (peer->local_id.s_addr) +	nexthop->v4 = peer->local_id; + +      /* Global address*/ +      if (! IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) +	{ +	  memcpy (&nexthop->v6_global, &local->sin6.sin6_addr,  +		  IPV6_MAX_BYTELEN); + +	  /* If directory connected set link-local address. */ +	  direct = if_lookup_by_ipv6 (&remote->sin6.sin6_addr); +	  if (direct) +	    if_get_ipv6_local (ifp, &nexthop->v6_local); +	} +      else +	/* Link-local address. */ +	{ +	  ret = if_get_ipv6_global (ifp, &nexthop->v6_global); + +	  /* If there is no global address.  Set link-local address as +             global.  I know this break RFC specification... */ +	  if (!ret) +	    memcpy (&nexthop->v6_global, &local->sin6.sin6_addr,  +		    IPV6_MAX_BYTELEN); +	  else +	    memcpy (&nexthop->v6_local, &local->sin6.sin6_addr,  +		    IPV6_MAX_BYTELEN); +	} +    } + +  if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr) || +      if_lookup_by_ipv6 (&remote->sin6.sin6_addr)) +    peer->shared_network = 1; +  else +    peer->shared_network = 0; + +  /* KAME stack specific treatment.  */ +#ifdef KAME +  if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_global) +      && IN6_LINKLOCAL_IFINDEX (nexthop->v6_global)) +    { +      SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_global, 0); +    } +  if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_local) +      && IN6_LINKLOCAL_IFINDEX (nexthop->v6_local)) +    { +      SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_local, 0); +    } +#endif /* KAME */ +#endif /* HAVE_IPV6 */ +  return ret; +} + +#ifdef HAVE_IPV6 +unsigned int +bgp_ifindex_by_nexthop (struct in6_addr *addr) +{ +  listnode ifnode; +  listnode cnode; +  struct interface *ifp; +  struct connected *connected; +  struct prefix_ipv6 p; +   +  p.family = AF_INET6; +  p.prefix = *addr; +  p.prefixlen = IPV6_MAX_BITLEN; + +  for (ifnode = listhead (iflist); ifnode; nextnode (ifnode)) +    { +      ifp = getdata (ifnode); + +      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) +	{ +	  struct prefix *cp;  + +	  connected = getdata (cnode); +	  cp = connected->address; +	     +	  if (cp->family == AF_INET6) +	    { +	      if (prefix_match (cp, (struct prefix *)&p)) +		return ifp->ifindex; +	    } +	} +    } +  return 0; +} +#endif /* HAVE_IPV6 */ + +void +bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) +{ +  int flags; +  u_char distance; +  struct peer *peer; + +  if (zclient->sock < 0) +    return; + +  if (! zclient->redist[ZEBRA_ROUTE_BGP]) +    return; + +  flags = 0; +  peer = info->peer; + +  if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED) +    { +      SET_FLAG (flags, ZEBRA_FLAG_IBGP); +      SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); +    } + +  if ((peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) +      || CHECK_FLAG (peer->flags, PEER_FLAG_ENFORCE_MULTIHOP)) +    SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); + +  if (p->family == AF_INET) +    { +      struct zapi_ipv4 api; +      struct in_addr *nexthop; + +      api.flags = flags; +      nexthop = &info->attr->nexthop; + +      api.type = ZEBRA_ROUTE_BGP; +      api.message = 0; +      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); +      api.nexthop_num = 1; +      api.nexthop = &nexthop; +      api.ifindex_num = 0; +      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); +      api.metric = info->attr->med; + +      distance = bgp_distance_apply (p, info, bgp); + +      if (distance) +	{ +	  SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); +	  api.distance = distance; +	} +      zapi_ipv4_add (zclient, (struct prefix_ipv4 *) p, &api); +    } +#ifdef HAVE_IPV6 +  /* We have to think about a IPv6 link-local address curse. */ +  if (p->family == AF_INET6) +    { +      unsigned int ifindex; +      struct in6_addr *nexthop; +      struct zapi_ipv6 api; + +      ifindex = 0; +      nexthop = NULL; + +      /* Only global address nexthop exists. */ +      if (info->attr->mp_nexthop_len == 16) +	nexthop = &info->attr->mp_nexthop_global; +       +      /* If both global and link-local address present. */ +      if (info->attr->mp_nexthop_len == 32) +	{ +	  /* Workaround for Cisco's nexthop bug.  */ +	  if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->mp_nexthop_global) +	      && peer->su_remote->sa.sa_family == AF_INET6) +	    nexthop = &peer->su_remote->sin6.sin6_addr; +	  else +	    nexthop = &info->attr->mp_nexthop_local; + +	  if (info->peer->nexthop.ifp) +	    ifindex = info->peer->nexthop.ifp->ifindex; +	} + +      if (nexthop == NULL) +	return; + +      if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) +	{ +	  if (info->peer->ifname) +	    ifindex = if_nametoindex (info->peer->ifname); +	  else if (info->peer->nexthop.ifp) +	    ifindex = info->peer->nexthop.ifp->ifindex; +	} + +      /* Make Zebra API structure. */ +      api.flags = flags; +      api.type = ZEBRA_ROUTE_BGP; +      api.message = 0; +      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); +      api.nexthop_num = 1; +      api.nexthop = &nexthop; +      SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); +      api.ifindex_num = 1; +      api.ifindex = &ifindex; +      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); +      api.metric = info->attr->med; + +      zapi_ipv6_add (zclient, (struct prefix_ipv6 *) p, &api); +    } +#endif /* HAVE_IPV6 */ +} + +void +bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info) +{ +  int flags; +  struct peer *peer; + +  if (zclient->sock < 0) +    return; + +  if (! zclient->redist[ZEBRA_ROUTE_BGP]) +    return; + +  peer = info->peer; +  flags = 0; + +  if (peer_sort (peer) == BGP_PEER_IBGP) +    { +      SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); +      SET_FLAG (flags, ZEBRA_FLAG_IBGP); +    } + +  if ((peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1) +      || CHECK_FLAG (peer->flags, PEER_FLAG_ENFORCE_MULTIHOP)) +    SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); + +  if (p->family == AF_INET) +    { +      struct zapi_ipv4 api; +      struct in_addr *nexthop; + +      api.flags = flags; +      nexthop = &info->attr->nexthop; + +      api.type = ZEBRA_ROUTE_BGP; +      api.message = 0; +      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); +      api.nexthop_num = 1; +      api.nexthop = &nexthop; +      api.ifindex_num = 0; +      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); +      api.metric = info->attr->med; + +      zapi_ipv4_delete (zclient, (struct prefix_ipv4 *) p, &api); +    } +#ifdef HAVE_IPV6 +  /* We have to think about a IPv6 link-local address curse. */ +  if (p->family == AF_INET6) +    { +      struct zapi_ipv6 api; +      unsigned int ifindex; +      struct in6_addr *nexthop; + +      ifindex = 0; +      nexthop = NULL; + +      /* Only global address nexthop exists. */ +      if (info->attr->mp_nexthop_len == 16) +	nexthop = &info->attr->mp_nexthop_global; + +      /* If both global and link-local address present. */ +      if (info->attr->mp_nexthop_len == 32) +	{ +	  nexthop = &info->attr->mp_nexthop_local; +	  if (info->peer->nexthop.ifp) +	    ifindex = info->peer->nexthop.ifp->ifindex; +	} + +      if (nexthop == NULL) +	return; + +      if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) +	if (info->peer->ifname) +	  ifindex = if_nametoindex (info->peer->ifname); + +      api.flags = flags; +      api.type = ZEBRA_ROUTE_BGP; +      api.message = 0; +      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); +      api.nexthop_num = 1; +      api.nexthop = &nexthop; +      SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); +      api.ifindex_num = 1; +      api.ifindex = &ifindex; +      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); +      api.metric = info->attr->med; + +      zapi_ipv6_delete (zclient, (struct prefix_ipv6 *) p, &api); +    } +#endif /* HAVE_IPV6 */ +} + +/* Other routes redistribution into BGP. */ +int +bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type) +{ +  /* Set flag to BGP instance. */ +  bgp->redist[afi][type] = 1; + +  /* Return if already redistribute flag is set. */ +  if (zclient->redist[type]) +    return CMD_WARNING; + +  zclient->redist[type] = 1; + +  /* Return if zebra connection is not established. */ +  if (zclient->sock < 0) +    return CMD_WARNING; +     +  /* Send distribute add message to zebra. */ +  zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type); + +  return CMD_SUCCESS; +} + +/* Redistribute with route-map specification.  */ +int +bgp_redistribute_rmap_set (struct bgp *bgp, afi_t afi, int type, char *name) +{ +  if (bgp->rmap[afi][type].name +      && (strcmp (bgp->rmap[afi][type].name, name) == 0)) +    return 0; + +  if (bgp->rmap[afi][type].name) +    free (bgp->rmap[afi][type].name); +  bgp->rmap[afi][type].name = strdup (name); +  bgp->rmap[afi][type].map = route_map_lookup_by_name (name); + +  return 1; +} + +/* Redistribute with metric specification.  */ +int +bgp_redistribute_metric_set (struct bgp *bgp, afi_t afi, int type, +			     u_int32_t metric) +{ +  if (bgp->redist_metric_flag[afi][type] +      && bgp->redist_metric[afi][type] == metric) +    return 0; + +  bgp->redist_metric_flag[afi][type] = 1; +  bgp->redist_metric[afi][type] = metric; + +  return 1; +} + +/* Unset redistribution.  */ +int +bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type) +{ +  /* Unset flag from BGP instance. */ +  bgp->redist[afi][type] = 0; + +  /* Unset route-map. */ +  if (bgp->rmap[afi][type].name) +    free (bgp->rmap[afi][type].name); +  bgp->rmap[afi][type].name = NULL; +  bgp->rmap[afi][type].map = NULL; + +  /* Unset metric. */ +  bgp->redist_metric_flag[afi][type] = 0; +  bgp->redist_metric[afi][type] = 0; + +  /* Return if zebra connection is disabled. */ +  if (! zclient->redist[type]) +    return CMD_WARNING; +  zclient->redist[type] = 0; + +  if (bgp->redist[AFI_IP][type] == 0  +      && bgp->redist[AFI_IP6][type] == 0  +      && zclient->sock >= 0) +    /* Send distribute delete message to zebra. */ +    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type); +   +  /* Withdraw redistributed routes from current BGP's routing table. */ +  bgp_redistribute_withdraw (bgp, afi, type); + +  return CMD_SUCCESS; +} + +/* Unset redistribution route-map configuration.  */ +int +bgp_redistribute_routemap_unset (struct bgp *bgp, afi_t afi, int type) +{ +  if (! bgp->rmap[afi][type].name) +    return 0; + +  /* Unset route-map. */ +  free (bgp->rmap[afi][type].name); +  bgp->rmap[afi][type].name = NULL; +  bgp->rmap[afi][type].map = NULL; + +  return 1; +} + +/* Unset redistribution metric configuration.  */ +int +bgp_redistribute_metric_unset (struct bgp *bgp, afi_t afi, int type) +{ +  if (! bgp->redist_metric_flag[afi][type]) +    return 0; + +  /* Unset metric. */ +  bgp->redist_metric_flag[afi][type] = 0; +  bgp->redist_metric[afi][type] = 0; + +  return 1; +} + +void +bgp_zclient_reset () +{ +  zclient_reset (zclient); +} + +void +bgp_zebra_init (int enable) +{ +  /* Set default values. */ +  zclient = zclient_new (); +  zclient_init (zclient, ZEBRA_ROUTE_BGP); +  zclient->interface_add = bgp_interface_add; +  zclient->interface_delete = bgp_interface_delete; +  zclient->interface_address_add = bgp_interface_address_add; +  zclient->interface_address_delete = bgp_interface_address_delete; +  zclient->ipv4_route_add = zebra_read_ipv4; +  zclient->ipv4_route_delete = zebra_read_ipv4; +  zclient->interface_up = bgp_interface_up; +  zclient->interface_down = bgp_interface_down; +#ifdef HAVE_IPV6 +  zclient->ipv6_route_add = zebra_read_ipv6; +  zclient->ipv6_route_delete = zebra_read_ipv6; +#endif /* HAVE_IPV6 */ + +  /* Interface related init. */ +  if_init (); +} diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h new file mode 100644 index 0000000000..1620c8478a --- /dev/null +++ b/bgpd/bgp_zebra.h @@ -0,0 +1,39 @@ +/* zebra connection and redistribute fucntions. +   Copyright (C) 1999 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA.  */ + +int bgp_if_update_all (); +int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t, +				   int *); +void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *); +void bgp_zebra_withdraw (struct prefix *, struct bgp_info *); + +int bgp_redistribute_set (struct bgp *, afi_t, int); +int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, char *); +int bgp_redistribute_metric_set (struct bgp *, afi_t, int, u_int32_t); +int bgp_redistribute_unset (struct bgp *, afi_t, int); +int bgp_redistribute_routemap_unset (struct bgp *, afi_t, int); +int bgp_redistribute_metric_unset (struct bgp *, afi_t, int); + +struct interface *if_lookup_by_ipv4 (struct in_addr *); +struct interface *if_lookup_by_ipv4_exact (struct in_addr *); +#ifdef HAVE_IPV6 +struct interface *if_lookup_by_ipv6 (struct in6_addr *); +struct interface *if_lookup_by_ipv6_exact (struct in6_addr *); +#endif /* HAVE_IPV6 */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c new file mode 100644 index 0000000000..f116a0cf77 --- /dev/null +++ b/bgpd/bgpd.c @@ -0,0 +1,4601 @@ +/* BGP-4, BGP-4+ daemon program +   Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +#include <zebra.h> + +#include "prefix.h" +#include "thread.h" +#include "buffer.h" +#include "stream.h" +#include "command.h" +#include "sockunion.h" +#include "network.h" +#include "memory.h" +#include "filter.h" +#include "routemap.h" +#include "str.h" +#include "log.h" +#include "plist.h" +#include "linklist.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_dump.h" +#include "bgpd/bgp_debug.h" +#include "bgpd/bgp_community.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_regex.h" +#include "bgpd/bgp_clist.h" +#include "bgpd/bgp_fsm.h" +#include "bgpd/bgp_packet.h" +#include "bgpd/bgp_zebra.h" +#include "bgpd/bgp_open.h" +#include "bgpd/bgp_filter.h" +#include "bgpd/bgp_nexthop.h" +#include "bgpd/bgp_damp.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_advertise.h" +#include "bgpd/bgp_network.h" +#include "bgpd/bgp_vty.h" +#ifdef HAVE_SNMP +#include "bgpd/bgp_snmp.h" +#endif /* HAVE_SNMP */ + +/* BGP process wide configuration.  */ +static struct bgp_master bgp_master; + +/* BGP process wide configuration pointer to export.  */ +struct bgp_master *bm; + +/* BGP community-list.  */ +struct community_list_handler *bgp_clist; + +/* BGP global flag manipulation.  */ +int +bgp_option_set (int flag) +{ +  switch (flag) +    { +    case BGP_OPT_NO_FIB: +    case BGP_OPT_MULTIPLE_INSTANCE: +    case BGP_OPT_CONFIG_CISCO: +      SET_FLAG (bm->options, flag); +      break; +    default: +      return BGP_ERR_INVALID_FLAG; +      break; +    } +  return 0; +} + +int +bgp_option_unset (int flag) +{ +  switch (flag) +    { +    case BGP_OPT_MULTIPLE_INSTANCE: +      if (listcount (bm->bgp) > 1) +	return BGP_ERR_MULTIPLE_INSTANCE_USED; +      /* Fall through.  */ +    case BGP_OPT_NO_FIB: +    case BGP_OPT_CONFIG_CISCO: +      UNSET_FLAG (bm->options, flag); +      break; +    default: +      return BGP_ERR_INVALID_FLAG; +      break; +    } +  return 0; +} + +int +bgp_option_check (int flag) +{ +  return CHECK_FLAG (bm->options, flag); +} + +/* BGP flag manipulation.  */ +int +bgp_flag_set (struct bgp *bgp, int flag) +{ +  SET_FLAG (bgp->flags, flag); +  return 0; +} + +int +bgp_flag_unset (struct bgp *bgp, int flag) +{ +  UNSET_FLAG (bgp->flags, flag); +  return 0; +} + +int +bgp_flag_check (struct bgp *bgp, int flag) +{ +  return CHECK_FLAG (bgp->flags, flag); +} + +/* Internal function to set BGP structure configureation flag.  */ +static void +bgp_config_set (struct bgp *bgp, int config) +{ +  SET_FLAG (bgp->config, config); +} + +static void +bgp_config_unset (struct bgp *bgp, int config) +{ +  UNSET_FLAG (bgp->config, config); +} + +static int +bgp_config_check (struct bgp *bgp, int config) +{ +  return CHECK_FLAG (bgp->config, config); +} + +/* Set BGP router identifier. */ +int +bgp_router_id_set (struct bgp *bgp, struct in_addr *id) +{ +  struct peer *peer; +  struct listnode *nn; + +  if (bgp_config_check (bgp, BGP_CONFIG_ROUTER_ID) +      && IPV4_ADDR_SAME (&bgp->router_id, id)) +    return 0; + +  IPV4_ADDR_COPY (&bgp->router_id, id); +  bgp_config_set (bgp, BGP_CONFIG_ROUTER_ID); + +  /* Set all peer's local identifier with this value. */ +  LIST_LOOP (bgp->peer, peer, nn) +    { +      IPV4_ADDR_COPY (&peer->local_id, id); + +      if (peer->status == Established) +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +    } +  return 0; +} + +/* Unset BGP router identifier. */ +int +bgp_router_id_unset (struct bgp *bgp) +{ +  struct peer *peer; +  struct listnode *nn; + +  if (! bgp_config_check (bgp, BGP_CONFIG_ROUTER_ID)) +    return 0; + +  bgp->router_id.s_addr = 0; +  bgp_config_unset (bgp, BGP_CONFIG_ROUTER_ID); + +  /* Clear peer router id configuration.  */ +  LIST_LOOP (bgp->peer, peer, nn) +    { +      peer->local_id.s_addr = 0; +    } + +  /* Set router-id from interface's address. */ +  bgp_if_update_all (); + +  /* Reset all BGP sessions to use new router-id.  */ +  LIST_LOOP (bgp->peer, peer, nn) +    { +      if (peer->status == Established) +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +    } + +  return 0; +} + +/* BGP's cluster-id control. */ +int +bgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id) +{ +  struct peer *peer; +  struct listnode *nn; + +  if (bgp_config_check (bgp, BGP_CONFIG_CLUSTER_ID) +      && IPV4_ADDR_SAME (&bgp->cluster_id, cluster_id)) +    return 0; + +  IPV4_ADDR_COPY (&bgp->cluster_id, cluster_id); +  bgp_config_set (bgp, BGP_CONFIG_CLUSTER_ID); + +  /* Clear all IBGP peer. */ +  LIST_LOOP (bgp->peer, peer, nn) +    { +      if (peer_sort (peer) != BGP_PEER_IBGP) +	continue; + +      if (peer->status == Established) +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +    } +  return 0; +} + +int +bgp_cluster_id_unset (struct bgp *bgp) +{ +  struct peer *peer; +  struct listnode *nn; + +  if (! bgp_config_check (bgp, BGP_CONFIG_CLUSTER_ID)) +    return 0; + +  bgp->cluster_id.s_addr = 0; +  bgp_config_unset (bgp, BGP_CONFIG_CLUSTER_ID); + +  /* Clear all IBGP peer. */ +  LIST_LOOP (bgp->peer, peer, nn) +    { +      if (peer_sort (peer) != BGP_PEER_IBGP) +	continue; + +      if (peer->status == Established) +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +    } +  return 0; +} + +/* BGP timer configuration.  */ +int +bgp_timers_set (struct bgp *bgp, u_int32_t keepalive, u_int32_t holdtime) +{ +  bgp->default_keepalive = (keepalive < holdtime / 3  +			    ? keepalive : holdtime / 3); +  bgp->default_holdtime = holdtime; + +  return 0; +} + +int +bgp_timers_unset (struct bgp *bgp) +{ +  bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; +  bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; + +  return 0; +} + +/* BGP confederation configuration.  */ +int +bgp_confederation_id_set (struct bgp *bgp, as_t as) +{ +  struct peer *peer; +  struct listnode *nn; +  int already_confed; + +  if (as == 0) +    return BGP_ERR_INVALID_AS; + +  /* Remember - were we doing confederation before? */ +  already_confed = bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION); +  bgp->confed_id = as; +  bgp_config_set (bgp, BGP_CONFIG_CONFEDERATION); + +  /* If we were doing confederation already, this is just an external +     AS change.  Just Reset EBGP sessions, not CONFED sessions.  If we +     were not doing confederation before, reset all EBGP sessions.  */ +  LIST_LOOP (bgp->peer, peer, nn) +    { +      /* We're looking for peers who's AS is not local or part of our +	 confederation.  */ +      if (already_confed) +	{ +	  if (peer_sort (peer) == BGP_PEER_EBGP) +	    { +	      peer->local_as = as; +	      if (peer->status == Established) +		bgp_notify_send (peer, BGP_NOTIFY_CEASE, +				 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +	      else +		BGP_EVENT_ADD (peer, BGP_Stop); +	    } +	} +      else +	{ +	  /* Not doign confederation before, so reset every non-local +	     session */ +	  if (peer_sort (peer) != BGP_PEER_IBGP) +	    { +	      /* Reset the local_as to be our EBGP one */ +	      if (peer_sort (peer) == BGP_PEER_EBGP) +		peer->local_as = as; +	      if (peer->status == Established) +		bgp_notify_send (peer, BGP_NOTIFY_CEASE, +				 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +	      else +		BGP_EVENT_ADD (peer, BGP_Stop); +	    } +	} +    } +  return 0; +} + +int +bgp_confederation_id_unset (struct bgp *bgp) +{ +  struct peer *peer; +  struct listnode *nn; + +  bgp->confed_id = 0; +  bgp_config_unset (bgp, BGP_CONFIG_CONFEDERATION); +       +  LIST_LOOP (bgp->peer, peer, nn) +    { +      /* We're looking for peers who's AS is not local */ +      if (peer_sort (peer) != BGP_PEER_IBGP) +	{ +	  peer->local_as = bgp->as; +	  if (peer->status == Established) +	    bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			     BGP_NOTIFY_CEASE_CONFIG_CHANGE); +	  else +	    BGP_EVENT_ADD (peer, BGP_Stop); +	} +    } +  return 0; +} + +/* Is an AS part of the confed or not? */ +int +bgp_confederation_peers_check (struct bgp *bgp, as_t as) +{ +  int i; + +  if (! bgp) +    return 0; + +  for (i = 0; i < bgp->confed_peers_cnt; i++) +    if (bgp->confed_peers[i] == as) +      return 1; +   +  return 0; +} + +/* Add an AS to the confederation set.  */ +int +bgp_confederation_peers_add (struct bgp *bgp, as_t as) +{ +  struct peer *peer; +  struct listnode *nn; + +  if (! bgp) +    return BGP_ERR_INVALID_BGP; + +  if (bgp->as == as) +    return BGP_ERR_INVALID_AS; + +  if (bgp_confederation_peers_check (bgp, as)) +    return -1; + +  if (bgp->confed_peers) +    bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST,  +				  bgp->confed_peers, +				  (bgp->confed_peers_cnt + 1) * sizeof (as_t)); +  else +    bgp->confed_peers = XMALLOC (MTYPE_BGP_CONFED_LIST,  +				 (bgp->confed_peers_cnt + 1) * sizeof (as_t)); + +  bgp->confed_peers[bgp->confed_peers_cnt] = as; +  bgp->confed_peers_cnt++; + +  if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION)) +    { +      LIST_LOOP (bgp->peer, peer, nn) +	{ +	  if (peer->as == as) +	    { +	      peer->local_as = bgp->as; +	      if (peer->status == Established) +		bgp_notify_send (peer, BGP_NOTIFY_CEASE, +				 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +	      else +	        BGP_EVENT_ADD (peer, BGP_Stop); +	    } +	} +    } +  return 0; +} + +/* Delete an AS from the confederation set.  */ +int +bgp_confederation_peers_remove (struct bgp *bgp, as_t as) +{ +  int i; +  int j; +  struct peer *peer; +  struct listnode *nn; + +  if (! bgp) +    return -1; + +  if (! bgp_confederation_peers_check (bgp, as)) +    return -1; + +  for (i = 0; i < bgp->confed_peers_cnt; i++) +    if (bgp->confed_peers[i] == as) +      for(j = i + 1; j < bgp->confed_peers_cnt; j++) +	bgp->confed_peers[j - 1] = bgp->confed_peers[j]; + +  bgp->confed_peers_cnt--; + +  if (bgp->confed_peers_cnt == 0) +    { +      if (bgp->confed_peers) +	XFREE (MTYPE_BGP_CONFED_LIST, bgp->confed_peers); +      bgp->confed_peers = NULL; +    } +  else +    bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST, +				  bgp->confed_peers, +				  bgp->confed_peers_cnt * sizeof (as_t)); + +  /* Now reset any peer who's remote AS has just been removed from the +     CONFED */ +  if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION)) +    { +      LIST_LOOP (bgp->peer, peer, nn) +	{ +	  if (peer->as == as) +	    { +	      peer->local_as = bgp->confed_id; +	      if (peer->status == Established) +		bgp_notify_send (peer, BGP_NOTIFY_CEASE, +				 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +	      else +		BGP_EVENT_ADD (peer, BGP_Stop); +	    } +	} +    } + +  return 0; +} + +/* Local preference configuration.  */ +int +bgp_default_local_preference_set (struct bgp *bgp, u_int32_t local_pref) +{ +  if (! bgp) +    return -1; + +  bgp_config_set (bgp, BGP_CONFIG_DEFAULT_LOCAL_PREF); +  bgp->default_local_pref = local_pref; + +  return 0; +} + +int +bgp_default_local_preference_unset (struct bgp *bgp) +{ +  if (! bgp) +    return -1; + +  bgp_config_unset (bgp, BGP_CONFIG_DEFAULT_LOCAL_PREF); +  bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; + +  return 0; +} + +/* Peer comparison function for sorting.  */ +static int +peer_cmp (struct peer *p1, struct peer *p2) +{ +  return sockunion_cmp (&p1->su, &p2->su); +} + +int +peer_af_flag_check (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag) +{ +  return CHECK_FLAG (peer->af_flags[afi][safi], flag); +} + +/* Reset all address family specific configuration.  */ +static void +peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi) +{ +  int i; +  struct bgp_filter *filter; +  char orf_name[BUFSIZ]; + +  filter = &peer->filter[afi][safi]; + +  /* Clear neighbor filter and route-map */ +  for (i = FILTER_IN; i < FILTER_MAX; i++) +    { +      if (filter->dlist[i].name) +	{ +	  free (filter->dlist[i].name); +	  filter->dlist[i].name = NULL; +	} +      if (filter->plist[i].name) +	{ +	  free (filter->plist[i].name); +	  filter->plist[i].name = NULL;  +	} +      if (filter->aslist[i].name) +	{ +	  free (filter->aslist[i].name); +	  filter->aslist[i].name = NULL; +	} +      if (filter->map[i].name) +	{ +	  free (filter->map[i].name); +	  filter->map[i].name = NULL; +	} +    } + +  /* Clear unsuppress map.  */ +  if (filter->usmap.name) +    free (filter->usmap.name); +  filter->usmap.name = NULL; +  filter->usmap.map = NULL; + +  /* Clear neighbor's all address family flags.  */ +  peer->af_flags[afi][safi] = 0; + +  /* Clear neighbor's all address family sflags. */ +  peer->af_sflags[afi][safi] = 0; + +  /* Clear neighbor's all address family capabilities. */ +  peer->af_cap[afi][safi] = 0; + +  /* Clear ORF info */ +  peer->orf_plist[afi][safi] = NULL; +  sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); +  prefix_bgp_orf_remove_all (orf_name); + +  /* Set default neighbor send-community.  */ +  if (! bgp_option_check (BGP_OPT_CONFIG_CISCO)) +    { +      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY); +      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); +    } + +  /* Clear neighbor default_originate_rmap */ +  if (peer->default_rmap[afi][safi].name) +    free (peer->default_rmap[afi][safi].name); +  peer->default_rmap[afi][safi].name = NULL; +  peer->default_rmap[afi][safi].map = NULL; + +  /* Clear neighbor maximum-prefix */ +  peer->pmax[afi][safi] = 0; +} + +/* peer global config reset */ +void +peer_global_config_reset (struct peer *peer) +{ +  peer->weight = 0; +  peer->change_local_as = 0; +  peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1); +  if (peer->update_source) +    { +      sockunion_free (peer->update_source); +      peer->update_source = NULL; +    } +  if (peer->update_if) +    { +      XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); +      peer->update_if = NULL; +    } + +  if (peer_sort (peer) == BGP_PEER_IBGP) +    peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; +  else +    peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + +  peer->flags = 0; +  peer->config = 0; +  peer->holdtime = 0; +  peer->keepalive = 0; +  peer->connect = 0; +  peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; +} + +/* Check peer's AS number and determin is this peer IBGP or EBGP */ +int +peer_sort (struct peer *peer) +{ +  struct bgp *bgp; + +  bgp = peer->bgp; + +  /* Peer-group */ +  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (peer->as) +	return (bgp->as == peer->as ? BGP_PEER_IBGP : BGP_PEER_EBGP); +      else +	{ +	  struct peer *peer1; +	  peer1 = listnode_head (peer->group->peer); +	  if (peer1) +	    return (peer1->local_as == peer1->as  +		    ? BGP_PEER_IBGP : BGP_PEER_EBGP); +	}  +      return BGP_PEER_INTERNAL; +    } + +  /* Normal peer */ +  if (bgp && CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) +    { +      if (peer->local_as == 0) +	return BGP_PEER_INTERNAL; + +      if (peer->local_as == peer->as) +	{ +	  if (peer->local_as == bgp->confed_id) +	    return BGP_PEER_EBGP; +	  else +	    return BGP_PEER_IBGP; +	} + +      if (bgp_confederation_peers_check (bgp, peer->as)) +	return BGP_PEER_CONFED; + +      return BGP_PEER_EBGP; +    } +  else +    { +      return (peer->local_as == 0 +	      ? BGP_PEER_INTERNAL : peer->local_as == peer->as +	      ? BGP_PEER_IBGP : BGP_PEER_EBGP); +    } +} + +/* Allocate new peer object.  */ +static struct peer * +peer_new () +{ +  afi_t afi; +  safi_t safi; +  struct peer *peer; +  struct servent *sp; + +  /* Allocate new peer. */ +  peer = XMALLOC (MTYPE_BGP_PEER, sizeof (struct peer)); +  memset (peer, 0, sizeof (struct peer)); + +  /* Set default value. */ +  peer->fd = -1; +  peer->v_start = BGP_INIT_START_TIMER; +  peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; +  peer->v_asorig = BGP_DEFAULT_ASORIGINATE; +  peer->status = Idle; +  peer->ostatus = Idle; +  peer->version = BGP_VERSION_4; +  peer->weight = 0; + +  /* Set default flags.  */ +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      { +	if (! bgp_option_check (BGP_OPT_CONFIG_CISCO)) +	  { +	    SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY); +	    SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); +	  } +	peer->orf_plist[afi][safi] = NULL; +      } +  SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + +  /* Create buffers.  */ +  peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE); +  peer->obuf = stream_fifo_new (); +  peer->work = stream_new (BGP_MAX_PACKET_SIZE); + +  bgp_sync_init (peer); + +  /* Get service port number.  */ +  sp = getservbyname ("bgp", "tcp"); +  peer->port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port); + +  return peer; +} + +/* Create new BGP peer.  */ +struct peer * +peer_create (union sockunion *su, struct bgp *bgp, as_t local_as, +	     as_t remote_as, afi_t afi, safi_t safi) +{ +  int active; +  struct peer *peer; +  char buf[SU_ADDRSTRLEN]; + +  peer = peer_new (); +  peer->bgp = bgp; +  peer->su = *su; +  peer->local_as = local_as; +  peer->as = remote_as; +  peer->local_id = bgp->router_id; +  peer->v_holdtime = bgp->default_holdtime; +  peer->v_keepalive = bgp->default_keepalive; +  if (peer_sort (peer) == BGP_PEER_IBGP) +    peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; +  else +    peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; +  listnode_add_sort (bgp->peer, peer); + +  active = peer_active (peer); + +  if (afi && safi) +    peer->afc[afi][safi] = 1; + +  /* Last read time set */ +  peer->readtime = time (NULL); + +  /* Default TTL set. */ +  peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1); + +  /* Make peer's address string. */ +  sockunion2str (su, buf, SU_ADDRSTRLEN); +  peer->host = strdup (buf); + +  /* Set up peer's events and timers. */ +  if (! active && peer_active (peer)) +    bgp_timer_set (peer); + +  return peer; +} + +/* Make accept BGP peer.  Called from bgp_accept (). */ +struct peer * +peer_create_accept (struct bgp *bgp) +{ +  struct peer *peer; + +  peer = peer_new (); +  peer->bgp = bgp; +  listnode_add_sort (bgp->peer, peer); + +  return peer; +} + +/* Change peer's AS number.  */ +void +peer_as_change (struct peer *peer, as_t as) +{ +  int type; + +  /* Stop peer. */ +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (peer->status == Established) +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +      else +	BGP_EVENT_ADD (peer, BGP_Stop); +    } +  type = peer_sort (peer); +  peer->as = as; + +  /* Advertisement-interval reset */ +  if (peer_sort (peer) == BGP_PEER_IBGP) +    peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; +  else +    peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + +  /* TTL reset */ +  if (peer_sort (peer) == BGP_PEER_IBGP) +    peer->ttl = 255; +  else if (type == BGP_PEER_IBGP) +    peer->ttl = 1; + +  /* reflector-client reset */ +  if (peer_sort (peer) != BGP_PEER_IBGP) +    { +      UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], +		  PEER_FLAG_REFLECTOR_CLIENT); +      UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST], +		  PEER_FLAG_REFLECTOR_CLIENT); +      UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN], +		  PEER_FLAG_REFLECTOR_CLIENT); +      UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], +		  PEER_FLAG_REFLECTOR_CLIENT); +      UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST], +		  PEER_FLAG_REFLECTOR_CLIENT); +    } + +  /* local-as reset */ +  if (peer_sort (peer) != BGP_PEER_EBGP) +    { +      peer->change_local_as = 0; +      UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); +    } +} + +/* If peer does not exist, create new one.  If peer already exists, +   set AS number to the peer.  */ +int +peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as, +		afi_t afi, safi_t safi) +{ +  struct peer *peer; +  as_t local_as; + +  peer = peer_lookup (bgp, su); + +  if (peer) +    { +      /* When this peer is a member of peer-group.  */ +      if (peer->group) +	{ +	  if (peer->group->conf->as) +	    { +	      /* Return peer group's AS number.  */ +	      *as = peer->group->conf->as; +	      return BGP_ERR_PEER_GROUP_MEMBER; +	    } +	  if (peer_sort (peer->group->conf) == BGP_PEER_IBGP) +	    { +	      if (bgp->as != *as) +		{ +		  *as = peer->as; +		  return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; +		} +	    } +	  else +	    { +	      if (bgp->as == *as) +		{ +		  *as = peer->as; +		  return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; +		} +	    } +	} + +      /* Existing peer's AS number change. */ +      if (peer->as != *as) +	peer_as_change (peer, *as); +    } +  else +    { + +      /* If the peer is not part of our confederation, and its not an +	 iBGP peer then spoof the source AS */ +      if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION) +	  && ! bgp_confederation_peers_check (bgp, *as)  +	  && bgp->as != *as) +	local_as = bgp->confed_id; +      else +	local_as = bgp->as; +       +      /* If this is IPv4 unicast configuration and "no bgp default +         ipv4-unicast" is specified. */ + +      if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4) +	  && afi == AFI_IP && safi == SAFI_UNICAST) +	peer = peer_create (su, bgp, local_as, *as, 0, 0);  +      else +	peer = peer_create (su, bgp, local_as, *as, afi, safi);  +    } + +  return 0; +} + +/* Activate the peer or peer group for specified AFI and SAFI.  */ +int +peer_activate (struct peer *peer, afi_t afi, safi_t safi) +{ +  int active; + +  if (peer->afc[afi][safi]) +    return 0; + +  /* Activate the address family configuration. */ +  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    peer->afc[afi][safi] = 1; +  else +    { +      active = peer_active (peer); + +      peer->afc[afi][safi] = 1; + +      if (! active && peer_active (peer)) +	bgp_timer_set (peer); +      else +	{ +	  if (peer->status == Established) +	    { +	      if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV)) +		{ +		  peer->afc_adv[afi][safi] = 1; +		  bgp_capability_send (peer, afi, safi, +				       CAPABILITY_CODE_MP, +				       CAPABILITY_ACTION_SET); +		  if (peer->afc_recv[afi][safi]) +		    { +		      peer->afc_nego[afi][safi] = 1; +		      bgp_announce_route (peer, afi, safi); +		    } +		} +	      else +		bgp_notify_send (peer, BGP_NOTIFY_CEASE, +				 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +	    } +	} +    } +  return 0; +} + +int +peer_deactivate (struct peer *peer, afi_t afi, safi_t safi) +{ +  struct peer_group *group; +  struct peer *peer1; +  struct listnode *nn; + +  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      group = peer->group; + +      LIST_LOOP (group->peer, peer1, nn) +	{ +	  if (peer1->af_group[afi][safi]) +	    return BGP_ERR_PEER_GROUP_MEMBER_EXISTS; +	} +    } +  else +    { +      if (peer->af_group[afi][safi]) +	return BGP_ERR_PEER_BELONGS_TO_GROUP; +    } + +  if (! peer->afc[afi][safi]) +    return 0; + +  /* De-activate the address family configuration. */ +  peer->afc[afi][safi] = 0; +  peer_af_flag_reset (peer, afi, safi); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    {   +      if (peer->status == Established) +	{ +	  if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV)) +	    { +	      peer->afc_adv[afi][safi] = 0; +	      peer->afc_nego[afi][safi] = 0; + +	      if (peer_active_nego (peer)) +		{ +		  bgp_capability_send (peer, afi, safi, +				       CAPABILITY_CODE_MP, +				       CAPABILITY_ACTION_UNSET); +		  bgp_clear_route (peer, afi, safi); +		  peer->pcount[afi][safi] = 0; +		} +	      else +		bgp_notify_send (peer, BGP_NOTIFY_CEASE, +				 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +	    } +	  else +	    bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			     BGP_NOTIFY_CEASE_CONFIG_CHANGE); +	} +    } +  return 0; +} + +/* Delete peer from confguration. */ +int +peer_delete (struct peer *peer) +{ +  int i; +  afi_t afi; +  safi_t safi; +  struct bgp *bgp; +  struct bgp_filter *filter; + +  bgp = peer->bgp; + +  /* If this peer belongs to peer group.  Clearn up the +     relationship.  */ +  if (peer->group) +    { +      listnode_delete (peer->group->peer, peer); +      peer->group = NULL; +    } + +  /* Withdraw all information from routing table.  We can not use +     BGP_EVENT_ADD (peer, BGP_Stop) at here.  Because the event is +     executed after peer structure is deleted. */ +  bgp_stop (peer); +  bgp_fsm_change_status (peer, Idle); + +  /* Stop all timers. */ +  BGP_TIMER_OFF (peer->t_start); +  BGP_TIMER_OFF (peer->t_connect); +  BGP_TIMER_OFF (peer->t_holdtime); +  BGP_TIMER_OFF (peer->t_keepalive); +  BGP_TIMER_OFF (peer->t_asorig); +  BGP_TIMER_OFF (peer->t_routeadv); + +  /* Delete from all peer list. */ +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    listnode_delete (bgp->peer, peer); + +  /* Buffer.  */ +  if (peer->ibuf) +    stream_free (peer->ibuf); + +  if (peer->obuf) +    stream_fifo_free (peer->obuf); + +  if (peer->work) +    stream_free (peer->work); + +  /* Free allocated host character. */ +  if (peer->host) +    free (peer->host); + +  /* Local and remote addresses. */ +  if (peer->su_local) +    XFREE (MTYPE_TMP, peer->su_local); +  if (peer->su_remote) +    XFREE (MTYPE_TMP, peer->su_remote); + +  /* Peer description string.  */ +  if (peer->desc) +    XFREE (MTYPE_TMP, peer->desc); + +  bgp_sync_delete (peer); + +  /* Free filter related memory.  */ +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      { +	filter = &peer->filter[afi][safi]; + +	for (i = FILTER_IN; i < FILTER_MAX; i++) +	  { +	    if (filter->dlist[i].name) +	      free (filter->dlist[i].name); +	    if (filter->plist[i].name) +	      free (filter->plist[i].name); +	    if (filter->aslist[i].name) +	      free (filter->aslist[i].name); +	    if (filter->map[i].name) +	      free (filter->map[i].name); +	  } + +	if (filter->usmap.name) +	  free (filter->usmap.name); + +	if (peer->default_rmap[afi][safi].name) +	  free (peer->default_rmap[afi][safi].name); +      } + +  /* Update source configuration.  */ +  if (peer->update_source) +    { +      sockunion_free (peer->update_source); +      peer->update_source = NULL; +    } +  if (peer->update_if) +    { +      XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); +      peer->update_if = NULL; +    } + +  /* Free peer structure. */ +  XFREE (MTYPE_BGP_PEER, peer); + +  return 0; +} + +int +peer_group_cmp (struct peer_group *g1, struct peer_group *g2) +{ +  return strcmp (g1->name, g2->name); +} + +/* If peer is configured at least one address family return 1. */ +int +peer_group_active (struct peer *peer) +{ +  if (peer->af_group[AFI_IP][SAFI_UNICAST] +      || peer->af_group[AFI_IP][SAFI_MULTICAST] +      || peer->af_group[AFI_IP][SAFI_MPLS_VPN] +      || peer->af_group[AFI_IP6][SAFI_UNICAST] +      || peer->af_group[AFI_IP6][SAFI_MULTICAST]) +    return 1; +  return 0; +} + +/* Peer group cofiguration. */ +static struct peer_group * +peer_group_new () +{ +  return (struct peer_group *) XCALLOC (MTYPE_PEER_GROUP, +					sizeof (struct peer_group)); +} + +void +peer_group_free (struct peer_group *group) +{ +  XFREE (MTYPE_PEER_GROUP, group); +} + +struct peer_group * +peer_group_lookup (struct bgp *bgp, char *name) +{ +  struct peer_group *group; +  struct listnode *nn; + +  LIST_LOOP (bgp->group, group, nn) +    { +      if (strcmp (group->name, name) == 0) +	return group; +    } +  return NULL; +} + +struct peer_group * +peer_group_get (struct bgp *bgp, char *name) +{ +  struct peer_group *group; + +  group = peer_group_lookup (bgp, name); +  if (group) +    return group; + +  group = peer_group_new (); +  group->bgp = bgp; +  group->name = strdup (name); +  group->peer = list_new (); +  group->conf = peer_new (); +  if (! bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) +    group->conf->afc[AFI_IP][SAFI_UNICAST] = 1; +  group->conf->host = strdup (name); +  group->conf->bgp = bgp; +  group->conf->group = group; +  group->conf->as = 0;  +  group->conf->ttl = 1; +  group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; +  UNSET_FLAG (group->conf->config, PEER_CONFIG_TIMER); +  UNSET_FLAG (group->conf->config, PEER_CONFIG_CONNECT); +  group->conf->keepalive = 0; +  group->conf->holdtime = 0; +  group->conf->connect = 0; +  SET_FLAG (group->conf->sflags, PEER_STATUS_GROUP); +  listnode_add_sort (bgp->group, group); + +  return 0; +} + +void  +peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, +			     afi_t afi, safi_t safi) +{ +  int in = FILTER_IN; +  int out = FILTER_OUT; +  struct peer *conf; +  struct bgp_filter *pfilter; +  struct bgp_filter *gfilter; + +  conf = group->conf; +  pfilter = &peer->filter[afi][safi]; +  gfilter = &conf->filter[afi][safi]; + +  /* remote-as */ +  if (conf->as) +    peer->as = conf->as; + +  /* remote-as */ +  if (conf->change_local_as) +    peer->change_local_as = conf->change_local_as; + +  /* TTL */ +  peer->ttl = conf->ttl; + +  /* Weight */ +  peer->weight = conf->weight; + +  /* peer flags apply */ +  peer->flags = conf->flags; +  /* peer af_flags apply */ +  peer->af_flags[afi][safi] = conf->af_flags[afi][safi]; +  /* peer config apply */ +  peer->config = conf->config; + +  /* peer timers apply */ +  peer->holdtime = conf->holdtime; +  peer->keepalive = conf->keepalive; +  peer->connect = conf->connect; +  if (CHECK_FLAG (conf->config, PEER_CONFIG_CONNECT)) +    peer->v_connect = conf->connect; +  else +    peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; + +  /* advertisement-interval reset */ +  if (peer_sort (peer) == BGP_PEER_IBGP) +    peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; +  else +    peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + +  /* maximum-prefix */ +  peer->pmax[afi][safi] = conf->pmax[afi][safi]; + +  /* allowas-in */ +  peer->allowas_in[afi][safi] = conf->allowas_in[afi][safi]; + +  /* default-originate route-map */ +  if (conf->default_rmap[afi][safi].name) +    { +      if (peer->default_rmap[afi][safi].name) +	free (peer->default_rmap[afi][safi].name); +      peer->default_rmap[afi][safi].name = strdup (conf->default_rmap[afi][safi].name); +      peer->default_rmap[afi][safi].map = conf->default_rmap[afi][safi].map; +    } + +  /* update-source apply */ +  if (conf->update_source) +    { +      if (peer->update_source) +	sockunion_free (peer->update_source); +      if (peer->update_if) +	{ +	  XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); +	  peer->update_if = NULL; +	} +      peer->update_source = sockunion_dup (conf->update_source); +    } +  else if (conf->update_if) +    { +      if (peer->update_if) +	XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); +      if (peer->update_source) +	{ +	  sockunion_free (peer->update_source); +	  peer->update_source = NULL; +	} +      peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, conf->update_if); +    } + +  /* inbound filter apply */ +  if (gfilter->dlist[in].name && ! pfilter->dlist[in].name) +    { +      if (pfilter->dlist[in].name) +	free (pfilter->dlist[in].name); +      pfilter->dlist[in].name = strdup (gfilter->dlist[in].name); +      pfilter->dlist[in].alist = gfilter->dlist[in].alist; +    } +  if (gfilter->plist[in].name && ! pfilter->plist[in].name) +    { +      if (pfilter->plist[in].name) +	free (pfilter->plist[in].name); +      pfilter->plist[in].name = strdup (gfilter->plist[in].name); +      pfilter->plist[in].plist = gfilter->plist[in].plist; +    } +  if (gfilter->aslist[in].name && ! pfilter->aslist[in].name) +    { +      if (pfilter->aslist[in].name) +	free (pfilter->aslist[in].name); +      pfilter->aslist[in].name = strdup (gfilter->aslist[in].name); +      pfilter->aslist[in].aslist = gfilter->aslist[in].aslist; +    } +  if (gfilter->map[in].name && ! pfilter->map[in].name) +    { +      if (pfilter->map[in].name) +	free (pfilter->map[in].name); +      pfilter->map[in].name = strdup (gfilter->map[in].name); +      pfilter->map[in].map = gfilter->map[in].map; +    } + +  /* outbound filter apply */ +  if (gfilter->dlist[out].name) +    { +      if (pfilter->dlist[out].name) +	free (pfilter->dlist[out].name); +      pfilter->dlist[out].name = strdup (gfilter->dlist[out].name); +      pfilter->dlist[out].alist = gfilter->dlist[out].alist; +    } +  else +    { +      if (pfilter->dlist[out].name) +	free (pfilter->dlist[out].name); +      pfilter->dlist[out].name = NULL; +      pfilter->dlist[out].alist = NULL; +    } +  if (gfilter->plist[out].name) +    { +      if (pfilter->plist[out].name) +	free (pfilter->plist[out].name); +      pfilter->plist[out].name = strdup (gfilter->plist[out].name); +      pfilter->plist[out].plist = gfilter->plist[out].plist; +    } +  else +    { +      if (pfilter->plist[out].name) +	free (pfilter->plist[out].name); +      pfilter->plist[out].name = NULL; +      pfilter->plist[out].plist = NULL; +    } +  if (gfilter->aslist[out].name) +    { +      if (pfilter->aslist[out].name) +	free (pfilter->aslist[out].name); +      pfilter->aslist[out].name = strdup (gfilter->aslist[out].name); +      pfilter->aslist[out].aslist = gfilter->aslist[out].aslist; +    } +  else +    { +      if (pfilter->aslist[out].name) +	free (pfilter->aslist[out].name); +      pfilter->aslist[out].name = NULL; +      pfilter->aslist[out].aslist = NULL; +    } +  if (gfilter->map[out].name) +    { +      if (pfilter->map[out].name) +	free (pfilter->map[out].name); +      pfilter->map[out].name = strdup (gfilter->map[out].name); +      pfilter->map[out].map = gfilter->map[out].map; +    } +  else +    { +      if (pfilter->map[out].name) +	free (pfilter->map[out].name); +      pfilter->map[out].name = NULL; +      pfilter->map[out].map = NULL; +    } + +  if (gfilter->usmap.name) +    { +      if (pfilter->usmap.name) +	free (pfilter->usmap.name); +      pfilter->usmap.name = strdup (gfilter->usmap.name); +      pfilter->usmap.map = gfilter->usmap.map; +    } +  else +    { +      if (pfilter->usmap.name) +	free (pfilter->usmap.name); +      pfilter->usmap.name = NULL; +      pfilter->usmap.map = NULL; +    } +}  + +/* Peer group's remote AS configuration.  */ +int +peer_group_remote_as (struct bgp *bgp, char *group_name, as_t *as) +{ +  struct peer_group *group; +  struct peer *peer; +  struct listnode *nn; + +  group = peer_group_lookup (bgp, group_name); +  if (! group) +    return -1; + +  if (group->conf->as == *as) +    return 0; + +  /* When we setup peer-group AS number all peer group member's AS +     number must be updated to same number.  */ +  peer_as_change (group->conf, *as); + +  LIST_LOOP (group->peer, peer, nn) +    { +      if (peer->as != *as) +	peer_as_change (peer, *as); +    } + +  return 0; +} + +int +peer_group_delete (struct peer_group *group) +{ +  struct bgp *bgp; +  struct peer *peer; +  struct listnode *nn; + +  bgp = group->bgp; + +  LIST_LOOP (group->peer, peer, nn) +    { +      peer->group = NULL; +      peer_delete (peer); +    } +  list_delete (group->peer); + +  free (group->name); +  group->name = NULL; + +  group->conf->group = NULL; +  peer_delete (group->conf); + +  /* Delete from all peer_group list. */ +  listnode_delete (bgp->group, group); + +  peer_group_free (group); + +  return 0; +} + +int +peer_group_remote_as_delete (struct peer_group *group) +{ +  struct peer *peer; +  struct listnode *nn; + +  if (! group->conf->as) +    return 0; + +  LIST_LOOP (group->peer, peer, nn) +    { +      peer->group = NULL; +      peer_delete (peer); +    } +  list_delete_all_node (group->peer); + +  group->conf->as = 0; + +  return 0; +} + +/* Bind specified peer to peer group.  */ +int +peer_group_bind (struct bgp *bgp, union sockunion *su, +		 struct peer_group *group, afi_t afi, safi_t safi, as_t *as) +{ +  struct peer *peer; +  int first_member = 0; + +  /* Check peer group's address family.  */ +  if (! group->conf->afc[afi][safi]) +    return BGP_ERR_PEER_GROUP_AF_UNCONFIGURED; + +  /* Lookup the peer.  */ +  peer = peer_lookup (bgp, su); + +  /* Create a new peer. */ +  if (! peer) +    { +      if (! group->conf->as) +	return BGP_ERR_PEER_GROUP_NO_REMOTE_AS; + +      peer = peer_create (su, bgp, bgp->as, group->conf->as, afi, safi); +      peer->group = group; +      peer->af_group[afi][safi] = 1; +      listnode_add (group->peer, peer); +      peer_group2peer_config_copy (group, peer, afi, safi); + +      return 0; +    } + +  /* When the peer already belongs to peer group, check the consistency.  */ +  if (peer->af_group[afi][safi]) +    { +      if (strcmp (peer->group->name, group->name) != 0) +	return BGP_ERR_PEER_GROUP_CANT_CHANGE; + +      return 0; +    } + +  /* Check current peer group configuration.  */ +  if (peer_group_active (peer) +      && strcmp (peer->group->name, group->name) != 0) +    return BGP_ERR_PEER_GROUP_MISMATCH; + +  if (! group->conf->as) +    { +      if (peer_sort (group->conf) != BGP_PEER_INTERNAL +	  && peer_sort (group->conf) != peer_sort (peer)) +	{ +	  if (as) +	    *as = peer->as; +	  return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; +	} + +      if (peer_sort (group->conf) == BGP_PEER_INTERNAL) +	first_member = 1; +    } + +  peer->af_group[afi][safi] = 1; +  peer->afc[afi][safi] = 1; +  if (! peer->group) +    { +      peer->group = group; +      listnode_add (group->peer, peer); +    } + +  if (first_member) +    { +      /* Advertisement-interval reset */ +      if (peer_sort (group->conf) == BGP_PEER_IBGP) +	group->conf->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; +      else +	group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + +      /* ebgp-multihop reset */ +      if (peer_sort (group->conf) == BGP_PEER_IBGP) +	group->conf->ttl = 255; + +      /* local-as reset */ +      if (peer_sort (group->conf) != BGP_PEER_EBGP) +	{ +	  group->conf->change_local_as = 0; +	  UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); +	} +    } +  peer_group2peer_config_copy (group, peer, afi, safi); + +  if (peer->status == Established) +    bgp_notify_send (peer, BGP_NOTIFY_CEASE, +		     BGP_NOTIFY_CEASE_CONFIG_CHANGE); +  else +    BGP_EVENT_ADD (peer, BGP_Stop); + +  return 0; +} + +int +peer_group_unbind (struct bgp *bgp, struct peer *peer, +		   struct peer_group *group, afi_t afi, safi_t safi) +{ +  if (! peer->af_group[afi][safi]) +      return 0; + +  if (group != peer->group) +    return BGP_ERR_PEER_GROUP_MISMATCH; + +  peer->af_group[afi][safi] = 0; +  peer->afc[afi][safi] = 0; +  peer_af_flag_reset (peer, afi, safi); + +  if (! peer_group_active (peer)) +    { +      listnode_delete (group->peer, peer); +      peer->group = NULL; +      if (group->conf->as) +	{ +	  peer_delete (peer); +	  return 0; +	} +      peer_global_config_reset (peer); +    } + +  if (peer->status == Established) +    bgp_notify_send (peer, BGP_NOTIFY_CEASE, +		     BGP_NOTIFY_CEASE_CONFIG_CHANGE); +  else +    BGP_EVENT_ADD (peer, BGP_Stop); + +  return 0; +} + +/* BGP instance creation by `router bgp' commands. */ +struct bgp * +bgp_create (as_t *as, char *name) +{ +  struct bgp *bgp; +  afi_t afi; +  safi_t safi; + +  bgp = XCALLOC (MTYPE_BGP, sizeof (struct bgp)); + +  bgp->peer_self = peer_new (); +  bgp->peer_self->host = "Static announcement"; + +  bgp->peer = list_new (); +  bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp; + +  bgp->group = list_new (); +  bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp; + +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      { +	bgp->route[afi][safi] = bgp_table_init (); +	bgp->aggregate[afi][safi] = bgp_table_init (); +	bgp->rib[afi][safi] = bgp_table_init (); +      } + +  bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; +  bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; +  bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; + +  bgp->as = *as; + +  if (name) +    bgp->name = strdup (name); + +  return bgp; +} + +/* Return first entry of BGP. */ +struct bgp * +bgp_get_default () +{ +  if (bm->bgp->head) +    return bm->bgp->head->data; +  return NULL; +} + +/* Lookup BGP entry. */ +struct bgp * +bgp_lookup (as_t as, char *name) +{ +  struct bgp *bgp; +  struct listnode *nn; + +  LIST_LOOP (bm->bgp, bgp, nn) +    if (bgp->as == as +	&& ((bgp->name == NULL && name == NULL)  +	    || (bgp->name && name && strcmp (bgp->name, name) == 0))) +      return bgp; +  return NULL; +} + +/* Lookup BGP structure by view name. */ +struct bgp * +bgp_lookup_by_name (char *name) +{ +  struct bgp *bgp; +  struct listnode *nn; + +  LIST_LOOP (bm->bgp, bgp, nn) +    if ((bgp->name == NULL && name == NULL) +	|| (bgp->name && name && strcmp (bgp->name, name) == 0)) +      return bgp; +  return NULL; +} + +/* Called from VTY commands. */ +int +bgp_get (struct bgp **bgp_val, as_t *as, char *name) +{ +  struct bgp *bgp; + +  /* Multiple instance check. */ +  if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE)) +    { +      if (name) +	bgp = bgp_lookup_by_name (name); +      else +	bgp = bgp_get_default (); + +      /* Already exists. */ +      if (bgp) +	{ +          if (bgp->as != *as) +	    { +	      *as = bgp->as; +	      return BGP_ERR_INSTANCE_MISMATCH; +	    } +	  *bgp_val = bgp; +	  return 0; +	} +    } +  else +    { +      /* BGP instance name can not be specified for single instance.  */ +      if (name) +	return BGP_ERR_MULTIPLE_INSTANCE_NOT_SET; + +      /* Get default BGP structure if exists. */ +      bgp = bgp_get_default (); + +      if (bgp) +	{ +	  if (bgp->as != *as) +	    { +	      *as = bgp->as; +	      return BGP_ERR_AS_MISMATCH; +	    } +	  *bgp_val = bgp; +	  return 0; +	} +    } + +  bgp = bgp_create (as, name); +  listnode_add (bm->bgp, bgp); +  bgp_if_update_all (); +  *bgp_val = bgp; + +  return 0; +} + +/* Delete BGP instance. */ +int +bgp_delete (struct bgp *bgp) +{ +  struct peer *peer; +  struct listnode *nn; +  struct listnode *next; +  afi_t afi; +  safi_t safi; +  int i; + +  /* Delete static route. */ +  bgp_static_delete (bgp); + +  /* Unset redistribution. */ +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (i = 0; i < ZEBRA_ROUTE_MAX; i++)  +      if (i != ZEBRA_ROUTE_BGP) +	bgp_redistribute_unset (bgp, afi, i); + +  bgp->group->del = (void (*)(void *)) peer_group_delete; +  list_delete (bgp->group); + +  for (nn = bgp->peer->head; nn; nn = next) +    { +      peer = nn->data; +      next = nn->next; +      peer_delete (peer); +    } + +  listnode_delete (bm->bgp, bgp); + +  if (bgp->name) +    free (bgp->name); +   +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      { +	if (bgp->route[afi][safi]) +	  XFREE (MTYPE_ROUTE_TABLE, bgp->route[afi][safi]); +	if (bgp->aggregate[afi][safi]) +	  XFREE (MTYPE_ROUTE_TABLE,bgp->aggregate[afi][safi]) ; +	if (bgp->rib[afi][safi]) +	  XFREE (MTYPE_ROUTE_TABLE,bgp->rib[afi][safi]); +      } +  XFREE (MTYPE_BGP, bgp); + +  return 0; +} + +struct peer * +peer_lookup (struct bgp *bgp, union sockunion *su) +{ +  struct peer *peer; +  struct listnode *nn; + +  if (! bgp) +    bgp = bgp_get_default (); + +  if (! bgp) +    return NULL; +   +  LIST_LOOP (bgp->peer, peer, nn) +    { +      if (sockunion_same (&peer->su, su) +	  && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) +	return peer; +    } +  return NULL; +} + +struct peer * +peer_lookup_with_open (union sockunion *su, as_t remote_as, +		       struct in_addr *remote_id, int *as) +{ +  struct peer *peer; +  struct listnode *nn; +  struct bgp *bgp; + +  bgp = bgp_get_default (); +  if (! bgp) +    return NULL; + +  LIST_LOOP (bgp->peer, peer, nn) +    { +      if (sockunion_same (&peer->su, su) +	  && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) +	{ +	  if (peer->as == remote_as +	      && peer->remote_id.s_addr == remote_id->s_addr) +	    return peer; +	  if (peer->as == remote_as) +	    *as = 1; +	} +    } +  LIST_LOOP (bgp->peer, peer, nn) +    { +      if (sockunion_same (&peer->su, su) +	  &&  ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) +	{ +	  if (peer->as == remote_as +	      && peer->remote_id.s_addr == 0) +	    return peer; +	  if (peer->as == remote_as) +	    *as = 1; +	} +    } +  return NULL; +} + +/* If peer is configured at least one address family return 1. */ +int +peer_active (struct peer *peer) +{ +  if (peer->afc[AFI_IP][SAFI_UNICAST] +      || peer->afc[AFI_IP][SAFI_MULTICAST] +      || peer->afc[AFI_IP][SAFI_MPLS_VPN] +      || peer->afc[AFI_IP6][SAFI_UNICAST] +      || peer->afc[AFI_IP6][SAFI_MULTICAST]) +    return 1; +  return 0; +} + +/* If peer is negotiated at least one address family return 1. */ +int +peer_active_nego (struct peer *peer) +{ +  if (peer->afc_nego[AFI_IP][SAFI_UNICAST] +      || peer->afc_nego[AFI_IP][SAFI_MULTICAST] +      || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] +      || peer->afc_nego[AFI_IP6][SAFI_UNICAST] +      || peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) +    return 1; +  return 0; +} + +/* peer_flag_change_type. */ +enum peer_change_type +{ +  peer_change_none, +  peer_change_reset, +  peer_change_reset_in, +  peer_change_reset_out, +}; + +void +peer_change_action (struct peer *peer, afi_t afi, safi_t safi, +		    enum peer_change_type type) +{ +  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return; + +  if (type == peer_change_reset) +    bgp_notify_send (peer, BGP_NOTIFY_CEASE, +		     BGP_NOTIFY_CEASE_CONFIG_CHANGE); +  else if (type == peer_change_reset_in) +    { +      if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV) +	  || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) +	bgp_route_refresh_send (peer, afi, safi, 0, 0, 0); +      else +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +    } +  else if (type == peer_change_reset_out) +    bgp_announce_route (peer, afi, safi); +} + +struct peer_flag_action +{ +  /* Peer's flag.  */ +  u_int32_t flag; + +  /* This flag can be set for peer-group member.  */ +  u_char not_for_member; + +  /* Action when the flag is changed.  */ +  enum peer_change_type type; +}; + +struct peer_flag_action peer_flag_action_list[] =  +  { +    { PEER_FLAG_PASSIVE,                  0, peer_change_reset }, +    { PEER_FLAG_SHUTDOWN,                 0, peer_change_reset }, +    { PEER_FLAG_DONT_CAPABILITY,          0, peer_change_none }, +    { PEER_FLAG_OVERRIDE_CAPABILITY,      0, peer_change_none }, +    { PEER_FLAG_STRICT_CAP_MATCH,         0, peer_change_none }, +    { PEER_FLAG_NO_ROUTE_REFRESH_CAP,     0, peer_change_reset }, +    { PEER_FLAG_DYNAMIC_CAPABILITY,       0, peer_change_reset }, +    { PEER_FLAG_ENFORCE_MULTIHOP,         0, peer_change_reset }, +    { 0, 0, 0 } +  }; + +struct peer_flag_action peer_af_flag_action_list[] =  +  { +    { PEER_FLAG_NEXTHOP_SELF,             1, peer_change_reset_out }, +    { PEER_FLAG_SEND_COMMUNITY,           1, peer_change_reset_out }, +    { PEER_FLAG_SEND_EXT_COMMUNITY,       1, peer_change_reset_out }, +    { PEER_FLAG_SOFT_RECONFIG,            0, peer_change_reset_in }, +    { PEER_FLAG_REFLECTOR_CLIENT,         1, peer_change_reset }, +    { PEER_FLAG_RSERVER_CLIENT,           1, peer_change_reset }, +    { PEER_FLAG_AS_PATH_UNCHANGED,        1, peer_change_reset_out }, +    { PEER_FLAG_NEXTHOP_UNCHANGED,        1, peer_change_reset_out }, +    { PEER_FLAG_MED_UNCHANGED,            1, peer_change_reset_out }, +    { PEER_FLAG_REMOVE_PRIVATE_AS,        1, peer_change_reset_out }, +    { PEER_FLAG_ALLOWAS_IN,               0, peer_change_reset_in }, +    { PEER_FLAG_ORF_PREFIX_SM,            1, peer_change_reset }, +    { PEER_FLAG_ORF_PREFIX_RM,            1, peer_change_reset }, +    { 0, 0, 0 } +  }; + +/* Proper action set. */ +int +peer_flag_action_set (struct peer_flag_action *action_list, int size, +		      struct peer_flag_action *action, u_int32_t flag) +{ +  int i; +  int found = 0; +  int reset_in = 0; +  int reset_out = 0; +  struct peer_flag_action *match = NULL; + +  /* Check peer's frag action.  */ +  for (i = 0; i < size; i++) +    { +      match = &action_list[i]; + +      if (match->flag == 0) +	break; + +      if (match->flag & flag) +	{ +	  found = 1; + +	  if (match->type == peer_change_reset_in) +	    reset_in = 1; +	  if (match->type == peer_change_reset_out) +	    reset_out = 1; +	  if (match->type == peer_change_reset) +	    { +	      reset_in = 1; +	      reset_out = 1; +	    } +	  if (match->not_for_member) +	    action->not_for_member = 1; +	} +    } + +  /* Set peer clear type.  */ +  if (reset_in && reset_out) +    action->type = peer_change_reset; +  else if (reset_in) +    action->type = peer_change_reset_in; +  else if (reset_out) +    action->type = peer_change_reset_out; +  else +    action->type = peer_change_none; + +  return found; +} + +void +peer_flag_modify_action (struct peer *peer, u_int32_t flag) +{ +  if (flag == PEER_FLAG_SHUTDOWN) +    { +      if (CHECK_FLAG (peer->flags, flag)) +	{ +	  if (peer->status == Established) +	    bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			     BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); +	  else +	    BGP_EVENT_ADD (peer, BGP_Stop); +	} +      else +	{ +	  peer->v_start = BGP_INIT_START_TIMER; +	  BGP_EVENT_ADD (peer, BGP_Stop); +	} +    } +  else if (peer->status == Established) +    { +      if (flag == PEER_FLAG_NO_ROUTE_REFRESH_CAP +	  && CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV)) +	{ +	  if (CHECK_FLAG (peer->flags, flag)) +	    UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV); +	  else +	    SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV); + +	  bgp_capability_send (peer, AFI_IP, SAFI_UNICAST, +			       CAPABILITY_CODE_REFRESH, +			       CHECK_FLAG (peer->flags, flag) ? +			       CAPABILITY_ACTION_UNSET : CAPABILITY_ACTION_SET); +	} +      else +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +    } +  else +    BGP_EVENT_ADD (peer, BGP_Stop); +} + +/* Change specified peer flag. */ +int +peer_flag_modify (struct peer *peer, u_int32_t flag, int set) +{ +  int found; +  int size; +  struct peer_group *group; +  struct listnode *nn; +  struct peer_flag_action action; + +  memset (&action, 0, sizeof (struct peer_flag_action)); +  size = sizeof peer_flag_action_list / sizeof (struct peer_flag_action); + +  found = peer_flag_action_set (peer_flag_action_list, size, &action, flag); + +  /* No flag action is found.  */ +  if (! found) +    return BGP_ERR_INVALID_FLAG;     + +  /* Not for peer-group member.  */ +  if (action.not_for_member && peer_group_active (peer)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  /* When unset the peer-group member's flag we have to check +     peer-group configuration.  */ +  if (! set && peer_group_active (peer)) +    if (CHECK_FLAG (peer->group->conf->flags, flag)) +      { +	if (flag == PEER_FLAG_SHUTDOWN) +	  return BGP_ERR_PEER_GROUP_SHUTDOWN; +	else +	  return BGP_ERR_PEER_GROUP_HAS_THE_FLAG; +      } + +  /* Flag conflict check.  */ +  if (set +      && CHECK_FLAG (peer->flags | flag, PEER_FLAG_STRICT_CAP_MATCH) +      && CHECK_FLAG (peer->flags | flag, PEER_FLAG_OVERRIDE_CAPABILITY)) +    return BGP_ERR_PEER_FLAG_CONFLICT; + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (set && CHECK_FLAG (peer->flags, flag) == flag) +	return 0; +      if (! set && ! CHECK_FLAG (peer->flags, flag)) +	return 0; +    } + +  if (set) +    SET_FLAG (peer->flags, flag); +  else +    UNSET_FLAG (peer->flags, flag); +  +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (action.type == peer_change_reset) +	peer_flag_modify_action (peer, flag); + +      return 0; +    } + +  /* peer-group member updates. */ +  group = peer->group; + +  LIST_LOOP (group->peer, peer, nn) +    { +      if (set && CHECK_FLAG (peer->flags, flag) == flag) +	continue; + +      if (! set && ! CHECK_FLAG (peer->flags, flag)) +	continue; + +      if (set) +	SET_FLAG (peer->flags, flag); +      else +	UNSET_FLAG (peer->flags, flag); + +      if (action.type == peer_change_reset) +	peer_flag_modify_action (peer, flag); +    } +  return 0; +} + +int +peer_flag_set (struct peer *peer, u_int32_t flag) +{ +  return peer_flag_modify (peer, flag, 1); +} + +int +peer_flag_unset (struct peer *peer, u_int32_t flag) +{ +  return peer_flag_modify (peer, flag, 0); +} + +int +peer_is_group_member (struct peer *peer, afi_t afi, safi_t safi) +{ +  if (peer->af_group[afi][safi]) +    return 1; +  return 0; +} + +int +peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag, +		     int set) +{ +  int found; +  int size; +  struct listnode *nn; +  struct peer_group *group; +  struct peer_flag_action action; + +  memset (&action, 0, sizeof (struct peer_flag_action)); +  size = sizeof peer_af_flag_action_list / sizeof (struct peer_flag_action); +   +  found = peer_flag_action_set (peer_af_flag_action_list, size, &action, flag); +   +  /* No flag action is found.  */ +  if (! found) +    return BGP_ERR_INVALID_FLAG;     + +  /* Adress family must be activated.  */ +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  /* Not for peer-group member.  */ +  if (action.not_for_member && peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + + /* Spcecial check for reflector client.  */ +  if (flag & PEER_FLAG_REFLECTOR_CLIENT +      && peer_sort (peer) != BGP_PEER_IBGP) +    return BGP_ERR_NOT_INTERNAL_PEER; + +  /* Spcecial check for remove-private-AS.  */ +  if (flag & PEER_FLAG_REMOVE_PRIVATE_AS +      && peer_sort (peer) == BGP_PEER_IBGP) +    return BGP_ERR_REMOVE_PRIVATE_AS; + +  /* When unset the peer-group member's flag we have to check +     peer-group configuration.  */ +  if (! set && peer->af_group[afi][safi]) +    if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi], flag)) +      return BGP_ERR_PEER_GROUP_HAS_THE_FLAG; + +  /* When current flag configuration is same as requested one.  */ +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag) +	return 0; +      if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag)) +	return 0; +    } + +  if (set) +    SET_FLAG (peer->af_flags[afi][safi], flag); +  else +    UNSET_FLAG (peer->af_flags[afi][safi], flag); + +  /* Execute action when peer is established.  */ +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) +      && peer->status == Established) +    { +      if (! set && flag == PEER_FLAG_SOFT_RECONFIG) +	bgp_clear_adj_in (peer, afi, safi); +      else +	peer_change_action (peer, afi, safi, action.type); +    } + +  /* Peer group member updates.  */ +  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      group = peer->group; +       +      LIST_LOOP (group->peer, peer, nn) +	{ +	  if (! peer->af_group[afi][safi]) +	    continue; + +	  if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag) +	    continue; + +	  if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag)) +	    continue; + +	  if (set) +	    SET_FLAG (peer->af_flags[afi][safi], flag); +	  else +	    UNSET_FLAG (peer->af_flags[afi][safi], flag); + +	  if (peer->status == Established) +	    { +	      if (! set && flag == PEER_FLAG_SOFT_RECONFIG) +		bgp_clear_adj_in (peer, afi, safi); +	      else +		peer_change_action (peer, afi, safi, action.type); +	    } +	} +    } +  return 0; +} + +int +peer_af_flag_set (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag) +{ +  return peer_af_flag_modify (peer, afi, safi, flag, 1); +} + +int +peer_af_flag_unset (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag) +{ +  return peer_af_flag_modify (peer, afi, safi, flag, 0); +} + +/* EBGP multihop configuration. */ +int +peer_ebgp_multihop_set (struct peer *peer, int ttl) +{ +  struct peer_group *group; +  struct listnode *nn; + +  if (peer_sort (peer) == BGP_PEER_IBGP) +    return 0; + +  peer->ttl = ttl; + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) +	sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); +    } +  else +    { +      group = peer->group; +      LIST_LOOP (group->peer, peer, nn) +	{ +	  if (peer_sort (peer) == BGP_PEER_IBGP) +	    continue; + +	  peer->ttl = group->conf->ttl; + +	  if (peer->fd >= 0) +	    sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); +	} +    } +  return 0; +} + +int +peer_ebgp_multihop_unset (struct peer *peer) +{ +  struct peer_group *group; +  struct listnode *nn; + +  if (peer_sort (peer) == BGP_PEER_IBGP) +    return 0; + +  if (peer_group_active (peer)) +    peer->ttl = peer->group->conf->ttl; +  else +    peer->ttl = 1; + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) +	sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); +    } +  else +    { +      group = peer->group; +      LIST_LOOP (group->peer, peer, nn) +	{ +	  if (peer_sort (peer) == BGP_PEER_IBGP) +	    continue; + +	  peer->ttl = 1; +	   +	  if (peer->fd >= 0) +	    sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); +	} +    } +  return 0; +} + +/* Neighbor description. */ +int +peer_description_set (struct peer *peer, char *desc) +{ +  if (peer->desc) +    XFREE (MTYPE_PEER_DESC, peer->desc); + +  peer->desc = XSTRDUP (MTYPE_PEER_DESC, desc); + +  return 0; +} + +int +peer_description_unset (struct peer *peer) +{ +  if (peer->desc) +    XFREE (MTYPE_PEER_DESC, peer->desc); + +  peer->desc = NULL; + +  return 0; +} + +/* Neighbor update-source. */ +int +peer_update_source_if_set (struct peer *peer, char *ifname) +{ +  struct peer_group *group; +  struct listnode *nn; + +  if (peer->update_if) +    { +      if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) +	  && strcmp (peer->update_if, ifname) == 0) +	return 0; + +      XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); +      peer->update_if = NULL; +    } + +  if (peer->update_source) +    { +      sockunion_free (peer->update_source); +      peer->update_source = NULL; +    } + +  peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (peer->status == Established) +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +      else +	BGP_EVENT_ADD (peer, BGP_Stop); +      return 0; +    } + +  /* peer-group member updates. */ +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      if (peer->update_if) +	{ +	  if (strcmp (peer->update_if, ifname) == 0) +	    continue; + +	  XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); +	  peer->update_if = NULL; +	} + +      if (peer->update_source) +	{ +	  sockunion_free (peer->update_source); +	  peer->update_source = NULL; +	} + +      peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname); + +      if (peer->status == Established) +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +      else +	BGP_EVENT_ADD (peer, BGP_Stop); +    } +  return 0; +} + +int +peer_update_source_addr_set (struct peer *peer, union sockunion *su) +{ +  struct peer_group *group; +  struct listnode *nn; + +  if (peer->update_source) +    { +      if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) +	  && sockunion_cmp (peer->update_source, su) == 0) +	return 0; +      sockunion_free (peer->update_source); +      peer->update_source = NULL; +    } + +  if (peer->update_if) +    { +      XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); +      peer->update_if = NULL; +    } + +  peer->update_source = sockunion_dup (su); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (peer->status == Established) +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +      else +	BGP_EVENT_ADD (peer, BGP_Stop); +      return 0; +    } + +  /* peer-group member updates. */ +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      if (peer->update_source) +	{ +	  if (sockunion_cmp (peer->update_source, su) == 0) +	    continue; +	  sockunion_free (peer->update_source); +	  peer->update_source = NULL; +	} + +      if (peer->update_if) +	{ +	  XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); +	  peer->update_if = NULL; +	} + +      peer->update_source = sockunion_dup (su); + +      if (peer->status == Established) +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +      else +	BGP_EVENT_ADD (peer, BGP_Stop); +    } +  return 0; +} + +int +peer_update_source_unset (struct peer *peer) +{ +  union sockunion *su; +  struct peer_group *group; +  struct listnode *nn; + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) +      && ! peer->update_source +      && ! peer->update_if) +    return 0; + +  if (peer->update_source) +    { +      sockunion_free (peer->update_source); +      peer->update_source = NULL; +    } +  if (peer->update_if) +    { +      XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); +      peer->update_if = NULL; +    } + +  if (peer_group_active (peer)) +    { +      group = peer->group; + +      if (group->conf->update_source) +	{ +	  su = sockunion_dup (group->conf->update_source); +	  peer->update_source = su; +	} +      else if (group->conf->update_if) +	peer->update_if =  +	  XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, group->conf->update_if); +    } + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (peer->status == Established) +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +      else +	BGP_EVENT_ADD (peer, BGP_Stop); +      return 0; +    } + +  /* peer-group member updates. */ +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      if (! peer->update_source && ! peer->update_if) +	continue; + +      if (peer->update_source) +	{ +	  sockunion_free (peer->update_source); +	  peer->update_source = NULL; +	} + +      if (peer->update_if) +	{ +	  XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); +	  peer->update_if = NULL; +	} + +      if (peer->status == Established) +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_CONFIG_CHANGE); +      else +	BGP_EVENT_ADD (peer, BGP_Stop); +    } +  return 0; +} + +int +peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi, +			    char *rmap) +{ +  struct peer_group *group; +  struct listnode *nn; + +  /* Adress family must be activated.  */ +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  /* Default originate can't be used for peer group memeber.  */ +  if (peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE) +      || (rmap && ! peer->default_rmap[afi][safi].name) +      || (rmap && strcmp (rmap, peer->default_rmap[afi][safi].name) != 0)) +    {  +      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE); + +      if (rmap) +	{ +	  if (peer->default_rmap[afi][safi].name) +	    free (peer->default_rmap[afi][safi].name); +	  peer->default_rmap[afi][safi].name = strdup (rmap); +	  peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap); +	} +    } + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (peer->status == Established && peer->afc_nego[afi][safi]) +	bgp_default_originate (peer, afi, safi, 0); +      return 0; +    } + +  /* peer-group member updates. */ +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE); + +      if (rmap) +	{ +	  if (peer->default_rmap[afi][safi].name) +	    free (peer->default_rmap[afi][safi].name); +	  peer->default_rmap[afi][safi].name = strdup (rmap); +	  peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap); +	} + +      if (peer->status == Established && peer->afc_nego[afi][safi]) +	bgp_default_originate (peer, afi, safi, 0); +    } +  return 0; +} + +int +peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi) +{ +  struct peer_group *group; +  struct listnode *nn; + +  /* Adress family must be activated.  */ +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  /* Default originate can't be used for peer group memeber.  */ +  if (peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) +    {  +      UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE); + +      if (peer->default_rmap[afi][safi].name) +	free (peer->default_rmap[afi][safi].name); +      peer->default_rmap[afi][safi].name = NULL; +      peer->default_rmap[afi][safi].map = NULL; +    } + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (peer->status == Established && peer->afc_nego[afi][safi]) +	bgp_default_originate (peer, afi, safi, 1); +      return 0; +    } + +  /* peer-group member updates. */ +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE); + +      if (peer->default_rmap[afi][safi].name) +	free (peer->default_rmap[afi][safi].name); +      peer->default_rmap[afi][safi].name = NULL; +      peer->default_rmap[afi][safi].map = NULL; + +      if (peer->status == Established && peer->afc_nego[afi][safi]) +	bgp_default_originate (peer, afi, safi, 1); +    } +  return 0; +} + +int +peer_port_set (struct peer *peer, u_int16_t port) +{ +  peer->port = port; +  return 0; +} + +int +peer_port_unset (struct peer *peer) +{ +  peer->port = BGP_PORT_DEFAULT; +  return 0; +} + +/* neighbor weight. */ +int +peer_weight_set (struct peer *peer, u_int16_t weight) +{ +  struct peer_group *group; +  struct listnode *nn; + +  SET_FLAG (peer->config, PEER_CONFIG_WEIGHT); +  peer->weight = weight; + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  /* peer-group member updates. */ +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      peer->weight = group->conf->weight; +    } +  return 0; +} + +int +peer_weight_unset (struct peer *peer) +{ +  struct peer_group *group; +  struct listnode *nn; + +  /* Set default weight. */ +  if (peer_group_active (peer)) +    peer->weight = peer->group->conf->weight; +  else +    peer->weight = 0; + +  UNSET_FLAG (peer->config, PEER_CONFIG_WEIGHT); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  /* peer-group member updates. */ +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      peer->weight = 0; +    } +  return 0; +} + +int +peer_timers_set (struct peer *peer, u_int32_t keepalive, u_int32_t holdtime) +{ +  struct peer_group *group; +  struct listnode *nn; + +  /* Not for peer group memeber.  */ +  if (peer_group_active (peer)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  /* keepalive value check.  */ +  if (keepalive > 65535) +    return BGP_ERR_INVALID_VALUE; + +  /* Holdtime value check.  */ +  if (holdtime > 65535) +    return BGP_ERR_INVALID_VALUE; + +  /* Holdtime value must be either 0 or greater than 3.  */ +  if (holdtime < 3 && holdtime != 0) +    return BGP_ERR_INVALID_VALUE; + +  /* Set value to the configuration. */ +  SET_FLAG (peer->config, PEER_CONFIG_TIMER); +  peer->holdtime = holdtime; +  peer->keepalive = (keepalive < holdtime / 3 ? keepalive : holdtime / 3); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  /* peer-group member updates. */ +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      SET_FLAG (peer->config, PEER_CONFIG_TIMER); +      peer->holdtime = group->conf->holdtime; +      peer->keepalive = group->conf->keepalive; +    } +  return 0; +} + +int +peer_timers_unset (struct peer *peer) +{ +  struct peer_group *group; +  struct listnode *nn; + +  if (peer_group_active (peer)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  /* Clear configuration. */ +  UNSET_FLAG (peer->config, PEER_CONFIG_TIMER); +  peer->keepalive = 0; +  peer->holdtime = 0; + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  /* peer-group member updates. */ +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      UNSET_FLAG (peer->config, PEER_CONFIG_TIMER); +      peer->holdtime = 0; +      peer->keepalive = 0; +    } + +  return 0; +} + +int +peer_timers_connect_set (struct peer *peer, u_int32_t connect) +{ +  if (peer_group_active (peer)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  if (connect > 65535) +    return BGP_ERR_INVALID_VALUE; + +  /* Set value to the configuration. */ +  SET_FLAG (peer->config, PEER_CONFIG_CONNECT); +  peer->connect = connect; + +  /* Set value to timer setting. */ +  peer->v_connect = connect; + +  return 0; +} + +int +peer_timers_connect_unset (struct peer *peer) +{ +  if (peer_group_active (peer)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  /* Clear configuration. */ +  UNSET_FLAG (peer->config, PEER_CONFIG_CONNECT); +  peer->connect = 0; + +  /* Set timer setting to default value. */ +  peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; + +  return 0; +} + +int +peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv) +{ +  if (peer_group_active (peer)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  if (routeadv > 600) +    return BGP_ERR_INVALID_VALUE; + +  SET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); +  peer->routeadv = routeadv; +  peer->v_routeadv = routeadv; + +  return 0; +} + +int +peer_advertise_interval_unset (struct peer *peer) +{ +  if (peer_group_active (peer)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); +  peer->routeadv = 0; + +  if (peer_sort (peer) == BGP_PEER_IBGP) +    peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; +  else +    peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; +   +  return 0; +} + +int +peer_version_set (struct peer *peer, int version) +{ +  if (version != BGP_VERSION_4 && version != BGP_VERSION_MP_4_DRAFT_00) +    return BGP_ERR_INVALID_VALUE; + +  peer->version = version; + +  return 0; +} + +int +peer_version_unset (struct peer *peer) +{ +  peer->version = BGP_VERSION_4; +  return 0; +} + +/* neighbor interface */ +int +peer_interface_set (struct peer *peer, char *str) +{ +  if (peer->ifname) +    free (peer->ifname); +  peer->ifname = strdup (str); + +  return 0; +} + +int +peer_interface_unset (struct peer *peer) +{ +  if (peer->ifname) +    free (peer->ifname); +  peer->ifname = NULL; + +  return 0; +} + +/* Allow-as in.  */ +int +peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num) +{ +  struct peer_group *group; +  struct listnode *nn; + +  if (allow_num < 1 || allow_num > 10) +    return BGP_ERR_INVALID_VALUE; + +  if (peer->allowas_in[afi][safi] != allow_num) +    { +      peer->allowas_in[afi][safi] = allow_num; +      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN); +      peer_change_action (peer, afi, safi, peer_change_reset_in); +    } + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      if (peer->allowas_in[afi][safi] != allow_num) +	{ +	  peer->allowas_in[afi][safi] = allow_num; +	  SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN); +	  peer_change_action (peer, afi, safi, peer_change_reset_in); +	} +	   +    } +  return 0; +} + +int +peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi) +{ +  struct peer_group *group; +  struct listnode *nn; + +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)) +    { +      peer->allowas_in[afi][safi] = 0; +      peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN); +    } + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)) +	{ +	  peer->allowas_in[afi][safi] = 0; +	  peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN); +	} +    } +  return 0; +} + +int +peer_local_as_set (struct peer *peer, as_t as, int no_prepend) +{ +  struct bgp *bgp = peer->bgp; +  struct peer_group *group; +  struct listnode *nn; + +  if (peer_sort (peer) != BGP_PEER_EBGP +      && peer_sort (peer) != BGP_PEER_INTERNAL) +    return BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP; + +  if (bgp->as == as) +    return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS; + +  if (peer_group_active (peer)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  if (peer->change_local_as == as && +      ((CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && no_prepend) +       || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && ! no_prepend))) +    return 0; + +  peer->change_local_as = as; +  if (no_prepend) +    SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); +  else +    UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (peer->status == Established) +        bgp_notify_send (peer, BGP_NOTIFY_CEASE, +                         BGP_NOTIFY_CEASE_CONFIG_CHANGE); +      else +        BGP_EVENT_ADD (peer, BGP_Stop); + +      return 0; +    } + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      peer->change_local_as = as; +      if (no_prepend) +	SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); +      else +	UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + +      if (peer->status == Established) +        bgp_notify_send (peer, BGP_NOTIFY_CEASE, +                         BGP_NOTIFY_CEASE_CONFIG_CHANGE); +      else +        BGP_EVENT_ADD (peer, BGP_Stop); +    } + +  return 0; +} + +int +peer_local_as_unset (struct peer *peer) +{ +  struct peer_group *group; +  struct listnode *nn; + +  if (peer_group_active (peer)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  if (! peer->change_local_as) +    return 0; + +  peer->change_local_as = 0; +  UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    { +      if (peer->status == Established) +        bgp_notify_send (peer, BGP_NOTIFY_CEASE, +                         BGP_NOTIFY_CEASE_CONFIG_CHANGE); +      else +        BGP_EVENT_ADD (peer, BGP_Stop); + +      return 0; +    } + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      peer->change_local_as = 0; +      UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); + +      if (peer->status == Established) +        bgp_notify_send (peer, BGP_NOTIFY_CEASE, +                         BGP_NOTIFY_CEASE_CONFIG_CHANGE); +      else +        BGP_EVENT_ADD (peer, BGP_Stop); +    } +  return 0; +} + +/* Set distribute list to the peer. */ +int +peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct,  +		     char *name) +{ +  struct bgp_filter *filter; +  struct peer_group *group; +  struct listnode *nn; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  if (direct != FILTER_IN && direct != FILTER_OUT) +    return BGP_ERR_INVALID_VALUE; + +  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  filter = &peer->filter[afi][safi]; + +  if (filter->plist[direct].name) +    return BGP_ERR_PEER_FILTER_CONFLICT; + +  if (filter->dlist[direct].name) +    free (filter->dlist[direct].name); +  filter->dlist[direct].name = strdup (name); +  filter->dlist[direct].alist = access_list_lookup (afi, name); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      filter = &peer->filter[afi][safi]; + +      if (! peer->af_group[afi][safi]) +	continue; + +      if (filter->dlist[direct].name) +	free (filter->dlist[direct].name); +      filter->dlist[direct].name = strdup (name); +      filter->dlist[direct].alist = access_list_lookup (afi, name); +    } + +  return 0; +} + +int +peer_distribute_unset (struct peer *peer, afi_t afi, safi_t safi, int direct) +{ +  struct bgp_filter *filter; +  struct bgp_filter *gfilter; +  struct peer_group *group; +  struct listnode *nn; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  if (direct != FILTER_IN && direct != FILTER_OUT) +    return BGP_ERR_INVALID_VALUE; + +  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  filter = &peer->filter[afi][safi]; + +  /* apply peer-group filter */ +  if (peer->af_group[afi][safi]) +    { +      gfilter = &peer->group->conf->filter[afi][safi]; + +      if (gfilter->dlist[direct].name) +	{ +	  if (filter->dlist[direct].name) +	    free (filter->dlist[direct].name); +	  filter->dlist[direct].name = strdup (gfilter->dlist[direct].name); +	  filter->dlist[direct].alist = gfilter->dlist[direct].alist; +	  return 0; +	} +    } + +  if (filter->dlist[direct].name) +    free (filter->dlist[direct].name); +  filter->dlist[direct].name = NULL; +  filter->dlist[direct].alist = NULL; + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +    group = peer->group; +    LIST_LOOP (group->peer, peer, nn) +      { +	filter = &peer->filter[afi][safi]; + +	if (! peer->af_group[afi][safi]) +	  continue; + +	if (filter->dlist[direct].name) +	  free (filter->dlist[direct].name); +	filter->dlist[direct].name = NULL; +	filter->dlist[direct].alist = NULL; +      } + +  return 0; +} + +/* Update distribute list. */ +void +peer_distribute_update (struct access_list *access) +{ +  afi_t afi; +  safi_t safi; +  int direct; +  struct listnode *nn, *nm; +  struct bgp *bgp; +  struct peer *peer; +  struct peer_group *group; +  struct bgp_filter *filter; + +  LIST_LOOP (bm->bgp, bgp, nn) +    { +      LIST_LOOP (bgp->peer, peer, nm) +	{ +	  for (afi = AFI_IP; afi < AFI_MAX; afi++) +	    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +	      { +		filter = &peer->filter[afi][safi]; + +		for (direct = FILTER_IN; direct < FILTER_MAX; direct++) +		  { +		    if (filter->dlist[direct].name) +		      filter->dlist[direct].alist =  +			access_list_lookup (afi, filter->dlist[direct].name); +		    else +		      filter->dlist[direct].alist = NULL; +		  } +	      } +	} +      LIST_LOOP (bgp->group, group, nm) +	{ +	  for (afi = AFI_IP; afi < AFI_MAX; afi++) +	    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +	      { +		filter = &group->conf->filter[afi][safi]; + +		for (direct = FILTER_IN; direct < FILTER_MAX; direct++) +		  { +		    if (filter->dlist[direct].name) +		      filter->dlist[direct].alist =  +			access_list_lookup (afi, filter->dlist[direct].name); +		    else +		      filter->dlist[direct].alist = NULL; +		  } +	      } +	} +    } +} + +/* Set prefix list to the peer. */ +int +peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct,  +		      char *name) +{ +  struct bgp_filter *filter; +  struct peer_group *group; +  struct listnode *nn; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  if (direct != FILTER_IN && direct != FILTER_OUT) +    return BGP_ERR_INVALID_VALUE; + +  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  filter = &peer->filter[afi][safi]; + +  if (filter->dlist[direct].name) +    return BGP_ERR_PEER_FILTER_CONFLICT; + +  if (filter->plist[direct].name) +    free (filter->plist[direct].name); +  filter->plist[direct].name = strdup (name); +  filter->plist[direct].plist = prefix_list_lookup (afi, name); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      filter = &peer->filter[afi][safi]; + +      if (! peer->af_group[afi][safi]) +	continue; + +      if (filter->plist[direct].name) +	free (filter->plist[direct].name); +      filter->plist[direct].name = strdup (name); +      filter->plist[direct].plist = prefix_list_lookup (afi, name); +    } +  return 0; +} + +int +peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct) +{ +  struct bgp_filter *filter; +  struct bgp_filter *gfilter; +  struct peer_group *group; +  struct listnode *nn; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  if (direct != FILTER_IN && direct != FILTER_OUT) +    return BGP_ERR_INVALID_VALUE; + +  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  filter = &peer->filter[afi][safi]; + +  /* apply peer-group filter */ +  if (peer->af_group[afi][safi]) +    { +      gfilter = &peer->group->conf->filter[afi][safi]; + +      if (gfilter->plist[direct].name) +	{ +	  if (filter->plist[direct].name) +	    free (filter->plist[direct].name); +	  filter->plist[direct].name = strdup (gfilter->plist[direct].name); +	  filter->plist[direct].plist = gfilter->plist[direct].plist; +	  return 0; +	} +    } + +  if (filter->plist[direct].name) +    free (filter->plist[direct].name); +  filter->plist[direct].name = NULL; +  filter->plist[direct].plist = NULL; + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      filter = &peer->filter[afi][safi]; + +      if (! peer->af_group[afi][safi]) +	continue; + +      if (filter->plist[direct].name) +	free (filter->plist[direct].name); +      filter->plist[direct].name = NULL; +      filter->plist[direct].plist = NULL; +    } + +  return 0; +} + +/* Update prefix-list list. */ +void +peer_prefix_list_update (struct prefix_list *plist) +{ +  struct listnode *nn, *nm; +  struct bgp *bgp; +  struct peer *peer; +  struct peer_group *group; +  struct bgp_filter *filter; +  afi_t afi; +  safi_t safi; +  int direct; + +  LIST_LOOP (bm->bgp, bgp, nn) +    { +      LIST_LOOP (bgp->peer, peer, nm) +	{ +	  for (afi = AFI_IP; afi < AFI_MAX; afi++) +	    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +	      { +		filter = &peer->filter[afi][safi]; + +		for (direct = FILTER_IN; direct < FILTER_MAX; direct++) +		  { +		    if (filter->plist[direct].name) +		      filter->plist[direct].plist =  +			prefix_list_lookup (afi, filter->plist[direct].name); +		    else +		      filter->plist[direct].plist = NULL; +		  } +	      } +	} +      LIST_LOOP (bgp->group, group, nm) +	{ +	  for (afi = AFI_IP; afi < AFI_MAX; afi++) +	    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +	      { +		filter = &group->conf->filter[afi][safi]; + +		for (direct = FILTER_IN; direct < FILTER_MAX; direct++) +		  { +		    if (filter->plist[direct].name) +		      filter->plist[direct].plist =  +			prefix_list_lookup (afi, filter->plist[direct].name); +		    else +		      filter->plist[direct].plist = NULL; +		  } +	      } +	} +    } +} + +int +peer_aslist_set (struct peer *peer, afi_t afi, safi_t safi, int direct, +		 char *name) +{ +  struct bgp_filter *filter; +  struct peer_group *group; +  struct listnode *nn; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  if (direct != FILTER_IN && direct != FILTER_OUT) +    return BGP_ERR_INVALID_VALUE; + +  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  filter = &peer->filter[afi][safi]; + +  if (filter->aslist[direct].name) +    free (filter->aslist[direct].name); +  filter->aslist[direct].name = strdup (name); +  filter->aslist[direct].aslist = as_list_lookup (name); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      filter = &peer->filter[afi][safi]; + +      if (! peer->af_group[afi][safi]) +	continue; + +      if (filter->aslist[direct].name) +	free (filter->aslist[direct].name); +      filter->aslist[direct].name = strdup (name); +      filter->aslist[direct].aslist = as_list_lookup (name); +    } +  return 0; +} + +int +peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct) +{ +  struct bgp_filter *filter; +  struct bgp_filter *gfilter; +  struct peer_group *group; +  struct listnode *nn; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  if (direct != FILTER_IN && direct != FILTER_OUT) +    return BGP_ERR_INVALID_VALUE; + +  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  filter = &peer->filter[afi][safi]; + +  /* apply peer-group filter */ +  if (peer->af_group[afi][safi]) +    { +      gfilter = &peer->group->conf->filter[afi][safi]; + +      if (gfilter->aslist[direct].name) +	{ +	  if (filter->aslist[direct].name) +	    free (filter->aslist[direct].name); +	  filter->aslist[direct].name = strdup (gfilter->aslist[direct].name); +	  filter->aslist[direct].aslist = gfilter->aslist[direct].aslist; +	  return 0; +	} +    } + +  if (filter->aslist[direct].name) +    free (filter->aslist[direct].name); +  filter->aslist[direct].name = NULL; +  filter->aslist[direct].aslist = NULL; + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      filter = &peer->filter[afi][safi]; + +      if (! peer->af_group[afi][safi]) +	continue; + +      if (filter->aslist[direct].name) +	free (filter->aslist[direct].name); +      filter->aslist[direct].name = NULL; +      filter->aslist[direct].aslist = NULL; +    } + +  return 0; +} + +void +peer_aslist_update () +{ +  afi_t afi; +  safi_t safi; +  int direct; +  struct listnode *nn, *nm; +  struct bgp *bgp; +  struct peer *peer; +  struct peer_group *group; +  struct bgp_filter *filter; + +  LIST_LOOP (bm->bgp, bgp, nn) +    { +      LIST_LOOP (bgp->peer, peer, nm) +	{ +	  for (afi = AFI_IP; afi < AFI_MAX; afi++) +	    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +	      { +		filter = &peer->filter[afi][safi]; + +		for (direct = FILTER_IN; direct < FILTER_MAX; direct++) +		  { +		    if (filter->aslist[direct].name) +		      filter->aslist[direct].aslist =  +			as_list_lookup (filter->aslist[direct].name); +		    else +		      filter->aslist[direct].aslist = NULL; +		  } +	      } +	} +      LIST_LOOP (bgp->group, group, nm) +	{ +	  for (afi = AFI_IP; afi < AFI_MAX; afi++) +	    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +	      { +		filter = &group->conf->filter[afi][safi]; + +		for (direct = FILTER_IN; direct < FILTER_MAX; direct++) +		  { +		    if (filter->aslist[direct].name) +		      filter->aslist[direct].aslist =  +			as_list_lookup (filter->aslist[direct].name); +		    else +		      filter->aslist[direct].aslist = NULL; +		  } +	      } +	} +    } +} + +/* Set route-map to the peer. */ +int +peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,  +		    char *name) +{ +  struct bgp_filter *filter; +  struct peer_group *group; +  struct listnode *nn; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  if (direct != FILTER_IN && direct != FILTER_OUT) +    return BGP_ERR_INVALID_VALUE; + +  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  filter = &peer->filter[afi][safi]; + +  if (filter->map[direct].name) +    free (filter->map[direct].name); +   +  filter->map[direct].name = strdup (name); +  filter->map[direct].map = route_map_lookup_by_name (name); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      filter = &peer->filter[afi][safi]; + +      if (! peer->af_group[afi][safi]) +	continue; + +      if (filter->map[direct].name) +	free (filter->map[direct].name); +      filter->map[direct].name = strdup (name); +      filter->map[direct].map = route_map_lookup_by_name (name); +    } +  return 0; +} + +/* Unset route-map from the peer. */ +int +peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct) +{ +  struct bgp_filter *filter; +  struct bgp_filter *gfilter; +  struct peer_group *group; +  struct listnode *nn; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  if (direct != FILTER_IN && direct != FILTER_OUT) +    return BGP_ERR_INVALID_VALUE; + +  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  filter = &peer->filter[afi][safi]; + +  /* apply peer-group filter */ +  if (peer->af_group[afi][safi]) +    { +      gfilter = &peer->group->conf->filter[afi][safi]; + +      if (gfilter->map[direct].name) +	{ +	  if (filter->map[direct].name) +	    free (filter->map[direct].name); +	  filter->map[direct].name = strdup (gfilter->map[direct].name); +	  filter->map[direct].map = gfilter->map[direct].map; +	  return 0; +	} +    } + +  if (filter->map[direct].name) +    free (filter->map[direct].name); +  filter->map[direct].name = NULL; +  filter->map[direct].map = NULL; + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      filter = &peer->filter[afi][safi]; + +      if (! peer->af_group[afi][safi]) +	continue; + +      if (filter->map[direct].name) +	free (filter->map[direct].name); +      filter->map[direct].name = NULL; +      filter->map[direct].map = NULL; +    } +  return 0; +} + +/* Set unsuppress-map to the peer. */ +int +peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi, char *name) +{ +  struct bgp_filter *filter; +  struct peer_group *group; +  struct listnode *nn; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  if (peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; +       +  filter = &peer->filter[afi][safi]; + +  if (filter->usmap.name) +    free (filter->usmap.name); +   +  filter->usmap.name = strdup (name); +  filter->usmap.map = route_map_lookup_by_name (name); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      filter = &peer->filter[afi][safi]; + +      if (! peer->af_group[afi][safi]) +	continue; + +      if (filter->usmap.name) +	free (filter->usmap.name); +      filter->usmap.name = strdup (name); +      filter->usmap.map = route_map_lookup_by_name (name); +    } +  return 0; +} + +/* Unset route-map from the peer. */ +int +peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi) +{ +  struct bgp_filter *filter; +  struct peer_group *group; +  struct listnode *nn; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; +   +  if (peer_is_group_member (peer, afi, safi)) +    return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; + +  filter = &peer->filter[afi][safi]; + +  if (filter->usmap.name) +    free (filter->usmap.name); +  filter->usmap.name = NULL; +  filter->usmap.map = NULL; + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      filter = &peer->filter[afi][safi]; + +      if (! peer->af_group[afi][safi]) +	continue; + +      if (filter->usmap.name) +	free (filter->usmap.name); +      filter->usmap.name = NULL; +      filter->usmap.map = NULL; +    } +  return 0; +} + +int +peer_maximum_prefix_set (struct peer *peer, afi_t afi, safi_t safi, +			 u_int32_t max, int warning) +{ +  struct peer_group *group; +  struct listnode *nn; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); +  peer->pmax[afi][safi] = max; +  if (warning) +    SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); +  else +    UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      if (! peer->af_group[afi][safi]) +	continue; + +      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); +      peer->pmax[afi][safi] = max; +      if (warning) +	SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); +      else +	UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); +    } +  return 0; +} + +int +peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi) +{ +  struct peer_group *group; +  struct listnode *nn; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_PEER_INACTIVE; + +  /* apply peer-group config */ +  if (peer->af_group[afi][safi]) +    { +      if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi], +	  PEER_FLAG_MAX_PREFIX)) +	SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); +      else +	UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); + +      if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi], +	  PEER_FLAG_MAX_PREFIX_WARNING)) +	SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); +      else +	UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); + +      peer->pmax[afi][safi] = peer->group->conf->pmax[afi][safi]; +      return 0; +    } + +  UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); +  UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); +  peer->pmax[afi][safi] = 0; + +  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    return 0; + +  group = peer->group; +  LIST_LOOP (group->peer, peer, nn) +    { +      if (! peer->af_group[afi][safi]) +	continue; + +      UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); +      UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); +      peer->pmax[afi][safi] = 0; +    } +  return 0; +} + +int +peer_clear (struct peer *peer) +{ +  if (! CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) +    { +      UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); +      peer->v_start = BGP_INIT_START_TIMER; +      if (peer->status == Established) +	bgp_notify_send (peer, BGP_NOTIFY_CEASE, +			 BGP_NOTIFY_CEASE_ADMIN_RESET); +      else +        BGP_EVENT_ADD (peer, BGP_Stop); +    } +  return 0; +} + +int +peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi, +		 enum bgp_clear_type stype) +{ +  if (peer->status != Established) +    return 0; + +  if (! peer->afc[afi][safi]) +    return BGP_ERR_AF_UNCONFIGURED; + +  if (stype == BGP_CLEAR_SOFT_OUT || stype == BGP_CLEAR_SOFT_BOTH) +    bgp_announce_route (peer, afi, safi); + +  if (stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX) +    { +      if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) +	  && (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV) +	      || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV))) +	{ +	  struct bgp_filter *filter = &peer->filter[afi][safi]; +	  u_char prefix_type; + +	  if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) +	    prefix_type = ORF_TYPE_PREFIX; +	  else +	    prefix_type = ORF_TYPE_PREFIX_OLD; + +	  if (filter->plist[FILTER_IN].plist) +	    { +	      if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND)) +		bgp_route_refresh_send (peer, afi, safi, +					prefix_type, REFRESH_DEFER, 1); +	      bgp_route_refresh_send (peer, afi, safi, prefix_type, +				      REFRESH_IMMEDIATE, 0); +	    } +	  else +	    { +	      if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND)) +		bgp_route_refresh_send (peer, afi, safi, +					prefix_type, REFRESH_IMMEDIATE, 1); +	      else +		bgp_route_refresh_send (peer, afi, safi, 0, 0, 0); +	    } +	  return 0; +	} +    } + +  if (stype == BGP_CLEAR_SOFT_IN || stype == BGP_CLEAR_SOFT_BOTH +      || stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX) +    { +      /* If neighbor has soft reconfiguration inbound flag. +	 Use Adj-RIB-In database. */ +      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) +	bgp_soft_reconfig_in (peer, afi, safi); +      else +	{ +	  /* If neighbor has route refresh capability, send route refresh +	     message to the peer. */ +	  if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV) +	      || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) +	    bgp_route_refresh_send (peer, afi, safi, 0, 0, 0); +	  else +	    return BGP_ERR_SOFT_RECONFIG_UNCONFIGURED; +	} +    } +  return 0; +} + +/* Display peer uptime. */ +char * +peer_uptime (time_t uptime2, char *buf, size_t len) +{ +  time_t uptime1; +  struct tm *tm; + +  /* Check buffer length. */ +  if (len < BGP_UPTIME_LEN) +    { +      zlog_warn ("peer_uptime (): buffer shortage %d", len); +      return ""; +    } + +  /* If there is no connection has been done before print `never'. */ +  if (uptime2 == 0) +    { +      snprintf (buf, len, "never   "); +      return buf; +    } + +  /* Get current time. */ +  uptime1 = time (NULL); +  uptime1 -= uptime2; +  tm = gmtime (&uptime1); + +  /* Making formatted timer strings. */ +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + +  if (uptime1 < ONE_DAY_SECOND) +    snprintf (buf, len, "%02d:%02d:%02d",  +	      tm->tm_hour, tm->tm_min, tm->tm_sec); +  else if (uptime1 < ONE_WEEK_SECOND) +    snprintf (buf, len, "%dd%02dh%02dm",  +	      tm->tm_yday, tm->tm_hour, tm->tm_min); +  else +    snprintf (buf, len, "%02dw%dd%02dh",  +	      tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); +  return buf; +} + +void +bgp_config_write_filter (struct vty *vty, struct peer *peer, +			 afi_t afi, safi_t safi) +{ +  struct bgp_filter *filter; +  struct bgp_filter *gfilter = NULL; +  char *addr; +  int in = FILTER_IN; +  int out = FILTER_OUT; + +  addr = peer->host; +  filter = &peer->filter[afi][safi]; +  if (peer->af_group[afi][safi]) +    gfilter = &peer->group->conf->filter[afi][safi]; + +  /* distribute-list. */ +  if (filter->dlist[in].name) +    if (! gfilter || ! gfilter->dlist[in].name +	|| strcmp (filter->dlist[in].name, gfilter->dlist[in].name) != 0) +    vty_out (vty, " neighbor %s distribute-list %s in%s", addr,  +	     filter->dlist[in].name, VTY_NEWLINE); +  if (filter->dlist[out].name && ! gfilter) +    vty_out (vty, " neighbor %s distribute-list %s out%s", addr,  +	     filter->dlist[out].name, VTY_NEWLINE); + +  /* prefix-list. */ +  if (filter->plist[in].name) +    if (! gfilter || ! gfilter->plist[in].name +	|| strcmp (filter->plist[in].name, gfilter->plist[in].name) != 0) +    vty_out (vty, " neighbor %s prefix-list %s in%s", addr,  +	     filter->plist[in].name, VTY_NEWLINE); +  if (filter->plist[out].name && ! gfilter) +    vty_out (vty, " neighbor %s prefix-list %s out%s", addr,  +	     filter->plist[out].name, VTY_NEWLINE); + +  /* route-map. */ +  if (filter->map[in].name) +    if (! gfilter || ! gfilter->map[in].name +	|| strcmp (filter->map[in].name, gfilter->map[in].name) != 0) +      vty_out (vty, " neighbor %s route-map %s in%s", addr,  +	       filter->map[in].name, VTY_NEWLINE); +  if (filter->map[out].name && ! gfilter) +    vty_out (vty, " neighbor %s route-map %s out%s", addr,  +	     filter->map[out].name, VTY_NEWLINE); + +  /* unsuppress-map */ +  if (filter->usmap.name && ! gfilter) +    vty_out (vty, " neighbor %s unsuppress-map %s%s", addr, +	     filter->usmap.name, VTY_NEWLINE); + +  /* filter-list. */ +  if (filter->aslist[in].name) +    if (! gfilter || ! gfilter->aslist[in].name +	|| strcmp (filter->aslist[in].name, gfilter->aslist[in].name) != 0) +      vty_out (vty, " neighbor %s filter-list %s in%s", addr,  +	       filter->aslist[in].name, VTY_NEWLINE); +  if (filter->aslist[out].name && ! gfilter) +    vty_out (vty, " neighbor %s filter-list %s out%s", addr,  +	     filter->aslist[out].name, VTY_NEWLINE); +} + +/* BGP peer configuration display function. */ +void +bgp_config_write_peer (struct vty *vty, struct bgp *bgp, +		       struct peer *peer, afi_t afi, safi_t safi) +{ +  struct bgp_filter *filter; +  struct peer *g_peer = NULL; +  char buf[SU_ADDRSTRLEN]; +  char *addr; + +  filter = &peer->filter[afi][safi]; +  addr = peer->host; +  if (peer_group_active (peer)) +    g_peer = peer->group->conf; + +  /************************************ +   ****** Global to the neighbor ****** +   ************************************/ +  if (afi == AFI_IP && safi == SAFI_UNICAST) +    { +      /* remote-as. */ +      if (! peer_group_active (peer)) +	{ +	  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +	    vty_out (vty, " neighbor %s peer-group%s", addr, +		     VTY_NEWLINE); +	  if (peer->as) +	    vty_out (vty, " neighbor %s remote-as %d%s", addr, peer->as, +		     VTY_NEWLINE); +	} +      else +	{ +	  if (! g_peer->as) +	    vty_out (vty, " neighbor %s remote-as %d%s", addr, peer->as, +		     VTY_NEWLINE); +	  if (peer->af_group[AFI_IP][SAFI_UNICAST]) +	    vty_out (vty, " neighbor %s peer-group %s%s", addr, +		     peer->group->name, VTY_NEWLINE); +	} + +      /* local-as. */ +      if (peer->change_local_as) +	if (! peer_group_active (peer)) +	  vty_out (vty, " neighbor %s local-as %d%s%s", addr, +		   peer->change_local_as, +		   CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ? +		   " no-prepend" : "", VTY_NEWLINE); + +      /* Description. */ +      if (peer->desc) +	vty_out (vty, " neighbor %s description %s%s", addr, peer->desc, +		 VTY_NEWLINE); + +      /* Shutdown. */ +      if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) +        if (! peer_group_active (peer) || +	    ! CHECK_FLAG (g_peer->flags, PEER_FLAG_SHUTDOWN)) +	  vty_out (vty, " neighbor %s shutdown%s", addr, VTY_NEWLINE); + +      /* BGP port. */ +      if (peer->port != BGP_PORT_DEFAULT) +	vty_out (vty, " neighbor %s port %d%s", addr, peer->port,  +		 VTY_NEWLINE); + +      /* Local interface name. */ +      if (peer->ifname) +	vty_out (vty, " neighbor %s interface %s%s", addr, peer->ifname, +		 VTY_NEWLINE); +   +      /* Passive. */ +      if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)) +        if (! peer_group_active (peer) || +	    ! CHECK_FLAG (g_peer->flags, PEER_FLAG_PASSIVE)) +	  vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE); + +      /* EBGP multihop.  */ +      if (peer_sort (peer) != BGP_PEER_IBGP && peer->ttl != 1) +        if (! peer_group_active (peer) || +	    g_peer->ttl != peer->ttl) +	  vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer->ttl, +		   VTY_NEWLINE); + +      /* Enforce multihop.  */ +      if (CHECK_FLAG (peer->flags, PEER_FLAG_ENFORCE_MULTIHOP)) +	if (! peer_group_active (peer) || +	    ! CHECK_FLAG (g_peer->flags, PEER_FLAG_ENFORCE_MULTIHOP)) +	  vty_out (vty, " neighbor %s enforce-multihop%s", addr, VTY_NEWLINE); + +      /* Update-source. */ +      if (peer->update_if) +	if (! peer_group_active (peer) || ! g_peer->update_if +	    || strcmp (g_peer->update_if, peer->update_if) != 0) +	  vty_out (vty, " neighbor %s update-source %s%s", addr, +		   peer->update_if, VTY_NEWLINE); +      if (peer->update_source) +	if (! peer_group_active (peer) || ! g_peer->update_source +	    || sockunion_cmp (g_peer->update_source, +			      peer->update_source) != 0) +	  vty_out (vty, " neighbor %s update-source %s%s", addr, +		   sockunion2str (peer->update_source, buf, SU_ADDRSTRLEN), +		   VTY_NEWLINE); + +      /* BGP version print. */ +      if (peer->version == BGP_VERSION_MP_4_DRAFT_00) +	vty_out (vty, " neighbor %s version %s%s", +		 addr,"4-", VTY_NEWLINE); + +      /* advertisement-interval */ +      if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV)) +	vty_out (vty, " neighbor %s advertisement-interval %d%s", +		 addr, peer->v_routeadv, VTY_NEWLINE);  + +      /* timers. */ +      if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER) +	  && ! peer_group_active (peer)) +	  vty_out (vty, " neighbor %s timers %d %d%s", addr,  +	  peer->keepalive, peer->holdtime, VTY_NEWLINE); + +      if (CHECK_FLAG (peer->config, PEER_CONFIG_CONNECT)) +	  vty_out (vty, " neighbor %s timers connect %d%s", addr,  +	  peer->connect, VTY_NEWLINE); + +      /* Default weight. */ +      if (CHECK_FLAG (peer->config, PEER_CONFIG_WEIGHT)) +        if (! peer_group_active (peer) || +	    g_peer->weight != peer->weight) +	  vty_out (vty, " neighbor %s weight %d%s", addr, peer->weight, +		   VTY_NEWLINE); + +      /* Route refresh. */ +      if (CHECK_FLAG (peer->flags, PEER_FLAG_NO_ROUTE_REFRESH_CAP)) +        if (! peer_group_active (peer) || +	    ! CHECK_FLAG (g_peer->flags, PEER_FLAG_NO_ROUTE_REFRESH_CAP)) +	  vty_out (vty, " no neighbor %s capability route-refresh%s", addr, +	  VTY_NEWLINE); + +      /* Dynamic capability.  */ +      if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) +        if (! peer_group_active (peer) || +	    ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) +	vty_out (vty, " neighbor %s capability dynamic%s", addr, +	     VTY_NEWLINE); + +      /* dont capability negotiation. */ +      if (CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY)) +        if (! peer_group_active (peer) || +	    ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DONT_CAPABILITY)) +	vty_out (vty, " neighbor %s dont-capability-negotiate%s", addr, +		 VTY_NEWLINE); + +      /* override capability negotiation. */ +      if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) +        if (! peer_group_active (peer) || +	    ! CHECK_FLAG (g_peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) +	vty_out (vty, " neighbor %s override-capability%s", addr, +		 VTY_NEWLINE); + +      /* strict capability negotiation. */ +      if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) +        if (! peer_group_active (peer) || +	    ! CHECK_FLAG (g_peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) +	vty_out (vty, " neighbor %s strict-capability-match%s", addr, +	     VTY_NEWLINE); + +      if (! peer_group_active (peer)) +	{ +	  if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) +	    { +	      if (peer->afc[AFI_IP][SAFI_UNICAST]) +		vty_out (vty, " neighbor %s activate%s", addr, VTY_NEWLINE); +	    } +          else +	    { +	      if (! peer->afc[AFI_IP][SAFI_UNICAST]) +		vty_out (vty, " no neighbor %s activate%s", addr, VTY_NEWLINE); +	    } +	} +    } + + +  /************************************ +   ****** Per AF to the neighbor ****** +   ************************************/ + +  if (! (afi == AFI_IP && safi == SAFI_UNICAST)) +    { +      if (peer->af_group[afi][safi]) +	vty_out (vty, " neighbor %s peer-group %s%s", addr, +		 peer->group->name, VTY_NEWLINE); +      else +	vty_out (vty, " neighbor %s activate%s", addr, VTY_NEWLINE); +    } + +  /* ORF capability.  */ +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) +      || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) +    if (! peer->af_group[afi][safi]) +    { +      vty_out (vty, " neighbor %s capability orf prefix-list", addr); + +      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) +	  && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) +	vty_out (vty, " both"); +      else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)) +	vty_out (vty, " send"); +      else +	vty_out (vty, " receive"); +      vty_out (vty, "%s", VTY_NEWLINE); +    } + +  /* Route reflector client. */ +  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT) +      && ! peer->af_group[afi][safi]) +    vty_out (vty, " neighbor %s route-reflector-client%s", addr,  +	     VTY_NEWLINE); + +  /* Nexthop self. */ +  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF) +      && ! peer->af_group[afi][safi]) +    vty_out (vty, " neighbor %s next-hop-self%s", addr, VTY_NEWLINE); + +  /* Remove private AS. */ +  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) +      && ! peer->af_group[afi][safi]) +    vty_out (vty, " neighbor %s remove-private-AS%s", +	     addr, VTY_NEWLINE); + +  /* send-community print. */ +  if (! peer->af_group[afi][safi]) +    { +      if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) +	{ +	  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) +	      && peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) +	    vty_out (vty, " neighbor %s send-community both%s", addr, VTY_NEWLINE); +	  else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))	 +	    vty_out (vty, " neighbor %s send-community extended%s", +		     addr, VTY_NEWLINE); +	  else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) +	    vty_out (vty, " neighbor %s send-community%s", addr, VTY_NEWLINE); +	} +      else +	{ +	  if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) +	      && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) +	    vty_out (vty, " no neighbor %s send-community both%s", +		     addr, VTY_NEWLINE); +	  else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) +	    vty_out (vty, " no neighbor %s send-community extended%s", +		     addr, VTY_NEWLINE); +	  else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) +	    vty_out (vty, " no neighbor %s send-community%s", +		     addr, VTY_NEWLINE); +	} +    } + +  /* Default information */ +  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_DEFAULT_ORIGINATE) +      && ! peer->af_group[afi][safi]) +    { +      vty_out (vty, " neighbor %s default-originate", addr); +      if (peer->default_rmap[afi][safi].name) +	vty_out (vty, " route-map %s", peer->default_rmap[afi][safi].name); +      vty_out (vty, "%s", VTY_NEWLINE); +    } + +  /* Soft reconfiguration inbound. */ +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) +    if (! peer->af_group[afi][safi] || +	! CHECK_FLAG (g_peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) +    vty_out (vty, " neighbor %s soft-reconfiguration inbound%s", addr, +	     VTY_NEWLINE); + +  /* maximum-prefix. */ +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) +    if (! peer->af_group[afi][safi] +	|| g_peer->pmax[afi][safi] != peer->pmax[afi][safi] +	|| CHECK_FLAG (g_peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING) +	   != CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)) +      vty_out (vty, " neighbor %s maximum-prefix %ld%s%s", +	       addr, peer->pmax[afi][safi], +	       CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING) +	       ? " warning-only" : "", VTY_NEWLINE); + +  /* Route server client. */ +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) +      && ! peer->af_group[afi][safi]) +    vty_out (vty, " neighbor %s route-server-client%s", addr, VTY_NEWLINE); + +  /* Allow AS in.  */ +  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) +    if (! peer_group_active (peer) +	|| ! peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_ALLOWAS_IN) +	|| peer->allowas_in[afi][safi] != g_peer->allowas_in[afi][safi]) +      { +	if (peer->allowas_in[afi][safi] == 3) +	  vty_out (vty, " neighbor %s allowas-in%s", addr, VTY_NEWLINE); +	else +	  vty_out (vty, " neighbor %s allowas-in %d%s", addr, +		   peer->allowas_in[afi][safi], VTY_NEWLINE); +      } + +  /* Filter. */ +  bgp_config_write_filter (vty, peer, afi, safi); + +  /* atribute-unchanged. */ +  if ((CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) +      || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) +      || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) +      && ! peer->af_group[afi][safi]) +    { +      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) +          && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) +          && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) +	vty_out (vty, " neighbor %s attribute-unchanged%s", addr, VTY_NEWLINE); +      else +	vty_out (vty, " neighbor %s attribute-unchanged%s%s%s%s", addr,  +	     (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)) ? +	     " as-path" : "", +	     (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)) ? +	     " next-hop" : "", +	     (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) ? +	     " med" : "", VTY_NEWLINE); +    } +} + +/* Display "address-family" configuration header. */ +void +bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi, +				int *write) +{ +  if (*write) +    return; + +  if (afi == AFI_IP && safi == SAFI_UNICAST) +    return; + +  vty_out (vty, "!%s address-family ", VTY_NEWLINE); + +  if (afi == AFI_IP) +    { +      if (safi == SAFI_MULTICAST) +	vty_out (vty, "ipv4 multicast"); +      else if (safi == SAFI_MPLS_VPN) +	vty_out (vty, "vpnv4 unicast"); +    } +  else if (afi == AFI_IP6) +    vty_out (vty, "ipv6"); + +  vty_out (vty, "%s", VTY_NEWLINE); + +  *write = 1; +} + +/* Address family based peer configuration display.  */ +int +bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi, +			 safi_t safi) +{ +  int write = 0; +  struct peer *peer; +  struct peer_group *group; +  struct listnode *nn; + +  bgp_config_write_network (vty, bgp, afi, safi, &write); + +  bgp_config_write_redistribute (vty, bgp, afi, safi, &write); + +  LIST_LOOP (bgp->group, group, nn) +    { +      if (group->conf->afc[afi][safi]) +	{ +	  bgp_config_write_family_header (vty, afi, safi, &write); +	  bgp_config_write_peer (vty, bgp, group->conf, afi, safi); +	} +    } +  LIST_LOOP (bgp->peer, peer, nn) +    { +      if (peer->afc[afi][safi]) +	{ +	  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) +	    { +	      bgp_config_write_family_header (vty, afi, safi, &write); +	      bgp_config_write_peer (vty, bgp, peer, afi, safi); +	    } +	} +    } +  if (write) +    vty_out (vty, " exit-address-family%s", VTY_NEWLINE); + +  return write; +} + +int +bgp_config_write (struct vty *vty) +{ +  int write = 0; +  struct bgp *bgp; +  struct peer_group *group; +  struct peer *peer; +  struct listnode *nn, *nm, *no; + +  /* BGP Multiple instance. */ +  if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE)) +    {     +      vty_out (vty, "bgp multiple-instance%s", VTY_NEWLINE); +      write++; +    } + +  /* BGP Config type. */ +  if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) +    {     +      vty_out (vty, "bgp config-type cisco%s", VTY_NEWLINE); +      write++; +    } + +  /* BGP configuration. */ +  LIST_LOOP (bm->bgp, bgp, nn) +    { +      if (write) +	vty_out (vty, "!%s", VTY_NEWLINE); + +      /* Router bgp ASN */ +      vty_out (vty, "router bgp %d", bgp->as); + +      if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE)) +	{ +	  if (bgp->name) +	    vty_out (vty, " view %s", bgp->name); +	} +      vty_out (vty, "%s", VTY_NEWLINE); + +      /* No Synchronization */ +      if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) +	vty_out (vty, " no synchronization%s", VTY_NEWLINE); + +      /* BGP fast-external-failover. */ +      if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) +	vty_out (vty, " no bgp fast-external-failover%s", VTY_NEWLINE);  + +      /* BGP router ID. */ +      if (CHECK_FLAG (bgp->config, BGP_CONFIG_ROUTER_ID)) +	vty_out (vty, " bgp router-id %s%s", inet_ntoa (bgp->router_id),  +		 VTY_NEWLINE); + +      /* BGP configuration. */ +      if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED)) +	vty_out (vty, " bgp always-compare-med%s", VTY_NEWLINE); + +      /* BGP default ipv4-unicast. */ +      if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) +	vty_out (vty, " no bgp default ipv4-unicast%s", VTY_NEWLINE); + +      /* BGP default local-preference. */ +      if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF) +	vty_out (vty, " bgp default local-preference %d%s", +		 bgp->default_local_pref, VTY_NEWLINE); + +      /* BGP client-to-client reflection. */ +      if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT)) +	vty_out (vty, " no bgp client-to-client reflection%s", VTY_NEWLINE); +       +      /* BGP cluster ID. */ +      if (CHECK_FLAG (bgp->config, BGP_CONFIG_CLUSTER_ID)) +	vty_out (vty, " bgp cluster-id %s%s", inet_ntoa (bgp->cluster_id), +		 VTY_NEWLINE); + +      /* Confederation Information */ +      if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) +	{ +	  vty_out (vty, " bgp confederation identifier %i%s", bgp->confed_id, +		   VTY_NEWLINE); +	  if (bgp->confed_peers_cnt > 0) +	    { +	      int i; + +	      vty_out (vty, " bgp confederation peers"); + +	      for (i = 0; i < bgp->confed_peers_cnt; i++) +		{ +		  vty_out(vty, " "); +		  vty_out(vty, "%d", bgp->confed_peers[i]); +		} + +	      vty_out (vty, "%s", VTY_NEWLINE); +	    } +	} + +      /* BGP enforce-first-as. */ +      if (bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS)) +	vty_out (vty, " bgp enforce-first-as%s", VTY_NEWLINE); + +      /* BGP deterministic-med. */ +      if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) +	vty_out (vty, " bgp deterministic-med%s", VTY_NEWLINE); +       +      /* BGP bestpath method. */ +      if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE)) +	vty_out (vty, " bgp bestpath as-path ignore%s", VTY_NEWLINE); +      if (bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID)) +	vty_out (vty, " bgp bestpath compare-routerid%s", VTY_NEWLINE); +      if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED) +	  || bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST)) +	{ +	  vty_out (vty, " bgp bestpath med"); +	  if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED)) +	    vty_out (vty, " confed"); +	  if (bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST)) +	    vty_out (vty, " missing-as-worst"); +	  vty_out (vty, "%s", VTY_NEWLINE); +	} + +      /* BGP network import check. */ +      if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) +	vty_out (vty, " bgp network import-check%s", VTY_NEWLINE); + +      /* BGP scan interval. */ +      bgp_config_write_scan_time (vty); + +      /* BGP flag dampening. */ +      if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST], +	  BGP_CONFIG_DAMPENING)) +	bgp_config_write_damp (vty); + +      /* BGP static route configuration. */ +      bgp_config_write_network (vty, bgp, AFI_IP, SAFI_UNICAST, &write); + +      /* BGP redistribute configuration. */ +      bgp_config_write_redistribute (vty, bgp, AFI_IP, SAFI_UNICAST, &write); + +      /* BGP timers configuration. */ +      if (bgp->default_keepalive != BGP_DEFAULT_KEEPALIVE +	  && bgp->default_holdtime != BGP_DEFAULT_HOLDTIME) +	vty_out (vty, " timers bgp %d %d%s", bgp->default_keepalive,  +		 bgp->default_holdtime, VTY_NEWLINE); + +      /* peer-group */ +      LIST_LOOP (bgp->group, group, nm) +	{ +	  bgp_config_write_peer (vty, bgp, group->conf, AFI_IP, SAFI_UNICAST); +	} + +      /* Normal neighbor configuration. */ +      LIST_LOOP (bgp->peer, peer, no) +	{ +	  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) +	    bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST); +	} + +      /* Distance configuration. */ +      bgp_config_write_distance (vty, bgp); +       +      /* No auto-summary */ +      if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) +	vty_out (vty, " no auto-summary%s", VTY_NEWLINE); + +      /* IPv4 multicast configuration.  */ +      write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MULTICAST); + +      /* IPv4 VPN configuration.  */ +      write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MPLS_VPN); + +      /* IPv6 unicast configuration.  */ +      write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_UNICAST); + +      write++; +    } +  return write; +} + +void +bgp_master_init () +{ +  memset (&bgp_master, 0, sizeof (struct bgp_master)); + +  bm = &bgp_master; +  bm->bgp = list_new (); +  bm->port = BGP_PORT_DEFAULT; +  bm->master = thread_master_create (); +  bm->start_time = time (NULL); +} + +void +bgp_init () +{ +  void bgp_zebra_init (); +  void bgp_route_map_init (); +  void bgp_filter_init (); + +  /* BGP VTY commands installation.  */ +  bgp_vty_init (); + +  /* Create BGP server socket.  */ +  bgp_socket (NULL, bm->port); + +  /* Init zebra. */ +  bgp_zebra_init (); + +  /* BGP inits. */ +  bgp_attr_init (); +  bgp_debug_init (); +  bgp_dump_init (); +  bgp_route_init (); +  bgp_route_map_init (); +  bgp_scan_init (); +  bgp_mplsvpn_init (); + +  /* Access list initialize. */ +  access_list_init (); +  access_list_add_hook (peer_distribute_update); +  access_list_delete_hook (peer_distribute_update); + +  /* Filter list initialize. */ +  bgp_filter_init (); +  as_list_add_hook (peer_aslist_update); +  as_list_delete_hook (peer_aslist_update); + +  /* Prefix list initialize.*/ +  prefix_list_init (); +  prefix_list_add_hook (peer_prefix_list_update); +  prefix_list_delete_hook (peer_prefix_list_update); + +  /* Community list initialize. */ +  bgp_clist = community_list_init (); + +#ifdef HAVE_SNMP +  bgp_snmp_init (); +#endif /* HAVE_SNMP */ +} diff --git a/bgpd/bgpd.conf.sample b/bgpd/bgpd.conf.sample new file mode 100644 index 0000000000..b6a8b6f100 --- /dev/null +++ b/bgpd/bgpd.conf.sample @@ -0,0 +1,29 @@ +! -*- bgp -*- +! +! BGPd sample configuratin file +! +! $Id: bgpd.conf.sample,v 1.1 2002/12/13 20:15:29 paul Exp $ +! +hostname bgpd +password zebra +!enable password please-set-at-here +! +!bgp mulitple-instance +! +router bgp 7675 +! bgp router-id 10.0.0.1 +! network 10.0.0.0/8 +! neighbor 10.0.0.2 remote-as 7675 +! neighbor 10.0.0.2 route-map set-nexthop out +! neighbor 10.0.0.2 ebgp-multihop +! neighbor 10.0.0.2 next-hop-self +! +! access-list all permit any +! +!route-map set-nexthop permit 10 +! match ip address all +! set ip next-hop 10.0.0.1 +! +!log file bgpd.log +! +log stdout diff --git a/bgpd/bgpd.conf.sample2 b/bgpd/bgpd.conf.sample2 new file mode 100644 index 0000000000..d376ad25bc --- /dev/null +++ b/bgpd/bgpd.conf.sample2 @@ -0,0 +1,77 @@ +! +! Zebra configuration saved from vty +!   2002/07/01 03:16:33 +! +hostname bgpd +password zebra +log file bgpd.log +log stdout +! +router bgp 7675 + no bgp default ipv4-unicast + neighbor 3ffe:506:1000::2 remote-as 7675 + neighbor fe80::200:c0ff:fe30:9be3 remote-as 9377 + neighbor fe80::200:c0ff:fe30:9be3 interface sit3 + neighbor fe80::210:5aff:fe6b:3cee remote-as 7675 + neighbor fe80::210:5aff:fe6b:3cee interface eth0 + neighbor fe80::290:27ff:fe51:84c7 remote-as 4691 + neighbor fe80::290:27ff:fe51:84c7 description DTI  + neighbor fe80::290:27ff:fe51:84c7 interface sit7 + neighbor fe80::2a0:c9ff:fec8:82ec remote-as 7530 + neighbor fe80::2a0:c9ff:fec8:82ec description IRI  + neighbor fe80::2a0:c9ff:fec8:82ec interface sit8 + neighbor fe80::2e0:18ff:fe98:2725 remote-as 2500 + neighbor fe80::2e0:18ff:fe98:2725 description WIDE  + neighbor fe80::2e0:18ff:fe98:2725 interface sit5 + neighbor fe80::2e0:18ff:fea8:bf5 remote-as 65000 + neighbor fe80::2e0:18ff:fea8:bf5 interface sit6 +! + address-family ipv6 + network 3ffe:506::/33 + network 3ffe:1800:e800::/40 + aggregate-address 3ffe:506::/32 + redistribute connected + neighbor 3ffe:506:1000::2 activate + neighbor fe80::200:c0ff:fe30:9be3 activate + neighbor fe80::200:c0ff:fe30:9be3 route-map set-nexthop out + neighbor fe80::210:5aff:fe6b:3cee activate + neighbor fe80::290:27ff:fe51:84c7 activate + neighbor fe80::290:27ff:fe51:84c7 route-map set-nexthop out + neighbor fe80::2a0:c9ff:fec8:82ec activate + neighbor fe80::2a0:c9ff:fec8:82ec route-map set-nexthop out + neighbor fe80::2e0:18ff:fe98:2725 activate + neighbor fe80::2e0:18ff:fe98:2725 distribute-list nla1 out + neighbor fe80::2e0:18ff:fe98:2725 route-map set-nexthop out + neighbor fe80::2e0:18ff:fea8:bf5 activate + neighbor fe80::2e0:18ff:fea8:bf5 route-map set-nexthop out + exit-address-family +! +ipv6 access-list all permit any +ipv6 access-list nla1 deny 3ffe:506::/33 +ipv6 access-list nla1 permit 3ffe:506::/32 +ipv6 access-list nla1 deny any +ipv6 access-list ntt-nla1 permit 3ffe:1800:0:ffff::c/127 +ipv6 access-list ntt-nla1 deny 3ffe:1800:e800::/41 +ipv6 access-list ntt-nla1 permit 3ffe:1800:e800::/40 +ipv6 access-list ntt-nla1 deny any +! +ipv6 prefix-list 6bone-filter seq 5 permit 3ffe::/17 ge 24 le 24 +ipv6 prefix-list 6bone-filter seq 10 permit 3ffe:8000::/17 ge 28 le 28 +ipv6 prefix-list 6bone-filter seq 12 deny 3ffe::/16 +ipv6 prefix-list 6bone-filter seq 15 permit 2000::/3 ge 16 le 16 +ipv6 prefix-list 6bone-filter seq 20 permit 2001::/16 ge 35 le 35 +! +route-map set-nexthop permit 10 + match ipv6 address all + set ipv6 next-hop global 3ffe:506::1 + set ipv6 next-hop local fe80::cbb5:591a + set ip next-hop 203.181.89.26 + set community 7675:0 +! +route-map set-link-local permit 10 + match ipv6 address all + set ipv6 next-hop local fe80::cbb5:591a + set ipv6 next-hop global 3ffe:1800:0:ffff::d +! +line vty +! diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h new file mode 100644 index 0000000000..01d47212bf --- /dev/null +++ b/bgpd/bgpd.h @@ -0,0 +1,824 @@ +/* BGP message definition header. +   Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING.  If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA.  */ + +/* For union sockunion.  */ +#include "sockunion.h" + +/* Typedef BGP specific types.  */ +typedef u_int16_t as_t; +typedef u_int16_t bgp_size_t; + +/* BGP master for system wide configurations and variables.  */ +struct bgp_master +{ +  /* BGP instance list.  */ +  struct list *bgp; + +  /* BGP thread master.  */ +  struct thread_master *master; + +  /* BGP port number.  */ +  u_int16_t port; + +  /* BGP start time.  */ +  time_t start_time; + +  /* Various BGP global configuration.  */ +  u_char options; +#define BGP_OPT_NO_FIB                   (1 << 0) +#define BGP_OPT_MULTIPLE_INSTANCE        (1 << 1) +#define BGP_OPT_CONFIG_CISCO             (1 << 2) +}; + +/* BGP instance structure.  */ +struct bgp  +{ +  /* AS number of this BGP instance.  */ +  as_t as; + +  /* Name of this BGP instance.  */ +  char *name; + +  /* Self peer.  */ +  struct peer *peer_self; + +  /* BGP peer. */ +  struct list *peer; + +  /* BGP peer group.  */ +  struct list *group; + +  /* BGP configuration.  */ +  u_int16_t config; +#define BGP_CONFIG_ROUTER_ID              (1 << 0) +#define BGP_CONFIG_CLUSTER_ID             (1 << 1) +#define BGP_CONFIG_CONFEDERATION          (1 << 2) +#define BGP_CONFIG_DEFAULT_LOCAL_PREF     (1 << 3) + +  /* BGP router identifier.  */ +  struct in_addr router_id; + +  /* BGP route reflector cluster ID.  */ +  struct in_addr cluster_id; + +  /* BGP confederation information.  */ +  as_t confed_id; +  as_t *confed_peers; +  int confed_peers_cnt; + +  /* BGP flags. */ +  u_int16_t flags; +#define BGP_FLAG_ALWAYS_COMPARE_MED       (1 << 0) +#define BGP_FLAG_DETERMINISTIC_MED        (1 << 1) +#define BGP_FLAG_MED_MISSING_AS_WORST     (1 << 2) +#define BGP_FLAG_MED_CONFED               (1 << 3) +#define BGP_FLAG_NO_DEFAULT_IPV4          (1 << 4) +#define BGP_FLAG_NO_CLIENT_TO_CLIENT      (1 << 5) +#define BGP_FLAG_ENFORCE_FIRST_AS         (1 << 6) +#define BGP_FLAG_COMPARE_ROUTER_ID        (1 << 7) +#define BGP_FLAG_ASPATH_IGNORE            (1 << 8) +#define BGP_FLAG_IMPORT_CHECK             (1 << 9) +#define BGP_FLAG_NO_FAST_EXT_FAILOVER     (1 << 10) + +  /* BGP Per AF flags */ +  u_int16_t af_flags[AFI_MAX][SAFI_MAX]; +#define BGP_CONFIG_DAMPENING              (1 << 0) + +  /* Static route configuration.  */ +  struct bgp_table *route[AFI_MAX][SAFI_MAX]; + +  /* Aggregate address configuration.  */ +  struct bgp_table *aggregate[AFI_MAX][SAFI_MAX]; + +  /* BGP routing information base.  */ +  struct bgp_table *rib[AFI_MAX][SAFI_MAX]; + +  /* BGP redistribute configuration. */ +  u_char redist[AFI_MAX][ZEBRA_ROUTE_MAX]; + +  /* BGP redistribute metric configuration. */ +  u_char redist_metric_flag[AFI_MAX][ZEBRA_ROUTE_MAX]; +  u_int32_t redist_metric[AFI_MAX][ZEBRA_ROUTE_MAX]; + +  /* BGP redistribute route-map.  */ +  struct +  { +    char *name; +    struct route_map *map; +  } rmap[AFI_MAX][ZEBRA_ROUTE_MAX]; + +  /* BGP distance configuration.  */ +  u_char distance_ebgp; +  u_char distance_ibgp; +  u_char distance_local; +   +  /* BGP default local-preference.  */ +  u_int32_t default_local_pref; + +  /* BGP default timer.  */ +  u_int32_t default_holdtime; +  u_int32_t default_keepalive; +}; + +/* BGP peer-group support. */ +struct peer_group +{ +  /* Name of the peer-group. */ +  char *name; + +  /* Pointer to BGP.  */ +  struct bgp *bgp; +   +  /* Peer-group client list. */ +  struct list *peer; + +  /* Peer-group config */ +  struct peer *conf; +}; + +/* BGP Notify message format. */ +struct bgp_notify  +{ +  u_char code; +  u_char subcode; +  char *data; +  bgp_size_t length; +}; + +/* Next hop self address. */ +struct bgp_nexthop +{ +  struct interface *ifp; +  struct in_addr v4; +#ifdef HAVE_IPV6 +  struct in6_addr v6_global; +  struct in6_addr v6_local; +#endif /* HAVE_IPV6 */   +}; + +/* BGP router distinguisher value.  */ +#define BGP_RD_SIZE                8 + +struct bgp_rd +{ +  u_char val[BGP_RD_SIZE]; +}; + +/* BGP filter structure. */ +struct bgp_filter +{ +  /* Distribute-list.  */ +  struct  +  { +    char *name; +    struct access_list *alist; +  } dlist[FILTER_MAX]; + +  /* Prefix-list.  */ +  struct +  { +    char *name; +    struct prefix_list *plist; +  } plist[FILTER_MAX]; + +  /* Filter-list.  */ +  struct +  { +    char *name; +    struct as_list *aslist; +  } aslist[FILTER_MAX]; + +  /* Route-map.  */ +  struct +  { +    char *name; +    struct route_map *map; +  } map[FILTER_MAX]; + +  /* Unsuppress-map.  */ +  struct +  { +    char *name; +    struct route_map *map; +  } usmap; +}; + +/* BGP neighbor structure. */ +struct peer +{ +  /* BGP structure.  */ +  struct bgp *bgp; + +  /* BGP peer group.  */ +  struct peer_group *group; +  u_char af_group[AFI_MAX][SAFI_MAX]; + +  /* Peer's remote AS number. */ +  as_t as;			 + +  /* Peer's local AS number. */ +  as_t local_as; + +  /* Peer's Change local AS number. */ +  as_t change_local_as; + +  /* Remote router ID. */ +  struct in_addr remote_id; + +  /* Local router ID. */ +  struct in_addr local_id; + +  /* Packet receive and send buffer. */ +  struct stream *ibuf; +  struct stream_fifo *obuf; +  struct stream *work; + +  /* Status of the peer. */ +  int status; +  int ostatus; + +  /* Peer information */ +  int fd;			/* File descriptor */ +  int ttl;			/* TTL of TCP connection to the peer. */ +  char *desc;			/* Description of the peer. */ +  unsigned short port;          /* Destination port for peer */ +  char *host;			/* Printable address of the peer. */ +  union sockunion su;		/* Sockunion address of the peer. */ +  time_t uptime;		/* Last Up/Down time */ +  time_t readtime;		/* Last read time */ +   +  unsigned int ifindex;		/* ifindex of the BGP connection. */ +  char *ifname;			/* bind interface name. */ +  char *update_if; +  union sockunion *update_source; +  struct zlog *log; +  u_char version;		/* Peer BGP version. */ + +  union sockunion *su_local;	/* Sockunion of local address.  */ +  union sockunion *su_remote;	/* Sockunion of remote address.  */ +  int shared_network;		/* Is this peer shared same network. */ +  struct bgp_nexthop nexthop;	/* Nexthop */ + +  /* Peer address family configuration. */ +  u_char afc[AFI_MAX][SAFI_MAX]; +  u_char afc_nego[AFI_MAX][SAFI_MAX]; +  u_char afc_adv[AFI_MAX][SAFI_MAX]; +  u_char afc_recv[AFI_MAX][SAFI_MAX]; + +  /* Capability Flags.*/ +  u_char cap; +#define PEER_CAP_REFRESH_ADV                (1 << 0) /* refresh advertised */ +#define PEER_CAP_REFRESH_OLD_RCV            (1 << 1) /* refresh old received */ +#define PEER_CAP_REFRESH_NEW_RCV            (1 << 2) /* refresh rfc received */ +#define PEER_CAP_DYNAMIC_ADV                (1 << 3) /* dynamic advertised */ +#define PEER_CAP_DYNAMIC_RCV                (1 << 4) /* dynamic received */ + +  /* Capability Flags.*/ +  u_int16_t af_cap[AFI_MAX][SAFI_MAX]; +#define PEER_CAP_ORF_PREFIX_SM_ADV          (1 << 0) /* send-mode advertised */ +#define PEER_CAP_ORF_PREFIX_RM_ADV          (1 << 1) /* receive-mode advertised */ +#define PEER_CAP_ORF_PREFIX_SM_RCV          (1 << 2) /* send-mode received */ +#define PEER_CAP_ORF_PREFIX_RM_RCV          (1 << 3) /* receive-mode received */ +#define PEER_CAP_ORF_PREFIX_SM_OLD_RCV      (1 << 4) /* send-mode received */ +#define PEER_CAP_ORF_PREFIX_RM_OLD_RCV      (1 << 5) /* receive-mode received */ + +  /* Global configuration flags. */ +  u_int32_t flags; +#define PEER_FLAG_PASSIVE                   (1 << 0) /* passive mode */ +#define PEER_FLAG_SHUTDOWN                  (1 << 1) /* shutdown */ +#define PEER_FLAG_DONT_CAPABILITY           (1 << 2) /* dont-capability */ +#define PEER_FLAG_OVERRIDE_CAPABILITY       (1 << 3) /* override-capability */ +#define PEER_FLAG_STRICT_CAP_MATCH          (1 << 4) /* strict-match */ +#define PEER_FLAG_NO_ROUTE_REFRESH_CAP      (1 << 5) /* route-refresh */ +#define PEER_FLAG_DYNAMIC_CAPABILITY        (1 << 6) /* dynamic capability */ +#define PEER_FLAG_ENFORCE_MULTIHOP          (1 << 7) /* enforce-multihop */ +#define PEER_FLAG_LOCAL_AS_NO_PREPEND       (1 << 8) /* local-as no-prepend */ + +  /* Per AF configuration flags. */ +  u_int32_t af_flags[AFI_MAX][SAFI_MAX]; +#define PEER_FLAG_SEND_COMMUNITY            (1 << 0) /* send-community */ +#define PEER_FLAG_SEND_EXT_COMMUNITY        (1 << 1) /* send-community ext. */ +#define PEER_FLAG_NEXTHOP_SELF              (1 << 2) /* next-hop-self */ +#define PEER_FLAG_REFLECTOR_CLIENT          (1 << 3) /* reflector-client */ +#define PEER_FLAG_RSERVER_CLIENT            (1 << 4) /* route-server-client */ +#define PEER_FLAG_SOFT_RECONFIG             (1 << 5) /* soft-reconfiguration */ +#define PEER_FLAG_AS_PATH_UNCHANGED         (1 << 6) /* transparent-as */ +#define PEER_FLAG_NEXTHOP_UNCHANGED         (1 << 7) /* transparent-next-hop */ +#define PEER_FLAG_MED_UNCHANGED             (1 << 8) /* transparent-next-hop */ +#define PEER_FLAG_DEFAULT_ORIGINATE         (1 << 9) /* default-originate */ +#define PEER_FLAG_REMOVE_PRIVATE_AS         (1 << 10) /* remove-private-as */ +#define PEER_FLAG_ALLOWAS_IN                (1 << 11) /* set allowas-in */ +#define PEER_FLAG_ORF_PREFIX_SM             (1 << 12) /* orf capability send-mode */ +#define PEER_FLAG_ORF_PREFIX_RM             (1 << 13) /* orf capability receive-mode */ +#define PEER_FLAG_MAX_PREFIX                (1 << 14) /* maximum prefix */ +#define PEER_FLAG_MAX_PREFIX_WARNING        (1 << 15) /* maximum prefix warning-only */ + +  /* default-originate route-map.  */ +  struct +  { +    char *name; +    struct route_map *map; +  } default_rmap[AFI_MAX][SAFI_MAX]; + +  /* Peer status flags. */ +  u_int16_t sflags; +#define PEER_STATUS_ACCEPT_PEER	      (1 << 0) /* accept peer */ +#define PEER_STATUS_PREFIX_OVERFLOW   (1 << 1) /* prefix-overflow */ +#define PEER_STATUS_CAPABILITY_OPEN   (1 << 2) /* capability open send */ +#define PEER_STATUS_HAVE_ACCEPT       (1 << 3) /* accept peer's parent */ +#define PEER_STATUS_GROUP             (1 << 4) /* peer-group conf */ + +  /* Peer status af flags. */ +  u_int16_t af_sflags[AFI_MAX][SAFI_MAX]; +#define PEER_STATUS_ORF_PREFIX_SEND   (1 << 0) /* prefix-list send peer */ +#define PEER_STATUS_ORF_WAIT_REFRESH  (1 << 1) /* wait refresh received peer */ +#define PEER_STATUS_DEFAULT_ORIGINATE (1 << 2) /* default-originate peer */ + +  /* Default attribute value for the peer. */ +  u_int32_t config; +#define PEER_CONFIG_WEIGHT            (1 << 0) /* Default weight. */ +#define PEER_CONFIG_TIMER             (1 << 1) /* keepalive & holdtime */ +#define PEER_CONFIG_CONNECT           (1 << 2) /* connect */ +#define PEER_CONFIG_ROUTEADV          (1 << 3) /* route advertise */ +  u_int32_t weight; +  u_int32_t holdtime; +  u_int32_t keepalive; +  u_int32_t connect; +  u_int32_t routeadv; + +  /* Timer values. */ +  u_int32_t v_start; +  u_int32_t v_connect; +  u_int32_t v_holdtime; +  u_int32_t v_keepalive; +  u_int32_t v_asorig; +  u_int32_t v_routeadv; + +  /* Threads. */ +  struct thread *t_read; +  struct thread *t_write; +  struct thread *t_start; +  struct thread *t_connect; +  struct thread *t_holdtime; +  struct thread *t_keepalive; +  struct thread *t_asorig; +  struct thread *t_routeadv; + +  /* Statistics field */ +  u_int32_t open_in;		/* Open message input count */ +  u_int32_t open_out;		/* Open message output count */ +  u_int32_t update_in;		/* Update message input count */ +  u_int32_t update_out;		/* Update message ouput count */ +  time_t update_time;		/* Update message received time. */ +  u_int32_t keepalive_in;	/* Keepalive input count */ +  u_int32_t keepalive_out;	/* Keepalive output count */ +  u_int32_t notify_in;		/* Notify input count */ +  u_int32_t notify_out;		/* Notify output count */ +  u_int32_t refresh_in;		/* Route Refresh input count */ +  u_int32_t refresh_out;	/* Route Refresh output count */ +  u_int32_t dynamic_cap_in;	/* Dynamic Capability input count.  */ +  u_int32_t dynamic_cap_out;	/* Dynamic Capability output count.  */ + +  /* BGP state count */ +  u_int32_t established;	/* Established */ +  u_int32_t dropped;		/* Dropped */ + +  /* Syncronization list and time.  */ +  struct bgp_synchronize *sync[AFI_MAX][SAFI_MAX]; +  time_t synctime; + +  /* Send prefix count. */ +  unsigned long scount[AFI_MAX][SAFI_MAX]; + +  /* Announcement attribute hash.  */ +  struct hash *hash[AFI_MAX][SAFI_MAX]; + +  /* Notify data. */ +  struct bgp_notify notify; + +  /* Whole packet size to be read. */ +  unsigned long packet_size; + +  /* Filter structure. */ +  struct bgp_filter filter[AFI_MAX][SAFI_MAX]; + +  /* ORF Prefix-list */ +  struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX]; + +  /* Prefix count. */ +  unsigned long pcount[AFI_MAX][SAFI_MAX]; + +  /* Max prefix count. */ +  unsigned long pmax[AFI_MAX][SAFI_MAX]; + +  /* allowas-in. */ +  char allowas_in[AFI_MAX][SAFI_MAX]; +}; + +/* This structure's member directly points incoming packet data +   stream. */ +struct bgp_nlri +{ +  /* AFI.  */ +  afi_t afi; + +  /* SAFI.  */ +  safi_t safi; + +  /* Pointer to NLRI byte stream.  */ +  u_char *nlri; + +  /* Length of whole NLRI.  */ +  bgp_size_t length; +}; + +/* BGP versions.  */ +#define BGP_VERSION_4		                 4 +#define BGP_VERSION_MP_4_DRAFT_00               40 + +/* Default BGP port number.  */ +#define BGP_PORT_DEFAULT                       179 + +/* BGP message header and packet size.  */ +#define BGP_MARKER_SIZE		                16 +#define BGP_HEADER_SIZE		                19 +#define BGP_MAX_PACKET_SIZE                   4096 + +/* BGP minimum message size.  */ +#define BGP_MSG_OPEN_MIN_SIZE                   (BGP_HEADER_SIZE + 10) +#define BGP_MSG_UPDATE_MIN_SIZE                 (BGP_HEADER_SIZE + 4) +#define BGP_MSG_NOTIFY_MIN_SIZE                 (BGP_HEADER_SIZE + 2) +#define BGP_MSG_KEEPALIVE_MIN_SIZE              (BGP_HEADER_SIZE + 0) +#define BGP_MSG_ROUTE_REFRESH_MIN_SIZE          (BGP_HEADER_SIZE + 4) +#define BGP_MSG_CAPABILITY_MIN_SIZE             (BGP_HEADER_SIZE + 3) + +/* BGP message types.  */ +#define	BGP_MSG_OPEN		                 1 +#define	BGP_MSG_UPDATE		                 2 +#define	BGP_MSG_NOTIFY		                 3 +#define	BGP_MSG_KEEPALIVE	                 4 +#define BGP_MSG_ROUTE_REFRESH_NEW                5 +#define BGP_MSG_CAPABILITY                       6 +#define BGP_MSG_ROUTE_REFRESH_OLD              128 + +/* BGP open optional parameter.  */ +#define BGP_OPEN_OPT_AUTH                        1 +#define BGP_OPEN_OPT_CAP                         2 + +/* BGP4 attribute type codes.  */ +#define BGP_ATTR_ORIGIN                          1 +#define BGP_ATTR_AS_PATH                         2 +#define BGP_ATTR_NEXT_HOP                        3 +#define BGP_ATTR_MULTI_EXIT_DISC                 4 +#define BGP_ATTR_LOCAL_PREF                      5 +#define BGP_ATTR_ATOMIC_AGGREGATE                6 +#define BGP_ATTR_AGGREGATOR                      7 +#define BGP_ATTR_COMMUNITIES                     8 +#define BGP_ATTR_ORIGINATOR_ID                   9 +#define BGP_ATTR_CLUSTER_LIST                   10 +#define BGP_ATTR_DPA                            11 +#define BGP_ATTR_ADVERTISER                     12 +#define BGP_ATTR_RCID_PATH                      13 +#define BGP_ATTR_MP_REACH_NLRI                  14 +#define BGP_ATTR_MP_UNREACH_NLRI                15 +#define BGP_ATTR_EXT_COMMUNITIES                16 + +/* BGP update origin.  */ +#define BGP_ORIGIN_IGP                           0 +#define BGP_ORIGIN_EGP                           1 +#define BGP_ORIGIN_INCOMPLETE                    2 + +/* BGP notify message codes.  */ +#define BGP_NOTIFY_HEADER_ERR                    1 +#define BGP_NOTIFY_OPEN_ERR                      2 +#define BGP_NOTIFY_UPDATE_ERR                    3 +#define BGP_NOTIFY_HOLD_ERR                      4 +#define BGP_NOTIFY_FSM_ERR                       5 +#define BGP_NOTIFY_CEASE                         6 +#define BGP_NOTIFY_CAPABILITY_ERR                7 +#define BGP_NOTIFY_MAX	                         8 + +/* BGP_NOTIFY_HEADER_ERR sub codes.  */ +#define BGP_NOTIFY_HEADER_NOT_SYNC               1 +#define BGP_NOTIFY_HEADER_BAD_MESLEN             2 +#define BGP_NOTIFY_HEADER_BAD_MESTYPE            3 +#define BGP_NOTIFY_HEADER_MAX                    4 + +/* BGP_NOTIFY_OPEN_ERR sub codes.  */ +#define BGP_NOTIFY_OPEN_UNSUP_VERSION            1 +#define BGP_NOTIFY_OPEN_BAD_PEER_AS              2 +#define BGP_NOTIFY_OPEN_BAD_BGP_IDENT            3 +#define BGP_NOTIFY_OPEN_UNSUP_PARAM              4 +#define BGP_NOTIFY_OPEN_AUTH_FAILURE             5 +#define BGP_NOTIFY_OPEN_UNACEP_HOLDTIME          6 +#define BGP_NOTIFY_OPEN_UNSUP_CAPBL              7 +#define BGP_NOTIFY_OPEN_MAX                      8 + +/* BGP_NOTIFY_UPDATE_ERR sub codes.  */ +#define BGP_NOTIFY_UPDATE_MAL_ATTR               1 +#define BGP_NOTIFY_UPDATE_UNREC_ATTR             2 +#define BGP_NOTIFY_UPDATE_MISS_ATTR              3 +#define BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR          4 +#define BGP_NOTIFY_UPDATE_ATTR_LENG_ERR          5 +#define BGP_NOTIFY_UPDATE_INVAL_ORIGIN           6 +#define BGP_NOTIFY_UPDATE_AS_ROUTE_LOOP          7 +#define BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP         8 +#define BGP_NOTIFY_UPDATE_OPT_ATTR_ERR           9 +#define BGP_NOTIFY_UPDATE_INVAL_NETWORK         10 +#define BGP_NOTIFY_UPDATE_MAL_AS_PATH           11 +#define BGP_NOTIFY_UPDATE_MAX                   12 + +/* BGP_NOTIFY_CEASE sub codes (draft-ietf-idr-cease-subcode-00).  */ +#define BGP_NOTIFY_CEASE_MAX_PREFIX              1 +#define BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN          2 +#define BGP_NOTIFY_CEASE_PEER_UNCONFIG           3 +#define BGP_NOTIFY_CEASE_ADMIN_RESET             4 +#define BGP_NOTIFY_CEASE_CONNECT_REJECT          5 +#define BGP_NOTIFY_CEASE_CONFIG_CHANGE           6 +#define BGP_NOTIFY_CEASE_MAX                     7 + +/* BGP_NOTIFY_CAPABILITY_ERR sub codes (draft-ietf-idr-dynamic-cap-02). */ +#define BGP_NOTIFY_CAPABILITY_INVALID_ACTION     1 +#define BGP_NOTIFY_CAPABILITY_INVALID_LENGTH     2 +#define BGP_NOTIFY_CAPABILITY_MALFORMED_CODE     3 +#define BGP_NOTIFY_CAPABILITY_MAX                4 + +/* BGP finite state machine status.  */ +#define Idle                                     1 +#define Connect                                  2 +#define Active                                   3 +#define OpenSent                                 4 +#define OpenConfirm                              5 +#define Established                              6 +#define BGP_STATUS_MAX                           7 + +/* BGP finite state machine events.  */ +#define BGP_Start                                1 +#define BGP_Stop                                 2 +#define TCP_connection_open                      3 +#define TCP_connection_closed                    4 +#define TCP_connection_open_failed               5 +#define TCP_fatal_error                          6 +#define ConnectRetry_timer_expired               7 +#define Hold_Timer_expired                       8 +#define KeepAlive_timer_expired                  9 +#define Receive_OPEN_message                    10 +#define Receive_KEEPALIVE_message               11 +#define Receive_UPDATE_message                  12 +#define Receive_NOTIFICATION_message            13 +#define BGP_EVENTS_MAX                          14 + +/* BGP timers default value.  */ +#define BGP_INIT_START_TIMER                     5 +#define BGP_ERROR_START_TIMER                   30 +#define BGP_DEFAULT_HOLDTIME                   180 +#define BGP_DEFAULT_KEEPALIVE                   60  +#define BGP_DEFAULT_ASORIGINATE                 15 +#define BGP_DEFAULT_EBGP_ROUTEADV               30 +#define BGP_DEFAULT_IBGP_ROUTEADV                5 +#define BGP_CLEAR_CONNECT_RETRY                 20 +#define BGP_DEFAULT_CONNECT_RETRY              120 + +/* BGP default local preference.  */ +#define BGP_DEFAULT_LOCAL_PREF                 100 + +/* SAFI which used in open capability negotiation.  */ +#define BGP_SAFI_VPNV4                         128 +#define BGP_SAFI_VPNV6                         129 + +/* Max TTL value.  */ +#define TTL_MAX                                255 + +/* BGP uptime string length.  */ +#define BGP_UPTIME_LEN 25 + +/* Default configuration settings for bgpd.  */ +#define BGP_VTY_PORT                          2605 +#define BGP_VTYSH_PATH                "/tmp/.bgpd" +#define BGP_DEFAULT_CONFIG             "bgpd.conf" + +/* Check AS path loop when we send NLRI.  */ +/* #define BGP_SEND_ASPATH_CHECK */ + +/* IBGP/EBGP identifier.  We also have a CONFED peer, which is to say, +   a peer who's AS is part of our Confederation.  */ +enum +{ +  BGP_PEER_IBGP, +  BGP_PEER_EBGP, +  BGP_PEER_INTERNAL, +  BGP_PEER_CONFED +}; + +/* Flag for peer_clear_soft().  */ +enum bgp_clear_type +{ +  BGP_CLEAR_SOFT_NONE, +  BGP_CLEAR_SOFT_OUT, +  BGP_CLEAR_SOFT_IN, +  BGP_CLEAR_SOFT_BOTH, +  BGP_CLEAR_SOFT_IN_ORF_PREFIX +}; + +/* Macros. */ +#define BGP_INPUT(P)         ((P)->ibuf) +#define BGP_INPUT_PNT(P)     (STREAM_PNT(BGP_INPUT(P))) + +/* Macro to check BGP information is alive or not.  */ +#define BGP_INFO_HOLDDOWN(BI)                         \ +  (! CHECK_FLAG ((BI)->flags, BGP_INFO_VALID)         \ +   || CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY)      \ +   || CHECK_FLAG ((BI)->flags, BGP_INFO_DAMPED)) + +/* Count prefix size from mask length */ +#define PSIZE(a) (((a) + 7) / (8)) + +/* BGP error codes.  */ +#define BGP_SUCCESS                               0 +#define BGP_ERR_INVALID_VALUE                    -1 +#define BGP_ERR_INVALID_FLAG                     -2 +#define BGP_ERR_INVALID_AS                       -3 +#define BGP_ERR_INVALID_BGP                      -4 +#define BGP_ERR_PEER_GROUP_MEMBER                -5 +#define BGP_ERR_MULTIPLE_INSTANCE_USED           -6 +#define BGP_ERR_PEER_GROUP_MEMBER_EXISTS         -7 +#define BGP_ERR_PEER_BELONGS_TO_GROUP            -8 +#define BGP_ERR_PEER_GROUP_AF_UNCONFIGURED       -9 +#define BGP_ERR_PEER_GROUP_NO_REMOTE_AS         -10 +#define BGP_ERR_PEER_GROUP_CANT_CHANGE          -11 +#define BGP_ERR_PEER_GROUP_MISMATCH             -12 +#define BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT  -13 +#define BGP_ERR_MULTIPLE_INSTANCE_NOT_SET       -14 +#define BGP_ERR_AS_MISMATCH                     -15 +#define BGP_ERR_PEER_INACTIVE                   -16 +#define BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER   -17 +#define BGP_ERR_PEER_GROUP_HAS_THE_FLAG         -18 +#define BGP_ERR_PEER_FLAG_CONFLICT              -19 +#define BGP_ERR_PEER_GROUP_SHUTDOWN             -20 +#define BGP_ERR_PEER_FILTER_CONFLICT            -21 +#define BGP_ERR_NOT_INTERNAL_PEER               -22 +#define BGP_ERR_REMOVE_PRIVATE_AS               -23 +#define BGP_ERR_AF_UNCONFIGURED                 -24 +#define BGP_ERR_SOFT_RECONFIG_UNCONFIGURED      -25 +#define BGP_ERR_INSTANCE_MISMATCH               -26 +#define BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP  -27 +#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS    -28 +#define BGP_ERR_MAX                             -29 + +extern struct bgp_master *bm; + +extern struct thread_master *master; + +/* Prototypes. */ +void bgp_terminate (void); +void bgp_reset (void); +void bgp_zclient_reset (); +int bgp_nexthop_set (union sockunion *, union sockunion *,  +		     struct bgp_nexthop *, struct peer *); +struct bgp *bgp_get_default (); +struct bgp *bgp_lookup (as_t, char *); +struct bgp *bgp_lookup_by_name (char *); +struct peer *peer_lookup (struct bgp *, union sockunion *); +struct peer_group *peer_group_lookup (struct bgp *, char *); +struct peer_group *peer_group_get (struct bgp *, char *); +struct peer *peer_lookup_with_open (union sockunion *, as_t, struct in_addr *, +				    int *); +int peer_sort (struct peer *peer); +int peer_active (struct peer *); +int peer_active_nego (struct peer *); +struct peer *peer_create_accept (struct bgp *); +char *peer_uptime (time_t, char *, size_t); +void bgp_config_write_family_header (struct vty *, afi_t, safi_t, int *); + +void bgp_master_init (); + +void bgp_init (); + +int bgp_option_set (int); +int bgp_option_unset (int); +int bgp_option_check (int); + +int bgp_get (struct bgp **, as_t *, char *); +int bgp_delete (struct bgp *); + +int bgp_flag_set (struct bgp *, int); +int bgp_flag_unset (struct bgp *, int); +int bgp_flag_check (struct bgp *, int); + +int bgp_router_id_set (struct bgp *, struct in_addr *); +int bgp_router_id_unset (struct bgp *); + +int bgp_cluster_id_set (struct bgp *, struct in_addr *); +int bgp_cluster_id_unset (struct bgp *); + +int bgp_confederation_id_set (struct bgp *, as_t); +int bgp_confederation_id_unset (struct bgp *); +int bgp_confederation_peers_check (struct bgp *, as_t); + +int bgp_confederation_peers_add (struct bgp *, as_t); +int bgp_confederation_peers_remove (struct bgp *, as_t); + +int bgp_timers_set (struct bgp *, u_int32_t, u_int32_t); +int bgp_timers_unset (struct bgp *); + +int bgp_default_local_preference_set (struct bgp *, u_int32_t); +int bgp_default_local_preference_unset (struct bgp *); + +int peer_remote_as (struct bgp *, union sockunion *, as_t *, afi_t, safi_t); +int peer_group_remote_as (struct bgp *, char *, as_t *); +int peer_delete (struct peer *peer); +int peer_group_delete (struct peer_group *); +int peer_group_remote_as_delete (struct peer_group *); + +int peer_activate (struct peer *, afi_t, safi_t); +int peer_deactivate (struct peer *, afi_t, safi_t); + +int peer_group_bind (struct bgp *, union sockunion *, struct peer_group *, +		     afi_t, safi_t, as_t *); +int peer_group_unbind (struct bgp *, struct peer *, struct peer_group *, +		       afi_t, safi_t); + +int peer_flag_set (struct peer *, u_int32_t); +int peer_flag_unset (struct peer *, u_int32_t); + +int peer_af_flag_set (struct peer *, afi_t, safi_t, u_int32_t); +int peer_af_flag_unset (struct peer *, afi_t, safi_t, u_int32_t); +int peer_af_flag_check (struct peer *, afi_t, safi_t, u_int32_t); + +int peer_ebgp_multihop_set (struct peer *, int); +int peer_ebgp_multihop_unset (struct peer *); + +int peer_description_set (struct peer *, char *); +int peer_description_unset (struct peer *); + +int peer_update_source_if_set (struct peer *, char *); +int peer_update_source_addr_set (struct peer *, union sockunion *); +int peer_update_source_unset (struct peer *); + +int peer_default_originate_set (struct peer *, afi_t, safi_t, char *); +int peer_default_originate_unset (struct peer *, afi_t, safi_t); + +int peer_port_set (struct peer *, u_int16_t); +int peer_port_unset (struct peer *); + +int peer_weight_set (struct peer *, u_int16_t); +int peer_weight_unset (struct peer *); + +int peer_timers_set (struct peer *, u_int32_t, u_int32_t); +int peer_timers_unset (struct peer *); + +int peer_timers_connect_set (struct peer *, u_int32_t); +int peer_timers_connect_unset (struct peer *); + +int peer_advertise_interval_set (struct peer *, u_int32_t); +int peer_advertise_interval_unset (struct peer *); + +int peer_version_set (struct peer *, int); +int peer_version_unset (struct peer *); + +int peer_interface_set (struct peer *, char *); +int peer_interface_unset (struct peer *); + +int peer_distribute_set (struct peer *, afi_t, safi_t, int, char *); +int peer_distribute_unset (struct peer *, afi_t, safi_t, int); + +int peer_allowas_in_set (struct peer *, afi_t, safi_t, int); +int peer_allowas_in_unset (struct peer *, afi_t, safi_t); + +int peer_local_as_set (struct peer *, as_t, int); +int peer_local_as_unset (struct peer *); + +int peer_prefix_list_set (struct peer *, afi_t, safi_t, int, char *); +int peer_prefix_list_unset (struct peer *, afi_t, safi_t, int); + +int peer_aslist_set (struct peer *, afi_t, safi_t, int, char *); +int peer_aslist_unset (struct peer *,afi_t, safi_t, int); + +int peer_route_map_set (struct peer *, afi_t, safi_t, int, char *); +int peer_route_map_unset (struct peer *, afi_t, safi_t, int); + +int peer_unsuppress_map_set (struct peer *, afi_t, safi_t, char *); +int peer_unsuppress_map_unset (struct peer *, afi_t, safi_t); + +int peer_maximum_prefix_set (struct peer *, afi_t, safi_t, u_int32_t, int); +int peer_maximum_prefix_unset (struct peer *, afi_t, safi_t); + +int peer_clear (struct peer *); +int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type);  | 
