Initial revision
diff --git a/bgpd/.cvsignore b/bgpd/.cvsignore
new file mode 100644
index 0000000..8edffb6
--- /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 0000000..c911316
--- /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 0000000..4f7a20e
--- /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 0000000..7f739f6
--- /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 0000000..06c5189
--- /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 0000000..4778a97
--- /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 0000000..e2ae010
--- /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 0000000..fc5efb1
--- /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 0000000..0295faf
--- /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 0000000..480bb91
--- /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 0000000..9c5bf87
--- /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 0000000..7c70881
--- /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 0000000..0b6a2e8
--- /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 0000000..ffc707c
--- /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 0000000..83b1cc5
--- /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 0000000..58b3f9e
--- /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 0000000..d70105f
--- /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 0000000..f3b9bd6
--- /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 0000000..bb1a610
--- /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 0000000..06ba075
--- /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 0000000..fca51ed
--- /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 0000000..d2f96a9
--- /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 0000000..2f9cc94
--- /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 0000000..678d130
--- /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 0000000..b544c71
--- /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 0000000..8d55a22
--- /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 0000000..64a4c1b
--- /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 0000000..f051aaa
--- /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 0000000..7fc68fa
--- /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 0000000..e820cab
--- /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 0000000..cd861a8
--- /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 0000000..40e9cdb
--- /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 0000000..b994987
--- /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 0000000..24a113d
--- /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 0000000..5f4255d
--- /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 0000000..a3e86b0
--- /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 0000000..af7505a
--- /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 0000000..48879f3
--- /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 0000000..c1efc8b
--- /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 0000000..a6b6598
--- /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 0000000..0829dd9
--- /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 0000000..87d305c
--- /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 0000000..a11aa14
--- /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 0000000..498a600
--- /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 0000000..bf9c7f8
--- /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 0000000..a8af032
--- /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 0000000..a2a3c97
--- /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 0000000..52eb6a4
--- /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 0000000..795d155
--- /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 0000000..c1bae93
--- /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 0000000..15ad581
--- /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 0000000..3e5cdd2
--- /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 0000000..1620c84
--- /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 0000000..f116a0c
--- /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 0000000..b6a8b6f
--- /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 0000000..d376ad2
--- /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 0000000..01d4721
--- /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);