diff options
60 files changed, 17222 insertions, 8 deletions
diff --git a/Makefile.am b/Makefile.am index aa978b7d25..aeacd4c3ce 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 e46e44a8b7..821e0e230b 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 0000000000..e46af767b9 --- /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 0000000000..f6ea298cfd --- /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 0000000000..89cb72cfde --- /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 0000000000..a1d09e684c --- /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 0000000000..c15eecc266 --- /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 0000000000..54e6338a33 --- /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 0000000000..aaac379d9b --- /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 0000000000..01c776b17e --- /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 0000000000..0277dc830f --- /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 0000000000..0677c09d7f --- /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 0000000000..df4ed1069f --- /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 0000000000..18573caa00 --- /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 0000000000..c7de3b75b6 --- /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 0000000000..dd22829e88 --- /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 0000000000..85a97e79ab --- /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 0000000000..dabc0774e2 --- /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 0000000000..0cafdfb1bd --- /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 0000000000..8dcf76dc47 --- /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 0000000000..e9ddc22f9e --- /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 0000000000..fba7717b9b --- /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 0000000000..87d1280620 --- /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 0000000000..9a0a9897f0 --- /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 0000000000..b8b2815168 --- /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 0000000000..e69de29bb2 --- /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 0000000000..e69de29bb2 --- /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 0000000000..d4bd379856 --- /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 0000000000..ff40e2e5c5 --- /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 0000000000..9dd5b15aff --- /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 0000000000..0fee25b9ab --- /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 0000000000..030a86c1c0 --- /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 0000000000..b494090612 --- /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 0000000000..f5dd69f1b3 --- /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 0000000000..ab14912c48 --- /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 0000000000..6e90c8cbae --- /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 0000000000..c8b53515b1 --- /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 0000000000..9f1569ea6b --- /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 0000000000..358d77c84c --- /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 0000000000..9208b8301d --- /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 0000000000..56a40263fa --- /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 0000000000..aef7208987 --- /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 0000000000..f1c8e62e7a --- /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 0000000000..cb60db16ca --- /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 0000000000..662e667d3f --- /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 0000000000..61d4ba752a --- /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 1a8c7af42b..55b1eb8044 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 bfff581d9b..cae848a5c1 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 d62f7655ee..c8172caa76 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 f9ac3158a3..b7ce0679c3 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 5cb06ffb7f..7625d1f690 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 0000000000..c7588a5f18 --- /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 0000000000..502f3fc224 --- /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 0000000000..b28b81eeda --- /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 d02ec9661f..c28b9cb71a 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 c1b1d705a4..e46901b856 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 114022d199..afb742d903 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 07ba8367de..340f85df15 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  | 
