diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-03-09 05:07:46 +0100 |
---|---|---|
committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-03-09 05:07:46 +0100 |
commit | 7f57883ee6322b728e44f447da68ebc96b0664e9 (patch) | |
tree | 8b1392c96f88324176f253d6fa7c64edc8d1a1a2 | |
parent | Merge pull request #262 from donaldsharp/pim_jp_fixes (diff) | |
download | frr-7f57883ee6322b728e44f447da68ebc96b0664e9.tar.xz frr-7f57883ee6322b728e44f447da68ebc96b0664e9.zip |
eigrp: Initial Commit
Please Note, I will be redoing this commit message with
more information.
Additionally I will rework the lib/* changes into their
own commits.
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
60 files changed, 17222 insertions, 8 deletions
diff --git a/Makefile.am b/Makefile.am index aa978b7d2..aeacd4c3c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,13 +2,14 @@ SUBDIRS = lib qpb fpm @ZEBRA@ @LIBRFP@ @RFPTEST@ \ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @LDPD@ \ - @ISISD@ @PIMD@ @NHRPD@ \ + @ISISD@ @PIMD@ @NHRPD@ @EIGRPD@ \ @WATCHFRR@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ redhat @SOLARIS@ tests tools cumulus snapcraft DIST_SUBDIRS = lib qpb fpm zebra bgpd ripd ripngd ospfd ospf6d ldpd \ isisd watchfrr vtysh ospfclient doc m4 pkgsrc redhat tests \ - solaris pimd nhrpd @LIBRFP@ @RFPTEST@ tools cumulus snapcraft + solaris pimd nhrpd eigrpd @LIBRFP@ @RFPTEST@ tools cumulus \ + snapcraft EXTRA_DIST = aclocal.m4 SERVICES REPORTING-BUGS \ update-autotools \ diff --git a/configure.ac b/configure.ac index e46e44a8b..821e0e230 100755 --- a/configure.ac +++ b/configure.ac @@ -217,6 +217,8 @@ AC_ARG_ENABLE(ldpd, AS_HELP_STRING([--enable-ldpd], [build ldpd])) AC_ARG_ENABLE(nhrpd, AS_HELP_STRING([--disable-nhrpd], [do not build nhrpd])) +AC_ARG_ENABLE(eigrpd, + AS_HELP_STRING([--disable-eigrpd], [do not build eigrpd])) AC_ARG_ENABLE(watchfrr, AS_HELP_STRING([--disable-watchfrr], [do not build watchfrr])) AC_ARG_ENABLE(isisd, @@ -1200,6 +1202,13 @@ else fi AM_CONDITIONAL(NHRPD, test "x$NHRPD" = "xnhrpd") +if test "${enable_eigrpd}" = "no";then + EIGRPD="" +else + EIGRPD="eigrpd" +fi +AM_CONDITIONAL(EIGRPD, test "x$EIGRPD" = "xeigrpd") + if test "${enable_watchfrr}" = "no";then WATCHFRR="" else @@ -1281,6 +1290,7 @@ AC_SUBST(OSPFD) AC_SUBST(OSPF6D) AC_SUBST(LDPD) AC_SUBST(NHRPD) +AC_SUBST(EIGRPD) AC_SUBST(WATCHFRR) AC_SUBST(ISISD) AC_SUBST(PIMD) @@ -1671,6 +1681,7 @@ AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile pimd/Makefile + eigrpd/Makefile nhrpd/Makefile redhat/Makefile tools/Makefile @@ -1697,7 +1708,8 @@ AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile doc/zebra.8 doc/frr.1 pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh - pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh]) + pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh + pkgsrc/eigrpd.sh]) if test "${enable_bgp_vnc}" != "no"; then if test "${with_rfp_path}" = "bgpd/rfp-example" ; then diff --git a/eigrpd/.gitignore b/eigrpd/.gitignore new file mode 100644 index 000000000..e46af767b --- /dev/null +++ b/eigrpd/.gitignore @@ -0,0 +1,17 @@ +Makefile +Makefile.in +*.o +eigrpd +eigrpd.conf +tags +TAGS +.deps +.nfs* +*.lo +*.la +*.libs +.arch-inventory +.arch-ids +*~ +*.loT + diff --git a/eigrpd/EIGRP-MIB.txt b/eigrpd/EIGRP-MIB.txt new file mode 100644 index 000000000..f6ea298cf --- /dev/null +++ b/eigrpd/EIGRP-MIB.txt @@ -0,0 +1,1321 @@ +CISCO-EIGRP-MIB DEFINITIONS ::= BEGIN + + IMPORTS + MODULE-IDENTITY, + OBJECT-TYPE, + NOTIFICATION-TYPE, + Unsigned32, + Gauge32, + Counter32, + Counter64 + FROM SNMPv2-SMI + TruthValue, + TEXTUAL-CONVENTION + FROM SNMPv2-TC + SnmpAdminString + FROM SNMP-FRAMEWORK-MIB + MODULE-COMPLIANCE, + OBJECT-GROUP, + NOTIFICATION-GROUP + FROM SNMPv2-CONF + ciscoMgmt + FROM CISCO-SMI + InterfaceIndexOrZero, + ifIndex + FROM IF-MIB + InetAddressType, + InetAddress, + InetAddressPrefixLength + FROM INET-ADDRESS-MIB; + +ciscoEigrpMIB MODULE-IDENTITY + LAST-UPDATED "200411160000Z" + ORGANIZATION "Cisco Systems, Inc." + CONTACT-INFO "Cisco Systems + Customer Service + + Postal: 170 W Tasman Drive + San Jose, CA 95134 + USA + + Tel: +1 800 553-NETS + + E-mail: cs-eigrp@cisco.com" + DESCRIPTION + "Enhanced Interior Gateway Protocol (EIGRP) is a Cisco + proprietary distance vector routing protocol. It is based on + the Diffusing Update Algorithm (DUAL), which is a method of + finding loop-free paths through a network. Directly + connected routers running EIGRP form neighbor adjacencies in + order to propagate best-path and alternate-path routing + information for configured and learned routes. + + The tables defined within the MIB are closely aligned with how + the router command-line interface for EIGRP displays + information on EIGRP configurations, i.e., the topology table + contains objects associated with the EIGRP topology commands, + and the peer table contains objects associated withe EIGRP + neighbor commands, etc. + + There are five main tables within this mib: + + EIGRP VPN table + Contains information regarding which virtual private + networks (VPN) are configured with EIGRP. + + EIGRP traffic statistics table + Contains counter & statistcs regarding specific types of + EIGRP packets sent and related collective information + per VPN and per autonomous system (AS). + + EIGRP topology table + Contains information regarding EIGRP routes received in + updates and originated locally. EIGRP sends and + receives routing updates from adjacent routers running + EIGRP with which it formed a peer relationship. + + EIGRP peer (neighbor) table + Contains information about neighbor EIGRP routers with + which peer adjacencies have been established. EIGRP + uses a Hello protocol to form neighbor relationships + with directly connected routers also running EIGRP. + + EIGRP interfaces table + Contains information and statistics on each of the + interfaces on the router over which EIGRP has been + configured to run." + + + REVISION "200411160000Z" + DESCRIPTION + "Initial version of the MIB module." + ::= { ciscoMgmt 449 } + +-- +-- Textual Conventions +-- + + EigrpUpTimeString ::= TEXTUAL-CONVENTION + DISPLAY-HINT "8a" + STATUS current + DESCRIPTION + "Specifies a timer value in days, hours, minutes, + and seconds in ASCII format. + + If the up time is less than 24 hours, the number + of days will not be reflected and the string will + be formatted like this: 'hh:mm:ss', reflecting + hours, minutes, and seconds. + + If the up time is greater than 24 hours, EIGRP is + less precise and the minutes and seconds are not + reflected. Instead only the days and hours are shown + and the string will be formatted like this: 'xxxdxxh'." + SYNTAX OCTET STRING (SIZE (0..8)) + + EigrpVersionString ::= TEXTUAL-CONVENTION + DISPLAY-HINT "1d.1d/1d.1d" + STATUS current + DESCRIPTION + "Specifies an ASCII string representing the IOS major + and minor version followed by the EIGRP major and minor + version." + SYNTAX OCTET STRING (SIZE (0..9)) + +-- +-- Objects +-- + + cEigrpMIBNotifications OBJECT IDENTIFIER ::= { ciscoEigrpMIB 0 } + cEigrpMIBObjects OBJECT IDENTIFIER ::= { ciscoEigrpMIB 1 } + cEigrpMIBConformance OBJECT IDENTIFIER ::= { ciscoEigrpMIB 2 } + cEigrpVpnInfo OBJECT IDENTIFIER ::= { cEigrpMIBObjects 1 } + cEigrpAsInfo OBJECT IDENTIFIER ::= { cEigrpMIBObjects 2 } + cEigrpTopologyInfo OBJECT IDENTIFIER ::= { cEigrpMIBObjects 3 } + cEigrpPeerInfo OBJECT IDENTIFIER ::= { cEigrpMIBObjects 4 } + cEigrpInterfaceInfo OBJECT IDENTIFIER ::= { cEigrpMIBObjects 5 } + + -- EIGRP VPN Base Table definition + + cEigrpVpnTable OBJECT-TYPE + SYNTAX SEQUENCE OF CEigrpVpnEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "This table contains information on those VPN's configured + to run EIGRP. The VPN creation on a router is independent + of the routing protocol to be used over it. A VPN is + given a name and has a dedicated routing table associated + with it. This routing table is identified internally + by a unique integer value." + ::= { cEigrpVpnInfo 1 } + + cEigrpVpnEntry OBJECT-TYPE + SYNTAX CEigrpVpnEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information relating to a single VPN which is configured + to run EIGRP." + INDEX { cEigrpVpnId } + ::= { cEigrpVpnTable 1 } + + CEigrpVpnEntry ::= + SEQUENCE { + cEigrpVpnId Unsigned32, + cEigrpVpnName SnmpAdminString + } + + cEigrpVpnId OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The unique VPN identifier. This is a unique integer + relative to all other VPN's defined on the router. It + also identifies internally the routing table instance." + ::= { cEigrpVpnEntry 1 } + + cEigrpVpnName OBJECT-TYPE + SYNTAX SnmpAdminString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name given to the VPN." + ::= { cEigrpVpnEntry 2 } + + -- EIGRP Traffic Stats table definition + + cEigrpTraffStatsTable OBJECT-TYPE + SYNTAX SEQUENCE OF CEigrpTraffStatsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table of EIGRP traffic statistics and information + associated with all EIGRP autonomous systems." + ::= { cEigrpAsInfo 1 } + + cEigrpTraffStatsEntry OBJECT-TYPE + SYNTAX CEigrpTraffStatsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The set of statistics and information for a single EIGRP + Autonomous System." + INDEX { cEigrpVpnId, cEigrpAsNumber } + ::= { cEigrpTraffStatsTable 1 } + + CEigrpTraffStatsEntry ::= + SEQUENCE { + cEigrpAsNumber Unsigned32, + cEigrpNbrCount Unsigned32, + cEigrpHellosSent Counter32, + cEigrpHellosRcvd Counter32, + cEigrpUpdatesSent Counter32, + cEigrpUpdatesRcvd Counter32, + cEigrpQueriesSent Counter32, + cEigrpQueriesRcvd Counter32, + cEigrpRepliesSent Counter32, + cEigrpRepliesRcvd Counter32, + cEigrpAcksSent Counter32, + cEigrpAcksRcvd Counter32, + cEigrpInputQHighMark Unsigned32, + cEigrpInputQDrops Counter32, + cEigrpSiaQueriesSent Counter32, + cEigrpSiaQueriesRcvd Counter32, + cEigrpAsRouterIdType InetAddressType, + cEigrpAsRouterId InetAddress, + cEigrpTopoRoutes Counter32, + cEigrpHeadSerial Counter64, + cEigrpNextSerial Counter64, + cEigrpXmitPendReplies Unsigned32, + cEigrpXmitDummies Unsigned32 + } + + cEigrpAsNumber OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Autonomous System number which is unique integer + per VPN." + ::= { cEigrpTraffStatsEntry 1 } + + cEigrpNbrCount OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of live EIGRP neighbors formed on all + interfaces whose IP addresses fall under networks configured + in the EIGRP AS." + ::= { cEigrpTraffStatsEntry 2 } + + cEigrpHellosSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number Hello packets that have been sent to all + EIGRP neighbors formed on all interfaces whose IP addresses + fall under networks configured for the EIGRP AS." + ::= { cEigrpTraffStatsEntry 3 } + + cEigrpHellosRcvd OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number Hello packets that have been received + from all EIGRP neighbors formed on all interfaces whose IP + addresses fall under networks configured for the + EIGRP AS." + ::= { cEigrpTraffStatsEntry 4 } + + cEigrpUpdatesSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number routing update packets that have been + sent to all EIGRP neighbors formed on all interfaces whose + IP addresses fall under networks configured for the + EIGRP AS." + ::= { cEigrpTraffStatsEntry 5 } + + cEigrpUpdatesRcvd OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number routing update packets that have been + received from all EIGRP neighbors formed on all interfaces + whose IP addresses fall under networks configured for the + EIGRP AS." + ::= { cEigrpTraffStatsEntry 6 } + + cEigrpQueriesSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number alternate route query packets that have + been sent to all EIGRP neighbors formed on all interfaces + whose IP addresses fall under networks configured for the + EIGRP AS." + ::= { cEigrpTraffStatsEntry 7 } + + cEigrpQueriesRcvd OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number alternate route query packets that + have been received from all EIGRP neighbors formed on + all interfaces whose IP addresses fall under networks + configured for the EIGRP AS." + ::= { cEigrpTraffStatsEntry 8 } + + cEigrpRepliesSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number query reply packets that have been sent + to all EIGRP neighbors formed on all interfaces whose IP + addresses fall under networks configured for the + EIGRP AS." + ::= { cEigrpTraffStatsEntry 9 } + + cEigrpRepliesRcvd OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number query reply packets that have been + received from all EIGRP neighbors formed on all interfaces + whose IP addresses fall under networks configured for the + EIGRP AS." + ::= { cEigrpTraffStatsEntry 10 } + + cEigrpAcksSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number packet acknowledgements that have been + sent to all EIGRP neighbors formed on all interfaces whose + IP addresses fall under networks configured for the + EIGRP AS." + ::= { cEigrpTraffStatsEntry 11 } + + cEigrpAcksRcvd OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number packet acknowledgements that have been + received from all EIGRP neighbors formed on all interfaces + whose IP addresses fall under networks configured for the + EIGRP AS." + ::= { cEigrpTraffStatsEntry 12 } + + cEigrpInputQHighMark OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The highest number of EIGRP packets in the input queue + waiting to be processed internally addressed to this + AS." + ::= { cEigrpTraffStatsEntry 13 } + + cEigrpInputQDrops OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of EIGRP packets dropped from the input + queue due to it being full within the AS." + ::= { cEigrpTraffStatsEntry 14 } + + cEigrpSiaQueriesSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Stuck-In-Active (SIA) query packets + sent to all EIGRP neighbors formed on all interfaces whose + IP addresses fall under networks configured for the + EIGRP AS." + ::= { cEigrpTraffStatsEntry 15 } + + cEigrpSiaQueriesRcvd OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Stuck-In-Active (SIA) query packets + received from all EIGRP neighbors formed on all interfaces + whose IP addresses fall under networks configured for the + EIGRP AS." + ::= { cEigrpTraffStatsEntry 16 } + + cEigrpAsRouterIdType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The format of the router-id configured or automatically + selected for the EIGRP AS." + ::= { cEigrpTraffStatsEntry 17 } + + cEigrpAsRouterId OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The router-id configured or automatically selected for the + EIGRP AS. Each EIGRP routing process has a unique + router-id selected from each autonomous system configured. + The format is governed by object cEigrpAsRouterIdType." + ::= { cEigrpTraffStatsEntry 18 } + + cEigrpTopoRoutes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of EIGRP derived routes currently existing + in the topology table for the AS." + ::= { cEigrpTraffStatsEntry 19 } + + cEigrpHeadSerial OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Routes in a topology table for an AS are assigned serial + numbers and are sequenced internally as they are inserted + and deleted. The serial number of the first route in + that internal sequence is called the head serial number. + Each AS has its own topology table, and its own serial + number space, each of which begins with the value 1. + A serial number of zero implies that there are no routes + in the topology." + ::= { cEigrpTraffStatsEntry 20 } + + cEigrpNextSerial OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The serial number that would be assigned to the next new + or changed route in the topology table for the AS." + ::= { cEigrpTraffStatsEntry 21 } + + cEigrpXmitPendReplies OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "When alternate route query packets are sent to adjacent + EIGRP peers in an AS, replies are expected. This object + is the total number of outstanding replies expected to + queries that have been sent to peers in the current AS. + It remains at zero most of the time until an EIGRP route + becomes active." + ::= { cEigrpTraffStatsEntry 22 } + + cEigrpXmitDummies OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A dummy is a temporary internal entity used as a place + holder in the topology table for an AS. They are not + transmitted in routing updates. This is the total + number currently in existence associated with the AS." + ::= { cEigrpTraffStatsEntry 23 } + + -- EIGRP topology table definition + + cEigrpTopoTable OBJECT-TYPE + SYNTAX SEQUENCE OF CEigrpTopoEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table of EIGRP routes and their associated + attributes for an Autonomous System (AS) configured + in a VPN is called a topology table. All route entries in + the topology table will be indexed by IP network type, + IP network number and network mask (prefix) size." + ::= { cEigrpTopologyInfo 1 } + + cEigrpTopoEntry OBJECT-TYPE + SYNTAX CEigrpTopoEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The entry for a single EIGRP topology table in the given + AS." + INDEX { cEigrpVpnId, cEigrpAsNumber, cEigrpDestNetType, + cEigrpDestNet, cEigrpDestNetPrefixLen } + ::= { cEigrpTopoTable 1 } + + CEigrpTopoEntry ::= + SEQUENCE { + cEigrpDestNetType InetAddressType, + cEigrpDestNet InetAddress, + cEigrpDestNetPrefixLen InetAddressPrefixLength, + cEigrpActive TruthValue, + cEigrpStuckInActive TruthValue, + cEigrpDestSuccessors Unsigned32, + cEigrpFdistance Unsigned32, + cEigrpRouteOriginType SnmpAdminString, + cEigrpRouteOriginAddrType InetAddressType, + cEigrpRouteOriginAddr InetAddress, + cEigrpNextHopAddressType InetAddressType, + cEigrpNextHopAddress InetAddress, + cEigrpNextHopInterface SnmpAdminString, + cEigrpDistance Unsigned32, + cEigrpReportDistance Unsigned32 + } + + cEigrpDestNetType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The format of the destination IP network number for + a single route in the topology table in the AS specified + in cEigrpDestNet." + ::= { cEigrpTopoEntry 1 } + + cEigrpDestNet OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The destination IP network number for a single route in + the topology table in the AS. The format is governed + by object cEigrpDestNetType." + ::= { cEigrpTopoEntry 2 } + + cEigrpDestNetPrefixLen OBJECT-TYPE + SYNTAX InetAddressPrefixLength + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The prefix length associated with the destination IP + network address for a single route in the topology + table in the AS. The format is governed by the object + cEigrpDestNetType." + ::= { cEigrpTopoEntry 4 } + + cEigrpActive OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A value of true(1) indicates the route to the + destination network has failed and an active (query) + search for an alternative path is in progress. A value + of false(2) indicates the route is stable (passive)." + ::= { cEigrpTopoEntry 5 } + + cEigrpStuckInActive OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A value of true(1) indicates that that this route which is + in active state (cEigrpActive = true(1)) has not received + any replies to queries for alternate paths, and a second + EIGRP route query, called a stuck-in-active query, has + now been sent." + ::= { cEigrpTopoEntry 6 } + + cEigrpDestSuccessors OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A successor is the next routing hop for a path to the + destination IP network number for a single route in the + topology table in the AS. There can be several + potential successors if there are multiple paths to the + destination. This is the total number of successors for + a topology entry." + ::= { cEigrpTopoEntry 7 } + + cEigrpFdistance OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The feasibility (best) distance is the minimum distance + from this router to the destination IP network in + this topology entry. The feasibility distance is + used in determining the best successor for a path to the + destination network." + ::= { cEigrpTopoEntry 8 } + + cEigrpRouteOriginType OBJECT-TYPE + SYNTAX SnmpAdminString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This is a text string describing the internal origin + of the EIGRP route represented by the topology entry." + ::= { cEigrpTopoEntry 9 } + + cEigrpRouteOriginAddrType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The format of the IP address defined as the origin of + this topology route entry." + ::= { cEigrpTopoEntry 10 } + + cEigrpRouteOriginAddr OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "If the origin of the topology route entry is external + to this router, then this object is the IP address + of the router from which it originated. The format + is governed by object cEigrpRouteOriginAddrType." + ::= { cEigrpTopoEntry 11 } + + cEigrpNextHopAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The format of the next hop IP address for the route + represented by the topology entry." + ::= { cEigrpTopoEntry 12 } + + cEigrpNextHopAddress OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This is the next hop IP address for the route represented + by the topology entry. The next hop is where + network traffic will be routed to in order to reach + the destination network for this topology entry. The + format is governed by cEigrpNextHopAddressType." + ::= { cEigrpTopoEntry 13 } + + cEigrpNextHopInterface OBJECT-TYPE + SYNTAX SnmpAdminString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The interface through which the next hop IP address + is reached to send network traffic to the destination + network represented by the topology entry." + ::= { cEigrpTopoEntry 14 } + + cEigrpDistance OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The computed distance to the destination network entry + from this router." + ::= { cEigrpTopoEntry 15 } + + cEigrpReportDistance OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The computed distance to the destination network in the + topology entry reported to this router by the originator + of this route." + ::= { cEigrpTopoEntry 16 } + + -- EIGRP Peer table per VPN and AS (expansion table) + + cEigrpPeerTable OBJECT-TYPE + SYNTAX SEQUENCE OF CEigrpPeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table of established EIGRP peers (neighbors) in the + selected autonomous system. Peers are indexed by their + unique internal handle id, as well as the AS number and + VPN id. The peer entry is removed from the table if + the peer is declared down." + ::= { cEigrpPeerInfo 1 } + + cEigrpPeerEntry OBJECT-TYPE + SYNTAX CEigrpPeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Statistics and operational parameters for a single peer + in the AS." + INDEX { cEigrpVpnId, cEigrpAsNumber, cEigrpHandle } + ::= { cEigrpPeerTable 1 } + + CEigrpPeerEntry ::= + SEQUENCE { + cEigrpHandle Unsigned32, + cEigrpPeerAddrType InetAddressType, + cEigrpPeerAddr InetAddress, + cEigrpPeerIfIndex InterfaceIndexOrZero, + cEigrpHoldTime Unsigned32, + cEigrpUpTime EigrpUpTimeString, + cEigrpSrtt Unsigned32, + cEigrpRto Unsigned32, + cEigrpPktsEnqueued Unsigned32, + cEigrpLastSeq Unsigned32, + cEigrpVersion EigrpVersionString, + cEigrpRetrans Counter32, + cEigrpRetries Unsigned32 + } + + cEigrpHandle OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The unique internal identifier for the peer in the AS. + This is a unique value among peer entries in a selected + table." + ::= { cEigrpPeerEntry 1 } + + cEigrpPeerAddrType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The format of the remote source IP address used by the + peer to establish the EIGRP adjacency with this router." + ::= { cEigrpPeerEntry 2 } + + cEigrpPeerAddr OBJECT-TYPE + SYNTAX InetAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The source IP address used by the peer to establish the + EIGRP adjacency with this router. The format is + governed by object cEigrpPeerAddrType." + ::= { cEigrpPeerEntry 3 } + + cEigrpPeerIfIndex OBJECT-TYPE + SYNTAX InterfaceIndexOrZero + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The ifIndex of the interface on this router through + which this peer can be reached." + ::= { cEigrpPeerEntry 4 } + + cEigrpHoldTime OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The count-down timer indicating how much time must + pass without receiving a hello packet from this + EIGRP peer before this router declares the peer down. + A peer declared as down is removed from the table and + is no longer visible." + ::= { cEigrpPeerEntry 5 } + + cEigrpUpTime OBJECT-TYPE + SYNTAX EigrpUpTimeString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The elapsed time since the EIGRP adjacency was first + established with the peer." + ::= { cEigrpPeerEntry 6 } + + cEigrpSrtt OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The computed smooth round trip time for packets to and + from the peer." + ::= { cEigrpPeerEntry 7 } + + cEigrpRto OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The computed retransmission timeout for the peer. + This value is computed over time as packets are sent to + the peer and acknowledgements are received from it, + and is the amount of time to wait before resending + a packet from the retransmission queue to the peer + when an expected acknowledgement has not been received." + ::= { cEigrpPeerEntry 8 } + + cEigrpPktsEnqueued OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of any EIGRP packets currently enqueued + waiting to be sent to this peer." + ::= { cEigrpPeerEntry 9 } + + cEigrpLastSeq OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "All transmitted EIGRP packets have a sequence number + assigned. This is the sequence number of the last EIGRP + packet sent to this peer." + ::= { cEigrpPeerEntry 10 } + + cEigrpVersion OBJECT-TYPE + SYNTAX EigrpVersionString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The EIGRP version information reported by the remote + peer." + ::= { cEigrpPeerEntry 11 } + + cEigrpRetrans OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The cumulative number of retransmissions to this peer + during the period that the peer adjacency has remained + up." + ::= { cEigrpPeerEntry 12 } + + cEigrpRetries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times the current unacknowledged packet + has been retried, i.e. resent to this peer to be + acknowledged." + ::= { cEigrpPeerEntry 13 } + + -- EIGRP Interfaces table per VPN and AS + + cEigrpInterfaceTable OBJECT-TYPE + SYNTAX SEQUENCE OF CEigrpInterfaceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table of interfaces over which EIGRP is running, and + their associated statistics. This table is independent + of whether any peer adjacencies have been formed over + the interfaces or not. Interfaces running EIGRP are + determined by whether their assigned IP addresses fall + within configured EIGRP network statements." + ::= { cEigrpInterfaceInfo 1 } + + cEigrpInterfaceEntry OBJECT-TYPE + SYNTAX CEigrpInterfaceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information for a single interface running EIGRP in the + AS and VPN." + INDEX { cEigrpVpnId, cEigrpAsNumber, ifIndex } + ::= { cEigrpInterfaceTable 1 } + + CEigrpInterfaceEntry ::= + SEQUENCE { + cEigrpPeerCount Gauge32, + cEigrpXmitReliableQ Gauge32, + cEigrpXmitUnreliableQ Gauge32, + cEigrpMeanSrtt Unsigned32, + cEigrpPacingReliable Unsigned32, + cEigrpPacingUnreliable Unsigned32, + cEigrpMFlowTimer Unsigned32, + cEigrpPendingRoutes Gauge32, + cEigrpHelloInterval Unsigned32, + cEigrpXmitNextSerial Counter64, + cEigrpUMcasts Counter32, + cEigrpRMcasts Counter32, + cEigrpUUcasts Counter32, + cEigrpRUcasts Counter32, + cEigrpMcastExcepts Counter32, + cEigrpCRpkts Counter32, + cEigrpAcksSuppressed Counter32, + cEigrpRetransSent Counter32, + cEigrpOOSrcvd Counter32, + cEigrpAuthMode INTEGER, + cEigrpAuthKeyChain SnmpAdminString + } + + cEigrpPeerCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of EIGRP adjacencies currently formed with + peers reached through this interface." + ::= { cEigrpInterfaceEntry 3 } + + cEigrpXmitReliableQ OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of EIGRP packets currently waiting in the + reliable transport (acknowledgement-required) + transmission queue to be sent to a peer." + ::= { cEigrpInterfaceEntry 4 } + + cEigrpXmitUnreliableQ OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number EIGRP of packets currently waiting in + the unreliable transport (no acknowledgement required) + transmission queue." + ::= { cEigrpInterfaceEntry 5 } + + cEigrpMeanSrtt OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The average of all the computed smooth round trip time + values for a packet to and from all peers established on + this interface." + ::= { cEigrpInterfaceEntry 6 } + + cEigrpPacingReliable OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The configured time interval between EIGRP packet + transmissions on the interface when the reliable transport + method is used." + ::= { cEigrpInterfaceEntry 7 } + + cEigrpPacingUnreliable OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The configured time interval between EIGRP packet + transmissions on the interface when the unreliable + transport method is used." + ::= { cEigrpInterfaceEntry 8 } + + cEigrpMFlowTimer OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The configured multicast flow control timer value for + this interface." + ::= { cEigrpInterfaceEntry 9 } + + cEigrpPendingRoutes OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of queued EIGRP routing updates awaiting + transmission on this interface." + ::= { cEigrpInterfaceEntry 10 } + + cEigrpHelloInterval OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The configured time interval between Hello packet + transmissions for this interface." + ::= { cEigrpInterfaceEntry 11 } + + cEigrpXmitNextSerial OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The serial number of the next EIGRP packet that is to + be queued for transmission on this interface." + ::= { cEigrpInterfaceEntry 12 } + + cEigrpUMcasts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of unreliable (no acknowledgement + required) EIGRP multicast packets sent on this + interface." + ::= { cEigrpInterfaceEntry 13 } + + cEigrpRMcasts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of reliable (acknowledgement required) + EIGRP multicast packets sent on this interface." + ::= { cEigrpInterfaceEntry 14 } + + cEigrpUUcasts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of unreliable (no acknowledgement + required) EIGRP unicast packets sent on this + interface." + ::= { cEigrpInterfaceEntry 15 } + + cEigrpRUcasts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of reliable (acknowledgement required) + unicast packets sent on this interface." + ::= { cEigrpInterfaceEntry 16 } + + cEigrpMcastExcepts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of EIGRP multicast exception + transmissions that have occurred on this interface." + ::= { cEigrpInterfaceEntry 17 } + + cEigrpCRpkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number EIGRP Conditional-Receive packets sent on + this interface." + ::= { cEigrpInterfaceEntry 18 } + + cEigrpAcksSuppressed OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of individual EIGRP acknowledgement + packets that have been suppressed and combined in + an already enqueued outbound reliable packet on this + interface." + ::= { cEigrpInterfaceEntry 19 } + + cEigrpRetransSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number EIGRP packet retransmissions sent on + the interface." + ::= { cEigrpInterfaceEntry 20 } + + cEigrpOOSrcvd OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of out-of-sequence EIGRP packets + received." + ::= { cEigrpInterfaceEntry 21 } + + cEigrpAuthMode OBJECT-TYPE + SYNTAX INTEGER { + none(1), + md5(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The EIGRP authentication mode of the interface. + none : no authentication enabled on the interface + md5 : MD5 authentication enabled on the interface" + ::= { cEigrpInterfaceEntry 22 } + + cEigrpAuthKeyChain OBJECT-TYPE + SYNTAX SnmpAdminString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the authentication key-chain configured + on this interface. The key-chain is a reference to + which set of secret keys are to be accessed in order + to determine which secret key string to use. The key + chain name is not the secret key string password and + can also be used in other routing protocols, such + as RIP and ISIS." + ::= { cEigrpInterfaceEntry 23 } + + -- Notifications + + cEigrpAuthFailureEvent NOTIFICATION-TYPE + OBJECTS { cEigrpPeerAddrType, cEigrpPeerAddr } + STATUS current + DESCRIPTION + "This notification is sent when EIGRP MD5 authentication + is enabled on any interface and peer adjacencies are + formed, and any adjacencies go down as a result of an + authentication failure." + ::= { cEigrpMIBNotifications 1 } + + cEigrpRouteStuckInActive NOTIFICATION-TYPE + OBJECTS { cEigrpPeerAddrType, cEigrpPeerAddr, + cEigrpStuckInActive } + STATUS current + DESCRIPTION + "This notification is sent when a route in the topology + table is stuck in an active state. During the query + phase for a new route to a destination network, a route + is described as being in the active state if when an + alternate path is actively being sought, no replies are + received to normal queries or stuck-in-active queries." + ::= { cEigrpMIBNotifications 2 } + + -- Conformance + + cEigrpMIBCompliances + OBJECT IDENTIFIER ::= { cEigrpMIBConformance 1 } + + cEigrpMIBGroups + OBJECT IDENTIFIER ::= { cEigrpMIBConformance 2 } + + -- Compliance + + cEigrpMIBCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for entities which implement + the Cisco EIGRP Management MIB." + MODULE + MANDATORY-GROUPS { + cEigrpVpnDataGroup, + cEigrpTrafficStatsGroup, + cEigrpInterfaceDataGroup, + cEigrpPeerDataGroup, + cEigrpTopoDataGroup, + cEigrpNotificationsGroup + } + + OBJECT cEigrpAsRouterIdType + SYNTAX INTEGER { ipv4(1) } + DESCRIPTION + "An implementation is only required to support + IPv4 address type." + + OBJECT cEigrpRouteOriginAddrType + SYNTAX INTEGER { ipv4(1) } + DESCRIPTION + "An implementation is only required to support + IPv4 address type." + + OBJECT cEigrpNextHopAddressType + SYNTAX INTEGER { ipv4(1) } + DESCRIPTION + "An implementation is only required to support + IPv4 address type." + + OBJECT cEigrpPeerAddrType + SYNTAX INTEGER { ipv4(1) } + DESCRIPTION + "An implementation is only required to support + IPv4 address type." + ::= { cEigrpMIBCompliances 1 } + + -- Units of Conformance + + cEigrpVpnDataGroup OBJECT-GROUP + OBJECTS { + cEigrpVpnName + } + STATUS current + DESCRIPTION + "The collection of VPN names which have been configured + with one or more EIGRP autonmous systems." + ::= { cEigrpMIBGroups 1 } + + cEigrpTrafficStatsGroup OBJECT-GROUP + OBJECTS { + cEigrpHellosSent, + cEigrpHellosRcvd, + cEigrpUpdatesSent, + cEigrpUpdatesRcvd, + cEigrpQueriesSent, + cEigrpQueriesRcvd, + cEigrpRepliesSent, + cEigrpRepliesRcvd, + cEigrpAcksSent, + cEigrpAcksRcvd, + cEigrpInputQHighMark, + cEigrpInputQDrops, + cEigrpSiaQueriesSent, + cEigrpSiaQueriesRcvd + } + STATUS current + DESCRIPTION + "A collection of objects providing management information + regarding collective EIGRP packet statistics for all EIGRP + autonomous systems configured." + ::= { cEigrpMIBGroups 2 } + + cEigrpInterfaceDataGroup OBJECT-GROUP + OBJECTS { + cEigrpPeerCount, + cEigrpXmitReliableQ, + cEigrpXmitUnreliableQ, + cEigrpMeanSrtt, + cEigrpPacingReliable, + cEigrpPacingUnreliable, + cEigrpMFlowTimer, + cEigrpPendingRoutes, + cEigrpHelloInterval, + cEigrpXmitNextSerial, + cEigrpUMcasts, + cEigrpRMcasts, + cEigrpUUcasts, + cEigrpRUcasts, + cEigrpMcastExcepts, + cEigrpCRpkts, + cEigrpAcksSuppressed, + cEigrpRetransSent, + cEigrpOOSrcvd, + cEigrpAuthMode, + cEigrpAuthKeyChain + } + STATUS current + DESCRIPTION + "A collection of objects providing management information + for interfaces over which EIGRP is configured and + running." + ::= { cEigrpMIBGroups 3 } + + cEigrpPeerDataGroup OBJECT-GROUP + OBJECTS { + cEigrpNbrCount, + cEigrpPeerAddrType, + cEigrpPeerAddr, + cEigrpPeerIfIndex, + cEigrpHoldTime, + cEigrpUpTime, + cEigrpSrtt, + cEigrpRto, + cEigrpPktsEnqueued, + cEigrpLastSeq, + cEigrpVersion, + cEigrpRetrans, + cEigrpRetries + } + STATUS current + DESCRIPTION + "A collection of objects providing management information + for EIGRP peer adjacencies formed in the EIGRP + autonoumous systems." + ::= { cEigrpMIBGroups 4 } + + cEigrpTopoDataGroup OBJECT-GROUP + OBJECTS { + cEigrpAsRouterId, + cEigrpAsRouterIdType, + cEigrpTopoRoutes, + cEigrpHeadSerial, + cEigrpNextSerial, + cEigrpXmitPendReplies, + cEigrpXmitDummies, + cEigrpActive, + cEigrpStuckInActive, + cEigrpDestSuccessors, + cEigrpFdistance, + cEigrpRouteOriginType, + cEigrpRouteOriginAddrType, + cEigrpRouteOriginAddr, + cEigrpNextHopAddressType, + cEigrpNextHopAddress, + cEigrpNextHopInterface, + cEigrpDistance, + cEigrpReportDistance + } + STATUS current + DESCRIPTION + "A collection of objects providing management information + for EIGRP topology routes derived within autonomous + systems and received in updates from EIGRP neighbors." + ::= { cEigrpMIBGroups 5 } + + cEigrpNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + cEigrpAuthFailureEvent, + cEigrpRouteStuckInActive + } + STATUS current + DESCRIPTION + "Group of notifications on EIGRP routers." + ::= { cEigrpMIBGroups 6 } +END
\ No newline at end of file diff --git a/eigrpd/Makefile.am b/eigrpd/Makefile.am new file mode 100644 index 000000000..89cb72cfd --- /dev/null +++ b/eigrpd/Makefile.am @@ -0,0 +1,45 @@ +## Process this file with automake to produce Makefile.in. + +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +AM_CFLAGS = $(WERROR) + +noinst_LIBRARIES = libeigrp.a +sbin_PROGRAMS = eigrpd + +libeigrp_a_SOURCES = \ + eigrpd.c eigrp_zebra.c \ + eigrp_interface.c eigrp_neighbor.c \ + eigrp_dump.c eigrp_vty.c \ + eigrp_network.c eigrp_packet.c \ + eigrp_topology.c eigrp_fsm.c \ + eigrp_hello.c eigrp_update.c \ + eigrp_query.c eigrp_reply.c \ + eigrp_snmp.c eigrp_siaquery.c \ + eigrp_siareply.c eigrp_filter.c \ + eigrp_memory.c + + +eigrpdheaderdir = $(pkgincludedir)/eigrpd + +eigrpdheader_HEADERS = \ + eigrp_topology.h eigrp_dump.h eigrpd.h + +noinst_HEADERS = \ + eigrp_const.h eigrp_structs.h \ + eigrp_macros.h eigrp_interface.h \ + eigrp_neighbor.h eigrp_network.h \ + eigrp_packet.h eigrp_memory.h \ + eigrp_zebra.h eigrp_vty.h \ + eigrp_snmp.h eigrp_filter.h + +eigrpd_SOURCES = eigrp_main.c $(libeigrp_a_SOURCES) + +eigrpd_LDADD = ../lib/libfrr.la @LIBCAP@ + +EXTRA_DIST = EIGRP-MIB.txt + +examplesdir = $(exampledir) +dist_examples_DATA = eigrpd.conf.sample diff --git a/eigrpd/eigrp_const.h b/eigrpd/eigrp_const.h new file mode 100644 index 000000000..a1d09e684 --- /dev/null +++ b/eigrpd/eigrp_const.h @@ -0,0 +1,439 @@ +/* + * EIGRP Definition of Constants. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * 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. + */ + +#ifndef _ZEBRA_EIGRP_CONST_H_ +#define _ZEBRA_EIGRP_CONST_H_ + +#define FALSE 0 + +#define EIGRP_NEIGHBOR_DOWN 0 +#define EIGRP_NEIGHBOR_PENDING 1 +#define EIGRP_NEIGHBOR_UP 2 +#define EIGRP_NEIGHBOR_STATE_MAX 3 + +/*Packet requiring ack will be retransmitted again after this time*/ +#define EIGRP_PACKET_RETRANS_TIME 2 /* in seconds */ +#define EIGRP_PACKET_RETRANS_MAX 16 /* number of retrans attempts */ +#define PLAINTEXT_LENGTH 81 + +/*Metric variance multiplier*/ +#define EIGRP_VARIANCE_DEFAULT 1 +#define EIGRP_MAX_PATHS_DEFAULT 4 + + +/* Return values of functions involved in packet verification */ +#define MSG_OK 0 +#define MSG_NG 1 + +#define EIGRP_HEADER_VERSION 2 + +/* Default protocol, port number. */ +#ifndef IPPROTO_EIGRPIGP +#define IPPROTO_EIGRPIGP 88 +#endif /* IPPROTO_EIGRPIGP */ + +#define EIGRP_AUTH_MD5_TLV_SIZE 40 +#define EIGRP_AUTH_SHA256_TLV_SIZE 56 + +/*Cisco routers use only first 44 bytes of basic hello for their MD5 calculations*/ +#define EIGRP_MD5_BASIC_COMPUTE 44 +#define EIGRP_MD5_UPDATE_INIT_COMPUTE 40 + + + +#define EIGRP_AUTH_BASIC_HELLO_FLAG 0x01 +#define EIGRP_AUTH_TID_HELLO_FLAG 0x02 +#define EIGRP_AUTH_UPDATE_INIT_FLAG 0x04 +#define EIGRP_AUTH_UPDATE_FLAG 0x08 +#define EIGRP_AUTH_EXTRA_SALT_FLAG 0x10 + +#define EIGRP_NEXT_SEQUENCE_TLV_SIZE 8 + +/* IP TTL for EIGRP protocol. */ +#define EIGRP_IP_TTL 1 + +/* VTY port number. */ +#define EIGRP_VTY_PORT 2609 + +/* Default configuration file name for eigrp. */ +#define EIGRP_DEFAULT_CONFIG "eigrpd.conf" + +#define EIGRP_HELLO_INTERVAL_DEFAULT 5 +#define EIGRP_HOLD_INTERVAL_DEFAULT 15 +#define EIGRP_BANDWIDTH_DEFAULT 10000000 +#define EIGRP_DELAY_DEFAULT 1000 +#define EIGRP_RELIABILITY_DEFAULT 255 +#define EIGRP_LOAD_DEFAULT 1 + +#define EIGRP_MULTICAST_ADDRESS 0xe000000A /*224.0.0.10*/ + +#define EIGRP_MAX_METRIC 0xffffffffU /*4294967295*/ + +#define DEFAULT_ROUTE ZEBRA_ROUTE_MAX +#define DEFAULT_ROUTE_TYPE(T) ((T) == DEFAULT_ROUTE) + +#define INTERFACE_DOWN_BY_ZEBRA 1 +#define INTERFACE_DOWN_BY_VTY 2 + +#define EIGRP_HELLO_NORMAL 0x00 +#define EIGRP_HELLO_GRACEFUL_SHUTDOWN 0x01 +#define EIGRP_HELLO_ADD_SEQUENCE 0x02 +#define EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR 0x04 + + /* EIGRP Network Type. */ + #define EIGRP_IFTYPE_NONE 0 + #define EIGRP_IFTYPE_POINTOPOINT 1 + #define EIGRP_IFTYPE_BROADCAST 2 + #define EIGRP_IFTYPE_NBMA 3 + #define EIGRP_IFTYPE_POINTOMULTIPOINT 4 + #define EIGRP_IFTYPE_LOOPBACK 5 + #define EIGRP_IFTYPE_MAX 6 + +#define EIGRP_IF_ACTIVE 0 +#define EIGRP_IF_PASSIVE 1 + +/* EIGRP TT destination type */ +#define EIGRP_TOPOLOGY_TYPE_CONNECTED 0 // Connected network +#define EIGRP_TOPOLOGY_TYPE_REMOTE 1 // Remote internal network +#define EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL 2 // Remote external network + +/*EIGRP TT entry flags*/ +#define EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG 1 +#define EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG 2 +#define EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG 4 +#define EIGRP_NEIGHBOR_ENTRY_EXTERNAL_FLAG 8 + +/*EIGRP FSM state count, event count*/ +#define EIGRP_FSM_STATE_MAX 5 +#define EIGRP_FSM_EVENT_MAX 16 + +/*EGRP FSM states*/ +#define EIGRP_FSM_STATE_PASSIVE 0 +#define EIGRP_FSM_STATE_ACTIVE_0 1 +#define EIGRP_FSM_STATE_ACTIVE_1 2 +#define EIGRP_FSM_STATE_ACTIVE_2 3 +#define EIGRP_FSM_STATE_ACTIVE_3 4 + +/*EIGRP FSM events return values*/ +#define EIGRP_FSM_NEED_UPDATE 1 +#define EIGRP_FSM_NEED_QUERY 2 + +/*EIGRP FSM events*/ +#define EIGRP_FSM_EVENT_NQ_FCN 0 /*input event other than query from succ, FC not satisfied*/ +#define EIGRP_FSM_EVENT_LR 1 /*last reply, FD is reset*/ +#define EIGRP_FSM_EVENT_Q_FCN 2 /*query from succ, FC not satisfied*/ +#define EIGRP_FSM_EVENT_LR_FCS 3 /*last reply, FC satisfied with current value of FDij*/ +#define EIGRP_FSM_EVENT_DINC 4 /*distance increase while in active state*/ +#define EIGRP_FSM_EVENT_QACT 5 /*query from succ while in active state*/ +#define EIGRP_FSM_EVENT_LR_FCN 6 /*last reply, FC not satisfied with current value of FDij*/ +#define EIGRP_FSM_KEEP_STATE 7 /*state not changed, usually by receiving not last reply */ + +#define INT_TYPES_CMD_STR \ + "detail|fastethernet|loopback|static" + +#define INT_TYPES_DESC \ + "Virtual Ethernet interface\n" \ + "FastEthernet IEEE 802.3\n" \ + "Loopback interface\n" \ + "Show static peer information\n" + +/** + * External routes originate from some other protocol - these are them + */ +#define NULL_PROTID 0 /*!< unknown protocol */ +#define IGRP_PROTID 1 /*!< IGRP.. whos your daddy! */ +#define EIGRP_PROTID 2 /*!< EIGRP - Just flat out the best */ +#define STATIC_PROTID 3 /*!< Staticly configured source */ +#define RIP_PROTID 4 /*!< Routing Information Protocol */ +#define HELLO_PROTID 5 /*!< Hello? RFC-891 you there? */ +#define OSPF_PROTID 6 /*!< OSPF - Open Shortest Path First */ +#define ISIS_PROTID 7 /*!< Intermediate System To Intermediate System */ +#define EGP_PROTID 8 /*!< Exterior Gateway Protocol */ +#define BGP_PROTID 9 /*!< Border Gateway Protocol */ +#define IDRP_PROTID 10 /*!< InterDomain Routing Protocol */ +#define CONN_PROTID 11 /*!< Connected source */ + +/* + * metric k-value defaults + */ +#define EIGRP_K1_DEFAULT 1 //!< unweighed inverse bandwidth +#define EIGRP_K2_DEFAULT 0 //!< no loading term +#define EIGRP_K3_DEFAULT 1 //!< unweighted delay +#define EIGRP_K4_DEFAULT 0 //!< no reliability term +#define EIGRP_K5_DEFAULT 0 //!< no reliability term +#define EIGRP_K6_DEFAULT 0 //!< do not add in extended metrics + + +/* + * EIGRP Fixed header + */ +#define EIGRP_HEADER_LEN 20U +#define EIGRP_PACKET_MAX_LEN 65535U /* includes IP Header size. */ + + +#define EIGRP_TLV_HDR_LENGTH 4 + +/** + * EIGRP Packet Opcodes + */ +#define EIGRP_OPC_UPDATE 1 /*!< packet containing routing information */ +#define EIGRP_OPC_REQUEST 2 /*!< sent to request one or more routes */ +#define EIGRP_OPC_QUERY 3 /*!< sent when a routing is in active start */ +#define EIGRP_OPC_REPLY 4 /*!< sent in response to a query */ +#define EIGRP_OPC_HELLO 5 /*!< sent to maintain a peering session */ +#define EIGRP_OPC_IPXSAP 6 /*!< IPX SAP information */ +#define EIGRP_OPC_PROBE 7 /*!< for test purposes */ +#define EIGRP_OPC_ACK 8 /*!< acknowledge */ +#define EIGRP_OPC_SIAQUERY 10 /*!< QUERY - with relaxed restrictions */ +#define EIGRP_OPC_SIAREPLY 11 /*!< REPLY - may contain old routing information */ + +/** + * EIGRP TLV Range definitions + * PDM TLV Range + * General 0x0000 + * IPv4 0x0100 ** TLVs for one and all + * ATALK 0x0200 ** legacy + * IPX 0x0300 ** discontinued + * IPv6 0x0400 ** legacy + * Multiprotocol 0x0600 ** wide metrics + * MultiTopology 0x00f0 ** deprecated + */ +#define EIGRP_TLV_RANGEMASK 0xfff0 /*!< should be 0xff00 - opps */ +#define EIGRP_TLV_GENERAL 0x0000 + +/** + * 1.2 TLV Definitions ** legacy + * These are considered legacyu and are only used for backward compability with + * older Cisco Routers. They should not be your first choice for packet codings + */ +#define EIGRP_TLV_IPv4 0x0100 /*!< Classic IPv4 TLV encoding */ +#define EIGRP_TLV_ATALK 0x0200 /*!< Classic Appletalk TLV encoding*/ +#define EIGRP_TLV_IPX 0x0300 /*!< Classic IPX TLV encoding */ +#define EIGRP_TLV_IPv6 0x0400 /*!< Classic IPv6 TLV encoding */ + +/** + * 2.0 Multi-Protocol TLV Definitions + * These are the current packet formats and should be used for packets + */ +#define EIGRP_TLV_MP 0x0600 /*!< Non-PDM specific encoding */ + +/** + * TLV type definitions. Generic (protocol-independent) TLV types are + * defined here. Protocol-specific ones are defined elsewhere. + */ +#define EIGRP_TLV_PARAMETER (EIGRP_TLV_GENERAL | 0x0001) /*!< eigrp parameters */ +#define EIGRP_TLV_PARAMETER_LEN (12U) +#define EIGRP_TLV_AUTH (EIGRP_TLV_GENERAL | 0x0002) /*!< authentication */ +#define EIGRP_TLV_SEQ (EIGRP_TLV_GENERAL | 0x0003) /*!< sequenced packet */ +#define EIGRP_TLV_SEQ_BASE_LEN (5U) +#define EIGRP_TLV_SW_VERSION (EIGRP_TLV_GENERAL | 0x0004) /*!< software version */ +#define EIGRP_TLV_SW_VERSION_LEN (8U) +#define EIGRP_TLV_NEXT_MCAST_SEQ (EIGRP_TLV_GENERAL | 0x0005) /*!< sequence number */ +#define EIGRP_TLV_PEER_TERMINATION (EIGRP_TLV_GENERAL | 0x0007) /*!< peer termination */ +#define EIGRP_TLV_PEER_TERMINATION_LEN (9U) +#define EIGRP_TLV_PEER_TIDLIST (EIGRP_TLV_GENERAL | 0x0008) /*!< peer sub-topology list */ + +/* Older cisco routers send TIDLIST value wrong, adding for backwards compatabily */ +#define EIGRP_TLV_PEER_MTRLIST (EIGRP_TLV_GENERAL | 0x00f5) + +/** + * Route Based TLVs + */ +#define EIGRP_TLV_REQUEST 0x0001 +#define EIGRP_TLV_INTERNAL 0x0002 +#define EIGRP_TLV_EXTERNAL 0x0003 +#define EIGRP_TLV_COMMUNITY 0x0004 +#define EIGRP_TLV_TYPEMASK 0x000f + +#define EIGRP_TLV_IPv4_REQ (EIGRP_TLV_IPv4 | EIGRP_TLV_REQUEST) +#define EIGRP_TLV_IPv4_INT (EIGRP_TLV_IPv4 | EIGRP_TLV_INTERNAL) +#define EIGRP_TLV_IPv4_EXT (EIGRP_TLV_IPv4 | EIGRP_TLV_EXTERNAL) +#define EIGRP_TLV_IPv4_COM (EIGRP_TLV_IPv4 | EIGRP_TLV_COMMUNITY) + +/* max number of TLV IPv4 prefixes in packet */ +#define EIGRP_TLV_MAX_IPv4 25 + +/** + * + * extdata flag field definitions + */ +#define EIGRP_OPAQUE_EXT 0x01 /*!< Route is external */ +#define EIGRP_OPAQUE_CD 0x02 /*!< Candidate default route */ + +/** + * Address-Family types are taken from: + * http://www.iana.org/assignments/address-family-numbers + * to provide a standards based exchange of AFI information between + * EIGRP routers. + */ +#define EIGRP_AF_IPv4 1 /*!< IPv4 (IP version 4) */ +#define EIGRP_AF_IPv6 2 /*!< IPv6 (IP version 6) */ +#define EIGRP_AF_IPX 11 /*!< IPX */ +#define EIGRP_AF_ATALK 12 /*!< Appletalk */ +#define EIGRP_SF_COMMON 16384 /*!< Cisco Service Family */ +#define EIGRP_SF_IPv4 16385 /*!< Cisco IPv4 Service Family */ +#define EIGRP_SF_IPv6 16386 /*!< Cisco IPv6 Service Family */ + +/** + * Authentication types supported by EIGRP + */ +#define EIGRP_AUTH_TYPE_NONE 0 +#define EIGRP_AUTH_TYPE_TEXT 1 +#define EIGRP_AUTH_TYPE_MD5 2 +#define EIGRP_AUTH_TYPE_MD5_LEN 16 +#define EIGRP_AUTH_TYPE_SHA256 3 +#define EIGRP_AUTH_TYPE_SHA256_LEN 32 + +/** + * opaque flag field definitions + */ +#define EIGRP_OPAQUE_SRCWD 0x01 /*!< Route Source Withdraw */ +#define EIGRP_OPAQUE_ACTIVE 0x04 /*!< Route is currently in active state */ +#define EIGRP_OPAQUE_REPL 0x08 /*!< Route is replicated from different tableid */ + +/** + * pak flag bit field definitions - 0 (none)-7 source priority + */ +#define EIGRP_PRIV_DEFAULT 0x00 /* 0 (none)-7 source priority */ +#define EIGRP_PRIV_LOW 0x01 +#define EIGRP_PRIV_MEDIUM 0x04 +#define EIGRP_PRIV_HIGH 0x07 + +/* + * Init bit definition. First unicast transmitted Update has this + * bit set in the flags field of the fixed header. It tells the neighbor + * to down-load his topology table. + */ +#define EIGRP_INIT_FLAG 0x01 + +/* + * CR bit (Conditionally Received) definition in flags field on header. Any + * packets with the CR-bit set can be accepted by an EIGRP speaker if and + * only if a previous Hello was received with the SEQUENCE_TYPE TLV present. + * + * This allows multicasts to be transmitted in order and reliably at the + * same time as unicasts are transmitted. + */ +#define EIGRP_CR_FLAG 0x02 + +/* + * RS bit. The Restart flag is set in the hello and the init + * update packets during the nsf signaling period. A nsf-aware + * router looks at the RS flag to detect if a peer is restarting + * and maintain the adjacency. A restarting router looks at + * this flag to determine if the peer is helping out with the restart. + */ +#define EIGRP_RS_FLAG 0x04 + +/* + * EOT bit. The End-of-Table flag marks the end of the start-up updates + * sent to a new peer. A nsf restarting router looks at this flag to + * determine if it has finished receiving the start-up updates from all + * peers. A nsf-aware router waits for this flag before cleaning up + * the stale routes from the restarting peer. + */ +#define EIGRP_EOT_FLAG 0x08 + +/** + * EIGRP Virtual Router ID + * + * Define values to deal with EIGRP virtual router ids. Virtual + * router IDs are stored in the upper short of the EIGRP fixed packet + * header. The lower short of the packet header continues to be used + * as asystem number. + * + * Virtual Router IDs are PDM-independent. All PDMs will use + * VRID_BASE to indicate the 'base' or 'legacy' EIGRP instance. + * All PDMs need to initialize their vrid to VRID_BASE for compatibility + * with legacy routers. + * Once IPv6 supports 'MTR Multicast', it will use the same VRID as + * IPv4. No current plans to support VRIDs on IPX. :) + * Initial usage of VRID is to signal usage of Multicast topology for + * MTR. + * + * VRID_MCAST is a well known constant, other VRIDs will be determined + * programmatic... + * + * With the addition of SAF the VRID space has been divided into two + * segments 0x0000-0x7fff is for EIGRP and vNets, 0x8000-0xffff is + * for saf and its associated vNets. + */ +#define EIGRP_VRID_MASK 0x8001 +#define EIGRP_VRID_AF_BASE 0x0000 +#define EIGRP_VRID_MCAST_BASE 0x0001 +#define EIGRP_VRID_SF_BASE 0x8000 + +/* Extended Attributes for a destination */ +#define EIGRP_ATTR_HDRLEN (2) +#define EIGRP_ATTR_MAXDATA (512) + +#define EIGRP_ATTR_NOOP 0 /*!< No-Op used as offset padding */ +#define EIGRP_ATTR_SCALED 1 /*!< Scaled metric values */ +#define EIGRP_ATTR_TAG 2 /*!< Tag assigned by Admin for dest */ +#define EIGRP_ATTR_COMM 3 /*!< Community attribute for dest */ +#define EIGRP_ATTR_JITTER 4 /*!< Variation in path delay */ +#define EIGRP_ATTR_QENERGY 5 /*!< Non-Active energy usage along path */ +#define EIGRP_ATTR_ENERGY 6 /*!< Active energy usage along path */ + +/* + * Begin EIGRP-BGP interoperability communities + */ +#define EIGRP_EXTCOMM_SOO_ASFMT 0x0003 /* Site-of-Origin, BGP AS format */ +#define EIGRP_EXTCOMM_SOO_ADRFMT 0x0103 /* Site-of-Origin, BGP/EIGRP addr format */ + +/* + * EIGRP Specific communities + */ +#define EIGRP_EXTCOMM_EIGRP 0x8800 /* EIGRP route information appended*/ +#define EIGRP_EXTCOMM_DAD 0x8801 /* EIGRP AS + Delay */ +#define EIGRP_EXTCOMM_VRHB 0x8802 /* EIGRP Vector: Reliability + Hop + BW */ +#define EIGRP_EXTCOMM_SRLM 0x8803 /* EIGRP System: Reserve +Load + MTU */ +#define EIGRP_EXTCOMM_SAR 0x8804 /* EIGRP System: Remote AS + Remote ID */ +#define EIGRP_EXTCOMM_RPM 0x8805 /* EIGRP Remote: Protocol + Metric */ +#define EIGRP_EXTCOMM_VRR 0x8806 /* EIGRP Vecmet: Rsvd + (internal) Routerid */ + + +/* + * EIGRP Filter constants + */ +#define EIGRP_FILTER_IN 0 +#define EIGRP_FILTER_OUT 1 +#define EIGRP_FILTER_MAX 2 + +/* + * EIGRP Filter constants + */ +#define EIGRP_HSROLE_DEFAULT EIGRP_HSROLE_SPOKE +#define EIGRP_HSROLE_HUB 0x01 +#define EIGRP_HSROLE_SPOKE 0x02 + +#endif /* _ZEBRA_EIGRP_CONST_H_ */ diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c new file mode 100644 index 000000000..c15eecc26 --- /dev/null +++ b/eigrpd/eigrp_dump.c @@ -0,0 +1,768 @@ +/* + * EIGRP Dump Functions and Debugging. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "linklist.h" +#include "thread.h" +#include "prefix.h" +#include "command.h" +#include "stream.h" +#include "log.h" +#include "sockopt.h" +#include "table.h" +#include "keychain.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_topology.h" + +/* Enable debug option variables -- valid only session. */ +unsigned long term_debug_eigrp = 0; +unsigned long term_debug_eigrp_nei = 0; +unsigned long term_debug_eigrp_packet[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +unsigned long term_debug_eigrp_zebra = 6; +unsigned long term_debug_eigrp_transmit = 0; + +/* Configuration debug option variables. */ +unsigned long conf_debug_eigrp = 0; +unsigned long conf_debug_eigrp_nei = 0; +unsigned long conf_debug_eigrp_packet[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +unsigned long conf_debug_eigrp_zebra = 0; +unsigned long conf_debug_eigrp_transmit = 0; + + +static int +config_write_debug (struct vty *vty) +{ + int write = 0; + int i; + + const char *type_str[] = {"update", "request", "query", "reply", "hello", "", "probe", "ack", "", + "SIA query", "SIA reply", "stub", "all"}; + const char *detail_str[] = {"", " send", " recv", "", " detail", + " send detail", " recv detail", " detail"}; + + + /* debug eigrp event. */ +// if (IS_CONF_DEBUG_EIGRP (event, EVENT) == EIGRP_DEBUG_EVENT) +// { +// vty_out (vty, "debug eigrp event%s", VTY_NEWLINE); +// write = 1; +// } + + /* debug eigrp packet all detail. */ +// r = EIGRP_DEBUG_SEND_RECV|EIGRP_DEBUG_DETAIL; +// for (i = 0; i < 11; i++) +// r &= conf_debug_eigrp_packet[i] & (EIGRP_DEBUG_SEND_RECV|EIGRP_DEBUG_DETAIL); +// if (r == (EIGRP_DEBUG_SEND_RECV|EIGRP_DEBUG_DETAIL)) +// { +// vty_out (vty, "debug eigrp packet all detail%s", VTY_NEWLINE); +//// return 1; +// } +// +// /* debug eigrp packet all. */ +// r = EIGRP_DEBUG_SEND_RECV; +// for (i = 0; i < 11; i++) +// r &= conf_debug_eigrp_packet[i] & EIGRP_DEBUG_SEND_RECV; +// if (r == EIGRP_DEBUG_SEND_RECV) +// { +// vty_out (vty, "debug eigrp packet all%s", VTY_NEWLINE); +// for (i = 0; i < 11; i++) +// if (conf_debug_eigrp_packet[i] & EIGRP_DEBUG_DETAIL) +// vty_out (vty, "debug eigrp packet %s detail%s", +// type_str[i], +// VTY_NEWLINE); +//// return 1; +// } + + /* debug eigrp packet */ + for (i = 0; i < 10; i++) + { + if (conf_debug_eigrp_packet[i] == 0 && term_debug_eigrp_packet[i] == 0 ) + continue; + + vty_out (vty, "debug eigrp packet %s%s%s", + type_str[i], detail_str[conf_debug_eigrp_packet[i]], + VTY_NEWLINE); + write = 1; + } + + // int write = 0; + // int i, r; + // + // const char *type_str[] = {"hello", "dd", "ls-request", "ls-update", "ls-ack"}; + // const char *detail_str[] = {"", " send", " recv", "", " detail", + // " send detail", " recv detail", " detail"}; + // + // /* debug ospf ism (status|events|timers). */ + // if (IS_CONF_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM) + // vty_out (vty, "debug ospf ism%s", VTY_NEWLINE); + // else + // { + // if (IS_CONF_DEBUG_OSPF (ism, ISM_STATUS)) + // vty_out (vty, "debug ospf ism status%s", VTY_NEWLINE); + // if (IS_CONF_DEBUG_OSPF (ism, ISM_EVENTS)) + // vty_out (vty, "debug ospf ism event%s", VTY_NEWLINE); + // if (IS_CONF_DEBUG_OSPF (ism, ISM_TIMERS)) + // vty_out (vty, "debug ospf ism timer%s", VTY_NEWLINE); + // } + // + // /* debug ospf nsm (status|events|timers). */ + // if (IS_CONF_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM) + // vty_out (vty, "debug ospf nsm%s", VTY_NEWLINE); + // else + // { + // if (IS_CONF_DEBUG_OSPF (nsm, NSM_STATUS)) + // vty_out (vty, "debug ospf nsm status%s", VTY_NEWLINE); + // if (IS_CONF_DEBUG_OSPF (nsm, NSM_EVENTS)) + // vty_out (vty, "debug ospf nsm event%s", VTY_NEWLINE); + // if (IS_CONF_DEBUG_OSPF (nsm, NSM_TIMERS)) + // vty_out (vty, "debug ospf nsm timer%s", VTY_NEWLINE); + // } + // + // /* debug ospf lsa (generate|flooding|install|refresh). */ + // if (IS_CONF_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) + // vty_out (vty, "debug ospf lsa%s", VTY_NEWLINE); + // else + // { + // if (IS_CONF_DEBUG_OSPF (lsa, LSA_GENERATE)) + // vty_out (vty, "debug ospf lsa generate%s", VTY_NEWLINE); + // if (IS_CONF_DEBUG_OSPF (lsa, LSA_FLOODING)) + // vty_out (vty, "debug ospf lsa flooding%s", VTY_NEWLINE); + // if (IS_CONF_DEBUG_OSPF (lsa, LSA_INSTALL)) + // vty_out (vty, "debug ospf lsa install%s", VTY_NEWLINE); + // if (IS_CONF_DEBUG_OSPF (lsa, LSA_REFRESH)) + // vty_out (vty, "debug ospf lsa refresh%s", VTY_NEWLINE); + // + // write = 1; + // } + // + // /* debug ospf zebra (interface|redistribute). */ + // if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA) + // vty_out (vty, "debug ospf zebra%s", VTY_NEWLINE); + // else + // { + // if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) + // vty_out (vty, "debug ospf zebra interface%s", VTY_NEWLINE); + // if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) + // vty_out (vty, "debug ospf zebra redistribute%s", VTY_NEWLINE); + // + // write = 1; + // } + // + // /* debug ospf event. */ + // if (IS_CONF_DEBUG_OSPF (event, EVENT) == OSPF_DEBUG_EVENT) + // { + // vty_out (vty, "debug ospf event%s", VTY_NEWLINE); + // write = 1; + // } + // + // /* debug ospf nssa. */ + // if (IS_CONF_DEBUG_OSPF (nssa, NSSA) == OSPF_DEBUG_NSSA) + // { + // vty_out (vty, "debug ospf nssa%s", VTY_NEWLINE); + // write = 1; + // } + // + // /* debug ospf packet all detail. */ + // r = OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL; + // for (i = 0; i < 5; i++) + // r &= conf_debug_ospf_packet[i] & (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL); + // if (r == (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL)) + // { + // vty_out (vty, "debug ospf packet all detail%s", VTY_NEWLINE); + // return 1; + // } + // + // /* debug ospf packet all. */ + // r = OSPF_DEBUG_SEND_RECV; + // for (i = 0; i < 5; i++) + // r &= conf_debug_ospf_packet[i] & OSPF_DEBUG_SEND_RECV; + // if (r == OSPF_DEBUG_SEND_RECV) + // { + // vty_out (vty, "debug ospf packet all%s", VTY_NEWLINE); + // for (i = 0; i < 5; i++) + // if (conf_debug_ospf_packet[i] & OSPF_DEBUG_DETAIL) + // vty_out (vty, "debug ospf packet %s detail%s", + // type_str[i], + // VTY_NEWLINE); + // return 1; + // } + // + // /* debug ospf packet (hello|dd|ls-request|ls-update|ls-ack) + // (send|recv) (detail). */ + // for (i = 0; i < 5; i++) + // { + // if (conf_debug_ospf_packet[i] == 0) + // continue; + // + // vty_out (vty, "debug ospf packet %s%s%s", + // type_str[i], detail_str[conf_debug_ospf_packet[i]], + // VTY_NEWLINE); + // write = 1; + // } + + return write; +} + + +static int +eigrp_neighbor_packet_queue_sum (struct eigrp_interface *ei) +{ + struct eigrp_neighbor *nbr; + struct listnode *node, *nnode; + int sum; + sum = 0; + + for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr)) + { + sum += nbr->retrans_queue->count; + } + + return sum; +} + +/* + * Expects header to be in host order + */ +void +eigrp_ip_header_dump (struct ip *iph) +{ + /* IP Header dump. */ + zlog_debug ("ip_v %u", iph->ip_v); + zlog_debug ("ip_hl %u", iph->ip_hl); + zlog_debug ("ip_tos %u", iph->ip_tos); + zlog_debug ("ip_len %u", iph->ip_len); + zlog_debug ("ip_id %u", (u_int32_t) iph->ip_id); + zlog_debug ("ip_off %u", (u_int32_t) iph->ip_off); + zlog_debug ("ip_ttl %u", iph->ip_ttl); + zlog_debug ("ip_p %u", iph->ip_p); + zlog_debug ("ip_sum 0x%x", (u_int32_t) iph->ip_sum); + zlog_debug ("ip_src %s", inet_ntoa (iph->ip_src)); + zlog_debug ("ip_dst %s", inet_ntoa (iph->ip_dst)); +} + +/* + * Expects header to be in host order + */ +void +eigrp_header_dump (struct eigrp_header *eigrph) +{ + /* EIGRP Header dump. */ + zlog_debug ("eigrp_version %u", eigrph->version); + zlog_debug ("eigrp_opcode %u", eigrph->opcode); + zlog_debug ("eigrp_checksum 0x%x", ntohs(eigrph->checksum)); + zlog_debug ("eigrp_flags 0x%x", ntohl(eigrph->flags)); + zlog_debug ("eigrp_sequence %u", ntohl(eigrph->sequence)); + zlog_debug ("eigrp_ack %u", ntohl(eigrph->ack)); + zlog_debug ("eigrp_vrid %u" , ntohs(eigrph->vrid)); + zlog_debug ("eigrp_AS %u", ntohs(eigrph->ASNumber)); +} + +const char * +eigrp_if_name_string (struct eigrp_interface *ei) +{ + static char buf[EIGRP_IF_STRING_MAXLEN] = ""; + + if (!ei) + return "inactive"; + + snprintf (buf, EIGRP_IF_STRING_MAXLEN, + "%s", ei->ifp->name); + return buf; +} + +const char * +eigrp_topology_ip_string (struct eigrp_prefix_entry *tn) +{ + static char buf[EIGRP_IF_STRING_MAXLEN] = ""; + u_int32_t ifaddr; + + ifaddr = ntohl (tn->destination_ipv4->prefix.s_addr); + snprintf (buf, EIGRP_IF_STRING_MAXLEN, + "%u.%u.%u.%u", + (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, + (ifaddr >> 8) & 0xff, ifaddr & 0xff); + return buf; +} + + +const char * +eigrp_if_ip_string (struct eigrp_interface *ei) +{ + static char buf[EIGRP_IF_STRING_MAXLEN] = ""; + u_int32_t ifaddr; + + if (!ei) + return "inactive"; + + ifaddr = ntohl (ei->address->u.prefix4.s_addr); + snprintf (buf, EIGRP_IF_STRING_MAXLEN, + "%u.%u.%u.%u", + (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, + (ifaddr >> 8) & 0xff, ifaddr & 0xff); + + return buf; +} + +const char * +eigrp_neigh_ip_string (struct eigrp_neighbor *nbr) +{ + static char buf[EIGRP_IF_STRING_MAXLEN] = ""; + u_int32_t ifaddr; + + ifaddr = ntohl (nbr->src.s_addr); + snprintf (buf, EIGRP_IF_STRING_MAXLEN, + "%u.%u.%u.%u", + (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, + (ifaddr >> 8) & 0xff, ifaddr & 0xff); + + return buf; +} + +void +show_ip_eigrp_interface_header (struct vty *vty, struct eigrp *eigrp) +{ + + vty_out (vty, "%s%s%d%s%s%s %-10s %-10s %-10s %-6s %-12s %-7s %-14s %-12s %-8s %-8s %-8s%s %-39s %-12s %-7s %-14s %-12s %-8s%s", + VTY_NEWLINE, + "EIGRP interfaces for AS(",eigrp->AS,")",VTY_NEWLINE,VTY_NEWLINE, + "Interface", "Bandwidth", "Delay", "Peers", "Xmit Queue", "Mean", + "Pacing Time", "Multicast", "Pending", "Hello", "Holdtime", + VTY_NEWLINE,"","Un/Reliable","SRTT","Un/Reliable","Flow Timer","Routes", + VTY_NEWLINE); +} + +void +show_ip_eigrp_interface_sub (struct vty *vty, struct eigrp *eigrp, + struct eigrp_interface *ei) +{ + vty_out (vty, "%-11s ", eigrp_if_name_string (ei)); + vty_out (vty, "%-11u",IF_DEF_PARAMS (ei->ifp)->bandwidth); + vty_out (vty, "%-11u",IF_DEF_PARAMS (ei->ifp)->delay); + vty_out (vty, "%-7u", ei->nbrs->count); + vty_out (vty, "%u %c %-10u",0,'/',eigrp_neighbor_packet_queue_sum (ei)); + vty_out (vty, "%-7u %-14u %-12u %-8u",0,0,0,0); + vty_out (vty, "%-8u %-8u %s",IF_DEF_PARAMS (ei->ifp)->v_hello,IF_DEF_PARAMS (ei->ifp)->v_wait,VTY_NEWLINE); +} + +void +show_ip_eigrp_interface_detail (struct vty *vty, struct eigrp *eigrp, + struct eigrp_interface *ei) +{ + vty_out (vty, "%-2s %s %d %-3s %s","","Hello interval is ",0," sec",VTY_NEWLINE); + vty_out (vty, "%-2s %s %s %s","","Next xmit serial","<none>",VTY_NEWLINE); + vty_out (vty, "%-2s %s %d %s %d %s %d %s %d %s","","Un/reliable mcasts: ",0,"/",0,"Un/reliable ucasts: ",0,"/",0,VTY_NEWLINE); + vty_out (vty, "%-2s %s %d %s %d %s %d %s","","Mcast exceptions: ",0," CR packets: ",0," ACKs supressed: ",0,VTY_NEWLINE); + vty_out (vty, "%-2s %s %d %s %d %s","","Retransmissions sent: ",0,"Out-of-sequence rcvd: ",0,VTY_NEWLINE); + vty_out (vty, "%-2s %s %s %s %s","","Authentication mode is ","not","set",VTY_NEWLINE); + vty_out (vty, "%-2s %s %s","","Use multicast",VTY_NEWLINE); +} + +void +show_ip_eigrp_neighbor_header (struct vty *vty, struct eigrp *eigrp) +{ + vty_out (vty, "%s%s%d%s%s%s%-3s %-17s %-20s %-6s %-8s %-6s %-5s %-5s %-5s%s %-41s %-6s %-8s %-6s %-4s %-6s %-5s %s", + VTY_NEWLINE, + "EIGRP neighbors for AS(",eigrp->AS,")",VTY_NEWLINE,VTY_NEWLINE, + "H", "Address", "Interface", "Hold", "Uptime", + "SRTT", "RTO", "Q", "Seq", VTY_NEWLINE + ,"","(sec)","","(ms)","","Cnt","Num", VTY_NEWLINE); +} + +void +show_ip_eigrp_neighbor_sub (struct vty *vty, struct eigrp_neighbor *nbr, + int detail) +{ + + vty_out (vty, "%-3u %-17s %-21s",0,eigrp_neigh_ip_string (nbr),eigrp_if_name_string (nbr->ei)); + vty_out (vty,"%-7lu",thread_timer_remain_second (nbr->t_holddown)); + vty_out (vty,"%-8u %-6u %-5u",0,0,EIGRP_PACKET_RETRANS_TIME); + vty_out (vty,"%-7lu",nbr->retrans_queue->count); + vty_out (vty,"%u%s",nbr->recv_sequence_number,VTY_NEWLINE); + + + if (detail) + { + vty_out(vty," Version %u.%u/%u.%u", + nbr->os_rel_major, nbr->os_rel_minor, + nbr->tlv_rel_major, nbr->tlv_rel_minor); + vty_out(vty,", Retrans: %lu, Retries: %lu", + nbr->retrans_queue->count, 0UL); + vty_out(vty,", %s%s", eigrp_nbr_state_str(nbr), VTY_NEWLINE); + } +} + +/* + * Print standard header for show EIGRP topology output + */ +void +show_ip_eigrp_topology_header (struct vty *vty, struct eigrp *eigrp) +{ + struct in_addr router_id; + router_id.s_addr = htonl(eigrp->router_id); + + vty_out (vty, "%s%s%d%s%s%s%s%s%s%s%s%s%s%s", + VTY_NEWLINE, + "EIGRP Topology Table for AS(", eigrp->AS, ")/ID(", inet_ntoa(router_id), ")", VTY_NEWLINE,VTY_NEWLINE, + "Codes: P - Passive, A - Active, U - Update, Q - Query, " + "R - Reply", VTY_NEWLINE ," ","r - reply Status, s - sia Status",VTY_NEWLINE,VTY_NEWLINE); +} + +void +show_ip_eigrp_prefix_entry (struct vty *vty, struct eigrp_prefix_entry *tn) +{ + vty_out (vty, "%-3c",(tn->state > 0) ? 'A' : 'P'); + vty_out (vty, "%s/%u, ",inet_ntoa (tn->destination_ipv4->prefix),tn->destination_ipv4->prefixlen); + vty_out (vty, "%u successors, ",eigrp_topology_get_successor(tn)->count); + vty_out (vty, "FD is %u, serno: %lu %s",tn->fdistance, tn->serno, VTY_NEWLINE); + +} + +void +show_ip_eigrp_neighbor_entry (struct vty *vty, struct eigrp *eigrp, struct eigrp_neighbor_entry *te) +{ + if (te->adv_router == eigrp->neighbor_self) + vty_out (vty, "%-7s%s, %s%s"," ","via Connected",eigrp_if_name_string (te->ei), VTY_NEWLINE); + else + { + vty_out (vty, "%-7s%s%s (%u/%u), %s%s"," ","via ",inet_ntoa (te->adv_router->src),te->distance, te->reported_distance, eigrp_if_name_string (te->ei), VTY_NEWLINE); + } +} + + +DEFUN (show_debugging_eigrp, + show_debugging_eigrp_cmd, + "show debugging eigrp", + SHOW_STR + DEBUG_STR + EIGRP_STR) +{ + int i; + + vty_out (vty, "EIGRP debugging status:%s", VTY_NEWLINE); + + /* Show debug status for events. */ + if (IS_DEBUG_EIGRP(event,EVENT)) + vty_out (vty, " EIGRP event debugging is on%s", VTY_NEWLINE); + + /* Show debug status for EIGRP Packets. */ + for (i = 0; i < 11 ; i++) + { + if (i == 8) + continue; + + if (IS_DEBUG_EIGRP_PACKET (i, SEND) && IS_DEBUG_EIGRP_PACKET (i, RECV)) + { + vty_out (vty, " EIGRP packet %s%s debugging is on%s", + LOOKUP (eigrp_packet_type_str, i + 1), + IS_DEBUG_EIGRP_PACKET (i, PACKET_DETAIL) ? " detail" : "", + VTY_NEWLINE); + } + else + { + if (IS_DEBUG_EIGRP_PACKET (i, SEND)) + vty_out (vty, " EIGRP packet %s send%s debugging is on%s", + LOOKUP (eigrp_packet_type_str, i + 1), + IS_DEBUG_EIGRP_PACKET (i, PACKET_DETAIL) ? " detail" : "", + VTY_NEWLINE); + if (IS_DEBUG_EIGRP_PACKET (i, RECV)) + vty_out (vty, " EIGRP packet %s receive%s debugging is on%s", + LOOKUP (eigrp_packet_type_str, i + 1), + IS_DEBUG_EIGRP_PACKET (i, PACKET_DETAIL) ? " detail" : "", + VTY_NEWLINE); + } + } + + return CMD_SUCCESS; +} + + +/* + [no] debug eigrp packet (hello|dd|ls-request|ls-update|ls-ack|all) + [send|recv [detail]] +*/ + +DEFUN (debug_eigrp_transmit, + debug_eigrp_transmit_cmd, + "debug eigrp transmit <send|recv|all> [detail]", + DEBUG_STR + EIGRP_STR + "EIGRP transmission events\n" + "packet sent\n" + "packet received\n" + "all packets\n" + "Detailed Information\n") +{ + int flag = 0; + int idx = 2; + + /* send or recv. */ + if (argv_find (argv, argc, "send", &idx)) + flag = EIGRP_DEBUG_SEND; + else if (argv_find (argv, argc, "recv", &idx)) + flag = EIGRP_DEBUG_RECV; + else if (argv_find (argv, argc, "all", &idx) == 0) + flag = EIGRP_DEBUG_SEND_RECV; + + /* detail option */ + if (argv_find (argv, argc, "detail", &idx) == 0) + flag = EIGRP_DEBUG_PACKET_DETAIL; + + if (vty->node == CONFIG_NODE) + DEBUG_TRANSMIT_ON (0, flag); + else + TERM_DEBUG_TRANSMIT_ON (0, flag); + + return CMD_SUCCESS; +} + +DEFUN (no_debug_eigrp_transmit, + no_debug_eigrp_transmit_cmd, + "no debug eigrp transmit <send|recv|all> [detail]", + NO_STR + UNDEBUG_STR + EIGRP_STR + "EIGRP transmission events\n" + "packet sent\n" + "packet received\n" + "all packets\n" + "Detailed Information\n") +{ + int flag = 0; + int idx = 3; + + /* send or recv. */ + if (argv_find (argv, argc, "send", &idx) == 0) + flag = EIGRP_DEBUG_SEND; + else if (argv_find (argv, argc, "recv", &idx) == 0) + flag = EIGRP_DEBUG_RECV; + else if (argv_find (argv, argc, "all", &idx) == 0) + flag = EIGRP_DEBUG_SEND_RECV; + + /* detail option */ + if (argv_find (argv, argc, "detail", &idx) == 0) + flag = EIGRP_DEBUG_PACKET_DETAIL; + + if (vty->node == CONFIG_NODE) + DEBUG_TRANSMIT_OFF (0, flag); + else + TERM_DEBUG_TRANSMIT_OFF (0, flag); + + return CMD_SUCCESS; +} + +DEFUN (debug_eigrp_packets, + debug_eigrp_packets_all_cmd, + "debug eigrp packets <siaquery|siareply|ack|hello|probe|query|reply|request|retry|stub|terse|update|all> [send|receive] [detail]", + DEBUG_STR + EIGRP_STR + "EIGRP packets\n" + "EIGRP SIA-Query packets\n" + "EIGRP SIA-Reply packets\n" + "EIGRP ack packets\n" + "EIGRP hello packets\n" + "EIGRP probe packets\n" + "EIGRP query packets\n" + "EIGRP reply packets\n" + "EIGRP request packets\n" + "EIGRP retransmissions\n" + "EIGRP stub packets\n" + "Display all EIGRP packets except Hellos\n" + "EIGRP update packets\n" + "Display all EIGRP packets\n" + "Send Packets\n" + "Receive Packets\n" + "Detail Information\n") +{ + int type = 0; + int flag = 0; + int i; + int idx = 0; + + /* Check packet type. */ + if (argv_find (argv, argc, "hello", &idx) == 0) + type = EIGRP_DEBUG_HELLO; + if (argv_find (argv, argc, "update", &idx) == 0) + type = EIGRP_DEBUG_UPDATE; + if (argv_find (argv, argc, "query", &idx) == 0) + type = EIGRP_DEBUG_QUERY; + if (argv_find (argv, argc, "ack", &idx) == 0) + type = EIGRP_DEBUG_ACK; + if (argv_find (argv, argc, "probe", &idx) == 0) + type = EIGRP_DEBUG_PROBE; + if (argv_find (argv, argc, "stub", &idx) == 0) + type = EIGRP_DEBUG_STUB; + if (argv_find (argv, argc, "reply", &idx) == 0) + type = EIGRP_DEBUG_REPLY; + if (argv_find (argv, argc, "request", &idx) == 0) + type = EIGRP_DEBUG_REQUEST; + if (argv_find (argv, argc, "siaquery", &idx) == 0) + type = EIGRP_DEBUG_SIAQUERY; + if (argv_find (argv, argc, "siareply", &idx) == 0) + type = EIGRP_DEBUG_SIAREPLY; + if (argv_find (argv, argc, "all", &idx) == 0) + type = EIGRP_DEBUG_PACKETS_ALL; + + + /* All packet types, both send and recv. */ + flag = EIGRP_DEBUG_SEND_RECV; + + /* send or recv. */ + if (argv_find (argv, argc, "s", &idx) == 0) + flag = EIGRP_DEBUG_SEND; + else if (argv_find (argv, argc, "r", &idx) == 0) + flag = EIGRP_DEBUG_RECV; + + /* detail. */ + if (argv_find (argv, argc, "detail", &idx) == 0) + flag |= EIGRP_DEBUG_PACKET_DETAIL; + + for (i = 0; i < 11; i++) + if (type & (0x01 << i)) + { + if (vty->node == CONFIG_NODE) + DEBUG_PACKET_ON (i, flag); + else + TERM_DEBUG_PACKET_ON (i, flag); + } + + return CMD_SUCCESS; +} + +DEFUN (no_debug_eigrp_packets, + no_debug_eigrp_packets_all_cmd, + "no debug eigrp packets <siaquery|siareply|ack|hello|probe|query|reply|request|retry|stub|terse|update|all> [send|receive] [detail]", + NO_STR + UNDEBUG_STR + EIGRP_STR + "EIGRP packets\n" + "EIGRP SIA-Query packets\n" + "EIGRP SIA-Reply packets\n" + "EIGRP ack packets\n" + "EIGRP hello packets\n" + "EIGRP probe packets\n" + "EIGRP query packets\n" + "EIGRP reply packets\n" + "EIGRP request packets\n" + "EIGRP retransmissions\n" + "EIGRP stub packets\n" + "Display all EIGRP packets except Hellos\n" + "EIGRP update packets\n" + "Display all EIGRP packets\n" + "Send Packets\n" + "Receive Packets\n" + "Detailed Information\n") +{ + int type = 0; + int flag = 0; + int i; + int idx = 0; + + /* Check packet type. */ + if (argv_find (argv, argc, "hello", &idx) == 0) + type = EIGRP_DEBUG_HELLO; + if (argv_find (argv, argc, "update", &idx) == 0) + type = EIGRP_DEBUG_UPDATE; + if (argv_find (argv, argc, "query", &idx) == 0) + type = EIGRP_DEBUG_QUERY; + if (argv_find (argv, argc, "ack", &idx) == 0) + type = EIGRP_DEBUG_ACK; + if (argv_find (argv, argc, "probe", &idx) == 0) + type = EIGRP_DEBUG_PROBE; + if (argv_find (argv, argc, "stub", &idx) == 0) + type = EIGRP_DEBUG_STUB; + if (argv_find (argv, argc, "reply", &idx) == 0) + type = EIGRP_DEBUG_REPLY; + if (argv_find (argv, argc, "request", &idx) == 0) + type = EIGRP_DEBUG_REQUEST; + if (argv_find (argv, argc, "siaquery", &idx) == 0) + type = EIGRP_DEBUG_SIAQUERY; + if (argv_find (argv, argc, "siareply", &idx) == 0) + type = EIGRP_DEBUG_SIAREPLY; + + /* Default, both send and recv. */ + flag = EIGRP_DEBUG_SEND_RECV; + + /* send or recv. */ + if (argv_find (argv, argc, "send", &idx) == 0) + flag = EIGRP_DEBUG_SEND; + else if (argv_find (argv, argc, "reply", &idx) == 0) + flag = EIGRP_DEBUG_RECV; + + /* detail. */ + if (argv_find (argv, argc, "detail", &idx) == 0) + flag |= EIGRP_DEBUG_PACKET_DETAIL; + + for (i = 0; i < 11; i++) + if (type & (0x01 << i)) + { + if (vty->node == CONFIG_NODE) + DEBUG_PACKET_OFF (i, flag); + else + TERM_DEBUG_PACKET_OFF (i, flag); + } + + return CMD_SUCCESS; +} + +/* Debug node. */ +static struct cmd_node eigrp_debug_node = +{ + DEBUG_NODE, + "", + 1 /* VTYSH */ +}; + +/* Initialize debug commands. */ +void +eigrp_debug_init () +{ + install_node (&eigrp_debug_node, config_write_debug); + + install_element (ENABLE_NODE, &show_debugging_eigrp_cmd); + install_element (ENABLE_NODE, &debug_eigrp_packets_all_cmd); + install_element (ENABLE_NODE, &no_debug_eigrp_packets_all_cmd); + install_element (ENABLE_NODE, &debug_eigrp_transmit_cmd); + install_element (ENABLE_NODE, &no_debug_eigrp_transmit_cmd); + + install_element (CONFIG_NODE, &show_debugging_eigrp_cmd); + install_element (CONFIG_NODE, &debug_eigrp_packets_all_cmd); + install_element (CONFIG_NODE, &no_debug_eigrp_packets_all_cmd); + install_element (CONFIG_NODE, &no_debug_eigrp_transmit_cmd); +} + + diff --git a/eigrpd/eigrp_dump.h b/eigrpd/eigrp_dump.h new file mode 100644 index 000000000..54e6338a3 --- /dev/null +++ b/eigrpd/eigrp_dump.h @@ -0,0 +1,165 @@ +/* + * EIGRP Dump Functions and Debbuging. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * 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. + */ + +#ifndef _ZEBRA_EIGRPD_DUMP_H_ +#define _ZEBRA_EIGRPD_DUMP_H_ + +#define EIGRP_TIME_DUMP_SIZE 16 + +/* general debug flags */ +extern unsigned long term_debug_eigrp; +#define EIGRP_DEBUG_EVENT 0x01 +#define EIGRP_DEBUG_DETAIL 0x02 +#define EIGRP_DEBUG_TIMERS 0x04 + +/* neighbor debug flags */ +extern unsigned long term_debug_eigrp_nei; +#define EIGRP_DEBUG_NEI 0x01 + +/* packet debug flags */ +extern unsigned long term_debug_eigrp_packet[]; +#define EIGRP_DEBUG_UPDATE 0x01 +#define EIGRP_DEBUG_REQUEST 0x02 +#define EIGRP_DEBUG_QUERY 0x04 +#define EIGRP_DEBUG_REPLY 0x08 +#define EIGRP_DEBUG_HELLO 0x10 +#define EIGRP_DEBUG_PROBE 0x40 +#define EIGRP_DEBUG_ACK 0x80 +#define EIGRP_DEBUG_SIAQUERY 0x200 +#define EIGRP_DEBUG_SIAREPLY 0x400 +#define EIGRP_DEBUG_STUB 0x800 +#define EIGRP_DEBUG_PACKETS_ALL 0xfff + +extern unsigned long term_debug_eigrp_transmit; +#define EIGRP_DEBUG_SEND 0x01 +#define EIGRP_DEBUG_RECV 0x02 +#define EIGRP_DEBUG_SEND_RECV 0x03 +#define EIGRP_DEBUG_PACKET_DETAIL 0x04 + +/* zebra debug flags */ +extern unsigned long term_debug_eigrp_zebra; +#define EIGRP_DEBUG_ZEBRA_INTERFACE 0x01 +#define EIGRP_DEBUG_ZEBRA_REDISTRIBUTE 0x02 +#define EIGRP_DEBUG_ZEBRA 0x03 + +/* Macro for setting debug option. */ +#define CONF_DEBUG_NEI_ON(a, b) conf_debug_eigrp_nei[a] |= (b) +#define CONF_DEBUG_NEI_OFF(a, b) conf_debug_eigrp_nei[a] &= ~(b) +#define TERM_DEBUG_NEI_ON(a, b) term_debug_eigrp_nei[a] |= (b) +#define TERM_DEBUG_NEI_OFF(a, b) term_debug_eigrp_nei[a] &= ~(b) +#define DEBUG_NEI_ON(a, b) \ + do { \ + CONF_DEBUG_NEI_ON(a, b); \ + TERM_DEBUG_NEI_ON(a, b); \ + } while (0) +#define DEBUG_NEI_OFF(a, b) \ + do { \ + CONF_DEBUG_NEI_OFF(a, b); \ + TERM_DEBUG_NEI_OFF(a, b); \ + } while (0) + +#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_eigrp_packet[a] |= (b) +#define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_eigrp_packet[a] &= ~(b) +#define TERM_DEBUG_PACKET_ON(a, b) term_debug_eigrp_packet[a] |= (b) +#define TERM_DEBUG_PACKET_OFF(a, b) term_debug_eigrp_packet[a] &= ~(b) +#define DEBUG_PACKET_ON(a, b) \ + do { \ + CONF_DEBUG_PACKET_ON(a, b); \ + TERM_DEBUG_PACKET_ON(a, b); \ + } while (0) +#define DEBUG_PACKET_OFF(a, b) \ + do { \ + CONF_DEBUG_PACKET_OFF(a, b); \ + TERM_DEBUG_PACKET_OFF(a, b); \ + } while (0) + +#define CONF_DEBUG_TRANSMIT_ON(a, b) conf_debug_eigrp_transmit |= (b) +#define CONF_DEBUG_TRANSMIT_OFF(a, b) conf_debug_eigrp_transmit &= ~(b) +#define TERM_DEBUG_TRANSMIT_ON(a, b) term_debug_eigrp_transmit |= (b) +#define TERM_DEBUG_TRANSMIT_OFF(a, b) term_debug_eigrp_transmit &= ~(b) +#define DEBUG_TRANSMIT_ON(a, b) \ + do { \ + CONF_DEBUG_TRANSMIT_ON(a, b); \ + TERM_DEBUG_TRANSMIT_ON(a, b); \ + } while (0) +#define DEBUG_TRANSMIT_OFF(a, b) \ + do { \ + CONF_DEBUG_TRANSMIT_OFF(a, b); \ + TERM_DEBUG_TRANSMIT_OFF(a, b); \ + } while (0) + +#define CONF_DEBUG_ON(a, b) conf_debug_eigrp_ ## a |= (EIGRP_DEBUG_ ## b) +#define CONF_DEBUG_OFF(a, b) conf_debug_eigrp_ ## a &= ~(EIGRP_DEBUG_ ## b) +#define TERM_DEBUG_ON(a, b) term_debug_eigrp_ ## a |= (EIGRP_DEBUG_ ## b) +#define TERM_DEBUG_OFF(a, b) term_debug_eigrp_ ## a &= ~(EIGRP_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) + +/* Macro for checking debug option. */ +#define IS_DEBUG_EIGRP_PACKET(a, b) \ + (term_debug_eigrp_packet[a] & EIGRP_DEBUG_ ## b) +#define IS_DEBUG_EIGRP_TRANSMIT(a, b) \ + (term_debug_eigrp_transmit & EIGRP_DEBUG_ ## b) +#define IS_DEBUG_EIGRP_NEI(a, b) \ + (term_debug_eigrp_nei & EIGRP_DEBUG_ ## b) +#define IS_DEBUG_EIGRP(a, b) \ + (term_debug_eigrp & EIGRP_DEBUG_ ## b) +#define IS_DEBUG_EIGRP_EVENT IS_DEBUG_EIGRP(event, EVENT) + + +/* Prototypes. */ +extern const char *eigrp_if_name_string (struct eigrp_interface *); +extern const char *eigrp_if_ip_string (struct eigrp_interface *); +extern const char *eigrp_neigh_ip_string (struct eigrp_neighbor *); +extern const char *eigrp_topology_ip_string (struct eigrp_prefix_entry *); + +extern void eigrp_ip_header_dump(struct ip *); +extern void eigrp_header_dump(struct eigrp_header *); + +extern void show_ip_eigrp_interface_header (struct vty *, struct eigrp *); +extern void show_ip_eigrp_neighbor_header (struct vty *, struct eigrp *); +extern void show_ip_eigrp_topology_header (struct vty *, struct eigrp *); +extern void show_ip_eigrp_interface_detail (struct vty *, struct eigrp *, + struct eigrp_interface *); +extern void show_ip_eigrp_interface_sub (struct vty *, struct eigrp *, + struct eigrp_interface *); +extern void show_ip_eigrp_neighbor_sub (struct vty *, struct eigrp_neighbor *, int); +extern void show_ip_eigrp_prefix_entry (struct vty *, struct eigrp_prefix_entry *); +extern void show_ip_eigrp_neighbor_entry (struct vty *, struct eigrp *, struct eigrp_neighbor_entry *); + +extern void eigrp_debug_init (void); + +#endif /* _ZEBRA_EIGRPD_DUMP_H_ */ diff --git a/eigrpd/eigrp_filter.c b/eigrpd/eigrp_filter.c new file mode 100644 index 000000000..aaac379d9 --- /dev/null +++ b/eigrpd/eigrp_filter.c @@ -0,0 +1,395 @@ +/* + * EIGRP Filter Functions. + * Copyright (C) 2013-2015 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "if.h" +#include "command.h" +#include "prefix.h" +#include "table.h" +#include "thread.h" +#include "memory.h" +#include "log.h" +#include "stream.h" +#include "filter.h" +#include "sockunion.h" +#include "sockopt.h" +#include "routemap.h" +#include "if_rmap.h" +#include "plist.h" +#include "distribute.h" +#include "md5.h" +#include "keychain.h" +#include "privs.h" +#include "vrf.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_const.h" +#include "eigrpd/eigrp_filter.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_memory.h" + +/* + * Distribute-list update functions. + */ +void +eigrp_distribute_update (struct distribute *dist) +{ + struct interface *ifp; + struct eigrp_interface *ei = NULL; + struct access_list *alist; + struct prefix_list *plist; + //struct route_map *routemap; + struct eigrp *e; + + /* if no interface address is present, set list to eigrp process struct */ + e = eigrp_lookup(); + + /* Check if distribute-list was set for process or interface */ + if (! dist->ifname) + { + /* access list IN for whole process */ + if (dist->list[DISTRIBUTE_V4_IN]) + { + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_IN]); + zlog_info("<DEBUG DISTRIBUTE ACL IN FOUND: %s",alist->name); + if (alist) + e->list[EIGRP_FILTER_IN] = alist; + else + e->list[EIGRP_FILTER_IN] = NULL; + } + else + { + e->list[EIGRP_FILTER_IN] = NULL; + } + + /* access list OUT for whole process */ + if (dist->list[DISTRIBUTE_V4_OUT]) + { + zlog_info("<DEBUG DISTRIBUTE ACL OUT FOUND: %s",dist->list[DISTRIBUTE_V4_OUT]); + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_OUT]); + if (alist) + e->list[EIGRP_FILTER_OUT] = alist; + else + e->list[EIGRP_FILTER_OUT] = NULL; + } + else + { + e->list[EIGRP_FILTER_OUT] = NULL; + } + + /* PREFIX_LIST IN for process */ + if (dist->prefix[DISTRIBUTE_V4_IN]) + { + zlog_info("<DEBUG DISTRIBUTE PREFIX IN FOUND: %s",dist->prefix[DISTRIBUTE_V4_IN]); + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_IN]); + if (plist) + { + e->prefix[EIGRP_FILTER_IN] = plist; + } + else + e->prefix[EIGRP_FILTER_IN] = NULL; + } else + e->prefix[EIGRP_FILTER_IN] = NULL; + + /* PREFIX_LIST OUT for process */ + if (dist->prefix[DISTRIBUTE_V4_OUT]) + { + zlog_info("<DEBUG DISTRIBUTE PREFIX OUT FOUND: %s",dist->prefix[DISTRIBUTE_V4_OUT]); + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_OUT]); + if (plist) + { + e->prefix[EIGRP_FILTER_OUT] = plist; + + } + else + e->prefix[EIGRP_FILTER_OUT] = NULL; + } + else + e->prefix[EIGRP_FILTER_OUT] = NULL; + + //This is commented out, because the distribute.[ch] code + //changes looked poorly written from first glance + //commit was 133bdf2d + //TODO: DBS +#if 0 + /* route-map IN for whole process */ + if (dist->route[DISTRIBUTE_V4_IN]) + { + routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_IN]); + if (routemap) + e->routemap[EIGRP_FILTER_IN] = routemap; + else + e->routemap[EIGRP_FILTER_IN] = NULL; + } + else + { + e->routemap[EIGRP_FILTER_IN] = NULL; + } + + /* route-map OUT for whole process */ + if (dist->route[DISTRIBUTE_V4_OUT]) + { + routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_OUT]); + if (routemap) + e->routemap[EIGRP_FILTER_OUT] = routemap; + else + e->routemap[EIGRP_FILTER_OUT] = NULL; + } + else + { + e->routemap[EIGRP_FILTER_OUT] = NULL; + } +#endif + //TODO: check Graceful restart after 10sec + + /* check if there is already GR scheduled */ + if(e->t_distribute != NULL) + { + /* if is, cancel schedule */ + thread_cancel(e->t_distribute); + } + /* schedule Graceful restart for whole process in 10sec */ + e->t_distribute = thread_add_timer(master, eigrp_distribute_timer_process, e,(10)); + + return; + } + + ifp = if_lookup_by_name (dist->ifname); + if (ifp == NULL) + return; + + zlog_info("<DEBUG ACL 2"); + + /*struct eigrp_if_info * info = ifp->info; + ei = info->eigrp_interface;*/ + struct listnode *node, *nnode; + struct eigrp_interface *ei2; + /* Find proper interface */ + for (ALL_LIST_ELEMENTS (e->eiflist, node, nnode, ei2)) + { + if(strcmp(ei2->ifp->name,ifp->name) == 0){ + ei = ei2; + break; + } + } + + if(ei == NULL) + { + zlog_info("Not Found eigrp interface %s",ifp->name); + } + + /* Access-list for interface in */ + if (dist->list[DISTRIBUTE_V4_IN]) + { + zlog_info("<DEBUG ACL in"); + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_IN]); + if (alist){ + ei->list[EIGRP_FILTER_IN] = alist; + } + else + ei->list[EIGRP_FILTER_IN] = NULL; + } + else + { + ei->list[EIGRP_FILTER_IN] = NULL; + } + + /* Access-list for interface in */ + if (dist->list[DISTRIBUTE_V4_OUT]) + { + alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_OUT]); + if (alist) + ei->list[EIGRP_FILTER_OUT] = alist; + else + ei->list[EIGRP_FILTER_OUT] = NULL; + + } + else + { + ei->list[EIGRP_FILTER_OUT] = NULL; + zlog_info("<DEBUG ACL out else"); + } + + /* Prefix-list for interface in */ + if (dist->prefix[DISTRIBUTE_V4_IN]) + { + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_IN]); + if (plist) + ei->prefix[EIGRP_FILTER_IN] = plist; + else + ei->prefix[EIGRP_FILTER_IN] = NULL; + } + else + ei->prefix[EIGRP_FILTER_IN] = NULL; + + /* Prefix-list for interface out */ + if (dist->prefix[DISTRIBUTE_V4_OUT]) + { + plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_OUT]); + if (plist) + ei->prefix[EIGRP_FILTER_OUT] = plist; + else + ei->prefix[EIGRP_FILTER_OUT] = NULL; + } + else + ei->prefix[EIGRP_FILTER_OUT] = NULL; + +#if 0 + /* route-map IN for whole process */ + if (dist->route[DISTRIBUTE_V4_IN]) + { + zlog_info("<DEBUG ACL ALL in"); + routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_IN]); + if (routemap) + ei->routemap[EIGRP_FILTER_IN] = routemap; + else + ei->routemap[EIGRP_FILTER_IN] = NULL; + } + else + { + ei->routemap[EIGRP_FILTER_IN] = NULL; + } + + /* route-map OUT for whole process */ + if (dist->route[DISTRIBUTE_V4_OUT]) + { + routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_OUT]); + if (routemap) + ei->routemap[EIGRP_FILTER_OUT] = routemap; + else + ei->routemap[EIGRP_FILTER_OUT] = NULL; + } + else + { + ei->routemap[EIGRP_FILTER_OUT] = NULL; + } +#endif + //TODO: check Graceful restart after 10sec + + /* check if there is already GR scheduled */ + if(ei->t_distribute != NULL) + { + /* if is, cancel schedule */ + thread_cancel(ei->t_distribute); + } + /* schedule Graceful restart for interface in 10sec */ + e->t_distribute = thread_add_timer(master, eigrp_distribute_timer_interface, ei,(10)); + +} + +/* + * Function called by prefix-list and access-list update + */ +void +eigrp_distribute_update_interface (struct interface *ifp) +{ + struct distribute *dist; + + dist = distribute_lookup (ifp->name); + if (dist) + eigrp_distribute_update (dist); +} + +/* Update all interface's distribute list. + * Function used in hook for prefix-list + */ +void +eigrp_distribute_update_all (struct prefix_list *notused) +{ + struct interface *ifp; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS (vrf_iflist(VRF_DEFAULT), node, nnode, ifp)) + eigrp_distribute_update_interface (ifp); +} + +/* + * Function used in hook for acces-list + */ +void +eigrp_distribute_update_all_wrapper(struct access_list *notused) +{ + eigrp_distribute_update_all(NULL); +} + +/* + * @fn eigrp_distribute_timer_process + * + * @param[in] thread current execution thread timer is associated with + * + * @return int always returns 0 + * + * @par + * Called when 10sec waiting time expire and + * executes Graceful restart for whole process + */ +int +eigrp_distribute_timer_process (struct thread *thread) +{ + struct eigrp *eigrp; + + eigrp = THREAD_ARG(thread); + eigrp->t_distribute = NULL; + + /* execute GR for whole process */ + eigrp_update_send_process_GR(eigrp, EIGRP_GR_FILTER, NULL); + + return 0; +} + +/* + * @fn eigrp_distribute_timer_interface + * + * @param[in] thread current execution thread timer is associated with + * + * @return int always returns 0 + * + * @par + * Called when 10sec waiting time expire and + * executes Graceful restart for interface + */ +int +eigrp_distribute_timer_interface (struct thread *thread) +{ + struct eigrp_interface *ei; + + ei = THREAD_ARG(thread); + ei->t_distribute = NULL; + + /* execute GR for interface */ + eigrp_update_send_interface_GR(ei, EIGRP_GR_FILTER, NULL); + + return 0; +} diff --git a/eigrpd/eigrp_filter.h b/eigrpd/eigrp_filter.h new file mode 100644 index 000000000..01c776b17 --- /dev/null +++ b/eigrpd/eigrp_filter.h @@ -0,0 +1,44 @@ +/* + * EIGRP Filter Functions. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * + * 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. + */ + +#ifndef EIGRPD_EIGRP_FILTER_H_ +#define EIGRPD_EIGRP_FILTER_H_ + +extern void eigrp_distribute_update (struct distribute *); +extern void eigrp_distribute_update_interface (struct interface *); +extern void eigrp_distribute_update_all (struct prefix_list *); +extern void eigrp_distribute_update_all_wrapper(struct access_list *); +extern int eigrp_distribute_timer_process (struct thread *); +extern int eigrp_distribute_timer_interface (struct thread *); + +#endif /* EIGRPD_EIGRP_FILTER_H_ */ diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c new file mode 100644 index 000000000..0277dc830 --- /dev/null +++ b/eigrpd/eigrp_fsm.c @@ -0,0 +1,502 @@ +/* + * EIGRPd Finite State Machine (DUAL). + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * 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. + * + * + * This file contains functions for executing logic of finite state machine + * + * +------------ + + * | (7) | + * | v + * +=====================================+ + * | | + * | Passive | + * | | + * +=====================================+ + * ^ | ^ ^ ^ | + * (3)| | (1)| | (1)| | + * | (0)| | (3)| | (2)| + * | | | | | +---------------+ + * | | | | | \ + * +--------+ | | | +-----------------+ \ + * / / / | \ \ + * / / / +----+ \ \ + * | | | | | | + * | v | | | v + * +===========+ (6) +===========+ +===========+ (6) +===========+ + * | |------->| | (5) | |-------->| | + * | | (4) | |------>| | (4) | | + * | ACTIVE 0 |<-------| ACTIVE 1 | | ACTIVE 2 |<--------| ACTIVE 3 | + * +--| | +--| | +--| | +--| | + * | +===========+ | +===========+ | +===========+ | +===========+ + * | ^ |(5) | ^ | ^ ^ | ^ + * | | +---------|------|------------|----+ | | | + * +-------+ +------+ +---------+ +---------+ + * (7) (7) (7) (7) + * + * 0- input event other than query from successor, FC not satisfied + * 1- last reply, FD is reset + * 2- query from successor, FC not satisfied + * 3- last reply, FC satisfied with current value of FDij + * 4- distance increase while in active state + * 5- query from successor while in active state + * 6- last reply, FC not satisfied with current value of FDij + * 7- state not changed, usually by receiving not last reply + * + */ + +#include <thread.h> +#include <zebra.h> + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "log.h" +#include "linklist.h" +#include "vty.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_fsm.h" + +/* + * Prototypes + */ +int +eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *); +int +eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *); +int +eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *); +int +eigrp_fsm_event_lr(struct eigrp_fsm_action_message *); +int +eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *); +int +eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *); +int +eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *); +int +eigrp_fsm_event_qact(struct eigrp_fsm_action_message *); + +//--------------------------------------------------------------------- + +/* + * NSM - field of fields of struct containing one function each. + * Which function is used depends on actual state of FSM and occurred + * event(arrow in diagram). Usage: + * NSM[actual/starting state][occurred event].func + * Functions are should be executed within separate thread. + */ +struct { + int + (*func)(struct eigrp_fsm_action_message *); +} NSM[EIGRP_FSM_STATE_MAX][EIGRP_FSM_EVENT_MAX] = { { +//PASSIVE STATE + { eigrp_fsm_event_nq_fcn }, /* Event 0 */ + { eigrp_fsm_event_keep_state }, /* Event 1 */ + { eigrp_fsm_event_q_fcn }, /* Event 2 */ + { eigrp_fsm_event_keep_state }, /* Event 3 */ + { eigrp_fsm_event_keep_state }, /* Event 4 */ + { eigrp_fsm_event_keep_state }, /* Event 5 */ + { eigrp_fsm_event_keep_state }, /* Event 6 */ + { eigrp_fsm_event_keep_state }, /* Event 7 */ +}, { +//Active 0 state + { eigrp_fsm_event_keep_state }, /* Event 0 */ + { eigrp_fsm_event_keep_state }, /* Event 1 */ + { eigrp_fsm_event_keep_state }, /* Event 2 */ + { eigrp_fsm_event_lr_fcs }, /* Event 3 */ + { eigrp_fsm_event_keep_state }, /* Event 4 */ + { eigrp_fsm_event_qact }, /* Event 5 */ + { eigrp_fsm_event_lr_fcn }, /* Event 6 */ + { eigrp_fsm_event_keep_state }, /* Event 7 */ + +}, { +//Active 1 state + { eigrp_fsm_event_keep_state }, /* Event 0 */ + { eigrp_fsm_event_lr }, /* Event 1 */ + { eigrp_fsm_event_keep_state }, /* Event 2 */ + { eigrp_fsm_event_keep_state }, /* Event 3 */ + { eigrp_fsm_event_dinc }, /* Event 4 */ + { eigrp_fsm_event_qact }, /* Event 5 */ + { eigrp_fsm_event_keep_state }, /* Event 6 */ + { eigrp_fsm_event_keep_state }, /* Event 7 */ +}, { +//Active 2 state + { eigrp_fsm_event_keep_state }, /* Event 0 */ + { eigrp_fsm_event_keep_state }, /* Event 1 */ + { eigrp_fsm_event_keep_state }, /* Event 2 */ + { eigrp_fsm_event_lr_fcs }, /* Event 3 */ + { eigrp_fsm_event_keep_state }, /* Event 4 */ + { eigrp_fsm_event_keep_state }, /* Event 5 */ + { eigrp_fsm_event_lr_fcn }, /* Event 6 */ + { eigrp_fsm_event_keep_state }, /* Event 7 */ +}, { +//Active 3 state + { eigrp_fsm_event_keep_state }, /* Event 0 */ + { eigrp_fsm_event_lr }, /* Event 1 */ + { eigrp_fsm_event_keep_state }, /* Event 2 */ + { eigrp_fsm_event_keep_state }, /* Event 3 */ + { eigrp_fsm_event_dinc }, /* Event 4 */ + { eigrp_fsm_event_keep_state }, /* Event 5 */ + { eigrp_fsm_event_keep_state }, /* Event 6 */ + { eigrp_fsm_event_keep_state }, /* Event 7 */ +}, }; + +/* + * Main function in which are make decisions which event occurred. + * msg - argument of type struct eigrp_fsm_action_message contain + * details about what happen + * + * Return number of occurred event (arrow in diagram). + * + */ +int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) { + // Loading base information from message + //struct eigrp *eigrp = msg->eigrp; + struct eigrp_prefix_entry *prefix = msg->prefix; + struct eigrp_neighbor_entry *entry = msg->entry; + u_char actual_state = prefix->state; + + if (entry == NULL) { + entry = eigrp_neighbor_entry_new(); + entry->adv_router = msg->adv_router; + entry->ei = msg->adv_router->ei; + entry->prefix = prefix; + msg->entry = entry; + } + + // Dividing by actual state of prefix's FSM + switch (actual_state) { + case EIGRP_FSM_STATE_PASSIVE: { + //Calculate resultant metrics and insert to correct position in entries list + eigrp_topology_update_distance(msg); + + struct eigrp_neighbor_entry * head = + (struct eigrp_neighbor_entry *) entry->prefix->entries->head->data; + //zlog_info ("flag: %d rdist: %u dist: %u pfdist: %u pdist: %u", head->flags, head->reported_distance, head->distance, prefix->fdistance, prefix->distance); + if (head->reported_distance < prefix->fdistance) { + return EIGRP_FSM_KEEP_STATE; + } + /* + * if best entry doesn't satisfy feasibility condition it means move to active state + * dependently if it was query from successor + */ + else { + if (msg->packet_type == EIGRP_OPC_QUERY) { + return EIGRP_FSM_EVENT_Q_FCN; + } else { + return EIGRP_FSM_EVENT_NQ_FCN; + } + } + + break; + } + case EIGRP_FSM_STATE_ACTIVE_0: { + eigrp_topology_update_distance(msg); + + if (msg->packet_type == EIGRP_OPC_REPLY) { + listnode_delete(prefix->rij, entry->adv_router); + if (prefix->rij->count) { + return EIGRP_FSM_KEEP_STATE; + } else { + zlog_info("All reply received\n"); + if (((struct eigrp_neighbor_entry *) prefix->entries->head->data)->reported_distance + < prefix->fdistance) { + return EIGRP_FSM_EVENT_LR_FCS; + } + + return EIGRP_FSM_EVENT_LR_FCN; + } + } else if (msg->packet_type == EIGRP_OPC_QUERY + && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) { + return EIGRP_FSM_EVENT_QACT; + } + + return EIGRP_FSM_KEEP_STATE; + + break; + } + case EIGRP_FSM_STATE_ACTIVE_1: { + int change = eigrp_topology_update_distance(msg); + + if (msg->packet_type == EIGRP_OPC_QUERY + && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) { + return EIGRP_FSM_EVENT_QACT; + } else if (msg->packet_type == EIGRP_OPC_REPLY) { + listnode_delete(prefix->rij, entry->adv_router); + + if (change == 1 + && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) { + return EIGRP_FSM_EVENT_DINC; + } else if (prefix->rij->count) { + return EIGRP_FSM_KEEP_STATE; + } else { + zlog_info("All reply received\n"); + return EIGRP_FSM_EVENT_LR; + } + } else if (msg->packet_type == EIGRP_OPC_UPDATE && change == 1 + && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) { + return EIGRP_FSM_EVENT_DINC; + } + return EIGRP_FSM_KEEP_STATE; + + break; + } + case EIGRP_FSM_STATE_ACTIVE_2: { + + eigrp_topology_update_distance(msg); + + if (msg->packet_type == EIGRP_OPC_REPLY) { + listnode_delete(prefix->rij, entry->adv_router); + if (prefix->rij->count) { + return EIGRP_FSM_KEEP_STATE; + } else { + zlog_info("All reply received\n"); + if (((struct eigrp_neighbor_entry *) prefix->entries->head->data)->reported_distance + < prefix->fdistance) { + return EIGRP_FSM_EVENT_LR_FCS; + } + + return EIGRP_FSM_EVENT_LR_FCN; + } + } + return EIGRP_FSM_KEEP_STATE; + + break; + } + case EIGRP_FSM_STATE_ACTIVE_3: { + + int change = eigrp_topology_update_distance(msg); + + if (msg->packet_type == EIGRP_OPC_REPLY) { + listnode_delete(prefix->rij, entry->adv_router); + + if (change == 1 + && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) { + return EIGRP_FSM_EVENT_DINC; + } else if (prefix->rij->count) { + return EIGRP_FSM_KEEP_STATE; + } else { + zlog_info("All reply received\n"); + return EIGRP_FSM_EVENT_LR; + } + } else if (msg->packet_type == EIGRP_OPC_UPDATE && change == 1 + && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) { + return EIGRP_FSM_EVENT_DINC; + } + return EIGRP_FSM_KEEP_STATE; + + break; + } + } + + return EIGRP_FSM_KEEP_STATE; +} + +/* + * Function made to execute in separate thread. + * Load argument from thread and execute proper NSM function + */ +int eigrp_fsm_event(struct eigrp_fsm_action_message *msg, int event) { + + zlog_info("EIGRP AS: %d State: %d Event: %d Network: %s\n", msg->eigrp->AS, + msg->prefix->state, event, eigrp_topology_ip_string(msg->prefix)); + (*(NSM[msg->prefix->state][event].func))(msg); + + return 1; +} +/* + * Function of event 0. + * + */ +int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg) { + struct eigrp *eigrp = msg->eigrp; + struct eigrp_prefix_entry *prefix = msg->prefix; + struct list *successors = eigrp_topology_get_successor(prefix); + prefix->state = EIGRP_FSM_STATE_ACTIVE_1; + prefix->rdistance = prefix->distance = prefix->fdistance = + ((struct eigrp_neighbor_entry *) successors->head->data)->distance; + prefix->reported_metric = + ((struct eigrp_neighbor_entry *) successors->head->data)->total_metric; + + if (eigrp_nbr_count_get()) { + prefix->req_action |= EIGRP_FSM_NEED_QUERY; + listnode_add(eigrp->topology_changes_internalIPV4,prefix); + } else { + eigrp_fsm_event_lr(msg); //in the case that there are no more neighbors left + } + + return 1; +} + +int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg) { + struct eigrp *eigrp = msg->eigrp; + struct eigrp_prefix_entry *prefix = msg->prefix; + struct list *successors = eigrp_topology_get_successor(prefix); + prefix->state = EIGRP_FSM_STATE_ACTIVE_3; + prefix->rdistance = prefix->distance = prefix->fdistance = + ((struct eigrp_neighbor_entry *) successors->head->data)->distance; + prefix->reported_metric = + ((struct eigrp_neighbor_entry *) successors->head->data)->total_metric; + if (eigrp_nbr_count_get()) { + prefix->req_action |= EIGRP_FSM_NEED_QUERY; + listnode_add(eigrp->topology_changes_internalIPV4,prefix); + } else { + eigrp_fsm_event_lr(msg); //in the case that there are no more neighbors left + } + + return 1; +} + +int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg) { + + struct eigrp_prefix_entry *prefix = msg->prefix; + + if (prefix->state == EIGRP_FSM_STATE_PASSIVE) { + if (!eigrp_metrics_is_same(&prefix->reported_metric, + &((struct eigrp_neighbor_entry *) prefix->entries->head->data)->total_metric)) { + prefix->rdistance = + prefix->fdistance = + prefix->distance = + ((struct eigrp_neighbor_entry *) prefix->entries->head->data)->distance; + prefix->reported_metric = + ((struct eigrp_neighbor_entry *) prefix->entries->head->data)->total_metric; + if (msg->packet_type == EIGRP_OPC_QUERY) + eigrp_send_reply(msg->adv_router, prefix); + prefix->req_action |= EIGRP_FSM_NEED_UPDATE; + listnode_add((eigrp_lookup())->topology_changes_internalIPV4,prefix); + } + eigrp_topology_update_node_flags(prefix); + eigrp_update_routing_table(prefix); + } + + if (msg->packet_type == EIGRP_OPC_QUERY) + eigrp_send_reply(msg->adv_router, prefix); + + return 1; +} + +int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg) { + struct eigrp *eigrp = msg->eigrp; + struct eigrp_prefix_entry *prefix = msg->prefix; + prefix->fdistance = + prefix->distance = + prefix->rdistance = + ((struct eigrp_neighbor_entry *) (prefix->entries->head->data))->distance; + prefix->reported_metric = + ((struct eigrp_neighbor_entry *) (prefix->entries->head->data))->total_metric; + if (prefix->state == EIGRP_FSM_STATE_ACTIVE_3) + eigrp_send_reply( + ((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor( + prefix)->head->data))->adv_router, prefix); + prefix->state = EIGRP_FSM_STATE_PASSIVE; + prefix->req_action |= EIGRP_FSM_NEED_UPDATE; + listnode_add(eigrp->topology_changes_internalIPV4,prefix); + eigrp_topology_update_node_flags(prefix); + eigrp_update_routing_table(prefix); + eigrp_update_topology_table_prefix(eigrp->topology_table, prefix); + + return 1; +} + +int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg) { + + msg->prefix->state = + msg->prefix->state == EIGRP_FSM_STATE_ACTIVE_1 ? + EIGRP_FSM_STATE_ACTIVE_0 : EIGRP_FSM_STATE_ACTIVE_2; + msg->prefix->distance = + ((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor( + msg->prefix)->head->data))->distance; + if (!msg->prefix->rij->count) { + (*(NSM[msg->prefix->state][eigrp_get_fsm_event(msg)].func))(msg); + } + + return 1; +} + +int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg) { + struct eigrp *eigrp = msg->eigrp; + struct eigrp_prefix_entry *prefix = msg->prefix; + prefix->state = EIGRP_FSM_STATE_PASSIVE; + prefix->distance = + prefix->rdistance = + ((struct eigrp_neighbor_entry *) (prefix->entries->head->data))->distance; + prefix->reported_metric = + ((struct eigrp_neighbor_entry *) (prefix->entries->head->data))->total_metric; + prefix->fdistance = + prefix->fdistance > prefix->distance ? + prefix->distance : prefix->fdistance; + if (prefix->state == EIGRP_FSM_STATE_ACTIVE_2) + eigrp_send_reply( + ((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor( + prefix)->head->data))->adv_router, prefix); + prefix->req_action |= EIGRP_FSM_NEED_UPDATE; + listnode_add(eigrp->topology_changes_internalIPV4,prefix); + eigrp_topology_update_node_flags(prefix); + eigrp_update_routing_table(prefix); + eigrp_update_topology_table_prefix(eigrp->topology_table, prefix); + + return 1; +} + +int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg) { + struct eigrp *eigrp = msg->eigrp; + struct eigrp_prefix_entry *prefix = msg->prefix; + prefix->state = + prefix->state == EIGRP_FSM_STATE_ACTIVE_0 ? + EIGRP_FSM_STATE_ACTIVE_1 : EIGRP_FSM_STATE_ACTIVE_3; + struct eigrp_neighbor_entry *best_successor = + ((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor( + prefix)->head->data)); + prefix->rdistance = prefix->distance = best_successor->distance; + prefix->reported_metric = best_successor->total_metric; + if (eigrp_nbr_count_get()) { + prefix->req_action |= EIGRP_FSM_NEED_QUERY; + listnode_add(eigrp->topology_changes_internalIPV4,prefix); + } else { + eigrp_fsm_event_lr(msg); //in the case that there are no more neighbors left + } + + return 1; +} + +int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg) { + msg->prefix->state = EIGRP_FSM_STATE_ACTIVE_2; + msg->prefix->distance = + ((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor( + msg->prefix)->head->data))->distance; + return 1; +} diff --git a/eigrpd/eigrp_fsm.h b/eigrpd/eigrp_fsm.h new file mode 100644 index 000000000..0677c09d7 --- /dev/null +++ b/eigrpd/eigrp_fsm.h @@ -0,0 +1,37 @@ +/* + * EIGRP Finite State Machine (DUAL). + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * 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. + */ + +#ifndef _ZEBRA_EIGRP_FSM_H +#define _ZEBRA_EIGRP_FSM_H + + +extern int eigrp_get_fsm_event (struct eigrp_fsm_action_message *); +extern int eigrp_fsm_event (struct eigrp_fsm_action_message *, int); + + +#endif /* _ZEBRA_EIGRP_DUAL_H */ diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c new file mode 100644 index 000000000..df4ed1069 --- /dev/null +++ b/eigrpd/eigrp_hello.c @@ -0,0 +1,774 @@ +/* + * EIGRP Sending and Receiving EIGRP Hello Packets. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "sockunion.h" +#include "stream.h" +#include "log.h" +#include "sockopt.h" +#include "checksum.h" +#include "vty.h" +#include "md5.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_macros.h" + +/* Packet Type String. */ +static const struct message eigrp_general_tlv_type_str[] = +{ + { EIGRP_TLV_PARAMETER, "PARAMETER" }, + { EIGRP_TLV_AUTH, "AUTH" }, + { EIGRP_TLV_SEQ, "SEQ" }, + { EIGRP_TLV_SW_VERSION, "SW_VERSION" }, + { EIGRP_TLV_NEXT_MCAST_SEQ, "NEXT_MCAST_SEQ" }, + { EIGRP_TLV_PEER_TERMINATION, "PEER_TERMINATION" }, + { EIGRP_TLV_PEER_MTRLIST, "PEER_MTRLIST" }, + { EIGRP_TLV_PEER_TIDLIST, "PEER_TIDLIST" }, +}; + +static const size_t eigrp_general_tlv_type_str_max = sizeof(eigrp_general_tlv_type_str) / + sizeof(eigrp_general_tlv_type_str[0]); + + +/* + * @fn eigrp_hello_timer + * + * @param[in] thread current execution thread timer is associated with + * + * @return int always returns 0 + * + * @par + * Called once per "hello" time interval, default 5 seconds + * Sends hello packet via multicast for all interfaces eigrp + * is configured for + */ +int +eigrp_hello_timer (struct thread *thread) +{ + struct eigrp_interface *ei; + + ei = THREAD_ARG(thread); + ei->t_hello = NULL; + + if (IS_DEBUG_EIGRP(0, TIMERS)) + zlog (NULL, LOG_DEBUG, "Start Hello Timer (%s) Expire [%u]", + IF_NAME(ei), EIGRP_IF_PARAM(ei, v_hello)); + + /* Sending hello packet. */ + eigrp_hello_send(ei, EIGRP_HELLO_NORMAL, NULL); + + /* Hello timer set. */ + ei->t_hello = thread_add_timer(master, eigrp_hello_timer, ei, + EIGRP_IF_PARAM(ei, v_hello)); + + return 0; +} + +/** + * @fn eigrp_hello_parameter_decode + * + * @param[in] nbr neighbor the ACK should be sent to + * @param[in] param pointer packet TLV is stored to + * + * @return u_int16_t number of bytes added to packet stream + * + * @par + * Encode Parameter TLV, used to convey metric weights and the hold time. + * + * @usage + * Note the addition of K6 for the new extended metrics, and does not apply to + * older TLV packet formats. + */ +static void +eigrp_hello_parameter_decode (struct eigrp_neighbor *nbr, + struct eigrp_tlv_hdr_type *tlv) +{ + struct eigrp *eigrp = nbr->ei->eigrp; + struct TLV_Parameter_Type *param = (struct TLV_Parameter_Type *)tlv; + + /* copy over the values passed in by the neighbor */ + nbr->K1 = param->K1; + nbr->K2 = param->K2; + nbr->K3 = param->K3; + nbr->K4 = param->K4; + nbr->K5 = param->K5; + nbr->K6 = param->K6; + nbr->v_holddown = ntohs(param->hold_time); + + /* + * Check K1-K5 have the correct values to be able to become neighbors + * K6 does not have to match + */ + if ((eigrp->k_values[0] == nbr->K1) && + (eigrp->k_values[1] == nbr->K2) && + (eigrp->k_values[2] == nbr->K3) && + (eigrp->k_values[3] == nbr->K4) && + (eigrp->k_values[4] == nbr->K5)) + { + + if (eigrp_nbr_state_get(nbr) == EIGRP_NEIGHBOR_DOWN) + { + zlog_info("Neighbor %s (%s) is pending: new adjacency", + inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex)); + + /* Expedited hello sent */ + eigrp_hello_send(nbr->ei, EIGRP_HELLO_NORMAL, NULL); + +// if(ntohl(nbr->ei->address->u.prefix4.s_addr) > ntohl(nbr->src.s_addr)) + eigrp_update_send_init(nbr); + + eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING); + } + } + else + { + if (eigrp_nbr_state_get(nbr) != EIGRP_NEIGHBOR_DOWN) + { + if ((param->K1 & param->K2 & param->K3 & param->K4 & param->K5) == 255) + { + zlog_info ("Neighbor %s (%s) is down: Interface PEER-TERMINATION received", + inet_ntoa (nbr->src),ifindex2ifname (nbr->ei->ifp->ifindex)); + eigrp_nbr_delete (nbr); + } + else + { + zlog_info ("Neighbor %s (%s) going down: Kvalue mismatch", + inet_ntoa (nbr->src),ifindex2ifname (nbr->ei->ifp->ifindex)); + eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN); + } + } + } +} + +static u_char +eigrp_hello_authentication_decode(struct stream *s, struct eigrp_tlv_hdr_type *tlv_header, struct eigrp_neighbor *nbr) +{ + + struct TLV_MD5_Authentication_Type *md5; + + md5 = (struct TLV_MD5_Authentication_Type *) tlv_header; + + if(md5->auth_type == EIGRP_AUTH_TYPE_MD5) + return eigrp_check_md5_digest(s, md5, nbr, EIGRP_AUTH_BASIC_HELLO_FLAG); + else if (md5->auth_type == EIGRP_AUTH_TYPE_SHA256) + return eigrp_check_sha256_digest(s, (struct TLV_SHA256_Authentication_Type *) tlv_header, nbr, EIGRP_AUTH_BASIC_HELLO_FLAG); + + return 0; +} + +/** + * @fn eigrp_sw_version_decode + * + * @param[in] nbr neighbor the ACK shoudl be sent to + * @param[in] param pointer to TLV software version information + * + * @return void + * + * @par + * Read the software version in the specified location. + * This consists of two bytes of OS version, and two bytes of EIGRP + * revision number. + */ +static void +eigrp_sw_version_decode (struct eigrp_neighbor *nbr, + struct eigrp_tlv_hdr_type *tlv) +{ + struct TLV_Software_Type *version = (struct TLV_Software_Type *)tlv; + + nbr->os_rel_major = version->vender_major; + nbr->os_rel_minor = version->vender_minor; + nbr->tlv_rel_major = version->eigrp_major; + nbr->tlv_rel_minor = version->eigrp_minor; + return; +} + +/** + * @fn eigrp_peer_termination_decode + * + * @param[in] nbr neighbor the ACK shoudl be sent to + * @param[in] tlv pointer to TLV software version information + * + * @return void + * + * @par + * Read the address in the TLV and match to out address. If + * a match is found, move the sending neighbor to the down state. If + * out address is not in the TLV, then ignore the peer termination + */ +static void +eigrp_peer_termination_decode (struct eigrp_neighbor *nbr, + struct eigrp_tlv_hdr_type *tlv) +{ + struct TLV_Peer_Termination_type *param = (struct TLV_Peer_Termination_type *)tlv; + + uint32_t my_ip = nbr->ei->address->u.prefix4.s_addr; + uint32_t received_ip = param->neighbor_ip; + + if(my_ip == received_ip) + { + zlog_info ("Neighbor %s (%s) is down: Peer Termination received", + inet_ntoa (nbr->src),ifindex2ifname (nbr->ei->ifp->ifindex)); + /* set neighbor to DOWN */ + nbr->state = EIGRP_NEIGHBOR_DOWN; + /* delete neighbor */ + eigrp_nbr_delete (nbr); + } +} + +/** + * @fn eigrp_peer_termination_encode + * + * @param[in,out] s packet stream TLV is stored to + * @param[in] nbr_addr pointer to neighbor address for Peer Termination TLV + * + * @return u_int16_t number of bytes added to packet stream + * + * @par + * Function used to encode Peer Termination TLV to Hello packet. + */ +static u_int16_t +eigrp_peer_termination_encode (struct stream *s, struct in_addr *nbr_addr) +{ + u_int16_t length = EIGRP_TLV_PEER_TERMINATION_LEN; + + /* fill in type and length */ + stream_putw(s, EIGRP_TLV_PEER_TERMINATION); + stream_putw(s, length); + + /* fill in unknown field 0x04 */ + stream_putc(s, 0x04); + + /* finally neighbor IP address */ + stream_put_ipv4(s, nbr_addr->s_addr); + + return(length); +} + +/* + * @fn eigrp_hello_receive + * + * @param[in] eigrp eigrp routing process + * @param[in] iph pointer to ip header + * @param[in] eigrph pointer to eigrp header + * @param[in] s input ip stream + * @param[in] ei eigrp interface packet arrived on + * @param[in] size size of eigrp packet + * + * @return void + * + * @par + * This is the main worker function for processing hello packets. It + * will validate the peer associated with the src ip address of the ip + * header, and then decode each of the general TLVs which the packet + * may contain. + * + * @usage + * Not all TLVs are current decoder. This is a work in progress.. + */ +void +eigrp_hello_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph, + struct stream *s, struct eigrp_interface *ei, int size) +{ + struct eigrp_tlv_hdr_type *tlv_header; + struct eigrp_neighbor *nbr; + uint16_t type; + uint16_t length; + + /* get neighbor struct */ + nbr = eigrp_nbr_get(ei, eigrph, iph); + + /* neighbor must be valid, eigrp_nbr_get creates if none existed */ + assert(nbr); + + if (IS_DEBUG_EIGRP_PACKET(eigrph->opcode - 1, RECV)) + zlog_debug("Processing Hello size[%u] int(%s) nbr(%s)", + size, ifindex2ifname(nbr->ei->ifp->ifindex), + inet_ntoa(nbr->src)); + + size -= EIGRP_HEADER_LEN; + if (size < 0) + return; + + tlv_header = (struct eigrp_tlv_hdr_type *)eigrph->tlv; + + do { + type = ntohs(tlv_header->type); + length = ntohs(tlv_header->length); + + if ((length > 0) && (length <= size)) + { + if (IS_DEBUG_EIGRP_PACKET(0, RECV)) + zlog_debug(" General TLV(%s)", LOOKUP(eigrp_general_tlv_type_str, type)); + + // determine what General TLV is being processed + switch (type) + { + case EIGRP_TLV_PARAMETER: + eigrp_hello_parameter_decode(nbr, tlv_header); + break; + case EIGRP_TLV_AUTH: + { + if(eigrp_hello_authentication_decode(s,tlv_header,nbr) == 0) + return; + else + break; + break; + } + case EIGRP_TLV_SEQ: + break; + case EIGRP_TLV_SW_VERSION: + eigrp_sw_version_decode(nbr, tlv_header); + break; + case EIGRP_TLV_NEXT_MCAST_SEQ: + break; + case EIGRP_TLV_PEER_TERMINATION: + eigrp_peer_termination_decode(nbr, tlv_header); + break; + case EIGRP_TLV_PEER_MTRLIST: + case EIGRP_TLV_PEER_TIDLIST: + break; + default: + break; + } + } + + tlv_header = (struct eigrp_tlv_hdr_type *)(((char *)tlv_header) + length); + size -= length; + + } while (size > 0); + + + /*If received packet is hello with Parameter TLV*/ + if (ntohl(eigrph->ack) == 0) + { + /* increment statistics. */ + ei->hello_in++; + eigrp_nbr_state_update(nbr); + + } + + if (IS_DEBUG_EIGRP_PACKET(0, RECV)) + zlog_debug("Hello Packet received from %s", inet_ntoa(nbr->src)); + +} + +/** + * @fn eigrp_sw_version_encode + * + * @param[in,out] s packet stream TLV is stored to + * + * @return u_int16_t number of bytes added to packet stream + * + * @par + * Store the software version in the specified location. + * This consists of two bytes of OS version, and two bytes of EIGRP + * revision number. + */ +static u_int16_t +eigrp_sw_version_encode (struct stream *s) +{ + u_int16_t length = EIGRP_TLV_SW_VERSION_LEN; + + // setup the tlv fields + stream_putw(s, EIGRP_TLV_SW_VERSION); + stream_putw(s, length); + + // encode the version of quagga we're running + // DVS: need to figure out a cleaner way to do this + stream_putc(s, 0); //!< major os version + stream_putc(s, 99); //!< minor os version + + /* and the core eigrp version */ + stream_putc(s, EIGRP_MAJOR_VERSION); + stream_putc(s, EIGRP_MINOR_VERSION); + + return(length); +} + +/** + * @fn eigrp_tidlist_encode + * + * @param[in,out] s packet stream TLV is stored to + * + * @return void + * + * @par + * If doing mutli-topology, then store the supported TID list. + * This is currently a place holder function + */ +static u_int16_t +eigrp_tidlist_encode (struct stream *s) +{ + //u_int16_t length = EIGRP_TLV_SW_VERSION_LEN; + return 0; +} + +/** + * @fn eigrp_sequence_encode + * + * @param[in,out] s packet stream TLV is stored to + * + * @return u_int16_t number of bytes added to packet stream + * + * @par + * Part of conditional receive process + * + */ +static u_int16_t +eigrp_sequence_encode (struct stream *s) +{ + u_int16_t length = EIGRP_TLV_SEQ_BASE_LEN; + struct eigrp *eigrp; + struct eigrp_interface *ei; + struct listnode *node, *node2, *nnode2; + struct eigrp_neighbor *nbr; + size_t backup_end, size_end; + int found; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + return 0; + } + + // add in the parameters TLV + backup_end = stream_get_endp(s); + stream_putw(s, EIGRP_TLV_SEQ); + size_end = s->endp; + stream_putw(s, 0x0000); + stream_putc(s, IPV4_MAX_BYTELEN); + + found = 0; + for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei)) + { + for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr)) + { + if(nbr->multicast_queue->count > 0) + { + length += (u_int16_t) stream_put_ipv4(s,nbr->src.s_addr); + found = 1; + } + } + } + + if(found == 0) + { + stream_set_endp(s,backup_end); + return 0; + } + + backup_end = stream_get_endp (s); + stream_set_endp (s,size_end); + stream_putw (s, length); + stream_set_endp (s, backup_end); + + return length; +} + +/** + * @fn eigrp_sequence_encode + * + * @param[in,out] s packet stream TLV is stored to + * + * @return u_int16_t number of bytes added to packet stream + * + * @par + * Part of conditional receive process + * + */ +static u_int16_t +eigrp_next_sequence_encode (struct stream *s) +{ + u_int16_t length = EIGRP_NEXT_SEQUENCE_TLV_SIZE; + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + return 0; + } + + // add in the parameters TLV + stream_putw(s, EIGRP_TLV_NEXT_MCAST_SEQ); + stream_putw(s, EIGRP_NEXT_SEQUENCE_TLV_SIZE); + stream_putl(s,eigrp->sequence_number+1); + + return length; +} + +/** + * @fn eigrp_hello_parameter_encode + * + * @param[in] ei pointer to interface hello packet came in on + * @param[in,out] s packet stream TLV is stored to + * + * @return u_int16_t number of bytes added to packet stream + * + * @par + * Encode Parameter TLV, used to convey metric weights and the hold time. + * + * @usage + * Note the addition of K6 for the new extended metrics, and does not apply to + * older TLV packet formats. + */ +static u_int16_t +eigrp_hello_parameter_encode (struct eigrp_interface *ei, struct stream *s, u_char flags) +{ + u_int16_t length = EIGRP_TLV_PARAMETER_LEN; + + // add in the parameters TLV + stream_putw(s, EIGRP_TLV_PARAMETER); + stream_putw(s, EIGRP_TLV_PARAMETER_LEN); + + //if graceful shutdown is needed to be announced, send all 255 in K values + if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN) + { + stream_putc(s, 0xff); /* K1 */ + stream_putc(s, 0xff); /* K2 */ + stream_putc(s, 0xff); /* K3 */ + stream_putc(s, 0xff); /* K4 */ + stream_putc(s, 0xff); /* K5 */ + stream_putc(s, 0xff); /* K6 */ + } + else // set k values + { + stream_putc(s, ei->eigrp->k_values[0]); /* K1 */ + stream_putc(s, ei->eigrp->k_values[1]); /* K2 */ + stream_putc(s, ei->eigrp->k_values[2]); /* K3 */ + stream_putc(s, ei->eigrp->k_values[3]); /* K4 */ + stream_putc(s, ei->eigrp->k_values[4]); /* K5 */ + stream_putc(s, ei->eigrp->k_values[5]); /* K6 */ + } + + // and set hold time value.. + stream_putw(s, IF_DEF_PARAMS(ei->ifp)->v_wait); + + return length; +} + +/** + * @fn eigrp_hello_encode + * + * @param[in] ei pointer to interface hello packet came in on + * @param[in] s packet stream TLV is stored to + * @param[in] ack if non-zero, neigbors sequence packet to ack + * @param[in] flags type of hello packet + * @param[in] nbr_addr pointer to neighbor address for Peer Termination TLV + * + * @return eigrp_packet pointer initialize hello packet + * + * @par + * Allocate an EIGRP hello packet, and add in the the approperate TLVs + * + */ +static struct eigrp_packet * +eigrp_hello_encode (struct eigrp_interface *ei, in_addr_t addr, u_int32_t ack, u_char flags, struct in_addr *nbr_addr) +{ + struct eigrp_packet *ep; + u_int16_t length = EIGRP_HEADER_LEN; + + // allocate a new packet to be sent + ep = eigrp_packet_new(ei->ifp->mtu); + + if (ep) + { + // encode common header feilds + eigrp_packet_header_init(EIGRP_OPC_HELLO, ei, ep->s, 0, 0, ack); + + // encode Authentication TLV + if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL)) + { + length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei); + } + else if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_SHA256) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL)) + { + length += eigrp_add_authTLV_SHA256_to_stream(ep->s,ei); + } + + /* encode appropriate parameters to Hello packet */ + if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN) + length += eigrp_hello_parameter_encode(ei, ep->s, EIGRP_HELLO_GRACEFUL_SHUTDOWN); + else + length += eigrp_hello_parameter_encode(ei, ep->s, EIGRP_HELLO_NORMAL); + + // figure out the version of code we're running + length += eigrp_sw_version_encode(ep->s); + + if(flags & EIGRP_HELLO_ADD_SEQUENCE) + { + length += eigrp_sequence_encode(ep->s); + length += eigrp_next_sequence_encode(ep->s); + } + + // add in the TID list if doing multi-topology + length += eigrp_tidlist_encode(ep->s); + + /* encode Peer Termination TLV if needed */ + if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR) + length += eigrp_peer_termination_encode(ep->s, nbr_addr); + + // Set packet length + ep->length = length; + + // set soruce address for the hello packet + ep->dst.s_addr = addr; + + if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL)) + { + eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_BASIC_HELLO_FLAG); + } + else if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_SHA256) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL)) + { + eigrp_make_sha256_digest(ei,ep->s, EIGRP_AUTH_BASIC_HELLO_FLAG); + } + + // EIGRP Checksum + eigrp_packet_checksum(ei, ep->s, length); + } + + return(ep); +} + +/** + * @fn eigrp_hello_send + * + * @param[in] nbr neighbor the ACK should be sent to + * + * @return void + * + * @par + * Send (unicast) a hello packet with the destination address + * associated with the neighbor. The eigrp header ACK feild will be + * updated to the neighbor's sequence number to acknolodge any + * outstanding packets + */ +void +eigrp_hello_send_ack (struct eigrp_neighbor *nbr) +{ + struct eigrp_packet *ep; + + /* if packet succesfully created, add it to the interface queue */ + ep = eigrp_hello_encode(nbr->ei, nbr->src.s_addr, nbr->recv_sequence_number, EIGRP_HELLO_NORMAL, NULL); + + if (ep) + { + if (IS_DEBUG_EIGRP_PACKET(0, SEND)) + zlog_debug("Queueing [Hello] Ack Seq [%u] nbr [%s]", + nbr->recv_sequence_number, inet_ntoa(nbr->src)); + + /* Add packet to the top of the interface output queue*/ + eigrp_fifo_push_head(nbr->ei->obuf, ep); + + /* Hook thread to write packet. */ + if (nbr->ei->on_write_q == 0) + { + listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei); + nbr->ei->on_write_q = 1; + } + if (nbr->ei->eigrp->t_write == NULL) + nbr->ei->eigrp->t_write = + thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd); + } +} + +/** + * @fn eigrp_hello_send + * + * @param[in] ei pointer to interface hello should be sent + * @param[in] flags type of hello packet + * @param[in] nbr_addr pointer to neighbor address for Peer Termination TLV + * + * @return void + * + * @par + * Build and enqueue a generic (multicast) periodic hello packet for + * sending. If no packets are currently queues, the packet will be + * sent immadiatly + */ +void +eigrp_hello_send (struct eigrp_interface *ei, u_char flags, struct in_addr *nbr_addr) +{ + struct eigrp_packet *ep = NULL; + + /* If this is passive interface, do not send EIGRP Hello. + if ((EIGRP_IF_PASSIVE_STATUS (ei) == EIGRP_IF_PASSIVE) || + (ei->type != EIGRP_IFTYPE_NBMA)) + return; + */ + + if (IS_DEBUG_EIGRP_PACKET(0, SEND)) + zlog_debug("Queueing [Hello] Interface(%s)", IF_NAME(ei)); + + /* if packet was succesfully created, then add it to the interface queue */ + ep = eigrp_hello_encode(ei, htonl(EIGRP_MULTICAST_ADDRESS), 0, flags, nbr_addr); + + if (ep) + { + // Add packet to the top of the interface output queue + eigrp_fifo_push_head(ei->obuf, ep); + + /* Hook thread to write packet. */ + if (ei->on_write_q == 0) + { + listnode_add(ei->eigrp->oi_write_q, ei); + ei->on_write_q = 1; + } + + if (ei->eigrp->t_write == NULL) + { + if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN) + { + ei->eigrp->t_write = + thread_execute(master, eigrp_write, ei->eigrp, ei->eigrp->fd); + } + else + { + ei->eigrp->t_write = + thread_add_write(master, eigrp_write, ei->eigrp, ei->eigrp->fd); + } + } + } +} diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c new file mode 100644 index 000000000..18573caa0 --- /dev/null +++ b/eigrpd/eigrp_interface.c @@ -0,0 +1,613 @@ +/* + * EIGRP Interface Functions. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "thread.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "memory.h" +#include "command.h" +#include "stream.h" +#include "log.h" +#include "keychain.h" +#include "vrf.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_memory.h" + +static void +eigrp_delete_from_if (struct interface *, struct eigrp_interface *); + +static void +eigrp_add_to_if (struct interface *ifp, struct eigrp_interface *ei) +{ + struct route_node *rn; + struct prefix p; + + p = *ei->address; + p.prefixlen = IPV4_MAX_PREFIXLEN; + + rn = route_node_get (IF_OIFS (ifp), &p); + /* rn->info should either be NULL or equal to this ei + * as route_node_get may return an existing node + */ + assert (!rn->info || rn->info == ei); + rn->info = ei; +} + +struct eigrp_interface * +eigrp_if_new (struct eigrp *eigrp, struct interface *ifp, struct prefix *p) +{ + struct eigrp_interface *ei; + int i; + + if ((ei = eigrp_if_table_lookup (ifp, p)) == NULL) + { + ei = XCALLOC (MTYPE_EIGRP_IF, sizeof (struct eigrp_interface)); + memset (ei, 0, sizeof (struct eigrp_interface)); + } + else + return ei; + + /* Set zebra interface pointer. */ + ei->ifp = ifp; + ei->address = p; + + eigrp_add_to_if (ifp, ei); + listnode_add (eigrp->eiflist, ei); + + ei->type = EIGRP_IFTYPE_BROADCAST; + + /* Initialize neighbor list. */ + ei->nbrs = list_new (); + + ei->crypt_seqnum = time (NULL); + + /* Initialize lists */ + for (i = 0; i < EIGRP_FILTER_MAX; i++) + { + ei->list[i] = NULL; + ei->prefix[i] = NULL; + ei->routemap[i] = NULL; + } + + return ei; +} + +/* lookup ei for specified prefix/ifp */ +struct eigrp_interface * +eigrp_if_table_lookup (struct interface *ifp, struct prefix *prefix) +{ + struct prefix p; + struct route_node *rn; + struct eigrp_interface *rninfo = NULL; + + p = *prefix; + p.prefixlen = IPV4_MAX_PREFIXLEN; + + /* route_node_get implicitly locks */ + if ((rn = route_node_lookup (IF_OIFS (ifp), &p))) + { + rninfo = (struct eigrp_interface *) rn->info; + route_unlock_node (rn); + } + + return rninfo; +} + +int +eigrp_if_delete_hook (struct interface *ifp) +{ + + struct route_node *rn; + + route_table_finish (IF_OIFS (ifp)); + + for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn)) + if (rn->info) + eigrp_del_if_params (rn->info); + route_table_finish (IF_OIFS_PARAMS (ifp)); + + XFREE (MTYPE_EIGRP_IF_INFO, ifp->info); + ifp->info = NULL; + + return 0; +} + +struct list *eigrp_iflist; + +void +eigrp_if_init () +{ + /* Initialize Zebra interface data structure. */ + if_add_hook (IF_NEW_HOOK, eigrp_if_new_hook); + if_add_hook (IF_DELETE_HOOK, eigrp_if_delete_hook); +} + +int +eigrp_if_new_hook (struct interface *ifp) +{ + int rc = 0; + + ifp->info = XCALLOC (MTYPE_EIGRP_IF_INFO, sizeof (struct eigrp_if_info)); + + IF_OIFS (ifp) = route_table_init (); + IF_OIFS_PARAMS (ifp) = route_table_init (); + + IF_DEF_PARAMS (ifp) = eigrp_new_if_params (); + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello); + IF_DEF_PARAMS (ifp)->v_hello = (u_int32_t) EIGRP_HELLO_INTERVAL_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait); + IF_DEF_PARAMS (ifp)->v_wait = (u_int16_t) EIGRP_HOLD_INTERVAL_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), bandwidth); + IF_DEF_PARAMS (ifp)->bandwidth = (u_int32_t) EIGRP_BANDWIDTH_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), delay); + IF_DEF_PARAMS (ifp)->delay = (u_int32_t) EIGRP_DELAY_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), reliability); + IF_DEF_PARAMS (ifp)->reliability = (u_char) EIGRP_RELIABILITY_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), load); + IF_DEF_PARAMS (ifp)->load = (u_char) EIGRP_LOAD_DEFAULT; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type); + IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_NONE; + + SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_keychain); + IF_DEF_PARAMS (ifp)->auth_keychain= NULL; + + return rc; +} + +struct eigrp_if_params * +eigrp_new_if_params (void) +{ + struct eigrp_if_params *eip; + + eip = XCALLOC (MTYPE_EIGRP_IF_PARAMS, sizeof (struct eigrp_if_params)); + if (!eip) + return NULL; + + UNSET_IF_PARAM (eip, passive_interface); + UNSET_IF_PARAM (eip, v_hello); + UNSET_IF_PARAM (eip, v_wait); + UNSET_IF_PARAM (eip, bandwidth); + UNSET_IF_PARAM (eip, delay); + UNSET_IF_PARAM (eip, reliability); + UNSET_IF_PARAM (eip, load); + UNSET_IF_PARAM (eip, auth_keychain); + UNSET_IF_PARAM (eip, auth_type); + + + return eip; +} + +void +eigrp_del_if_params (struct eigrp_if_params *eip) +{ + if(eip->auth_keychain) + free(eip->auth_keychain); + + XFREE (MTYPE_EIGRP_IF_PARAMS, eip); +} + +struct eigrp_if_params * +eigrp_lookup_if_params (struct interface *ifp, struct in_addr addr) +{ + struct prefix_ipv4 p; + struct route_node *rn; + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = addr; + + rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*) &p); + + if (rn) + { + route_unlock_node (rn); + return rn->info; + } + + return NULL; +} + +int +eigrp_if_up (struct eigrp_interface *ei) +{ + struct eigrp_prefix_entry *pe; + struct eigrp_neighbor_entry *ne; + struct eigrp_metrics metric; + struct eigrp_interface *ei2; + struct listnode *node, *nnode; + struct eigrp *eigrp = eigrp_lookup (); + + if (ei == NULL) + return 0; + + if (eigrp != NULL) + eigrp_adjust_sndbuflen (eigrp, ei->ifp->mtu); + else + zlog_warn ("%s: eigrp_lookup () returned NULL", __func__); + eigrp_if_stream_set (ei); + + /* Set multicast memberships appropriately for new state. */ + eigrp_if_set_multicast (ei); + + thread_add_event (master, eigrp_hello_timer, ei, (1)); + + /*Prepare metrics*/ + metric.bandwith = eigrp_bandwidth_to_scaled (EIGRP_IF_PARAM (ei,bandwidth)); + metric.delay = eigrp_delay_to_scaled (EIGRP_IF_PARAM (ei,delay)); + metric.load = EIGRP_IF_PARAM (ei,load); + metric.reliability = EIGRP_IF_PARAM (ei,reliability); + metric.mtu[0] = 0xDC; + metric.mtu[1] = 0x05; + metric.mtu[2] = 0x00; + metric.hop_count = 0; + metric.flags = 0; + metric.tag = 0; + + /*Add connected entry to topology table*/ + + struct prefix_ipv4 *dest_addr = prefix_ipv4_new (); + + dest_addr->family = AF_INET; + dest_addr->prefix = ei->connected->address->u.prefix4; + dest_addr->prefixlen = ei->connected->address->prefixlen; + apply_mask_ipv4 (dest_addr); + pe = eigrp_topology_table_lookup_ipv4 (eigrp->topology_table, dest_addr); + + if (pe == NULL) + { + pe = eigrp_prefix_entry_new (); + pe->serno = eigrp->serno; + pe->destination_ipv4 = dest_addr; + pe->af = AF_INET; + pe->nt = EIGRP_TOPOLOGY_TYPE_CONNECTED; + + pe->state = EIGRP_FSM_STATE_PASSIVE; + pe->fdistance = eigrp_calculate_metrics (eigrp, &metric); + pe->req_action |= EIGRP_FSM_NEED_UPDATE; + eigrp_prefix_entry_add (eigrp->topology_table, pe); + listnode_add(eigrp->topology_changes_internalIPV4, pe); + } + ne = eigrp_neighbor_entry_new (); + ne->ei = ei; + ne->reported_metric = metric; + ne->total_metric = metric; + ne->distance = eigrp_calculate_metrics (eigrp, &metric); + ne->reported_distance = 0; + ne->prefix = pe; + ne->adv_router = eigrp->neighbor_self; + ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG; + eigrp_neighbor_entry_add (pe, ne); + + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei2)) + { + if (ei2->nbrs->count != 0) + { + eigrp_update_send (ei2); + } + } + + pe->req_action &= ~EIGRP_FSM_NEED_UPDATE; + listnode_delete(eigrp->topology_changes_internalIPV4, pe); + + return 1; +} + +int +eigrp_if_down (struct eigrp_interface *ei) +{ + struct listnode *node, *nnode; + struct eigrp_neighbor *nbr; + + if (ei == NULL) + return 0; + + /* Shutdown packet reception and sending */ + if(ei->t_hello) + THREAD_OFF (ei->t_hello); + + eigrp_if_stream_unset (ei); + + /*Set infinite metrics to routes learned by this interface and start query process*/ + for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr)) + { + eigrp_nbr_delete(nbr); + } + + return 1; +} + +void +eigrp_if_stream_set (struct eigrp_interface *ei) +{ + /* set output fifo queue. */ + if (ei->obuf == NULL) + ei->obuf = eigrp_fifo_new (); +} + +void +eigrp_if_stream_unset (struct eigrp_interface *ei) +{ + struct eigrp *eigrp = ei->eigrp; + + if (ei->obuf) + { + eigrp_fifo_free (ei->obuf); + ei->obuf = NULL; + + if (ei->on_write_q) + { + listnode_delete (eigrp->oi_write_q, ei); + if (list_isempty (eigrp->oi_write_q)) + thread_cancel (eigrp->t_write); + ei->on_write_q = 0; + } + } +} + +void +eigrp_if_set_multicast (struct eigrp_interface *ei) +{ + if ((EIGRP_IF_PASSIVE_STATUS (ei) == EIGRP_IF_ACTIVE)) + { + /* The interface should belong to the EIGRP-all-routers group. */ + if (!EI_MEMBER_CHECK (ei, MEMBER_ALLROUTERS) + && (eigrp_if_add_allspfrouters (ei->eigrp, ei->address, + ei->ifp->ifindex) >= 0)) + /* Set the flag only if the system call to join succeeded. */ + EI_MEMBER_JOINED (ei, MEMBER_ALLROUTERS); + } + else + { + /* The interface should NOT belong to the EIGRP-all-routers group. */ + if (EI_MEMBER_CHECK (ei, MEMBER_ALLROUTERS)) + { + /* Only actually drop if this is the last reference */ + if (EI_MEMBER_COUNT (ei, MEMBER_ALLROUTERS) == 1) + eigrp_if_drop_allspfrouters (ei->eigrp, ei->address, + ei->ifp->ifindex); + /* Unset the flag regardless of whether the system call to leave + the group succeeded, since it's much safer to assume that + we are not a member. */ + EI_MEMBER_LEFT (ei, MEMBER_ALLROUTERS); + } + } +} + +u_char +eigrp_default_iftype (struct interface *ifp) +{ + if (if_is_pointopoint (ifp)) + return EIGRP_IFTYPE_POINTOPOINT; + else if (if_is_loopback (ifp)) + return EIGRP_IFTYPE_LOOPBACK; + else + return EIGRP_IFTYPE_BROADCAST; +} + +void +eigrp_if_free (struct eigrp_interface *ei, int source) +{ + + if (source == INTERFACE_DOWN_BY_VTY) + { + THREAD_OFF (ei->t_hello); + eigrp_hello_send(ei,EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL); + } + + eigrp_if_down (ei); + + list_delete (ei->nbrs); + eigrp_delete_from_if (ei->ifp, ei); + listnode_delete (ei->eigrp->eiflist, ei); + + thread_cancel_event (master, ei); + + memset (ei, 0, sizeof (*ei)); + XFREE (MTYPE_EIGRP_IF, ei); +} + +static void +eigrp_delete_from_if (struct interface *ifp, struct eigrp_interface *ei) +{ + struct route_node *rn; + struct prefix p; + + p = *ei->address; + p.prefixlen = IPV4_MAX_PREFIXLEN; + + rn = route_node_lookup (IF_OIFS (ei->ifp), &p); + assert (rn); + assert (rn->info); + rn->info = NULL; + route_unlock_node (rn); + route_unlock_node (rn); +} + +/* Simulate down/up on the interface. This is needed, for example, when + the MTU changes. */ +void +eigrp_if_reset (struct interface *ifp) +{ + struct route_node *rn; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + struct eigrp_interface *ei; + + if ((ei = rn->info) == NULL) + continue; + + eigrp_if_down (ei); + eigrp_if_up (ei); + } +} + +struct eigrp_interface * +eigrp_if_lookup_by_local_addr (struct eigrp *eigrp, struct interface *ifp, + struct in_addr address) +{ + struct listnode *node; + struct eigrp_interface *ei; + + for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei)) + { + if (ifp && ei->ifp != ifp) + continue; + + if (IPV4_ADDR_SAME (&address, &ei->address->u.prefix4)) + return ei; + } + + return NULL; +} + +/** + * @fn eigrp_if_lookup_by_name + * + * @param[in] eigrp EIGRP process + * @param[in] if_name Name of the interface + * + * @return struct eigrp_interface * + * + * @par + * Function is used for lookup interface by name. + */ +struct eigrp_interface * +eigrp_if_lookup_by_name (struct eigrp *eigrp, const char *if_name) +{ + struct eigrp_interface *ei; + struct listnode *node; + + /* iterate over all eigrp interfaces */ + for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei)) + { + /* compare int name with eigrp interface's name */ + if(strcmp(ei->ifp->name, if_name) == 0) + { + return ei; + } + } + + return NULL; +} + +/* determine receiving interface by ifp and source address */ +struct eigrp_interface * +eigrp_if_lookup_recv_if (struct eigrp *eigrp, struct in_addr src, + struct interface *ifp) +{ + struct route_node *rn; + struct prefix_ipv4 addr; + struct eigrp_interface *ei, *match; + + addr.family = AF_INET; + addr.prefix = src; + addr.prefixlen = IPV4_MAX_BITLEN; + + match = NULL; + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + ei = rn->info; + + if (!ei) /* oi can be NULL for PtP aliases */ + continue; + + if (if_is_loopback (ei->ifp)) + continue; + + if (prefix_match (CONNECTED_PREFIX (ei->connected), + (struct prefix *) &addr)) + { + if ((match == NULL) + || (match->address->prefixlen < ei->address->prefixlen)) + match = ei; + } + } + + return match; +} + +u_int32_t +eigrp_bandwidth_to_scaled (u_int32_t bandwidth) +{ + u_int64_t temp_bandwidth = (256ull * 10000000) / bandwidth; + + temp_bandwidth = + temp_bandwidth < EIGRP_MAX_METRIC ? temp_bandwidth : EIGRP_MAX_METRIC; + + return (u_int32_t) temp_bandwidth; + +} + +u_int32_t +eigrp_scaled_to_bandwidth (u_int32_t scaled) +{ + u_int64_t temp_scaled = scaled * (256ull * 10000000); + + temp_scaled = + temp_scaled < EIGRP_MAX_METRIC ? temp_scaled : EIGRP_MAX_METRIC; + + return (u_int32_t) temp_scaled; +} + +u_int32_t +eigrp_delay_to_scaled (u_int32_t delay) +{ + return delay * 256; +} + +u_int32_t +eigrp_scaled_to_delay (u_int32_t scaled) +{ + return scaled / 256; +} diff --git a/eigrpd/eigrp_interface.h b/eigrpd/eigrp_interface.h new file mode 100644 index 000000000..c7de3b75b --- /dev/null +++ b/eigrpd/eigrp_interface.h @@ -0,0 +1,73 @@ +/* + * EIGRP Interface Functions. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * 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. + */ + +#ifndef _ZEBRA_EIGRP_INTERFACE_H_ +#define _ZEBRA_EIGRP_INTERFACE_H_ + +/*Prototypes*/ +extern void eigrp_if_init (void); +extern int eigrp_if_new_hook (struct interface *); +extern int eigrp_if_delete_hook (struct interface *); + +extern void eigrp_del_if_params (struct eigrp_if_params *); +extern struct eigrp_if_params *eigrp_new_if_params (void); +extern struct eigrp_interface * eigrp_if_new (struct eigrp *, struct interface *, + struct prefix *); +extern struct eigrp_interface * eigrp_if_table_lookup (struct interface *, + struct prefix *); +extern struct eigrp_if_params *eigrp_lookup_if_params (struct interface *, + struct in_addr); +extern int eigrp_if_up (struct eigrp_interface *); +extern void eigrp_if_stream_set (struct eigrp_interface *); +extern void eigrp_if_set_multicast (struct eigrp_interface *); +extern u_char eigrp_default_iftype (struct interface *); +extern void eigrp_if_free (struct eigrp_interface *, int); +extern int eigrp_if_down (struct eigrp_interface *); +extern void eigrp_if_stream_unset (struct eigrp_interface *); + +extern struct eigrp_interface *eigrp_if_lookup_by_local_addr (struct eigrp *, + struct interface *, + struct in_addr); +extern struct eigrp_interface *eigrp_if_lookup_by_name (struct eigrp *, const char *); +struct eigrp_interface * eigrp_if_lookup_recv_if (struct eigrp *, struct in_addr, + struct interface *); + +/* Simulate down/up on the interface. */ +extern void eigrp_if_reset (struct interface *); + +extern u_int32_t eigrp_bandwidth_to_scaled (u_int32_t); +extern u_int32_t eigrp_scaled_to_bandwidth (u_int32_t); +extern u_int32_t eigrp_delay_to_scaled (u_int32_t); +extern u_int32_t eigrp_scaled_to_delay (u_int32_t); + + +#endif /* ZEBRA_EIGRP_INTERFACE_H_ */ diff --git a/eigrpd/eigrp_macros.h b/eigrpd/eigrp_macros.h new file mode 100644 index 000000000..dd22829e8 --- /dev/null +++ b/eigrpd/eigrp_macros.h @@ -0,0 +1,85 @@ +/* + * EIGRP Macros Definition. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * 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. + */ + +#ifndef _ZEBRA_EIGRP_MACROS_H_ +#define _ZEBRA_EIGRP_MACROS_H_ + +#define DECLARE_IF_PARAM(T, P) T P; u_char P##__config:1 +#define IF_EIGRP_IF_INFO(I) ((struct eigrp_if_info *)((I)->info)) +#define IF_OIFS(I) (IF_EIGRP_IF_INFO (I)->eifs) +#define IF_OIFS_PARAMS(I) (IF_EIGRP_IF_INFO (I)->params) + +#define SET_IF_PARAM(S, P) ((S)->P##__config) = 1 +#define IF_DEF_PARAMS(I) (IF_EIGRP_IF_INFO (I)->def_params) + +#define UNSET_IF_PARAM(S, P) ((S)->P##__config) = 0 + +#define EIGRP_IF_PARAM_CONFIGURED(S, P) ((S) && (S)->P##__config) +#define EIGRP_IF_PARAM(O, P) \ + (EIGRP_IF_PARAM_CONFIGURED ((O)->params, P)?\ + (O)->params->P:IF_DEF_PARAMS((O)->ifp)->P) + +#define EIGRP_IF_PASSIVE_STATUS(O) \ + (EIGRP_IF_PARAM_CONFIGURED((O)->params, passive_interface) ? \ + (O)->params->passive_interface : \ + (EIGRP_IF_PARAM_CONFIGURED(IF_DEF_PARAMS((O)->ifp), passive_interface) ? \ + IF_DEF_PARAMS((O)->ifp)->passive_interface : \ + (O)->eigrp->passive_interface_default)) + +//------------------------------------------------------------------------------------------------------------------------------------ + +#define EIGRP_IF_STRING_MAXLEN 40 +#define IF_NAME(I) eigrp_if_name_string ((I)) + +//------------------------------------------------------------------------------------------------------------------------------------ + +/*Macros for EIGRP interface multicast membership*/ +#define EI_MEMBER_FLAG(M) (1 << (M)) +#define EI_MEMBER_COUNT(O,M) (IF_EIGRP_IF_INFO(ei->ifp)->membership_counts[(M)]) +#define EI_MEMBER_CHECK(O,M) \ + (CHECK_FLAG((O)->multicast_memberships, EI_MEMBER_FLAG(M))) +#define EI_MEMBER_JOINED(O,M) \ + do { \ + SET_FLAG ((O)->multicast_memberships, EI_MEMBER_FLAG(M)); \ + IF_EIGRP_IF_INFO((O)->ifp)->membership_counts[(M)]++; \ + } while (0) +#define EI_MEMBER_LEFT(O,M) \ + do { \ + UNSET_FLAG ((O)->multicast_memberships, EI_MEMBER_FLAG(M)); \ + IF_EIGRP_IF_INFO((O)->ifp)->membership_counts[(M)]--; \ + } while (0) + +//----------------------------------------------------------------------------------------------------------------------------------- +/* Topology Macros */ + + +/* FSM macros*/ +#define EIGRP_FSM_EVENT_SCHEDULE(I,E) \ + thread_add_event (master, eigrp_fsm_event, (I), (E)) + +#endif /* _ZEBRA_EIGRP_MACROS_H_ */ diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c new file mode 100644 index 000000000..85a97e79a --- /dev/null +++ b/eigrpd/eigrp_main.c @@ -0,0 +1,231 @@ +/* + * EIGRP Main Routine. + * Copyright (C) 2013-2015 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include <zebra.h> + +#include <lib/version.h> +#include "getopt.h" +#include "thread.h" +#include "prefix.h" +#include "linklist.h" +#include "if.h" +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "filter.h" +#include "plist.h" +#include "stream.h" +#include "log.h" +#include "memory.h" +#include "privs.h" +#include "sigevent.h" +#include "zclient.h" +#include "keychain.h" +#include "distribute.h" +#include "libfrr.h" +//#include "routemap.h" +//#include "if_rmap.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_snmp.h" +#include "eigrpd/eigrp_filter.h" +//#include "eigrpd/eigrp_routemap.h" + +/* eigprd privileges */ +zebra_capabilities_t _caps_p [] = +{ + ZCAP_NET_RAW, + ZCAP_BIND, + ZCAP_NET_ADMIN, +}; + +struct zebra_privs_t eigrpd_privs = +{ +#if defined (FRR_USER) && defined (FRR_GROUP) + .user = FRR_USER, + .group = FRR_GROUP, +#endif +#if defined (VTY_GROUP) + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = array_size (_caps_p), + .cap_num_i = 0 +}; + +/* EIGRPd options. */ +struct option longopts[] = +{ + { 0 } +}; + +/* Master of threads. */ +struct thread_master *master; + +/* SIGHUP handler. */ +static void +sighup (void) +{ + zlog_info ("SIGHUP received"); +} + +/* SIGINT / SIGTERM handler. */ +static void +sigint (void) +{ + zlog_notice ("Terminating on signal"); + eigrp_terminate (); +} + +/* SIGUSR1 handler. */ +static void +sigusr1 (void) +{ + zlog_rotate (); +} + +struct quagga_signal_t eigrp_signals[] = +{ + { + .signal = SIGHUP, + .handler = &sighup, + }, + { + .signal = SIGUSR1, + .handler = &sigusr1, + }, + { + .signal = SIGINT, + .handler = &sigint, + }, + { + .signal = SIGTERM, + .handler = &sigint, + }, +}; + +FRR_DAEMON_INFO(eigrpd, EIGRP, + .vty_port = EIGRP_VTY_PORT, + + .proghelp = "Implementation of the EIGRP routing protocol.", + + .signals = eigrp_signals, + .n_signals = array_size(eigrp_signals), + + .privs = &eigrpd_privs, + ) + +/* EIGRPd main routine. */ +int +main (int argc, char **argv, char **envp) +{ + frr_preinit (&eigrpd_di, argc, argv); + frr_opt_add ("", longopts, ""); + + while (1) + { + int opt; + + opt = frr_getopt (argc, argv, NULL); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + default: + frr_help_exit (1); + break; + } + } + + /* EIGRP master init. */ + eigrp_master_init (); + eigrp_om->master = frr_init(); + master = eigrp_om->master; + + vrf_init (); + + /*EIGRPd init*/ + eigrp_if_init (); + eigrp_zebra_init (); + eigrp_debug_init (); + + /* Get configuration file. */ + /* EIGRP VTY inits */ + eigrp_vty_init (); + keychain_init(); + eigrp_vty_show_init (); + eigrp_vty_if_init (); + +#ifdef HAVE_SNMP + eigrp_snmp_init (); +#endif /* HAVE_SNMP */ + + /* Access list install. */ + access_list_init (); + access_list_add_hook (eigrp_distribute_update_all_wrapper); + access_list_delete_hook (eigrp_distribute_update_all_wrapper); + + /* Prefix list initialize.*/ + prefix_list_init (); + prefix_list_add_hook (eigrp_distribute_update_all); + prefix_list_delete_hook (eigrp_distribute_update_all); + + /*eigrp_route_map_init(); + route_map_add_hook (eigrp_rmap_update); + route_map_delete_hook (eigrp_rmap_update);*/ + /*if_rmap_init (EIGRP_NODE); + if_rmap_hook_add (eigrp_if_rmap_update); + if_rmap_hook_delete (eigrp_if_rmap_update);*/ + + /* Distribute list install. */ + distribute_list_init (EIGRP_NODE); + distribute_list_add_hook (eigrp_distribute_update); + distribute_list_delete_hook (eigrp_distribute_update); + + frr_config_fork (); + frr_run(master); + + /* Not reached. */ + return (0); + +} diff --git a/eigrpd/eigrp_memory.c b/eigrpd/eigrp_memory.c new file mode 100644 index 000000000..dabc0774e --- /dev/null +++ b/eigrpd/eigrp_memory.c @@ -0,0 +1,43 @@ +/* eigrpd memory type definitions + * + * Copyright (C) 2017 Donald Sharp + * + * This file is part of FRR + * + * FRR 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. + * + * FRR 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 FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "eigrp_memory.h" + +DEFINE_MGROUP(EIGRPD, "eigrpd") +DEFINE_MTYPE(EIGRPD, EIGRP_TOP, "EIGRP structure") +DEFINE_MTYPE(EIGRPD, EIGRP_IF, "EIGRP interface") +DEFINE_MTYPE(EIGRPD, EIGRP_NEIGHBOR, "EIGRP neighbor") +DEFINE_MTYPE(EIGRPD, EIGRP_IF_PARAMS, "EIGRP Interface Parameters") +DEFINE_MTYPE(EIGRPD, EIGRP_IF_INFO, "EIGRP Interface Information") +DEFINE_MTYPE(EIGRPD, EIGRP_FIFO, "EIGRP FIFO") +DEFINE_MTYPE(EIGRPD, EIGRP_PACKET, "EIGRP Packet") +DEFINE_MTYPE(EIGRPD, EIGRP_IPV4_INT_TLV, "EIGRP IPv4 TLV") +DEFINE_MTYPE(EIGRPD, EIGRP_SEQ_TLV, "EIGRP SEQ TLV") +DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_TLV, "EIGRP AUTH TLV") +DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV") +DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_ENTRY, "EIGRP Prefix") +DEFINE_MTYPE(EIGRPD, EIGRP_NEIGHBOR_ENTRY, "EIGRP Neighbor Entry") +DEFINE_MTYPE(EIGRPD, EIGRP_FSM_MSG, "EIGRP FSM Message") diff --git a/eigrpd/eigrp_memory.h b/eigrpd/eigrp_memory.h new file mode 100644 index 000000000..0cafdfb1b --- /dev/null +++ b/eigrpd/eigrp_memory.h @@ -0,0 +1,44 @@ +/* eigrpd memory type declarations + * + * Copyright (C) 2017 Donald Sharp + * + * This file is part of FRR. + * + * FRR 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. + * + * FRR 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 FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _FRR_EIGRP_MEMORY_H +#define _FRR_EIGRP_MEMORY_H + +#include "memory.h" + +DECLARE_MGROUP(EIGRPD) +DECLARE_MTYPE(EIGRP_TOP) +DECLARE_MTYPE(EIGRP_IF) +DECLARE_MTYPE(EIGRP_NEIGHBOR) +DECLARE_MTYPE(EIGRP_IF_PARAMS) +DECLARE_MTYPE(EIGRP_IF_INFO) +DECLARE_MTYPE(EIGRP_FIFO) +DECLARE_MTYPE(EIGRP_PACKET) +DECLARE_MTYPE(EIGRP_IPV4_INT_TLV) +DECLARE_MTYPE(EIGRP_SEQ_TLV) +DECLARE_MTYPE(EIGRP_AUTH_TLV) +DECLARE_MTYPE(EIGRP_AUTH_SHA256_TLV) +DECLARE_MTYPE(EIGRP_PREFIX_ENTRY) +DECLARE_MTYPE(EIGRP_NEIGHBOR_ENTRY) +DECLARE_MTYPE(EIGRP_FSM_MSG) + +#endif /* _FRR_EIGRP_MEMORY_H */ diff --git a/eigrpd/eigrp_neighbor.c b/eigrpd/eigrp_neighbor.c new file mode 100644 index 000000000..8dcf76dc4 --- /dev/null +++ b/eigrpd/eigrp_neighbor.c @@ -0,0 +1,384 @@ +/* + * EIGRP Neighbor Handling. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "linklist.h" +#include "prefix.h" +#include "memory.h" +#include "command.h" +#include "thread.h" +#include "stream.h" +#include "table.h" +#include "log.h" +#include "keychain.h" +#include "vty.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_memory.h" + +struct eigrp_neighbor * +eigrp_nbr_new (struct eigrp_interface *ei) +{ + struct eigrp_neighbor *nbr; + + /* Allcate new neighbor. */ + nbr = XCALLOC (MTYPE_EIGRP_NEIGHBOR, sizeof (struct eigrp_neighbor)); + + /* Relate neighbor to the interface. */ + nbr->ei = ei; + + /* Set default values. */ + + eigrp_nbr_state_set (nbr, EIGRP_NEIGHBOR_DOWN); + + return nbr; +} + +/** + *@fn void dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree, + * proto_item *ti) + * + * @par + * Create a new neighbor structure and initalize it. + */ +static struct eigrp_neighbor * +eigrp_nbr_add (struct eigrp_interface *ei, struct eigrp_header *eigrph, + struct ip *iph) +{ + struct eigrp_neighbor *nbr; + + nbr = eigrp_nbr_new (ei); + nbr->src = iph->ip_src; + +// if (IS_DEBUG_EIGRP_EVENT) +// zlog_debug("NSM[%s:%s]: start", IF_NAME (nbr->oi), +// inet_ntoa (nbr->router_id)); + + return nbr; +} + +struct eigrp_neighbor * +eigrp_nbr_get (struct eigrp_interface *ei, struct eigrp_header *eigrph, + struct ip *iph) +{ + struct eigrp_neighbor *nbr; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr)) + { + if (iph->ip_src.s_addr == nbr->src.s_addr) + { + return nbr; + } + } + + nbr = eigrp_nbr_add (ei, eigrph, iph); + listnode_add (ei->nbrs, nbr); + + return nbr; +} + +/** + * @fn eigrp_nbr_lookup_by_addr + * + * @param[in] ei EIGRP interface + * @param[in] nbr_addr Address of neighbor + * + * @return void + * + * @par + * Function is used for neighbor lookup by address + * in specified interface. + */ +struct eigrp_neighbor * +eigrp_nbr_lookup_by_addr (struct eigrp_interface *ei, struct in_addr *addr) +{ + struct eigrp_neighbor *nbr; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr)) + { + if (addr->s_addr == nbr->src.s_addr) + { + return nbr; + } + } + + return NULL; +} + +/** + * @fn eigrp_nbr_lookup_by_addr_process + * + * @param[in] eigrp EIGRP process + * @param[in] nbr_addr Address of neighbor + * + * @return void + * + * @par + * Function is used for neighbor lookup by address + * in whole EIGRP process. + */ +struct eigrp_neighbor * +eigrp_nbr_lookup_by_addr_process (struct eigrp *eigrp, struct in_addr nbr_addr) +{ + struct eigrp_interface *ei; + struct listnode *node, *node2, *nnode2; + struct eigrp_neighbor *nbr; + + /* iterate over all eigrp interfaces */ + for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei)) + { + /* iterate over all neighbors on eigrp interface */ + for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr)) + { + /* compare if neighbor address is same as arg address */ + if (nbr->src.s_addr == nbr_addr.s_addr) + { + return nbr; + } + } + } + + return NULL; +} + + +/* Delete specified EIGRP neighbor from interface. */ +void +eigrp_nbr_delete (struct eigrp_neighbor *nbr) +{ + + eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN); + eigrp_topology_neighbor_down(nbr->ei->eigrp, nbr); + + /* Cancel all events. *//* Thread lookup cost would be negligible. */ + thread_cancel_event (master, nbr); + eigrp_fifo_free (nbr->multicast_queue); + eigrp_fifo_free (nbr->retrans_queue); + THREAD_OFF (nbr->t_holddown); + + listnode_delete (nbr->ei->nbrs,nbr); + XFREE (MTYPE_EIGRP_NEIGHBOR, nbr); +} + +int +holddown_timer_expired (struct thread *thread) +{ + struct eigrp_neighbor *nbr; + + nbr = THREAD_ARG (thread); + + zlog_info ("Neighbor %s (%s) is down: holding time expired", + inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex)); + nbr->state = EIGRP_NEIGHBOR_DOWN; + eigrp_nbr_delete (nbr); + + return 0; +} + +u_char +eigrp_nbr_state_get (struct eigrp_neighbor *nbr) +{ + return(nbr->state); +} + +void +eigrp_nbr_state_set (struct eigrp_neighbor *nbr, u_char state) +{ + + nbr->state = state; + + if (eigrp_nbr_state_get(nbr) == EIGRP_NEIGHBOR_DOWN) + { + // reset all the seq/ack counters + nbr->recv_sequence_number = 0; + nbr->init_sequence_number = 0; + nbr->retrans_counter = 0; + + // Kvalues + nbr->K1 = EIGRP_K1_DEFAULT; + nbr->K2 = EIGRP_K2_DEFAULT; + nbr->K3 = EIGRP_K3_DEFAULT; + nbr->K4 = EIGRP_K4_DEFAULT; + nbr->K5 = EIGRP_K5_DEFAULT; + nbr->K6 = EIGRP_K6_DEFAULT; + + // hold time.. + nbr->v_holddown = EIGRP_HOLD_INTERVAL_DEFAULT; + THREAD_OFF(nbr->t_holddown); + + /* out with the old */ + if (nbr->multicast_queue) + eigrp_fifo_free (nbr->multicast_queue); + if (nbr->retrans_queue) + eigrp_fifo_free (nbr->retrans_queue); + + /* in with the new */ + nbr->retrans_queue = eigrp_fifo_new (); + nbr->multicast_queue = eigrp_fifo_new (); + + nbr->crypt_seqnum = 0; + } +} + +const char * +eigrp_nbr_state_str (struct eigrp_neighbor *nbr) +{ + const char *state; + switch (nbr->state) + { + case EIGRP_NEIGHBOR_DOWN: + state = "Down"; + break; + case EIGRP_NEIGHBOR_PENDING: + state = "Waiting for Init"; + break; + case EIGRP_NEIGHBOR_UP: + state = "Up"; + break; + default: + state = "Unknown"; + break; + } + + return(state); +} + +void +eigrp_nbr_state_update (struct eigrp_neighbor *nbr) +{ + switch (nbr->state) + { + case EIGRP_NEIGHBOR_DOWN: + { + /*Start Hold Down Timer for neighbor*/ +// THREAD_OFF(nbr->t_holddown); +// THREAD_TIMER_ON(master, nbr->t_holddown, holddown_timer_expired, +// nbr, nbr->v_holddown); + break; + } + case EIGRP_NEIGHBOR_PENDING: + { + /*Reset Hold Down Timer for neighbor*/ + THREAD_OFF(nbr->t_holddown); + THREAD_TIMER_ON(master, nbr->t_holddown, holddown_timer_expired, nbr, + nbr->v_holddown); + break; + } + case EIGRP_NEIGHBOR_UP: + { + /*Reset Hold Down Timer for neighbor*/ + THREAD_OFF(nbr->t_holddown); + THREAD_TIMER_ON(master, nbr->t_holddown, holddown_timer_expired, nbr, + nbr->v_holddown); + break; + } + } +} + +int eigrp_nbr_count_get(void){ + + struct eigrp_interface *iface; + struct listnode *node, *node2, *nnode2; + struct eigrp_neighbor *nbr; + struct eigrp *eigrp = eigrp_lookup(); + u_int32_t counter; + + if (eigrp == NULL) + { + zlog_debug("EIGRP Routing Process not enabled"); + return 0; + } + + counter=0; + for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface)) + { + for (ALL_LIST_ELEMENTS(iface->nbrs, node2, nnode2, nbr)) + { + if (nbr->state == EIGRP_NEIGHBOR_UP){ + counter++; + } + } + } + return counter; +} + +/** + * @fn eigrp_nbr_hard_restart + * + * @param[in] nbr Neighbor who would receive hard restart + * @param[in] vty Virtual terminal for log output + * @return void + * + * @par + * Function used for executing hard restart for neighbor: + * Send Hello packet with Peer Termination TLV with + * neighbor's address, set it's state to DOWN and delete the neighbor + */ +void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty) +{ + if(nbr == NULL) + { + zlog_err("Nbr Hard restart: Neighbor not specified."); + return; + } + + zlog_debug ("Neighbor %s (%s) is down: manually cleared", + inet_ntoa (nbr->src), + ifindex2ifname (nbr->ei->ifp->ifindex)); + if(vty != NULL) + { + vty_time_print (vty, 0); + vty_out (vty, "Neighbor %s (%s) is down: manually cleared%s", + inet_ntoa (nbr->src), + ifindex2ifname (nbr->ei->ifp->ifindex), + VTY_NEWLINE); + } + + /* send Hello with Peer Termination TLV */ + eigrp_hello_send(nbr->ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR, &(nbr->src)); + /* set neighbor to DOWN */ + nbr->state = EIGRP_NEIGHBOR_DOWN; + /* delete neighbor */ + eigrp_nbr_delete (nbr); +} diff --git a/eigrpd/eigrp_neighbor.h b/eigrpd/eigrp_neighbor.h new file mode 100644 index 000000000..e9ddc22f9 --- /dev/null +++ b/eigrpd/eigrp_neighbor.h @@ -0,0 +1,55 @@ +/* + * EIGRP Neighbor Handling. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * 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. + */ + +#ifndef _ZEBRA_EIGRP_NEIGHBOR_H +#define _ZEBRA_EIGRP_NEIGHBOR_H + +/* Prototypes */ +extern struct eigrp_neighbor *eigrp_nbr_get(struct eigrp_interface *, + struct eigrp_header *, + struct ip *); +extern struct eigrp_neighbor *eigrp_nbr_new (struct eigrp_interface *); +extern void eigrp_nbr_delete(struct eigrp_neighbor *); + +extern int holddown_timer_expired(struct thread *); + +extern int eigrp_neighborship_check(struct eigrp_neighbor *,struct TLV_Parameter_Type *); +extern void eigrp_nbr_state_update(struct eigrp_neighbor *); +extern void eigrp_nbr_state_set(struct eigrp_neighbor *, u_char state); +extern u_char eigrp_nbr_state_get(struct eigrp_neighbor *); +extern int eigrp_nbr_count_get(void); +extern const char *eigrp_nbr_state_str(struct eigrp_neighbor *); +extern struct eigrp_neighbor *eigrp_nbr_lookup_by_addr (struct eigrp_interface *, struct in_addr *); +extern struct eigrp_neighbor *eigrp_nbr_lookup_by_addr_process (struct eigrp *, struct in_addr); +extern void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty); + +#endif /* _ZEBRA_EIGRP_NEIGHBOR_H */ diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c new file mode 100644 index 000000000..fba7717b9 --- /dev/null +++ b/eigrpd/eigrp_network.c @@ -0,0 +1,463 @@ +/* + * EIGRP Network Related Functions. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "thread.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "sockunion.h" +#include "log.h" +#include "sockopt.h" +#include "privs.h" +#include "table.h" +#include "vty.h" + +extern struct zebra_privs_t eigrpd_privs; + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_network.h" + +static int +eigrp_network_match_iface(const struct connected *, const struct prefix *); +static void +eigrp_network_run_interface(struct eigrp *, struct prefix *, struct interface *); + +int +eigrp_sock_init(void) +{ + int eigrp_sock; + int ret, hincl = 1; + + if (eigrpd_privs.change(ZPRIVS_RAISE)) + zlog_err("eigrp_sock_init: could not raise privs, %s", + safe_strerror(errno)); + + eigrp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP); + if (eigrp_sock < 0) + { + int save_errno = errno; + if (eigrpd_privs.change(ZPRIVS_LOWER)) + zlog_err("eigrp_sock_init: could not lower privs, %s", + safe_strerror(errno)); + zlog_err("eigrp_read_sock_init: socket: %s", safe_strerror(save_errno)); + exit(1); + } + +#ifdef IP_HDRINCL + /* we will include IP header with packet */ + ret = setsockopt(eigrp_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)); + if (ret < 0) + { + int save_errno = errno; + if (eigrpd_privs.change(ZPRIVS_LOWER)) + zlog_err("eigrp_sock_init: could not lower privs, %s", + safe_strerror(errno)); + zlog_warn("Can't set IP_HDRINCL option for fd %d: %s", eigrp_sock, + safe_strerror(save_errno)); + + } +#elif defined (IPTOS_PREC_INTERNETCONTROL) +#warning "IP_HDRINCL not available on this system" +#warning "using IPTOS_PREC_INTERNETCONTROL" + ret = setsockopt_ipv4_tos (eigrp_sock, IPTOS_PREC_INTERNETCONTROL); + if (ret < 0) + { + int save_errno = errno; + if ( eigrpd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("eigrpd_sock_init: could not lower privs, %s", + safe_strerror (errno) ); + zlog_warn ("can't set sockopt IP_TOS %d to socket %d: %s", + tos, eigrp_sock, safe_strerror (save_errno)); + close (eigrp_sock); /* Prevent sd leak. */ + return ret; + } +#else /* !IPTOS_PREC_INTERNETCONTROL */ +#warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL" + zlog_warn ("IP_HDRINCL option not available"); +#endif /* IP_HDRINCL */ + + ret = setsockopt_ifindex(AF_INET, eigrp_sock, 1); + + if (ret < 0) + zlog_warn("Can't set pktinfo option for fd %d", eigrp_sock); + + if (eigrpd_privs.change(ZPRIVS_LOWER)) + { + zlog_err("eigrp_sock_init: could not lower privs, %s", + safe_strerror(errno)); + } + + return eigrp_sock; +} + +void +eigrp_adjust_sndbuflen(struct eigrp * eigrp, unsigned int buflen) +{ + int newbuflen; + /* Check if any work has to be done at all. */ + if (eigrp->maxsndbuflen >= buflen) + return; + if (eigrpd_privs.change(ZPRIVS_RAISE)) + zlog_err("%s: could not raise privs, %s", __func__, safe_strerror(errno)); + /* Now we try to set SO_SNDBUF to what our caller has requested + * (the MTU of a newly added interface). However, if the OS has + * truncated the actual buffer size to somewhat less size, try + * to detect it and update our records appropriately. The OS + * may allocate more buffer space, than requested, this isn't + * a error. + */ + setsockopt_so_sendbuf(eigrp->fd, buflen); + newbuflen = getsockopt_so_sendbuf(eigrp->fd); + if (newbuflen < 0 || newbuflen < (int) buflen) + zlog_warn("%s: tried to set SO_SNDBUF to %u, but got %d", __func__, buflen, + newbuflen); + if (newbuflen >= 0) + eigrp->maxsndbuflen = (unsigned int) newbuflen; + else + zlog_warn("%s: failed to get SO_SNDBUF", __func__); + if (eigrpd_privs.change(ZPRIVS_LOWER)) + zlog_err("%s: could not lower privs, %s", __func__, safe_strerror(errno)); +} + +int +eigrp_if_ipmulticast(struct eigrp *top, struct prefix *p, unsigned int ifindex) +{ + u_char val; + int ret, len; + + val = 0; + len = sizeof(val); + + /* Prevent receiving self-origined multicast packets. */ + ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *) &val, len); + if (ret < 0) + zlog_warn("can't setsockopt IP_MULTICAST_LOOP (0) for fd %d: %s", top->fd, + safe_strerror(errno)); + + /* Explicitly set multicast ttl to 1 -- endo. */ + val = 1; + ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *) &val, len); + if (ret < 0) + zlog_warn("can't setsockopt IP_MULTICAST_TTL (1) for fd %d: %s", top->fd, + safe_strerror(errno)); + + ret = setsockopt_ipv4_multicast_if(top->fd, p->u.prefix4, ifindex); + if (ret < 0) + zlog_warn("can't setsockopt IP_MULTICAST_IF (fd %d, addr %s, " + "ifindex %u): %s", top->fd, inet_ntoa(p->u.prefix4), ifindex, + safe_strerror(errno)); + + return ret; +} + +/* Join to the EIGRP multicast group. */ +int +eigrp_if_add_allspfrouters(struct eigrp *top, struct prefix *p, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_ipv4_multicast(top->fd, IP_ADD_MEMBERSHIP, p->u.prefix4, + htonl(EIGRP_MULTICAST_ADDRESS), ifindex); + if (ret < 0) + zlog_warn("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, " + "ifindex %u, AllSPFRouters): %s; perhaps a kernel limit " + "on # of multicast group memberships has been exceeded?", top->fd, + inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); + else + zlog_debug("interface %s [%u] join EIGRP Multicast group.", + inet_ntoa(p->u.prefix4), ifindex); + + return ret; +} + +int +eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p, + unsigned int ifindex) +{ + int ret; + + ret = setsockopt_ipv4_multicast(top->fd, IP_DROP_MEMBERSHIP, p->u.prefix4, + htonl(EIGRP_MULTICAST_ADDRESS), ifindex); + if (ret < 0) + zlog_warn("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, " + "ifindex %u, AllSPFRouters): %s", top->fd, inet_ntoa(p->u.prefix4), + ifindex, safe_strerror(errno)); + else + zlog_debug("interface %s [%u] leave EIGRP Multicast group.", + inet_ntoa(p->u.prefix4), ifindex); + + return ret; +} + +int +eigrp_network_set(struct eigrp *eigrp, struct prefix_ipv4 *p) +{ + struct route_node *rn; + struct interface *ifp; + struct listnode *node; + + zlog_debug ("A"); + rn = route_node_get(eigrp->networks, (struct prefix *) p); + if (rn->info) + { + /* There is already same network statement. */ + route_unlock_node(rn); + return 0; + } + + struct prefix_ipv4 *pref = prefix_ipv4_new(); + PREFIX_COPY_IPV4(pref,p); + rn->info = (void *) pref; + + zlog_debug ("B"); + /* Schedule Router ID Update. */ +// if (eigrp->router_id == 0) +// eigrp_router_id_update(eigrp); + /* Run network config now. */ + /* Get target interface. */ + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) + { + zlog_debug("Setting up %s", ifp->name); + eigrp_network_run_interface(eigrp, (struct prefix *) p, ifp); + } + return 1; +} + +/* Check whether interface matches given network + * returns: 1, true. 0, false + */ +static int +eigrp_network_match_iface(const struct connected *co, const struct prefix *net) +{ + /* new approach: more elegant and conceptually clean */ + return prefix_match(net, CONNECTED_PREFIX (co)); +} + +static void +eigrp_network_run_interface(struct eigrp *eigrp, struct prefix *p, + struct interface *ifp) +{ + struct listnode *cnode; + struct connected *co; + + /* if interface prefix is match specified prefix, + then create socket and join multicast group. */ + for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, co)) + { + + if (CHECK_FLAG (co->flags,ZEBRA_IFA_SECONDARY)) + continue; + + if (p->family == co->address->family + && !eigrp_if_table_lookup(ifp, co->address) + && eigrp_network_match_iface(co, p)) + { + struct eigrp_interface *ei; + + ei = eigrp_if_new(eigrp, ifp, co->address); + ei->connected = co; + + ei->params = eigrp_lookup_if_params(ifp, ei->address->u.prefix4); + + /* Relate eigrp interface to eigrp instance. */ + ei->eigrp = eigrp; + + /* update network type as interface flag */ + /* If network type is specified previously, + skip network type setting. */ + ei->type = IF_DEF_PARAMS (ifp)->type; + + /* if router_id is not configured, dont bring up + * interfaces. + * eigrp_router_id_update() will call eigrp_if_update + * whenever r-id is configured instead. + */ + if (if_is_operative(ifp)) + eigrp_if_up(ei); + } + } +} + +void +eigrp_if_update(struct interface *ifp) +{ + struct listnode *node, *nnode; + struct route_node *rn; + struct eigrp *eigrp; + + /* + * In the event there are multiple eigrp autonymnous systems running, + * we need to check eac one and add the interface as approperate + */ + for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) + { + /* EIGRP must be on and Router-ID must be configured. */ + if (!eigrp || eigrp->router_id == 0) + continue; + + /* Run each network for this interface. */ + for (rn = route_top(eigrp->networks); rn; rn = route_next(rn)) + if (rn->info != NULL) + { + eigrp_network_run_interface(eigrp, &rn->p, ifp); + } + } +} + +int +eigrp_network_unset(struct eigrp *eigrp, struct prefix_ipv4 *p) +{ + struct route_node *rn; + struct listnode *node, *nnode; + struct eigrp_interface *ei; + struct prefix *pref; + + rn = route_node_lookup(eigrp->networks, (struct prefix *) p); + if (rn == NULL) + return 0; + + pref = rn->info; + route_unlock_node (rn); + + if (!IPV4_ADDR_SAME (&pref->u.prefix4, &p->prefix)) + return 0; + + prefix_ipv4_free(rn->info); + rn->info = NULL; + route_unlock_node(rn); /* initial reference */ + + /* Find interfaces that not configured already. */ + for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei)) + { + int found = 0; + struct connected *co = ei->connected; + + for (rn = route_top(eigrp->networks); rn; rn = route_next(rn)) + { + if (rn->info == NULL) + continue; + + if (eigrp_network_match_iface(co, &rn->p)) + { + zlog_debug("eigrp_network_unset()2"); + found = 1; + route_unlock_node(rn); + break; + } + } + + if (found == 0) + { + eigrp_if_free(ei, INTERFACE_DOWN_BY_VTY); + } + } + + return 1; +} + +u_int32_t +eigrp_calculate_metrics(struct eigrp *eigrp, struct eigrp_metrics *metric) +{ + u_int64_t temp_metric; + temp_metric = 0; + + if(metric->delay == EIGRP_MAX_METRIC) + return EIGRP_MAX_METRIC; + + // EIGRP Metric = {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)} + + if (eigrp->k_values[0]) + temp_metric += (eigrp->k_values[0] * metric->bandwith); + if (eigrp->k_values[1]) + temp_metric += ((eigrp->k_values[1] * metric->bandwith) + / (256 - metric->load)); + if (eigrp->k_values[2]) + temp_metric += (eigrp->k_values[2] * metric->delay); + if (eigrp->k_values[3] && !eigrp->k_values[4]) + temp_metric *= eigrp->k_values[3]; + if (!eigrp->k_values[3] && eigrp->k_values[4]) + temp_metric *= (eigrp->k_values[4] / metric->reliability); + if (eigrp->k_values[3] && eigrp->k_values[4]) + temp_metric *= ((eigrp->k_values[4] / metric->reliability) + + eigrp->k_values[3]); + + if (temp_metric <= EIGRP_MAX_METRIC) + return (u_int32_t) temp_metric; + else + return EIGRP_MAX_METRIC; +} + +u_int32_t +eigrp_calculate_total_metrics(struct eigrp *eigrp, + struct eigrp_neighbor_entry *entry) +{ + entry->total_metric = entry->reported_metric; + u_int64_t temp_delay = (u_int64_t) entry->total_metric.delay + + (u_int64_t) EIGRP_IF_PARAM (entry->ei, delay); + entry->total_metric.delay = + temp_delay > EIGRP_MAX_METRIC ? EIGRP_MAX_METRIC : (u_int32_t) temp_delay; + + u_int32_t bw = EIGRP_IF_PARAM (entry->ei,bandwidth); + entry->total_metric.bandwith = + entry->total_metric.bandwith > bw ? bw : entry->total_metric.bandwith; + + return eigrp_calculate_metrics(eigrp, &entry->total_metric); +} + +u_char +eigrp_metrics_is_same(struct eigrp_metrics *metric1, + struct eigrp_metrics *metric2) +{ + if ((metric1->bandwith == metric2->bandwith) + && (metric1->delay == metric2->delay) + && (metric1->hop_count == metric2->hop_count) + && (metric1->load == metric2->load) + && (metric1->reliability == metric2->reliability) + && (metric1->mtu[0] == metric2->mtu[0]) + && (metric1->mtu[1] == metric2->mtu[1]) + && (metric1->mtu[2] == metric2->mtu[2])) + return 1; + + return 0; // if different +} +void +eigrp_external_routes_refresh (struct eigrp *eigrp, int type) +{ + + +} + diff --git a/eigrpd/eigrp_network.h b/eigrpd/eigrp_network.h new file mode 100644 index 000000000..87d128062 --- /dev/null +++ b/eigrpd/eigrp_network.h @@ -0,0 +1,52 @@ +/* + * EIGRP Network Related Functions. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * 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. + */ + +#ifndef _ZEBRA_EIGRP_NETWORK_H +#define _ZEBRA_EIGRP_NETWORK_H + +/* Prototypes */ + +extern int eigrp_sock_init (void); +extern int eigrp_if_ipmulticast (struct eigrp *, struct prefix *, unsigned int); +extern int eigrp_network_set (struct eigrp *, struct prefix_ipv4 *); +extern int eigrp_network_unset (struct eigrp *eigrp, struct prefix_ipv4 *p); + +extern int eigrp_hello_timer (struct thread *); +extern void eigrp_if_update (struct interface *); +extern int eigrp_if_add_allspfrouters (struct eigrp *, struct prefix *, + unsigned int); +extern int eigrp_if_drop_allspfrouters (struct eigrp *top, struct prefix *p, + unsigned int ifindex); +extern void eigrp_adjust_sndbuflen (struct eigrp *, unsigned int); + +extern u_int32_t eigrp_calculate_metrics (struct eigrp *, struct eigrp_metrics *); +extern u_int32_t eigrp_calculate_total_metrics (struct eigrp *, struct eigrp_neighbor_entry *); +extern u_char eigrp_metrics_is_same(struct eigrp_metrics *,struct eigrp_metrics *); +extern void eigrp_external_routes_refresh (struct eigrp *, int); + +#endif /* EIGRP_NETWORK_H_ */ diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c new file mode 100644 index 000000000..9a0a9897f --- /dev/null +++ b/eigrpd/eigrp_packet.c @@ -0,0 +1,1441 @@ +/* + * EIGRP General Sending and Receiving of EIGRP Packets. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "vty.h" +#include "keychain.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "sockunion.h" +#include "stream.h" +#include "log.h" +#include "sockopt.h" +#include "checksum.h" +#include "md5.h" +#include "sha256.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_fsm.h" +#include "eigrpd/eigrp_memory.h" + +/* Packet Type String. */ +const struct message eigrp_packet_type_str[] = +{ + { EIGRP_OPC_UPDATE, "Update" }, + { EIGRP_OPC_REQUEST, "Request" }, + { EIGRP_OPC_QUERY, "Query" }, + { EIGRP_OPC_REPLY, "Reply" }, + { EIGRP_OPC_HELLO, "Hello" }, + { EIGRP_OPC_IPXSAP, "IPX-SAP" }, + { EIGRP_OPC_PROBE, "Probe" }, + { EIGRP_OPC_ACK, "Ack" }, + { EIGRP_OPC_SIAQUERY, "SIAQuery" }, + { EIGRP_OPC_SIAREPLY, "SIAReply" }, +}; +const size_t eigrp_packet_type_str_max = sizeof(eigrp_packet_type_str) / + sizeof(eigrp_packet_type_str[0]); + +static unsigned char zeropad[16] = {0}; + +/* Forward function reference*/ +static struct stream * eigrp_recv_packet (int, struct interface **, struct stream *); +static int eigrp_verify_header (struct stream *, struct eigrp_interface *, struct ip *, + struct eigrp_header *); +static int eigrp_check_network_mask (struct eigrp_interface *, struct in_addr); + + +static int eigrp_retrans_count_exceeded(struct eigrp_packet *ep, struct eigrp_neighbor *nbr) +{ + return 1; +} + +int +eigrp_make_md5_digest (struct eigrp_interface *ei, struct stream *s, u_char flags) +{ + struct key *key = NULL; + struct keychain *keychain; + + unsigned char digest[EIGRP_AUTH_TYPE_MD5_LEN]; + MD5_CTX ctx; + u_char *ibuf; + size_t backup_get, backup_end; + struct TLV_MD5_Authentication_Type *auth_TLV; + + ibuf = s->data; + backup_end = s->endp; + backup_get = s->getp; + + auth_TLV = eigrp_authTLV_MD5_new(); + + stream_set_getp(s,EIGRP_HEADER_LEN); + stream_get(auth_TLV,s,EIGRP_AUTH_MD5_TLV_SIZE); + stream_set_getp(s, backup_get); + + keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain); + if(keychain) + key = key_lookup_for_send(keychain); + else + return EIGRP_AUTH_TYPE_NONE; + + memset(&ctx, 0, sizeof(ctx)); + MD5Init(&ctx); + + /* Generate a digest. Each situation needs different handling */ + if(flags & EIGRP_AUTH_BASIC_HELLO_FLAG) + { + MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE); + MD5Update(&ctx, key->string, strlen(key->string)); + if(strlen(key->string) < 16) + MD5Update(&ctx, zeropad, 16 - strlen(key->string)); + } + else if(flags & EIGRP_AUTH_UPDATE_INIT_FLAG) + { + MD5Update(&ctx, ibuf, EIGRP_MD5_UPDATE_INIT_COMPUTE); + } + else if(flags & EIGRP_AUTH_UPDATE_FLAG) + { + MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE); + MD5Update(&ctx, key->string, strlen(key->string)); + if(strlen(key->string) < 16) + MD5Update(&ctx, zeropad, 16 - strlen(key->string)); + if(backup_end > (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE)) + { + MD5Update(&ctx, ibuf + (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE), + backup_end - 20 - (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE)); + } + } + + MD5Final(digest, &ctx); + + + /* Append md5 digest to the end of the stream. */ + memcpy(auth_TLV->digest,digest,EIGRP_AUTH_TYPE_MD5_LEN); + + stream_set_endp(s,EIGRP_HEADER_LEN); + stream_put(s,auth_TLV,EIGRP_AUTH_MD5_TLV_SIZE); + stream_set_endp(s, backup_end); + + eigrp_authTLV_MD5_free(auth_TLV); + return EIGRP_AUTH_TYPE_MD5_LEN; +} + +int +eigrp_check_md5_digest (struct stream *s, struct TLV_MD5_Authentication_Type *authTLV,struct eigrp_neighbor *nbr, u_char flags) +{ + MD5_CTX ctx; + unsigned char digest[EIGRP_AUTH_TYPE_MD5_LEN]; + struct key *key = NULL; + struct keychain *keychain; + u_char *ibuf; + size_t backup_end; + struct TLV_MD5_Authentication_Type *auth_TLV; + struct eigrp_header *eigrph; + + + if (nbr && ntohl(nbr->crypt_seqnum) > ntohl(authTLV->key_sequence)) + { + zlog_warn ("interface %s: eigrp_check_md5 bad sequence %d (expect %d)", + IF_NAME (nbr->ei), + ntohl(authTLV->key_sequence), + ntohl(nbr->crypt_seqnum)); + return 0; + } + + eigrph = (struct eigrp_header *) s->data; + eigrph->checksum = 0; + + auth_TLV =(struct TLV_MD5_Authentication_Type *) (s->data + EIGRP_HEADER_LEN); + memcpy(auth_TLV->digest, "0", sizeof(auth_TLV->digest)); + + ibuf = s->data; + backup_end = s->endp; + + keychain = keychain_lookup(IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain); + if(keychain) + key = key_lookup_for_send(keychain); + + memset(&ctx, 0, sizeof(ctx)); + MD5Init(&ctx); + + /* Generate a digest. Each situation needs different handling */ + if(flags & EIGRP_AUTH_BASIC_HELLO_FLAG) + { + MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE); + MD5Update(&ctx, key->string, strlen(key->string)); + if(strlen(key->string) < 16) + MD5Update(&ctx, zeropad, 16 - strlen(key->string)); + } + else if(flags & EIGRP_AUTH_UPDATE_INIT_FLAG) + { + MD5Update(&ctx, ibuf, EIGRP_MD5_UPDATE_INIT_COMPUTE); + } + else if(flags & EIGRP_AUTH_UPDATE_FLAG) + { + MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE); + MD5Update(&ctx, key->string, strlen(key->string)); + if(strlen(key->string) < 16) + MD5Update(&ctx, zeropad, 16 - strlen(key->string)); + if(backup_end > (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE)) + { + MD5Update(&ctx, ibuf + (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE), + backup_end - 20 - (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE)); + } + } + + MD5Final(digest, &ctx); + + /* compare the two */ + if (memcmp (authTLV->digest, digest, EIGRP_AUTH_TYPE_MD5_LEN) == 0) + { + zlog_debug("VSETKO OK"); + } + else + { + zlog_warn ("interface %s: eigrp_check_md5 checksum mismatch", + IF_NAME (nbr->ei)); + return 0; + } + + /* save neighbor's crypt_seqnum */ + if (nbr) + nbr->crypt_seqnum = authTLV->key_sequence; + + return 1; +} + +int +eigrp_make_sha256_digest (struct eigrp_interface *ei, struct stream *s, u_char flags) +{ + struct key *key = NULL; + struct keychain *keychain; + char *source_ip; + + unsigned char digest[EIGRP_AUTH_TYPE_SHA256_LEN]; + unsigned char buffer[1 + PLAINTEXT_LENGTH + 45 + 1] = { 0 }; + HMAC_SHA256_CTX ctx; + void *ibuf; + size_t backup_get, backup_end; + struct TLV_SHA256_Authentication_Type *auth_TLV; + + ibuf = s->data; + backup_end = s->endp; + backup_get = s->getp; + + auth_TLV = eigrp_authTLV_SHA256_new (); + + stream_set_getp(s,EIGRP_HEADER_LEN); + stream_get(auth_TLV,s,EIGRP_AUTH_SHA256_TLV_SIZE); + stream_set_getp(s, backup_get); + + keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain); + if(keychain) + key = key_lookup_for_send(keychain); + +// saved_len[index] = strnzcpyn(saved_key[index], key, +// PLAINTEXT_LENGTH + 1); + + source_ip = calloc(16, sizeof(char)); + inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, 16); + + memset(&ctx, 0, sizeof(ctx)); + buffer[0] = '\n'; + memcpy(buffer + 1, key, strlen (key->string)); + memcpy(buffer + 1 + strlen(key->string), source_ip, strlen(source_ip)); + HMAC__SHA256_Init(&ctx, buffer, 1 + strlen (key->string) + strlen(source_ip)); + HMAC__SHA256_Update(&ctx, ibuf, strlen(ibuf)); + HMAC__SHA256_Final(digest, &ctx); + + + /* Put hmac-sha256 digest to it's place */ + memcpy(auth_TLV->digest,digest,EIGRP_AUTH_TYPE_SHA256_LEN); + + stream_set_endp(s,EIGRP_HEADER_LEN); + stream_put(s,auth_TLV,EIGRP_AUTH_SHA256_TLV_SIZE); + stream_set_endp(s, backup_end); + + eigrp_authTLV_SHA256_free(auth_TLV); + free(source_ip); + + return EIGRP_AUTH_TYPE_SHA256_LEN; +} + +int +eigrp_check_sha256_digest (struct stream *s, struct TLV_SHA256_Authentication_Type *authTLV,struct eigrp_neighbor *nbr, u_char flags) +{ + + return 1; +} +/* + * eigrp_packet_dump + * + * This routing dumps the contents of the IP packet either received or + * built by EIGRP. + */ +static void +eigrp_packet_dump (struct stream *s) +{ + // not yet... + return; +} + +/* + * Converts a 24-bit integer represented as an unsigned char[3] *value + * in network byte order into uint32_t in host byte order + */ +//static uint32_t u24_32 (const unsigned char *value) +//{ +// return (value[0] << 16) + (value[1] << 8) + value[2]; +//} +// +///* +// * Converts an uint32_t value in host byte order into a 24-bit integer +// * in network byte order represented by unsigned char[3] *result +// */ +//static unsigned char * u32_24 (uint32_t value, unsigned char *result) +//{ +// value = htonl(value & 0x00FFFFFF); +// memcpy (result, (unsigned char *) &value + 1, 3); +// +// return result; +//} + +int +eigrp_write (struct thread *thread) +{ + struct eigrp *eigrp = THREAD_ARG(thread); + struct eigrp_header *eigrph; + struct eigrp_interface *ei; + struct eigrp_packet *ep; + struct sockaddr_in sa_dst; + struct ip iph; + struct msghdr msg; + struct iovec iov[2]; + u_int16_t opcode = 0; + + int ret; + int flags = 0; + struct listnode *node; +#ifdef WANT_EIGRP_WRITE_FRAGMENT + static u_int16_t ipid = 0; +#endif /* WANT_EIGRP_WRITE_FRAGMENT */ +#define EIGRP_WRITE_IPHL_SHIFT 2 + + eigrp->t_write = NULL; + + node = listhead(eigrp->oi_write_q); + assert(node); + ei = listgetdata(node); + assert(ei); + +#ifdef WANT_EIGRP_WRITE_FRAGMENT + /* seed ipid static with low order bits of time */ + if (ipid == 0) + ipid = (time(NULL) & 0xffff); +#endif /* WANT_EIGRP_WRITE_FRAGMENT */ + + /* Get one packet from queue. */ + ep = eigrp_fifo_head(ei->obuf); + assert(ep); + assert(ep->length >= EIGRP_HEADER_LEN); + + if (ep->dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) + eigrp_if_ipmulticast(eigrp, ei->address, ei->ifp->ifindex); + + memset(&iph, 0, sizeof(struct ip)); + memset(&sa_dst, 0, sizeof(sa_dst)); + + sa_dst.sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + sa_dst.sin_len = sizeof(sa_dst); +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + sa_dst.sin_addr = ep->dst; + sa_dst.sin_port = htons(0); + + /* Set DONTROUTE flag if dst is unicast. */ + if (!IN_MULTICAST(htonl(ep->dst.s_addr))) + flags = MSG_DONTROUTE; + + iph.ip_hl = sizeof(struct ip) >> EIGRP_WRITE_IPHL_SHIFT; + /* it'd be very strange for header to not be 4byte-word aligned but.. */ + if (sizeof(struct ip) > (unsigned int)(iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT)) + iph.ip_hl++; /* we presume sizeof struct ip cant overflow ip_hl.. */ + + iph.ip_v = IPVERSION; + iph.ip_tos = IPTOS_PREC_INTERNETCONTROL; + iph.ip_len = (iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT) + ep->length; + +#if defined (__DragonFly__) + /* + * DragonFly's raw socket expects ip_len/ip_off in network byte order. + */ + iph.ip_len = htons(iph.ip_len); +#endif + + iph.ip_off = 0; + iph.ip_ttl = EIGRP_IP_TTL; + iph.ip_p = IPPROTO_EIGRPIGP; + iph.ip_sum = 0; + iph.ip_src.s_addr = ei->address->u.prefix4.s_addr; + iph.ip_dst.s_addr = ep->dst.s_addr; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = (caddr_t) &sa_dst; + msg.msg_namelen = sizeof(sa_dst); + msg.msg_iov = iov; + msg.msg_iovlen = 2; + + iov[0].iov_base = (char*)&iph; + iov[0].iov_len = iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT; + iov[1].iov_base = STREAM_PNT(ep->s); + iov[1].iov_len = ep->length; + + /* send final fragment (could be first) */ + sockopt_iphdrincl_swab_htosys(&iph); + ret = sendmsg(eigrp->fd, &msg, flags); + sockopt_iphdrincl_swab_systoh(&iph); + + if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND)) + { + eigrph = (struct eigrp_header *) STREAM_DATA(ep->s); + opcode = eigrph->opcode; + zlog_debug("Sending [%s] to [%s] via [%s] ret [%d].", + LOOKUP(eigrp_packet_type_str, opcode), inet_ntoa(ep->dst), + IF_NAME(ei), ret); + } + + if (ret < 0) + zlog_warn("*** sendmsg in eigrp_write failed to %s, " + "id %d, off %d, len %d, interface %s, mtu %u: %s", + inet_ntoa(iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len, ei->ifp->name, + ei->ifp->mtu, safe_strerror(errno)); + + /* Show debug sending packet. */ + if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND) && (IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))) + { + zlog_debug("-----------------------------------------------------"); + eigrp_ip_header_dump(&iph); + stream_set_getp(ep->s, 0); + eigrp_packet_dump(ep->s); + zlog_debug("-----------------------------------------------------"); + } + + /* Now delete packet from queue. */ + eigrp_packet_delete(ei); + + if (eigrp_fifo_head(ei->obuf) == NULL) + { + ei->on_write_q = 0; + list_delete_node(eigrp->oi_write_q, node); + } + + /* If packets still remain in queue, call write thread. */ + if (!list_isempty(eigrp->oi_write_q)) + eigrp->t_write = thread_add_write(master, eigrp_write, eigrp, eigrp->fd); + + return 0; +} + +/* Starting point of packet process function. */ +int +eigrp_read (struct thread *thread) +{ + int ret; + struct stream *ibuf; + struct eigrp *eigrp; + struct eigrp_interface *ei; + struct ip *iph; + struct eigrp_header *eigrph; + struct interface *ifp; + struct eigrp_neighbor *nbr; + + u_int16_t opcode = 0; + u_int16_t length = 0; + + /* first of all get interface pointer. */ + eigrp = THREAD_ARG(thread); + + /* prepare for next packet. */ + eigrp->t_read = thread_add_read(master, eigrp_read, eigrp, eigrp->fd); + + stream_reset(eigrp->ibuf); + if (!(ibuf = eigrp_recv_packet(eigrp->fd, &ifp, eigrp->ibuf))) + { + /* This raw packet is known to be at least as big as its IP header. */ + return -1; + } + + /* Note that there should not be alignment problems with this assignment + because this is at the beginning of the stream data buffer. */ + iph = (struct ip *)STREAM_DATA(ibuf); + + //Substract IPv4 header size from EIGRP Packet itself + if(iph->ip_v == 4) + length = (iph->ip_len) - 20U; + + + /* IP Header dump. */ + if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV) && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL)) + eigrp_ip_header_dump(iph); + + /* Note that sockopt_iphdrincl_swab_systoh was called in eigrp_recv_packet. */ + if (ifp == NULL) + { + /* Handle cases where the platform does not support retrieving the ifindex, + and also platforms (such as Solaris 8) that claim to support ifindex + retrieval but do not. */ + ifp = if_lookup_address((void *)&iph->ip_src, VRF_DEFAULT); + + if (ifp == NULL) + return 0; + } + + /* associate packet with eigrp interface */ + ei = eigrp_if_lookup_recv_if(eigrp, iph->ip_src, ifp); + + /* eigrp_verify_header() relies on a valid "ei" and thus can be called only + after the checks below are passed. These checks in turn access the + fields of unverified "eigrph" structure for their own purposes and + must remain very accurate in doing this. + */ + if (!ei) + return 0; + + /* Self-originated packet should be discarded silently. */ + if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src) || + (IPV4_ADDR_SAME(&iph->ip_src.s_addr, &ei->address->u.prefix4))) + { + if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) + zlog_debug("eigrp_read[%s]: Dropping self-originated packet", + inet_ntoa(iph->ip_src)); + return 0; + } + + /* Advance from IP header to EIGRP header (iph->ip_hl has been verified + by eigrp_recv_packet() to be correct). */ + + stream_forward_getp(ibuf, (iph->ip_hl * 4)); + eigrph = (struct eigrp_header *) STREAM_PNT(ibuf); + + if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV) && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL)) + eigrp_header_dump(eigrph); + +// if (MSG_OK != eigrp_packet_examin(eigrph, stream_get_endp(ibuf) - stream_get_getp(ibuf))) +// return -1; + + /* Now it is safe to access all fields of EIGRP packet header. */ + /* associate packet with eigrp interface */ + ei = eigrp_if_lookup_recv_if(eigrp, iph->ip_src, ifp); + + /* eigrp_verify_header() relies on a valid "ei" and thus can be called only + after the checks below are passed. These checks in turn access the + fields of unverified "eigrph" structure for their own purposes and + must remain very accurate in doing this. + */ + if (!ei) + return 0; + + /* If incoming interface is passive one, ignore it. */ + if (ei && EIGRP_IF_PASSIVE_STATUS(ei) == EIGRP_IF_PASSIVE) + { + char buf[3][INET_ADDRSTRLEN]; + + if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) + zlog_debug("ignoring packet from router %s sent to %s, " + "received on a passive interface, %s", + inet_ntop(AF_INET, &eigrph->vrid, buf[0], sizeof(buf[0])), + inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])), + inet_ntop(AF_INET, &ei->address->u.prefix4, + buf[2], sizeof(buf[2]))); + + if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) + { + /* Try to fix multicast membership. + * Some OS:es may have problems in this area, + * make sure it is removed. + */ + EI_MEMBER_JOINED(ei, MEMBER_ALLROUTERS); + eigrp_if_set_multicast(ei); + } + return 0; + } + + /* else it must be a local eigrp interface, check it was received on + * correct link + */ + else if (ei->ifp != ifp) + { + if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) + zlog_warn("Packet from [%s] received on wrong link %s", + inet_ntoa(iph->ip_src), ifp->name); + return 0; + } + + /* Verify more EIGRP header fields. */ + ret = eigrp_verify_header(ibuf, ei, iph, eigrph); + if (ret < 0) + { + if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) + zlog_debug("eigrp_read[%s]: Header check failed, dropping.", + inet_ntoa(iph->ip_src)); + return ret; + } + + /* calcualte the eigrp packet length, and move the pounter to the + start of the eigrp TLVs */ + opcode = eigrph->opcode; + + if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) + zlog_debug("Received [%s] length [%u] via [%s] src [%s] dst [%s]", + LOOKUP(eigrp_packet_type_str, opcode), length, + IF_NAME(ei), inet_ntoa(iph->ip_src), inet_ntoa(iph->ip_dst)); + + /* Read rest of the packet and call each sort of packet routine. */ + stream_forward_getp(ibuf, EIGRP_HEADER_LEN); + + + /* New testing block of code for handling Acks */ + if (ntohl(eigrph->ack) != 0) + { + nbr = eigrp_nbr_get(ei, eigrph, iph); + + /* neighbor must be valid, eigrp_nbr_get creates if none existed */ + assert(nbr); + + struct eigrp_packet *ep; + + ep = eigrp_fifo_tail(nbr->retrans_queue); + if (ep != NULL) + { + if (ntohl(eigrph->ack) == ep->sequence_number) + { + if((nbr->state == EIGRP_NEIGHBOR_PENDING) && (ntohl(eigrph->ack) == nbr->init_sequence_number)) + { + eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_UP); + zlog_info("Neighbor adjacency became full"); + nbr->init_sequence_number = 0; + nbr->recv_sequence_number = ntohl(eigrph->sequence); + eigrp_update_send_EOT(nbr); + } + ep = eigrp_fifo_pop_tail(nbr->retrans_queue); + /*eigrp_packet_free(ep);*/ + if (nbr->retrans_queue->count > 0) + { + eigrp_send_packet_reliably(nbr); + } + } + } + ep = eigrp_fifo_tail(nbr->multicast_queue); + if (ep != NULL) + { + if (ntohl(eigrph->ack) == ep->sequence_number) + { + ep = eigrp_fifo_pop_tail(nbr->multicast_queue); + eigrp_packet_free(ep); + if (nbr->multicast_queue->count > 0) + { + eigrp_send_packet_reliably(nbr); + } + } + } + } + + + switch (opcode) + { + case EIGRP_OPC_HELLO: + eigrp_hello_receive(eigrp, iph, eigrph, ibuf, ei, length); + break; + case EIGRP_OPC_PROBE: + // eigrp_probe_receive(eigrp, iph, eigrph, ibuf, ei, length); + break; + case EIGRP_OPC_QUERY: + eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length); + break; + case EIGRP_OPC_REPLY: + eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length); + break; + case EIGRP_OPC_REQUEST: + // eigrp_request_receive(eigrp, iph, eigrph, ibuf, ei, length); + break; + case EIGRP_OPC_SIAQUERY: + eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length); + break; + case EIGRP_OPC_SIAREPLY: + eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length); + break; + case EIGRP_OPC_UPDATE: + eigrp_update_receive(eigrp, iph, eigrph, ibuf, ei, length); + break; + default: + zlog(NULL, LOG_WARNING, + "interface %s: EIGRP packet header type %d unsupported", + IF_NAME(ei), opcode); + break; + } + + return 0; +} + +static struct stream * +eigrp_recv_packet (int fd, struct interface **ifp, struct stream *ibuf) +{ + int ret; + struct ip *iph; + u_int16_t ip_len; + unsigned int ifindex = 0; + struct iovec iov; + /* Header and data both require alignment. */ + char buff[CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())]; + struct msghdr msgh; + + memset(&msgh, 0, sizeof(struct msghdr)); + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + msgh.msg_control = (caddr_t) buff; + msgh.msg_controllen = sizeof(buff); + + ret = stream_recvmsg(ibuf, fd, &msgh, 0, (EIGRP_PACKET_MAX_LEN + 1)); + if (ret < 0) + { + zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno)); + return NULL; + } + if ((unsigned int) ret < sizeof(iph)) /* ret must be > 0 now */ + { + zlog_warn("eigrp_recv_packet: discarding runt packet of length %d " + "(ip header size is %u)", ret, (u_int) sizeof(iph)); + return NULL; + } + + /* Note that there should not be alignment problems with this assignment + because this is at the beginning of the stream data buffer. */ + iph = (struct ip *) STREAM_DATA(ibuf); + sockopt_iphdrincl_swab_systoh(iph); + + ip_len = iph->ip_len; + +#if !defined (GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000) + /* + * Kernel network code touches incoming IP header parameters, + * before protocol specific processing. + * + * 1) Convert byteorder to host representation. + * --> ip_len, ip_id, ip_off + * + * 2) Adjust ip_len to strip IP header size! + * --> If user process receives entire IP packet via RAW + * socket, it must consider adding IP header size to + * the "ip_len" field of "ip" structure. + * + * For more details, see <netinet/ip_input.c>. + */ + ip_len = ip_len + (iph->ip_hl << 2); +#endif + +#if defined (__DragonFly__) + /* + * in DragonFly's raw socket, ip_len/ip_off are read + * in network byte order. + * As OpenBSD < 200311 adjust ip_len to strip IP header size! + */ + ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2); +#endif + + ifindex = getsockopt_ifindex(AF_INET, &msgh); + + *ifp = if_lookup_by_index(ifindex); + + if (ret != ip_len) + { + zlog_warn("eigrp_recv_packet read length mismatch: ip_len is %d, " + "but recvmsg returned %d", ip_len, ret); + return NULL; + } + + return ibuf; +} + +struct eigrp_fifo * +eigrp_fifo_new (void) +{ + struct eigrp_fifo *new; + + new = XCALLOC(MTYPE_EIGRP_FIFO, sizeof(struct eigrp_fifo)); + return new; +} + +/* Free eigrp packet fifo. */ +void +eigrp_fifo_free (struct eigrp_fifo *fifo) +{ + struct eigrp_packet *ep; + struct eigrp_packet *next; + + for (ep = fifo->head; ep; ep = next) + { + next = ep->next; + eigrp_packet_free(ep); + } + fifo->head = fifo->tail = NULL; + fifo->count = 0; + + XFREE(MTYPE_EIGRP_FIFO, fifo); +} + +/* Free eigrp fifo entries without destroying fifo itself*/ +void +eigrp_fifo_reset (struct eigrp_fifo *fifo) +{ + struct eigrp_packet *ep; + struct eigrp_packet *next; + + for (ep = fifo->head; ep; ep = next) + { + next = ep->next; + eigrp_packet_free(ep); + } + fifo->head = fifo->tail = NULL; + fifo->count = 0; +} + +struct eigrp_packet * +eigrp_packet_new (size_t size) +{ + struct eigrp_packet *new; + + new = XCALLOC(MTYPE_EIGRP_PACKET, sizeof(struct eigrp_packet)); + new->s = stream_new(size); + new->retrans_counter = 0; + + return new; +} + +void +eigrp_send_packet_reliably (struct eigrp_neighbor *nbr) +{ + struct eigrp_packet *ep; + + ep = eigrp_fifo_tail(nbr->retrans_queue); + + if (ep) + { + struct eigrp_packet *duplicate; + duplicate = eigrp_packet_duplicate(ep, nbr); + /* Add packet to the top of the interface output queue*/ + eigrp_fifo_push_head(nbr->ei->obuf, duplicate); + + /*Start retransmission timer*/ + THREAD_TIMER_ON(master, ep->t_retrans_timer, eigrp_unack_packet_retrans, + nbr, EIGRP_PACKET_RETRANS_TIME); + + /*Increment sequence number counter*/ + nbr->ei->eigrp->sequence_number++; + + /* Hook thread to write packet. */ + if (nbr->ei->on_write_q == 0) + { + listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei); + nbr->ei->on_write_q = 1; + } + if (nbr->ei->eigrp->t_write == NULL) + nbr->ei->eigrp->t_write = + thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd); + } +} + +/* Calculate EIGRP checksum */ +void +eigrp_packet_checksum (struct eigrp_interface *ei, struct stream *s, + u_int16_t length) +{ + struct eigrp_header *eigrph; + + eigrph = (struct eigrp_header *) STREAM_DATA(s); + + /* Calculate checksum. */ + eigrph->checksum = in_cksum(eigrph, length); +} + +/* Make EIGRP header. */ +void +eigrp_packet_header_init (int type, struct eigrp_interface *ei, struct stream *s, + u_int32_t flags, u_int32_t sequence, u_int32_t ack) +{ + struct eigrp_header *eigrph; + + eigrph = (struct eigrp_header *) STREAM_DATA(s); + + eigrph->version = (u_char) EIGRP_HEADER_VERSION; + eigrph->opcode = (u_char) type; + eigrph->checksum = 0; + + eigrph->vrid = htons(ei->eigrp->vrid); + eigrph->ASNumber = htons(ei->eigrp->AS); + eigrph->ack = htonl(ack); + eigrph->sequence = htonl(sequence); +// if(flags == EIGRP_INIT_FLAG) +// eigrph->sequence = htonl(3); + eigrph->flags = htonl(flags); + + if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) + zlog_debug("Packet Header Init Seq [%u] Ack [%u]", + htonl(eigrph->sequence), htonl(eigrph->ack)); + + stream_forward_endp(s, EIGRP_HEADER_LEN); +} + +/* Add new packet to head of fifo. */ +void +eigrp_fifo_push_head (struct eigrp_fifo *fifo, struct eigrp_packet *ep) +{ + ep->next = fifo->head; + ep->previous = NULL; + + if (fifo->tail == NULL) + fifo->tail = ep; + + if (fifo->count != 0) + fifo->head->previous = ep; + + fifo->head = ep; + + fifo->count++; +} + +/* Return first fifo entry. */ +struct eigrp_packet * +eigrp_fifo_head (struct eigrp_fifo *fifo) +{ + return fifo->head; +} + +/* Return last fifo entry. */ +struct eigrp_packet * +eigrp_fifo_tail (struct eigrp_fifo *fifo) +{ + return fifo->tail; +} + +void +eigrp_packet_delete (struct eigrp_interface *ei) +{ + struct eigrp_packet *ep; + + ep = eigrp_fifo_pop (ei->obuf); + + if (ep) + eigrp_packet_free(ep); +} + +/* Delete first packet from fifo. */ +struct eigrp_packet * +eigrp_fifo_pop (struct eigrp_fifo *fifo) +{ + struct eigrp_packet *ep; + + ep = fifo->head; + + if (ep) + { + fifo->head = ep->next; + + if (fifo->head == NULL) + fifo->tail = NULL; + else + fifo->head->previous = NULL; + + fifo->count--; + } + + return ep; +} + +void +eigrp_packet_free (struct eigrp_packet *ep) +{ + if (ep->s) + stream_free(ep->s); + + THREAD_OFF(ep->t_retrans_timer); + + XFREE(MTYPE_EIGRP_PACKET, ep); + + ep = NULL; +} + +/* EIGRP Header verification. */ +static int +eigrp_verify_header (struct stream *ibuf, struct eigrp_interface *ei, + struct ip *iph, struct eigrp_header *eigrph) +{ + + /* Check network mask, Silently discarded. */ + if (!eigrp_check_network_mask(ei, iph->ip_src)) + { + zlog_warn("interface %s: eigrp_read network address is not same [%s]", + IF_NAME(ei), inet_ntoa(iph->ip_src)); + return -1; + } +// +// /* Check authentication. The function handles logging actions, where required. */ +// if (! eigrp_check_auth(ei, eigrph)) +// return -1; + + return 0; +} + +/* Unbound socket will accept any Raw IP packets if proto is matched. + To prevent it, compare src IP address and i/f address with masking + i/f network mask. */ +static int +eigrp_check_network_mask (struct eigrp_interface *ei, struct in_addr ip_src) +{ + struct in_addr mask, me, him; + + if (ei->type == EIGRP_IFTYPE_POINTOPOINT) + return 1; + + masklen2ip(ei->address->prefixlen, &mask); + + me.s_addr = ei->address->u.prefix4.s_addr & mask.s_addr; + him.s_addr = ip_src.s_addr & mask.s_addr; + + if (IPV4_ADDR_SAME(&me, &him)) + return 1; + + return 0; +} + +int +eigrp_unack_packet_retrans (struct thread *thread) +{ + struct eigrp_neighbor *nbr; + nbr = (struct eigrp_neighbor *) THREAD_ARG(thread); + + struct eigrp_packet *ep; + ep = eigrp_fifo_tail(nbr->retrans_queue); + + if (ep) + { + struct eigrp_packet *duplicate; + duplicate = eigrp_packet_duplicate(ep, nbr); + + /* Add packet to the top of the interface output queue*/ + eigrp_fifo_push_head(nbr->ei->obuf, duplicate); + + ep->retrans_counter++; + if(ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX) + return eigrp_retrans_count_exceeded(ep, nbr); + + /*Start retransmission timer*/ + ep->t_retrans_timer = + thread_add_timer(master, eigrp_unack_packet_retrans, nbr,EIGRP_PACKET_RETRANS_TIME); + + /* Hook thread to write packet. */ + if (nbr->ei->on_write_q == 0) + { + listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei); + nbr->ei->on_write_q = 1; + } + if (nbr->ei->eigrp->t_write == NULL) + nbr->ei->eigrp->t_write = + thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd); + } + + return 0; +} + +int +eigrp_unack_multicast_packet_retrans (struct thread *thread) +{ + struct eigrp_neighbor *nbr; + nbr = (struct eigrp_neighbor *) THREAD_ARG(thread); + + struct eigrp_packet *ep; + ep = eigrp_fifo_tail(nbr->multicast_queue); + + if (ep) + { + struct eigrp_packet *duplicate; + duplicate = eigrp_packet_duplicate(ep, nbr); + /* Add packet to the top of the interface output queue*/ + eigrp_fifo_push_head(nbr->ei->obuf, duplicate); + + ep->retrans_counter++; + if(ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX) + return eigrp_retrans_count_exceeded(ep, nbr); + + /*Start retransmission timer*/ + ep->t_retrans_timer = + thread_add_timer(master, eigrp_unack_multicast_packet_retrans, nbr,EIGRP_PACKET_RETRANS_TIME); + + /* Hook thread to write packet. */ + if (nbr->ei->on_write_q == 0) + { + listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei); + nbr->ei->on_write_q = 1; + } + if (nbr->ei->eigrp->t_write == NULL) + nbr->ei->eigrp->t_write = + thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd); + } + + return 0; +} + +/* Get packet from tail of fifo. */ +struct eigrp_packet * +eigrp_fifo_pop_tail (struct eigrp_fifo *fifo) +{ + struct eigrp_packet *ep; + + ep = fifo->tail; + + if (ep) + { + fifo->tail = ep->previous; + + if (fifo->tail == NULL) + fifo->head = NULL; + else + fifo->tail->next = NULL; + + fifo->count--; + } + + return ep; +} + +struct eigrp_packet * +eigrp_packet_duplicate (struct eigrp_packet *old, struct eigrp_neighbor *nbr) +{ + struct eigrp_packet *new; + + new = eigrp_packet_new(nbr->ei->ifp->mtu); + new->length = old->length; + new->retrans_counter = old->retrans_counter; + new->dst = old->dst; + new->sequence_number = old->sequence_number; + stream_copy(new->s, old->s); + + return new; +} + +struct TLV_IPv4_Internal_type * +eigrp_read_ipv4_tlv (struct stream *s) +{ + struct TLV_IPv4_Internal_type *tlv; + + tlv = eigrp_IPv4_InternalTLV_new (); + + tlv->type = stream_getw(s); + tlv->length = stream_getw(s); + tlv->forward.s_addr = stream_getl(s); + tlv->metric.delay = stream_getl(s); + tlv->metric.bandwith = stream_getl(s); + tlv->metric.mtu[0] = stream_getc(s); + tlv->metric.mtu[1] = stream_getc(s); + tlv->metric.mtu[2] = stream_getc(s); + tlv->metric.hop_count = stream_getc(s); + tlv->metric.reliability = stream_getc(s); + tlv->metric.load = stream_getc(s); + tlv->metric.tag = stream_getc(s); + tlv->metric.flags = stream_getc(s); + + tlv->prefix_length = stream_getc(s); + + if (tlv->prefix_length <= 8) + { + tlv->destination_part[0] = stream_getc(s); + tlv->destination.s_addr = (tlv->destination_part[0]); + + } + else if (tlv->prefix_length > 8 && tlv->prefix_length <= 16) + { + tlv->destination_part[0] = stream_getc(s); + tlv->destination_part[1] = stream_getc(s); + tlv->destination.s_addr = ((tlv->destination_part[1] << 8) + + tlv->destination_part[0]); + } + else if (tlv->prefix_length > 16 && tlv->prefix_length <= 24) + { + tlv->destination_part[0] = stream_getc(s); + tlv->destination_part[1] = stream_getc(s); + tlv->destination_part[2] = stream_getc(s); + tlv->destination.s_addr = ((tlv->destination_part[2] << 16) + + (tlv->destination_part[1] << 8) + tlv->destination_part[0]); + } + else if (tlv->prefix_length > 24 && tlv->prefix_length <= 32) + { + tlv->destination_part[0] = stream_getc(s); + tlv->destination_part[1] = stream_getc(s); + tlv->destination_part[2] = stream_getc(s); + tlv->destination_part[3] = stream_getc(s); + tlv->destination.s_addr = ((tlv->destination_part[3] << 24) + + (tlv->destination_part[2] << 16) + (tlv->destination_part[1] << 8) + + tlv->destination_part[0]); + } + return tlv; +} + +u_int16_t +eigrp_add_internalTLV_to_stream (struct stream *s, + struct eigrp_prefix_entry *pe) +{ + u_int16_t length; + + stream_putw(s, EIGRP_TLV_IPv4_INT); + if (pe->destination_ipv4->prefixlen <= 8) + { + stream_putw(s, 0x001A); + length = 0x001A; + } + if ((pe->destination_ipv4->prefixlen > 8) + && (pe->destination_ipv4->prefixlen <= 16)) + { + stream_putw(s, 0x001B); + length = 0x001B; + } + if ((pe->destination_ipv4->prefixlen > 16) + && (pe->destination_ipv4->prefixlen <= 24)) + { + stream_putw(s, 0x001C); + length = 0x001C; + } + if (pe->destination_ipv4->prefixlen > 24) + { + stream_putw(s, 0x001D); + length = 0x001D; + } + + stream_putl(s, 0x00000000); + + /*Metric*/ + stream_putl(s, pe->reported_metric.delay); + stream_putl(s, pe->reported_metric.bandwith); + stream_putc(s, pe->reported_metric.mtu[2]); + stream_putc(s, pe->reported_metric.mtu[1]); + stream_putc(s, pe->reported_metric.mtu[0]); + stream_putc(s, pe->reported_metric.hop_count); + stream_putc(s, pe->reported_metric.reliability); + stream_putc(s, pe->reported_metric.load); + stream_putc(s, pe->reported_metric.tag); + stream_putc(s, pe->reported_metric.flags); + + stream_putc(s, pe->destination_ipv4->prefixlen); + + if (pe->destination_ipv4->prefixlen <= 8) + { + stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF); + } + if ((pe->destination_ipv4->prefixlen > 8) + && (pe->destination_ipv4->prefixlen <= 16)) + { + stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF); + stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF); + } + if ((pe->destination_ipv4->prefixlen > 16) + && (pe->destination_ipv4->prefixlen <= 24)) + { + stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF); + stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF); + stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF); + } + if (pe->destination_ipv4->prefixlen > 24) + { + stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF); + stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF); + stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF); + stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 24) & 0xFF); + } + + return length; +} + +u_int16_t +eigrp_add_authTLV_MD5_to_stream (struct stream *s, + struct eigrp_interface *ei) +{ + struct key *key; + struct keychain *keychain; + struct TLV_MD5_Authentication_Type *authTLV; + + authTLV = eigrp_authTLV_MD5_new(); + + authTLV->type = htons(EIGRP_TLV_AUTH); + authTLV->length = htons(EIGRP_AUTH_MD5_TLV_SIZE); + authTLV->auth_type = htons(EIGRP_AUTH_TYPE_MD5); + authTLV->auth_length = htons(EIGRP_AUTH_TYPE_MD5_LEN); + authTLV->key_sequence = 0; + memset(authTLV->Nullpad,0,sizeof(authTLV->Nullpad)); + + + keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain); + if(keychain) + key = key_lookup_for_send(keychain); + else + { + free(IF_DEF_PARAMS (ei->ifp)->auth_keychain); + IF_DEF_PARAMS (ei->ifp)->auth_keychain = NULL; + eigrp_authTLV_MD5_free(authTLV); + return 0; + } + + if(key) + { + authTLV->key_id = htonl(key->index); + memset(authTLV->digest,0,EIGRP_AUTH_TYPE_MD5_LEN); + stream_put(s,authTLV, sizeof(struct TLV_MD5_Authentication_Type)); + eigrp_authTLV_MD5_free(authTLV); + return EIGRP_AUTH_MD5_TLV_SIZE; + } + + eigrp_authTLV_MD5_free(authTLV); + + return 0; +} + +u_int16_t +eigrp_add_authTLV_SHA256_to_stream (struct stream *s, + struct eigrp_interface *ei) +{ + struct key *key; + struct keychain *keychain; + struct TLV_SHA256_Authentication_Type *authTLV; + + authTLV = eigrp_authTLV_SHA256_new(); + + authTLV->type = htons(EIGRP_TLV_AUTH); + authTLV->length = htons(EIGRP_AUTH_SHA256_TLV_SIZE); + authTLV->auth_type = htons(EIGRP_AUTH_TYPE_SHA256); + authTLV->auth_length = htons(EIGRP_AUTH_TYPE_SHA256_LEN); + authTLV->key_sequence = 0; + memset(authTLV->Nullpad,0,sizeof(authTLV->Nullpad)); + + + keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain); + if(keychain) + key = key_lookup_for_send(keychain); + else + { + free(IF_DEF_PARAMS (ei->ifp)->auth_keychain); + IF_DEF_PARAMS (ei->ifp)->auth_keychain = NULL; + eigrp_authTLV_SHA256_free(authTLV); + return 0; + } + + if(key) + { + authTLV->key_id = 0; + memset(authTLV->digest,0,EIGRP_AUTH_TYPE_SHA256_LEN); + stream_put(s,authTLV, sizeof(struct TLV_SHA256_Authentication_Type)); + eigrp_authTLV_SHA256_free(authTLV); + return EIGRP_AUTH_SHA256_TLV_SIZE; + } + + eigrp_authTLV_SHA256_free(authTLV); + + return 0; + +} + +struct TLV_MD5_Authentication_Type * +eigrp_authTLV_MD5_new () +{ + struct TLV_MD5_Authentication_Type *new; + + new = XCALLOC(MTYPE_EIGRP_AUTH_TLV, sizeof(struct TLV_MD5_Authentication_Type)); + + return new; +} + +void +eigrp_authTLV_MD5_free (struct TLV_MD5_Authentication_Type *authTLV) +{ + + XFREE(MTYPE_EIGRP_AUTH_TLV, authTLV); +} + +struct TLV_SHA256_Authentication_Type * +eigrp_authTLV_SHA256_new () +{ + struct TLV_SHA256_Authentication_Type *new; + + new = XCALLOC(MTYPE_EIGRP_AUTH_SHA256_TLV, sizeof(struct TLV_SHA256_Authentication_Type)); + + return new; +} + +void +eigrp_authTLV_SHA256_free (struct TLV_SHA256_Authentication_Type *authTLV) +{ + + XFREE(MTYPE_EIGRP_AUTH_SHA256_TLV, authTLV); +} + + +struct TLV_IPv4_Internal_type * +eigrp_IPv4_InternalTLV_new () +{ + struct TLV_IPv4_Internal_type *new; + + new = XCALLOC(MTYPE_EIGRP_IPV4_INT_TLV,sizeof(struct TLV_IPv4_Internal_type)); + + return new; +} + +void +eigrp_IPv4_InternalTLV_free (struct TLV_IPv4_Internal_type *IPv4_InternalTLV) +{ + + XFREE(MTYPE_EIGRP_IPV4_INT_TLV, IPv4_InternalTLV); +} + +struct TLV_Sequence_Type * +eigrp_SequenceTLV_new () +{ + struct TLV_Sequence_Type *new; + + new = XCALLOC(MTYPE_EIGRP_SEQ_TLV,sizeof(struct TLV_Sequence_Type)); + + return new; +} diff --git a/eigrpd/eigrp_packet.h b/eigrpd/eigrp_packet.h new file mode 100644 index 000000000..b8b281516 --- /dev/null +++ b/eigrpd/eigrp_packet.h @@ -0,0 +1,143 @@ +/* + * EIGRP General Sending and Receiving of EIGRP Packets. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * 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. + */ + +#ifndef _ZEBRA_EIGRP_PACKET_H +#define _ZEBRA_EIGRP_PACKET_H + +/*Prototypes*/ +extern int eigrp_read (struct thread *); +extern int eigrp_write (struct thread *); + +extern struct eigrp_packet *eigrp_packet_new (size_t); +extern struct eigrp_packet *eigrp_packet_duplicate (struct eigrp_packet *, struct eigrp_neighbor *); +extern void eigrp_packet_free (struct eigrp_packet *); +extern void eigrp_packet_delete (struct eigrp_interface *); +extern void eigrp_packet_header_init (int, struct eigrp_interface *, struct stream *, + u_int32_t, u_int32_t, u_int32_t); +extern void eigrp_packet_checksum (struct eigrp_interface *, struct stream *, u_int16_t); + +extern struct eigrp_fifo *eigrp_fifo_new (void); +extern struct eigrp_packet *eigrp_fifo_head (struct eigrp_fifo *); +extern struct eigrp_packet *eigrp_fifo_tail (struct eigrp_fifo *); +extern struct eigrp_packet *eigrp_fifo_pop (struct eigrp_fifo *); +extern struct eigrp_packet *eigrp_fifo_pop_tail (struct eigrp_fifo *); +extern void eigrp_fifo_push_head (struct eigrp_fifo *, struct eigrp_packet *); +extern void eigrp_fifo_free (struct eigrp_fifo *); +extern void eigrp_fifo_reset (struct eigrp_fifo *); + +extern void eigrp_send_packet_reliably (struct eigrp_neighbor *); + +extern struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv (struct stream *); +extern u_int16_t eigrp_add_internalTLV_to_stream (struct stream *, struct eigrp_prefix_entry *); +extern u_int16_t eigrp_add_authTLV_MD5_to_stream (struct stream *, struct eigrp_interface *); +extern u_int16_t eigrp_add_authTLV_SHA256_to_stream (struct stream *, struct eigrp_interface *); + +extern int eigrp_unack_packet_retrans (struct thread *); +extern int eigrp_unack_multicast_packet_retrans (struct thread *); + +/* + * untill there is reason to have their own header, these externs are found in + * eigrp_hello.c + */ +extern void eigrp_hello_send (struct eigrp_interface *, u_char, struct in_addr *); +extern void eigrp_hello_send_ack (struct eigrp_neighbor *); +extern void eigrp_hello_receive (struct eigrp *, struct ip *, struct eigrp_header *, + struct stream *, struct eigrp_interface *, int); +extern int eigrp_hello_timer (struct thread *); + +/* + * These externs are found in eigrp_update.c + */ +extern void eigrp_update_send (struct eigrp_interface *); +extern void eigrp_update_receive (struct eigrp *, struct ip *, struct eigrp_header *, + struct stream *, struct eigrp_interface *, int); +extern void eigrp_update_send_all (struct eigrp *, struct eigrp_interface *); +extern void eigrp_update_send_init (struct eigrp_neighbor *); +extern void eigrp_update_send_EOT (struct eigrp_neighbor *); +extern int eigrp_update_send_GR_thread(struct thread *); +extern void eigrp_update_send_GR (struct eigrp_neighbor *, enum GR_type, struct vty *); +extern void eigrp_update_send_interface_GR (struct eigrp_interface *, enum GR_type, struct vty *); +extern void eigrp_update_send_process_GR (struct eigrp *, enum GR_type, struct vty *); + +/* + * These externs are found in eigrp_query.c + */ + +extern void eigrp_send_query (struct eigrp_interface *); +extern void eigrp_query_receive (struct eigrp *, struct ip *, struct eigrp_header *, + struct stream *, struct eigrp_interface *, int); +extern u_int32_t eigrp_query_send_all (struct eigrp *); + +/* + * These externs are found in eigrp_reply.c + */ +extern void eigrp_send_reply (struct eigrp_neighbor *, struct eigrp_prefix_entry *); +extern void eigrp_reply_receive (struct eigrp *, struct ip *, struct eigrp_header *, + struct stream *, struct eigrp_interface *, int); + +/* + * These externs are found in eigrp_siaquery.c + */ +extern void eigrp_send_siaquery (struct eigrp_neighbor *, struct eigrp_prefix_entry *); +extern void eigrp_siaquery_receive (struct eigrp *, struct ip *, struct eigrp_header *, + struct stream *, struct eigrp_interface *, int); + +/* + * These externs are found in eigrp_siareply.c + */ +extern void eigrp_send_siareply (struct eigrp_neighbor *, struct eigrp_prefix_entry *); +extern void eigrp_siareply_receive (struct eigrp *, struct ip *, struct eigrp_header *, + struct stream *, struct eigrp_interface *, int); + +extern struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new (void); +extern void eigrp_authTLV_MD5_free (struct TLV_MD5_Authentication_Type *); +extern struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new (void); +extern void eigrp_authTLV_SHA256_free (struct TLV_SHA256_Authentication_Type *); + +extern int eigrp_make_md5_digest (struct eigrp_interface *, struct stream *, + u_char); +extern int eigrp_check_md5_digest (struct stream *, struct TLV_MD5_Authentication_Type *, + struct eigrp_neighbor *, u_char); +extern int eigrp_make_sha256_digest (struct eigrp_interface *, struct stream *, u_char); +extern int eigrp_check_sha256_digest (struct stream *, struct TLV_SHA256_Authentication_Type *, + struct eigrp_neighbor *, u_char ); + + +extern struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new (void); +extern void eigrp_IPv4_InternalTLV_free (struct TLV_IPv4_Internal_type *); + +extern struct TLV_Sequence_Type *eigrp_SequenceTLV_new (void); + +extern const struct message eigrp_packet_type_str[]; +extern const size_t eigrp_packet_type_str_max; + +#endif /* _ZEBRA_EIGRP_PACKET_H */ diff --git a/eigrpd/eigrp_pkt_tlv1.c b/eigrpd/eigrp_pkt_tlv1.c new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/eigrpd/eigrp_pkt_tlv1.c diff --git a/eigrpd/eigrp_pkt_tlv2.c b/eigrpd/eigrp_pkt_tlv2.c new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/eigrpd/eigrp_pkt_tlv2.c diff --git a/eigrpd/eigrp_query.c b/eigrpd/eigrp_query.c new file mode 100644 index 000000000..d4bd37985 --- /dev/null +++ b/eigrpd/eigrp_query.c @@ -0,0 +1,226 @@ +/* + * EIGRP Sending and Receiving EIGRP Query Packets. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "sockunion.h" +#include "stream.h" +#include "log.h" +#include "sockopt.h" +#include "checksum.h" +#include "md5.h" +#include "vty.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_macros.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_fsm.h" +#include "eigrpd/eigrp_memory.h" + +u_int32_t +eigrp_query_send_all (struct eigrp *eigrp) +{ + struct eigrp_interface *iface; + struct listnode *node, *node2, *nnode2; + struct eigrp_prefix_entry *pe; + u_int32_t counter; + + if (eigrp == NULL) + { + zlog_debug("EIGRP Routing Process not enabled"); + return 0; + } + + counter=0; + for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface)) + { + eigrp_send_query(iface); + counter++; + } + + for (ALL_LIST_ELEMENTS(eigrp->topology_changes_internalIPV4, node2, nnode2, pe)) + { + if(pe->req_action & EIGRP_FSM_NEED_QUERY) + { + pe->req_action &= ~EIGRP_FSM_NEED_QUERY; + listnode_delete(eigrp->topology_changes_internalIPV4, pe); + } + } + + return counter; +} + +/*EIGRP QUERY read function*/ +void +eigrp_query_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph, + struct stream * s, struct eigrp_interface *ei, int size) +{ + struct eigrp_neighbor *nbr; + struct TLV_IPv4_Internal_type *tlv; + + u_int16_t type; + + /* increment statistics. */ + ei->query_in++; + + /* get neighbor struct */ + nbr = eigrp_nbr_get(ei, eigrph, iph); + + /* neighbor must be valid, eigrp_nbr_get creates if none existed */ + assert(nbr); + + nbr->recv_sequence_number = ntohl(eigrph->sequence); + + while (s->endp > s->getp) + { + type = stream_getw(s); + if (type == EIGRP_TLV_IPv4_INT) + { + stream_set_getp(s, s->getp - sizeof(u_int16_t)); + + tlv = eigrp_read_ipv4_tlv(s); + + struct prefix_ipv4 *dest_addr; + dest_addr = prefix_ipv4_new(); + dest_addr->prefix = tlv->destination; + dest_addr->prefixlen = tlv->prefix_length; + struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( + eigrp->topology_table, dest_addr); + + /* If the destination exists (it should, but one never know)*/ + if (dest != NULL) + { + struct eigrp_fsm_action_message *msg; + msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, + sizeof(struct eigrp_fsm_action_message)); + struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup( + dest->entries, nbr); + msg->packet_type = EIGRP_OPC_QUERY; + msg->eigrp = eigrp; + msg->data_type = EIGRP_TLV_IPv4_INT; + msg->adv_router = nbr; + msg->data.ipv4_int_type = tlv; + msg->entry = entry; + msg->prefix = dest; + int event = eigrp_get_fsm_event(msg); + eigrp_fsm_event(msg, event); + } + eigrp_IPv4_InternalTLV_free (tlv); + } + } + eigrp_hello_send_ack(nbr); + eigrp_query_send_all(eigrp); + eigrp_update_send_all(eigrp,nbr->ei); +} + +void +eigrp_send_query (struct eigrp_interface *ei) +{ + struct eigrp_packet *ep; + u_int16_t length = EIGRP_HEADER_LEN; + struct listnode *node, *nnode, *node2, *nnode2; + struct eigrp_neighbor *nbr; + struct eigrp_prefix_entry *pe; + char has_tlv; + + ep = eigrp_packet_new(ei->ifp->mtu); + + /* Prepare EIGRP INIT UPDATE header */ + eigrp_packet_header_init(EIGRP_OPC_QUERY, ei, ep->s, 0, + ei->eigrp->sequence_number, 0); + + // encode Authentication TLV, if needed + if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL)) + { + length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei); + } + + has_tlv = 0; + for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node, nnode, pe)) + { + if(pe->req_action & EIGRP_FSM_NEED_QUERY) + { + length += eigrp_add_internalTLV_to_stream(ep->s, pe); + for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr)) + { + if(nbr->state == EIGRP_NEIGHBOR_UP) + { + listnode_add(pe->rij, nbr); + has_tlv = 1; + } + } + } + } + + if(!has_tlv) + { + eigrp_packet_free(ep); + return; + } + + if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL)) + { + eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_UPDATE_FLAG); + } + + /* EIGRP Checksum */ + eigrp_packet_checksum(ei, ep->s, length); + + ep->length = length; + ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS); + + /*This ack number we await from neighbor*/ + ep->sequence_number = ei->eigrp->sequence_number; + + for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr)) + { + if (nbr->state == EIGRP_NEIGHBOR_UP) + { + /*Put packet to retransmission queue*/ + eigrp_fifo_push_head(nbr->retrans_queue, ep); + + if (nbr->retrans_queue->count == 1) + { + eigrp_send_packet_reliably(nbr); + } + } + } +} diff --git a/eigrpd/eigrp_reply.c b/eigrpd/eigrp_reply.c new file mode 100644 index 000000000..ff40e2e5c --- /dev/null +++ b/eigrpd/eigrp_reply.c @@ -0,0 +1,249 @@ +/* + * EIGRP Sending and Receiving EIGRP Reply Packets. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "sockunion.h" +#include "stream.h" +#include "log.h" +#include "sockopt.h" +#include "checksum.h" +#include "md5.h" +#include "vty.h" +#include "keychain.h" +#include "plist.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_macros.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_fsm.h" +#include "eigrpd/eigrp_memory.h" + +void +eigrp_send_reply (struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe) +{ + struct eigrp_packet *ep; + u_int16_t length = EIGRP_HEADER_LEN; + + struct access_list *alist; + struct prefix_list *plist; + struct access_list *alist_i; + struct prefix_list *plist_i; + struct eigrp *e; + struct eigrp_prefix_entry *pe2; + + //TODO: Work in progress + /* Filtering */ + /* get list from eigrp process */ + e = eigrp_lookup(); + pe2 = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY, sizeof(struct eigrp_prefix_entry)); + memcpy(pe2,pe,sizeof(struct eigrp_prefix_entry)); + /* Get access-lists and prefix-lists from process and interface */ + alist = e->list[EIGRP_FILTER_OUT]; + plist = e->prefix[EIGRP_FILTER_OUT]; + alist_i = nbr->ei->list[EIGRP_FILTER_OUT]; + plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT]; + zlog_info("REPLY Send: Filtering"); + + zlog_info("REPLY SEND Prefix: %s", inet_ntoa(nbr->src)); + /* Check if any list fits */ + if ((alist && access_list_apply (alist, (struct prefix *) pe2->destination_ipv4) == FILTER_DENY)|| + (plist && prefix_list_apply (plist, (struct prefix *) pe2->destination_ipv4) == FILTER_DENY)|| + (alist_i && access_list_apply (alist_i, (struct prefix *) pe2->destination_ipv4) == FILTER_DENY)|| + (plist_i && prefix_list_apply (plist_i, (struct prefix *) pe2->destination_ipv4) == FILTER_DENY)) + { + zlog_info("REPLY SEND: Setting Metric to max"); + pe2->reported_metric.delay = EIGRP_MAX_METRIC; + + } else { + zlog_info("REPLY SEND: Not setting metric"); + } + + + /* + * End of filtering + */ + + ep = eigrp_packet_new(nbr->ei->ifp->mtu); + + /* Prepare EIGRP INIT UPDATE header */ + eigrp_packet_header_init(EIGRP_OPC_REPLY, nbr->ei, ep->s, 0, + nbr->ei->eigrp->sequence_number, 0); + + // encode Authentication TLV, if needed + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + { + length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei); + } + + + length += eigrp_add_internalTLV_to_stream(ep->s, pe2); + + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + { + eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG); + } + + /* EIGRP Checksum */ + eigrp_packet_checksum(nbr->ei, ep->s, length); + + ep->length = length; + ep->dst.s_addr = nbr->src.s_addr; + + /*This ack number we await from neighbor*/ + ep->sequence_number = nbr->ei->eigrp->sequence_number; + + /*Put packet to retransmission queue*/ + eigrp_fifo_push_head(nbr->retrans_queue, ep); + + if (nbr->retrans_queue->count == 1) + { + eigrp_send_packet_reliably(nbr); + } +} + +/*EIGRP REPLY read function*/ +void +eigrp_reply_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph, + struct stream * s, struct eigrp_interface *ei, int size) +{ + struct eigrp_neighbor *nbr; + struct TLV_IPv4_Internal_type *tlv; + + struct access_list *alist; + struct prefix_list *plist; + struct access_list *alist_i; + struct prefix_list *plist_i; + struct eigrp *e; + + u_int16_t type; + + /* increment statistics. */ + ei->reply_in++; + + /* get neighbor struct */ + nbr = eigrp_nbr_get(ei, eigrph, iph); + + /* neighbor must be valid, eigrp_nbr_get creates if none existed */ + assert(nbr); + + nbr->recv_sequence_number = ntohl(eigrph->sequence); + + while (s->endp > s->getp) + { + type = stream_getw(s); + if (type == EIGRP_TLV_IPv4_INT) + { + stream_set_getp(s, s->getp - sizeof(u_int16_t)); + + tlv = eigrp_read_ipv4_tlv(s); + + struct prefix_ipv4 *dest_addr; + dest_addr = prefix_ipv4_new(); + dest_addr->prefix = tlv->destination; + dest_addr->prefixlen = tlv->prefix_length; + struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( + eigrp->topology_table, dest_addr); + /* + * Destination must exists + */ + assert(dest); + + struct eigrp_fsm_action_message *msg; + msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, + sizeof(struct eigrp_fsm_action_message)); + struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup( + dest->entries, nbr); + + /* + * Filtering + */ + //TODO: Work in progress + /* get list from eigrp process */ + e = eigrp_lookup(); + /* Get access-lists and prefix-lists from process and interface */ + alist = e->list[EIGRP_FILTER_IN]; + plist = e->prefix[EIGRP_FILTER_IN]; + alist_i = ei->list[EIGRP_FILTER_IN]; + plist_i = ei->prefix[EIGRP_FILTER_IN]; + zlog_info("REPLY Receive: Filtering"); + zlog_info("REPLY RECEIVE Prefix: %s", inet_ntoa(dest_addr->prefix)); + /* Check if any list fits */ + if ((alist && access_list_apply (alist, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (plist && prefix_list_apply (plist, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (alist_i && access_list_apply (alist_i, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (plist_i && prefix_list_apply (plist_i, + (struct prefix *) dest_addr) == FILTER_DENY)) + { + zlog_info("REPLY RECEIVE: Setting metric to max"); + tlv->metric.delay = EIGRP_MAX_METRIC; + zlog_info("REPLY RECEIVE Prefix: %s", inet_ntoa(dest_addr->prefix)); + } else { + zlog_info("REPLY RECEIVE: Not setting metric"); + } + /* + * End of filtering + */ + + msg->packet_type = EIGRP_OPC_REPLY; + msg->eigrp = eigrp; + msg->data_type = EIGRP_TLV_IPv4_INT; + msg->adv_router = nbr; + msg->data.ipv4_int_type = tlv; + msg->entry = entry; + msg->prefix = dest; + int event = eigrp_get_fsm_event(msg); + eigrp_fsm_event(msg, event); + + + eigrp_IPv4_InternalTLV_free (tlv); + } + } + eigrp_hello_send_ack(nbr); +} + diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c new file mode 100644 index 000000000..9dd5b15af --- /dev/null +++ b/eigrpd/eigrp_routemap.c @@ -0,0 +1,1244 @@ +/* + * EIGRP Filter Functions. + * Copyright (C) 2013-2015 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * Note: This file contains skeleton for all possible matches and sets, + * but they are hidden in comment block and not properly implemented. + * At this time, the only function we consider useful for our use + * in distribute command in EIGRP is matching destination IP (with both + * access and prefix list). + * + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "memory.h" +#include "prefix.h" +#include "if_rmap.h" +#include "routemap.h" +#include "command.h" +#include "filter.h" +#include "log.h" +#include "sockunion.h" /* for inet_aton () */ +#include "plist.h" + +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrp_const.h" +#include "eigrpd/eigrp_macros.h" +#include "eigrpd/eigrp_routemap.h" + +void +eigrp_if_rmap_update (struct if_rmap *if_rmap) +{ + struct interface *ifp; + struct eigrp_interface *ei, *ei2; + struct listnode *node, *nnode; + struct route_map *rmap; + struct eigrp *e; + + ifp = if_lookup_by_name (if_rmap->ifname); + if (ifp == NULL) + return; + + ei=NULL; + e = eigrp_lookup(); + for (ALL_LIST_ELEMENTS (e->eiflist, node, nnode, ei2)) + { + if(strcmp(ei2->ifp->name,ifp->name) == 0){ + ei = ei2; + break; + } + } + + if (if_rmap->routemap[IF_RMAP_IN]) + { + rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]); + if (rmap) + ei->routemap[IF_RMAP_IN] = rmap; + else + ei->routemap[IF_RMAP_IN] = NULL; + } + else + ei->routemap[EIGRP_FILTER_IN] = NULL; + + if (if_rmap->routemap[IF_RMAP_OUT]) + { + rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]); + if (rmap) + ei->routemap[IF_RMAP_OUT] = rmap; + else + ei->routemap[IF_RMAP_OUT] = NULL; + } + else + ei->routemap[EIGRP_FILTER_OUT] = NULL; +} + +void +eigrp_if_rmap_update_interface (struct interface *ifp) +{ + struct if_rmap *if_rmap; + + if_rmap = if_rmap_lookup (ifp->name); + if (if_rmap) + eigrp_if_rmap_update (if_rmap); +} + +void +eigrp_routemap_update_redistribute (void) +{ + int i; + struct eigrp *e; + + e = eigrp_lookup(); + + if (e) + { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (e->route_map[i].name) + e->route_map[i].map = + route_map_lookup_by_name (e->route_map[i].name); + } + } +} + +/* ARGSUSED */ +void +eigrp_rmap_update (const char *notused) +{ + struct interface *ifp; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) + eigrp_if_rmap_update_interface (ifp); + + eigrp_routemap_update_redistribute (); +} + +/* Add eigrp route map rule. */ +static int +eigrp_route_match_add (struct vty *vty, struct route_map_index *index, + const char *command, const 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; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + return CMD_SUCCESS; +} + +/* Delete rip route map rule. */ +static int +eigrp_route_match_delete (struct vty *vty, struct route_map_index *index, + const char *command, const 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; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + return CMD_SUCCESS; +} + +/* Add eigrp route map rule. */ +static int +eigrp_route_set_add (struct vty *vty, struct route_map_index *index, + const char *command, const 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; + case RMAP_COMPILE_ERROR: + /* rip, ripng and other protocols share the set metric command + but only values from 0 to 16 are valid for rip and ripng + if metric is out of range for rip and ripng, it is not for + other protocols. Do not return an error */ + if (strcmp(command, "metric")) { + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + } + return CMD_SUCCESS; +} + +/* Delete eigrp route map rule. */ +static int +eigrp_route_set_delete (struct vty *vty, struct route_map_index *index, + const char *command, const 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; + case RMAP_COMPILE_ERROR: + vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + return CMD_SUCCESS; +} + +/* Hook function for updating route_map assignment. */ +/* ARGSUSED */ +void +eigrp_route_map_update (const char *notused) +{ + int i; + struct eigrp *e; + e = eigrp_lookup(); + + if (e) + { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (e->route_map[i].name) + e->route_map[i].map = + route_map_lookup_by_name (e->route_map[i].name); + } + } +} + + + +/* `match metric METRIC' */ +/* Match function return 1 if match is success else return zero. */ +static route_map_result_t +route_match_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ +// u_int32_t *metric; +// u_int32_t check; +// struct rip_info *rinfo; +// struct eigrp_neighbor_entry *te; +// struct eigrp_prefix_entry *pe; +// struct listnode *node, *node2, *nnode, *nnode2; +// struct eigrp *e; +// +// e = eigrp_lookup(); +// +// if (type == RMAP_EIGRP) +// { +// metric = rule; +// rinfo = object; +// +// /* If external metric is available, the route-map should +// work on this one (for redistribute purpose) */ +// /*check = (rinfo->external_metric) ? rinfo->external_metric : +// rinfo->metric;*/ +// +// if (check == *metric) +// return RMAP_MATCH; +// else +// return RMAP_NOMATCH; +// } + return RMAP_NOMATCH; +} + +/* Route map `match metric' match statement. `arg' is METRIC value */ +static void * +route_match_metric_compile (const char *arg) +{ +// u_int32_t *metric; +// +// metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); +// *metric = atoi (arg); +// +// if(*metric > 0) +// return metric; +// +// XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); + return NULL; +} + +/* Free route map's compiled `match metric' value. */ +static 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 interface IFNAME' */ +/* Match function return 1 if match is success else return zero. */ +static route_map_result_t +route_match_interface (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ +// struct rip_info *rinfo; +// struct interface *ifp; +// char *ifname; +// +// if (type == RMAP_EIGRP) +// { +// ifname = rule; +// ifp = if_lookup_by_name(ifname); +// +// if (!ifp) +// return RMAP_NOMATCH; +// +// rinfo = object; +// +// /*if (rinfo->ifindex_out == ifp->ifindex || rinfo->ifindex == ifp->ifindex) +// return RMAP_MATCH; +// else +// return RMAP_NOMATCH;*/ +// } + return RMAP_NOMATCH; +} + +/* Route map `match interface' match statement. `arg' is IFNAME value */ +/* XXX I don`t know if I need to check does interface exist? */ +static void * +route_match_interface_compile (const char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `match interface' value. */ +static void +route_match_interface_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for interface matching. */ +struct route_map_rule_cmd route_match_interface_cmd = +{ + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; + +/* `match ip next-hop IP_ACCESS_LIST' */ + +/* Match function return 1 if match is success else return zero. */ +static 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 rip_info *rinfo; +// struct prefix_ipv4 p; +// +// if (type == RMAP_EIGRP) +// { +// rinfo = object; +// p.family = AF_INET; +// /*p.prefix = (rinfo->nexthop.s_addr) ? rinfo->nexthop : rinfo->from;*/ +// 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' should be + access-list name. */ +static void * +route_match_ip_next_hop_compile (const char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `. */ +static void +route_match_ip_next_hop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip next-hop matching. */ +static 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 next-hop prefix-list PREFIX_LIST' */ + +static 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 rip_info *rinfo; +// struct prefix_ipv4 p; +// +// if (type == RMAP_EIGRP) +// { +// rinfo = object; +// p.family = AF_INET; +// /*p.prefix = (rinfo->nexthop.s_addr) ? rinfo->nexthop : rinfo->from;*/ +// 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; +} + +static void * +route_match_ip_next_hop_prefix_list_compile (const char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void +route_match_ip_next_hop_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static 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 ip address IP_ACCESS_LIST' */ + +/* Match function should return 1 if match is success else return + zero. */ +static route_map_result_t +route_match_ip_address (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct access_list *alist; + + if (type == RMAP_EIGRP) + { + 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. */ +static void * +route_match_ip_address_compile (const char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +static void +route_match_ip_address_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +static 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 address prefix-list PREFIX_LIST' */ + +static 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_EIGRP) + { + 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; +} + +static void * +route_match_ip_address_prefix_list_compile (const char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void +route_match_ip_address_prefix_list_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static 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 tag TAG' */ +/* Match function return 1 if match is success else return zero. */ +static route_map_result_t +route_match_tag (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ +// u_short *tag; +// struct rip_info *rinfo; +// +// if (type == RMAP_EIGRP) +// { +// tag = rule; +// rinfo = object; +// +// /* The information stored by rinfo is host ordered. */ +// /*if (rinfo->tag == *tag) +// return RMAP_MATCH; +// else +// return RMAP_NOMATCH;*/ +// } + return RMAP_NOMATCH; +} + +/* Route map `match tag' match statement. `arg' is TAG value */ +static void * +route_match_tag_compile (const char *arg) +{ +// u_short *tag; +// +// tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); +// *tag = atoi (arg); +// +// return tag; +} + +/* Free route map's compiled `match tag' value. */ +static void +route_match_tag_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for tag matching. */ +struct route_map_rule_cmd route_match_tag_cmd = +{ + "tag", + route_match_tag, + route_match_tag_compile, + route_match_tag_free +}; + +/* Set metric to attribute. */ +static route_map_result_t +route_set_metric (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ +// if (type == RMAP_RIP) +// { +// struct rip_metric_modifier *mod; +// struct rip_info *rinfo; +// +// mod = rule; +// rinfo = object; +// +// /*if (mod->type == metric_increment) +// rinfo->metric_out += mod->metric; +// else if (mod->type == metric_decrement) +// rinfo->metric_out -= mod->metric; +// else if (mod->type == metric_absolute) +// rinfo->metric_out = mod->metric; +// +// if ((signed int)rinfo->metric_out < 1) +// rinfo->metric_out = 1; +// if (rinfo->metric_out > RIP_METRIC_INFINITY) +// rinfo->metric_out = RIP_METRIC_INFINITY;*/ +// +// rinfo->metric_set = 1; +// } + return RMAP_OKAY; +} + +/* set metric compilation. */ +static void * +route_set_metric_compile (const char *arg) +{ +// int len; +// const char *pnt; +// int type; +// long metric; +// char *endptr = NULL; +// struct rip_metric_modifier *mod; +// +// len = strlen (arg); +// pnt = arg; +// +// if (len == 0) +// return NULL; +// +// /* Examine first character. */ +// if (arg[0] == '+') +// { +// //type = metric_increment; +// pnt++; +// } +// else if (arg[0] == '-') +// { +// //type = metric_decrement; +// pnt++; +// } +// /*else +// type = metric_absolute;*/ +// +// /* Check beginning with digit string. */ +// if (*pnt < '0' || *pnt > '9') +// return NULL; +// +// /* Convert string to integer. */ +// metric = strtol (pnt, &endptr, 10); +// +// if (metric == LONG_MAX || *endptr != '\0') +// return NULL; +// /*if (metric < 0 || metric > RIP_METRIC_INFINITY) +// return NULL;*/ +// +// mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, +// sizeof (struct rip_metric_modifier)); +// mod->type = type; +// mod->metric = metric; + +// return mod; +} + +/* Free route map's compiled `set metric' value. */ +static void +route_set_metric_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +static struct route_map_rule_cmd route_set_metric_cmd = +{ + "metric", + route_set_metric, + route_set_metric_compile, + route_set_metric_free, +}; + +/* `set ip next-hop IP_ADDRESS' */ + +/* Set nexthop to object. ojbect must be pointer to struct attr. */ +static 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 rip_info *rinfo; +// +// if(type == RMAP_RIP) +// { +// /* Fetch routemap's rule information. */ +// address = rule; +// rinfo = object; +// +// /* Set next hop value. */ +// rinfo->nexthop_out = *address; +// } + + return RMAP_OKAY; +} + +/* Route map `ip nexthop' compile function. Given string is converted + to struct in_addr structure. */ +static void * +route_set_ip_nexthop_compile (const 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. */ +static void +route_set_ip_nexthop_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +static 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 tag TAG' */ + +/* Set tag to object. ojbect must be pointer to struct attr. */ +static route_map_result_t +route_set_tag (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ +// u_short *tag; +// struct rip_info *rinfo; +// +// if(type == RMAP_RIP) +// { +// /* Fetch routemap's rule information. */ +// tag = rule; +// rinfo = object; +// +// /* Set next hop value. */ +// rinfo->tag_out = *tag; +// } + + return RMAP_OKAY; +} + +/* Route map `tag' compile function. Given string is converted + to u_short. */ +static void * +route_set_tag_compile (const char *arg) +{ +// u_short *tag; +// +// tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); +// *tag = atoi (arg); +// +// return tag; +} + +/* Free route map's compiled `ip nexthop' value. */ +static void +route_set_tag_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for tag set. */ +static struct route_map_rule_cmd route_set_tag_cmd = +{ + "tag", + route_set_tag, + route_set_tag_compile, + route_set_tag_free +}; + +#define MATCH_STR "Match values from routing table\n" +#define SET_STR "Set values in destination routing protocol\n" + +DEFUN (match_metric, + match_metric_cmd, + "match metric <0-4294967295>", + MATCH_STR + "Match metric of route\n" + "Metric value\n") +{ + return eigrp_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 eigrp_route_match_delete (vty, vty->index, "metric", NULL); + + return eigrp_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_interface, + match_interface_cmd, + "match interface WORD", + MATCH_STR + "Match first hop interface of route\n" + "Interface name\n") +{ + return eigrp_route_match_add (vty, vty->index, "interface", argv[0]); +} + +DEFUN (no_match_interface, + no_match_interface_cmd, + "no match interface", + NO_STR + MATCH_STR + "Match first hop interface of route\n") +{ + if (argc == 0) + return eigrp_route_match_delete (vty, vty->index, "interface", NULL); + + return eigrp_route_match_delete (vty, vty->index, "interface", argv[0]); +} + +ALIAS (no_match_interface, + no_match_interface_val_cmd, + "no match interface WORD", + NO_STR + MATCH_STR + "Match first hop interface of route\n" + "Interface 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 eigrp_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 eigrp_route_match_delete (vty, vty->index, "ip next-hop", NULL); + + return eigrp_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_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 eigrp_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 eigrp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); + + return eigrp_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_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 eigrp_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 eigrp_route_match_delete (vty, vty->index, "ip address", NULL); + + return eigrp_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_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 eigrp_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 eigrp_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); + + return eigrp_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_tag, + match_tag_cmd, + "match tag <0-65535>", + MATCH_STR + "Match tag of route\n" + "Metric value\n") +{ + return eigrp_route_match_add (vty, vty->index, "tag", argv[0]); +} + +DEFUN (no_match_tag, + no_match_tag_cmd, + "no match tag", + NO_STR + MATCH_STR + "Match tag of route\n") +{ + if (argc == 0) + return eigrp_route_match_delete (vty, vty->index, "tag", NULL); + + return eigrp_route_match_delete (vty, vty->index, "tag", argv[0]); +} + +ALIAS (no_match_tag, + no_match_tag_val_cmd, + "no match tag <0-65535>", + NO_STR + MATCH_STR + "Match tag of route\n" + "Metric value\n") + +/* set functions */ + +DEFUN (set_metric, + set_metric_cmd, + "set metric <0-4294967295>", + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") +{ + return eigrp_route_set_add (vty, vty->index, "metric", argv[0]); +} + +ALIAS (set_metric, + set_metric_addsub_cmd, + "set metric <+/-metric>", + SET_STR + "Metric value for destination routing protocol\n" + "Add or subtract metric\n") + +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 eigrp_route_set_delete (vty, vty->index, "metric", NULL); + + return eigrp_route_set_delete (vty, vty->index, "metric", argv[0]); +} + +ALIAS (no_set_metric, + no_set_metric_val_cmd, + "no set metric (<0-4294967295>|<+/-metric>)", + NO_STR + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n" + "Add or subtract metric\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 eigrp_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 eigrp_route_set_delete (vty, vty->index, "ip next-hop", NULL); + + return eigrp_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_tag, + set_tag_cmd, + "set tag <0-65535>", + SET_STR + "Tag value for routing protocol\n" + "Tag value\n") +{ + return eigrp_route_set_add (vty, vty->index, "tag", argv[0]); +} + +DEFUN (no_set_tag, + no_set_tag_cmd, + "no set tag", + NO_STR + SET_STR + "Tag value for routing protocol\n") +{ + if (argc == 0) + return eigrp_route_set_delete (vty, vty->index, "tag", NULL); + + return eigrp_route_set_delete (vty, vty->index, "tag", argv[0]); +} + +ALIAS (no_set_tag, + no_set_tag_val_cmd, + "no set tag <0-65535>", + NO_STR + SET_STR + "Tag value for routing protocol\n" + "Tag value\n") + + +/* Route-map init */ +void +eigrp_route_map_init () +{ + route_map_init (); + route_map_init_vty (); + route_map_add_hook (eigrp_route_map_update); + route_map_delete_hook (eigrp_route_map_update); + + /*route_map_install_match (&route_match_metric_cmd); + route_map_install_match (&route_match_interface_cmd);*/ + /*route_map_install_match (&route_match_ip_next_hop_cmd); + route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); + route_map_install_match (&route_match_ip_address_cmd); + route_map_install_match (&route_match_ip_address_prefix_list_cmd);*/ + /*route_map_install_match (&route_match_tag_cmd);*/ + + /*route_map_install_set (&route_set_metric_cmd); + route_map_install_set (&route_set_ip_nexthop_cmd); + route_map_install_set (&route_set_tag_cmd);*/ + + /*install_element (RMAP_NODE, &route_match_metric_cmd); + install_element (RMAP_NODE, &no_match_metric_cmd); + install_element (RMAP_NODE, &no_match_metric_val_cmd); + install_element (RMAP_NODE, &route_match_interface_cmd); + install_element (RMAP_NODE, &no_match_interface_cmd); + install_element (RMAP_NODE, &no_match_interface_val_cmd); + install_element (RMAP_NODE, &route_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, &route_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, &route_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, &route_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, &route_match_tag_cmd); + install_element (RMAP_NODE, &no_match_tag_cmd); + install_element (RMAP_NODE, &no_match_tag_val_cmd);*/ + + /*install_element (RMAP_NODE, &set_metric_cmd); + install_element (RMAP_NODE, &set_metric_addsub_cmd); + install_element (RMAP_NODE, &no_set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_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_tag_cmd); + install_element (RMAP_NODE, &no_set_tag_cmd); + install_element (RMAP_NODE, &no_set_tag_val_cmd);*/ +} diff --git a/eigrpd/eigrp_routemap.h b/eigrpd/eigrp_routemap.h new file mode 100644 index 000000000..0fee25b9a --- /dev/null +++ b/eigrpd/eigrp_routemap.h @@ -0,0 +1,18 @@ +/* + * eigrp_routemap.h + * + * Created on: Nov 19, 2015 + * Author: root + */ + +#ifndef EIGRPD_EIGRP_ROUTEMAP_H_ +#define EIGRPD_EIGRP_ROUTEMAP_H_ + +extern void eigrp_route_map_update (const char *); +extern void eigrp_route_map_init (); +extern void eigrp_if_rmap_update (struct if_rmap *); +extern void eigrp_if_rmap_update_interface (struct interface *); +extern void eigrp_routemap_update_redistribute (void); +extern void eigrp_rmap_update (const char *); + +#endif /* EIGRPD_EIGRP_ROUTEMAP_H_ */ diff --git a/eigrpd/eigrp_siaquery.c b/eigrpd/eigrp_siaquery.c new file mode 100644 index 000000000..030a86c1c --- /dev/null +++ b/eigrpd/eigrp_siaquery.c @@ -0,0 +1,164 @@ +/* + * EIGRP Sending and Receiving EIGRP SIA-Query Packets. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "sockunion.h" +#include "stream.h" +#include "log.h" +#include "sockopt.h" +#include "checksum.h" +#include "md5.h" +#include "vty.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_macros.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_fsm.h" +#include "eigrpd/eigrp_memory.h" + +/*EIGRP SIA-QUERY read function*/ +void +eigrp_siaquery_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph, + struct stream * s, struct eigrp_interface *ei, int size) +{ + struct eigrp_neighbor *nbr; + struct TLV_IPv4_Internal_type *tlv; + + u_int16_t type; + + /* increment statistics. */ + ei->siaQuery_in++; + + /* get neighbor struct */ + nbr = eigrp_nbr_get(ei, eigrph, iph); + + /* neighbor must be valid, eigrp_nbr_get creates if none existed */ + assert(nbr); + + nbr->recv_sequence_number = ntohl(eigrph->sequence); + + while (s->endp > s->getp) + { + type = stream_getw(s); + if (type == EIGRP_TLV_IPv4_INT) + { + stream_set_getp(s, s->getp - sizeof(u_int16_t)); + + tlv = eigrp_read_ipv4_tlv(s); + + struct prefix_ipv4 *dest_addr; + dest_addr = prefix_ipv4_new(); + dest_addr->prefix = tlv->destination; + dest_addr->prefixlen = tlv->prefix_length; + struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( + eigrp->topology_table, dest_addr); + + /* If the destination exists (it should, but one never know)*/ + if (dest != NULL) + { + struct eigrp_fsm_action_message *msg; + msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, + sizeof(struct eigrp_fsm_action_message)); + struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup( + dest->entries, nbr); + msg->packet_type = EIGRP_OPC_SIAQUERY; + msg->eigrp = eigrp; + msg->data_type = EIGRP_TLV_IPv4_INT; + msg->adv_router = nbr; + msg->data.ipv4_int_type = tlv; + msg->entry = entry; + msg->prefix = dest; + int event = eigrp_get_fsm_event(msg); + eigrp_fsm_event(msg, event); + } + eigrp_IPv4_InternalTLV_free (tlv); + } + } + eigrp_hello_send_ack(nbr); +} + + +void +eigrp_send_siaquery (struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe) +{ + struct eigrp_packet *ep; + u_int16_t length = EIGRP_HEADER_LEN; + + ep = eigrp_packet_new(nbr->ei->ifp->mtu); + + /* Prepare EIGRP INIT UPDATE header */ + eigrp_packet_header_init(EIGRP_OPC_SIAQUERY, nbr->ei, ep->s, 0, + nbr->ei->eigrp->sequence_number, 0); + + // encode Authentication TLV, if needed + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + { + length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei); + } + + length += eigrp_add_internalTLV_to_stream(ep->s, pe); + + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + { + eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG); + } + + /* EIGRP Checksum */ + eigrp_packet_checksum(nbr->ei, ep->s, length); + + ep->length = length; + ep->dst.s_addr = nbr->src.s_addr; + + /*This ack number we await from neighbor*/ + ep->sequence_number = nbr->ei->eigrp->sequence_number; + + if (nbr->state == EIGRP_NEIGHBOR_UP) + { + /*Put packet to retransmission queue*/ + eigrp_fifo_push_head(nbr->retrans_queue, ep); + + if (nbr->retrans_queue->count == 1) + { + eigrp_send_packet_reliably(nbr); + } + } +} diff --git a/eigrpd/eigrp_siareply.c b/eigrpd/eigrp_siareply.c new file mode 100644 index 000000000..b49409061 --- /dev/null +++ b/eigrpd/eigrp_siareply.c @@ -0,0 +1,165 @@ +/* + * EIGRP Sending and Receiving EIGRP SIA-Reply Packets. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "sockunion.h" +#include "stream.h" +#include "log.h" +#include "sockopt.h" +#include "checksum.h" +#include "md5.h" +#include "vty.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_macros.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_fsm.h" +#include "eigrpd/eigrp_memory.h" + +/*EIGRP SIA-REPLY read function*/ +void +eigrp_siareply_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph, + struct stream * s, struct eigrp_interface *ei, int size) +{ + struct eigrp_neighbor *nbr; + struct TLV_IPv4_Internal_type *tlv; + + u_int16_t type; + + /* increment statistics. */ + ei->siaReply_in++; + + /* get neighbor struct */ + nbr = eigrp_nbr_get(ei, eigrph, iph); + + /* neighbor must be valid, eigrp_nbr_get creates if none existed */ + assert(nbr); + + nbr->recv_sequence_number = ntohl(eigrph->sequence); + + while (s->endp > s->getp) + { + type = stream_getw(s); + if (type == EIGRP_TLV_IPv4_INT) + { + stream_set_getp(s, s->getp - sizeof(u_int16_t)); + + tlv = eigrp_read_ipv4_tlv(s); + + struct prefix_ipv4 *dest_addr; + dest_addr = prefix_ipv4_new(); + dest_addr->prefix = tlv->destination; + dest_addr->prefixlen = tlv->prefix_length; + struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( + eigrp->topology_table, dest_addr); + + /* If the destination exists (it should, but one never know)*/ + if (dest != NULL) + { + struct eigrp_fsm_action_message *msg; + msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, + sizeof(struct eigrp_fsm_action_message)); + struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup( + dest->entries, nbr); + msg->packet_type = EIGRP_OPC_SIAQUERY; + msg->eigrp = eigrp; + msg->data_type = EIGRP_TLV_IPv4_INT; + msg->adv_router = nbr; + msg->data.ipv4_int_type = tlv; + msg->entry = entry; + msg->prefix = dest; + int event = eigrp_get_fsm_event(msg); + eigrp_fsm_event(msg, event); + } + eigrp_IPv4_InternalTLV_free (tlv); + } + } + eigrp_hello_send_ack(nbr); +} + +void +eigrp_send_siareply (struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe) +{ + struct eigrp_packet *ep; + u_int16_t length = EIGRP_HEADER_LEN; + + ep = eigrp_packet_new(nbr->ei->ifp->mtu); + + /* Prepare EIGRP INIT UPDATE header */ + eigrp_packet_header_init(EIGRP_OPC_SIAREPLY, nbr->ei, ep->s, 0, + nbr->ei->eigrp->sequence_number, 0); + + // encode Authentication TLV, if needed + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + { + length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei); + } + + length += eigrp_add_internalTLV_to_stream(ep->s, pe); + + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + { + eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG); + } + + /* EIGRP Checksum */ + eigrp_packet_checksum(nbr->ei, ep->s, length); + + ep->length = length; + ep->dst.s_addr = nbr->src.s_addr; + + /*This ack number we await from neighbor*/ + ep->sequence_number = nbr->ei->eigrp->sequence_number; + + if (nbr->state == EIGRP_NEIGHBOR_UP) + { + /*Put packet to retransmission queue*/ + eigrp_fifo_push_head(nbr->retrans_queue, ep); + + if (nbr->retrans_queue->count == 1) + { + eigrp_send_packet_reliably(nbr); + } + } +} + + diff --git a/eigrpd/eigrp_snmp.c b/eigrpd/eigrp_snmp.c new file mode 100644 index 000000000..f5dd69f1b --- /dev/null +++ b/eigrpd/eigrp_snmp.c @@ -0,0 +1,1395 @@ +/* + * EIGRP SNMP Support. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#ifdef HAVE_SNMP +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-includes.h> + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "sockunion.h" +#include "stream.h" +#include "log.h" +#include "sockopt.h" +#include "checksum.h" +#include "md5.h" +#include "keychain.h" +#include "smux.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_fsm.h" +#include "eigrpd/eigrp_snmp.h" + + +struct list *eigrp_snmp_iflist; + +/* Declare static local variables for convenience. */ +SNMP_LOCAL_VARIABLES + +/* EIGRP-MIB - 1.3.6.1.4.1.9.9.449.1*/ +#define EIGRPMIB 1,3,6,1,4,1,9,9,449,1 + +/* EIGRP-MIB instances. */ +oid eigrp_oid [] = { EIGRPMIB }; + +/* EIGRP VPN entry */ +#define EIGRPVPNID 1 +#define EIGRPVPNNAME 2 + +/* EIGRP Traffic statistics entry */ +#define EIGRPASNUMBER 1 +#define EIGRPNBRCOUNT 2 +#define EIGRPHELLOSSENT 3 +#define EIGRPHELLOSRCVD 4 +#define EIGRPUPDATESSENT 5 +#define EIGRPUPDATESRCVD 6 +#define EIGRPQUERIESSENT 7 +#define EIGRPQUERIESRCVD 8 +#define EIGRPREPLIESSENT 9 +#define EIGRPREPLIESRCVD 10 +#define EIGRPACKSSENT 11 +#define EIGRPACKSRCVD 12 +#define EIGRPINPUTQHIGHMARK 13 +#define EIGRPINPUTQDROPS 14 +#define EIGRPSIAQUERIESSENT 15 +#define EIGRPSIAQUERIESRCVD 16 +#define EIGRPASROUTERIDTYPE 17 +#define EIGRPASROUTERID 18 +#define EIGRPTOPOROUTES 19 +#define EIGRPHEADSERIAL 20 +#define EIGRPNEXTSERIAL 21 +#define EIGRPXMITPENDREPLIES 22 +#define EIGRPXMITDUMMIES 23 + +/* EIGRP topology entry */ +#define EIGRPDESTNETTYPE 1 +#define EIGRPDESTNET 2 +#define EIGRPDESTNETPREFIXLEN 4 +#define EIGRPACTIVE 5 +#define EIGRPSTUCKINACTIVE 6 +#define EIGRPDESTSUCCESSORS 7 +#define EIGRPFDISTANCE 8 +#define EIGRPROUTEORIGINTYPE 9 +#define EIGRPROUTEORIGINADDRTYPE 10 +#define EIGRPROUTEORIGINADDR 11 +#define EIGRPNEXTHOPADDRESSTYPE 12 +#define EIGRPNEXTHOPADDRESS 13 +#define EIGRPNEXTHOPINTERFACE 14 +#define EIGRPDISTANCE 15 +#define EIGRPREPORTDISTANCE 16 + +/* EIGRP peer entry */ +#define EIGRPHANDLE 1 +#define EIGRPPEERADDRTYPE 2 +#define EIGRPPEERADDR 3 +#define EIGRPPEERIFINDEX 4 +#define EIGRPHOLDTIME 5 +#define EIGRPUPTIME 6 +#define EIGRPSRTT 7 +#define EIGRPRTO 8 +#define EIGRPPKTSENQUEUED 9 +#define EIGRPLASTSEQ 10 +#define EIGRPVERSION 11 +#define EIGRPRETRANS 12 +#define EIGRPRETRIES 13 + +/* EIGRP interface entry */ +#define EIGRPPEERCOUNT 3 +#define EIGRPXMITRELIABLEQ 4 +#define EIGRPXMITUNRELIABLEQ 5 +#define EIGRPMEANSRTT 6 +#define EIGRPPACINGRELIABLE 7 +#define EIGRPPACINGUNRELIABLE 8 +#define EIGRPMFLOWTIMER 9 +#define EIGRPPENDINGROUTES 10 +#define EIGRPHELLOINTERVAL 11 +#define EIGRPXMITNEXTSERIAL 12 +#define EIGRPUMCASTS 13 +#define EIGRPRMCASTS 14 +#define EIGRPUUCASTS 15 +#define EIGRPRUCASTS 16 +#define EIGRPMCASTEXCEPTS 17 +#define EIGRPCRPKTS 18 +#define EIGRPACKSSUPPRESSED 19 +#define EIGRPRETRANSSENT 20 +#define EIGRPOOSRCVD 21 +#define EIGRPAUTHMODE 22 +#define EIGRPAUTHKEYCHAIN 23 + +/* SNMP value hack. */ +#define COUNTER ASN_COUNTER +#define INTEGER ASN_INTEGER +#define GAUGE ASN_GAUGE +#define TIMETICKS ASN_TIMETICKS +#define IPADDRESS ASN_IPADDRESS +#define STRING ASN_OCTET_STR +#define IPADDRESSPREFIXLEN ASN_INTEGER +#define IPADDRESSTYPE ASN_INTEGER +#define INTERFACEINDEXORZERO ASN_INTEGER +#define UINTEGER ASN_UNSIGNED + + + + +/* Hook functions. */ +static u_char *eigrpVpnEntry (struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); +static u_char *eigrpTraffStatsEntry (struct variable *, oid *, size_t *, int, + size_t *, WriteMethod **); +static u_char *eigrpTopologyEntry (struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); +static u_char *eigrpPeerEntry (struct variable *, oid *, size_t *, int, + size_t *, WriteMethod **); +static u_char *eigrpInterfaceEntry (struct variable *, oid *, size_t *, int, + size_t *, WriteMethod **); + + +struct variable eigrp_variables[] = +{ + /* EIGRP vpn variables */ + {EIGRPVPNID, INTEGER, NOACCESS, eigrpVpnEntry, + 4, {1, 1, 1, 1}}, + {EIGRPVPNNAME, STRING, RONLY, eigrpVpnEntry, + 4, {1, 1, 1, 2}}, + + /* EIGRP traffic stats variables */ + {EIGRPASNUMBER, UINTEGER, NOACCESS, eigrpTraffStatsEntry, + 4, {2, 1, 1, 1}}, + {EIGRPNBRCOUNT, UINTEGER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 2}}, + {EIGRPHELLOSSENT, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 3}}, + {EIGRPHELLOSRCVD, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 4}}, + {EIGRPUPDATESSENT, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 5}}, + {EIGRPUPDATESRCVD, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 6}}, + {EIGRPQUERIESSENT, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 7}}, + {EIGRPQUERIESRCVD, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 8}}, + {EIGRPREPLIESSENT, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 9}}, + {EIGRPREPLIESRCVD, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 10}}, + {EIGRPACKSSENT, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 11}}, + {EIGRPACKSRCVD, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 12}}, + {EIGRPINPUTQHIGHMARK, INTEGER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 13}}, + {EIGRPINPUTQDROPS, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 14}}, + {EIGRPSIAQUERIESSENT, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 15}}, + {EIGRPSIAQUERIESRCVD, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 16}}, + {EIGRPASROUTERIDTYPE, IPADDRESSTYPE, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 17}}, + {EIGRPASROUTERID, IPADDRESS, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 18}}, + {EIGRPTOPOROUTES, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 19}}, + {EIGRPHEADSERIAL, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 20}}, + {EIGRPNEXTSERIAL, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 21}}, + {EIGRPXMITPENDREPLIES, INTEGER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 22}}, + {EIGRPXMITDUMMIES, COUNTER, RONLY, eigrpTraffStatsEntry, + 4, {2, 1, 1, 23}}, + + /* EIGRP topology variables */ + {EIGRPDESTNETTYPE, IPADDRESSTYPE, NOACCESS, eigrpTopologyEntry, + 4, {3, 1, 1, 1}}, + {EIGRPDESTNET, IPADDRESSPREFIXLEN, NOACCESS, eigrpTopologyEntry, + 4, {3, 1, 1, 2}}, + {EIGRPDESTNETPREFIXLEN, IPADDRESSTYPE, NOACCESS, eigrpTopologyEntry, + 4, {3, 1, 1, 4}}, + {EIGRPACTIVE, INTEGER, RONLY, eigrpTopologyEntry, + 4, {3, 1, 1, 5}}, + {EIGRPSTUCKINACTIVE, INTEGER, RONLY, eigrpTopologyEntry, + 4, {3, 1, 1, 6}}, + {EIGRPDESTSUCCESSORS, INTEGER, RONLY, eigrpTopologyEntry, + 4, {3, 1, 1, 7}}, + {EIGRPFDISTANCE, INTEGER, RONLY, eigrpTopologyEntry, + 4, {3, 1, 1, 8}}, + {EIGRPROUTEORIGINTYPE, STRING, RONLY, eigrpTopologyEntry, + 4, {3, 1, 1, 9}}, + {EIGRPROUTEORIGINADDRTYPE, IPADDRESSTYPE, RONLY, eigrpTopologyEntry, + 4, {3, 1, 1, 10}}, + {EIGRPROUTEORIGINADDR, IPADDRESS, RONLY, eigrpTopologyEntry, + 4, {3, 1, 1, 11}}, + {EIGRPNEXTHOPADDRESSTYPE, IPADDRESSTYPE, RONLY, eigrpTopologyEntry, + 4, {3, 1, 1, 12}}, + {EIGRPNEXTHOPADDRESS, IPADDRESS, RONLY, eigrpTopologyEntry, + 4, {3, 1, 1, 13}}, + {EIGRPNEXTHOPINTERFACE, STRING, RONLY, eigrpTopologyEntry, + 4, {3, 1, 1, 14}}, + {EIGRPDISTANCE, INTEGER, RONLY, eigrpTopologyEntry, + 4, {3, 1, 1, 15}}, + {EIGRPREPORTDISTANCE, INTEGER, RONLY, eigrpTopologyEntry, + 4, {3, 1, 1, 16}}, + + /* EIGRP peer variables */ + {EIGRPHANDLE, INTEGER, NOACCESS, eigrpPeerEntry, + 4, {4, 1, 1, 1}}, + {EIGRPPEERADDRTYPE, IPADDRESSTYPE, RONLY, eigrpPeerEntry, + 4, {4, 1, 1, 2}}, + {EIGRPPEERADDR, IPADDRESS, RONLY, eigrpPeerEntry, + 4, {4, 1, 1, 3}}, + {EIGRPPEERIFINDEX, INTERFACEINDEXORZERO, RONLY, eigrpPeerEntry, + 4, {4, 1, 1, 4}}, + {EIGRPHOLDTIME, INTEGER, RONLY, eigrpPeerEntry, + 4, {4, 1, 1, 5}}, + {EIGRPUPTIME, STRING, RONLY, eigrpPeerEntry, + 4, {4, 1, 1, 6}}, + {EIGRPSRTT, INTEGER, RONLY, eigrpPeerEntry, + 4, {4, 1, 1, 7}}, + {EIGRPRTO, INTEGER, RONLY, eigrpPeerEntry, + 4, {4, 1, 1, 8}}, + {EIGRPPKTSENQUEUED, INTEGER, RONLY, eigrpPeerEntry, + 4, {4, 1, 1, 9}}, + {EIGRPLASTSEQ, INTEGER, RONLY, eigrpPeerEntry, + 4, {4, 1, 1, 10}}, + {EIGRPVERSION, STRING, RONLY, eigrpPeerEntry, + 4, {4, 1, 1, 11}}, + {EIGRPRETRANS, COUNTER, RONLY, eigrpPeerEntry, + 4, {4, 1, 1, 12}}, + {EIGRPRETRIES, INTEGER, RONLY, eigrpPeerEntry, + 4, {4, 1, 1, 13}}, + + /* EIGRP interface variables */ + {EIGRPPEERCOUNT, GAUGE, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 3}}, + {EIGRPXMITRELIABLEQ, GAUGE, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 4}}, + {EIGRPXMITUNRELIABLEQ, GAUGE, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 5}}, + {EIGRPMEANSRTT, INTEGER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 6}}, + {EIGRPPACINGRELIABLE, INTEGER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 7}}, + {EIGRPPACINGUNRELIABLE, INTEGER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 8}}, + {EIGRPMFLOWTIMER, INTEGER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 9}}, + {EIGRPPENDINGROUTES, GAUGE, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 10}}, + {EIGRPHELLOINTERVAL, INTEGER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 11}}, + {EIGRPXMITNEXTSERIAL, COUNTER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 12}}, + {EIGRPUMCASTS, COUNTER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 13}}, + {EIGRPRMCASTS, COUNTER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 14}}, + {EIGRPUUCASTS, COUNTER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 15}}, + {EIGRPRUCASTS, COUNTER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 16}}, + {EIGRPMCASTEXCEPTS, COUNTER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 17}}, + {EIGRPCRPKTS, COUNTER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 18}}, + {EIGRPACKSSUPPRESSED, COUNTER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 19}}, + {EIGRPRETRANSSENT, COUNTER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 20}}, + {EIGRPOOSRCVD, COUNTER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 21}}, + {EIGRPAUTHMODE, INTEGER, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 22}}, + {EIGRPAUTHKEYCHAIN, STRING, RONLY, eigrpInterfaceEntry, + 4, {5, 1, 1, 23}} +}; + +static struct eigrp_neighbor * +eigrp_snmp_nbr_lookup (struct eigrp *eigrp, struct in_addr *nbr_addr, + unsigned int *ifindex) +{ + struct listnode *node, *nnode, *node2, *nnode2; + struct eigrp_interface *ei; + struct eigrp_neighbor *nbr; + + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr)) + { + if (IPV4_ADDR_SAME (&nbr->src, nbr_addr)) + { + return nbr; + } + } + } + return NULL; +} + +static struct eigrp_neighbor * +eigrp_snmp_nbr_lookup_next (struct in_addr *nbr_addr, unsigned int *ifindex, + int first) +{ + struct listnode *node, *nnode, *node2, *nnode2; + struct eigrp_interface *ei; + struct eigrp_neighbor *nbr; + struct route_node *rn; + struct eigrp_neighbor *min = NULL; + struct eigrp *eigrp = eigrp; + + eigrp = eigrp_lookup (); + + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr)) + { + if (first) + { + if (! min) + min = nbr; + else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr)) + min = nbr; + } + else if (ntohl (nbr->src.s_addr) > ntohl (nbr_addr->s_addr)) + { + if (! min) + min = nbr; + else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr)) + min = nbr; + } + } + } + if (min) + { + *nbr_addr = min->src; + *ifindex = 0; + return min; + } + return NULL; +} + +static struct eigrp_neighbor * +eigrpNbrLookup (struct variable *v, oid *name, size_t *length, + struct in_addr *nbr_addr, unsigned int *ifindex, int exact) +{ + unsigned int len; + int first; + struct eigrp_neighbor *nbr; + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + + if (! eigrp) + return NULL; + + if (exact) + { + if (*length != v->namelen + IN_ADDR_SIZE + 1) + return NULL; + + oid2in_addr (name + v->namelen, IN_ADDR_SIZE, nbr_addr); + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + + return eigrp_snmp_nbr_lookup (eigrp, nbr_addr, ifindex); + } + else + { + first = 0; + len = *length - v->namelen; + + if (len <= 0) + first = 1; + + if (len > IN_ADDR_SIZE) + len = IN_ADDR_SIZE; + + oid2in_addr (name + v->namelen, len, nbr_addr); + + len = *length - v->namelen - IN_ADDR_SIZE; + if (len >= 1) + *ifindex = name[v->namelen + IN_ADDR_SIZE]; + + nbr = eigrp_snmp_nbr_lookup_next (nbr_addr, ifindex, first); + + if (nbr) + { + *length = v->namelen + IN_ADDR_SIZE + 1; + oid_copy_addr (name + v->namelen, nbr_addr, IN_ADDR_SIZE); + name[v->namelen + IN_ADDR_SIZE] = *ifindex; + return nbr; + } + } + return NULL; +} + + + static u_char * + eigrpVpnEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) + { + struct eigrp *eigrp; + + + eigrp = eigrp_lookup (); + + /* Check whether the instance identifier is valid */ + if (smux_header_generic (v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case EIGRPVPNID: /* 1 */ + /* The unique VPN identifier */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPVPNNAME: /* 2 */ + /* The name given to the VPN */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + default: + return NULL; + } + return NULL; + } + + static uint32_t + eigrp_neighbor_count(struct eigrp *eigrp) + { + uint32_t count; + struct eigrp_interface *ei; + struct listnode *node, *node2, *nnode2; + struct eigrp_neighbor *nbr; + + if (eigrp == NULL) + { + return 0; + } + + count = 0; + for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei)) + { + for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr)) + { + if (nbr->state == EIGRP_NEIGHBOR_UP) + count++; + } + } + + return count; + } + + + static u_char * + eigrpTraffStatsEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) + { + struct eigrp *eigrp; + struct eigrp_interface *ei; + struct listnode *node, *nnode; + int counter; + + + eigrp = eigrp_lookup (); + + /* Check whether the instance identifier is valid */ + if (smux_header_generic (v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case EIGRPASNUMBER: /* 1 */ + /* AS-number of this EIGRP instance. */ + if (eigrp) + return SNMP_INTEGER (eigrp->AS); + else + return SNMP_INTEGER (0); + break; + case EIGRPNBRCOUNT: /* 2 */ + /* Neighbor count of this EIGRP instance */ + if (eigrp) + return SNMP_INTEGER (eigrp_neighbor_count (eigrp)); + else + return SNMP_INTEGER (0); + break; + case EIGRPHELLOSSENT: /* 3 */ + /* Hello packets output count */ + if (eigrp) + { + counter = 0; + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + counter += ei->hello_out; + } + return SNMP_INTEGER (counter); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPHELLOSRCVD: /* 4 */ + /* Hello packets input count */ + if (eigrp) + { + counter = 0; + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + counter += ei->hello_in; + } + return SNMP_INTEGER (counter); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPUPDATESSENT: /* 5 */ + /* Update packets output count */ + if (eigrp) + { + counter = 0; + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + counter += ei->update_out; + } + return SNMP_INTEGER (counter); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPUPDATESRCVD: /* 6 */ + /* Update packets input count */ + if (eigrp) + { + counter = 0; + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + counter += ei->update_in; + } + return SNMP_INTEGER (counter); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPQUERIESSENT: /* 7 */ + /* Querry packets output count */ + if (eigrp) + { + counter = 0; + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + counter += ei->query_out; + } + return SNMP_INTEGER (counter); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPQUERIESRCVD: /* 8 */ + /* Querry packets input count */ + if (eigrp) + { + counter = 0; + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + counter += ei->query_in; + } + return SNMP_INTEGER (counter); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPREPLIESSENT: /* 9 */ + /* Reply packets output count */ + if (eigrp) + { + counter = 0; + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + counter += ei->reply_out; + } + return SNMP_INTEGER (counter); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPREPLIESRCVD: /* 10 */ + /* Reply packets input count */ + if (eigrp) + { + counter = 0; + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + counter += ei->reply_in; + } + return SNMP_INTEGER (counter); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPACKSSENT: /* 11 */ + /* Acknowledgement packets output count */ + if (eigrp) + { + counter = 0; + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + counter += ei->ack_out; + } + return SNMP_INTEGER (counter); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPACKSRCVD: /* 12 */ + /* Acknowledgement packets input count */ + if (eigrp) + { + counter = 0; + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + counter += ei->ack_in; + } + return SNMP_INTEGER (counter); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPINPUTQHIGHMARK: /* 13 */ + /* The highest number of EIGRP packets in the input queue */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPINPUTQDROPS: /* 14 */ + /* The number of EIGRP packets dropped from the input queue */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPSIAQUERIESSENT: /* 15 */ + /* SIA querry packets output count */ + if (eigrp) + { + counter = 0; + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + counter += ei->siaQuery_out; + } + return SNMP_INTEGER (counter); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPSIAQUERIESRCVD: /* 16 */ + /* SIA querry packets input count */ + if (eigrp) + { + counter = 0; + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + counter += ei->siaQuery_in; + } + return SNMP_INTEGER (counter); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPASROUTERIDTYPE: /* 17 */ + /* Whether the router ID is set manually or automatically */ + if (eigrp) + if(eigrp->router_id_static!=0) + return SNMP_INTEGER(1); + else + return SNMP_INTEGER(1); + else + return SNMP_INTEGER (0); + break; + case EIGRPASROUTERID: /* 18 */ + /* Router ID for this EIGRP AS */ + if (eigrp) + if(eigrp->router_id_static!=0) + return SNMP_INTEGER (eigrp->router_id_static); + else + return SNMP_INTEGER (eigrp->router_id); + else + return SNMP_INTEGER (0); + break; + case EIGRPTOPOROUTES: /* 19 */ + /* The total number of EIGRP derived routes currently existing + in the topology table for the AS */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPHEADSERIAL: /* 20 */ + /* The serial number of the first route in the internal + sequence for an AS*/ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPNEXTSERIAL: /* 21 */ + /* The serial number that would be assigned to the next new + or changed route in the topology table for the AS*/ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPXMITPENDREPLIES: /* 22 */ + /* Total number of outstanding replies expected to queries + that have been sent to peers in the current AS*/ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPXMITDUMMIES: /* 23 */ + /* Total number of currently existing dummies associated with the AS*/ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + default: + return NULL; + } + return NULL; + } + static u_char * + eigrpTopologyEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) + { + struct eigrp *eigrp; + struct eigrp_interface *ei; + struct listnode *node, *nnode; + + + eigrp = eigrp_lookup (); + + /* Check whether the instance identifier is valid */ + if (smux_header_generic (v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case EIGRPDESTNETTYPE: /* 1 */ + /* The format of the destination IP network number for a single + route in the topology table*/ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPDESTNET: /* 2 */ + /* The destination IP network number for a single route in the topology table*/ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPDESTNETPREFIXLEN: /* 4 */ + /* The prefix length associated with the destination IP network address + for a single route in the topology table in the AS*/ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPACTIVE: /* 5 */ + /* A value of true(1) indicates the route to the destination network has failed + A value of false(2) indicates the route is stable (passive).*/ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPSTUCKINACTIVE: /* 6 */ + /* A value of true(1) indicates that that this route which is in active state + has not received any replies to queries for alternate paths */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPDESTSUCCESSORS: /* 7 */ + /* Next routing hop for a path to the destination IP network */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPFDISTANCE: /* 8 */ + /* Minimum distance from this router to the destination IP network */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPROUTEORIGINTYPE: /* 9 */ + /* Text string describing the internal origin of the EIGRP route */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPROUTEORIGINADDRTYPE: /* 10 */ + /* The format of the IP address defined as the origin of this + topology route entry */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPROUTEORIGINADDR: /* 11 */ + /* If the origin of the topology route entry is external to this router, + then this object is the IP address of the router from which it originated */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPNEXTHOPADDRESSTYPE: /* 12 */ + /* The format of the next hop IP address */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPNEXTHOPADDRESS: /* 13 */ + /* Next hop IP address for the route */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPNEXTHOPINTERFACE: /* 14 */ + /* The interface through which the next hop IP address is reached */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPDISTANCE: /* 15 */ + /* The computed distance to the destination network entry from this router */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPREPORTDISTANCE: /* 16 */ + /* The computed distance to the destination network in the topology entry + reported to this router by the originator of this route */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + default: + return NULL; + } + return NULL; + } + + static u_char * + eigrpPeerEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) + { + struct eigrp *eigrp; + struct eigrp_interface *ei; + struct listnode *node, *nnode; + struct eigrp_neighbor *nbr; + struct in_addr nbr_addr; + unsigned int ifindex; + + eigrp = eigrp_lookup (); + + /* Check whether the instance identifier is valid */ + if (smux_header_generic (v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + memset (&nbr_addr, 0, sizeof (struct in_addr)); + ifindex = 0; + + nbr = eigrpNbrLookup (v, name, length, &nbr_addr, &ifindex, exact); + if (! nbr) + return NULL; + ei = nbr->ei; + if (! ei) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case EIGRPHANDLE: /* 1 */ + /* The unique internal identifier for the peer in the AS */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPPEERADDRTYPE: /* 2 */ + /* The format of the remote source IP address used by the peer */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPPEERADDR: /* 3 */ + /* The source IP address used by the peer */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPPEERIFINDEX: /* 4 */ + /* The ifIndex of the interface on this router */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPHOLDTIME: /* 5 */ + /* How much time must pass without receiving a hello packet from this + EIGRP peer before this router declares the peer down */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPUPTIME: /* 6 */ + /* The elapsed time since the EIGRP adjacency was first established */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPSRTT: /* 7 */ + /* The computed smooth round trip time for packets to and from the peer */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPRTO: /* 8 */ + /* The computed retransmission timeout for the peer */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPPKTSENQUEUED: /* 9 */ + /* The number of any EIGRP packets currently enqueued */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPLASTSEQ: /* 10 */ + /* sequence number of the last EIGRP packet sent to this peer */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPVERSION: /* 11 */ + /* The EIGRP version information reported by the remote peer */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPRETRANS: /* 12 */ + /* The cumulative number of retransmissions to this peer */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPRETRIES: /* 13 */ + /* The number of times the current unacknowledged packet has been retried */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + default: + return NULL; + } + return NULL; + } + static u_char * + eigrpInterfaceEntry (struct variable *v, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) + { + struct eigrp *eigrp; + struct eigrp_interface *ei; + struct listnode *node, *nnode; + struct keychain *keychain; + struct list *keylist; + int counter; + + + eigrp = eigrp_lookup (); + + /* Check whether the instance identifier is valid */ + if (smux_header_generic (v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Return the current value of the variable */ + switch (v->magic) + { + case EIGRPPEERCOUNT: /* 3 */ + /* The number of EIGRP adjacencies currently formed with + peers reached through this interface */ + if (eigrp) + { + return SNMP_INTEGER (eigrp_neighbor_count (eigrp)); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPXMITRELIABLEQ: /* 4 */ + /* The number of EIGRP packets currently waiting in the reliable + transport transmission queue */ + if (eigrp) + { + return SNMP_INTEGER (1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPXMITUNRELIABLEQ: /* 5 */ + /* The number of EIGRP packets currently waiting in the unreliable + transport transmission queue */ + if (eigrp) + { + return SNMP_INTEGER (1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPMEANSRTT: /* 6 */ + /* The average of all the computed smooth round trip time values + for a packet to and from all peers established on this interface */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPPACINGRELIABLE: /* 7 */ + /* The configured time interval between EIGRP packet transmissions */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPPACINGUNRELIABLE: /* 8 */ + /* The configured time interval between EIGRP packet transmissions + on the interface when the unreliable transport method is used */ + if (eigrp) + { + return SNMP_INTEGER (1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPMFLOWTIMER: /* 9 */ + /* The configured multicast flow control timer value */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPPENDINGROUTES: /* 10 */ + /* The number of queued EIGRP routing updates awaiting transmission */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPHELLOINTERVAL: /* 11 */ + /* The configured time interval between Hello packet transmissions */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPXMITNEXTSERIAL: /* 12 */ + /* The serial number of the next EIGRP packet that is to be queued + for transmission */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPUMCASTS: /* 13 */ + /* The total number of unreliable EIGRP multicast packets sent + on this interface */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPRMCASTS: /* 14 */ + /* The total number of reliable EIGRP multicast packets sent + on this interface */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPUUCASTS: /* 15 */ + /* The total number of unreliable EIGRP unicast packets sent + on this interface */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPRUCASTS: /* 16 */ + /* The total number of reliable EIGRP unicast packets sent + on this interface */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPMCASTEXCEPTS: /* 17 */ + /* The total number of EIGRP multicast exception transmissions */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPCRPKTS: /* 18 */ + /* The total number EIGRP Conditional-Receive packets sent on this interface */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPACKSSUPPRESSED: /* 19 */ + /* The total number of individual EIGRP acknowledgement packets that have been + suppressed and combined in an already enqueued outbound reliable packet on this interface */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPRETRANSSENT: /* 20 */ + /* The total number EIGRP packet retransmissions sent on the interface */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPOOSRCVD: /* 21 */ + /* The total number of out-of-sequence EIGRP packets received */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPAUTHMODE: /* 22 */ + /* The EIGRP authentication mode of the interface */ + if (eigrp) + { + return SNMP_INTEGER(1); + } + else + return SNMP_INTEGER (0); + break; + case EIGRPAUTHKEYCHAIN: /* 23 */ + /* The name of the authentication key-chain configured + on this interface. */ + keylist = keychain_list_get(); + for (ALL_LIST_ELEMENTS (keylist, node, nnode, keychain)) + { + return (u_char *) keychain->name; + } + if (eigrp && keychain) + { + *var_len = str_len (keychain->name); + return (u_char *) keychain->name; + } + else + return (u_char *) "TEST"; + break; + default: + return NULL; + } + return NULL; + } + + + /* Register EIGRP-MIB. */ + void + eigrp_snmp_init () + { + eigrp_snmp_iflist = list_new (); + smux_init (eigrp_om->master); + REGISTER_MIB("ciscoEigrpMIB", eigrp_variables, variable, eigrp_oid); + } + + +#endif diff --git a/eigrpd/eigrp_snmp.h b/eigrpd/eigrp_snmp.h new file mode 100644 index 000000000..ab14912c4 --- /dev/null +++ b/eigrpd/eigrp_snmp.h @@ -0,0 +1,36 @@ +/* + * EIGRP SNMP Support. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * 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. + */ + + +#ifndef _ZEBRA_EIGRP_SNMP_H +#define _ZEBRA_EIGRP_SNMP_H + +extern void eigrp_snmp_init (void); + + +#endif /* _ZEBRA_EIGRP_SNMP_H */ diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h new file mode 100644 index 000000000..6e90c8cba --- /dev/null +++ b/eigrpd/eigrp_structs.h @@ -0,0 +1,533 @@ +/* + * EIGRP Definition of Data Structures. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * 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. + */ + +#ifndef _ZEBRA_EIGRP_STRUCTS_H_ +#define _ZEBRA_EIGRP_STRUCTS_H_ + +#include "filter.h" + +#include "eigrpd/eigrp_const.h" +#include "eigrpd/eigrp_macros.h" + +/* EIGRP master for system wide configuration and variables. */ +struct eigrp_master +{ + /* EIGRP instance. */ + struct list *eigrp; + + /* EIGRP thread master. */ + struct thread_master *master; + + /* Zebra interface list. */ + struct list *iflist; + + /* EIGRP start time. */ + time_t start_time; + + /* Various EIGRP global configuration. */ + u_char options; + +#define EIGRP_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */ +}; + +struct eigrp_metrics +{ + u_int32_t delay; + u_int32_t bandwith; + unsigned char mtu[3]; + u_char hop_count; + u_char reliability; + u_char load; + u_char tag; + u_char flags; +}; + +struct eigrp +{ + u_int16_t AS; /* Autonomous system number */ + u_int16_t vrid; /* Virtual Router ID */ + u_char k_values[6]; /*Array for K values configuration*/ + u_char variance; /*Metric variance multiplier*/ + u_char max_paths; /*Maximum allowed paths for 1 prefix*/ + + /*Name of this EIGRP instance*/ + char *name; + + /* EIGRP Router ID. */ + u_int32_t router_id; /* Configured automatically. */ + u_int32_t router_id_static; /* Configured manually. */ + + struct list *eiflist; /* eigrp interfaces */ + u_char passive_interface_default; /* passive-interface default */ + + unsigned int fd; + unsigned int maxsndbuflen; + + u_int32_t sequence_number; /*Global EIGRP sequence number*/ + + struct stream *ibuf; + struct list *oi_write_q; + + /*Threads*/ + struct thread *t_write; + struct thread *t_read; + struct thread *t_distribute; /* timer for distribute list */ + + struct route_table *networks; /* EIGRP config networks. */ + + struct list *topology_table; + + u_int64_t serno; /* Global serial number counter for topology entry changes*/ + u_int64_t serno_last_update; /* Highest serial number of information send by last update*/ + struct list *topology_changes_internalIPV4; + struct list *topology_changes_externalIPV4; + + /*Neighbor self*/ + struct eigrp_neighbor *neighbor_self; + + /*Configured metric for redistributed routes*/ + struct eigrp_metrics dmetric[ZEBRA_ROUTE_MAX + 1]; + int redistribute; /* Num of redistributed protocols. */ + + /* Access-list. */ + struct access_list *list[EIGRP_FILTER_MAX]; + /* Prefix-list. */ + struct prefix_list *prefix[EIGRP_FILTER_MAX]; + /* Route-map. */ + struct route_map *routemap[EIGRP_FILTER_MAX]; + + /* For redistribute route map. */ + struct + { + char *name; + struct route_map *map; + int metric_config; + u_int32_t metric; + } route_map[ZEBRA_ROUTE_MAX]; + + QOBJ_FIELDS +}; +DECLARE_QOBJ_TYPE(eigrp) +//------------------------------------------------------------------------------------------------------------------------------------------ + +/*EIGRP interface structure*/ +struct eigrp_interface +{ + /* This interface's parent eigrp instance. */ + struct eigrp *eigrp; + + /* Interface data from zebra. */ + struct interface *ifp; + + /* Packet send buffer. */ + struct eigrp_fifo *obuf; /* Output queue */ + + /* To which multicast groups do we currently belong? */ + + /* Configured varables. */ + struct eigrp_if_params *params; + + u_char multicast_memberships; + + /* EIGRP Network Type. */ + u_char type; + + struct prefix *address; /* Interface prefix */ + struct connected *connected; /* Pointer to connected */ + + /* Neighbor information. */ + struct list *nbrs; /* EIGRP Neighbor List */ + + /* Threads. */ + struct thread *t_hello; /* timer */ + struct thread *t_distribute; /* timer for distribute list */ + + int on_write_q; + + /* Statistics fields. */ + u_int32_t hello_in; /* Hello message input count. */ + u_int32_t update_in; /* Update message input count. */ + u_int32_t query_in; /* Querry message input count. */ + u_int32_t reply_in; /* Reply message input count. */ + u_int32_t hello_out; /* Hello message output count. */ + u_int32_t update_out; /* Update message output count. */ + u_int32_t query_out; /* Query message output count. */ + u_int32_t reply_out; /* Reply message output count. */ + u_int32_t siaQuery_in; + u_int32_t siaQuery_out; + u_int32_t siaReply_in; + u_int32_t siaReply_out; + u_int32_t ack_out; + u_int32_t ack_in; + + u_int32_t crypt_seqnum; /* Cryptographic Sequence Number */ + + /* Access-list. */ + struct access_list *list[EIGRP_FILTER_MAX]; + /* Prefix-list. */ + struct prefix_list *prefix[EIGRP_FILTER_MAX]; + /* Route-map. */ + struct route_map *routemap[EIGRP_FILTER_MAX]; +}; + +struct eigrp_if_params +{ + DECLARE_IF_PARAM (u_char, passive_interface); /* EIGRP Interface is passive: no sending or receiving (no need to join multicast groups) */ + DECLARE_IF_PARAM (u_int32_t, v_hello); /* Hello Interval */ + DECLARE_IF_PARAM (u_int16_t, v_wait); /* Router Hold Time Interval */ + DECLARE_IF_PARAM (u_char, type); /* type of interface */ + DECLARE_IF_PARAM (u_int32_t, bandwidth); + DECLARE_IF_PARAM (u_int32_t, delay); + DECLARE_IF_PARAM (u_char, reliability); + DECLARE_IF_PARAM (u_char, load); + + DECLARE_IF_PARAM (char *, auth_keychain ); /* Associated keychain with interface*/ + DECLARE_IF_PARAM (int, auth_type); /* EIGRP authentication type */ +}; + +enum +{ + MEMBER_ALLROUTERS = 0, MEMBER_MAX, +}; + +struct eigrp_if_info +{ + struct eigrp_if_params *def_params; + struct route_table *params; + struct route_table *eifs; + unsigned int membership_counts[MEMBER_MAX]; /* multicast group refcnts */ +}; + +//------------------------------------------------------------------------------------------------------------------------------------------ + +/* Determines if it is first or last packet + * when packet consists of multiple packet + * chunks because of many route TLV + * (all won't fit into one packet) */ +enum Packet_part_type +{ + EIGRP_PACKET_PART_NA, + EIGRP_PACKET_PART_FIRST, + EIGRP_PACKET_PART_LAST +}; + +/* Neighbor Data Structure */ +struct eigrp_neighbor +{ + /* This neighbor's parent eigrp interface. */ + struct eigrp_interface *ei; + + /* EIGRP neighbor Information */ + u_char state; /* neigbor status. */ + + u_int32_t recv_sequence_number; /* Last received sequence Number. */ + u_int32_t init_sequence_number; + + /*If packet is unacknowledged, we try to send it again 16 times*/ + u_char retrans_counter; + + struct in_addr src; /* Neighbor Src address. */ + + u_char os_rel_major; // system version - just for show + u_char os_rel_minor; // system version - just for show + u_char tlv_rel_major; // eigrp version - tells us what TLV format to use + u_char tlv_rel_minor; // eigrp version - tells us what TLV format to use + + u_char K1; + u_char K2; + u_char K3; + u_char K4; + u_char K5; + u_char K6; + + /* Timer values. */ + u_int16_t v_holddown; + + /* Threads. */ + struct thread *t_holddown; + struct thread *t_nbr_send_gr; /* thread for sending multiple GR packet chunks */ + + struct eigrp_fifo *retrans_queue; + struct eigrp_fifo *multicast_queue; + + u_int32_t crypt_seqnum; /* Cryptographic Sequence Number. */ + + /* prefixes not received from neighbor during Graceful restart */ + struct list *nbr_gr_prefixes; + /* prefixes not yet send to neighbor during Graceful restart */ + struct list *nbr_gr_prefixes_send; + /* if packet is first or last during Graceful restart */ + enum Packet_part_type nbr_gr_packet_type; +}; + +//--------------------------------------------------------------------------------------------------------------------------------------------- + + +struct eigrp_packet +{ + struct eigrp_packet *next; + struct eigrp_packet *previous; + + /* Pointer to data stream. */ + struct stream *s; + + /* IP destination address. */ + struct in_addr dst; + + /*Packet retransmission thread*/ + struct thread *t_retrans_timer; + + /*Packet retransmission counter*/ + u_char retrans_counter; + + u_int32_t sequence_number; + + /* EIGRP packet length. */ + u_int16_t length; +}; + +struct eigrp_fifo +{ + struct eigrp_packet *head; + struct eigrp_packet *tail; + + unsigned long count; +}; + +struct eigrp_header +{ + u_char version; + u_char opcode; + u_int16_t checksum; + u_int32_t flags; + u_int32_t sequence; + u_int32_t ack; + u_int16_t vrid; + u_int16_t ASNumber; + char *tlv[0]; + +}__attribute__((packed)); + + +/** + * Generic TLV type used for packet decoding. + * + * +-----+------------------+ + * | | | | + * | Type| Len | Vector | + * | | | | + * +-----+------------------+ + */ +struct eigrp_tlv_hdr_type +{ + u_int16_t type; + u_int16_t length; + uint8_t value[0]; +}__attribute__((packed)); + +struct TLV_Parameter_Type +{ + u_int16_t type; + u_int16_t length; + u_char K1; + u_char K2; + u_char K3; + u_char K4; + u_char K5; + u_char K6; + u_int16_t hold_time; +}__attribute__((packed)); + +struct TLV_MD5_Authentication_Type +{ + u_int16_t type; + u_int16_t length; + u_int16_t auth_type; + u_int16_t auth_length; + u_int32_t key_id; + u_int32_t key_sequence; + u_char Nullpad[8]; + u_char digest[EIGRP_AUTH_TYPE_MD5_LEN]; + +}__attribute__((packed)); + +struct TLV_SHA256_Authentication_Type +{ + u_int16_t type; + u_int16_t length; + u_int16_t auth_type; + u_int16_t auth_length; + u_int32_t key_id; + u_int32_t key_sequence; + u_char Nullpad[8]; + u_char digest[EIGRP_AUTH_TYPE_SHA256_LEN]; + +}__attribute__((packed)); + +struct TLV_Sequence_Type +{ + u_int16_t type; + u_int16_t length; + u_char addr_length; + struct in_addr *addresses; +}__attribute__((packed)); + +struct TLV_Next_Multicast_Sequence +{ + u_int16_t type; + u_int16_t length; + u_int32_t multicast_sequence; +}__attribute__((packed)); + +struct TLV_Software_Type +{ + u_int16_t type; + u_int16_t length; + u_char vender_major; + u_char vender_minor; + u_char eigrp_major; + u_char eigrp_minor; +}__attribute__((packed)); + +struct TLV_IPv4_Internal_type +{ + u_int16_t type; + u_int16_t length; + struct in_addr forward; + + /*Metrics*/ + struct eigrp_metrics metric; + + u_char prefix_length; + + unsigned char destination_part[4]; + struct in_addr destination; +}__attribute__((packed)); + +struct TLV_IPv4_External_type +{ + u_int16_t type; + u_int16_t length; + struct in_addr next_hop; + struct in_addr originating_router; + u_int32_t originating_as; + u_int32_t administrative_tag; + u_int32_t external_metric; + u_int16_t reserved; + u_char external_protocol; + u_char external_flags; + + /*Metrics*/ + struct eigrp_metrics metric; + + u_char prefix_length; + unsigned char destination_part[4]; + struct in_addr destination; +}__attribute__((packed)); + +/* EIGRP Peer Termination TLV - used for hard restart */ +struct TLV_Peer_Termination_type +{ + u_int16_t type; + u_int16_t length; + u_char unknown; + u_int32_t neighbor_ip; +} __attribute__((packed)); + +/* Who executed Graceful restart */ +enum GR_type +{ + EIGRP_GR_MANUAL, + EIGRP_GR_FILTER +}; + +//--------------------------------------------------------------------------------------------------------------------------------------------- + +/* EIGRP Topology table node structure */ +struct eigrp_prefix_entry +{ + struct list *entries, *rij; + u_int32_t fdistance; // FD + u_int32_t rdistance; // RD + u_int32_t distance; // D + struct eigrp_metrics reported_metric; // RD for sending + + u_char nt; //network type + u_char state; //route fsm state + u_char af; // address family + u_char req_action; // required action + + struct prefix_ipv4 *destination_ipv4; // pointer to struct with ipv4 address + struct prefix_ipv6 *destination_ipv6; // pointer to struct with ipv6 address + + //If network type is REMOTE_EXTERNAL, pointer will have reference to its external TLV + struct TLV_IPv4_External_type *extTLV; + + u_int64_t serno; /*Serial number for this entry. Increased with each change of entry*/ +}; + +/* EIGRP Topology table record structure */ +struct eigrp_neighbor_entry +{ + struct eigrp_prefix_entry *prefix; + u_int32_t reported_distance; //distance reported by neighbor + u_int32_t distance; //sum of reported distance and link cost to advertised neighbor + + struct eigrp_metrics reported_metric; + struct eigrp_metrics total_metric; + + struct eigrp_neighbor *adv_router; //ip address of advertising neighbor + u_char flags; //used for marking successor and FS + + struct eigrp_interface *ei; //pointer for case of connected entry + +}; + +//--------------------------------------------------------------------------------------------------------------------------------------------- + +/* EIGRP Finite State Machine */ + +struct eigrp_fsm_action_message +{ + u_char packet_type; //UPDATE, QUERY, SIAQUERY, SIAREPLY + struct eigrp *eigrp; // which thread sent mesg + struct eigrp_neighbor *adv_router; //advertising neighbor + struct eigrp_neighbor_entry *entry; + struct eigrp_prefix_entry *prefix; + int data_type; // internal or external tlv type + union{ + struct TLV_IPv4_External_type *ipv4_ext_data; + struct TLV_IPv4_Internal_type *ipv4_int_type; + }data; +}; + +#endif /* _ZEBRA_EIGRP_STRUCTURES_H_ */ diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c new file mode 100644 index 000000000..c8b53515b --- /dev/null +++ b/eigrpd/eigrp_topology.c @@ -0,0 +1,586 @@ +/* + * EIGRP Topology Table. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "log.h" +#include "linklist.h" +#include "vty.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_fsm.h" +#include "eigrpd/eigrp_memory.h" + +static int +eigrp_prefix_entry_cmp(struct eigrp_prefix_entry *, struct eigrp_prefix_entry *); +static void +eigrp_prefix_entry_del(struct eigrp_prefix_entry *); +static int +eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *, + struct eigrp_neighbor_entry *); + +/* + * asdf;laksdjf;lajsdf;kasdjf;asdjf; + * asdfaskdjfa;sdkjf;adlskj + * Returns linkedlist used as topology table + * cmp - assigned function for comparing topology nodes + * del - assigned function executed before deleting topology node by list function + */ +struct list * +eigrp_topology_new() +{ + struct list* new = list_new(); + new->cmp = (int + (*)(void *, void *)) eigrp_prefix_entry_cmp; + new->del = (void + (*)(void *)) eigrp_prefix_entry_del; + + return new; +} + +/* + * Topology node comparison + */ + +static int +eigrp_prefix_entry_cmp(struct eigrp_prefix_entry *node1, + struct eigrp_prefix_entry *node2) +{ + if (node1->af == AF_INET) + { + if (node2->af == AF_INET) + { + if (node1->destination_ipv4->prefix.s_addr + < node2->destination_ipv4->prefix.s_addr) + { + return -1; // if it belong above node2 + } + else + { + if (node1->destination_ipv4->prefix.s_addr + > node2->destination_ipv4->prefix.s_addr) + { + return 1; //if it belongs under node2 + } + else + { + return 0; // same value... ERROR...in case of adding same prefix again + } + } + } + else + { + return 1; + } + } + else + { // TODO check if the prefix dont exists + return 1; // add to end + } +} + +/* + * Topology node delete + */ + +static void +eigrp_prefix_entry_del(struct eigrp_prefix_entry *node) +{ + list_delete_all_node(node->entries); + list_free(node->entries); +} + +/* + * Returns new created toplogy node + * cmp - assigned function for comparing topology entry + */ + +struct eigrp_prefix_entry * +eigrp_prefix_entry_new() +{ + struct eigrp_prefix_entry *new; + new = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY, sizeof(struct eigrp_prefix_entry)); + new->entries = list_new(); + new->rij = list_new(); + new->entries->cmp = (int + (*)(void *, void *)) eigrp_neighbor_entry_cmp; + new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC; + new->destination_ipv4 = NULL; + new->destination_ipv6 = NULL; + + return new; +} + +/* + * Topology entry comparison + */ + +static int +eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *entry1, + struct eigrp_neighbor_entry *entry2) +{ + if (entry1->distance < entry2->distance) // parameter used in list_add_sort () + return -1; // actually set to sort by distance + if (entry1->distance > entry2->distance) + return 1; + + return 0; +} + +/* + * Returns new topology entry + */ + +struct eigrp_neighbor_entry * +eigrp_neighbor_entry_new() +{ + struct eigrp_neighbor_entry *new; + + new = XCALLOC(MTYPE_EIGRP_NEIGHBOR_ENTRY, + sizeof(struct eigrp_neighbor_entry)); + new->reported_distance = EIGRP_MAX_METRIC; + new->distance = EIGRP_MAX_METRIC; + + return new; +} + +/* + * Freeing topology table list + */ + +void +eigrp_topology_free(struct list *list) +{ + list_free(list); +} + +/* + * Deleting all topology nodes in table + */ + +void +eigrp_topology_cleanup(struct list *topology) +{ + assert(topology); + + eigrp_topology_delete_all(topology); +} + +/* + * Adding topology node to topology table + */ + +void +eigrp_prefix_entry_add(struct list *topology, struct eigrp_prefix_entry *node) +{ + if (listnode_lookup(topology, node) == NULL) + { + listnode_add_sort(topology, node); + } +} + +/* + * Adding topology entry to topology node + */ + +void +eigrp_neighbor_entry_add(struct eigrp_prefix_entry *node, + struct eigrp_neighbor_entry *entry) +{ + if (listnode_lookup(node->entries, entry) == NULL) + { + listnode_add_sort(node->entries, entry); + entry->prefix = node; + } +} + +/* + * Deleting topology node from topology table + */ + +void +eigrp_prefix_entry_delete(struct list *topology, + struct eigrp_prefix_entry *node) +{ + if (listnode_lookup(topology, node) != NULL) + { + list_delete_all_node(node->entries); + list_free(node->entries); + list_free(node->rij); + listnode_delete(topology, node); + XFREE(MTYPE_EIGRP_PREFIX_ENTRY,node); + } +} + +/* + * Deleting topology entry from topology node + */ + +void +eigrp_neighbor_entry_delete(struct eigrp_prefix_entry *node, + struct eigrp_neighbor_entry *entry) +{ + if (listnode_lookup(node->entries, entry) != NULL) + { + listnode_delete(node->entries, entry); + XFREE(MTYPE_EIGRP_NEIGHBOR_ENTRY,entry); + } +} + +/* + * Deleting all nodes from topology table + */ + +void +eigrp_topology_delete_all(struct list *topology) +{ + list_delete_all_node(topology); +} + +/* + * Return 0 if topology is not empty + * otherwise return 1 + */ + +unsigned int +eigrp_topology_table_isempty(struct list *topology) +{ + if (topology->count) + return 1; + else + return 0; +} + +struct eigrp_prefix_entry * +eigrp_topology_table_lookup_ipv4(struct list *topology_table, + struct prefix_ipv4 * address) +{ + struct eigrp_prefix_entry *data; + struct listnode *node; + for (ALL_LIST_ELEMENTS_RO(topology_table, node, data)) + { + + if ((data->af == AF_INET) + && (data->destination_ipv4->prefix.s_addr == address->prefix.s_addr) + && (data->destination_ipv4->prefixlen == address->prefixlen)) + return data; + } + + return NULL; +} +/* TODO + struct eigrp_prefix_entry * + eigrp_topology_table_lookup_ipv6 (struct list *topology_table, + struct prefix_ipv6 * address) + { + struct eigrp_prefix_entry *data; + struct listnode *node, *nnode; + for (ALL_LIST_ELEMENTS (topology_table, node, nnode, data)) + { + + if (comparison) + return data; + } + + return NULL; + } + */ +struct list * +eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node) +{ + struct list *successors = list_new(); + ; + struct eigrp_neighbor_entry *data; + struct listnode *node1, *node2; + for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data)) + { + if (data->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG) + { + listnode_add(successors, data); + } + } + + return successors; +} + +/*extern struct eigrp_neighbor_entry * + eigrp_topology_get_fsuccessor (struct eigrp_prefix_entry *table_node) + { + struct eigrp_neighbor_entry *data; + struct listnode *node, *nnode; + for (ALL_LIST_ELEMENTS (table_node->entries, node, nnode, data)) + { + if ((data->flags & EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG) == 1) + { + return data; + } + } + + return NULL; + }*/ + +struct eigrp_neighbor_entry * +eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *nbr) +{ + struct eigrp_neighbor_entry *data; + struct listnode *node, *nnode; + for (ALL_LIST_ELEMENTS(entries, node, nnode, data)) + { + if (data->adv_router == nbr) + { + return data; + } + } + + return NULL; +} + +/* Lookup all prefixes from specified neighbor */ +struct list * +eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp, struct eigrp_neighbor *nbr) +{ + struct listnode *node1, *node11, *node2, *node22; + struct eigrp_prefix_entry *prefix; + struct eigrp_neighbor_entry *entry; + + /* create new empty list for prefixes storage */ + struct list *prefixes = list_new(); + + /* iterate over all prefixes in topology table */ + for (ALL_LIST_ELEMENTS(eigrp->topology_table, node1, node11, prefix)) + { + /* iterate over all neighbor entry in prefix */ + for (ALL_LIST_ELEMENTS(prefix->entries, node2, node22, entry)) + { + /* if entry is from specified neighbor, add to list */ + if (entry->adv_router == nbr) + { + listnode_add(prefixes, prefix); + } + } + } + + /* return list of prefixes from specified neighbor */ + return prefixes; +} + +int +eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg) +{ + struct eigrp *eigrp = msg->eigrp; + struct eigrp_prefix_entry *prefix = msg->prefix; + struct eigrp_neighbor_entry *entry = msg->entry; + int change = 0; + assert(entry); + + struct TLV_IPv4_External_type *ext_data = NULL; + struct TLV_IPv4_Internal_type *int_data = NULL; + if (msg->data_type == EIGRP_TLV_IPv4_INT) + { + int_data = msg->data.ipv4_int_type; + if (eigrp_metrics_is_same(&int_data->metric,&entry->reported_metric)) + { + return 0; // No change + } + change = + entry->reported_distance + < eigrp_calculate_metrics(eigrp, &int_data->metric) ? 1 : + entry->reported_distance + > eigrp_calculate_metrics(eigrp, &int_data->metric) ? 2 : 3; // Increase : Decrease : No change + entry->reported_metric = int_data->metric; + entry->reported_distance = eigrp_calculate_metrics(eigrp, + &int_data->metric); + entry->distance = eigrp_calculate_total_metrics(eigrp, entry); + } + else + { + ext_data = msg->data.ipv4_ext_data; + if (eigrp_metrics_is_same (&ext_data->metric, &entry->reported_metric)) + return 0; + } + /* + * Move to correct position in list according to new distance + */ + listnode_delete(prefix->entries, entry); + listnode_add_sort(prefix->entries, entry); + + return change; +} + +void +eigrp_topology_update_all_node_flags(struct eigrp *eigrp) +{ + struct list *table = eigrp->topology_table; + struct eigrp_prefix_entry *data; + struct listnode *node, *nnode; + for (ALL_LIST_ELEMENTS(table, node, nnode, data)) + { + eigrp_topology_update_node_flags(data); + } +} + +void +eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest) +{ + struct listnode *node; + struct eigrp_neighbor_entry *entry; + struct eigrp * eigrp = eigrp_lookup(); + + for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) + { + if ((entry->distance <= (u_int64_t)(dest->distance*eigrp->variance)) && entry->distance != EIGRP_MAX_METRIC) // is successor + { + entry->flags |= EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG; + entry->flags &= 0xfd; // 1111 1101 set fs flag to zero + } + else if (entry->reported_distance < dest->fdistance) // is feasible successor + { + entry->flags |= EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG; + entry->flags &= 0xfe; // 1111 1110 set successor flag to zero + } + else + { + entry->flags &= 0xfc; // 1111 1100 set successor and fs flag to zero + } + } +} + +void +eigrp_update_routing_table(struct eigrp_prefix_entry * prefix) +{ + struct listnode *node; + struct eigrp_neighbor_entry *entry; + + for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry)) + { + if (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG) + { + if (!(entry->flags & EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG)) + { + eigrp_zebra_route_add(prefix->destination_ipv4, entry); + entry->flags += EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG; + } + } + else if (entry->flags & EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG) + { + eigrp_zebra_route_delete(prefix->destination_ipv4, entry); + entry->flags -= EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG; + } + } +} + +void +eigrp_topology_neighbor_down(struct eigrp *eigrp, struct eigrp_neighbor * nbr) +{ + struct listnode *node1, *node11, *node2, *node22; + struct eigrp_prefix_entry *prefix; + struct eigrp_neighbor_entry *entry; + + for (ALL_LIST_ELEMENTS(eigrp->topology_table, node1, node11, prefix)) + { + for (ALL_LIST_ELEMENTS(prefix->entries, node2, node22, entry)) + { + if (entry->adv_router == nbr) + { + struct eigrp_fsm_action_message *msg; + msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, + sizeof(struct eigrp_fsm_action_message)); + struct TLV_IPv4_Internal_type * tlv = eigrp_IPv4_InternalTLV_new(); + tlv->metric.delay = EIGRP_MAX_METRIC; + msg->packet_type = EIGRP_OPC_UPDATE; + msg->eigrp = eigrp; + msg->data_type = EIGRP_TLV_IPv4_INT; + msg->adv_router = nbr; + msg->data.ipv4_int_type = tlv; + msg->entry = entry; + msg->prefix = prefix; + int event = eigrp_get_fsm_event(msg); + eigrp_fsm_event(msg, event); + } + } + } + + eigrp_query_send_all(eigrp); + eigrp_update_send_all(eigrp,nbr->ei); + +} + +void +eigrp_update_topology_table_prefix(struct list * table, struct eigrp_prefix_entry * prefix) +{ + struct listnode *node1, *node2; + + struct eigrp_neighbor_entry *entry; + for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry)) + { + if(entry->distance == EIGRP_MAX_METRIC) + { + eigrp_neighbor_entry_delete(prefix,entry); + } + } + if(prefix->distance == EIGRP_MAX_METRIC && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED) + { + eigrp_prefix_entry_delete(table,prefix); + } +} +/*int + eigrp_topology_get_successor_count (struct eigrp_prefix_entry *prefix) + { + + struct listnode *node; + struct eigrp_neighbor_entry *entry; + + int count = 0; + + for (ALL_LIST_ELEMENTS_RO (prefix->entries,node,entry)) + { + if ((entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG) == EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG) + { + count ++; + } + } + + return count; + } + */ diff --git a/eigrpd/eigrp_topology.h b/eigrpd/eigrp_topology.h new file mode 100644 index 000000000..9f1569ea6 --- /dev/null +++ b/eigrpd/eigrp_topology.h @@ -0,0 +1,75 @@ +/* + * EIGRP Topology Table. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * 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. + */ + +#ifndef _ZEBRA_EIGRP_TOPOLOGY_H +#define _ZEBRA_EIGRP_TOPOLOGY_H + + +/* EIGRP Topology table related functions. */ +extern struct list *eigrp_topology_new (void); +extern void eigrp_topology_init (struct list*); +extern struct eigrp_prefix_entry *eigrp_prefix_entry_new (void); +extern struct eigrp_neighbor_entry *eigrp_neighbor_entry_new (void); +extern void eigrp_topology_free (struct list *); +extern void eigrp_topology_cleanup (struct list *); +extern void eigrp_prefix_entry_add (struct list *, struct eigrp_prefix_entry *); +extern void eigrp_neighbor_entry_add (struct eigrp_prefix_entry *, struct eigrp_neighbor_entry *); +extern void eigrp_prefix_entry_delete (struct list *, struct eigrp_prefix_entry *); +extern void eigrp_neighbor_entry_delete (struct eigrp_prefix_entry *, struct eigrp_neighbor_entry *); +extern void eigrp_topology_delete_all (struct list *); +extern unsigned int eigrp_topology_table_isempty (struct list *); +extern struct eigrp_prefix_entry *eigrp_topology_table_lookup_ipv4 (struct list *, struct prefix_ipv4 *); +extern struct list *eigrp_topology_get_successor (struct eigrp_prefix_entry *); +//extern struct eigrp_neighbor_entry *eigrp_topology_get_fsuccessor (struct eigrp_prefix_entry *); +extern struct eigrp_neighbor_entry *eigrp_prefix_entry_lookup (struct list *, struct eigrp_neighbor *); +extern struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *, struct eigrp_neighbor *); +extern void eigrp_topology_update_all_node_flags (struct eigrp *); +extern void eigrp_topology_update_node_flags (struct eigrp_prefix_entry *); +extern int eigrp_topology_update_distance ( struct eigrp_fsm_action_message *); +extern void eigrp_update_routing_table(struct eigrp_prefix_entry *); +extern void eigrp_topology_neighbor_down(struct eigrp *, struct eigrp_neighbor *); +extern void eigrp_update_topology_table_prefix(struct list *, struct eigrp_prefix_entry * ); +//extern int eigrp_topology_get_successor_count (struct eigrp_prefix_entry *); +/* Set all stats to -1 (LSA_SPF_NOT_EXPLORED). */ +/*extern void eigrp_lsdb_clean_stat (struct eigrp_lsdb *lsdb); +extern struct eigrp_lsa *eigrp_lsdb_lookup_by_id (struct eigrp_lsdb *, u_char, + struct in_addr, struct in_addr); +extern struct eigrp_lsa *eigrp_lsdb_lookup_by_id_next (struct eigrp_lsdb *, u_char, + struct in_addr, struct in_addr, + int); +extern unsigned long eigrp_lsdb_count_all (struct eigrp_lsdb *); +extern unsigned long eigrp_lsdb_count (struct eigrp_lsdb *, int); +extern unsigned long eigrp_lsdb_count_self (struct eigrp_lsdb *, int); +extern unsigned int eigrp_lsdb_checksum (struct eigrp_lsdb *, int); +extern unsigned long eigrp_lsdb_isempty (struct eigrp_lsdb *); +*/ +#endif diff --git a/eigrpd/eigrp_update.c b/eigrpd/eigrp_update.c new file mode 100644 index 000000000..358d77c84 --- /dev/null +++ b/eigrpd/eigrp_update.c @@ -0,0 +1,1159 @@ +/* + * EIGRP Sending and Receiving EIGRP Update Packets. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "sockunion.h" +#include "stream.h" +#include "log.h" +#include "sockopt.h" +#include "checksum.h" +#include "md5.h" +#include "vty.h" +#include "plist.h" +#include "plist_int.h" +#include "routemap.h" +#include "vty.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_macros.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_fsm.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_memory.h" + +/** + * @fn remove_received_prefix_gr + * + * @param[in] nbr_prefixes List of neighbor prefixes + * @param[in] recv_prefix Prefix which needs to be removed from list + * + * @return void + * + * @par + * Function is used for removing received prefix + * from list of neighbor prefixes + */ +static void +remove_received_prefix_gr (struct list *nbr_prefixes, struct eigrp_prefix_entry *recv_prefix) +{ + struct listnode *node1, *node11; + struct eigrp_prefix_entry *prefix; + + /* iterate over all prefixes in list */ + for (ALL_LIST_ELEMENTS(nbr_prefixes, node1, node11, prefix)) + { + /* remove prefix from list if found */ + if (prefix == recv_prefix) + { + listnode_delete(nbr_prefixes, prefix); + } + } +} + +/** + * @fn eigrp_update_receive_GR_ask + * + * @param[in] eigrp EIGRP process + * @param[in] nbr Neighbor update of who we received + * @param[in] nbr_prefixes Prefixes which weren't advertised + * + * @return void + * + * @par + * Function is used for notifying FSM about prefixes which + * weren't advertised by neighbor: + * We will send message to FSM with prefix delay set to infinity. + */ +static void +eigrp_update_receive_GR_ask (struct eigrp *eigrp, struct eigrp_neighbor *nbr, struct list *nbr_prefixes) +{ + struct listnode *node1; + struct eigrp_prefix_entry *prefix; + struct TLV_IPv4_Internal_type *tlv_max; + + /* iterate over all prefixes which weren't advertised by neighbor */ + for (ALL_LIST_ELEMENTS_RO(nbr_prefixes, node1, prefix)) + { + zlog_debug("GR receive: Neighbor not advertised %s/%d", + inet_ntoa(prefix->destination_ipv4->prefix), + prefix->destination_ipv4->prefixlen); + + /* create internal IPv4 TLV with infinite delay */ + tlv_max = eigrp_IPv4_InternalTLV_new(); + tlv_max->type = EIGRP_TLV_IPv4_INT; + tlv_max->length = 28U; + tlv_max->metric = prefix->reported_metric; + /* set delay to MAX */ + tlv_max->metric.delay = EIGRP_MAX_METRIC; + tlv_max->destination = prefix->destination_ipv4->prefix; + tlv_max->prefix_length = prefix->destination_ipv4->prefixlen; + + + /* prepare message for FSM */ + struct eigrp_fsm_action_message *fsm_msg; + fsm_msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, + sizeof(struct eigrp_fsm_action_message)); + + struct eigrp_neighbor_entry *entry = + eigrp_prefix_entry_lookup(prefix->entries, nbr); + + fsm_msg->packet_type = EIGRP_OPC_UPDATE; + fsm_msg->eigrp = eigrp; + fsm_msg->data_type = EIGRP_TLV_IPv4_INT; + fsm_msg->adv_router = nbr; + fsm_msg->data.ipv4_int_type = tlv_max; + fsm_msg->entry = entry; + fsm_msg->prefix = prefix; + + /* send message to FSM */ + int event = eigrp_get_fsm_event(fsm_msg); + eigrp_fsm_event(fsm_msg, event); + + /* free memory used by TLV */ + eigrp_IPv4_InternalTLV_free (tlv_max); + } +} + +/* + * EIGRP UPDATE read function + */ +void +eigrp_update_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph, + struct stream * s, struct eigrp_interface *ei, int size) +{ + struct eigrp_neighbor *nbr; + struct TLV_IPv4_Internal_type *tlv; + struct eigrp_prefix_entry *pe; + struct eigrp_neighbor_entry *ne; + u_int32_t flags; + u_int16_t type; + u_char same; + struct access_list *alist; + struct prefix_list *plist; + struct eigrp *e; + u_char graceful_restart; + u_char graceful_restart_final; + struct list *nbr_prefixes; + + /* increment statistics. */ + ei->update_in++; + + /* get neighbor struct */ + nbr = eigrp_nbr_get(ei, eigrph, iph); + + /* neighbor must be valid, eigrp_nbr_get creates if none existed */ + assert(nbr); + + flags = ntohl(eigrph->flags); + + if (flags & EIGRP_CR_FLAG) + { + return; + } + + same = 0; + graceful_restart = 0; + graceful_restart_final = 0; + if((nbr->recv_sequence_number) == (ntohl(eigrph->sequence))) + same = 1; + + nbr->recv_sequence_number = ntohl(eigrph->sequence); + if (IS_DEBUG_EIGRP_PACKET(0, RECV)) + zlog_debug("Processing Update size[%u] int(%s) nbr(%s) seq [%u] flags [%0x]", + size, ifindex2ifname(nbr->ei->ifp->ifindex), + inet_ntoa(nbr->src), + nbr->recv_sequence_number, flags); + + + if((flags == (EIGRP_INIT_FLAG+EIGRP_RS_FLAG+EIGRP_EOT_FLAG)) && (!same)) + { + /* Graceful restart Update received with all routes */ + + zlog_info("Neighbor %s (%s) is resync: peer graceful-restart", + inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex)); + + /* get all prefixes from neighbor from topology table */ + nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr); + graceful_restart = 1; + graceful_restart_final = 1; + } + else if((flags == (EIGRP_INIT_FLAG+EIGRP_RS_FLAG)) && (!same)) + { + /* Graceful restart Update received, routes also in next packet */ + + zlog_info("Neighbor %s (%s) is resync: peer graceful-restart", + inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex)); + + /* get all prefixes from neighbor from topology table */ + nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr); + /* save prefixes to neighbor for later use */ + nbr->nbr_gr_prefixes = nbr_prefixes; + graceful_restart = 1; + graceful_restart_final = 0; + } + else if((flags == (EIGRP_EOT_FLAG)) && (!same)) + { + /* If there was INIT+RS Update packet before, + * consider this as GR EOT */ + + if(nbr->nbr_gr_prefixes != NULL) + { + /* this is final packet of GR */ + nbr_prefixes = nbr->nbr_gr_prefixes; + nbr->nbr_gr_prefixes = NULL; + + graceful_restart = 1; + graceful_restart_final = 1; + } + + } + else if((flags == (0)) && (!same)) + { + /* If there was INIT+RS Update packet before, + * consider this as GR not final packet */ + + if(nbr->nbr_gr_prefixes != NULL) + { + /* this is GR not final route packet */ + nbr_prefixes = nbr->nbr_gr_prefixes; + + graceful_restart = 1; + graceful_restart_final = 0; + } + + } + else if((flags & EIGRP_INIT_FLAG) && (!same)) + { /* When in pending state, send INIT update only if it wasn't + already sent before (only if init_sequence is 0) */ + if((nbr->state == EIGRP_NEIGHBOR_PENDING) && (nbr->init_sequence_number == 0)) + eigrp_update_send_init(nbr); + + if (nbr->state == EIGRP_NEIGHBOR_UP) + { + eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN); + eigrp_topology_neighbor_down(nbr->ei->eigrp,nbr); + nbr->recv_sequence_number = ntohl(eigrph->sequence); + zlog_info("Neighbor %s (%s) is down: peer restarted", + inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex)); + eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING); + zlog_info("Neighbor %s (%s) is pending: new adjacency", + inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex)); + eigrp_update_send_init(nbr); + } + } + + /*If there is topology information*/ + while (s->endp > s->getp) + { + type = stream_getw(s); + if (type == EIGRP_TLV_IPv4_INT) + { + stream_set_getp(s, s->getp - sizeof(u_int16_t)); + + tlv = eigrp_read_ipv4_tlv(s); + + /*searching if destination exists */ + struct prefix_ipv4 *dest_addr; + dest_addr = prefix_ipv4_new(); + dest_addr->prefix = tlv->destination; + dest_addr->prefixlen = tlv->prefix_length; + struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( + eigrp->topology_table, dest_addr); + + /*if exists it comes to DUAL*/ + if (dest != NULL) + { + /* remove received prefix from neighbor prefix list if in GR */ + if(graceful_restart) + remove_received_prefix_gr(nbr_prefixes, dest); + + struct eigrp_fsm_action_message *msg; + msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, + sizeof(struct eigrp_fsm_action_message)); + struct eigrp_neighbor_entry *entry = + eigrp_prefix_entry_lookup(dest->entries, nbr); + + msg->packet_type = EIGRP_OPC_UPDATE; + msg->eigrp = eigrp; + msg->data_type = EIGRP_TLV_IPv4_INT; + msg->adv_router = nbr; + msg->data.ipv4_int_type = tlv; + msg->entry = entry; + msg->prefix = dest; + int event = eigrp_get_fsm_event(msg); + eigrp_fsm_event(msg, event); + } + else + { + /*Here comes topology information save*/ + pe = eigrp_prefix_entry_new(); + pe->serno = eigrp->serno; + pe->destination_ipv4 = dest_addr; + pe->af = AF_INET; + pe->state = EIGRP_FSM_STATE_PASSIVE; + pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE; + + ne = eigrp_neighbor_entry_new(); + ne->ei = ei; + ne->adv_router = nbr; + ne->reported_metric = tlv->metric; + ne->reported_distance = + eigrp_calculate_metrics(eigrp, + &tlv->metric); + /* + * Filtering + */ + e = eigrp_lookup(); + /* + * Check if there is any access-list on interface (IN direction) + * and set distance to max + */ + alist = ei->list[EIGRP_FILTER_IN]; + + if (alist) { + zlog_info ("ALIST PROC IN: %s", alist->name); + } else { + zlog_info("ALIST je prazdny"); + } + + /* Check if access-list fits */ + if (alist && access_list_apply (alist, + (struct prefix *) dest_addr) == FILTER_DENY) + { + /* If yes, set reported metric to Max */ + zlog_info("PROC IN: Nastavujem metriku na MAX"); + ne->reported_metric.delay = EIGRP_MAX_METRIC; + zlog_info("PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix)); + } else { + zlog_info("PROC IN: NENastavujem metriku "); + ne->distance = eigrp_calculate_total_metrics(eigrp, ne); + } + + plist = e->prefix[EIGRP_FILTER_IN]; + + if (plist) { + zlog_info ("PLIST PROC IN: %s", plist->name); + } else { + zlog_info("PLIST PROC IN je prazdny"); + } + + /* Check if prefix-list fits */ + if (plist && prefix_list_apply (plist, + (struct prefix *) dest_addr) == FILTER_DENY) + { + /* If yes, set reported metric to Max */ + zlog_info("PLIST PROC IN: Nastavujem metriku na MAX"); + ne->reported_metric.delay = EIGRP_MAX_METRIC; + zlog_info("PLIST PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix)); + } else { + zlog_info("PLIST PROC IN: NENastavujem metriku "); + } + + /*Get access-list from current interface */ + zlog_info("Checking access_list on interface: %s",ei->ifp->name); + alist = ei->list[EIGRP_FILTER_IN]; + if (alist) { + zlog_info ("ALIST INT IN: %s", alist->name); + } else { + zlog_info("ALIST INT IN je prazdny"); + } + + /* Check if access-list fits */ + if (alist && access_list_apply (alist, (struct prefix *) dest_addr) == FILTER_DENY) + { + /* If yes, set reported metric to Max */ + zlog_info("INT IN: Nastavujem metriku na MAX"); + ne->reported_metric.delay = EIGRP_MAX_METRIC; + zlog_info("INT IN Prefix: %s", inet_ntoa(dest_addr->prefix)); + } else { + zlog_info("INT IN: NENastavujem metriku "); + } + + plist = ei->prefix[EIGRP_FILTER_IN]; + + if (plist) { + zlog_info ("PLIST INT IN: %s", plist->name); + } else { + zlog_info("PLIST INT IN je prazdny"); + } + + /* Check if prefix-list fits */ + if (plist && prefix_list_apply (plist, + (struct prefix *) dest_addr) == FILTER_DENY) + { + /* If yes, set reported metric to Max */ + zlog_info("PLIST INT IN: Nastavujem metriku na MAX"); + ne->reported_metric.delay = EIGRP_MAX_METRIC; + zlog_info("PLIST INT IN Prefix: %s", inet_ntoa(dest_addr->prefix)); + } else { + zlog_info("PLIST INT IN: NENastavujem metriku "); + } + /* + * End of filtering + */ + + ne->distance = eigrp_calculate_total_metrics(eigrp, ne); + + zlog_info("<DEBUG PROC IN Distance: %x", ne->distance); + zlog_info("<DEBUG PROC IN Delay: %x", ne->total_metric.delay); + + pe->fdistance = pe->distance = pe->rdistance = + ne->distance; + ne->prefix = pe; + ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG; + + eigrp_prefix_entry_add(eigrp->topology_table, pe); + eigrp_neighbor_entry_add(pe, ne); + pe->distance = pe->fdistance = pe->rdistance = + ne->distance; + pe->reported_metric = ne->total_metric; + eigrp_topology_update_node_flags(pe); + + pe->req_action |= EIGRP_FSM_NEED_UPDATE; + listnode_add(eigrp->topology_changes_internalIPV4, pe); + } + eigrp_IPv4_InternalTLV_free (tlv); + } + } + + /* ask about prefixes not present in GR update, + * if this is final GR packet */ + if(graceful_restart_final) + { + eigrp_update_receive_GR_ask(eigrp, nbr, nbr_prefixes); + } + + /* + * We don't need to send separate Ack for INIT Update. INIT will be acked in EOT Update. + */ + if ((nbr->state == EIGRP_NEIGHBOR_UP) && !(flags == EIGRP_INIT_FLAG)) + { + eigrp_hello_send_ack(nbr); + } + + eigrp_query_send_all(eigrp); + eigrp_update_send_all(eigrp, ei); +} + +/*send EIGRP Update packet*/ +void +eigrp_update_send_init (struct eigrp_neighbor *nbr) +{ + struct eigrp_packet *ep; + u_int16_t length = EIGRP_HEADER_LEN; + + ep = eigrp_packet_new(nbr->ei->ifp->mtu); + + /* Prepare EIGRP INIT UPDATE header */ + if (IS_DEBUG_EIGRP_PACKET(0, RECV)) + zlog_debug("Enqueuing Update Init Seq [%u] Ack [%u]", + nbr->ei->eigrp->sequence_number, + nbr->recv_sequence_number); + + eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_INIT_FLAG, + nbr->ei->eigrp->sequence_number, + nbr->recv_sequence_number); + + // encode Authentication TLV, if needed + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + { + length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei); + eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_INIT_FLAG); + } + + /* EIGRP Checksum */ + eigrp_packet_checksum(nbr->ei, ep->s, length); + + ep->length = length; + ep->dst.s_addr = nbr->src.s_addr; + + /*This ack number we await from neighbor*/ + nbr->init_sequence_number = nbr->ei->eigrp->sequence_number; + ep->sequence_number = nbr->ei->eigrp->sequence_number; + if (IS_DEBUG_EIGRP_PACKET(0, RECV)) + zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]", + ep->length, ep->sequence_number, inet_ntoa(ep->dst)); + + /*Put packet to retransmission queue*/ + eigrp_fifo_push_head(nbr->retrans_queue, ep); + + if (nbr->retrans_queue->count == 1) + { + eigrp_send_packet_reliably(nbr); + } +} + +void +eigrp_update_send_EOT (struct eigrp_neighbor *nbr) +{ + struct eigrp_packet *ep; +// struct eigrp_packet *ep_multicast; + u_int16_t length = EIGRP_HEADER_LEN; + struct eigrp_neighbor_entry *te; + struct eigrp_prefix_entry *pe; + struct listnode *node, *node2, *nnode, *nnode2; + struct access_list *alist; + struct prefix_list *plist; + struct access_list *alist_i; + struct prefix_list *plist_i; + struct eigrp *e; + struct prefix_ipv4 *dest_addr; + + ep = eigrp_packet_new(nbr->ei->ifp->mtu); + + /* Prepare EIGRP EOT UPDATE header */ + eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG, + nbr->ei->eigrp->sequence_number, + nbr->recv_sequence_number); + + // encode Authentication TLV, if needed + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + { + length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei); + } + + for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe)) + { + for (ALL_LIST_ELEMENTS(pe->entries, node2, nnode2, te)) + { + if ((te->ei == nbr->ei) + && (te->prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE)) + continue; + + /* Get destination address from prefix */ + dest_addr = pe->destination_ipv4; + + /* + * Filtering + */ + //TODO: Work in progress + /* get list from eigrp process */ + e = eigrp_lookup(); + /* Get access-lists and prefix-lists from process and interface */ + alist = e->list[EIGRP_FILTER_OUT]; + plist = e->prefix[EIGRP_FILTER_OUT]; + alist_i = nbr->ei->list[EIGRP_FILTER_OUT]; + plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT]; + + /* Check if any list fits */ + if ((alist && access_list_apply (alist, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (plist && prefix_list_apply (plist, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (alist_i && access_list_apply (alist_i, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (plist_i && prefix_list_apply (plist_i, + (struct prefix *) dest_addr) == FILTER_DENY)) + { + zlog_info("PROC OUT EOT: Skipping"); + //pe->reported_metric.delay = EIGRP_MAX_METRIC; + zlog_info("PROC OUT EOT Prefix: %s", inet_ntoa(dest_addr->prefix)); + continue; + } else { + zlog_info("PROC OUT EOT: NENastavujem metriku "); + length += eigrp_add_internalTLV_to_stream(ep->s, pe); + } + /* + * End of filtering + */ + + /* NULL the pointer */ + dest_addr = NULL; + + } + } + + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + { + eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG); + } + + /* EIGRP Checksum */ + eigrp_packet_checksum(nbr->ei, ep->s, length); + + ep->length = length; + ep->dst.s_addr = nbr->src.s_addr; + + /*This ack number we await from neighbor*/ + ep->sequence_number = nbr->ei->eigrp->sequence_number; + + if (IS_DEBUG_EIGRP_PACKET(0, RECV)) + zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]", + ep->length, ep->sequence_number, inet_ntoa(ep->dst)); + + /*Put packet to retransmission queue*/ + eigrp_fifo_push_head(nbr->retrans_queue, ep); + + if (nbr->retrans_queue->count == 1) + { + eigrp_send_packet_reliably(nbr); + } + +} + +void +eigrp_update_send (struct eigrp_interface *ei) +{ + struct eigrp_packet *ep; + struct listnode *node, *nnode; + struct eigrp_neighbor *nbr; + struct eigrp_prefix_entry *pe; + u_char has_tlv; + struct access_list *alist; + struct prefix_list *plist; + struct access_list *alist_i; + struct prefix_list *plist_i; + struct eigrp *e; + struct prefix_ipv4 *dest_addr; + + u_int16_t length = EIGRP_HEADER_LEN; + + ep = eigrp_packet_new(ei->ifp->mtu); + + /* Prepare EIGRP INIT UPDATE header */ + eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei, ep->s, 0, + ei->eigrp->sequence_number, 0); + + // encode Authentication TLV, if needed + if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL)) + { + length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei); + } + + has_tlv = 0; + for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node, nnode, pe)) + { + if(pe->req_action & EIGRP_FSM_NEED_UPDATE) + { + /* Get destination address from prefix */ + dest_addr = pe->destination_ipv4; + + /* + * Filtering + */ + //TODO: Work in progress + /* get list from eigrp process */ + e = eigrp_lookup(); + /* Get access-lists and prefix-lists from process and interface */ + alist = e->list[EIGRP_FILTER_OUT]; + plist = e->prefix[EIGRP_FILTER_OUT]; + alist_i = ei->list[EIGRP_FILTER_OUT]; + plist_i = ei->prefix[EIGRP_FILTER_OUT]; + + /* Check if any list fits */ + if ((alist && access_list_apply (alist, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (plist && prefix_list_apply (plist, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (alist_i && access_list_apply (alist_i, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (plist_i && prefix_list_apply (plist_i, + (struct prefix *) dest_addr) == FILTER_DENY)) + { + zlog_info("PROC OUT: Skipping"); + //pe->reported_metric.delay = EIGRP_MAX_METRIC; + zlog_info("PROC OUT Prefix: %s", inet_ntoa(dest_addr->prefix)); + continue; + } else { + zlog_info("PROC OUT: NENastavujem metriku "); + length += eigrp_add_internalTLV_to_stream(ep->s, pe); + has_tlv = 1; + } + /* + * End of filtering + */ + + /* NULL the pointer */ + dest_addr = NULL; + + } + } + + if(!has_tlv) + { + eigrp_packet_free(ep); + return; + } + + if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL)) + { + eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_UPDATE_FLAG); + } + + /* EIGRP Checksum */ + eigrp_packet_checksum(ei, ep->s, length); + ep->length = length; + + ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS); + + /*This ack number we await from neighbor*/ + ep->sequence_number = ei->eigrp->sequence_number; + + if (IS_DEBUG_EIGRP_PACKET(0, RECV)) + zlog_debug("Enqueuing Update length[%u] Seq [%u]", + length, ep->sequence_number); + + for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr)) + { + if (nbr->state == EIGRP_NEIGHBOR_UP) + { + /*Put packet to retransmission queue*/ + eigrp_fifo_push_head(nbr->retrans_queue, ep); + + if (nbr->retrans_queue->count == 1) + { + eigrp_send_packet_reliably(nbr); + } + } + } +} + +void +eigrp_update_send_all (struct eigrp *eigrp, struct eigrp_interface *exception) +{ + + struct eigrp_interface *iface; + struct listnode *node, *node2, *nnode2; + struct eigrp_prefix_entry *pe; + + for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface)) + { + if (iface != exception) + { + eigrp_update_send(iface); + } + } + + for (ALL_LIST_ELEMENTS(eigrp->topology_changes_internalIPV4, node2, nnode2, pe)) + { + if(pe->req_action & EIGRP_FSM_NEED_UPDATE) + { + pe->req_action &= ~EIGRP_FSM_NEED_UPDATE; + listnode_delete(eigrp->topology_changes_internalIPV4, pe); + zlog_debug("UPDATE COUNT: %d", eigrp->topology_changes_internalIPV4->count); + } + } +} + +/** + * @fn eigrp_update_send_GR_part + * + * @param[in] nbr contains neighbor who would receive Graceful restart + * + * @return void + * + * @par + * Function used for sending Graceful restart Update packet + * and if there are multiple chunks, send only one of them. + * It is called from thread. Do not call it directly. + * + * Uses nbr_gr_packet_type from neighbor. + */ +static void +eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) +{ + struct eigrp_packet *ep; + u_int16_t length = EIGRP_HEADER_LEN; + struct listnode *node, *nnode; + struct eigrp_prefix_entry *pe; + struct prefix_ipv4 *dest_addr; + struct eigrp *e; + struct access_list *alist, *alist_i; + struct prefix_list *plist, *plist_i; + struct list *prefixes; + u_int32_t flags; + unsigned int send_prefixes; + struct TLV_IPv4_Internal_type *tlv_max; + + /* get prefixes to send to neighbor */ + prefixes = nbr->nbr_gr_prefixes_send; + + send_prefixes = 0; + length = EIGRP_HEADER_LEN; + + /* if there already were last packet chunk, we won't continue */ + if(nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_LAST) + return; + + /* if this is first packet chunk, we need to decide, + * if there will be one or more chunks */ + if(nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_FIRST) + { + if(prefixes->count <= EIGRP_TLV_MAX_IPv4) + { + /* there will be only one chunk */ + flags = EIGRP_INIT_FLAG + EIGRP_RS_FLAG + EIGRP_EOT_FLAG; + nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_LAST; + } + else + { + /* there will be more chunks */ + flags = EIGRP_INIT_FLAG + EIGRP_RS_FLAG; + nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_NA; + } + } + else + { + /* this is not first chunk, and we need to decide, + * if there will be more chunks */ + if(prefixes->count <= EIGRP_TLV_MAX_IPv4) + { + /* this is last chunk */ + flags = EIGRP_EOT_FLAG; + nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_LAST; + } + else + { + /* there will be more chunks */ + flags = 0; + nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_NA; + } + } + + ep = eigrp_packet_new(nbr->ei->ifp->mtu); + + /* Prepare EIGRP Graceful restart UPDATE header */ + eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, + flags, + nbr->ei->eigrp->sequence_number, + nbr->recv_sequence_number); + + // encode Authentication TLV, if needed + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + { + length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei); + } + + for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe)) + { + + /* + * Filtering + */ + dest_addr = pe->destination_ipv4; + /* get list from eigrp process */ + e = eigrp_lookup(); + /* Get access-lists and prefix-lists from process and interface */ + alist = e->list[EIGRP_FILTER_OUT]; + plist = e->prefix[EIGRP_FILTER_OUT]; + alist_i = nbr->ei->list[EIGRP_FILTER_OUT]; + plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT]; + + + /* Check if any list fits */ + if ((alist && access_list_apply (alist, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (plist && prefix_list_apply (plist, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (alist_i && access_list_apply (alist_i, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (plist_i && prefix_list_apply (plist_i, + (struct prefix *) dest_addr) == FILTER_DENY)) + { + /* do not send filtered route */ + zlog_info("Filtered prefix %s won't be sent out.", + inet_ntoa(dest_addr->prefix)); + } + else + { + /* sending route which wasn't filtered */ + length += eigrp_add_internalTLV_to_stream(ep->s, pe); + send_prefixes++; + } + + + + alist = e->list[EIGRP_FILTER_IN]; + plist = e->prefix[EIGRP_FILTER_IN]; + alist_i = nbr->ei->list[EIGRP_FILTER_IN]; + plist_i = nbr->ei->prefix[EIGRP_FILTER_IN]; + + + /* Check if any list fits */ + if ((alist && access_list_apply (alist, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (plist && prefix_list_apply (plist, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (alist_i && access_list_apply (alist_i, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (plist_i && prefix_list_apply (plist_i, + (struct prefix *) dest_addr) == FILTER_DENY)) + { + /* do not send filtered route */ + zlog_info("Filtered prefix %s will be removed.", + inet_ntoa(dest_addr->prefix)); + + tlv_max = eigrp_IPv4_InternalTLV_new(); + tlv_max->type = EIGRP_TLV_IPv4_INT; + tlv_max->length = 28U; + tlv_max->metric = pe->reported_metric; + /* set delay to MAX */ + tlv_max->metric.delay = EIGRP_MAX_METRIC; + tlv_max->destination = pe->destination_ipv4->prefix; + tlv_max->prefix_length = pe->destination_ipv4->prefixlen; + + + /* prepare message for FSM */ + struct eigrp_fsm_action_message *fsm_msg; + fsm_msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, + sizeof(struct eigrp_fsm_action_message)); + + struct eigrp_neighbor_entry *entry = + eigrp_prefix_entry_lookup(pe->entries, nbr); + + fsm_msg->packet_type = EIGRP_OPC_UPDATE; + fsm_msg->eigrp = e; + fsm_msg->data_type = EIGRP_TLV_IPv4_INT; + fsm_msg->adv_router = nbr; + fsm_msg->data.ipv4_int_type = tlv_max; + fsm_msg->entry = entry; + fsm_msg->prefix = pe; + + /* send message to FSM */ + int event = eigrp_get_fsm_event(fsm_msg); + eigrp_fsm_event(fsm_msg, event); + + /* free memory used by TLV */ + eigrp_IPv4_InternalTLV_free (tlv_max); + } + /* + * End of filtering + */ + + /* NULL the pointer */ + dest_addr = NULL; + + /* delete processed prefix from list */ + listnode_delete(prefixes, pe); + + /* if there are enough prefixes, send packet */ + if(send_prefixes >= EIGRP_TLV_MAX_IPv4) + break; + } + + /* compute Auth digest */ + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + { + eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG); + } + + /* EIGRP Checksum */ + eigrp_packet_checksum(nbr->ei, ep->s, length); + + ep->length = length; + ep->dst.s_addr = nbr->src.s_addr; + + /*This ack number we await from neighbor*/ + ep->sequence_number = nbr->ei->eigrp->sequence_number; + + if (IS_DEBUG_EIGRP_PACKET(0, RECV)) + zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]", + ep->length, ep->sequence_number, inet_ntoa(ep->dst)); + + + /*Put packet to retransmission queue*/ + eigrp_fifo_push_head(nbr->retrans_queue, ep); + + if (nbr->retrans_queue->count == 1) + { + eigrp_send_packet_reliably(nbr); + } +} + +/** + * @fn eigrp_update_send_GR_thread + * + * @param[in] thread contains neighbor who would receive Graceful restart + * + * @return int always 0 + * + * @par + * Function used for sending Graceful restart Update packet + * in thread, it is prepared for multiple chunks of packet. + * + * Uses nbr_gr_packet_type and t_nbr_send_gr from neighbor. + */ +int +eigrp_update_send_GR_thread(struct thread *thread) +{ + struct eigrp_neighbor *nbr; + + /* get argument from thread */ + nbr = THREAD_ARG(thread); + /* remove this thread pointer */ + nbr->t_nbr_send_gr = NULL; + + /* if there is packet waiting in queue, + * schedule this thread again with small delay */ + if(nbr->retrans_queue->count > 0) + { + nbr->t_nbr_send_gr = thread_add_timer_msec(master, eigrp_update_send_GR_thread, nbr, 10); + return 0; + } + + /* send GR EIGRP packet chunk */ + eigrp_update_send_GR_part(nbr); + + /* if it wasn't last chunk, schedule this thread again */ + if(nbr->nbr_gr_packet_type != EIGRP_PACKET_PART_LAST) + nbr->t_nbr_send_gr = thread_execute(master, eigrp_update_send_GR_thread, nbr, 0); + + return 0; +} + +/** + * @fn eigrp_update_send_GR + * + * @param[in] nbr Neighbor who would receive Graceful restart + * @param[in] gr_type Who executed Graceful restart + * @param[in] vty Virtual terminal for log output + * + * @return void + * + * @par + * Function used for sending Graceful restart Update packet: + * Creates Update packet with INIT, RS, EOT flags and include + * all route except those filtered + */ +void +eigrp_update_send_GR (struct eigrp_neighbor *nbr, enum GR_type gr_type, struct vty *vty) +{ + struct eigrp_prefix_entry *pe2; + struct listnode *node2, *nnode2; + struct list *prefixes; + + if(gr_type == EIGRP_GR_FILTER) + { + /* function was called after applying filtration */ + zlog_info("Neighbor %s (%s) is resync: route configuration changed", + inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex)); + } + else if(gr_type == EIGRP_GR_MANUAL) + { + /* Graceful restart was called manually */ + zlog_info("Neighbor %s (%s) is resync: manually cleared", + inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex)); + + if(vty != NULL) + { + vty_time_print (vty, 0); + vty_out (vty, "Neighbor %s (%s) is resync: manually cleared%s", + inet_ntoa (nbr->src), + ifindex2ifname (nbr->ei->ifp->ifindex), + VTY_NEWLINE); + } + } + + prefixes = list_new(); + /* add all prefixes from topology table to list */ + for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node2, nnode2, pe2)) + { + listnode_add(prefixes, pe2); + } + + /* save prefixes to neighbor */ + nbr->nbr_gr_prefixes_send = prefixes; + /* indicate, that this is first GR Update packet chunk */ + nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_FIRST; + /* execute packet sending in thread */ + nbr->t_nbr_send_gr = thread_execute(master, eigrp_update_send_GR_thread, nbr, 0); +} + +/** + * @fn eigrp_update_send_interface_GR + * + * @param[in] ei Interface to neighbors of which the GR is sent + * @param[in] gr_type Who executed Graceful restart + * @param[in] vty Virtual terminal for log output + * + * @return void + * + * @par + * Function used for sending Graceful restart Update packet + * to all neighbors on specified interface. + */ +void +eigrp_update_send_interface_GR (struct eigrp_interface *ei, enum GR_type gr_type, struct vty *vty) +{ + struct listnode *node; + struct eigrp_neighbor *nbr; + + /* iterate over all neighbors on eigrp interface */ + for (ALL_LIST_ELEMENTS_RO(ei->nbrs, node, nbr)) + { + /* send GR to neighbor */ + eigrp_update_send_GR(nbr, gr_type, vty); + } +} + +/** + * @fn eigrp_update_send_process_GR + * + * @param[in] eigrp EIGRP process + * @param[in] gr_type Who executed Graceful restart + * @param[in] vty Virtual terminal for log output + * + * @return void + * + * @par + * Function used for sending Graceful restart Update packet + * to all neighbors in eigrp process. + */ +void +eigrp_update_send_process_GR (struct eigrp *eigrp, enum GR_type gr_type, struct vty *vty) +{ + struct listnode *node; + struct eigrp_interface *ei; + + /* iterate over all eigrp interfaces */ + for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei)) + { + /* send GR to all neighbors on interface */ + eigrp_update_send_interface_GR(ei, gr_type, vty); + } +} + + diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c new file mode 100644 index 000000000..9208b8301 --- /dev/null +++ b/eigrpd/eigrp_vty.c @@ -0,0 +1,1584 @@ +/* + * EIGRP VTY Interface. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "memory.h" +#include "thread.h" +#include "prefix.h" +#include "table.h" +#include "vty.h" +#include "command.h" +#include "plist.h" +#include "log.h" +#include "zclient.h" +#include "keychain.h" +#include "linklist.h" +#include "distribute.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_const.h" + + +static int +config_write_network (struct vty *vty, struct eigrp *eigrp) +{ + struct route_node *rn; + + /* `network area' print. */ + for (rn = route_top (eigrp->networks); rn; rn = route_next (rn)) + if (rn->info) + { + /* Network print. */ + vty_out (vty, " network %s/%d %s", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, VTY_NEWLINE); + } + + if (eigrp->max_paths != EIGRP_MAX_PATHS_DEFAULT) + vty_out (vty, " maximum-paths %d%s", eigrp->max_paths, VTY_NEWLINE); + + if (eigrp->variance != EIGRP_VARIANCE_DEFAULT) + vty_out (vty, " variance %d%s", eigrp->variance, VTY_NEWLINE); + + /*Separate EIGRP configuration from the rest of the config*/ + vty_out (vty, "!%s", VTY_NEWLINE); + + return 0; +} + +static int +config_write_interfaces (struct vty *vty, struct eigrp *eigrp) +{ + struct eigrp_interface *ei; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei)) + { + vty_out (vty, "interface %s%s", ei->ifp->name, VTY_NEWLINE); + + if ((IF_DEF_PARAMS (ei->ifp)->auth_type) == EIGRP_AUTH_TYPE_MD5) + { + vty_out (vty, " ip authentication mode eigrp %d md5%s", eigrp->AS, VTY_NEWLINE); + } + + if ((IF_DEF_PARAMS (ei->ifp)->auth_type) == EIGRP_AUTH_TYPE_SHA256) + { + vty_out (vty, " ip authentication mode eigrp %d hmac-sha-256%s", eigrp->AS, VTY_NEWLINE); + } + + if(IF_DEF_PARAMS (ei->ifp)->auth_keychain) + { + vty_out (vty, " ip authentication key-chain eigrp %d %s%s",eigrp->AS,IF_DEF_PARAMS (ei->ifp)->auth_keychain, VTY_NEWLINE); + } + + if ((IF_DEF_PARAMS (ei->ifp)->v_hello) != EIGRP_HELLO_INTERVAL_DEFAULT) + { + vty_out (vty, " ip hello-interval eigrp %d%s", IF_DEF_PARAMS (ei->ifp)->v_hello, VTY_NEWLINE); + } + + if ((IF_DEF_PARAMS (ei->ifp)->v_wait) != EIGRP_HOLD_INTERVAL_DEFAULT) + { + vty_out (vty, " ip hold-time eigrp %d%s", IF_DEF_PARAMS (ei->ifp)->v_wait, VTY_NEWLINE); + } + + /*Separate this EIGRP interface configuration from the others*/ + vty_out (vty, "!%s", VTY_NEWLINE); + } + + return 0; +} + +static int +eigrp_write_interface (struct vty *vty) +{ + int write=0; + + return write; +} + +/** + * Writes distribute lists to config + */ +static int +config_write_eigrp_distribute (struct vty *vty, struct eigrp *eigrp) +{ + int write=0; + + /* Distribute configuration. */ + write += config_write_distribute (vty); + + return write; +} + +/** + * Writes 'router eigrp' section to config + */ +static int +config_write_eigrp_router (struct vty *vty, struct eigrp *eigrp) +{ + int write=0; + + /* `router eigrp' print. */ + vty_out (vty, "router eigrp %d%s", eigrp->AS, VTY_NEWLINE); + + write++; + + if (!eigrp->networks) + return write; + + /* Router ID print. */ + if (eigrp->router_id_static != 0) + { + struct in_addr router_id_static; + router_id_static.s_addr = htonl(eigrp->router_id_static); + vty_out (vty, " eigrp router-id %s%s", + inet_ntoa (router_id_static), VTY_NEWLINE); + } + + /* Network area print. */ + config_write_network (vty, eigrp); + + /* Distribute-list and default-information print. */ + config_write_eigrp_distribute (vty, eigrp); + + /*Separate EIGRP configuration from the rest of the config*/ + vty_out (vty, "!%s", VTY_NEWLINE); + + return write; +} + +DEFUN (router_eigrp, + router_eigrp_cmd, + "router eigrp (1-65535)", + "Enable a routing process\n" + "Start EIGRP configuration\n" + "AS Number to use\n") +{ + struct eigrp *eigrp = eigrp_get (argv[2]->arg); + VTY_PUSH_CONTEXT(EIGRP_NODE, eigrp); + + return CMD_SUCCESS; +} + + +DEFUN (no_router_eigrp, + no_router_eigrp_cmd, + "no router eigrp (1-65535)", + NO_STR + "Routing process\n" + "EIGRP configuration\n" + "AS number to use\n") +{ + vty->node = CONFIG_NODE; + + /*TODO: */ + + return CMD_SUCCESS; +} + +DEFUN (eigrp_router_id, + eigrp_router_id_cmd, + "eigrp router-id A.B.C.D", + "EIGRP specific commands\n" + "Router ID for this EIGRP process\n" + "EIGRP Router-ID in IP address format\n") +{ + //struct eigrp *eigrp = vty->index; + /*TODO: */ + + return CMD_SUCCESS; +} + +DEFUN (no_eigrp_router_id, + no_eigrp_router_id_cmd, + "no eigrp router-id A.B.C.D", + NO_STR + "EIGRP specific commands\n" + "Router ID for this EIGRP process\n" + "EIGRP Router-ID in IP address format\n") +{ + //struct eigrp *eigrp = vty->index; + /*TODO: */ + + return CMD_SUCCESS; +} + +DEFUN (eigrp_passive_interface, + eigrp_passive_interface_cmd, + "passive-interface <" INT_TYPES_CMD_STR ">", + "Suppress routing updates on an interface\n" + INT_TYPES_DESC) +{ + //struct eigrp *eigrp = vty->index; + /*TODO: */ + + return CMD_SUCCESS; +} + +DEFUN (no_eigrp_passive_interface, + no_eigrp_passive_interface_cmd, + "no passive-interface <" INT_TYPES_CMD_STR ">", + NO_STR + "Suppress routing updates on an interface\n" + INT_TYPES_DESC) +{ + //struct eigrp *eigrp = vty->index; + /*TODO: */ + + return CMD_SUCCESS; +} + +DEFUN (eigrp_timers_active, + eigrp_timers_active_cmd, + "timers active-time <(1-65535)|disabled>", + "Adjust routing timers\n" + "Time limit for active state\n" + "Active state time limit in minutes\n" + "Disable time limit for active state\n") +{ + //struct eigrp *eigrp = vty->index; + /*TODO: */ + + return CMD_SUCCESS; +} + +DEFUN (no_eigrp_timers_active, + no_eigrp_timers_active_cmd, + "no timers active-time <(1-65535)|disabled>", + NO_STR + "Adjust routing timers\n" + "Time limit for active state\n" + "Active state time limit in minutes\n" + "Disable time limit for active state\n") +{ + //struct eigrp *eigrp = vty->index; + /*TODO: */ + + return CMD_SUCCESS; +} + + +DEFUN (eigrp_metric_weights, + eigrp_metric_weights_cmd, + "metric weights (0-255) (0-255) (0-255) (0-255) (0-255) ", + "Modify metrics and parameters for advertisement\n" + "Modify metric coefficients\n" + "K1\n" + "K2\n" + "K3\n" + "K4\n" + "K5\n") +{ + //struct eigrp *eigrp = vty->index; + /*TODO: */ + + return CMD_SUCCESS; +} + +DEFUN (no_eigrp_metric_weights, + no_eigrp_metric_weights_cmd, + "no metric weights <0-255> <0-255> <0-255> <0-255> <0-255>", + NO_STR + "Modify metrics and parameters for advertisement\n" + "Modify metric coefficients\n" + "K1\n" + "K2\n" + "K3\n" + "K4\n" + "K5\n") +{ + //struct eigrp *eigrp = vty->index; + /*TODO: */ + + return CMD_SUCCESS; +} + + +DEFUN (eigrp_network, + eigrp_network_cmd, + "network A.B.C.D/M", + "Enable routing on an IP network\n" + "EIGRP network prefix\n") +{ + VTY_DECLVAR_CONTEXT(eigrp, eigrp) + struct prefix_ipv4 p; + int ret; + + VTY_GET_IPV4_PREFIX ("network prefix", p, argv[1]->arg); + + ret = eigrp_network_set (eigrp, &p); + + if (ret == 0) + { + vty_out (vty, "There is already same network statement.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_eigrp_network, + no_eigrp_network_cmd, + "no network A.B.C.D/M", + NO_STR + "Disable routing on an IP network\n" + "EIGRP network prefix\n") +{ + VTY_DECLVAR_CONTEXT(eigrp, eigrp); + struct prefix_ipv4 p; + int ret; + + VTY_GET_IPV4_PREFIX ("network prefix", p, argv[2]->arg); + + ret = eigrp_network_unset (eigrp, &p); + + if (ret == 0) + { + vty_out (vty,"Can't find specified network configuration.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (eigrp_neighbor, + eigrp_neighbor_cmd, + "neighbor A.B.C.D <" INT_TYPES_CMD_STR ">", + "Specify a neighbor router\n" + "Neighbor address\n" + INT_TYPES_DESC) +{ + //struct eigrp *eigrp = vty->index; + + return CMD_SUCCESS; +} + +DEFUN (no_eigrp_neighbor, + no_eigrp_neighbor_cmd, + "no neighbor A.B.C.D <" INT_TYPES_CMD_STR ">", + NO_STR + "Specify a neighbor router\n" + "Neighbor address\n" + INT_TYPES_DESC) +{ + //struct eigrp *eigrp = vty->index; + + return CMD_SUCCESS; +} + +DEFUN (show_ip_eigrp_topology, + show_ip_eigrp_topology_cmd, + "show ip eigrp topology", + SHOW_STR + IP_STR + "IP-EIGRP show commands\n" + "IP-EIGRP topology\n") +{ + struct eigrp *eigrp; + struct listnode *node, *nnode, *node2, *nnode2; + struct eigrp_prefix_entry *tn; + struct eigrp_neighbor_entry *te; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + show_ip_eigrp_topology_header (vty, eigrp); + + for (ALL_LIST_ELEMENTS (eigrp->topology_table, node, nnode, tn)) + { + show_ip_eigrp_prefix_entry (vty,tn); + for (ALL_LIST_ELEMENTS (tn->entries, node2, nnode2, te)) + { + if (((te->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG) == EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)|| + ((te->flags & EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG) == EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG)) + show_ip_eigrp_neighbor_entry (vty, eigrp, te); + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_ip_eigrp_topology_all_links, + show_ip_eigrp_topology_all_links_cmd, + "show ip eigrp topology all-links", + SHOW_STR + IP_STR + "IP-EIGRP show commands\n" + "IP-EIGRP topology\n" + "Show all links in topology table\n") +{ + struct eigrp *eigrp; + struct listnode *node, *nnode, *node2, *nnode2; + struct eigrp_prefix_entry *tn; + struct eigrp_neighbor_entry *te; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + show_ip_eigrp_topology_header (vty, eigrp); + + for (ALL_LIST_ELEMENTS (eigrp->topology_table, node, nnode, tn)) + { + show_ip_eigrp_prefix_entry (vty,tn); + for (ALL_LIST_ELEMENTS (tn->entries, node2, nnode2, te)) + { + show_ip_eigrp_neighbor_entry (vty, eigrp, te); + } + } + + return CMD_SUCCESS; +} + +ALIAS (show_ip_eigrp_topology, + show_ip_eigrp_topology_detail_cmd, + "show ip eigrp topology <A.B.C.D|A.B.C.D/M|detail|summary>", + SHOW_STR + IP_STR + "IP-EIGRP show commands\n" + "IP-EIGRP topology\n" + "Netwok to display information about\n" + "IP prefix <network>/<length>, e.g., 192.168.0.0/16\n" + "Show all links in topology table\n" + "Show a summary of the topology table\n") + +DEFUN (show_ip_eigrp_interfaces, + show_ip_eigrp_interfaces_cmd, + "show ip eigrp interfaces", + SHOW_STR + IP_STR + "IP-EIGRP show commands\n" + "IP-EIGRP interfaces\n") +{ + struct eigrp_interface *ei; + struct eigrp *eigrp; + struct listnode *node; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + if (!argc) + { + show_ip_eigrp_interface_header (vty, eigrp); + } + + int idx = 0; + for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei)) + { + if (argv_find (argv, argc, "detail", &idx)) + { + show_ip_eigrp_interface_header (vty, eigrp); + } + + // if ((strncmp (argv[1], "f", 1) == 0 && strncmp (eigrp_if_name_string (ei), "F",1) == 0) || + // (strncmp (argv[1], "l", 1) == 0 && strncmp (eigrp_if_name_string (ei), "L",1) == 0) || + // (strncmp (argv[1], "s", 1) == 0 && strncmp (eigrp_if_name_string (ei), "S",1) == 0)) + // { + show_ip_eigrp_interface_sub (vty, eigrp, ei); + //} + idx = 0; + if (argv_find (argv, argc, "detail", &idx)) + { + show_ip_eigrp_interface_detail (vty, eigrp, ei); + } + } + + return CMD_SUCCESS; +} + +ALIAS (show_ip_eigrp_interfaces, + show_ip_eigrp_interfaces_detail_cmd, + "show ip eigrp interfaces <" INT_TYPES_CMD_STR ">", + SHOW_STR + IP_STR + "IP-EIGRP show commands\n" + "IP-EIGRP interfaces\n" + INT_TYPES_DESC) + +DEFUN (show_ip_eigrp_neighbors, + show_ip_eigrp_neighbors_cmd, + "show ip eigrp neighbors", + SHOW_STR + IP_STR + "IP-EIGRP show commands\n" + "IP-EIGRP neighbors\n") +{ + struct eigrp *eigrp; + struct eigrp_interface *ei; + struct listnode *node, *node2, *nnode2; + struct eigrp_neighbor *nbr; + int detail = FALSE; + int idx = 0; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + detail = (argv_find(argv, argc, "detail", &idx)); + show_ip_eigrp_neighbor_header (vty, eigrp); + + for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei)) + { + for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr)) + { + if (detail || (nbr->state == EIGRP_NEIGHBOR_UP)) + show_ip_eigrp_neighbor_sub (vty, nbr, detail); + } + } + + return CMD_SUCCESS; +} + +ALIAS (show_ip_eigrp_neighbors, + show_ip_eigrp_neighbors_detail_cmd, + "show ip eigrp neighbors <" INT_TYPES_CMD_STR ">", + SHOW_STR + IP_STR + "IP-EIGRP show commands\n" + "IP-EIGRP neighbors\n" + INT_TYPES_DESC) + +DEFUN (eigrp_if_delay, + eigrp_if_delay_cmd, + "delay (1-16777215)", + "Specify interface throughput delay\n" + "Throughput delay (tens of microseconds)\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct eigrp *eigrp; + u_int32_t delay; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + + return CMD_SUCCESS; + } + + delay = atoi (argv[1]->arg); + + IF_DEF_PARAMS (ifp)->delay = delay; + + return CMD_SUCCESS; +} + +DEFUN (no_eigrp_if_delay, + no_eigrp_if_delay_cmd, + "no delay (1-16777215)", + NO_STR + "Specify interface throughput delay\n" + "Throughput delay (tens of microseconds)\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + + return CMD_SUCCESS; + } + + IF_DEF_PARAMS (ifp)->delay = EIGRP_DELAY_DEFAULT; + + return CMD_SUCCESS; +} + +DEFUN (eigrp_if_bandwidth, + eigrp_if_bandwidth_cmd, + "bandwidth (1-10000000)", + "Set bandwidth informational parameter\n" + "Bandwidth in kilobits\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + u_int32_t bandwidth; + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + bandwidth = atoi (argv[1]->arg); + + IF_DEF_PARAMS (ifp)->bandwidth = bandwidth; + + return CMD_SUCCESS; +} + +DEFUN (no_eigrp_if_bandwidth, + no_eigrp_if_bandwidth_cmd, + "bandwidth (1-10000000)", + "Set bandwidth informational parameter\n" + "Bandwidth in kilobits\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + u_int32_t bandwidth; + struct eigrp *eigrp; + struct eigrp_interface *ei; + struct listnode *node, *nnode, *node2, *nnode2; + struct eigrp_prefix_entry *pe; + struct eigrp_neighbor_entry *ne; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + bandwidth = atoi (argv[1]->arg); + + IF_DEF_PARAMS (ifp)->bandwidth = bandwidth; + + for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei)) + { + if (ei->ifp == ifp) + break; + } + + for (ALL_LIST_ELEMENTS (eigrp->topology_table, node, nnode, pe)) + { + for (ALL_LIST_ELEMENTS (pe->entries, node2, nnode2, ne)) + { + if (ne->ei == ei) + break; + /*TODO: */ + } + } + + return CMD_SUCCESS; +} + +DEFUN (eigrp_if_ip_hellointerval, + eigrp_if_ip_hellointerval_cmd, + "ip hello-interval eigrp (1-65535)", + "Interface Internet Protocol config commands\n" + "Configures EIGRP hello interval\n" + "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" + "Seconds between hello transmissions\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + u_int32_t hello; + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + hello = atoi (argv[3]->arg); + + IF_DEF_PARAMS (ifp)->v_hello = hello; + + return CMD_SUCCESS; +} + +DEFUN (no_eigrp_if_ip_hellointerval, + no_eigrp_if_ip_hellointerval_cmd, + "no ip hello-interval eigrp (1-65535)", + NO_STR + "Interface Internet Protocol config commands\n" + "Configures EIGRP hello interval\n" + "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" + "Seconds between hello transmissions\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + IF_DEF_PARAMS (ifp)->v_hello = EIGRP_HELLO_INTERVAL_DEFAULT; + + return CMD_SUCCESS; +} + + + +DEFUN (eigrp_if_ip_holdinterval, + eigrp_if_ip_holdinterval_cmd, + "ip hold-time eigrp (1-65535)", + "Interface Internet Protocol config commands\n" + "Configures EIGRP hello interval\n" + "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" + "Seconds before neighbor is considered down\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + u_int32_t hold; + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + hold = atoi (argv[3]->arg); + + IF_DEF_PARAMS (ifp)->v_wait = hold; + + return CMD_SUCCESS; +} + +DEFUN (eigrp_ip_summary_address, + eigrp_ip_summary_address_cmd, + "ip summary-address eigrp (1-65535) A.B.C.D/M", + "Interface Internet Protocol config commands\n" + "Perform address summarization\n" + "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" + "AS number\n" + "Summary <network>/<length>, e.g. 192.168.0.0/16\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + u_int32_t AS; + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + AS = atoi (argv[3]->arg); + + /*TODO: */ + + return CMD_SUCCESS; +} + +DEFUN (no_eigrp_ip_summary_address, + no_eigrp_ip_summary_address_cmd, + "no ip summary-address eigrp (1-65535) A.B.C.D/M", + NO_STR + "Interface Internet Protocol config commands\n" + "Perform address summarization\n" + "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" + "AS number\n" + "Summary <network>/<length>, e.g. 192.168.0.0/16\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + u_int32_t AS; + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + AS = atoi (argv[4]->arg); + + /*TODO: */ + + return CMD_SUCCESS; +} + + + +DEFUN (no_eigrp_if_ip_holdinterval, + no_eigrp_if_ip_holdinterval_cmd, + "no ip hold-time eigrp", + "No" + "Interface Internet Protocol config commands\n" + "Configures EIGRP hello interval\n" + "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" + "Seconds before neighbor is considered down\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + IF_DEF_PARAMS (ifp)->v_wait = EIGRP_HOLD_INTERVAL_DEFAULT; + + return CMD_SUCCESS; +} + +static int +str2auth_type (const char *str, struct interface *ifp) +{ + /* Sanity check. */ + if (str == NULL) + return CMD_WARNING; + + if(strncmp(str, "md5",3) == 0) + { + IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_MD5; + return CMD_SUCCESS; + } + else if(strncmp(str, "hmac-sha-256",12) == 0) + { + IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_SHA256; + return CMD_SUCCESS; + } + + return CMD_WARNING; + +} + +DEFUN (eigrp_authentication_mode, + eigrp_authentication_mode_cmd, + "ip authentication mode eigrp (1-65535) <md5|hmac-sha-256>", + "Interface Internet Protocol config commands\n" + "Authentication subcommands\n" + "Mode\n" + "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" + "Autonomous system number\n" + "Keyed message digest\n" + "HMAC SHA256 algorithm \n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + +// if(strncmp(argv[2], "md5",3)) +// IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_MD5; +// else if(strncmp(argv[2], "hmac-sha-256",12)) +// IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_SHA256; + + return str2auth_type(argv[5]->arg, ifp); +} + +DEFUN (no_eigrp_authentication_mode, + no_eigrp_authentication_mode_cmd, + "no ip authentication mode eigrp (1-65535) <md5|hmac-sha-256>", + "Disable\n" + "Interface Internet Protocol config commands\n" + "Authentication subcommands\n" + "Mode\n" + "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" + "Autonomous system number\n" + "Keyed message digest\n" + "HMAC SHA256 algorithm \n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_NONE; + + return CMD_SUCCESS; +} + +DEFUN (eigrp_authentication_keychain, + eigrp_authentication_keychain_cmd, + "ip authentication key-chain eigrp (1-65535) WORD", + "Interface Internet Protocol config commands\n" + "Authentication subcommands\n" + "Key-chain\n" + "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" + "Autonomous system number\n" + "Name of key-chain\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct eigrp *eigrp; + struct keychain *keychain; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + keychain = keychain_lookup (argv[4]->arg); + if(keychain != NULL) + { + if(IF_DEF_PARAMS (ifp)->auth_keychain) + { + free (IF_DEF_PARAMS (ifp)->auth_keychain); + IF_DEF_PARAMS (ifp)->auth_keychain = strdup(keychain->name); + } + else + IF_DEF_PARAMS (ifp)->auth_keychain = strdup(keychain->name); + } + else + vty_out(vty,"Key chain with specified name not found%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN (no_eigrp_authentication_keychain, + no_eigrp_authentication_keychain_cmd, + "no ip authentication key-chain eigrp (1-65535) WORD", + "Disable\n" + "Interface Internet Protocol config commands\n" + "Authentication subcommands\n" + "Key-chain\n" + "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" + "Autonomous system number\n" + "Name of key-chain\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + if((IF_DEF_PARAMS (ifp)->auth_keychain != NULL) && (strcmp(IF_DEF_PARAMS (ifp)->auth_keychain,argv[5]->arg)==0)) + { + free (IF_DEF_PARAMS (ifp)->auth_keychain); + IF_DEF_PARAMS (ifp)->auth_keychain = NULL; + } + else + vty_out(vty,"Key chain with specified name not configured on interface%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + + +DEFUN (eigrp_redistribute_source_metric, + eigrp_redistribute_source_metric_cmd, + "redistribute " FRR_REDIST_STR_EIGRPD + " metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)", + REDIST_STR + FRR_REDIST_HELP_STR_EIGRPD + "Metric for redistributed routes\n" + "Bandwidth metric in Kbits per second\n" + "EIGRP delay metric, in 10 microsecond units\n" + "EIGRP reliability metric where 255 is 100% reliable2 ?\n" + "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n" + "EIGRP MTU of the path\n") +{ + VTY_DECLVAR_CONTEXT(eigrp, eigrp); + struct eigrp_metrics metrics_from_command = { 0 }; + int source; + int idx = 0; + + /* Get distribute source. */ + argv_find (argv, argc, "redistribute", &idx); + source = proto_redistnum(AFI_IP, argv[idx+1]->arg); + if (source < 0 ) + return CMD_WARNING; + + /* Get metrics values */ + + return eigrp_redistribute_set (eigrp, source, metrics_from_command); +} + + +DEFUN (no_eigrp_redistribute_source_metric, + no_eigrp_redistribute_source_metric_cmd, + "no redistribute " FRR_REDIST_STR_EIGRPD + " metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)", + "Disable\n" + REDIST_STR + FRR_REDIST_HELP_STR_EIGRPD + "Metric for redistributed routes\n" + "Bandwidth metric in Kbits per second\n" + "EIGRP delay metric, in 10 microsecond units\n" + "EIGRP reliability metric where 255 is 100% reliable2 ?\n" + "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n" + "EIGRP MTU of the path\n") +{ + VTY_DECLVAR_CONTEXT(eigrp, eigrp); + int source; + int idx = 0; + + /* Get distribute source. */ + argv_find (argv, argc, "redistribute", &idx); + source = proto_redistnum(AFI_IP, argv[idx+1]->arg); + if (source < 0 ) + return CMD_WARNING; + + /* Get metrics values */ + + return eigrp_redistribute_unset (eigrp, source); +} + +DEFUN (eigrp_variance, + eigrp_variance_cmd, + "variance (1-128)", + "Control load balancing variance\n" + "Metric variance multiplier\n") +{ + struct eigrp *eigrp; + u_char variance; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + variance = atoi(argv[1]->arg); + + eigrp->variance = variance; + + /*TODO: */ + + return CMD_SUCCESS; +} + + +DEFUN (no_eigrp_variance, + no_eigrp_variance_cmd, + "no variance (1-128)", + "Disable\n" + "Control load balancing variance\n" + "Metric variance multiplier\n") +{ + struct eigrp *eigrp; + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + eigrp->variance = EIGRP_VARIANCE_DEFAULT; + + /*TODO: */ + + return CMD_SUCCESS; +} + +DEFUN (eigrp_maximum_paths, + eigrp_maximum_paths_cmd, + "maximum-paths (1-32)", + "Forward packets over multiple paths\n" + "Number of paths\n") +{ + struct eigrp *eigrp; + u_char max; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + max = atoi(argv[1]->arg); + + eigrp->max_paths = max; + + /*TODO: */ + + return CMD_SUCCESS; +} + + +DEFUN (no_eigrp_maximum_paths, + no_eigrp_maximum_paths_cmd, + "no maximum-paths <1-32>", + NO_STR + "Forward packets over multiple paths\n" + "Number of paths\n") +{ + struct eigrp *eigrp; + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + eigrp->max_paths = EIGRP_MAX_PATHS_DEFAULT; + + /*TODO: */ + + return CMD_SUCCESS; +} + +/* + * Execute hard restart for all neighbors + */ +DEFUN (clear_ip_eigrp_neighbors, + clear_ip_eigrp_neighbors_cmd, + "clear ip eigrp neighbors", + CLEAR_STR + IP_STR + "Clear IP-EIGRP\n" + "Clear IP-EIGRP neighbors\n") +{ + struct eigrp *eigrp; + struct eigrp_interface *ei; + struct listnode *node, *node2, *nnode2; + struct eigrp_neighbor *nbr; + + /* Check if eigrp process is enabled */ + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* iterate over all eigrp interfaces */ + for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei)) + { + /* send Goodbye Hello */ + eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL); + + /* iterate over all neighbors on eigrp interface */ + for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr)) + { + if (nbr->state != EIGRP_NEIGHBOR_DOWN) + { + zlog_debug ("Neighbor %s (%s) is down: manually cleared", + inet_ntoa (nbr->src), + ifindex2ifname (nbr->ei->ifp->ifindex)); + vty_time_print (vty, 0); + vty_out (vty, "Neighbor %s (%s) is down: manually cleared%s", + inet_ntoa (nbr->src), + ifindex2ifname (nbr->ei->ifp->ifindex), + VTY_NEWLINE); + + /* set neighbor to DOWN */ + nbr->state = EIGRP_NEIGHBOR_DOWN; + /* delete neighbor */ + eigrp_nbr_delete (nbr); + } + } + } + + return CMD_SUCCESS; +} + +/* + * Execute hard restart for all neighbors on interface + */ +DEFUN (clear_ip_eigrp_neighbors_int, + clear_ip_eigrp_neighbors_int_cmd, + "clear ip eigrp neighbors IFNAME", + CLEAR_STR + IP_STR + "Clear IP-EIGRP\n" + "Clear IP-EIGRP neighbors\n" + "Interface's name\n") +{ + struct eigrp *eigrp; + struct eigrp_interface *ei; + struct listnode *node2, *nnode2; + struct eigrp_neighbor *nbr; + int idx = 0; + + /* Check if eigrp process is enabled */ + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* lookup interface by specified name */ + argv_find(argv, argc, "IFNAME", &idx); + ei = eigrp_if_lookup_by_name(eigrp, argv[idx]->arg); + if(ei == NULL) + { + vty_out (vty, " Interface (%s) doesn't exist%s", argv[idx]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + + /* send Goodbye Hello */ + eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL); + + /* iterate over all neighbors on eigrp interface */ + for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr)) + { + if (nbr->state != EIGRP_NEIGHBOR_DOWN) + { + zlog_debug ("Neighbor %s (%s) is down: manually cleared", + inet_ntoa (nbr->src), + ifindex2ifname (nbr->ei->ifp->ifindex)); + vty_time_print (vty, 0); + vty_out (vty, "Neighbor %s (%s) is down: manually cleared%s", + inet_ntoa (nbr->src), + ifindex2ifname (nbr->ei->ifp->ifindex), + VTY_NEWLINE); + + /* set neighbor to DOWN */ + nbr->state = EIGRP_NEIGHBOR_DOWN; + /* delete neighbor */ + eigrp_nbr_delete (nbr); + } + } + + return CMD_SUCCESS; +} + +/* + * Execute hard restart for neighbor specified by IP + */ +DEFUN (clear_ip_eigrp_neighbors_IP, + clear_ip_eigrp_neighbors_IP_cmd, + "clear ip eigrp neighbors A.B.C.D", + CLEAR_STR + IP_STR + "Clear IP-EIGRP\n" + "Clear IP-EIGRP neighbors\n" + "IP-EIGRP neighbor address\n") +{ + struct eigrp *eigrp; + struct eigrp_neighbor *nbr; + struct in_addr nbr_addr; + + VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[4]->arg); + + /* Check if eigrp process is enabled */ + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* lookup neighbor in whole process */ + nbr = eigrp_nbr_lookup_by_addr_process(eigrp, nbr_addr); + + /* if neighbor doesn't exists, notify user and exit */ + if(nbr == NULL) + { + vty_out (vty, "Neighbor with entered address doesn't exists.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* execute hard reset on neighbor */ + eigrp_nbr_hard_restart(nbr, vty); + + return CMD_SUCCESS; +} + +/* + * Execute graceful restart for all neighbors + */ +DEFUN (clear_ip_eigrp_neighbors_soft, + clear_ip_eigrp_neighbors_soft_cmd, + "clear ip eigrp neighbors soft", + CLEAR_STR + IP_STR + "Clear IP-EIGRP\n" + "Clear IP-EIGRP neighbors\n" + "Resync with peers without adjacency reset\n") +{ + struct eigrp *eigrp; + + /* Check if eigrp process is enabled */ + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* execute graceful restart on all neighbors */ + eigrp_update_send_process_GR(eigrp, EIGRP_GR_MANUAL, vty); + + return CMD_SUCCESS; +} + +/* + * Execute graceful restart for all neighbors on interface + */ +DEFUN (clear_ip_eigrp_neighbors_int_soft, + clear_ip_eigrp_neighbors_int_soft_cmd, + "clear ip eigrp neighbors IFNAME soft", + CLEAR_STR + IP_STR + "Clear IP-EIGRP\n" + "Clear IP-EIGRP neighbors\n" + "Interface's name\n" + "Resync with peer without adjacency reset\n") +{ + struct eigrp *eigrp; + struct eigrp_interface *ei; + + /* Check if eigrp process is enabled */ + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* lookup interface by specified name */ + ei = eigrp_if_lookup_by_name(eigrp, argv[4]->arg); + if(ei == NULL) + { + vty_out (vty, " Interface (%s) doesn't exist%s", argv[4]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + + /* execute graceful restart for all neighbors on interface */ + eigrp_update_send_interface_GR(ei, EIGRP_GR_MANUAL, vty); + return CMD_SUCCESS; +} + +/* + * Execute graceful restart for neighbor specified by IP + */ +DEFUN (clear_ip_eigrp_neighbors_IP_soft, + clear_ip_eigrp_neighbors_IP_soft_cmd, + "clear ip eigrp neighbors A.B.C.D soft", + CLEAR_STR + IP_STR + "Clear IP-EIGRP\n" + "Clear IP-EIGRP neighbors\n" + "IP-EIGRP neighbor address\n" + "Resync with peer without adjacency reset\n") +{ + struct eigrp *eigrp; + struct eigrp_neighbor *nbr; + struct in_addr nbr_addr; + + VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[4]->arg); + + /* Check if eigrp process is enabled */ + eigrp = eigrp_lookup (); + if (eigrp == NULL) + { + vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + /* lookup neighbor in whole process */ + nbr = eigrp_nbr_lookup_by_addr_process(eigrp, nbr_addr); + + /* if neighbor doesn't exists, notify user and exit */ + if(nbr == NULL) + { + vty_out (vty, "Neighbor with entered address doesn't exists.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* execute graceful restart on neighbor */ + eigrp_update_send_GR(nbr, EIGRP_GR_MANUAL, vty); + + return CMD_SUCCESS; +} + +static struct cmd_node eigrp_node = +{ + EIGRP_NODE, + "%s(config-router)# ", + 1 +}; + +/* Save EIGRP configuration */ +static int +eigrp_config_write (struct vty *vty) +{ + struct eigrp *eigrp; + + int write = 0; + + eigrp = eigrp_lookup (); + if (eigrp != NULL) + { + /* Writes 'router eigrp' section to config */ + config_write_eigrp_router (vty, eigrp); + + /* Interface config print */ + config_write_interfaces (vty, eigrp); +// +// /* static neighbor print. */ +// config_write_eigrp_nbr_nbma (vty, eigrp); +// +// /* Virtual-Link print. */ +// config_write_virtual_link (vty, eigrp); +// +// /* Default metric configuration. */ +// config_write_eigrp_default_metric (vty, eigrp); +// +// /* Distribute-list and default-information print. */ +// config_write_eigrp_distribute (vty, eigrp); +// +// /* Distance configuration. */ +// config_write_eigrp_distance (vty, eigrp) + } + + return write; +} + +void +eigrp_vty_show_init (void) +{ + install_element (VIEW_NODE, &show_ip_eigrp_interfaces_cmd); + + install_element (VIEW_NODE, &show_ip_eigrp_neighbors_cmd); + + install_element (VIEW_NODE, &show_ip_eigrp_topology_cmd); + + install_element (VIEW_NODE, &show_ip_eigrp_neighbors_detail_cmd); + + install_element (VIEW_NODE, &show_ip_eigrp_interfaces_detail_cmd); + + install_element (VIEW_NODE, &show_ip_eigrp_topology_all_links_cmd); + + install_element (VIEW_NODE, &show_ip_eigrp_topology_detail_cmd); + +} + +/* eigrpd's interface node. */ +static struct cmd_node eigrp_interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", + 1 +}; + +void +eigrp_vty_if_init (void) +{ + install_node (&eigrp_interface_node, eigrp_write_interface); + if_cmd_init(); + + /* Delay and bandwidth configuration commands*/ + install_element (INTERFACE_NODE, &eigrp_if_delay_cmd); + install_element (INTERFACE_NODE, &no_eigrp_if_delay_cmd); + install_element (INTERFACE_NODE, &eigrp_if_bandwidth_cmd); + install_element (INTERFACE_NODE, &no_eigrp_if_bandwidth_cmd); + + /*Hello-interval and hold-time interval configuration commands*/ + install_element (INTERFACE_NODE, &eigrp_if_ip_holdinterval_cmd); + install_element (INTERFACE_NODE, &no_eigrp_if_ip_holdinterval_cmd); + install_element (INTERFACE_NODE, &eigrp_if_ip_hellointerval_cmd); + install_element (INTERFACE_NODE, &no_eigrp_if_ip_hellointerval_cmd); + + /* "Authentication configuration commands */ + install_element (INTERFACE_NODE, &eigrp_authentication_mode_cmd); + install_element (INTERFACE_NODE, &no_eigrp_authentication_mode_cmd); + install_element (INTERFACE_NODE, &eigrp_authentication_keychain_cmd); + install_element (INTERFACE_NODE, &no_eigrp_authentication_keychain_cmd); + + /*EIGRP Summarization commands*/ + install_element (INTERFACE_NODE, &eigrp_ip_summary_address_cmd); + install_element (INTERFACE_NODE, &no_eigrp_ip_summary_address_cmd); + + +} + +static void +eigrp_vty_zebra_init (void) +{ + install_element (EIGRP_NODE, &eigrp_redistribute_source_metric_cmd); + install_element (EIGRP_NODE, &no_eigrp_redistribute_source_metric_cmd); + +} + +/* Install EIGRP related vty commands. */ +void +eigrp_vty_init (void) +{ + install_node (&eigrp_node, eigrp_config_write); + + install_default (EIGRP_NODE); + + install_element (CONFIG_NODE, &router_eigrp_cmd); + install_element (CONFIG_NODE, &no_router_eigrp_cmd); + install_element (EIGRP_NODE, &eigrp_network_cmd); + install_element (EIGRP_NODE, &no_eigrp_network_cmd); + install_element (EIGRP_NODE, &eigrp_variance_cmd); + install_element (EIGRP_NODE, &no_eigrp_variance_cmd); + install_element (EIGRP_NODE, &eigrp_router_id_cmd); + install_element (EIGRP_NODE, &no_eigrp_router_id_cmd); + install_element (EIGRP_NODE, &eigrp_passive_interface_cmd); + install_element (EIGRP_NODE, &no_eigrp_passive_interface_cmd); + install_element (EIGRP_NODE, &eigrp_timers_active_cmd); + install_element (EIGRP_NODE, &no_eigrp_timers_active_cmd); + install_element (EIGRP_NODE, &eigrp_metric_weights_cmd); + install_element (EIGRP_NODE, &no_eigrp_metric_weights_cmd); + install_element (EIGRP_NODE, &eigrp_maximum_paths_cmd); + install_element (EIGRP_NODE, &no_eigrp_maximum_paths_cmd); + install_element (EIGRP_NODE, &eigrp_neighbor_cmd); + install_element (EIGRP_NODE, &no_eigrp_neighbor_cmd); + + /* commands for manual hard restart */ + install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_cmd); + install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_int_cmd); + install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_IP_cmd); + /* commands for manual graceful restart */ + install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_int_soft_cmd); + install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_IP_soft_cmd); + + eigrp_vty_zebra_init (); +} diff --git a/eigrpd/eigrp_vty.h b/eigrpd/eigrp_vty.h new file mode 100644 index 000000000..56a40263f --- /dev/null +++ b/eigrpd/eigrp_vty.h @@ -0,0 +1,42 @@ +/* + * EIGRP VTY Interface. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * Frantisek Gazo + * Tomas Hvorkovy + * Martin Kontsek + * Lukas Koribsky + * + * 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. + */ + +#ifndef _QUAGGA_EIGRP_VTY_H +#define _QUAGGA_EIGRP_VTY_H + + +/* Prototypes. */ +extern void eigrp_vty_init (void); +extern void eigrp_vty_show_init (void); +extern void eigrp_vty_if_init (void); + +#endif /* _Quagga_EIGRP_VTY_H_ */ diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c new file mode 100644 index 000000000..aef720898 --- /dev/null +++ b/eigrpd/eigrp_zebra.c @@ -0,0 +1,579 @@ +/* + * Zebra connect library for EIGRP. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "thread.h" +#include "command.h" +#include "network.h" +#include "prefix.h" +#include "routemap.h" +#include "table.h" +#include "stream.h" +#include "memory.h" +#include "zclient.h" +#include "filter.h" +#include "plist.h" +#include "log.h" +#include "nexthop.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_fsm.h" + +static int eigrp_interface_add (int , struct zclient *, zebra_size_t, vrf_id_t); +static int eigrp_interface_delete (int , struct zclient *, + zebra_size_t, vrf_id_t); +static int eigrp_interface_address_add (int, struct zclient *, + zebra_size_t, vrf_id_t vrf_id); +static int eigrp_interface_address_delete (int, struct zclient *, + zebra_size_t, vrf_id_t vrf_id); +static int eigrp_interface_state_up (int, struct zclient *, + zebra_size_t, vrf_id_t vrf_id); +static int eigrp_interface_state_down (int, struct zclient *, + zebra_size_t, vrf_id_t vrf_id); +static struct interface * zebra_interface_if_lookup (struct stream *); + +static int eigrp_zebra_read_ipv4 (int , struct zclient *, + zebra_size_t, vrf_id_t vrf_id); + +/* Zebra structure to hold current status. */ +struct zclient *zclient = NULL; + +/* For registering threads. */ +extern struct thread_master *master; +struct in_addr router_id_zebra; + +/* Router-id update message from zebra. */ +static int +eigrp_router_id_update_zebra (int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct eigrp *eigrp; + struct prefix router_id; + zebra_router_id_update_read (zclient->ibuf,&router_id); + + router_id_zebra = router_id.u.prefix4; + + eigrp = eigrp_lookup (); + + if (eigrp != NULL) + eigrp_router_id_update (eigrp); + + return 0; +} + + +void +eigrp_zebra_init (void) +{ + zclient = zclient_new (master); + + zclient_init (zclient, ZEBRA_ROUTE_EIGRP, 0); + zclient->router_id_update = eigrp_router_id_update_zebra; + zclient->interface_add = eigrp_interface_add; + zclient->interface_delete = eigrp_interface_delete; + zclient->interface_up = eigrp_interface_state_up; + zclient->interface_down = eigrp_interface_state_down; + zclient->interface_address_add = eigrp_interface_address_add; + zclient->interface_address_delete = eigrp_interface_address_delete; + zclient->redistribute_route_ipv4_add = eigrp_zebra_read_ipv4; + zclient->redistribute_route_ipv4_del = eigrp_zebra_read_ipv4; +} + + +/* Zebra route add and delete treatment. */ +static int +eigrp_zebra_read_ipv4 (int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct stream *s; + struct zapi_ipv4 api; + struct prefix_ipv4 p; + struct eigrp *eigrp; + + s = zclient->ibuf; + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.instance = stream_getw (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)); + + if (IPV4_NET127(ntohl(p.prefix.s_addr))) + return 0; + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + { + api.nexthop_num = stream_getc (s); + stream_get_ipv4 (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) + { + api.ifindex_num = stream_getc (s); + /* XXX assert(api.ifindex_num == 1); */ + stream_getl (s); /* ifindex, unused */ + } + 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); + + eigrp = eigrp_lookup (); + if (eigrp == NULL) + return 0; + + if (command == ZEBRA_IPV4_ROUTE_ADD) + { + + } + else /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */ + { + + } + + return 0; +} + +/* Inteface addition message from zebra. */ +static int +eigrp_interface_add (int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); + + assert (ifp->info); + + if (!EIGRP_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type)) + { + SET_IF_PARAM (IF_DEF_PARAMS (ifp), type); + IF_DEF_PARAMS (ifp)->type = eigrp_default_iftype (ifp); + } + + eigrp_if_update (ifp); + + return 0; +} + +static int +eigrp_interface_delete (int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + struct stream *s; + struct route_node *rn; + + s = zclient->ibuf; + /* zebra_interface_state_read () updates interface structure in iflist */ + ifp = zebra_interface_state_read (s, vrf_id); + + if (ifp == NULL) + return 0; + + if (if_is_up (ifp)) + zlog_warn ("Zebra: got delete of %s, but interface is still up", + ifp->name); + + if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE)) + zlog_debug("Zebra: interface delete %s index %d flags %llx metric %d mtu %d", + ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + if (rn->info) + eigrp_if_free ((struct eigrp_interface *) rn->info, INTERFACE_DOWN_BY_ZEBRA); + + ifp->ifindex = IFINDEX_INTERNAL; + return 0; +} + +static int +eigrp_interface_address_add (int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct connected *c; + + c = zebra_interface_address_read (command, zclient->ibuf, vrf_id); + + if (c == NULL) + return 0; + + if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE)) + { + char buf[128]; + prefix2str (c->address, buf, sizeof (buf)); + zlog_debug ("Zebra: interface %s address add %s", c->ifp->name, buf); + } + + eigrp_if_update (c->ifp); + + return 0; +} + +static int +eigrp_interface_address_delete (int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct connected *c; + struct interface *ifp; + struct eigrp_interface *ei; + struct route_node *rn; + struct prefix p; + + c = zebra_interface_address_read (command, zclient->ibuf, vrf_id); + + if (c == NULL) + return 0; + + if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE)) + { + char buf[128]; + prefix2str (c->address, buf, sizeof (buf)); + zlog_debug ("Zebra: interface %s address delete %s", c->ifp->name, buf); + } + + ifp = c->ifp; + p = *c->address; + p.prefixlen = IPV4_MAX_PREFIXLEN; + + rn = route_node_lookup (IF_OIFS (ifp), &p); + if (!rn) + { + connected_free (c); + return 0; + } + + assert (rn->info); + ei = rn->info; + + /* Call interface hook functions to clean up */ + eigrp_if_free (ei, INTERFACE_DOWN_BY_ZEBRA); + + connected_free (c); + + return 0; +} + +static int +eigrp_interface_state_up (int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + struct eigrp_interface *ei; + struct route_node *rn; + + ifp = zebra_interface_if_lookup (zclient->ibuf); + + if (ifp == NULL) + return 0; + + /* Interface is already up. */ + if (if_is_operative (ifp)) + { + /* Temporarily keep ifp values. */ + struct interface if_tmp; + memcpy (&if_tmp, ifp, sizeof (struct interface)); + + zebra_interface_if_set_value (zclient->ibuf, ifp); + + if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE)) + zlog_debug ("Zebra: Interface[%s] state update.", ifp->name); + + if (if_tmp.bandwidth != ifp->bandwidth) + { + if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE)) + zlog_debug ("Zebra: Interface[%s] bandwidth change %d -> %d.", + ifp->name, if_tmp.bandwidth, ifp->bandwidth); + +// eigrp_if_recalculate_output_cost (ifp); + } + + if (if_tmp.mtu != ifp->mtu) + { + if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE)) + zlog_debug ("Zebra: Interface[%s] MTU change %u -> %u.", + ifp->name, if_tmp.mtu, ifp->mtu); + + /* Must reset the interface (simulate down/up) when MTU changes. */ + eigrp_if_reset (ifp); + } + return 0; + } + + zebra_interface_if_set_value (zclient->ibuf, ifp); + + if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE)) + zlog_debug ("Zebra: Interface[%s] state change to up.", ifp->name); + + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) + { + if ((ei = rn->info) == NULL) + continue; + + eigrp_if_up (ei); + } + + return 0; +} + +static int +eigrp_interface_state_down (int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + struct eigrp_interface *ei; + struct route_node *node; + + ifp = zebra_interface_state_read (zclient->ibuf, vrf_id); + + if (ifp == NULL) + return 0; + + if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE)) + zlog_debug ("Zebra: Interface[%s] state change to down.", ifp->name); + + for (node = route_top (IF_OIFS (ifp)); node; node = route_next (node)) + { + if ((ei = node->info) == NULL) + continue; + eigrp_if_down (ei); + } + + return 0; +} + +static struct interface * +zebra_interface_if_lookup (struct stream *s) +{ + char ifname_tmp[INTERFACE_NAMSIZ]; + + /* Read interface name. */ + stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); + + /* And look it up. */ + return if_lookup_by_name_len (ifname_tmp, + strnlen (ifname_tmp, INTERFACE_NAMSIZ)); +} + +void +eigrp_zebra_route_add (struct prefix_ipv4 *p, struct eigrp_neighbor_entry *te) +{ + u_char message; + u_char flags; + int psize; + struct stream *s; + + if (zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP]) + { + message = 0; + flags = 0; + + /* EIGRP pass nexthop and metric */ + SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP); + SET_FLAG (message, ZAPI_MESSAGE_METRIC); + + /* Distance value. */ +// distance = eigrp_distance_apply (p, er); +// if (distance) +// SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); + + /* Make packet. */ + s = zclient->obuf; + stream_reset (s); + + /* Put command, type, flags, message. */ + zclient_create_header (s, ZEBRA_IPV4_ROUTE_ADD, VRF_DEFAULT); + stream_putc (s, ZEBRA_ROUTE_EIGRP); + stream_putc (s, flags); + stream_putc (s, message); + stream_putw (s, SAFI_UNICAST); + + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *) & p->prefix, psize); + + /* Nexthop count. */ + stream_putc (s, 1); + + /* Nexthop, ifindex, distance and metric information. */ + stream_putc (s, NEXTHOP_TYPE_IPV4_IFINDEX); + stream_put_in_addr (s, &te->adv_router->src); + stream_putl (s, te->ei->ifp->ifindex); + + if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE)) + { + char buf[2][INET_ADDRSTRLEN]; + zlog_debug ("Zebra: Route add %s/%d nexthop %s", + inet_ntop(AF_INET, &p->prefix, buf[0], sizeof (buf[0])), + p->prefixlen, + inet_ntop(AF_INET, 0 /*&p->nexthop*/, buf[1], sizeof (buf[1]))); + } + + stream_putl (s, te->distance); + stream_putw_at (s, 0, stream_get_endp (s)); + + zclient_send_message (zclient); + } +} + +void +eigrp_zebra_route_delete (struct prefix_ipv4 *p, struct eigrp_neighbor_entry *te) +{ + u_char message; + u_char flags; + int psize; + struct stream *s; + + if (zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP]) + { + message = 0; + flags = 0; + /* Make packet. */ + s = zclient->obuf; + stream_reset (s); + + /* Put command, type, flags, message. */ + zclient_create_header (s, ZEBRA_IPV4_ROUTE_DELETE, VRF_DEFAULT); + stream_putc (s, ZEBRA_ROUTE_EIGRP); + stream_putc (s, flags); + stream_putc (s, message); + stream_putw (s, SAFI_UNICAST); + + /* Put prefix information. */ + psize = PSIZE (p->prefixlen); + stream_putc (s, p->prefixlen); + stream_write (s, (u_char *) & p->prefix, psize); + + /* Nexthop count. */ + stream_putc (s, 1); + + /* Nexthop, ifindex, distance and metric information. */ + stream_putc (s, NEXTHOP_TYPE_IPV4_IFINDEX); + stream_put_in_addr (s, &te->adv_router->src); + stream_putl (s, te->ei->ifp->ifindex); + + if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE)) + { + char buf[2][INET_ADDRSTRLEN]; + zlog_debug ("Zebra: Route del %s/%d nexthop %s", + inet_ntop (AF_INET, &p->prefix, buf[0], sizeof (buf[0])), + p->prefixlen, + inet_ntop (AF_INET, 0 /*&p->nexthop*/, buf[1], sizeof (buf[1]))); + } + + + if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) + { + stream_putl (s, te->distance); + } + + stream_putw_at (s, 0, stream_get_endp (s)); + + zclient_send_message (zclient); + } +} + +vrf_bitmap_t +eigrp_is_type_redistributed (int type) +{ + return (DEFAULT_ROUTE_TYPE (type)) ? + zclient->default_information : zclient->redist[AFI_IP][type]; +} + +int +eigrp_redistribute_set (struct eigrp *eigrp, int type, struct eigrp_metrics metric) +{ + + if (eigrp_is_type_redistributed (type)) + { + if (eigrp_metrics_is_same(&metric, &eigrp->dmetric[type])) + { + eigrp->dmetric[type] = metric; + } + + eigrp_external_routes_refresh (eigrp, type); + +// if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) +// zlog_debug ("Redistribute[%s]: Refresh Type[%d], Metric[%d]", +// eigrp_redist_string(type), +// metric_type (eigrp, type), metric_value (eigrp, type)); + return CMD_SUCCESS; + } + + eigrp->dmetric[type] = metric; + + zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, + AFI_IP, type, 0, VRF_DEFAULT); + +// if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE)) +// zlog_debug ("Redistribute[%s]: Start Type[%d], Metric[%d]", +// ospf_redist_string(type), +// metric_type (ospf, type), metric_value (ospf, type)); + + ++eigrp->redistribute; + + return CMD_SUCCESS; +} + +int +eigrp_redistribute_unset (struct eigrp *eigrp, int type) +{ + + if (eigrp_is_type_redistributed (type)) + { + memset(&eigrp->dmetric[type], 0, sizeof(struct eigrp_metrics)); + zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, + AFI_IP, type, 0, VRF_DEFAULT); + --eigrp->redistribute; + } + +// if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE)) +// zlog_debug ("Redistribute[%s]: Start Type[%d], Metric[%d]", +// ospf_redist_string(type), +// metric_type (ospf, type), metric_value (ospf, type)); + + return CMD_SUCCESS; +} + diff --git a/eigrpd/eigrp_zebra.h b/eigrpd/eigrp_zebra.h new file mode 100644 index 000000000..f1c8e62e7 --- /dev/null +++ b/eigrpd/eigrp_zebra.h @@ -0,0 +1,43 @@ +/* + * Zebra connect library for EIGRP. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * 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. + */ + +#ifndef _ZEBRA_EIGRP_ZEBRA_H_ +#define _ZEBRA_EIGRP_ZEBRA_H_ + +#include "vty.h" +#include "vrf.h" + +extern void eigrp_zebra_init (void); + +extern void eigrp_zebra_route_add (struct prefix_ipv4 *, struct eigrp_neighbor_entry *); +extern void eigrp_zebra_route_delete (struct prefix_ipv4 *, struct eigrp_neighbor_entry *); +extern int eigrp_redistribute_set (struct eigrp *, int, struct eigrp_metrics); +extern int eigrp_redistribute_unset (struct eigrp *, int); +extern vrf_bitmap_t eigrp_is_type_redistributed (int); + +#endif /* _ZEBRA_EIGRP_ZEBRA_H_ */ diff --git a/eigrpd/eigrpd.c b/eigrpd/eigrpd.c new file mode 100644 index 000000000..cb60db16c --- /dev/null +++ b/eigrpd/eigrpd.c @@ -0,0 +1,310 @@ +/* + * EIGRP Daemon Program. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "thread.h" +#include "vty.h" +#include "command.h" +#include "linklist.h" +#include "prefix.h" +#include "table.h" +#include "if.h" +#include "memory.h" +#include "stream.h" +#include "log.h" +#include "sockunion.h" /* for inet_aton () */ +#include "zclient.h" +#include "plist.h" +#include "sockopt.h" +#include "keychain.h" + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_interface.h" +#include "eigrpd/eigrp_zebra.h" +#include "eigrpd/eigrp_vty.h" +#include "eigrpd/eigrp_neighbor.h" +#include "eigrpd/eigrp_packet.h" +#include "eigrpd/eigrp_network.h" +#include "eigrpd/eigrp_topology.h" +#include "eigrpd/eigrp_memory.h" + +DEFINE_QOBJ_TYPE(eigrp) + +static struct eigrp_master eigrp_master; + +struct eigrp_master *eigrp_om; + +static void eigrp_finish_final(struct eigrp *); +static void eigrp_delete(struct eigrp *); +static struct eigrp *eigrp_new(const char *); +static void eigrp_add(struct eigrp *); + +extern struct zclient *zclient; +extern struct in_addr router_id_zebra; + + +/* + * void eigrp_router_id_update(struct eigrp *eigrp) + * + * Description: + * update routerid associated with this instance of EIGRP. + * If the id changes, then call if_update for each interface + * to resync the topology database with all neighbors + * + * Select the router ID based on these priorities: + * 1. Statically assigned router ID is always the first choice. + * 2. If there is no statically assigned router ID, then try to stick + * with the most recent value, since changing router ID's is very + * disruptive. + * 3. Last choice: just go with whatever the zebra daemon recommends. + * + * Note: + * router id for EIGRP is really just a 32 bit number. Cisco historically + * displays it in dotted decimal notation, and will pickup an IP address + * from an interface so it can be 'auto-configed" to a uniqe value + * + * This does not work for IPv6, and to make the code simpler, its + * stored and processed internerall as a 32bit number + */ +void +eigrp_router_id_update (struct eigrp *eigrp) +{ + struct interface *ifp; + struct listnode *node; + u_int32_t router_id, router_id_old; + + router_id_old = eigrp->router_id; + + if (eigrp->router_id_static != 0) + router_id = eigrp->router_id_static; + + else if (eigrp->router_id != 0) + router_id = eigrp->router_id; + + else + router_id = router_id_zebra.s_addr; + + eigrp->router_id = router_id; + if (router_id_old != router_id) + { +// if (IS_DEBUG_EIGRP_EVENT) +// zlog_debug("Router-ID[NEW:%s]: Update", inet_ntoa(eigrp->router_id)); + + /* update eigrp_interface's */ + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) + eigrp_if_update(ifp); + } +} + +void +eigrp_master_init () +{ + struct timeval tv; + + memset(&eigrp_master, 0, sizeof(struct eigrp_master)); + + eigrp_om = &eigrp_master; + eigrp_om->eigrp = list_new(); + + monotime(&tv); + eigrp_om->start_time = tv.tv_sec; +} + + +/* Allocate new eigrp structure. */ +static struct eigrp * +eigrp_new (const char *AS) +{ + struct eigrp *eigrp = XCALLOC(MTYPE_EIGRP_TOP, sizeof (struct eigrp)); + int eigrp_socket; + + /* init information relevant to peers */ + eigrp->vrid = 0; + eigrp->AS = atoi(AS); + eigrp->router_id = 0L; + eigrp->router_id_static = 0L; + eigrp->sequence_number = 1; + + /*Configure default K Values for EIGRP Process*/ + eigrp->k_values[0] = EIGRP_K1_DEFAULT; + eigrp->k_values[1] = EIGRP_K2_DEFAULT; + eigrp->k_values[2] = EIGRP_K3_DEFAULT; + eigrp->k_values[3] = EIGRP_K4_DEFAULT; + eigrp->k_values[4] = EIGRP_K5_DEFAULT; + eigrp->k_values[5] = EIGRP_K6_DEFAULT; + + /* init internal data structures */ + eigrp->eiflist = list_new(); + eigrp->passive_interface_default = EIGRP_IF_ACTIVE; + eigrp->networks = route_table_init(); + + if ((eigrp_socket = eigrp_sock_init()) < 0) + { + zlog_err("eigrp_new: fatal error: eigrp_sock_init was unable to open " + "a socket"); + exit (1); + } + + eigrp->fd = eigrp_socket; + eigrp->maxsndbuflen = getsockopt_so_sendbuf(eigrp->fd); + + if ((eigrp->ibuf = stream_new(EIGRP_PACKET_MAX_LEN+1)) == NULL) + { + zlog_err("eigrp_new: fatal error: stream_new (%u) failed allocating ibuf", + EIGRP_PACKET_MAX_LEN+1); + exit(1); + } + + eigrp->t_read = thread_add_read(master, eigrp_read, eigrp, eigrp->fd); + eigrp->oi_write_q = list_new(); + + eigrp->topology_table = eigrp_topology_new(); + + eigrp->neighbor_self = eigrp_nbr_new(NULL); + inet_aton("127.0.0.1", &eigrp->neighbor_self->src); + + eigrp->variance = EIGRP_VARIANCE_DEFAULT; + eigrp->max_paths = EIGRP_MAX_PATHS_DEFAULT; + + eigrp->serno = 0; + eigrp->serno_last_update = 0; + eigrp->topology_changes_externalIPV4 = list_new (); + eigrp->topology_changes_internalIPV4 = list_new (); + + eigrp->list[EIGRP_FILTER_IN] = NULL; + eigrp->list[EIGRP_FILTER_OUT] = NULL; + + eigrp->prefix[EIGRP_FILTER_IN] = NULL; + eigrp->prefix[EIGRP_FILTER_OUT] = NULL; + + eigrp->routemap[EIGRP_FILTER_IN] = NULL; + eigrp->routemap[EIGRP_FILTER_OUT] = NULL; + + QOBJ_REG(eigrp, eigrp); + return eigrp; +} + +static void +eigrp_add (struct eigrp *eigrp) +{ + listnode_add(eigrp_om->eigrp, eigrp); +} + +static void +eigrp_delete (struct eigrp *eigrp) +{ + listnode_delete(eigrp_om->eigrp, eigrp); +} + +struct eigrp * +eigrp_get (const char *AS) +{ + struct eigrp *eigrp; + + eigrp = eigrp_lookup(); + if (eigrp == NULL) + { + eigrp = eigrp_new(AS); + eigrp_add(eigrp); + } + + return eigrp; +} + +/* Shut down the entire process */ +void +eigrp_terminate (void) +{ + struct eigrp *eigrp; + struct listnode *node, *nnode; + + /* shutdown already in progress */ + if (CHECK_FLAG(eigrp_om->options, EIGRP_MASTER_SHUTDOWN)) + return; + + SET_FLAG(eigrp_om->options, EIGRP_MASTER_SHUTDOWN); + + /* exit immediately if EIGRP not actually running */ + if (listcount(eigrp_om->eigrp) == 0) + exit(0); + + for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) + eigrp_finish(eigrp); +} + +void +eigrp_finish (struct eigrp *eigrp) +{ + + eigrp_finish_final(eigrp); + + /* eigrp being shut-down? If so, was this the last eigrp instance? */ + if (CHECK_FLAG(eigrp_om->options, EIGRP_MASTER_SHUTDOWN) + && (listcount(eigrp_om->eigrp) == 0)) + exit(0); + + return; +} + +/* Final cleanup of eigrp instance */ +static void +eigrp_finish_final (struct eigrp *eigrp) +{ + + close(eigrp->fd); + + if (zclient) + zclient_free(zclient); + + list_delete(eigrp->eiflist); + list_delete(eigrp->oi_write_q); + list_delete(eigrp->topology_changes_externalIPV4); + list_delete(eigrp->topology_changes_internalIPV4); + + eigrp_topology_cleanup(eigrp->topology_table); + eigrp_topology_free(eigrp->topology_table); + + eigrp_nbr_delete(eigrp->neighbor_self); + + eigrp_delete(eigrp); + + XFREE(MTYPE_EIGRP_TOP,eigrp); + +} + +/*Look for existing eigrp process*/ +struct eigrp * +eigrp_lookup (void) +{ + if (listcount(eigrp_om->eigrp) == 0) + return NULL; + + return listgetdata(listhead(eigrp_om->eigrp)); +} diff --git a/eigrpd/eigrpd.conf.sample b/eigrpd/eigrpd.conf.sample new file mode 100644 index 000000000..662e667d3 --- /dev/null +++ b/eigrpd/eigrpd.conf.sample @@ -0,0 +1,13 @@ +! -*- eigrpd -*- +! +! EIGRPDd sample configuration file +! +! +hostname eigrpd +password zebra +!enable password please-set-at-here +! +!router eigrp 4453 +! network 192.168.1.0/24 +! +log stdout diff --git a/eigrpd/eigrpd.h b/eigrpd/eigrpd.h new file mode 100644 index 000000000..61d4ba752 --- /dev/null +++ b/eigrpd/eigrpd.h @@ -0,0 +1,54 @@ +/* + * EIGRP main header. + * Copyright (C) 2013-2014 + * Authors: + * Donnie Savage + * Jan Janovic + * Matej Perina + * Peter Orsag + * Peter Paluch + * + * 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. + */ + +#ifndef _ZEBRA_EIGRPD_H +#define _ZEBRA_EIGRPD_H + +#include <zebra.h> + +#include "filter.h" +#include "log.h" + +/* Set EIGRP version is "classic" - wide metrics comes next */ +#define EIGRP_MAJOR_VERSION 1 +#define EIGRP_MINOR_VERSION 2 + +/* Extern variables. */ +extern struct zclient *zclient; +extern struct thread_master *master; +extern struct eigrp_master *eigrp_om; + +/* Prototypes */ + extern void eigrp_master_init (void); + extern void eigrp_terminate (void); + extern void eigrp_finish (struct eigrp *); + extern struct eigrp *eigrp_get (const char *); + extern struct eigrp *eigrp_lookup (void); + extern void eigrp_router_id_update (struct eigrp *); + +#endif /* _ZEBRA_EIGRPD_H */ diff --git a/lib/Makefile.am b/lib/Makefile.am index 1a8c7af42..55b1eb804 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -31,7 +31,8 @@ libfrr_la_SOURCES = \ spf_backoff.c \ libfrr.c \ strlcpy.c \ - strlcat.c + strlcat.c \ + sha256.c BUILT_SOURCES = route_types.h gitversion.h command_parse.h command_lex.h @@ -55,6 +56,7 @@ pkginclude_HEADERS = \ spf_backoff.h \ srcdest_table.h \ libfrr.h \ + sha256.h \ # end noinst_HEADERS = \ diff --git a/lib/command.c b/lib/command.c index bfff581d9..cae848a5c 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1398,6 +1398,7 @@ cmd_exit (struct vty *vty) case ZEBRA_NODE: case BGP_NODE: case RIP_NODE: + case EIGRP_NODE: case RIPNG_NODE: case OSPF_NODE: case OSPF6_NODE: @@ -1479,6 +1480,7 @@ DEFUN (config_end, case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: + case EIGRP_NODE: case BGP_NODE: case BGP_ENCAP_NODE: case BGP_ENCAPV6_NODE: diff --git a/lib/command.h b/lib/command.h index d62f7655e..c8172caa7 100644 --- a/lib/command.h +++ b/lib/command.h @@ -91,6 +91,7 @@ enum node_type TABLE_NODE, /* rtm_table selection node. */ RIP_NODE, /* RIP protocol mode node. */ RIPNG_NODE, /* RIPng protocol mode node. */ + EIGRP_NODE, /* EIGRP protocol mode node. */ BGP_NODE, /* BGP protocol mode which includes BGP4+ */ BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */ BGP_VPNV6_NODE, /* BGP MPLS-VPN PE exchange. */ @@ -356,6 +357,7 @@ struct cmd_element #define REDIST_STR "Redistribute information from another routing protocol\n" #define CLEAR_STR "Reset functions\n" #define RIP_STR "RIP information\n" +#define EIGRP_STR "EIGRP information\n" #define BGP_STR "BGP information\n" #define BGP_SOFT_STR "Soft reconfig inbound and outbound updates\n" #define BGP_SOFT_IN_STR "Send route-refresh unless using 'soft-reconfiguration inbound'\n" diff --git a/lib/libfrr.c b/lib/libfrr.c index f9ac3158a..b7ce0679c 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -27,6 +27,7 @@ #include "version.h" #include "memory_vty.h" #include "zclient.h" +#include "log_int.h" const char frr_sysconfdir[] = SYSCONFDIR; const char frr_vtydir[] = DAEMON_VTY_DIR; @@ -303,7 +304,7 @@ struct thread_master *frr_init(void) openzlog (di->progname, di->logname, di->instance, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); #if defined(HAVE_CUMULUS) - zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); + zlog_set_level (ZLOG_DEST_SYSLOG, zlog_default->default_lvl); #endif zprivs_init(di->privs); @@ -1044,6 +1044,8 @@ proto_redistnum(int afi, const char *s) return ZEBRA_ROUTE_STATIC; else if (strmatch (s, "rip")) return ZEBRA_ROUTE_RIP; + else if (strmatch (s, "eigrp")) + return ZEBRA_ROUTE_EIGRP; else if (strmatch (s, "ospf")) return ZEBRA_ROUTE_OSPF; else if (strmatch (s, "isis")) diff --git a/lib/route_types.txt b/lib/route_types.txt index 5cb06ffb7..7625d1f69 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -52,6 +52,7 @@ ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, "OSPFv3" ZEBRA_ROUTE_ISIS, isis, isisd, 'I', 1, 1, "IS-IS" ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP" ZEBRA_ROUTE_PIM, pim, pimd, 'P', 1, 0, "PIM" +ZEBRA_ROUTE_EIGRP, eigrp, eigrpd, 'E', 1, 0, "EIGRP" ZEBRA_ROUTE_NHRP, nhrp, nhrpd, 'N', 1, 1, "NHRP" # HSLS and OLSR both are AFI independent (so: 1, 1), however # we want to disable for them for general Quagga distribution. @@ -86,6 +87,7 @@ ZEBRA_ROUTE_OSPF6, "Open Shortest Path First (IPv6) (OSPFv3)" ZEBRA_ROUTE_ISIS, "Intermediate System to Intermediate System (IS-IS)" ZEBRA_ROUTE_BGP, "Border Gateway Protocol (BGP)" ZEBRA_ROUTE_PIM, "Protocol Independent Multicast (PIM)" +ZEBRA_ROUTE_EIGRP, "Enhanced Interior Gateway Routing Protocol (EIGRP)" ZEBRA_ROUTE_NHRP, "Next Hop Resolution Protocol (NHRP)" ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)" ZEBRA_ROUTE_VNC, "Virtual Network Control (VNC)" diff --git a/lib/sha256.c b/lib/sha256.c new file mode 100644 index 000000000..c7588a5f1 --- /dev/null +++ b/lib/sha256.c @@ -0,0 +1,425 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <zebra.h> +#include "sha256.h" + +static inline uint32_t +be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static inline void +be32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +/* + * Encode a length len/4 vector of (uint32_t) into a length len vector of + * (unsigned char) in big-endian form. Assumes len is a multiple of 4. + */ +static void +be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + be32enc(dst + i * 4, src[i]); +} + +/* + * Decode a big-endian length len vector of (unsigned char) into a length + * len/4 vector of (uint32_t). Assumes len is a multiple of 4. + */ +static void +be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + dst[i] = be32dec(src + i * 4); +} + +/* Elementary functions used by SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +/* SHA256 round function */ +#define RND(a, b, c, d, e, f, g, h, k) \ + t0 = h + S1(e) + Ch(e, f, g) + k; \ + t1 = S0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +/* Adjusted round function for rotating state */ +#define RNDr(S, W, i, k) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i] + k) + +/* + * SHA256 block compression function. The 256-bit state is transformed via + * the 512-bit input block to produce a new state. + */ +static void +SHA256_Transform(uint32_t * state, const unsigned char block[64]) +{ + uint32_t W[64]; + uint32_t S[8]; + uint32_t t0, t1; + int i; + + /* 1. Prepare message schedule W. */ + be32dec_vect(W, block, 64); + for (i = 16; i < 64; i++) + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + RNDr(S, W, 0, 0x428a2f98); + RNDr(S, W, 1, 0x71374491); + RNDr(S, W, 2, 0xb5c0fbcf); + RNDr(S, W, 3, 0xe9b5dba5); + RNDr(S, W, 4, 0x3956c25b); + RNDr(S, W, 5, 0x59f111f1); + RNDr(S, W, 6, 0x923f82a4); + RNDr(S, W, 7, 0xab1c5ed5); + RNDr(S, W, 8, 0xd807aa98); + RNDr(S, W, 9, 0x12835b01); + RNDr(S, W, 10, 0x243185be); + RNDr(S, W, 11, 0x550c7dc3); + RNDr(S, W, 12, 0x72be5d74); + RNDr(S, W, 13, 0x80deb1fe); + RNDr(S, W, 14, 0x9bdc06a7); + RNDr(S, W, 15, 0xc19bf174); + RNDr(S, W, 16, 0xe49b69c1); + RNDr(S, W, 17, 0xefbe4786); + RNDr(S, W, 18, 0x0fc19dc6); + RNDr(S, W, 19, 0x240ca1cc); + RNDr(S, W, 20, 0x2de92c6f); + RNDr(S, W, 21, 0x4a7484aa); + RNDr(S, W, 22, 0x5cb0a9dc); + RNDr(S, W, 23, 0x76f988da); + RNDr(S, W, 24, 0x983e5152); + RNDr(S, W, 25, 0xa831c66d); + RNDr(S, W, 26, 0xb00327c8); + RNDr(S, W, 27, 0xbf597fc7); + RNDr(S, W, 28, 0xc6e00bf3); + RNDr(S, W, 29, 0xd5a79147); + RNDr(S, W, 30, 0x06ca6351); + RNDr(S, W, 31, 0x14292967); + RNDr(S, W, 32, 0x27b70a85); + RNDr(S, W, 33, 0x2e1b2138); + RNDr(S, W, 34, 0x4d2c6dfc); + RNDr(S, W, 35, 0x53380d13); + RNDr(S, W, 36, 0x650a7354); + RNDr(S, W, 37, 0x766a0abb); + RNDr(S, W, 38, 0x81c2c92e); + RNDr(S, W, 39, 0x92722c85); + RNDr(S, W, 40, 0xa2bfe8a1); + RNDr(S, W, 41, 0xa81a664b); + RNDr(S, W, 42, 0xc24b8b70); + RNDr(S, W, 43, 0xc76c51a3); + RNDr(S, W, 44, 0xd192e819); + RNDr(S, W, 45, 0xd6990624); + RNDr(S, W, 46, 0xf40e3585); + RNDr(S, W, 47, 0x106aa070); + RNDr(S, W, 48, 0x19a4c116); + RNDr(S, W, 49, 0x1e376c08); + RNDr(S, W, 50, 0x2748774c); + RNDr(S, W, 51, 0x34b0bcb5); + RNDr(S, W, 52, 0x391c0cb3); + RNDr(S, W, 53, 0x4ed8aa4a); + RNDr(S, W, 54, 0x5b9cca4f); + RNDr(S, W, 55, 0x682e6ff3); + RNDr(S, W, 56, 0x748f82ee); + RNDr(S, W, 57, 0x78a5636f); + RNDr(S, W, 58, 0x84c87814); + RNDr(S, W, 59, 0x8cc70208); + RNDr(S, W, 60, 0x90befffa); + RNDr(S, W, 61, 0xa4506ceb); + RNDr(S, W, 62, 0xbef9a3f7); + RNDr(S, W, 63, 0xc67178f2); + + /* 4. Mix local working variables into global state */ + for (i = 0; i < 8; i++) + state[i] += S[i]; + + /* Clean the stack. */ + memset(W, 0, 256); + memset(S, 0, 32); + t0 = t1 = 0; +} + +static unsigned char PAD[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Add padding and terminating bit-count. */ +static void +SHA256_Pad(SHA256_CTX * ctx) +{ + unsigned char len[8]; + uint32_t r, plen; + + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + be32enc_vect(len, ctx->count, 8); + + /* Add 1--64 bytes so that the resulting length is 56 mod 64 */ + r = (ctx->count[1] >> 3) & 0x3f; + plen = (r < 56) ? (56 - r) : (120 - r); + SHA256_Update(ctx, PAD, (size_t)plen); + + /* Add the terminating bit-count */ + SHA256_Update(ctx, len, 8); +} + +/* SHA-256 initialization. Begins a SHA-256 operation. */ +void +SHA256_Init(SHA256_CTX * ctx) +{ + + /* Zero bits processed so far */ + ctx->count[0] = ctx->count[1] = 0; + + /* Magic initialization constants */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +/* Add bytes into the hash */ +void +SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len) +{ + uint32_t bitlen[2]; + uint32_t r; + const unsigned char *src = in; + + /* Number of bytes left in the buffer from previous updates */ + r = (ctx->count[1] >> 3) & 0x3f; + + /* Convert the length into a number of bits */ + bitlen[1] = ((uint32_t)len) << 3; + bitlen[0] = (uint32_t)(len >> 29); + + /* Update number of bits */ + if ((ctx->count[1] += bitlen[1]) < bitlen[1]) + ctx->count[0]++; + ctx->count[0] += bitlen[0]; + + /* Handle the case where we don't need to perform any transforms */ + if (len < 64 - r) { + memcpy(&ctx->buf[r], src, len); + return; + } + + /* Finish the current block */ + memcpy(&ctx->buf[r], src, 64 - r); + SHA256_Transform(ctx->state, ctx->buf); + src += 64 - r; + len -= 64 - r; + + /* Perform complete blocks */ + while (len >= 64) { + SHA256_Transform(ctx->state, src); + src += 64; + len -= 64; + } + + /* Copy left over data into buffer */ + memcpy(ctx->buf, src, len); +} + +/* + * SHA-256 finalization. Pads the input data, exports the hash value, + * and clears the context state. + */ +void +SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx) +{ + + /* Add padding */ + SHA256_Pad(ctx); + + /* Write the hash */ + be32enc_vect(digest, ctx->state, 32); + + /* Clear the context state */ + memset((void *)ctx, 0, sizeof(*ctx)); +} + +/* Initialize an HMAC-SHA256 operation with the given key. */ +void +HMAC__SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + const unsigned char * K = _K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + SHA256_Init(&ctx->ictx); + SHA256_Update(&ctx->ictx, K, Klen); + SHA256_Final(khash, &ctx->ictx); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + SHA256_Init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + SHA256_Init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-SHA256 operation. */ +void +HMAC__SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len) +{ + + /* Feed data to the inner SHA256 operation. */ + SHA256_Update(&ctx->ictx, in, len); +} + +/* Finish an HMAC-SHA256 operation. */ +void +HMAC__SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx) +{ + unsigned char ihash[32]; + + /* Finish the inner SHA256 operation. */ + SHA256_Final(ihash, &ctx->ictx); + + /* Feed the inner hash to the outer SHA256 operation. */ + SHA256_Update(&ctx->octx, ihash, 32); + + /* Finish the outer SHA256 operation. */ + SHA256_Final(digest, &ctx->octx); + + /* Clean the stack. */ + memset(ihash, 0, 32); +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + HMAC_SHA256_CTX PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + HMAC__SHA256_Init(&PShctx, passwd, passwdlen); + HMAC__SHA256_Update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); + HMAC__SHA256_Update(&hctx, ivec, 4); + HMAC__SHA256_Final(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + HMAC__SHA256_Init(&hctx, passwd, passwdlen); + HMAC__SHA256_Update(&hctx, U, 32); + HMAC__SHA256_Final(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX)); +} diff --git a/lib/sha256.h b/lib/sha256.h new file mode 100644 index 000000000..502f3fc22 --- /dev/null +++ b/lib/sha256.h @@ -0,0 +1,58 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libmd/sha256.h,v 1.2 2006/01/17 15:35:56 phk Exp $ + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +typedef struct SHA256Context { + uint32_t state[8]; + uint32_t count[2]; + unsigned char buf[64]; +} SHA256_CTX; + +typedef struct HMAC_SHA256Context { + SHA256_CTX ictx; + SHA256_CTX octx; +} HMAC_SHA256_CTX; + +void SHA256_Init(SHA256_CTX *); +void SHA256_Update(SHA256_CTX *, const void *, size_t); +void SHA256_Final(unsigned char [32], SHA256_CTX *); +void HMAC__SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t); +void HMAC__SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t); +void HMAC__SHA256_Final(unsigned char [32], HMAC_SHA256_CTX *); + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#endif /* !_SHA256_H_ */ @@ -734,6 +734,7 @@ vty_end_config (struct vty *vty) case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: + case EIGRP_NODE: case BGP_NODE: case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: @@ -1161,6 +1162,7 @@ vty_stop_input (struct vty *vty) case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: + case EIGRP_NODE: case BGP_NODE: case RMAP_NODE: case OSPF_NODE: diff --git a/pkgsrc/eigrpd.sh.in b/pkgsrc/eigrpd.sh.in new file mode 100644 index 000000000..b28b81eed --- /dev/null +++ b/pkgsrc/eigrpd.sh.in @@ -0,0 +1,44 @@ +#!/bin/sh +# +# eigrpd is part of the quagga routing beast +# +# PROVIDE: eigrpd +# REQUIRE: zebra +## + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin +export PATH + +if [ -f /etc/rc.subr ] +then + . /etc/rc.subr +fi + +name="eigrpd" +rcvar=$name +required_files="@sysconfdir@/${name}.conf" +command="@prefix@/sbin/${name}" +command_args="-d" + +start_precmd="zebra_precmd" +socket_dir=@localstatedir@ +pidfile="${socket_dir}/${name}.pid" + +zebra_precmd() +{ + rc_flags="$( + set -- $rc_flags + while [ $# -ne 0 ]; do + if [ X"$1" = X-P -o X"$1" = X-A ]; then + break + fi + shift + done + if [ $# -eq 0 ]; then + echo "-P 0" + fi + ) $rc_flags" +} + +load_rc_config $name +run_rc_command "$1" diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index d02ec9661..c28b9cb71 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -71,6 +71,12 @@ if NHRPD vtysh_scan += $(top_srcdir)/nhrpd/nhrp_vty.c endif +if EIGRPD +vtysh_scan += $(top_srcdir)/eigrpd/eigrp_dump.c +vtysh_scan += $(top_srcdir)/eigrpd/eigrp_routemap.c +vtysh_scan += $(top_srcdir)/eigrpd/eigrp_vty.c +endif + vtysh_cmd_FILES = $(vtysh_scan) \ $(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \ $(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \ diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index c1b1d705a..e46901b85 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -52,6 +52,7 @@ $ignore{'"router bgp " "(1-4294967295)"'} = "ignore"; $ignore{'"router bgp " "(1-4294967295)" " <view|vrf> WORD"'} = "ignore"; $ignore{'"router bgp [(1-4294967295) [<view|vrf> WORD]]"'} = "ignore"; $ignore{'"router isis WORD"'} = "ignore"; +$ignore('"router eigrp (1-65535)"'} = "ignore"; $ignore{'"router zebra"'} = "ignore"; $ignore{'"address-family ipv4"'} = "ignore"; $ignore{'"address-family ipv4 [<unicast|multicast|vpn|encap>]"'} = "ignore"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 114022d19..afb742d90 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -75,6 +75,7 @@ struct vtysh_client vtysh_client[] = { .fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .next = NULL}, { .fd = -1, .name = "pimd", .flag = VTYSH_PIMD, .next = NULL}, { .fd = -1, .name = "nhrpd", .flag = VTYSH_NHRPD, .next = NULL}, + { .fd = -1, .name = "eigrpd", .flag = VTYSH_EIGRPD, .next = NULL}, { .fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL}, }; @@ -994,6 +995,12 @@ static struct cmd_node ospf_node = "%s(config-router)# " }; +static struct cmd_node eigrp_node = +{ + EIGRP_NODE, + "%s(config-router)# " +}; + static struct cmd_node ripng_node = { RIPNG_NODE, @@ -1332,6 +1339,18 @@ DEFUNSH (VTYSH_OSPFD, return CMD_SUCCESS; } +DEFUNSH (VTYSH_EIGRPD, + router_eigrp, + router_eigrp_cmd, + "router eigrp (1-65535)", + "Enable a routing process\n" + "Start EIGRP configuration\n" + "AS number to use\n") +{ + vty->node = EIGRP_NODE; + return CMD_SUCCESS; +} + DEFUNSH (VTYSH_OSPF6D, router_ospf6, router_ospf6_cmd, @@ -1515,6 +1534,7 @@ vtysh_exit (struct vty *vty) case RIPNG_NODE: case OSPF_NODE: case OSPF6_NODE: + case EIGRP_NODE: case LDP_NODE: case LDP_L2VPN_NODE: case ISIS_NODE: @@ -1716,6 +1736,24 @@ DEFUNSH (VTYSH_OSPFD, return vtysh_exit_ospfd (self, vty, argc, argv); } +DEFUNSH (VTYSH_EIGRPD, + vtysh_exit_eigrpd, + vtysh_exit_eigrpd_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit (vty); +} + +DEFUNSH (VTYSH_EIGRPD, + vtysh_quit_eigrpd, + vtysh_quit_eigrpd_cmd, + "quit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit (vty); +} + DEFUNSH (VTYSH_OSPF6D, vtysh_exit_ospf6d, vtysh_exit_ospf6d_cmd, @@ -1799,7 +1837,7 @@ DEFUNSH (VTYSH_INTERFACE, } /* TODO Implement "no interface command in isisd. */ -DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD, +DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_EIGRPD|VTYSH_LDPD, vtysh_no_interface_cmd, "no interface IFNAME", NO_STR @@ -1883,13 +1921,13 @@ DEFUNSH (VTYSH_VRF, /* TODO Implement interface description commands in ripngd, ospf6d * and isisd. */ -DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_LDPD, +DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_EIGRPD|VTYSH_LDPD, vtysh_interface_desc_cmd, "description LINE...", "Interface specific description\n" "Characters describing this interface\n") -DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD, +DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_EIGRPD, vtysh_no_interface_desc_cmd, "no description", NO_STR @@ -3118,6 +3156,7 @@ vtysh_init_vty (void) install_node (&bgp_vnc_nve_group_node, NULL); install_node (&bgp_vnc_l2_group_node, NULL); install_node (&ospf_node, NULL); + install_node (&eigrp_node, NULL); install_node (&ripng_node, NULL); install_node (&ospf6_node, NULL); install_node (&ldp_node, NULL); @@ -3158,6 +3197,7 @@ vtysh_init_vty (void) vtysh_install_default (BGP_VNC_L2_GROUP_NODE); #endif vtysh_install_default (OSPF_NODE); + vtysh_install_default (EIGRP_NODE); vtysh_install_default (RIPNG_NODE); vtysh_install_default (OSPF6_NODE); vtysh_install_default (LDP_NODE); @@ -3187,6 +3227,8 @@ vtysh_init_vty (void) install_element (RIPNG_NODE, &vtysh_quit_ripngd_cmd); install_element (OSPF_NODE, &vtysh_exit_ospfd_cmd); install_element (OSPF_NODE, &vtysh_quit_ospfd_cmd); + install_element (EIGRP_NODE, &vtysh_exit_eigrpd_cmd); + install_element (EIGRP_NODE, &vtysh_quit_eigrpd_cmd); install_element (OSPF6_NODE, &vtysh_exit_ospf6d_cmd); install_element (OSPF6_NODE, &vtysh_quit_ospf6d_cmd); #if defined (HAVE_LDPD) @@ -3251,6 +3293,7 @@ vtysh_init_vty (void) install_element (RIP_NODE, &vtysh_end_all_cmd); install_element (RIPNG_NODE, &vtysh_end_all_cmd); install_element (OSPF_NODE, &vtysh_end_all_cmd); + install_element (EIGRP_NODE, &vtysh_end_all_cmd); install_element (OSPF6_NODE, &vtysh_end_all_cmd); install_element (LDP_NODE, &vtysh_end_all_cmd); install_element (LDP_IPV4_NODE, &vtysh_end_all_cmd); @@ -3298,6 +3341,7 @@ vtysh_init_vty (void) install_element (VRF_NODE, &vtysh_exit_vrf_cmd); install_element (VRF_NODE, &vtysh_quit_vrf_cmd); + install_element (CONFIG_NODE, &router_eigrp_cmd); install_element (CONFIG_NODE, &router_rip_cmd); install_element (CONFIG_NODE, &router_ripng_cmd); install_element (CONFIG_NODE, &router_ospf_cmd); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 07ba8367d..340f85df1 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -36,6 +36,7 @@ DECLARE_MGROUP(MVTYSH) #define VTYSH_LDPD 0x200 #define VTYSH_WATCHFRR 0x400 #define VTYSH_NHRPD 0x800 +#define VTYSH_EIGRPD 0x1000 /* commands in REALLYALL are crucial to correct vtysh operation */ #define VTYSH_REALLYALL ~0U |