]> git.proxmox.com Git - mirror_frr.git/commitdiff
eigrp: Initial Commit
authorDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 9 Mar 2017 04:07:46 +0000 (23:07 -0500)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 9 Mar 2017 04:07:46 +0000 (23:07 -0500)
Please Note, I will be redoing this commit message with
more information.

Additionally I will rework the lib/* changes into their
own commits.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
60 files changed:
Makefile.am
configure.ac
eigrpd/.gitignore [new file with mode: 0644]
eigrpd/EIGRP-MIB.txt [new file with mode: 0644]
eigrpd/Makefile.am [new file with mode: 0644]
eigrpd/eigrp_const.h [new file with mode: 0644]
eigrpd/eigrp_dump.c [new file with mode: 0644]
eigrpd/eigrp_dump.h [new file with mode: 0644]
eigrpd/eigrp_filter.c [new file with mode: 0644]
eigrpd/eigrp_filter.h [new file with mode: 0644]
eigrpd/eigrp_fsm.c [new file with mode: 0644]
eigrpd/eigrp_fsm.h [new file with mode: 0644]
eigrpd/eigrp_hello.c [new file with mode: 0644]
eigrpd/eigrp_interface.c [new file with mode: 0644]
eigrpd/eigrp_interface.h [new file with mode: 0644]
eigrpd/eigrp_macros.h [new file with mode: 0644]
eigrpd/eigrp_main.c [new file with mode: 0644]
eigrpd/eigrp_memory.c [new file with mode: 0644]
eigrpd/eigrp_memory.h [new file with mode: 0644]
eigrpd/eigrp_neighbor.c [new file with mode: 0644]
eigrpd/eigrp_neighbor.h [new file with mode: 0644]
eigrpd/eigrp_network.c [new file with mode: 0644]
eigrpd/eigrp_network.h [new file with mode: 0644]
eigrpd/eigrp_packet.c [new file with mode: 0644]
eigrpd/eigrp_packet.h [new file with mode: 0644]
eigrpd/eigrp_pkt_tlv1.c [new file with mode: 0644]
eigrpd/eigrp_pkt_tlv2.c [new file with mode: 0644]
eigrpd/eigrp_query.c [new file with mode: 0644]
eigrpd/eigrp_reply.c [new file with mode: 0644]
eigrpd/eigrp_routemap.c [new file with mode: 0644]
eigrpd/eigrp_routemap.h [new file with mode: 0644]
eigrpd/eigrp_siaquery.c [new file with mode: 0644]
eigrpd/eigrp_siareply.c [new file with mode: 0644]
eigrpd/eigrp_snmp.c [new file with mode: 0644]
eigrpd/eigrp_snmp.h [new file with mode: 0644]
eigrpd/eigrp_structs.h [new file with mode: 0644]
eigrpd/eigrp_topology.c [new file with mode: 0644]
eigrpd/eigrp_topology.h [new file with mode: 0644]
eigrpd/eigrp_update.c [new file with mode: 0644]
eigrpd/eigrp_vty.c [new file with mode: 0644]
eigrpd/eigrp_vty.h [new file with mode: 0644]
eigrpd/eigrp_zebra.c [new file with mode: 0644]
eigrpd/eigrp_zebra.h [new file with mode: 0644]
eigrpd/eigrpd.c [new file with mode: 0644]
eigrpd/eigrpd.conf.sample [new file with mode: 0644]
eigrpd/eigrpd.h [new file with mode: 0644]
lib/Makefile.am
lib/command.c
lib/command.h
lib/libfrr.c
lib/log.c
lib/route_types.txt
lib/sha256.c [new file with mode: 0644]
lib/sha256.h [new file with mode: 0644]
lib/vty.c
pkgsrc/eigrpd.sh.in [new file with mode: 0644]
vtysh/Makefile.am
vtysh/extract.pl.in
vtysh/vtysh.c
vtysh/vtysh.h

index aa978b7d25df54baca98787069cf95465b72d328..aeacd4c3ce2ecd8827920d6cc095435a2d4b7bf1 100644 (file)
@@ -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 \
index e46e44a8b751f8aa8559923fbe94edc1ca4a74cb..821e0e230bdd0b2f8e50ac899e4187820c0e9bd9 100755 (executable)
@@ -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 (file)
index 0000000..e46af76
--- /dev/null
@@ -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 (file)
index 0000000..f6ea298
--- /dev/null
@@ -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 (file)
index 0000000..89cb72c
--- /dev/null
@@ -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 (file)
index 0000000..a1d09e6
--- /dev/null
@@ -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 (file)
index 0000000..c15eecc
--- /dev/null
@@ -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 (file)
index 0000000..54e6338
--- /dev/null
@@ -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 (file)
index 0000000..aaac379
--- /dev/null
@@ -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 (file)
index 0000000..01c776b
--- /dev/null
@@ -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 (file)
index 0000000..0277dc8
--- /dev/null
@@ -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 (file)
index 0000000..0677c09
--- /dev/null
@@ -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 (file)
index 0000000..df4ed10
--- /dev/null
@@ -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 (file)
index 0000000..18573ca
--- /dev/null
@@ -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 (file)
index 0000000..c7de3b7
--- /dev/null
@@ -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 (file)
index 0000000..dd22829
--- /dev/null
@@ -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 (file)
index 0000000..85a97e7
--- /dev/null
@@ -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 (file)
index 0000000..dabc077
--- /dev/null
@@ -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 (file)
index 0000000..0cafdfb
--- /dev/null
@@ -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 (file)
index 0000000..8dcf76d
--- /dev/null
@@ -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 (file)
index 0000000..e9ddc22
--- /dev/null
@@ -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 (file)
index 0000000..fba7717
--- /dev/null
@@ -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 (file)
index 0000000..87d1280
--- /dev/null
@@ -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 (file)
index 0000000..9a0a989
--- /dev/null
@@ -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 (file)
index 0000000..b8b2815
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/eigrpd/eigrp_pkt_tlv2.c b/eigrpd/eigrp_pkt_tlv2.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/eigrpd/eigrp_query.c b/eigrpd/eigrp_query.c
new file mode 100644 (file)
index 0000000..d4bd379
--- /dev/null
@@ -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 (file)
index 0000000..ff40e2e
--- /dev/null
@@ -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 (file)
index 0000000..9dd5b15
--- /dev/null
@@ -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 (file)
index 0000000..0fee25b
--- /dev/null
@@ -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 (file)
index 0000000..030a86c
--- /dev/null
@@ -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 (file)
index 0000000..b494090
--- /dev/null
@@ -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 (file)
index 0000000..f5dd69f
--- /dev/null
@@ -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 (file)
index 0000000..ab14912
--- /dev/null
@@ -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 (file)
index 0000000..6e90c8c
--- /dev/null
@@ -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 (file)
index 0000000..c8b5351
--- /dev/null
@@ -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 (file)
index 0000000..9f1569e
--- /dev/null
@@ -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 (file)
index 0000000..358d77c
--- /dev/null
@@ -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 (file)
index 0000000..9208b83
--- /dev/null
@@ -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 (file)
index 0000000..56a4026
--- /dev/null
@@ -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 (file)
index 0000000..aef7208
--- /dev/null
@@ -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 (file)
index 0000000..f1c8e62
--- /dev/null
@@ -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 (file)
index 0000000..cb60db1
--- /dev/null
@@ -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 (file)
index 0000000..662e667
--- /dev/null
@@ -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 (file)
index 0000000..61d4ba7
--- /dev/null
@@ -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 */
index 1a8c7af42b78e41230168eccbbff92cc60b99bba..55b1eb8044da0cae370af98d3d7041421a3a480b 100644 (file)
@@ -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 = \
index bfff581d9b2b2288c4fb51c7cf3285e14f5f135d..cae848a5c1c9b0ba06befd1e2f0f2f5f285b7b25 100644 (file)
@@ -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:
index d62f7655eed8cf65ee108e0e0ba51e84655a8609..c8172caa764f5f247c64a86873238e97e3674eaf 100644 (file)
@@ -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"
index f9ac3158a3681736e37a9fc7d49ecc03f59c9411..b7ce0679c3a007d5bfb0c10b187cde7c145694ec 100644 (file)
@@ -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);
index 0fd9621f371fb9c2c05f63f95a4569860ea61ed7..c86eb61af370567e455b403bc34b271d282502ec 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -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"))
index 5cb06ffb7f4db7695565ea54b07f8bc01b09cf57..7625d1f690ac35539281568b35e5b494407b56c9 100644 (file)
@@ -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 (file)
index 0000000..c7588a5
--- /dev/null
@@ -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 (file)
index 0000000..502f3fc
--- /dev/null
@@ -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_ */
index 4d34fead8b82c31b7eeb81611b5269ea0425970e..649b659492d2deb4429badf6df99f531ea8bdcad 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -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 (file)
index 0000000..b28b81e
--- /dev/null
@@ -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"
index d02ec9661fdf26dad9315ff99c5cd78788d09f46..c28b9cb71a801f709a32824dc11163b02cb9d3d1 100644 (file)
@@ -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 \
index c1b1d705a4d5c7368e7ec3909493e3199c074158..e46901b8568216ba4986cd42ed9a6202b7488b0c 100755 (executable)
@@ -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";
index 114022d199269018cf77afaaae2db313686b4c1b..afb742d903740165a910741d27da6e4f0cd1128b 100644 (file)
@@ -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);
index 07ba8367dec0e044834d74c07047ff1b177fb18a..340f85df1596403c27126cc84212d5716eceb25a 100644 (file)
@@ -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