From 718e3744195351130f4ce7dbe0613f4b3e23df93 Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 13 Dec 2002 20:15:29 +0000 Subject: Initial revision --- bgpd/.cvsignore | 8 + bgpd/BGP4-MIB.txt | 929 +++++ bgpd/ChangeLog | 2368 ++++++++++++ bgpd/Makefile.am | 44 + bgpd/Makefile.in | 534 +++ bgpd/bgp_advertise.c | 405 +++ bgpd/bgp_advertise.h | 178 + bgpd/bgp_aspath.c | 1186 ++++++ bgpd/bgp_aspath.h | 77 + bgpd/bgp_attr.c | 1838 ++++++++++ bgpd/bgp_attr.h | 125 + bgpd/bgp_btoa.c | 291 ++ bgpd/bgp_clist.c | 905 +++++ bgpd/bgp_clist.h | 143 + bgpd/bgp_community.c | 629 ++++ bgpd/bgp_community.h | 68 + bgpd/bgp_damp.c | 648 ++++ bgpd/bgp_damp.h | 141 + bgpd/bgp_debug.c | 732 ++++ bgpd/bgp_debug.h | 113 + bgpd/bgp_dump.c | 741 ++++ bgpd/bgp_dump.h | 34 + bgpd/bgp_ecommunity.c | 641 ++++ bgpd/bgp_ecommunity.h | 72 + bgpd/bgp_filter.c | 658 ++++ bgpd/bgp_filter.h | 31 + bgpd/bgp_fsm.c | 864 +++++ bgpd/bgp_fsm.h | 42 + bgpd/bgp_main.c | 285 ++ bgpd/bgp_mplsvpn.c | 741 ++++ bgpd/bgp_mplsvpn.h | 45 + bgpd/bgp_network.c | 381 ++ bgpd/bgp_network.h | 23 + bgpd/bgp_nexthop.c | 1405 ++++++++ bgpd/bgp_nexthop.h | 52 + bgpd/bgp_open.c | 793 ++++ bgpd/bgp_open.h | 69 + bgpd/bgp_packet.c | 2240 ++++++++++++ bgpd/bgp_packet.h | 49 + bgpd/bgp_regex.c | 93 + bgpd/bgp_regex.h | 31 + bgpd/bgp_route.c | 9053 ++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_route.h | 159 + bgpd/bgp_routemap.c | 3207 +++++++++++++++++ bgpd/bgp_snmp.c | 875 +++++ bgpd/bgp_snmp.h | 23 + bgpd/bgp_table.c | 489 +++ bgpd/bgp_table.h | 65 + bgpd/bgp_view.c | 258 ++ bgpd/bgp_vty.c | 9416 ++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_vty.h | 21 + bgpd/bgp_zebra.c | 1001 +++++ bgpd/bgp_zebra.h | 39 + bgpd/bgpd.c | 4601 +++++++++++++++++++++++ bgpd/bgpd.conf.sample | 29 + bgpd/bgpd.conf.sample2 | 77 + bgpd/bgpd.h | 824 +++++ 57 files changed, 50789 insertions(+) create mode 100644 bgpd/.cvsignore create mode 100644 bgpd/BGP4-MIB.txt create mode 100644 bgpd/ChangeLog create mode 100644 bgpd/Makefile.am create mode 100644 bgpd/Makefile.in create mode 100644 bgpd/bgp_advertise.c create mode 100644 bgpd/bgp_advertise.h create mode 100644 bgpd/bgp_aspath.c create mode 100644 bgpd/bgp_aspath.h create mode 100644 bgpd/bgp_attr.c create mode 100644 bgpd/bgp_attr.h create mode 100644 bgpd/bgp_btoa.c create mode 100644 bgpd/bgp_clist.c create mode 100644 bgpd/bgp_clist.h create mode 100644 bgpd/bgp_community.c create mode 100644 bgpd/bgp_community.h create mode 100644 bgpd/bgp_damp.c create mode 100644 bgpd/bgp_damp.h create mode 100644 bgpd/bgp_debug.c create mode 100644 bgpd/bgp_debug.h create mode 100644 bgpd/bgp_dump.c create mode 100644 bgpd/bgp_dump.h create mode 100644 bgpd/bgp_ecommunity.c create mode 100644 bgpd/bgp_ecommunity.h create mode 100644 bgpd/bgp_filter.c create mode 100644 bgpd/bgp_filter.h create mode 100644 bgpd/bgp_fsm.c create mode 100644 bgpd/bgp_fsm.h create mode 100644 bgpd/bgp_main.c create mode 100644 bgpd/bgp_mplsvpn.c create mode 100644 bgpd/bgp_mplsvpn.h create mode 100644 bgpd/bgp_network.c create mode 100644 bgpd/bgp_network.h create mode 100644 bgpd/bgp_nexthop.c create mode 100644 bgpd/bgp_nexthop.h create mode 100644 bgpd/bgp_open.c create mode 100644 bgpd/bgp_open.h create mode 100644 bgpd/bgp_packet.c create mode 100644 bgpd/bgp_packet.h create mode 100644 bgpd/bgp_regex.c create mode 100644 bgpd/bgp_regex.h create mode 100644 bgpd/bgp_route.c create mode 100644 bgpd/bgp_route.h create mode 100644 bgpd/bgp_routemap.c create mode 100644 bgpd/bgp_snmp.c create mode 100644 bgpd/bgp_snmp.h create mode 100644 bgpd/bgp_table.c create mode 100644 bgpd/bgp_table.h create mode 100644 bgpd/bgp_view.c create mode 100644 bgpd/bgp_vty.c create mode 100644 bgpd/bgp_vty.h create mode 100644 bgpd/bgp_zebra.c create mode 100644 bgpd/bgp_zebra.h create mode 100644 bgpd/bgpd.c create mode 100644 bgpd/bgpd.conf.sample create mode 100644 bgpd/bgpd.conf.sample2 create mode 100644 bgpd/bgpd.h (limited to 'bgpd') diff --git a/bgpd/.cvsignore b/bgpd/.cvsignore new file mode 100644 index 00000000..8edffb6e --- /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 00000000..c911316c --- /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 + . + + 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 00000000..4f7a20e9 --- /dev/null +++ b/bgpd/ChangeLog @@ -0,0 +1,2368 @@ +2002-10-23 Kunihiro Ishiguro + + * 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 + +2002-08-19 Kunihiro Ishiguro + + * bgp_clist.c (community_entry_free): Fix memory leak of standard + extcommunity-list config string. + +2002-08-19 Akihiro Mizutani + + * bgp_route.c (route_vty_out_detail): Fix bug of router-id display + when multiple instance is used. + +2002-08-18 Akihiro Mizutani + + * bgpd.c: Make "default-originate" and "maximum-prefix" commands + available in peer-group configuration. + +2002-08-13 Akihiro Mizutani + + * 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 + + * zebra-0.93 released. + +2001-10-28 Kunihiro Ishiguro + + * bgpd.c (bgp_vty_init): Translate update commands are removed. + +2001-10-10 Kunihiro Ishiguro + + * bgp_route.c (bgp_static_set): Add workaround for BGP static + route announcement when there is no zebra running. + +2001-10-08 Kunihiro Ishiguro + + * bgpd.c (neighbor_remote_as_unicast): Remove "remote-as nlri + unicast multicast" commands. + +2001-09-14 Akihiro Mizutani + + * 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 + + * bgp_advertise.c (bgp_advertise_intern): attr must be interned + before looking up hash table. + +2001-08-30 Kunihiro Ishiguro + + * bgpd.h (struct peer): BGP filter is moved from peer_conf to + peer. + +2001-08-28 Kunihiro Ishiguro + + * bgp_nexthop.c (bnc_nexthop_free): Fix next pointer bug. + Suggested by: "Hong-Sung Kim" . + +2001-08-26 Kunihiro Ishiguro + + * bgp_table.c (bgp_node_create): Clearn memory before use it. + +2001-08-24 Kunihiro Ishiguro + + * Change to use bgp_table.[ch]. + +2001-08-23 Kunihiro Ishiguro + + * bgpd.c (bgp_init): Add "transparent-as" and + "transparent-nexthop" for old version compatibility. + +2001-08-23 Akihiro Mizutani + + * 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 + + * 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 + + * zebra-0.92a released. + +2001-08-19 Akihiro Mizutani + + * bgpd.c: AF specific soft-reconfiguration inbound commands are + added. + +2001-08-17 Kunihiro Ishiguro + + * 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 + + * bgpd.c: AF specific route-reflector-client and + route-server-client configuration are added. + +2001-08-17 Rick Payne + + * bgp_clist.c (community_match_regexp): Check special ^$ case. + +2001-08-17 Akihiro Mizutani + + * bgp_clist.c (community_list_match): Fix bug of community list + permit and deny check. + +2001-08-16 Akihiro Mizutani + + * bgp_mplsvpn.c (bgp_mplsvpn_init): Add AF specific "nexthop-self" + command. + +2001-08-15 Akihiro Mizutani + + * 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 + + * zebra-0.92 released. + +2001-08-13 Kunihiro Ishiguro + + * bgpd.c (bgp_delete): "no router bgp" free static, aggregate, rib + table properly. + +2001-08-12 Kunihiro Ishiguro + + * 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 + + * bgpd.c (no_bgp_ipv4_multicast_route_map): Add IPv4 multicast + node filter commands. + +2001-08-11 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * bgp_route.c (bgp_announce_check): Enclose sending time AS loop + check code with #ifdef BGP_SEND_ASPATH_CHECK. + +2001-07-29 Kunihiro Ishiguro + + * 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 + + * bgp_route.c (bgp_announce_check): Simplify set next-hop self + check. + +2001-07-24 Akihiro Mizutani + + * bgp_route.c (bgp_announce_check): To route server clients, we + announce AS path, MED and nexthop transparently. + +2001-06-21 Kunihiro Ishiguro + + * 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 + + * 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 + + * bgp_route.c (bgp_withdraw): Add check for BGP_PEER_CONFED. + Reported by Rick Payne . + +2001-06-17 Kunihiro Ishiguro + + * 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 + + * bgpd.c (peer_delete): Fix memory leak. Reported by Yosi Yarchi + + +2001-06-01 Kunihiro Ishiguro + + * bgpd.c (bgp_delete): Fix memory leak. Reported by Yosi Yarchi + + +2001-05-27 Kunihiro Ishiguro + + * 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" + + * 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" + + * bgp_nexthop.c (bgp_scan_ipv4): bgp_scan() call bgp_process() for + all prefixes. + +2001-03-06 Kunihiro Ishiguro + + * 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" + + * 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" + + * bgp_route.c (bgp_info_cmp): During path seleciton, BGP + confederation peer is treated as same as IBGP peer. + +2001-02-19 Kunihiro Ishiguro + + * bgp_route.c (bgp_redistribute_add): Initialize attr_new with + attr. Call aspath_unintern when return from this function. + +2001-02-19 "Akihiro Mizutani" + + * bgpd.c (bgp_router_id_set): Reset BGP peer when router-id is + changed. + +2001-02-18 "Akihiro Mizutani" + + * bgp_packet.c (bgp_open_receive): When user configure holdtimer, + do not refrect the value to current session. + +2001-02-16 Kunihiro Ishiguro + + * 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" + + * bgp_aspath.c (aspath_make_str_count): Use ',' for separator for + AS_SET and AS_CONFED_SET. + +2001-02-15 Kunihiro Ishiguro + + * 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" + + * bgp_attr.c (bgp_attr_aggregate_intern): Do not set atomic + aggregate when using as-set. + +2001-02-14 "Akihiro Mizutani" + + * 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 + + * 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" + + * bgp_route.c (bgp_announce_check): Do not modify nexthop when the + route is passed by route reflector. + +2001-02-08 Kunihiro Ishiguro + + * 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" + + * 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 + + * bgp_fsm.c (bgp_establish): Do not send keepalive at established + time when keepalive timer is configured as zero. + +2001-02-01 Kunihiro Ishiguro + + * bgp_attr.c (bgp_attr_check): When peer is IBGP peer, local + preference is well-known attribute. + +2001-01-30 Kunihiro Ishiguro + + * 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" + + * bgp_route.c (bgp_info_cmp): Make route selection completely same + as Cisco's. + +2001-01-30 Kunihiro Ishiguro + + * bgp_attr.h (BGP_ATTR_FLAG_OPTIONAL): Rename old ATTR_FLAG_* to + BGP_ATTR_FLAG_* to clarify meenings. + +2001-01-30 "Akihiro Mizutani" + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * bgpd.c (bgp_network_import_check): New command for IGP network + check. + +2001-01-23 Kunihiro Ishiguro + + * 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" + + * bgp_route.c (bgp_info_cmp): Add IGP metric comparison. + +2001-01-23 Kunihiro Ishiguro + + * 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" + + * 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" + + * 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" + + * bgp_route.c (bgp_update): AS path lookup check is done in + bgp_update() not in attr_parse(). + +2001-01-18 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Call bgp_aggregate_decrement() just + before bgp_attr_unintern(). + +2001-01-17 Kunihiro Ishiguro + + * bgp_route.c (bgp_update): Now intern is performed very last part + of the BGP packet update procedure. + +2001-01-17 "Akihiro Mizutani" + + * bgp_route.c (bgp_update): When implicit withdraw occur, reuse + existing bgp_info structure. + +2001-01-17 Kunihiro Ishiguro + + * 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" + + * bgp_route.h (BGP_INFO_ATRR_CHANGED): Added for track attribute + change. + +2001-01-16 Kunihiro Ishiguro + + * 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 + + * bgp_packet.c (bgp_open_receive): Translated peer's packet_size + clear bug is fixed. + +2001-01-14 "Akihiro Mizutani" + + * bgp_packet.c (bgp_open_receive): Return notification with + supported version number. + +2001-01-13 Kunihiro Ishiguro + + * bgpd.c (bgp_show_summary): Display AS path and community + entries. Suggested by: "Matt Ranney" . + + * 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" + + * 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 + + * bgp_attr.c (bgp_mp_reach_parse): Fix warning code when second + IPv6 nexthop is not link-local addresss. + +2001-01-11 "Akihiro Mizutani" + + * 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 + + * 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" + + * 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 + + * 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 + + * 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 + + * bgp_main.c: Add "-n" no_kernel option to not install route to + kernel. Suggested by: "Matt Ranney" + +2001-01-09 Kunihiro Ishiguro + + * 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" + + * 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 soft in + -------------------------------------- + Try stored cache first then route-refresh + + clear ip bgp in + --------------------------------- + Try route-refresh first then try to use stored cache + +2001-01-09 Kunihiro Ishiguro + + * 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 + + * bgp_nexthop.c (bgp_nexthop_lookup): When IBGP nexthop is + changed, refresh it. + +2001-01-04 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info_tag): Add as_selected to + bgp_info_tag. + +2001-01-03 Kunihiro Ishiguro + + * 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 + + * bgpd.h (BGP_VTYSH_PATH): Change "/tmp/bgpd" to "/tmp/.bgpd". + +2000-12-29 Kunihiro Ishiguro + + * bgp_nexthop.c (zlookup_connect): Change to use UNIX domain + socket for zebra communication. + +2000-12-29 Akihiro Mizutani + + * bgp_route.c (bgp_process): Fix "bgp deterministic-med" process. + +2000-12-27 Akihiro Mizutani + + * bgp_route.c (bgp_process): Add "bgp deterministic-med" process. + +2000-12-25 Akihiro Mizutani + + * bgp_route.c (bgp_info_cmp): Use ntohl comparing router ID. + +2000-12-18 Akihiro Mizutani + + * bgp_route.c (bgp_info_cmp): When over three same prefix exit, + withdrawing best prefix perform router ID comparison. + +2000-12-15 Akihiro Mizutani + + * 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 + + * bgp_route.c (bgp_info_cmp): Compare originator ID when it is + available. + +2000-12-14 Akihiro Mizutani + + * bgp_packet.c (bgp_notify_receive): Disply received Notify data + information. + +2000-12-14 Kunihiro Ishiguro + + * 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 + + * 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 + + * bgp_packet.c (bgp_keepalive_send): Delete duplicate + bgp_packet_set_size () call. + +2000-11-28 Kunihiro Ishiguro + + * bgp_packet.c (bgp_read_packet): Remove debug codes. + +2000-11-27 Kunihiro Ishiguro + + * 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 + + * bgp_open.c: Fix error messages. + +2000-11-25 Kunihiro Ishiguro + + * 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 + + * 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 + + * bgp_debug.c (bgp_notify_print): Notify data length display bug + is fixed. + +2000-11-16 Kunihiro Ishiguro + + * bgp_nexthop.c (zlookup_connect): When UNIX domain connection to + zebra is enabled, use the method. + +2000-11-16 Akihiro Mizutani + + * bgpd.c: Revise debug message output. + +2000-11-15 Akihiro Mizutani + + * bgp_clist.c (ip_community_list): Fix bug of string comparison. + +2000-11-14 Akihiro Mizutani + + * bgp_community.c (community_match): Fix bug of memcmp return + value check. + +2000-11-07 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * bgp_fsm.c: Fix bug of holdtimer is not reset when bgp cleared. + +2000-10-31 Kunihiro Ishiguro + + * bgpd.h: Static bit flag is set by (1 << DIGIT). + +2000-10-24 Akihiro Mizutani + + * bgp_ecommunity.c (ecommunity_dup): Extended community display + format fix. + +2000-10-24 Arkadiusz Miskiewicz + + * bgp_network.c (bgp_serv_sock_addrinfo): Use gai_strerror. + (bgp_serv_sock_addrinfo): Check address family. + +2000-10-23 Jochen Friedrich + + * 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 + + * 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 + + * 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 + + * bgp_snmp.c (bgpPeerTable): ntohs missing bug is fixed. Change + to use linklist.c. Define COUNTER32 as ASN_COUNTER. + +2000-10-18 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * bgp_debug.c (debug_bgp_fsm): Fix typo. + +2000-10-17 Akihiro Mizutani + + * bgp_route.c: "show ipv6 bgp" route display improvement. + +2000-10-03 Kunihiro Ishiguro + + * 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 + + * 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 + + * zebra-0.89 is released. + +2000-10-02 Akihiro Mizutani + + * bgpd.c: "bgp deterministic-med" command is added. + +2000-10-02 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_connected_add): Apply mask for connected + route addition and deletion. + +2000-09-29 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_cmp_left): Skip confederation AS segment + when comparing leftmost AS number. + +2000-09-29 Akihiro Mizutani + + * 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 + + * 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 + + * 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 + + * 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 + + * bgp_routemap.c: Configuration of prefix-list match is shown as + "match ip address prefix-list ". Old configuration "match + ip prefix-list " is left for compatibilitty. + +2000-09-25 Akihiro Mizutani + + * 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 + + * 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 + + * 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 + + * bgpd.c (bgp_show_peer): Fix misplaced #endif. + +2000-09-12 Akihiro Mizutani + + * 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 + + * bgp_zebra.c (bgp_zebra_announce): BGP confederation peer's routes + are passed to zebra like IBGP route. + +2000-09-10 Akihiro Mizutani + + * bgpd.c (bgp_config_write_peer): Make it consistent passive + configuration. + + * bgp_route.c: Community match command is added. + "show ip bgp community " + "show ip bgp community exact-match" + +2000-09-08 Kunihiro Ishiguro + + * bgp_nexthop.c (bgp_nexthop_lookup): ebgp-multihop routes are + treated as IBGP routes. + +2000-09-08 Akihiro Mizutani + + * 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 + + * 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 + + * 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 + + * 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 + + * bgpd. (clear_ip_bgp_all_soft): Add "clear ip bgp * soft" for + both inbound and outbound soft reconfiguration. + +2000-08-17 Kunihiro Ishiguro + + * bgpd.c (clear_ip_bgp_peer_soft_out): Add soft-reconfiguration + outbound. + (peer_new): Set route-refresh flag. + +2000-08-16 Akihiro Mizutani + + * 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 + + * 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 + + * bgp_nexthop.c (bgp_scan): Care for aggregate route when the + route become inaccessible. + +2000-08-15 Akihiro Mizutani + + * bgp_route.c (show_ip_bgp_prefix): "show ip bgp A.B.C.D/M" + command is added. + +2000-08-15 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_interface_up): Register connected route. + (bgp_interface_down): Unregister connected route. + +2000-08-14 Kunihiro Ishiguro + + * 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 + + * 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 + + * bgp_route.c (route_vty_out_detail): Display format change. + +2000-08-06 Kunihiro Ishiguro + + * 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 + + * bgpd.c: Include bgpd/bgp_nexthop.h. + +2000-07-31 Akihiro Mizutani + + * 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 + + * bgp_snmp.c: Add BGP peer MIB implementation. + +2000-07-12 Akihiro Mizutani + + * bgpd.c (bgp_show_peer): Fix typo. + +2000-07-11 Akihiro Mizutani + + * bgp_routemap.c: Add commands for deleting set without argument. + +2000-07-03 Akihiro Mizutani + + * bgp_zebra.c: Fix redistribute help strings. + +2000-07-01 Kunihiro Ishiguro + + * bgp_route.c (bgp_show): When bgpd works as vtysh server send all + output to vty at once. + +2000-06-13 Kunihiro Ishiguro + + * 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 + + * 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 + + * bgpd.c: Fix help strings. + + * bgpd.h: Likewise. + +2000-06-11 Kunihiro Ishiguro + + * bgp_route.c (bgp_aggregate_unset): Fix bug of checking rn->info + instead of rn. Reported by Akihiro Mizutani . + + * 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 + + * 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 + + * 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 + + * bgp_route.c: Fix help strings and command arguments. + +2000-06-06 Kunihiro Ishiguro + + * bgp_ecommunity.c: Include prefix.h + +2000-06-05 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * 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 + + * bgp_routemap.c (route_set_community_none_cmd): "set community + none" command is added to route-map. + +2000-06-01 Akihiro Mizutani + + * bgp_debug.c: Change "show debug" to "show debugging". Now "show + debugging" is not used in VIEW_NODE. + +2000-05-30 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * bgp_ecommunity.c (ecommunity_parse): New file for Extended + Communities attribute. + * bgp_ecommunity.h: Likewise. + +2000-05-11 Kunihiro Ishiguro + + * 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 + + * bgpd.c (bgp_bestpath_missing_as_worst): Add "bgp bestpath + missing-as-worst". + +2000-05-08 Kunihiro Ishiguro + + * bgp_routemap.c (match_community): Clarify help of "match + community". + +2000-05-02 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_cmp_left): Remove debug code. + +2000-04-27 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * bgpd.c (bgp_distribute_update): Add struct access_list * + argument. + +2000-04-17 Kunihiro Ishiguro + + * 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 + + * bgp_routemap.c: Add "match ip address prefix-list". + +2000-03-29 Rick Payne + + * bgp_aspath.c (aspath_strip_confed): Fix realloc problem. + +2000-03-16 Kunihiro Ishiguro + + * bgp_fsm.c (bgp_reconnect): Connect retry timer is expired when + the peer status is Connect. + +2000-03-03 Kunihiro Ishiguro + + * Fix bug of rewritten originator-id. + +2000-01-27 Rick Payne + + * 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 + + * bgpd.c: Introduce peer_change_flag_with_reset() fucntion. + +2000-01-17 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * bgp_packet.c (bgp_write): Change status to Idle and set timer + after write failed. + +1999-12-14 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_zebra_announce): Add info->selected check. + +1999-12-12 Kunihiro Ishiguro + + * bgp_route.c (nlri_unfeasible): nlri_unfeasible() is merged with + nlri_parse(). + +1999-12-10 Kunihiro Ishiguro + + * 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 + + * 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 + + * bgpd.c (no_neighbor_port): New command added. + (peer_new): Set send_community. + +1999-12-04 Kunihiro Ishiguro + + * 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 + + * 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 + + * bgp_routemap.c (route_match_nlri): `match nlri + unicast|multicast' and `set nlri unicast|multicast' command are + added. + +1999-11-22 Robert Olsson + + * 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 + + * bgp_open.c (bgp_capability_mp): Temporary comment out + SAFI_UNICAST_MULTICAST handling until we know the meanings. + +1999-11-13 Kunihiro Ishiguro + + * bgp_btoa.c: New file added. + +1999-11-12 Kunihiro Ishiguro + + * 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 + + * bgp_attr.c (bgp_mp_reach_parse): Ignore link-local addresses + attribute from non-shared-network peers. + +1999-11-10 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * bgp_zebra.c: Redistribute route-map support is added. + + * bgp_zebra.h: New file added. + +1999-11-04 Kunihiro Ishiguro + + * 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 + + * BGP4-MIB.txt: New file added. Edited version of RFC1657. + +1999-10-25 Bill Sommerfeld + + * 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 + + * bgp_zebra.c: Add redistribute kernel command. + +1999-10-25 Kunihiro Ishiguro + + * bgp_route.c (bgp_reset): New function added. + + * bgpd.conf.sample2: Add IPv6 configuration sample. + +1999-10-24 Bill Sommerfeld + + * bgp_route.c (ipv6_aggregate_address): Function added. + +1999-10-21 Kunihiro Ishiguro + + * 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 + + * bgp_routemap.c (route_set_local_pref): Fix bug of setting + attribute flag. + +1999-10-21 Bill Sommerfeld + + * 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 + + * `show ip[v6] bgp PREFIX' show uptime of the route. + +1999-10-04 Kunihiro Ishiguro + + * 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 + + * bgpd.c (clear_ip_bgp): Add `clear ip bgp ASN'. + +1999-10-03 Kunihiro Ishiguro + + * bgp_routemap.c: Add `match ip prefix-list' and `match ipv6 + prefix-list'. + +1999-09-28 Kunihiro Ishiguro + + * bgpd.c (bgp_collision_detect): Add BGP collision detection + function. + +1999-09-26 Blake Meike + + * bgpd.c (neighbor_port): New command `neighbor PEER port PORT' is + added. + +1999-08-24 Kunihiro Ishiguro + + * bgpd.c (no_neighbor_timers_keepalive): Change MIN to min. Add + min() macro. + +1999-08-19 Rick Payne + + * bgp_packet.c (bgp_open): BGP holdtimer bug is fixed. Make BGP + keepalive timer configurable. + +1999-08-15 Kunihiro Ishiguro + + * bgp_zebra.c (bgp_redistribute_set): Fix redistribute bug. + +1999-08-13 Kunihiro Ishiguro + + * bgpd.c (bgp_peer_display): show ip bgp neighbors PEER only list + the peer not all of them. + +1999-08-11 Rick Payne + + * bgp_route.c (bgp_announce): Remove MED if its an EBGP peer - + will get overwritten by route-maps. + +1999-08-08 Rick Payne + + * bgp_routemap.c: Multi protocol route-map modification. + +1999-08-01 Kunihiro Ishiguro + + * 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 + + * bgp_route.c (bgp_peer_delete): Reselect of IPv6 route. + +1999-07-29 Rick Payne + + * Changed route-maps to behave in a more cisco-like fashion + +1999-07-27 Kunihiro Ishiguro + + * 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 . + +1999-07-23 Kunihiro Ishiguro + + * bgpd.c: Change peer's A.B.C.D to PEER. + +1999-07-22 Kunihiro Ishiguro + + * 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 + + * bgp_packet.c (bgp_open): Holdtime fetch bug is fixed. Reported + by Yuji SEKIYA . + +1999-07-15 Kunihiro Ishiguro + + * bgp_fsm.c (fsm_holdtime): Don't close file descriptor in + fsm_holdtime (). + +1999-07-11 Kunihiro Ishiguro + + * bgp_routemap.c: Add `set atomic-aggregate' command. + +1999-07-06 Kunihiro Ishiguro + + * bgp_routemap.c (route_set_ip_nexthop_cmd): Change "ip nexthop" + to "ip next-hop". + +1999-07-02 Kunihiro Ishiguro + + * bgp_route.c (show_ipv6_bgp_regexp): `show ipv6 bgp regexp' + added. + +1999-07-01 Rick Payne + + * bgp_zebra.c (zebra_init): Install standard commands to + ZEBRA_NODE. + +1999-06-28 Rick Payne + + * bgpd.c (bgp_delete): bgp peer deletion bug is fixed. + +1999-06-25 Kunihiro Ishiguro + + * bgpd.c: Add neighbor update-source command as ALIAS to + neighbor_interface. + +1999-06-19 Kunihiro Ishiguro + + * 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 + + * bgpd.c (router_bgp): router bgp's argument changed from AS_NO to + <1-65535>. + +1999-06-08 Kunihiro Ishiguro + + * bgp_route.h (struct bgp_info): Add subtype for BGP route type. + +1999-06-07 Kunihiro Ishiguro + + * bgp_community.c (community_merge): Function added. + +1999-06-04 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * bgp_main.c (signal_init): SIGTERM call sigint. + (sigint): Loggging more better message. + +1999-05-12 Kunihiro Ishiguro + + * bgp_attr.c (bgp_packet_attribute): AS path attribute extended + length bit check is added. + +1999-05-11 Kunihiro Ishiguro + + * 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 + + * 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 + + * bgpd.c (bgp_delete): Function added for `no router bgp'. + +1999-05-05 Kunihiro Ishiguro + + * 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 + + * bgpd.h (BGP_ATTR_ORIGINATOR_ID): Changed from BGP_ATTR_ORIGINATOR. + +1999-05-02 Kunihiro Ishiguro + + * bgp_route.c (bgp_announce): Add route reflector check. + +1999-05-01 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * bgp_route.c: Add bgp_aggregate_ipv4 and bgp_aggregate_ipv6. + +1999-04-17 Kunihiro Ishiguro + + * bgp_route.c (aggregate_address): Function added. + + * bgp_zebra.c (zebra_read): Change log to zlog. + +1999-04-15 Kunihiro Ishiguro + + * Makefile.am (noninst_HEADERS): Added for make dist. + +1999-04-09 Kunihiro Ishiguro + + * aspath_regex.c: Removed from distribution. + +1999-04-07 Kunihiro Ishiguro + + * bgp_attr.c (bgp_packet_attribute): Old draft-00 packet treatment + bug fixed. + +1999-04-06 Kunihiro Ishiguro + + * 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 + + * bgp_filter.c: New file added. + +1999-04-01 Kunihiro Ishiguro + + * bgp_aspath.c (aspath_empty_aspath): Change for peering with + gated. + +1999-03-24 Kunihiro Ishiguro + + * bgp_main.c (main): Default loggin method changed from syslog to + stdout. + +1999-03-05 Kunihiro Ishiguro + + * bgp_route.c: Delete obsolete default attribute DEFUN. + +1999-03-04 Kunihiro Ishiguro + + * bgp_attr.c: Make attribute structure put into attribute hash. + +1999-03-02 Kunihiro Ishiguro + + * bgp_view.c : Delete file. + +1999-02-25 Kunihiro Ishiguro + + * 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 + + * 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 + + * bgp_aspath.c (aspath_add_left): change function name from + aspath_add_leftmost_as(). + +1999-02-21 Kunihiro Ishiguro + + * bgp_aspath.c: add aspath_add_leftmost_as (). + +1999-02-18 Peter Galbavy + + * syslog support added + +1999-01-26 Kunihiro Ishiguro + + * bgpd.c: DEFUN (neighbor_nexthop): deleted. + DEFUN (neighbor_distribute_list): added. + +1999-01-19 Kunihiro Ishiguro + + * 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 + + * bgp_packet.c (bgp_keepalive_send): Now BGP keepalive packet is + buffered. + +1999-01-08 Kunihiro Ishiguro + + * bgp_packet.c: New file. + +1998-12-22 Kunihiro Ishiguro + + * 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 + + * bgp_fsm.h: New file. + +1998-12-15 Magnus Ahltorp + + * 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 + + * bgpd.c (bgp_config_write): Delete vector v argument. + +1998-12-07 Kunihiro Ishiguro + + * bgpd.h: Delete annoying ld_[124]byte and st_[124]byte macros. + +1998-11-23 Kunihiro Ishiguro + + * bgp_radix.[ch]: removed. + +1998-09-15 HEO SeonMeyong + + * bgp_main.c: ifdef HYDRANGEA -> ifdef KAME + +1998-08-13 Kunihiro Ishiguro + + * bgp_dump.c: delete nroute(). + +1998-05-19 Yamshita TAKAO + + * 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 + + * bgpd.h: Modify for compile on Solaris. + * bgp_aspath.h: likewize + +1998-05-08 Kunihiro Ishiguro + + * routemap.[ch]: move to ../lib directory. + +1998-05-07 Kunihiro Ishiguro + + * routemap.c (route_map_apply): add function. + +1998-05-06 Kunihiro Ishiguro + + * routemap.h: add file. + + * bgp_peer.h (enum ): change PEER_{IBGP,EBGP} to BGP_PEER_{IBGP,EBGP} + +1998-05-03 Kunihiro Ishiguro + + * Makefile.am: sysconfdir_DATA added. + +1998-05-02 Kunihiro Ishiguro + + * 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 + + * .cvsignore: File added. + +1998-04-30 Kunihiro Ishiguro + + * bgp_community.[ch]: File added. + +1998-03-04 Kunihiro Ishiguro + + * bgpd now use lib/thread.[ch]. + +1998-01-06 Kunihiro Ishiguro + + * 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 + + * bgp_vty.c: bgp_vty.c deleted. + + * bgpd.c (config_write_neighbor): add ebgp-multihop command. + +1997-12-29 Kunihiro Ishiguro + + * bgp_fsm.c: [-p bgp_port] and [-P vty_port] works + +1997-12-06 Kunihiro Ishiguro + + * bgp_vty.c: new file. + + * bgp_attr.c: add new logging system. + +1997-11-23 Kunihiro Ishiguro + + * Change all inet_addr call into inet_aton. + +1997-11-10 Kunihiro Ishiguro + + * bgp_radix.c: change radix_peer_delete + +1997-10-04 Kunihiro Ishiguro + + * bgp_aspath.c: move AS_TOKEN_??? definition from header to c source. + +1997-09-12 Kunihiro Ishiguro + + * bgp_dump.c (bgp_log_route): add dump_attr function + +1997-09-06 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * bgp_radix.c: Radix code is completely rewritten. It has better + memory treatment than old one. + +1997-08-14 Kunihiro Ishiguro + + * 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 + + * 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 + + * 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 + + * 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 + + * bgp_aspath.h: add next entry, delete rlist entry from struct aspath + +1997-08-04 Kunihiro Ishiguro + + * 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 00000000..7f739f6e --- /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 00000000..06c51892 --- /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 00000000..4778a977 --- /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 + +#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 00000000..e2ae0104 --- /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 00000000..fc5efb19 --- /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 + +#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 00000000..0295fafb --- /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 00000000..480bb912 --- /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 + +#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 00000000..9c5bf879 --- /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 00000000..7c708814 --- /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 + +#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 00000000..0b6a2e8c --- /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 + +#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 00000000..ffc707c2 --- /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 00000000..83b1cc5e --- /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 + +#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 00000000..58b3f9e6 --- /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 00000000..d70105f5 --- /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 +#include + +#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 00000000..f3b9bd6d --- /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 00000000..bb1a6107 --- /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 + +#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 00000000..06ba0757 --- /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 00000000..fca51edc --- /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 + +#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 00000000..d2f96a9e --- /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 00000000..2f9cc945 --- /dev/null +++ b/bgpd/bgp_ecommunity.c @@ -0,0 +1,641 @@ +/* BGP Extended Communities Attribute + 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 + +#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 00000000..678d1308 --- /dev/null +++ b/bgpd/bgp_ecommunity.h @@ -0,0 +1,72 @@ +/* BGP Extended Communities Attribute. + 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. */ + +/* 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 00000000..b544c716 --- /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 + +#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 00000000..8d55a224 --- /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 00000000..64a4c1bd --- /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 + +#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 00000000..f051aaa7 --- /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 00000000..7fc68fa7 --- /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 + +#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 00000000..e820cabf --- /dev/null +++ b/bgpd/bgp_mplsvpn.c @@ -0,0 +1,741 @@ +/* MPLS-VPN + 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 + +#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 /, 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 /, 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 00000000..cd861a87 --- /dev/null +++ b/bgpd/bgp_mplsvpn.h @@ -0,0 +1,45 @@ +/* MPLS-VPN + 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 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 00000000..40e9cdb3 --- /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 + +#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 00000000..b9949873 --- /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 00000000..24a113d9 --- /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 + +#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 00000000..5f4255d8 --- /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 00000000..a3e86b06 --- /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 + +#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 00000000..af7505a8 --- /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 00000000..48879f35 --- /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 + +#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 00000000..c1efc8bd --- /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 00000000..a6b65984 --- /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 + +#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 00000000..0829dd9a --- /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 + +#ifdef HAVE_GNU_REGEX +#include +#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 00000000..87d305cb --- /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 + +#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 /, 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 /, 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 /, 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 /, 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 /, 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 /, 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 /\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 /\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 /\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 /\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 /, 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 /, 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 + + */ +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 /, 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 /, 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 /, 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 /, 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 /, 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 /\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 /\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 /, 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 /, 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 /, 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 /, 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 /, 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 /, 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 /\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 /\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 /, 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 /, 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 /, 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 00000000..a11aa143 --- /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 00000000..498a6005 --- /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 + +#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 +#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 00000000..bf9c7f87 --- /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 + +#ifdef HAVE_SNMP +#include +#include +#include + +#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 00000000..a8af0329 --- /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 00000000..a2a3c97b --- /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 + +#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 00000000..52eb6a49 --- /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 00000000..795d1551 --- /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 + +#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 00000000..c1bae93e --- /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 + +#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 00000000..15ad5810 --- /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 00000000..3e5cdd2a --- /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 + +#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 00000000..1620c847 --- /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 00000000..f116a0cf --- /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 + +#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 00000000..b6a8b6f1 --- /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 00000000..d376ad25 --- /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 00000000..01d47212 --- /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); -- cgit v1.2.1