summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am5
-rwxr-xr-xconfigure.ac14
-rw-r--r--eigrpd/.gitignore17
-rw-r--r--eigrpd/EIGRP-MIB.txt1321
-rw-r--r--eigrpd/Makefile.am45
-rw-r--r--eigrpd/eigrp_const.h439
-rw-r--r--eigrpd/eigrp_dump.c768
-rw-r--r--eigrpd/eigrp_dump.h165
-rw-r--r--eigrpd/eigrp_filter.c395
-rw-r--r--eigrpd/eigrp_filter.h44
-rw-r--r--eigrpd/eigrp_fsm.c502
-rw-r--r--eigrpd/eigrp_fsm.h37
-rw-r--r--eigrpd/eigrp_hello.c774
-rw-r--r--eigrpd/eigrp_interface.c613
-rw-r--r--eigrpd/eigrp_interface.h73
-rw-r--r--eigrpd/eigrp_macros.h85
-rw-r--r--eigrpd/eigrp_main.c231
-rw-r--r--eigrpd/eigrp_memory.c43
-rw-r--r--eigrpd/eigrp_memory.h44
-rw-r--r--eigrpd/eigrp_neighbor.c384
-rw-r--r--eigrpd/eigrp_neighbor.h55
-rw-r--r--eigrpd/eigrp_network.c463
-rw-r--r--eigrpd/eigrp_network.h52
-rw-r--r--eigrpd/eigrp_packet.c1441
-rw-r--r--eigrpd/eigrp_packet.h143
-rw-r--r--eigrpd/eigrp_pkt_tlv1.c0
-rw-r--r--eigrpd/eigrp_pkt_tlv2.c0
-rw-r--r--eigrpd/eigrp_query.c226
-rw-r--r--eigrpd/eigrp_reply.c249
-rw-r--r--eigrpd/eigrp_routemap.c1244
-rw-r--r--eigrpd/eigrp_routemap.h18
-rw-r--r--eigrpd/eigrp_siaquery.c164
-rw-r--r--eigrpd/eigrp_siareply.c165
-rw-r--r--eigrpd/eigrp_snmp.c1395
-rw-r--r--eigrpd/eigrp_snmp.h36
-rw-r--r--eigrpd/eigrp_structs.h533
-rw-r--r--eigrpd/eigrp_topology.c586
-rw-r--r--eigrpd/eigrp_topology.h75
-rw-r--r--eigrpd/eigrp_update.c1159
-rw-r--r--eigrpd/eigrp_vty.c1584
-rw-r--r--eigrpd/eigrp_vty.h42
-rw-r--r--eigrpd/eigrp_zebra.c579
-rw-r--r--eigrpd/eigrp_zebra.h43
-rw-r--r--eigrpd/eigrpd.c310
-rw-r--r--eigrpd/eigrpd.conf.sample13
-rw-r--r--eigrpd/eigrpd.h54
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/command.c2
-rw-r--r--lib/command.h2
-rw-r--r--lib/libfrr.c3
-rw-r--r--lib/log.c2
-rw-r--r--lib/route_types.txt2
-rw-r--r--lib/sha256.c425
-rw-r--r--lib/sha256.h58
-rw-r--r--lib/vty.c2
-rw-r--r--pkgsrc/eigrpd.sh.in44
-rw-r--r--vtysh/Makefile.am6
-rwxr-xr-xvtysh/extract.pl.in1
-rw-r--r--vtysh/vtysh.c50
-rw-r--r--vtysh/vtysh.h1
60 files changed, 17222 insertions, 8 deletions
diff --git a/Makefile.am b/Makefile.am
index aa978b7d2..aeacd4c3c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,13 +2,14 @@
SUBDIRS = lib qpb fpm @ZEBRA@ @LIBRFP@ @RFPTEST@ \
@BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @LDPD@ \
- @ISISD@ @PIMD@ @NHRPD@ \
+ @ISISD@ @PIMD@ @NHRPD@ @EIGRPD@ \
@WATCHFRR@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \
redhat @SOLARIS@ tests tools cumulus snapcraft
DIST_SUBDIRS = lib qpb fpm zebra bgpd ripd ripngd ospfd ospf6d ldpd \
isisd watchfrr vtysh ospfclient doc m4 pkgsrc redhat tests \
- solaris pimd nhrpd @LIBRFP@ @RFPTEST@ tools cumulus snapcraft
+ solaris pimd nhrpd eigrpd @LIBRFP@ @RFPTEST@ tools cumulus \
+ snapcraft
EXTRA_DIST = aclocal.m4 SERVICES REPORTING-BUGS \
update-autotools \
diff --git a/configure.ac b/configure.ac
index e46e44a8b..821e0e230 100755
--- a/configure.ac
+++ b/configure.ac
@@ -217,6 +217,8 @@ AC_ARG_ENABLE(ldpd,
AS_HELP_STRING([--enable-ldpd], [build ldpd]))
AC_ARG_ENABLE(nhrpd,
AS_HELP_STRING([--disable-nhrpd], [do not build nhrpd]))
+AC_ARG_ENABLE(eigrpd,
+ AS_HELP_STRING([--disable-eigrpd], [do not build eigrpd]))
AC_ARG_ENABLE(watchfrr,
AS_HELP_STRING([--disable-watchfrr], [do not build watchfrr]))
AC_ARG_ENABLE(isisd,
@@ -1200,6 +1202,13 @@ else
fi
AM_CONDITIONAL(NHRPD, test "x$NHRPD" = "xnhrpd")
+if test "${enable_eigrpd}" = "no";then
+ EIGRPD=""
+else
+ EIGRPD="eigrpd"
+fi
+AM_CONDITIONAL(EIGRPD, test "x$EIGRPD" = "xeigrpd")
+
if test "${enable_watchfrr}" = "no";then
WATCHFRR=""
else
@@ -1281,6 +1290,7 @@ AC_SUBST(OSPFD)
AC_SUBST(OSPF6D)
AC_SUBST(LDPD)
AC_SUBST(NHRPD)
+AC_SUBST(EIGRPD)
AC_SUBST(WATCHFRR)
AC_SUBST(ISISD)
AC_SUBST(PIMD)
@@ -1671,6 +1681,7 @@ AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile
ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile
doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile
pimd/Makefile
+ eigrpd/Makefile
nhrpd/Makefile
redhat/Makefile
tools/Makefile
@@ -1697,7 +1708,8 @@ AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile
doc/zebra.8
doc/frr.1
pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh
- pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh])
+ pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh
+ pkgsrc/eigrpd.sh])
if test "${enable_bgp_vnc}" != "no"; then
if test "${with_rfp_path}" = "bgpd/rfp-example" ; then
diff --git a/eigrpd/.gitignore b/eigrpd/.gitignore
new file mode 100644
index 000000000..e46af767b
--- /dev/null
+++ b/eigrpd/.gitignore
@@ -0,0 +1,17 @@
+Makefile
+Makefile.in
+*.o
+eigrpd
+eigrpd.conf
+tags
+TAGS
+.deps
+.nfs*
+*.lo
+*.la
+*.libs
+.arch-inventory
+.arch-ids
+*~
+*.loT
+
diff --git a/eigrpd/EIGRP-MIB.txt b/eigrpd/EIGRP-MIB.txt
new file mode 100644
index 000000000..f6ea298cf
--- /dev/null
+++ b/eigrpd/EIGRP-MIB.txt
@@ -0,0 +1,1321 @@
+CISCO-EIGRP-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ MODULE-IDENTITY,
+ OBJECT-TYPE,
+ NOTIFICATION-TYPE,
+ Unsigned32,
+ Gauge32,
+ Counter32,
+ Counter64
+ FROM SNMPv2-SMI
+ TruthValue,
+ TEXTUAL-CONVENTION
+ FROM SNMPv2-TC
+ SnmpAdminString
+ FROM SNMP-FRAMEWORK-MIB
+ MODULE-COMPLIANCE,
+ OBJECT-GROUP,
+ NOTIFICATION-GROUP
+ FROM SNMPv2-CONF
+ ciscoMgmt
+ FROM CISCO-SMI
+ InterfaceIndexOrZero,
+ ifIndex
+ FROM IF-MIB
+ InetAddressType,
+ InetAddress,
+ InetAddressPrefixLength
+ FROM INET-ADDRESS-MIB;
+
+ciscoEigrpMIB MODULE-IDENTITY
+ LAST-UPDATED "200411160000Z"
+ ORGANIZATION "Cisco Systems, Inc."
+ CONTACT-INFO "Cisco Systems
+ Customer Service
+
+ Postal: 170 W Tasman Drive
+ San Jose, CA 95134
+ USA
+
+ Tel: +1 800 553-NETS
+
+ E-mail: cs-eigrp@cisco.com"
+ DESCRIPTION
+ "Enhanced Interior Gateway Protocol (EIGRP) is a Cisco
+ proprietary distance vector routing protocol. It is based on
+ the Diffusing Update Algorithm (DUAL), which is a method of
+ finding loop-free paths through a network. Directly
+ connected routers running EIGRP form neighbor adjacencies in
+ order to propagate best-path and alternate-path routing
+ information for configured and learned routes.
+
+ The tables defined within the MIB are closely aligned with how
+ the router command-line interface for EIGRP displays
+ information on EIGRP configurations, i.e., the topology table
+ contains objects associated with the EIGRP topology commands,
+ and the peer table contains objects associated withe EIGRP
+ neighbor commands, etc.
+
+ There are five main tables within this mib:
+
+ EIGRP VPN table
+ Contains information regarding which virtual private
+ networks (VPN) are configured with EIGRP.
+
+ EIGRP traffic statistics table
+ Contains counter & statistcs regarding specific types of
+ EIGRP packets sent and related collective information
+ per VPN and per autonomous system (AS).
+
+ EIGRP topology table
+ Contains information regarding EIGRP routes received in
+ updates and originated locally. EIGRP sends and
+ receives routing updates from adjacent routers running
+ EIGRP with which it formed a peer relationship.
+
+ EIGRP peer (neighbor) table
+ Contains information about neighbor EIGRP routers with
+ which peer adjacencies have been established. EIGRP
+ uses a Hello protocol to form neighbor relationships
+ with directly connected routers also running EIGRP.
+
+ EIGRP interfaces table
+ Contains information and statistics on each of the
+ interfaces on the router over which EIGRP has been
+ configured to run."
+
+
+ REVISION "200411160000Z"
+ DESCRIPTION
+ "Initial version of the MIB module."
+ ::= { ciscoMgmt 449 }
+
+--
+-- Textual Conventions
+--
+
+ EigrpUpTimeString ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "8a"
+ STATUS current
+ DESCRIPTION
+ "Specifies a timer value in days, hours, minutes,
+ and seconds in ASCII format.
+
+ If the up time is less than 24 hours, the number
+ of days will not be reflected and the string will
+ be formatted like this: 'hh:mm:ss', reflecting
+ hours, minutes, and seconds.
+
+ If the up time is greater than 24 hours, EIGRP is
+ less precise and the minutes and seconds are not
+ reflected. Instead only the days and hours are shown
+ and the string will be formatted like this: 'xxxdxxh'."
+ SYNTAX OCTET STRING (SIZE (0..8))
+
+ EigrpVersionString ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1d.1d/1d.1d"
+ STATUS current
+ DESCRIPTION
+ "Specifies an ASCII string representing the IOS major
+ and minor version followed by the EIGRP major and minor
+ version."
+ SYNTAX OCTET STRING (SIZE (0..9))
+
+--
+-- Objects
+--
+
+ cEigrpMIBNotifications OBJECT IDENTIFIER ::= { ciscoEigrpMIB 0 }
+ cEigrpMIBObjects OBJECT IDENTIFIER ::= { ciscoEigrpMIB 1 }
+ cEigrpMIBConformance OBJECT IDENTIFIER ::= { ciscoEigrpMIB 2 }
+ cEigrpVpnInfo OBJECT IDENTIFIER ::= { cEigrpMIBObjects 1 }
+ cEigrpAsInfo OBJECT IDENTIFIER ::= { cEigrpMIBObjects 2 }
+ cEigrpTopologyInfo OBJECT IDENTIFIER ::= { cEigrpMIBObjects 3 }
+ cEigrpPeerInfo OBJECT IDENTIFIER ::= { cEigrpMIBObjects 4 }
+ cEigrpInterfaceInfo OBJECT IDENTIFIER ::= { cEigrpMIBObjects 5 }
+
+ -- EIGRP VPN Base Table definition
+
+ cEigrpVpnTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF CEigrpVpnEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table contains information on those VPN's configured
+ to run EIGRP. The VPN creation on a router is independent
+ of the routing protocol to be used over it. A VPN is
+ given a name and has a dedicated routing table associated
+ with it. This routing table is identified internally
+ by a unique integer value."
+ ::= { cEigrpVpnInfo 1 }
+
+ cEigrpVpnEntry OBJECT-TYPE
+ SYNTAX CEigrpVpnEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information relating to a single VPN which is configured
+ to run EIGRP."
+ INDEX { cEigrpVpnId }
+ ::= { cEigrpVpnTable 1 }
+
+ CEigrpVpnEntry ::=
+ SEQUENCE {
+ cEigrpVpnId Unsigned32,
+ cEigrpVpnName SnmpAdminString
+ }
+
+ cEigrpVpnId OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The unique VPN identifier. This is a unique integer
+ relative to all other VPN's defined on the router. It
+ also identifies internally the routing table instance."
+ ::= { cEigrpVpnEntry 1 }
+
+ cEigrpVpnName OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name given to the VPN."
+ ::= { cEigrpVpnEntry 2 }
+
+ -- EIGRP Traffic Stats table definition
+
+ cEigrpTraffStatsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF CEigrpTraffStatsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Table of EIGRP traffic statistics and information
+ associated with all EIGRP autonomous systems."
+ ::= { cEigrpAsInfo 1 }
+
+ cEigrpTraffStatsEntry OBJECT-TYPE
+ SYNTAX CEigrpTraffStatsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The set of statistics and information for a single EIGRP
+ Autonomous System."
+ INDEX { cEigrpVpnId, cEigrpAsNumber }
+ ::= { cEigrpTraffStatsTable 1 }
+
+ CEigrpTraffStatsEntry ::=
+ SEQUENCE {
+ cEigrpAsNumber Unsigned32,
+ cEigrpNbrCount Unsigned32,
+ cEigrpHellosSent Counter32,
+ cEigrpHellosRcvd Counter32,
+ cEigrpUpdatesSent Counter32,
+ cEigrpUpdatesRcvd Counter32,
+ cEigrpQueriesSent Counter32,
+ cEigrpQueriesRcvd Counter32,
+ cEigrpRepliesSent Counter32,
+ cEigrpRepliesRcvd Counter32,
+ cEigrpAcksSent Counter32,
+ cEigrpAcksRcvd Counter32,
+ cEigrpInputQHighMark Unsigned32,
+ cEigrpInputQDrops Counter32,
+ cEigrpSiaQueriesSent Counter32,
+ cEigrpSiaQueriesRcvd Counter32,
+ cEigrpAsRouterIdType InetAddressType,
+ cEigrpAsRouterId InetAddress,
+ cEigrpTopoRoutes Counter32,
+ cEigrpHeadSerial Counter64,
+ cEigrpNextSerial Counter64,
+ cEigrpXmitPendReplies Unsigned32,
+ cEigrpXmitDummies Unsigned32
+ }
+
+ cEigrpAsNumber OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The Autonomous System number which is unique integer
+ per VPN."
+ ::= { cEigrpTraffStatsEntry 1 }
+
+ cEigrpNbrCount OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of live EIGRP neighbors formed on all
+ interfaces whose IP addresses fall under networks configured
+ in the EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 2 }
+
+ cEigrpHellosSent OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number Hello packets that have been sent to all
+ EIGRP neighbors formed on all interfaces whose IP addresses
+ fall under networks configured for the EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 3 }
+
+ cEigrpHellosRcvd OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number Hello packets that have been received
+ from all EIGRP neighbors formed on all interfaces whose IP
+ addresses fall under networks configured for the
+ EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 4 }
+
+ cEigrpUpdatesSent OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number routing update packets that have been
+ sent to all EIGRP neighbors formed on all interfaces whose
+ IP addresses fall under networks configured for the
+ EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 5 }
+
+ cEigrpUpdatesRcvd OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number routing update packets that have been
+ received from all EIGRP neighbors formed on all interfaces
+ whose IP addresses fall under networks configured for the
+ EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 6 }
+
+ cEigrpQueriesSent OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number alternate route query packets that have
+ been sent to all EIGRP neighbors formed on all interfaces
+ whose IP addresses fall under networks configured for the
+ EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 7 }
+
+ cEigrpQueriesRcvd OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number alternate route query packets that
+ have been received from all EIGRP neighbors formed on
+ all interfaces whose IP addresses fall under networks
+ configured for the EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 8 }
+
+ cEigrpRepliesSent OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number query reply packets that have been sent
+ to all EIGRP neighbors formed on all interfaces whose IP
+ addresses fall under networks configured for the
+ EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 9 }
+
+ cEigrpRepliesRcvd OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number query reply packets that have been
+ received from all EIGRP neighbors formed on all interfaces
+ whose IP addresses fall under networks configured for the
+ EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 10 }
+
+ cEigrpAcksSent OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number packet acknowledgements that have been
+ sent to all EIGRP neighbors formed on all interfaces whose
+ IP addresses fall under networks configured for the
+ EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 11 }
+
+ cEigrpAcksRcvd OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number packet acknowledgements that have been
+ received from all EIGRP neighbors formed on all interfaces
+ whose IP addresses fall under networks configured for the
+ EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 12 }
+
+ cEigrpInputQHighMark OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The highest number of EIGRP packets in the input queue
+ waiting to be processed internally addressed to this
+ AS."
+ ::= { cEigrpTraffStatsEntry 13 }
+
+ cEigrpInputQDrops OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of EIGRP packets dropped from the input
+ queue due to it being full within the AS."
+ ::= { cEigrpTraffStatsEntry 14 }
+
+ cEigrpSiaQueriesSent OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of Stuck-In-Active (SIA) query packets
+ sent to all EIGRP neighbors formed on all interfaces whose
+ IP addresses fall under networks configured for the
+ EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 15 }
+
+ cEigrpSiaQueriesRcvd OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of Stuck-In-Active (SIA) query packets
+ received from all EIGRP neighbors formed on all interfaces
+ whose IP addresses fall under networks configured for the
+ EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 16 }
+
+ cEigrpAsRouterIdType OBJECT-TYPE
+ SYNTAX InetAddressType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The format of the router-id configured or automatically
+ selected for the EIGRP AS."
+ ::= { cEigrpTraffStatsEntry 17 }
+
+ cEigrpAsRouterId OBJECT-TYPE
+ SYNTAX InetAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The router-id configured or automatically selected for the
+ EIGRP AS. Each EIGRP routing process has a unique
+ router-id selected from each autonomous system configured.
+ The format is governed by object cEigrpAsRouterIdType."
+ ::= { cEigrpTraffStatsEntry 18 }
+
+ cEigrpTopoRoutes OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of EIGRP derived routes currently existing
+ in the topology table for the AS."
+ ::= { cEigrpTraffStatsEntry 19 }
+
+ cEigrpHeadSerial OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Routes in a topology table for an AS are assigned serial
+ numbers and are sequenced internally as they are inserted
+ and deleted. The serial number of the first route in
+ that internal sequence is called the head serial number.
+ Each AS has its own topology table, and its own serial
+ number space, each of which begins with the value 1.
+ A serial number of zero implies that there are no routes
+ in the topology."
+ ::= { cEigrpTraffStatsEntry 20 }
+
+ cEigrpNextSerial OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The serial number that would be assigned to the next new
+ or changed route in the topology table for the AS."
+ ::= { cEigrpTraffStatsEntry 21 }
+
+ cEigrpXmitPendReplies OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "When alternate route query packets are sent to adjacent
+ EIGRP peers in an AS, replies are expected. This object
+ is the total number of outstanding replies expected to
+ queries that have been sent to peers in the current AS.
+ It remains at zero most of the time until an EIGRP route
+ becomes active."
+ ::= { cEigrpTraffStatsEntry 22 }
+
+ cEigrpXmitDummies OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A dummy is a temporary internal entity used as a place
+ holder in the topology table for an AS. They are not
+ transmitted in routing updates. This is the total
+ number currently in existence associated with the AS."
+ ::= { cEigrpTraffStatsEntry 23 }
+
+ -- EIGRP topology table definition
+
+ cEigrpTopoTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF CEigrpTopoEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The table of EIGRP routes and their associated
+ attributes for an Autonomous System (AS) configured
+ in a VPN is called a topology table. All route entries in
+ the topology table will be indexed by IP network type,
+ IP network number and network mask (prefix) size."
+ ::= { cEigrpTopologyInfo 1 }
+
+ cEigrpTopoEntry OBJECT-TYPE
+ SYNTAX CEigrpTopoEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The entry for a single EIGRP topology table in the given
+ AS."
+ INDEX { cEigrpVpnId, cEigrpAsNumber, cEigrpDestNetType,
+ cEigrpDestNet, cEigrpDestNetPrefixLen }
+ ::= { cEigrpTopoTable 1 }
+
+ CEigrpTopoEntry ::=
+ SEQUENCE {
+ cEigrpDestNetType InetAddressType,
+ cEigrpDestNet InetAddress,
+ cEigrpDestNetPrefixLen InetAddressPrefixLength,
+ cEigrpActive TruthValue,
+ cEigrpStuckInActive TruthValue,
+ cEigrpDestSuccessors Unsigned32,
+ cEigrpFdistance Unsigned32,
+ cEigrpRouteOriginType SnmpAdminString,
+ cEigrpRouteOriginAddrType InetAddressType,
+ cEigrpRouteOriginAddr InetAddress,
+ cEigrpNextHopAddressType InetAddressType,
+ cEigrpNextHopAddress InetAddress,
+ cEigrpNextHopInterface SnmpAdminString,
+ cEigrpDistance Unsigned32,
+ cEigrpReportDistance Unsigned32
+ }
+
+ cEigrpDestNetType OBJECT-TYPE
+ SYNTAX InetAddressType
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The format of the destination IP network number for
+ a single route in the topology table in the AS specified
+ in cEigrpDestNet."
+ ::= { cEigrpTopoEntry 1 }
+
+ cEigrpDestNet OBJECT-TYPE
+ SYNTAX InetAddress
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The destination IP network number for a single route in
+ the topology table in the AS. The format is governed
+ by object cEigrpDestNetType."
+ ::= { cEigrpTopoEntry 2 }
+
+ cEigrpDestNetPrefixLen OBJECT-TYPE
+ SYNTAX InetAddressPrefixLength
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The prefix length associated with the destination IP
+ network address for a single route in the topology
+ table in the AS. The format is governed by the object
+ cEigrpDestNetType."
+ ::= { cEigrpTopoEntry 4 }
+
+ cEigrpActive OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A value of true(1) indicates the route to the
+ destination network has failed and an active (query)
+ search for an alternative path is in progress. A value
+ of false(2) indicates the route is stable (passive)."
+ ::= { cEigrpTopoEntry 5 }
+
+ cEigrpStuckInActive OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A value of true(1) indicates that that this route which is
+ in active state (cEigrpActive = true(1)) has not received
+ any replies to queries for alternate paths, and a second
+ EIGRP route query, called a stuck-in-active query, has
+ now been sent."
+ ::= { cEigrpTopoEntry 6 }
+
+ cEigrpDestSuccessors OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A successor is the next routing hop for a path to the
+ destination IP network number for a single route in the
+ topology table in the AS. There can be several
+ potential successors if there are multiple paths to the
+ destination. This is the total number of successors for
+ a topology entry."
+ ::= { cEigrpTopoEntry 7 }
+
+ cEigrpFdistance OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The feasibility (best) distance is the minimum distance
+ from this router to the destination IP network in
+ this topology entry. The feasibility distance is
+ used in determining the best successor for a path to the
+ destination network."
+ ::= { cEigrpTopoEntry 8 }
+
+ cEigrpRouteOriginType OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This is a text string describing the internal origin
+ of the EIGRP route represented by the topology entry."
+ ::= { cEigrpTopoEntry 9 }
+
+ cEigrpRouteOriginAddrType OBJECT-TYPE
+ SYNTAX InetAddressType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The format of the IP address defined as the origin of
+ this topology route entry."
+ ::= { cEigrpTopoEntry 10 }
+
+ cEigrpRouteOriginAddr OBJECT-TYPE
+ SYNTAX InetAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "If the origin of the topology route entry is external
+ to this router, then this object is the IP address
+ of the router from which it originated. The format
+ is governed by object cEigrpRouteOriginAddrType."
+ ::= { cEigrpTopoEntry 11 }
+
+ cEigrpNextHopAddressType OBJECT-TYPE
+ SYNTAX InetAddressType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The format of the next hop IP address for the route
+ represented by the topology entry."
+ ::= { cEigrpTopoEntry 12 }
+
+ cEigrpNextHopAddress OBJECT-TYPE
+ SYNTAX InetAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This is the next hop IP address for the route represented
+ by the topology entry. The next hop is where
+ network traffic will be routed to in order to reach
+ the destination network for this topology entry. The
+ format is governed by cEigrpNextHopAddressType."
+ ::= { cEigrpTopoEntry 13 }
+
+ cEigrpNextHopInterface OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The interface through which the next hop IP address
+ is reached to send network traffic to the destination
+ network represented by the topology entry."
+ ::= { cEigrpTopoEntry 14 }
+
+ cEigrpDistance OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The computed distance to the destination network entry
+ from this router."
+ ::= { cEigrpTopoEntry 15 }
+
+ cEigrpReportDistance OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The computed distance to the destination network in the
+ topology entry reported to this router by the originator
+ of this route."
+ ::= { cEigrpTopoEntry 16 }
+
+ -- EIGRP Peer table per VPN and AS (expansion table)
+
+ cEigrpPeerTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF CEigrpPeerEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The table of established EIGRP peers (neighbors) in the
+ selected autonomous system. Peers are indexed by their
+ unique internal handle id, as well as the AS number and
+ VPN id. The peer entry is removed from the table if
+ the peer is declared down."
+ ::= { cEigrpPeerInfo 1 }
+
+ cEigrpPeerEntry OBJECT-TYPE
+ SYNTAX CEigrpPeerEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Statistics and operational parameters for a single peer
+ in the AS."
+ INDEX { cEigrpVpnId, cEigrpAsNumber, cEigrpHandle }
+ ::= { cEigrpPeerTable 1 }
+
+ CEigrpPeerEntry ::=
+ SEQUENCE {
+ cEigrpHandle Unsigned32,
+ cEigrpPeerAddrType InetAddressType,
+ cEigrpPeerAddr InetAddress,
+ cEigrpPeerIfIndex InterfaceIndexOrZero,
+ cEigrpHoldTime Unsigned32,
+ cEigrpUpTime EigrpUpTimeString,
+ cEigrpSrtt Unsigned32,
+ cEigrpRto Unsigned32,
+ cEigrpPktsEnqueued Unsigned32,
+ cEigrpLastSeq Unsigned32,
+ cEigrpVersion EigrpVersionString,
+ cEigrpRetrans Counter32,
+ cEigrpRetries Unsigned32
+ }
+
+ cEigrpHandle OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The unique internal identifier for the peer in the AS.
+ This is a unique value among peer entries in a selected
+ table."
+ ::= { cEigrpPeerEntry 1 }
+
+ cEigrpPeerAddrType OBJECT-TYPE
+ SYNTAX InetAddressType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The format of the remote source IP address used by the
+ peer to establish the EIGRP adjacency with this router."
+ ::= { cEigrpPeerEntry 2 }
+
+ cEigrpPeerAddr OBJECT-TYPE
+ SYNTAX InetAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The source IP address used by the peer to establish the
+ EIGRP adjacency with this router. The format is
+ governed by object cEigrpPeerAddrType."
+ ::= { cEigrpPeerEntry 3 }
+
+ cEigrpPeerIfIndex OBJECT-TYPE
+ SYNTAX InterfaceIndexOrZero
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The ifIndex of the interface on this router through
+ which this peer can be reached."
+ ::= { cEigrpPeerEntry 4 }
+
+ cEigrpHoldTime OBJECT-TYPE
+ SYNTAX Unsigned32
+ UNITS "seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The count-down timer indicating how much time must
+ pass without receiving a hello packet from this
+ EIGRP peer before this router declares the peer down.
+ A peer declared as down is removed from the table and
+ is no longer visible."
+ ::= { cEigrpPeerEntry 5 }
+
+ cEigrpUpTime OBJECT-TYPE
+ SYNTAX EigrpUpTimeString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The elapsed time since the EIGRP adjacency was first
+ established with the peer."
+ ::= { cEigrpPeerEntry 6 }
+
+ cEigrpSrtt OBJECT-TYPE
+ SYNTAX Unsigned32
+ UNITS "milliseconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The computed smooth round trip time for packets to and
+ from the peer."
+ ::= { cEigrpPeerEntry 7 }
+
+ cEigrpRto OBJECT-TYPE
+ SYNTAX Unsigned32
+ UNITS "milliseconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The computed retransmission timeout for the peer.
+ This value is computed over time as packets are sent to
+ the peer and acknowledgements are received from it,
+ and is the amount of time to wait before resending
+ a packet from the retransmission queue to the peer
+ when an expected acknowledgement has not been received."
+ ::= { cEigrpPeerEntry 8 }
+
+ cEigrpPktsEnqueued OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of any EIGRP packets currently enqueued
+ waiting to be sent to this peer."
+ ::= { cEigrpPeerEntry 9 }
+
+ cEigrpLastSeq OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "All transmitted EIGRP packets have a sequence number
+ assigned. This is the sequence number of the last EIGRP
+ packet sent to this peer."
+ ::= { cEigrpPeerEntry 10 }
+
+ cEigrpVersion OBJECT-TYPE
+ SYNTAX EigrpVersionString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The EIGRP version information reported by the remote
+ peer."
+ ::= { cEigrpPeerEntry 11 }
+
+ cEigrpRetrans OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The cumulative number of retransmissions to this peer
+ during the period that the peer adjacency has remained
+ up."
+ ::= { cEigrpPeerEntry 12 }
+
+ cEigrpRetries OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times the current unacknowledged packet
+ has been retried, i.e. resent to this peer to be
+ acknowledged."
+ ::= { cEigrpPeerEntry 13 }
+
+ -- EIGRP Interfaces table per VPN and AS
+
+ cEigrpInterfaceTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF CEigrpInterfaceEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The table of interfaces over which EIGRP is running, and
+ their associated statistics. This table is independent
+ of whether any peer adjacencies have been formed over
+ the interfaces or not. Interfaces running EIGRP are
+ determined by whether their assigned IP addresses fall
+ within configured EIGRP network statements."
+ ::= { cEigrpInterfaceInfo 1 }
+
+ cEigrpInterfaceEntry OBJECT-TYPE
+ SYNTAX CEigrpInterfaceEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information for a single interface running EIGRP in the
+ AS and VPN."
+ INDEX { cEigrpVpnId, cEigrpAsNumber, ifIndex }
+ ::= { cEigrpInterfaceTable 1 }
+
+ CEigrpInterfaceEntry ::=
+ SEQUENCE {
+ cEigrpPeerCount Gauge32,
+ cEigrpXmitReliableQ Gauge32,
+ cEigrpXmitUnreliableQ Gauge32,
+ cEigrpMeanSrtt Unsigned32,
+ cEigrpPacingReliable Unsigned32,
+ cEigrpPacingUnreliable Unsigned32,
+ cEigrpMFlowTimer Unsigned32,
+ cEigrpPendingRoutes Gauge32,
+ cEigrpHelloInterval Unsigned32,
+ cEigrpXmitNextSerial Counter64,
+ cEigrpUMcasts Counter32,
+ cEigrpRMcasts Counter32,
+ cEigrpUUcasts Counter32,
+ cEigrpRUcasts Counter32,
+ cEigrpMcastExcepts Counter32,
+ cEigrpCRpkts Counter32,
+ cEigrpAcksSuppressed Counter32,
+ cEigrpRetransSent Counter32,
+ cEigrpOOSrcvd Counter32,
+ cEigrpAuthMode INTEGER,
+ cEigrpAuthKeyChain SnmpAdminString
+ }
+
+ cEigrpPeerCount OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of EIGRP adjacencies currently formed with
+ peers reached through this interface."
+ ::= { cEigrpInterfaceEntry 3 }
+
+ cEigrpXmitReliableQ OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of EIGRP packets currently waiting in the
+ reliable transport (acknowledgement-required)
+ transmission queue to be sent to a peer."
+ ::= { cEigrpInterfaceEntry 4 }
+
+ cEigrpXmitUnreliableQ OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number EIGRP of packets currently waiting in
+ the unreliable transport (no acknowledgement required)
+ transmission queue."
+ ::= { cEigrpInterfaceEntry 5 }
+
+ cEigrpMeanSrtt OBJECT-TYPE
+ SYNTAX Unsigned32
+ UNITS "milliseconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The average of all the computed smooth round trip time
+ values for a packet to and from all peers established on
+ this interface."
+ ::= { cEigrpInterfaceEntry 6 }
+
+ cEigrpPacingReliable OBJECT-TYPE
+ SYNTAX Unsigned32
+ UNITS "milliseconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The configured time interval between EIGRP packet
+ transmissions on the interface when the reliable transport
+ method is used."
+ ::= { cEigrpInterfaceEntry 7 }
+
+ cEigrpPacingUnreliable OBJECT-TYPE
+ SYNTAX Unsigned32
+ UNITS "milliseconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The configured time interval between EIGRP packet
+ transmissions on the interface when the unreliable
+ transport method is used."
+ ::= { cEigrpInterfaceEntry 8 }
+
+ cEigrpMFlowTimer OBJECT-TYPE
+ SYNTAX Unsigned32
+ UNITS "milliseconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The configured multicast flow control timer value for
+ this interface."
+ ::= { cEigrpInterfaceEntry 9 }
+
+ cEigrpPendingRoutes OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of queued EIGRP routing updates awaiting
+ transmission on this interface."
+ ::= { cEigrpInterfaceEntry 10 }
+
+ cEigrpHelloInterval OBJECT-TYPE
+ SYNTAX Unsigned32
+ UNITS "seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The configured time interval between Hello packet
+ transmissions for this interface."
+ ::= { cEigrpInterfaceEntry 11 }
+
+ cEigrpXmitNextSerial OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The serial number of the next EIGRP packet that is to
+ be queued for transmission on this interface."
+ ::= { cEigrpInterfaceEntry 12 }
+
+ cEigrpUMcasts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of unreliable (no acknowledgement
+ required) EIGRP multicast packets sent on this
+ interface."
+ ::= { cEigrpInterfaceEntry 13 }
+
+ cEigrpRMcasts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of reliable (acknowledgement required)
+ EIGRP multicast packets sent on this interface."
+ ::= { cEigrpInterfaceEntry 14 }
+
+ cEigrpUUcasts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of unreliable (no acknowledgement
+ required) EIGRP unicast packets sent on this
+ interface."
+ ::= { cEigrpInterfaceEntry 15 }
+
+ cEigrpRUcasts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of reliable (acknowledgement required)
+ unicast packets sent on this interface."
+ ::= { cEigrpInterfaceEntry 16 }
+
+ cEigrpMcastExcepts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of EIGRP multicast exception
+ transmissions that have occurred on this interface."
+ ::= { cEigrpInterfaceEntry 17 }
+
+ cEigrpCRpkts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number EIGRP Conditional-Receive packets sent on
+ this interface."
+ ::= { cEigrpInterfaceEntry 18 }
+
+ cEigrpAcksSuppressed OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of individual EIGRP acknowledgement
+ packets that have been suppressed and combined in
+ an already enqueued outbound reliable packet on this
+ interface."
+ ::= { cEigrpInterfaceEntry 19 }
+
+ cEigrpRetransSent OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number EIGRP packet retransmissions sent on
+ the interface."
+ ::= { cEigrpInterfaceEntry 20 }
+
+ cEigrpOOSrcvd OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of out-of-sequence EIGRP packets
+ received."
+ ::= { cEigrpInterfaceEntry 21 }
+
+ cEigrpAuthMode OBJECT-TYPE
+ SYNTAX INTEGER {
+ none(1),
+ md5(2)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The EIGRP authentication mode of the interface.
+ none : no authentication enabled on the interface
+ md5 : MD5 authentication enabled on the interface"
+ ::= { cEigrpInterfaceEntry 22 }
+
+ cEigrpAuthKeyChain OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name of the authentication key-chain configured
+ on this interface. The key-chain is a reference to
+ which set of secret keys are to be accessed in order
+ to determine which secret key string to use. The key
+ chain name is not the secret key string password and
+ can also be used in other routing protocols, such
+ as RIP and ISIS."
+ ::= { cEigrpInterfaceEntry 23 }
+
+ -- Notifications
+
+ cEigrpAuthFailureEvent NOTIFICATION-TYPE
+ OBJECTS { cEigrpPeerAddrType, cEigrpPeerAddr }
+ STATUS current
+ DESCRIPTION
+ "This notification is sent when EIGRP MD5 authentication
+ is enabled on any interface and peer adjacencies are
+ formed, and any adjacencies go down as a result of an
+ authentication failure."
+ ::= { cEigrpMIBNotifications 1 }
+
+ cEigrpRouteStuckInActive NOTIFICATION-TYPE
+ OBJECTS { cEigrpPeerAddrType, cEigrpPeerAddr,
+ cEigrpStuckInActive }
+ STATUS current
+ DESCRIPTION
+ "This notification is sent when a route in the topology
+ table is stuck in an active state. During the query
+ phase for a new route to a destination network, a route
+ is described as being in the active state if when an
+ alternate path is actively being sought, no replies are
+ received to normal queries or stuck-in-active queries."
+ ::= { cEigrpMIBNotifications 2 }
+
+ -- Conformance
+
+ cEigrpMIBCompliances
+ OBJECT IDENTIFIER ::= { cEigrpMIBConformance 1 }
+
+ cEigrpMIBGroups
+ OBJECT IDENTIFIER ::= { cEigrpMIBConformance 2 }
+
+ -- Compliance
+
+ cEigrpMIBCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for entities which implement
+ the Cisco EIGRP Management MIB."
+ MODULE
+ MANDATORY-GROUPS {
+ cEigrpVpnDataGroup,
+ cEigrpTrafficStatsGroup,
+ cEigrpInterfaceDataGroup,
+ cEigrpPeerDataGroup,
+ cEigrpTopoDataGroup,
+ cEigrpNotificationsGroup
+ }
+
+ OBJECT cEigrpAsRouterIdType
+ SYNTAX INTEGER { ipv4(1) }
+ DESCRIPTION
+ "An implementation is only required to support
+ IPv4 address type."
+
+ OBJECT cEigrpRouteOriginAddrType
+ SYNTAX INTEGER { ipv4(1) }
+ DESCRIPTION
+ "An implementation is only required to support
+ IPv4 address type."
+
+ OBJECT cEigrpNextHopAddressType
+ SYNTAX INTEGER { ipv4(1) }
+ DESCRIPTION
+ "An implementation is only required to support
+ IPv4 address type."
+
+ OBJECT cEigrpPeerAddrType
+ SYNTAX INTEGER { ipv4(1) }
+ DESCRIPTION
+ "An implementation is only required to support
+ IPv4 address type."
+ ::= { cEigrpMIBCompliances 1 }
+
+ -- Units of Conformance
+
+ cEigrpVpnDataGroup OBJECT-GROUP
+ OBJECTS {
+ cEigrpVpnName
+ }
+ STATUS current
+ DESCRIPTION
+ "The collection of VPN names which have been configured
+ with one or more EIGRP autonmous systems."
+ ::= { cEigrpMIBGroups 1 }
+
+ cEigrpTrafficStatsGroup OBJECT-GROUP
+ OBJECTS {
+ cEigrpHellosSent,
+ cEigrpHellosRcvd,
+ cEigrpUpdatesSent,
+ cEigrpUpdatesRcvd,
+ cEigrpQueriesSent,
+ cEigrpQueriesRcvd,
+ cEigrpRepliesSent,
+ cEigrpRepliesRcvd,
+ cEigrpAcksSent,
+ cEigrpAcksRcvd,
+ cEigrpInputQHighMark,
+ cEigrpInputQDrops,
+ cEigrpSiaQueriesSent,
+ cEigrpSiaQueriesRcvd
+ }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing management information
+ regarding collective EIGRP packet statistics for all EIGRP
+ autonomous systems configured."
+ ::= { cEigrpMIBGroups 2 }
+
+ cEigrpInterfaceDataGroup OBJECT-GROUP
+ OBJECTS {
+ cEigrpPeerCount,
+ cEigrpXmitReliableQ,
+ cEigrpXmitUnreliableQ,
+ cEigrpMeanSrtt,
+ cEigrpPacingReliable,
+ cEigrpPacingUnreliable,
+ cEigrpMFlowTimer,
+ cEigrpPendingRoutes,
+ cEigrpHelloInterval,
+ cEigrpXmitNextSerial,
+ cEigrpUMcasts,
+ cEigrpRMcasts,
+ cEigrpUUcasts,
+ cEigrpRUcasts,
+ cEigrpMcastExcepts,
+ cEigrpCRpkts,
+ cEigrpAcksSuppressed,
+ cEigrpRetransSent,
+ cEigrpOOSrcvd,
+ cEigrpAuthMode,
+ cEigrpAuthKeyChain
+ }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing management information
+ for interfaces over which EIGRP is configured and
+ running."
+ ::= { cEigrpMIBGroups 3 }
+
+ cEigrpPeerDataGroup OBJECT-GROUP
+ OBJECTS {
+ cEigrpNbrCount,
+ cEigrpPeerAddrType,
+ cEigrpPeerAddr,
+ cEigrpPeerIfIndex,
+ cEigrpHoldTime,
+ cEigrpUpTime,
+ cEigrpSrtt,
+ cEigrpRto,
+ cEigrpPktsEnqueued,
+ cEigrpLastSeq,
+ cEigrpVersion,
+ cEigrpRetrans,
+ cEigrpRetries
+ }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing management information
+ for EIGRP peer adjacencies formed in the EIGRP
+ autonoumous systems."
+ ::= { cEigrpMIBGroups 4 }
+
+ cEigrpTopoDataGroup OBJECT-GROUP
+ OBJECTS {
+ cEigrpAsRouterId,
+ cEigrpAsRouterIdType,
+ cEigrpTopoRoutes,
+ cEigrpHeadSerial,
+ cEigrpNextSerial,
+ cEigrpXmitPendReplies,
+ cEigrpXmitDummies,
+ cEigrpActive,
+ cEigrpStuckInActive,
+ cEigrpDestSuccessors,
+ cEigrpFdistance,
+ cEigrpRouteOriginType,
+ cEigrpRouteOriginAddrType,
+ cEigrpRouteOriginAddr,
+ cEigrpNextHopAddressType,
+ cEigrpNextHopAddress,
+ cEigrpNextHopInterface,
+ cEigrpDistance,
+ cEigrpReportDistance
+ }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing management information
+ for EIGRP topology routes derived within autonomous
+ systems and received in updates from EIGRP neighbors."
+ ::= { cEigrpMIBGroups 5 }
+
+ cEigrpNotificationsGroup NOTIFICATION-GROUP
+ NOTIFICATIONS {
+ cEigrpAuthFailureEvent,
+ cEigrpRouteStuckInActive
+ }
+ STATUS current
+ DESCRIPTION
+ "Group of notifications on EIGRP routers."
+ ::= { cEigrpMIBGroups 6 }
+END \ No newline at end of file
diff --git a/eigrpd/Makefile.am b/eigrpd/Makefile.am
new file mode 100644
index 000000000..89cb72cfd
--- /dev/null
+++ b/eigrpd/Makefile.am
@@ -0,0 +1,45 @@
+## Process this file with automake to produce Makefile.in.
+
+AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+INSTALL_SDATA=@INSTALL@ -m 600
+
+AM_CFLAGS = $(WERROR)
+
+noinst_LIBRARIES = libeigrp.a
+sbin_PROGRAMS = eigrpd
+
+libeigrp_a_SOURCES = \
+ eigrpd.c eigrp_zebra.c \
+ eigrp_interface.c eigrp_neighbor.c \
+ eigrp_dump.c eigrp_vty.c \
+ eigrp_network.c eigrp_packet.c \
+ eigrp_topology.c eigrp_fsm.c \
+ eigrp_hello.c eigrp_update.c \
+ eigrp_query.c eigrp_reply.c \
+ eigrp_snmp.c eigrp_siaquery.c \
+ eigrp_siareply.c eigrp_filter.c \
+ eigrp_memory.c
+
+
+eigrpdheaderdir = $(pkgincludedir)/eigrpd
+
+eigrpdheader_HEADERS = \
+ eigrp_topology.h eigrp_dump.h eigrpd.h
+
+noinst_HEADERS = \
+ eigrp_const.h eigrp_structs.h \
+ eigrp_macros.h eigrp_interface.h \
+ eigrp_neighbor.h eigrp_network.h \
+ eigrp_packet.h eigrp_memory.h \
+ eigrp_zebra.h eigrp_vty.h \
+ eigrp_snmp.h eigrp_filter.h
+
+eigrpd_SOURCES = eigrp_main.c $(libeigrp_a_SOURCES)
+
+eigrpd_LDADD = ../lib/libfrr.la @LIBCAP@
+
+EXTRA_DIST = EIGRP-MIB.txt
+
+examplesdir = $(exampledir)
+dist_examples_DATA = eigrpd.conf.sample
diff --git a/eigrpd/eigrp_const.h b/eigrpd/eigrp_const.h
new file mode 100644
index 000000000..a1d09e684
--- /dev/null
+++ b/eigrpd/eigrp_const.h
@@ -0,0 +1,439 @@
+/*
+ * EIGRP Definition of Constants.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_CONST_H_
+#define _ZEBRA_EIGRP_CONST_H_
+
+#define FALSE 0
+
+#define EIGRP_NEIGHBOR_DOWN 0
+#define EIGRP_NEIGHBOR_PENDING 1
+#define EIGRP_NEIGHBOR_UP 2
+#define EIGRP_NEIGHBOR_STATE_MAX 3
+
+/*Packet requiring ack will be retransmitted again after this time*/
+#define EIGRP_PACKET_RETRANS_TIME 2 /* in seconds */
+#define EIGRP_PACKET_RETRANS_MAX 16 /* number of retrans attempts */
+#define PLAINTEXT_LENGTH 81
+
+/*Metric variance multiplier*/
+#define EIGRP_VARIANCE_DEFAULT 1
+#define EIGRP_MAX_PATHS_DEFAULT 4
+
+
+/* Return values of functions involved in packet verification */
+#define MSG_OK 0
+#define MSG_NG 1
+
+#define EIGRP_HEADER_VERSION 2
+
+/* Default protocol, port number. */
+#ifndef IPPROTO_EIGRPIGP
+#define IPPROTO_EIGRPIGP 88
+#endif /* IPPROTO_EIGRPIGP */
+
+#define EIGRP_AUTH_MD5_TLV_SIZE 40
+#define EIGRP_AUTH_SHA256_TLV_SIZE 56
+
+/*Cisco routers use only first 44 bytes of basic hello for their MD5 calculations*/
+#define EIGRP_MD5_BASIC_COMPUTE 44
+#define EIGRP_MD5_UPDATE_INIT_COMPUTE 40
+
+
+
+#define EIGRP_AUTH_BASIC_HELLO_FLAG 0x01
+#define EIGRP_AUTH_TID_HELLO_FLAG 0x02
+#define EIGRP_AUTH_UPDATE_INIT_FLAG 0x04
+#define EIGRP_AUTH_UPDATE_FLAG 0x08
+#define EIGRP_AUTH_EXTRA_SALT_FLAG 0x10
+
+#define EIGRP_NEXT_SEQUENCE_TLV_SIZE 8
+
+/* IP TTL for EIGRP protocol. */
+#define EIGRP_IP_TTL 1
+
+/* VTY port number. */
+#define EIGRP_VTY_PORT 2609
+
+/* Default configuration file name for eigrp. */
+#define EIGRP_DEFAULT_CONFIG "eigrpd.conf"
+
+#define EIGRP_HELLO_INTERVAL_DEFAULT 5
+#define EIGRP_HOLD_INTERVAL_DEFAULT 15
+#define EIGRP_BANDWIDTH_DEFAULT 10000000
+#define EIGRP_DELAY_DEFAULT 1000
+#define EIGRP_RELIABILITY_DEFAULT 255
+#define EIGRP_LOAD_DEFAULT 1
+
+#define EIGRP_MULTICAST_ADDRESS 0xe000000A /*224.0.0.10*/
+
+#define EIGRP_MAX_METRIC 0xffffffffU /*4294967295*/
+
+#define DEFAULT_ROUTE ZEBRA_ROUTE_MAX
+#define DEFAULT_ROUTE_TYPE(T) ((T) == DEFAULT_ROUTE)
+
+#define INTERFACE_DOWN_BY_ZEBRA 1
+#define INTERFACE_DOWN_BY_VTY 2
+
+#define EIGRP_HELLO_NORMAL 0x00
+#define EIGRP_HELLO_GRACEFUL_SHUTDOWN 0x01
+#define EIGRP_HELLO_ADD_SEQUENCE 0x02
+#define EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR 0x04
+
+ /* EIGRP Network Type. */
+ #define EIGRP_IFTYPE_NONE 0
+ #define EIGRP_IFTYPE_POINTOPOINT 1
+ #define EIGRP_IFTYPE_BROADCAST 2
+ #define EIGRP_IFTYPE_NBMA 3
+ #define EIGRP_IFTYPE_POINTOMULTIPOINT 4
+ #define EIGRP_IFTYPE_LOOPBACK 5
+ #define EIGRP_IFTYPE_MAX 6
+
+#define EIGRP_IF_ACTIVE 0
+#define EIGRP_IF_PASSIVE 1
+
+/* EIGRP TT destination type */
+#define EIGRP_TOPOLOGY_TYPE_CONNECTED 0 // Connected network
+#define EIGRP_TOPOLOGY_TYPE_REMOTE 1 // Remote internal network
+#define EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL 2 // Remote external network
+
+/*EIGRP TT entry flags*/
+#define EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG 1
+#define EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG 2
+#define EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG 4
+#define EIGRP_NEIGHBOR_ENTRY_EXTERNAL_FLAG 8
+
+/*EIGRP FSM state count, event count*/
+#define EIGRP_FSM_STATE_MAX 5
+#define EIGRP_FSM_EVENT_MAX 16
+
+/*EGRP FSM states*/
+#define EIGRP_FSM_STATE_PASSIVE 0
+#define EIGRP_FSM_STATE_ACTIVE_0 1
+#define EIGRP_FSM_STATE_ACTIVE_1 2
+#define EIGRP_FSM_STATE_ACTIVE_2 3
+#define EIGRP_FSM_STATE_ACTIVE_3 4
+
+/*EIGRP FSM events return values*/
+#define EIGRP_FSM_NEED_UPDATE 1
+#define EIGRP_FSM_NEED_QUERY 2
+
+/*EIGRP FSM events*/
+#define EIGRP_FSM_EVENT_NQ_FCN 0 /*input event other than query from succ, FC not satisfied*/
+#define EIGRP_FSM_EVENT_LR 1 /*last reply, FD is reset*/
+#define EIGRP_FSM_EVENT_Q_FCN 2 /*query from succ, FC not satisfied*/
+#define EIGRP_FSM_EVENT_LR_FCS 3 /*last reply, FC satisfied with current value of FDij*/
+#define EIGRP_FSM_EVENT_DINC 4 /*distance increase while in active state*/
+#define EIGRP_FSM_EVENT_QACT 5 /*query from succ while in active state*/
+#define EIGRP_FSM_EVENT_LR_FCN 6 /*last reply, FC not satisfied with current value of FDij*/
+#define EIGRP_FSM_KEEP_STATE 7 /*state not changed, usually by receiving not last reply */
+
+#define INT_TYPES_CMD_STR \
+ "detail|fastethernet|loopback|static"
+
+#define INT_TYPES_DESC \
+ "Virtual Ethernet interface\n" \
+ "FastEthernet IEEE 802.3\n" \
+ "Loopback interface\n" \
+ "Show static peer information\n"
+
+/**
+ * External routes originate from some other protocol - these are them
+ */
+#define NULL_PROTID 0 /*!< unknown protocol */
+#define IGRP_PROTID 1 /*!< IGRP.. whos your daddy! */
+#define EIGRP_PROTID 2 /*!< EIGRP - Just flat out the best */
+#define STATIC_PROTID 3 /*!< Staticly configured source */
+#define RIP_PROTID 4 /*!< Routing Information Protocol */
+#define HELLO_PROTID 5 /*!< Hello? RFC-891 you there? */
+#define OSPF_PROTID 6 /*!< OSPF - Open Shortest Path First */
+#define ISIS_PROTID 7 /*!< Intermediate System To Intermediate System */
+#define EGP_PROTID 8 /*!< Exterior Gateway Protocol */
+#define BGP_PROTID 9 /*!< Border Gateway Protocol */
+#define IDRP_PROTID 10 /*!< InterDomain Routing Protocol */
+#define CONN_PROTID 11 /*!< Connected source */
+
+/*
+ * metric k-value defaults
+ */
+#define EIGRP_K1_DEFAULT 1 //!< unweighed inverse bandwidth
+#define EIGRP_K2_DEFAULT 0 //!< no loading term
+#define EIGRP_K3_DEFAULT 1 //!< unweighted delay
+#define EIGRP_K4_DEFAULT 0 //!< no reliability term
+#define EIGRP_K5_DEFAULT 0 //!< no reliability term
+#define EIGRP_K6_DEFAULT 0 //!< do not add in extended metrics
+
+
+/*
+ * EIGRP Fixed header
+ */
+#define EIGRP_HEADER_LEN 20U
+#define EIGRP_PACKET_MAX_LEN 65535U /* includes IP Header size. */
+
+
+#define EIGRP_TLV_HDR_LENGTH 4
+
+/**
+ * EIGRP Packet Opcodes
+ */
+#define EIGRP_OPC_UPDATE 1 /*!< packet containing routing information */
+#define EIGRP_OPC_REQUEST 2 /*!< sent to request one or more routes */
+#define EIGRP_OPC_QUERY 3 /*!< sent when a routing is in active start */
+#define EIGRP_OPC_REPLY 4 /*!< sent in response to a query */
+#define EIGRP_OPC_HELLO 5 /*!< sent to maintain a peering session */
+#define EIGRP_OPC_IPXSAP 6 /*!< IPX SAP information */
+#define EIGRP_OPC_PROBE 7 /*!< for test purposes */
+#define EIGRP_OPC_ACK 8 /*!< acknowledge */
+#define EIGRP_OPC_SIAQUERY 10 /*!< QUERY - with relaxed restrictions */
+#define EIGRP_OPC_SIAREPLY 11 /*!< REPLY - may contain old routing information */
+
+/**
+ * EIGRP TLV Range definitions
+ * PDM TLV Range
+ * General 0x0000
+ * IPv4 0x0100 ** TLVs for one and all
+ * ATALK 0x0200 ** legacy
+ * IPX 0x0300 ** discontinued
+ * IPv6 0x0400 ** legacy
+ * Multiprotocol 0x0600 ** wide metrics
+ * MultiTopology 0x00f0 ** deprecated
+ */
+#define EIGRP_TLV_RANGEMASK 0xfff0 /*!< should be 0xff00 - opps */
+#define EIGRP_TLV_GENERAL 0x0000
+
+/**
+ * 1.2 TLV Definitions ** legacy
+ * These are considered legacyu and are only used for backward compability with
+ * older Cisco Routers. They should not be your first choice for packet codings
+ */
+#define EIGRP_TLV_IPv4 0x0100 /*!< Classic IPv4 TLV encoding */
+#define EIGRP_TLV_ATALK 0x0200 /*!< Classic Appletalk TLV encoding*/
+#define EIGRP_TLV_IPX 0x0300 /*!< Classic IPX TLV encoding */
+#define EIGRP_TLV_IPv6 0x0400 /*!< Classic IPv6 TLV encoding */
+
+/**
+ * 2.0 Multi-Protocol TLV Definitions
+ * These are the current packet formats and should be used for packets
+ */
+#define EIGRP_TLV_MP 0x0600 /*!< Non-PDM specific encoding */
+
+/**
+ * TLV type definitions. Generic (protocol-independent) TLV types are
+ * defined here. Protocol-specific ones are defined elsewhere.
+ */
+#define EIGRP_TLV_PARAMETER (EIGRP_TLV_GENERAL | 0x0001) /*!< eigrp parameters */
+#define EIGRP_TLV_PARAMETER_LEN (12U)
+#define EIGRP_TLV_AUTH (EIGRP_TLV_GENERAL | 0x0002) /*!< authentication */
+#define EIGRP_TLV_SEQ (EIGRP_TLV_GENERAL | 0x0003) /*!< sequenced packet */
+#define EIGRP_TLV_SEQ_BASE_LEN (5U)
+#define EIGRP_TLV_SW_VERSION (EIGRP_TLV_GENERAL | 0x0004) /*!< software version */
+#define EIGRP_TLV_SW_VERSION_LEN (8U)
+#define EIGRP_TLV_NEXT_MCAST_SEQ (EIGRP_TLV_GENERAL | 0x0005) /*!< sequence number */
+#define EIGRP_TLV_PEER_TERMINATION (EIGRP_TLV_GENERAL | 0x0007) /*!< peer termination */
+#define EIGRP_TLV_PEER_TERMINATION_LEN (9U)
+#define EIGRP_TLV_PEER_TIDLIST (EIGRP_TLV_GENERAL | 0x0008) /*!< peer sub-topology list */
+
+/* Older cisco routers send TIDLIST value wrong, adding for backwards compatabily */
+#define EIGRP_TLV_PEER_MTRLIST (EIGRP_TLV_GENERAL | 0x00f5)
+
+/**
+ * Route Based TLVs
+ */
+#define EIGRP_TLV_REQUEST 0x0001
+#define EIGRP_TLV_INTERNAL 0x0002
+#define EIGRP_TLV_EXTERNAL 0x0003
+#define EIGRP_TLV_COMMUNITY 0x0004
+#define EIGRP_TLV_TYPEMASK 0x000f
+
+#define EIGRP_TLV_IPv4_REQ (EIGRP_TLV_IPv4 | EIGRP_TLV_REQUEST)
+#define EIGRP_TLV_IPv4_INT (EIGRP_TLV_IPv4 | EIGRP_TLV_INTERNAL)
+#define EIGRP_TLV_IPv4_EXT (EIGRP_TLV_IPv4 | EIGRP_TLV_EXTERNAL)
+#define EIGRP_TLV_IPv4_COM (EIGRP_TLV_IPv4 | EIGRP_TLV_COMMUNITY)
+
+/* max number of TLV IPv4 prefixes in packet */
+#define EIGRP_TLV_MAX_IPv4 25
+
+/**
+ *
+ * extdata flag field definitions
+ */
+#define EIGRP_OPAQUE_EXT 0x01 /*!< Route is external */
+#define EIGRP_OPAQUE_CD 0x02 /*!< Candidate default route */
+
+/**
+ * Address-Family types are taken from:
+ * http://www.iana.org/assignments/address-family-numbers
+ * to provide a standards based exchange of AFI information between
+ * EIGRP routers.
+ */
+#define EIGRP_AF_IPv4 1 /*!< IPv4 (IP version 4) */
+#define EIGRP_AF_IPv6 2 /*!< IPv6 (IP version 6) */
+#define EIGRP_AF_IPX 11 /*!< IPX */
+#define EIGRP_AF_ATALK 12 /*!< Appletalk */
+#define EIGRP_SF_COMMON 16384 /*!< Cisco Service Family */
+#define EIGRP_SF_IPv4 16385 /*!< Cisco IPv4 Service Family */
+#define EIGRP_SF_IPv6 16386 /*!< Cisco IPv6 Service Family */
+
+/**
+ * Authentication types supported by EIGRP
+ */
+#define EIGRP_AUTH_TYPE_NONE 0
+#define EIGRP_AUTH_TYPE_TEXT 1
+#define EIGRP_AUTH_TYPE_MD5 2
+#define EIGRP_AUTH_TYPE_MD5_LEN 16
+#define EIGRP_AUTH_TYPE_SHA256 3
+#define EIGRP_AUTH_TYPE_SHA256_LEN 32
+
+/**
+ * opaque flag field definitions
+ */
+#define EIGRP_OPAQUE_SRCWD 0x01 /*!< Route Source Withdraw */
+#define EIGRP_OPAQUE_ACTIVE 0x04 /*!< Route is currently in active state */
+#define EIGRP_OPAQUE_REPL 0x08 /*!< Route is replicated from different tableid */
+
+/**
+ * pak flag bit field definitions - 0 (none)-7 source priority
+ */
+#define EIGRP_PRIV_DEFAULT 0x00 /* 0 (none)-7 source priority */
+#define EIGRP_PRIV_LOW 0x01
+#define EIGRP_PRIV_MEDIUM 0x04
+#define EIGRP_PRIV_HIGH 0x07
+
+/*
+ * Init bit definition. First unicast transmitted Update has this
+ * bit set in the flags field of the fixed header. It tells the neighbor
+ * to down-load his topology table.
+ */
+#define EIGRP_INIT_FLAG 0x01
+
+/*
+ * CR bit (Conditionally Received) definition in flags field on header. Any
+ * packets with the CR-bit set can be accepted by an EIGRP speaker if and
+ * only if a previous Hello was received with the SEQUENCE_TYPE TLV present.
+ *
+ * This allows multicasts to be transmitted in order and reliably at the
+ * same time as unicasts are transmitted.
+ */
+#define EIGRP_CR_FLAG 0x02
+
+/*
+ * RS bit. The Restart flag is set in the hello and the init
+ * update packets during the nsf signaling period. A nsf-aware
+ * router looks at the RS flag to detect if a peer is restarting
+ * and maintain the adjacency. A restarting router looks at
+ * this flag to determine if the peer is helping out with the restart.
+ */
+#define EIGRP_RS_FLAG 0x04
+
+/*
+ * EOT bit. The End-of-Table flag marks the end of the start-up updates
+ * sent to a new peer. A nsf restarting router looks at this flag to
+ * determine if it has finished receiving the start-up updates from all
+ * peers. A nsf-aware router waits for this flag before cleaning up
+ * the stale routes from the restarting peer.
+ */
+#define EIGRP_EOT_FLAG 0x08
+
+/**
+ * EIGRP Virtual Router ID
+ *
+ * Define values to deal with EIGRP virtual router ids. Virtual
+ * router IDs are stored in the upper short of the EIGRP fixed packet
+ * header. The lower short of the packet header continues to be used
+ * as asystem number.
+ *
+ * Virtual Router IDs are PDM-independent. All PDMs will use
+ * VRID_BASE to indicate the 'base' or 'legacy' EIGRP instance.
+ * All PDMs need to initialize their vrid to VRID_BASE for compatibility
+ * with legacy routers.
+ * Once IPv6 supports 'MTR Multicast', it will use the same VRID as
+ * IPv4. No current plans to support VRIDs on IPX. :)
+ * Initial usage of VRID is to signal usage of Multicast topology for
+ * MTR.
+ *
+ * VRID_MCAST is a well known constant, other VRIDs will be determined
+ * programmatic...
+ *
+ * With the addition of SAF the VRID space has been divided into two
+ * segments 0x0000-0x7fff is for EIGRP and vNets, 0x8000-0xffff is
+ * for saf and its associated vNets.
+ */
+#define EIGRP_VRID_MASK 0x8001
+#define EIGRP_VRID_AF_BASE 0x0000
+#define EIGRP_VRID_MCAST_BASE 0x0001
+#define EIGRP_VRID_SF_BASE 0x8000
+
+/* Extended Attributes for a destination */
+#define EIGRP_ATTR_HDRLEN (2)
+#define EIGRP_ATTR_MAXDATA (512)
+
+#define EIGRP_ATTR_NOOP 0 /*!< No-Op used as offset padding */
+#define EIGRP_ATTR_SCALED 1 /*!< Scaled metric values */
+#define EIGRP_ATTR_TAG 2 /*!< Tag assigned by Admin for dest */
+#define EIGRP_ATTR_COMM 3 /*!< Community attribute for dest */
+#define EIGRP_ATTR_JITTER 4 /*!< Variation in path delay */
+#define EIGRP_ATTR_QENERGY 5 /*!< Non-Active energy usage along path */
+#define EIGRP_ATTR_ENERGY 6 /*!< Active energy usage along path */
+
+/*
+ * Begin EIGRP-BGP interoperability communities
+ */
+#define EIGRP_EXTCOMM_SOO_ASFMT 0x0003 /* Site-of-Origin, BGP AS format */
+#define EIGRP_EXTCOMM_SOO_ADRFMT 0x0103 /* Site-of-Origin, BGP/EIGRP addr format */
+
+/*
+ * EIGRP Specific communities
+ */
+#define EIGRP_EXTCOMM_EIGRP 0x8800 /* EIGRP route information appended*/
+#define EIGRP_EXTCOMM_DAD 0x8801 /* EIGRP AS + Delay */
+#define EIGRP_EXTCOMM_VRHB 0x8802 /* EIGRP Vector: Reliability + Hop + BW */
+#define EIGRP_EXTCOMM_SRLM 0x8803 /* EIGRP System: Reserve +Load + MTU */
+#define EIGRP_EXTCOMM_SAR 0x8804 /* EIGRP System: Remote AS + Remote ID */
+#define EIGRP_EXTCOMM_RPM 0x8805 /* EIGRP Remote: Protocol + Metric */
+#define EIGRP_EXTCOMM_VRR 0x8806 /* EIGRP Vecmet: Rsvd + (internal) Routerid */
+
+
+/*
+ * EIGRP Filter constants
+ */
+#define EIGRP_FILTER_IN 0
+#define EIGRP_FILTER_OUT 1
+#define EIGRP_FILTER_MAX 2
+
+/*
+ * EIGRP Filter constants
+ */
+#define EIGRP_HSROLE_DEFAULT EIGRP_HSROLE_SPOKE
+#define EIGRP_HSROLE_HUB 0x01
+#define EIGRP_HSROLE_SPOKE 0x02
+
+#endif /* _ZEBRA_EIGRP_CONST_H_ */
diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c
new file mode 100644
index 000000000..c15eecc26
--- /dev/null
+++ b/eigrpd/eigrp_dump.c
@@ -0,0 +1,768 @@
+/*
+ * EIGRP Dump Functions and Debugging.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "thread.h"
+#include "prefix.h"
+#include "command.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "table.h"
+#include "keychain.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_topology.h"
+
+/* Enable debug option variables -- valid only session. */
+unsigned long term_debug_eigrp = 0;
+unsigned long term_debug_eigrp_nei = 0;
+unsigned long term_debug_eigrp_packet[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+unsigned long term_debug_eigrp_zebra = 6;
+unsigned long term_debug_eigrp_transmit = 0;
+
+/* Configuration debug option variables. */
+unsigned long conf_debug_eigrp = 0;
+unsigned long conf_debug_eigrp_nei = 0;
+unsigned long conf_debug_eigrp_packet[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+unsigned long conf_debug_eigrp_zebra = 0;
+unsigned long conf_debug_eigrp_transmit = 0;
+
+
+static int
+config_write_debug (struct vty *vty)
+{
+ int write = 0;
+ int i;
+
+ const char *type_str[] = {"update", "request", "query", "reply", "hello", "", "probe", "ack", "",
+ "SIA query", "SIA reply", "stub", "all"};
+ const char *detail_str[] = {"", " send", " recv", "", " detail",
+ " send detail", " recv detail", " detail"};
+
+
+ /* debug eigrp event. */
+// if (IS_CONF_DEBUG_EIGRP (event, EVENT) == EIGRP_DEBUG_EVENT)
+// {
+// vty_out (vty, "debug eigrp event%s", VTY_NEWLINE);
+// write = 1;
+// }
+
+ /* debug eigrp packet all detail. */
+// r = EIGRP_DEBUG_SEND_RECV|EIGRP_DEBUG_DETAIL;
+// for (i = 0; i < 11; i++)
+// r &= conf_debug_eigrp_packet[i] & (EIGRP_DEBUG_SEND_RECV|EIGRP_DEBUG_DETAIL);
+// if (r == (EIGRP_DEBUG_SEND_RECV|EIGRP_DEBUG_DETAIL))
+// {
+// vty_out (vty, "debug eigrp packet all detail%s", VTY_NEWLINE);
+//// return 1;
+// }
+//
+// /* debug eigrp packet all. */
+// r = EIGRP_DEBUG_SEND_RECV;
+// for (i = 0; i < 11; i++)
+// r &= conf_debug_eigrp_packet[i] & EIGRP_DEBUG_SEND_RECV;
+// if (r == EIGRP_DEBUG_SEND_RECV)
+// {
+// vty_out (vty, "debug eigrp packet all%s", VTY_NEWLINE);
+// for (i = 0; i < 11; i++)
+// if (conf_debug_eigrp_packet[i] & EIGRP_DEBUG_DETAIL)
+// vty_out (vty, "debug eigrp packet %s detail%s",
+// type_str[i],
+// VTY_NEWLINE);
+//// return 1;
+// }
+
+ /* debug eigrp packet */
+ for (i = 0; i < 10; i++)
+ {
+ if (conf_debug_eigrp_packet[i] == 0 && term_debug_eigrp_packet[i] == 0 )
+ continue;
+
+ vty_out (vty, "debug eigrp packet %s%s%s",
+ type_str[i], detail_str[conf_debug_eigrp_packet[i]],
+ VTY_NEWLINE);
+ write = 1;
+ }
+
+ // int write = 0;
+ // int i, r;
+ //
+ // const char *type_str[] = {"hello", "dd", "ls-request", "ls-update", "ls-ack"};
+ // const char *detail_str[] = {"", " send", " recv", "", " detail",
+ // " send detail", " recv detail", " detail"};
+ //
+ // /* debug ospf ism (status|events|timers). */
+ // if (IS_CONF_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM)
+ // vty_out (vty, "debug ospf ism%s", VTY_NEWLINE);
+ // else
+ // {
+ // if (IS_CONF_DEBUG_OSPF (ism, ISM_STATUS))
+ // vty_out (vty, "debug ospf ism status%s", VTY_NEWLINE);
+ // if (IS_CONF_DEBUG_OSPF (ism, ISM_EVENTS))
+ // vty_out (vty, "debug ospf ism event%s", VTY_NEWLINE);
+ // if (IS_CONF_DEBUG_OSPF (ism, ISM_TIMERS))
+ // vty_out (vty, "debug ospf ism timer%s", VTY_NEWLINE);
+ // }
+ //
+ // /* debug ospf nsm (status|events|timers). */
+ // if (IS_CONF_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM)
+ // vty_out (vty, "debug ospf nsm%s", VTY_NEWLINE);
+ // else
+ // {
+ // if (IS_CONF_DEBUG_OSPF (nsm, NSM_STATUS))
+ // vty_out (vty, "debug ospf nsm status%s", VTY_NEWLINE);
+ // if (IS_CONF_DEBUG_OSPF (nsm, NSM_EVENTS))
+ // vty_out (vty, "debug ospf nsm event%s", VTY_NEWLINE);
+ // if (IS_CONF_DEBUG_OSPF (nsm, NSM_TIMERS))
+ // vty_out (vty, "debug ospf nsm timer%s", VTY_NEWLINE);
+ // }
+ //
+ // /* debug ospf lsa (generate|flooding|install|refresh). */
+ // if (IS_CONF_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA)
+ // vty_out (vty, "debug ospf lsa%s", VTY_NEWLINE);
+ // else
+ // {
+ // if (IS_CONF_DEBUG_OSPF (lsa, LSA_GENERATE))
+ // vty_out (vty, "debug ospf lsa generate%s", VTY_NEWLINE);
+ // if (IS_CONF_DEBUG_OSPF (lsa, LSA_FLOODING))
+ // vty_out (vty, "debug ospf lsa flooding%s", VTY_NEWLINE);
+ // if (IS_CONF_DEBUG_OSPF (lsa, LSA_INSTALL))
+ // vty_out (vty, "debug ospf lsa install%s", VTY_NEWLINE);
+ // if (IS_CONF_DEBUG_OSPF (lsa, LSA_REFRESH))
+ // vty_out (vty, "debug ospf lsa refresh%s", VTY_NEWLINE);
+ //
+ // write = 1;
+ // }
+ //
+ // /* debug ospf zebra (interface|redistribute). */
+ // if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA)
+ // vty_out (vty, "debug ospf zebra%s", VTY_NEWLINE);
+ // else
+ // {
+ // if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+ // vty_out (vty, "debug ospf zebra interface%s", VTY_NEWLINE);
+ // if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+ // vty_out (vty, "debug ospf zebra redistribute%s", VTY_NEWLINE);
+ //
+ // write = 1;
+ // }
+ //
+ // /* debug ospf event. */
+ // if (IS_CONF_DEBUG_OSPF (event, EVENT) == OSPF_DEBUG_EVENT)
+ // {
+ // vty_out (vty, "debug ospf event%s", VTY_NEWLINE);
+ // write = 1;
+ // }
+ //
+ // /* debug ospf nssa. */
+ // if (IS_CONF_DEBUG_OSPF (nssa, NSSA) == OSPF_DEBUG_NSSA)
+ // {
+ // vty_out (vty, "debug ospf nssa%s", VTY_NEWLINE);
+ // write = 1;
+ // }
+ //
+ // /* debug ospf packet all detail. */
+ // r = OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL;
+ // for (i = 0; i < 5; i++)
+ // r &= conf_debug_ospf_packet[i] & (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL);
+ // if (r == (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL))
+ // {
+ // vty_out (vty, "debug ospf packet all detail%s", VTY_NEWLINE);
+ // return 1;
+ // }
+ //
+ // /* debug ospf packet all. */
+ // r = OSPF_DEBUG_SEND_RECV;
+ // for (i = 0; i < 5; i++)
+ // r &= conf_debug_ospf_packet[i] & OSPF_DEBUG_SEND_RECV;
+ // if (r == OSPF_DEBUG_SEND_RECV)
+ // {
+ // vty_out (vty, "debug ospf packet all%s", VTY_NEWLINE);
+ // for (i = 0; i < 5; i++)
+ // if (conf_debug_ospf_packet[i] & OSPF_DEBUG_DETAIL)
+ // vty_out (vty, "debug ospf packet %s detail%s",
+ // type_str[i],
+ // VTY_NEWLINE);
+ // return 1;
+ // }
+ //
+ // /* debug ospf packet (hello|dd|ls-request|ls-update|ls-ack)
+ // (send|recv) (detail). */
+ // for (i = 0; i < 5; i++)
+ // {
+ // if (conf_debug_ospf_packet[i] == 0)
+ // continue;
+ //
+ // vty_out (vty, "debug ospf packet %s%s%s",
+ // type_str[i], detail_str[conf_debug_ospf_packet[i]],
+ // VTY_NEWLINE);
+ // write = 1;
+ // }
+
+ return write;
+}
+
+
+static int
+eigrp_neighbor_packet_queue_sum (struct eigrp_interface *ei)
+{
+ struct eigrp_neighbor *nbr;
+ struct listnode *node, *nnode;
+ int sum;
+ sum = 0;
+
+ for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr))
+ {
+ sum += nbr->retrans_queue->count;
+ }
+
+ return sum;
+}
+
+/*
+ * Expects header to be in host order
+ */
+void
+eigrp_ip_header_dump (struct ip *iph)
+{
+ /* IP Header dump. */
+ zlog_debug ("ip_v %u", iph->ip_v);
+ zlog_debug ("ip_hl %u", iph->ip_hl);
+ zlog_debug ("ip_tos %u", iph->ip_tos);
+ zlog_debug ("ip_len %u", iph->ip_len);
+ zlog_debug ("ip_id %u", (u_int32_t) iph->ip_id);
+ zlog_debug ("ip_off %u", (u_int32_t) iph->ip_off);
+ zlog_debug ("ip_ttl %u", iph->ip_ttl);
+ zlog_debug ("ip_p %u", iph->ip_p);
+ zlog_debug ("ip_sum 0x%x", (u_int32_t) iph->ip_sum);
+ zlog_debug ("ip_src %s", inet_ntoa (iph->ip_src));
+ zlog_debug ("ip_dst %s", inet_ntoa (iph->ip_dst));
+}
+
+/*
+ * Expects header to be in host order
+ */
+void
+eigrp_header_dump (struct eigrp_header *eigrph)
+{
+ /* EIGRP Header dump. */
+ zlog_debug ("eigrp_version %u", eigrph->version);
+ zlog_debug ("eigrp_opcode %u", eigrph->opcode);
+ zlog_debug ("eigrp_checksum 0x%x", ntohs(eigrph->checksum));
+ zlog_debug ("eigrp_flags 0x%x", ntohl(eigrph->flags));
+ zlog_debug ("eigrp_sequence %u", ntohl(eigrph->sequence));
+ zlog_debug ("eigrp_ack %u", ntohl(eigrph->ack));
+ zlog_debug ("eigrp_vrid %u" , ntohs(eigrph->vrid));
+ zlog_debug ("eigrp_AS %u", ntohs(eigrph->ASNumber));
+}
+
+const char *
+eigrp_if_name_string (struct eigrp_interface *ei)
+{
+ static char buf[EIGRP_IF_STRING_MAXLEN] = "";
+
+ if (!ei)
+ return "inactive";
+
+ snprintf (buf, EIGRP_IF_STRING_MAXLEN,
+ "%s", ei->ifp->name);
+ return buf;
+}
+
+const char *
+eigrp_topology_ip_string (struct eigrp_prefix_entry *tn)
+{
+ static char buf[EIGRP_IF_STRING_MAXLEN] = "";
+ u_int32_t ifaddr;
+
+ ifaddr = ntohl (tn->destination_ipv4->prefix.s_addr);
+ snprintf (buf, EIGRP_IF_STRING_MAXLEN,
+ "%u.%u.%u.%u",
+ (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff,
+ (ifaddr >> 8) & 0xff, ifaddr & 0xff);
+ return buf;
+}
+
+
+const char *
+eigrp_if_ip_string (struct eigrp_interface *ei)
+{
+ static char buf[EIGRP_IF_STRING_MAXLEN] = "";
+ u_int32_t ifaddr;
+
+ if (!ei)
+ return "inactive";
+
+ ifaddr = ntohl (ei->address->u.prefix4.s_addr);
+ snprintf (buf, EIGRP_IF_STRING_MAXLEN,
+ "%u.%u.%u.%u",
+ (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff,
+ (ifaddr >> 8) & 0xff, ifaddr & 0xff);
+
+ return buf;
+}
+
+const char *
+eigrp_neigh_ip_string (struct eigrp_neighbor *nbr)
+{
+ static char buf[EIGRP_IF_STRING_MAXLEN] = "";
+ u_int32_t ifaddr;
+
+ ifaddr = ntohl (nbr->src.s_addr);
+ snprintf (buf, EIGRP_IF_STRING_MAXLEN,
+ "%u.%u.%u.%u",
+ (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff,
+ (ifaddr >> 8) & 0xff, ifaddr & 0xff);
+
+ return buf;
+}
+
+void
+show_ip_eigrp_interface_header (struct vty *vty, struct eigrp *eigrp)
+{
+
+ vty_out (vty, "%s%s%d%s%s%s %-10s %-10s %-10s %-6s %-12s %-7s %-14s %-12s %-8s %-8s %-8s%s %-39s %-12s %-7s %-14s %-12s %-8s%s",
+ VTY_NEWLINE,
+ "EIGRP interfaces for AS(",eigrp->AS,")",VTY_NEWLINE,VTY_NEWLINE,
+ "Interface", "Bandwidth", "Delay", "Peers", "Xmit Queue", "Mean",
+ "Pacing Time", "Multicast", "Pending", "Hello", "Holdtime",
+ VTY_NEWLINE,"","Un/Reliable","SRTT","Un/Reliable","Flow Timer","Routes",
+ VTY_NEWLINE);
+}
+
+void
+show_ip_eigrp_interface_sub (struct vty *vty, struct eigrp *eigrp,
+ struct eigrp_interface *ei)
+{
+ vty_out (vty, "%-11s ", eigrp_if_name_string (ei));
+ vty_out (vty, "%-11u",IF_DEF_PARAMS (ei->ifp)->bandwidth);
+ vty_out (vty, "%-11u",IF_DEF_PARAMS (ei->ifp)->delay);
+ vty_out (vty, "%-7u", ei->nbrs->count);
+ vty_out (vty, "%u %c %-10u",0,'/',eigrp_neighbor_packet_queue_sum (ei));
+ vty_out (vty, "%-7u %-14u %-12u %-8u",0,0,0,0);
+ vty_out (vty, "%-8u %-8u %s",IF_DEF_PARAMS (ei->ifp)->v_hello,IF_DEF_PARAMS (ei->ifp)->v_wait,VTY_NEWLINE);
+}
+
+void
+show_ip_eigrp_interface_detail (struct vty *vty, struct eigrp *eigrp,
+ struct eigrp_interface *ei)
+{
+ vty_out (vty, "%-2s %s %d %-3s %s","","Hello interval is ",0," sec",VTY_NEWLINE);
+ vty_out (vty, "%-2s %s %s %s","","Next xmit serial","<none>",VTY_NEWLINE);
+ vty_out (vty, "%-2s %s %d %s %d %s %d %s %d %s","","Un/reliable mcasts: ",0,"/",0,"Un/reliable ucasts: ",0,"/",0,VTY_NEWLINE);
+ vty_out (vty, "%-2s %s %d %s %d %s %d %s","","Mcast exceptions: ",0," CR packets: ",0," ACKs supressed: ",0,VTY_NEWLINE);
+ vty_out (vty, "%-2s %s %d %s %d %s","","Retransmissions sent: ",0,"Out-of-sequence rcvd: ",0,VTY_NEWLINE);
+ vty_out (vty, "%-2s %s %s %s %s","","Authentication mode is ","not","set",VTY_NEWLINE);
+ vty_out (vty, "%-2s %s %s","","Use multicast",VTY_NEWLINE);
+}
+
+void
+show_ip_eigrp_neighbor_header (struct vty *vty, struct eigrp *eigrp)
+{
+ vty_out (vty, "%s%s%d%s%s%s%-3s %-17s %-20s %-6s %-8s %-6s %-5s %-5s %-5s%s %-41s %-6s %-8s %-6s %-4s %-6s %-5s %s",
+ VTY_NEWLINE,
+ "EIGRP neighbors for AS(",eigrp->AS,")",VTY_NEWLINE,VTY_NEWLINE,
+ "H", "Address", "Interface", "Hold", "Uptime",
+ "SRTT", "RTO", "Q", "Seq", VTY_NEWLINE
+ ,"","(sec)","","(ms)","","Cnt","Num", VTY_NEWLINE);
+}
+
+void
+show_ip_eigrp_neighbor_sub (struct vty *vty, struct eigrp_neighbor *nbr,
+ int detail)
+{
+
+ vty_out (vty, "%-3u %-17s %-21s",0,eigrp_neigh_ip_string (nbr),eigrp_if_name_string (nbr->ei));
+ vty_out (vty,"%-7lu",thread_timer_remain_second (nbr->t_holddown));
+ vty_out (vty,"%-8u %-6u %-5u",0,0,EIGRP_PACKET_RETRANS_TIME);
+ vty_out (vty,"%-7lu",nbr->retrans_queue->count);
+ vty_out (vty,"%u%s",nbr->recv_sequence_number,VTY_NEWLINE);
+
+
+ if (detail)
+ {
+ vty_out(vty," Version %u.%u/%u.%u",
+ nbr->os_rel_major, nbr->os_rel_minor,
+ nbr->tlv_rel_major, nbr->tlv_rel_minor);
+ vty_out(vty,", Retrans: %lu, Retries: %lu",
+ nbr->retrans_queue->count, 0UL);
+ vty_out(vty,", %s%s", eigrp_nbr_state_str(nbr), VTY_NEWLINE);
+ }
+}
+
+/*
+ * Print standard header for show EIGRP topology output
+ */
+void
+show_ip_eigrp_topology_header (struct vty *vty, struct eigrp *eigrp)
+{
+ struct in_addr router_id;
+ router_id.s_addr = htonl(eigrp->router_id);
+
+ vty_out (vty, "%s%s%d%s%s%s%s%s%s%s%s%s%s%s",
+ VTY_NEWLINE,
+ "EIGRP Topology Table for AS(", eigrp->AS, ")/ID(", inet_ntoa(router_id), ")", VTY_NEWLINE,VTY_NEWLINE,
+ "Codes: P - Passive, A - Active, U - Update, Q - Query, "
+ "R - Reply", VTY_NEWLINE ," ","r - reply Status, s - sia Status",VTY_NEWLINE,VTY_NEWLINE);
+}
+
+void
+show_ip_eigrp_prefix_entry (struct vty *vty, struct eigrp_prefix_entry *tn)
+{
+ vty_out (vty, "%-3c",(tn->state > 0) ? 'A' : 'P');
+ vty_out (vty, "%s/%u, ",inet_ntoa (tn->destination_ipv4->prefix),tn->destination_ipv4->prefixlen);
+ vty_out (vty, "%u successors, ",eigrp_topology_get_successor(tn)->count);
+ vty_out (vty, "FD is %u, serno: %lu %s",tn->fdistance, tn->serno, VTY_NEWLINE);
+
+}
+
+void
+show_ip_eigrp_neighbor_entry (struct vty *vty, struct eigrp *eigrp, struct eigrp_neighbor_entry *te)
+{
+ if (te->adv_router == eigrp->neighbor_self)
+ vty_out (vty, "%-7s%s, %s%s"," ","via Connected",eigrp_if_name_string (te->ei), VTY_NEWLINE);
+ else
+ {
+ vty_out (vty, "%-7s%s%s (%u/%u), %s%s"," ","via ",inet_ntoa (te->adv_router->src),te->distance, te->reported_distance, eigrp_if_name_string (te->ei), VTY_NEWLINE);
+ }
+}
+
+
+DEFUN (show_debugging_eigrp,
+ show_debugging_eigrp_cmd,
+ "show debugging eigrp",
+ SHOW_STR
+ DEBUG_STR
+ EIGRP_STR)
+{
+ int i;
+
+ vty_out (vty, "EIGRP debugging status:%s", VTY_NEWLINE);
+
+ /* Show debug status for events. */
+ if (IS_DEBUG_EIGRP(event,EVENT))
+ vty_out (vty, " EIGRP event debugging is on%s", VTY_NEWLINE);
+
+ /* Show debug status for EIGRP Packets. */
+ for (i = 0; i < 11 ; i++)
+ {
+ if (i == 8)
+ continue;
+
+ if (IS_DEBUG_EIGRP_PACKET (i, SEND) && IS_DEBUG_EIGRP_PACKET (i, RECV))
+ {
+ vty_out (vty, " EIGRP packet %s%s debugging is on%s",
+ LOOKUP (eigrp_packet_type_str, i + 1),
+ IS_DEBUG_EIGRP_PACKET (i, PACKET_DETAIL) ? " detail" : "",
+ VTY_NEWLINE);
+ }
+ else
+ {
+ if (IS_DEBUG_EIGRP_PACKET (i, SEND))
+ vty_out (vty, " EIGRP packet %s send%s debugging is on%s",
+ LOOKUP (eigrp_packet_type_str, i + 1),
+ IS_DEBUG_EIGRP_PACKET (i, PACKET_DETAIL) ? " detail" : "",
+ VTY_NEWLINE);
+ if (IS_DEBUG_EIGRP_PACKET (i, RECV))
+ vty_out (vty, " EIGRP packet %s receive%s debugging is on%s",
+ LOOKUP (eigrp_packet_type_str, i + 1),
+ IS_DEBUG_EIGRP_PACKET (i, PACKET_DETAIL) ? " detail" : "",
+ VTY_NEWLINE);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+/*
+ [no] debug eigrp packet (hello|dd|ls-request|ls-update|ls-ack|all)
+ [send|recv [detail]]
+*/
+
+DEFUN (debug_eigrp_transmit,
+ debug_eigrp_transmit_cmd,
+ "debug eigrp transmit <send|recv|all> [detail]",
+ DEBUG_STR
+ EIGRP_STR
+ "EIGRP transmission events\n"
+ "packet sent\n"
+ "packet received\n"
+ "all packets\n"
+ "Detailed Information\n")
+{
+ int flag = 0;
+ int idx = 2;
+
+ /* send or recv. */
+ if (argv_find (argv, argc, "send", &idx))
+ flag = EIGRP_DEBUG_SEND;
+ else if (argv_find (argv, argc, "recv", &idx))
+ flag = EIGRP_DEBUG_RECV;
+ else if (argv_find (argv, argc, "all", &idx) == 0)
+ flag = EIGRP_DEBUG_SEND_RECV;
+
+ /* detail option */
+ if (argv_find (argv, argc, "detail", &idx) == 0)
+ flag = EIGRP_DEBUG_PACKET_DETAIL;
+
+ if (vty->node == CONFIG_NODE)
+ DEBUG_TRANSMIT_ON (0, flag);
+ else
+ TERM_DEBUG_TRANSMIT_ON (0, flag);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_eigrp_transmit,
+ no_debug_eigrp_transmit_cmd,
+ "no debug eigrp transmit <send|recv|all> [detail]",
+ NO_STR
+ UNDEBUG_STR
+ EIGRP_STR
+ "EIGRP transmission events\n"
+ "packet sent\n"
+ "packet received\n"
+ "all packets\n"
+ "Detailed Information\n")
+{
+ int flag = 0;
+ int idx = 3;
+
+ /* send or recv. */
+ if (argv_find (argv, argc, "send", &idx) == 0)
+ flag = EIGRP_DEBUG_SEND;
+ else if (argv_find (argv, argc, "recv", &idx) == 0)
+ flag = EIGRP_DEBUG_RECV;
+ else if (argv_find (argv, argc, "all", &idx) == 0)
+ flag = EIGRP_DEBUG_SEND_RECV;
+
+ /* detail option */
+ if (argv_find (argv, argc, "detail", &idx) == 0)
+ flag = EIGRP_DEBUG_PACKET_DETAIL;
+
+ if (vty->node == CONFIG_NODE)
+ DEBUG_TRANSMIT_OFF (0, flag);
+ else
+ TERM_DEBUG_TRANSMIT_OFF (0, flag);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_eigrp_packets,
+ debug_eigrp_packets_all_cmd,
+ "debug eigrp packets <siaquery|siareply|ack|hello|probe|query|reply|request|retry|stub|terse|update|all> [send|receive] [detail]",
+ DEBUG_STR
+ EIGRP_STR
+ "EIGRP packets\n"
+ "EIGRP SIA-Query packets\n"
+ "EIGRP SIA-Reply packets\n"
+ "EIGRP ack packets\n"
+ "EIGRP hello packets\n"
+ "EIGRP probe packets\n"
+ "EIGRP query packets\n"
+ "EIGRP reply packets\n"
+ "EIGRP request packets\n"
+ "EIGRP retransmissions\n"
+ "EIGRP stub packets\n"
+ "Display all EIGRP packets except Hellos\n"
+ "EIGRP update packets\n"
+ "Display all EIGRP packets\n"
+ "Send Packets\n"
+ "Receive Packets\n"
+ "Detail Information\n")
+{
+ int type = 0;
+ int flag = 0;
+ int i;
+ int idx = 0;
+
+ /* Check packet type. */
+ if (argv_find (argv, argc, "hello", &idx) == 0)
+ type = EIGRP_DEBUG_HELLO;
+ if (argv_find (argv, argc, "update", &idx) == 0)
+ type = EIGRP_DEBUG_UPDATE;
+ if (argv_find (argv, argc, "query", &idx) == 0)
+ type = EIGRP_DEBUG_QUERY;
+ if (argv_find (argv, argc, "ack", &idx) == 0)
+ type = EIGRP_DEBUG_ACK;
+ if (argv_find (argv, argc, "probe", &idx) == 0)
+ type = EIGRP_DEBUG_PROBE;
+ if (argv_find (argv, argc, "stub", &idx) == 0)
+ type = EIGRP_DEBUG_STUB;
+ if (argv_find (argv, argc, "reply", &idx) == 0)
+ type = EIGRP_DEBUG_REPLY;
+ if (argv_find (argv, argc, "request", &idx) == 0)
+ type = EIGRP_DEBUG_REQUEST;
+ if (argv_find (argv, argc, "siaquery", &idx) == 0)
+ type = EIGRP_DEBUG_SIAQUERY;
+ if (argv_find (argv, argc, "siareply", &idx) == 0)
+ type = EIGRP_DEBUG_SIAREPLY;
+ if (argv_find (argv, argc, "all", &idx) == 0)
+ type = EIGRP_DEBUG_PACKETS_ALL;
+
+
+ /* All packet types, both send and recv. */
+ flag = EIGRP_DEBUG_SEND_RECV;
+
+ /* send or recv. */
+ if (argv_find (argv, argc, "s", &idx) == 0)
+ flag = EIGRP_DEBUG_SEND;
+ else if (argv_find (argv, argc, "r", &idx) == 0)
+ flag = EIGRP_DEBUG_RECV;
+
+ /* detail. */
+ if (argv_find (argv, argc, "detail", &idx) == 0)
+ flag |= EIGRP_DEBUG_PACKET_DETAIL;
+
+ for (i = 0; i < 11; i++)
+ if (type & (0x01 << i))
+ {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_PACKET_ON (i, flag);
+ else
+ TERM_DEBUG_PACKET_ON (i, flag);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_eigrp_packets,
+ no_debug_eigrp_packets_all_cmd,
+ "no debug eigrp packets <siaquery|siareply|ack|hello|probe|query|reply|request|retry|stub|terse|update|all> [send|receive] [detail]",
+ NO_STR
+ UNDEBUG_STR
+ EIGRP_STR
+ "EIGRP packets\n"
+ "EIGRP SIA-Query packets\n"
+ "EIGRP SIA-Reply packets\n"
+ "EIGRP ack packets\n"
+ "EIGRP hello packets\n"
+ "EIGRP probe packets\n"
+ "EIGRP query packets\n"
+ "EIGRP reply packets\n"
+ "EIGRP request packets\n"
+ "EIGRP retransmissions\n"
+ "EIGRP stub packets\n"
+ "Display all EIGRP packets except Hellos\n"
+ "EIGRP update packets\n"
+ "Display all EIGRP packets\n"
+ "Send Packets\n"
+ "Receive Packets\n"
+ "Detailed Information\n")
+{
+ int type = 0;
+ int flag = 0;
+ int i;
+ int idx = 0;
+
+ /* Check packet type. */
+ if (argv_find (argv, argc, "hello", &idx) == 0)
+ type = EIGRP_DEBUG_HELLO;
+ if (argv_find (argv, argc, "update", &idx) == 0)
+ type = EIGRP_DEBUG_UPDATE;
+ if (argv_find (argv, argc, "query", &idx) == 0)
+ type = EIGRP_DEBUG_QUERY;
+ if (argv_find (argv, argc, "ack", &idx) == 0)
+ type = EIGRP_DEBUG_ACK;
+ if (argv_find (argv, argc, "probe", &idx) == 0)
+ type = EIGRP_DEBUG_PROBE;
+ if (argv_find (argv, argc, "stub", &idx) == 0)
+ type = EIGRP_DEBUG_STUB;
+ if (argv_find (argv, argc, "reply", &idx) == 0)
+ type = EIGRP_DEBUG_REPLY;
+ if (argv_find (argv, argc, "request", &idx) == 0)
+ type = EIGRP_DEBUG_REQUEST;
+ if (argv_find (argv, argc, "siaquery", &idx) == 0)
+ type = EIGRP_DEBUG_SIAQUERY;
+ if (argv_find (argv, argc, "siareply", &idx) == 0)
+ type = EIGRP_DEBUG_SIAREPLY;
+
+ /* Default, both send and recv. */
+ flag = EIGRP_DEBUG_SEND_RECV;
+
+ /* send or recv. */
+ if (argv_find (argv, argc, "send", &idx) == 0)
+ flag = EIGRP_DEBUG_SEND;
+ else if (argv_find (argv, argc, "reply", &idx) == 0)
+ flag = EIGRP_DEBUG_RECV;
+
+ /* detail. */
+ if (argv_find (argv, argc, "detail", &idx) == 0)
+ flag |= EIGRP_DEBUG_PACKET_DETAIL;
+
+ for (i = 0; i < 11; i++)
+ if (type & (0x01 << i))
+ {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_PACKET_OFF (i, flag);
+ else
+ TERM_DEBUG_PACKET_OFF (i, flag);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* Debug node. */
+static struct cmd_node eigrp_debug_node =
+{
+ DEBUG_NODE,
+ "",
+ 1 /* VTYSH */
+};
+
+/* Initialize debug commands. */
+void
+eigrp_debug_init ()
+{
+ install_node (&eigrp_debug_node, config_write_debug);
+
+ install_element (ENABLE_NODE, &show_debugging_eigrp_cmd);
+ install_element (ENABLE_NODE, &debug_eigrp_packets_all_cmd);
+ install_element (ENABLE_NODE, &no_debug_eigrp_packets_all_cmd);
+ install_element (ENABLE_NODE, &debug_eigrp_transmit_cmd);
+ install_element (ENABLE_NODE, &no_debug_eigrp_transmit_cmd);
+
+ install_element (CONFIG_NODE, &show_debugging_eigrp_cmd);
+ install_element (CONFIG_NODE, &debug_eigrp_packets_all_cmd);
+ install_element (CONFIG_NODE, &no_debug_eigrp_packets_all_cmd);
+ install_element (CONFIG_NODE, &no_debug_eigrp_transmit_cmd);
+}
+
+
diff --git a/eigrpd/eigrp_dump.h b/eigrpd/eigrp_dump.h
new file mode 100644
index 000000000..54e6338a3
--- /dev/null
+++ b/eigrpd/eigrp_dump.h
@@ -0,0 +1,165 @@
+/*
+ * EIGRP Dump Functions and Debbuging.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRPD_DUMP_H_
+#define _ZEBRA_EIGRPD_DUMP_H_
+
+#define EIGRP_TIME_DUMP_SIZE 16
+
+/* general debug flags */
+extern unsigned long term_debug_eigrp;
+#define EIGRP_DEBUG_EVENT 0x01
+#define EIGRP_DEBUG_DETAIL 0x02
+#define EIGRP_DEBUG_TIMERS 0x04
+
+/* neighbor debug flags */
+extern unsigned long term_debug_eigrp_nei;
+#define EIGRP_DEBUG_NEI 0x01
+
+/* packet debug flags */
+extern unsigned long term_debug_eigrp_packet[];
+#define EIGRP_DEBUG_UPDATE 0x01
+#define EIGRP_DEBUG_REQUEST 0x02
+#define EIGRP_DEBUG_QUERY 0x04
+#define EIGRP_DEBUG_REPLY 0x08
+#define EIGRP_DEBUG_HELLO 0x10
+#define EIGRP_DEBUG_PROBE 0x40
+#define EIGRP_DEBUG_ACK 0x80
+#define EIGRP_DEBUG_SIAQUERY 0x200
+#define EIGRP_DEBUG_SIAREPLY 0x400
+#define EIGRP_DEBUG_STUB 0x800
+#define EIGRP_DEBUG_PACKETS_ALL 0xfff
+
+extern unsigned long term_debug_eigrp_transmit;
+#define EIGRP_DEBUG_SEND 0x01
+#define EIGRP_DEBUG_RECV 0x02
+#define EIGRP_DEBUG_SEND_RECV 0x03
+#define EIGRP_DEBUG_PACKET_DETAIL 0x04
+
+/* zebra debug flags */
+extern unsigned long term_debug_eigrp_zebra;
+#define EIGRP_DEBUG_ZEBRA_INTERFACE 0x01
+#define EIGRP_DEBUG_ZEBRA_REDISTRIBUTE 0x02
+#define EIGRP_DEBUG_ZEBRA 0x03
+
+/* Macro for setting debug option. */
+#define CONF_DEBUG_NEI_ON(a, b) conf_debug_eigrp_nei[a] |= (b)
+#define CONF_DEBUG_NEI_OFF(a, b) conf_debug_eigrp_nei[a] &= ~(b)
+#define TERM_DEBUG_NEI_ON(a, b) term_debug_eigrp_nei[a] |= (b)
+#define TERM_DEBUG_NEI_OFF(a, b) term_debug_eigrp_nei[a] &= ~(b)
+#define DEBUG_NEI_ON(a, b) \
+ do { \
+ CONF_DEBUG_NEI_ON(a, b); \
+ TERM_DEBUG_NEI_ON(a, b); \
+ } while (0)
+#define DEBUG_NEI_OFF(a, b) \
+ do { \
+ CONF_DEBUG_NEI_OFF(a, b); \
+ TERM_DEBUG_NEI_OFF(a, b); \
+ } while (0)
+
+#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_eigrp_packet[a] |= (b)
+#define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_eigrp_packet[a] &= ~(b)
+#define TERM_DEBUG_PACKET_ON(a, b) term_debug_eigrp_packet[a] |= (b)
+#define TERM_DEBUG_PACKET_OFF(a, b) term_debug_eigrp_packet[a] &= ~(b)
+#define DEBUG_PACKET_ON(a, b) \
+ do { \
+ CONF_DEBUG_PACKET_ON(a, b); \
+ TERM_DEBUG_PACKET_ON(a, b); \
+ } while (0)
+#define DEBUG_PACKET_OFF(a, b) \
+ do { \
+ CONF_DEBUG_PACKET_OFF(a, b); \
+ TERM_DEBUG_PACKET_OFF(a, b); \
+ } while (0)
+
+#define CONF_DEBUG_TRANSMIT_ON(a, b) conf_debug_eigrp_transmit |= (b)
+#define CONF_DEBUG_TRANSMIT_OFF(a, b) conf_debug_eigrp_transmit &= ~(b)
+#define TERM_DEBUG_TRANSMIT_ON(a, b) term_debug_eigrp_transmit |= (b)
+#define TERM_DEBUG_TRANSMIT_OFF(a, b) term_debug_eigrp_transmit &= ~(b)
+#define DEBUG_TRANSMIT_ON(a, b) \
+ do { \
+ CONF_DEBUG_TRANSMIT_ON(a, b); \
+ TERM_DEBUG_TRANSMIT_ON(a, b); \
+ } while (0)
+#define DEBUG_TRANSMIT_OFF(a, b) \
+ do { \
+ CONF_DEBUG_TRANSMIT_OFF(a, b); \
+ TERM_DEBUG_TRANSMIT_OFF(a, b); \
+ } while (0)
+
+#define CONF_DEBUG_ON(a, b) conf_debug_eigrp_ ## a |= (EIGRP_DEBUG_ ## b)
+#define CONF_DEBUG_OFF(a, b) conf_debug_eigrp_ ## a &= ~(EIGRP_DEBUG_ ## b)
+#define TERM_DEBUG_ON(a, b) term_debug_eigrp_ ## a |= (EIGRP_DEBUG_ ## b)
+#define TERM_DEBUG_OFF(a, b) term_debug_eigrp_ ## a &= ~(EIGRP_DEBUG_ ## b)
+#define DEBUG_ON(a, b) \
+ do { \
+ CONF_DEBUG_ON(a, b); \
+ TERM_DEBUG_ON(a, b); \
+ } while (0)
+#define DEBUG_OFF(a, b) \
+ do { \
+ CONF_DEBUG_OFF(a, b); \
+ TERM_DEBUG_OFF(a, b); \
+ } while (0)
+
+/* Macro for checking debug option. */
+#define IS_DEBUG_EIGRP_PACKET(a, b) \
+ (term_debug_eigrp_packet[a] & EIGRP_DEBUG_ ## b)
+#define IS_DEBUG_EIGRP_TRANSMIT(a, b) \
+ (term_debug_eigrp_transmit & EIGRP_DEBUG_ ## b)
+#define IS_DEBUG_EIGRP_NEI(a, b) \
+ (term_debug_eigrp_nei & EIGRP_DEBUG_ ## b)
+#define IS_DEBUG_EIGRP(a, b) \
+ (term_debug_eigrp & EIGRP_DEBUG_ ## b)
+#define IS_DEBUG_EIGRP_EVENT IS_DEBUG_EIGRP(event, EVENT)
+
+
+/* Prototypes. */
+extern const char *eigrp_if_name_string (struct eigrp_interface *);
+extern const char *eigrp_if_ip_string (struct eigrp_interface *);
+extern const char *eigrp_neigh_ip_string (struct eigrp_neighbor *);
+extern const char *eigrp_topology_ip_string (struct eigrp_prefix_entry *);
+
+extern void eigrp_ip_header_dump(struct ip *);
+extern void eigrp_header_dump(struct eigrp_header *);
+
+extern void show_ip_eigrp_interface_header (struct vty *, struct eigrp *);
+extern void show_ip_eigrp_neighbor_header (struct vty *, struct eigrp *);
+extern void show_ip_eigrp_topology_header (struct vty *, struct eigrp *);
+extern void show_ip_eigrp_interface_detail (struct vty *, struct eigrp *,
+ struct eigrp_interface *);
+extern void show_ip_eigrp_interface_sub (struct vty *, struct eigrp *,
+ struct eigrp_interface *);
+extern void show_ip_eigrp_neighbor_sub (struct vty *, struct eigrp_neighbor *, int);
+extern void show_ip_eigrp_prefix_entry (struct vty *, struct eigrp_prefix_entry *);
+extern void show_ip_eigrp_neighbor_entry (struct vty *, struct eigrp *, struct eigrp_neighbor_entry *);
+
+extern void eigrp_debug_init (void);
+
+#endif /* _ZEBRA_EIGRPD_DUMP_H_ */
diff --git a/eigrpd/eigrp_filter.c b/eigrpd/eigrp_filter.c
new file mode 100644
index 000000000..aaac379d9
--- /dev/null
+++ b/eigrpd/eigrp_filter.c
@@ -0,0 +1,395 @@
+/*
+ * EIGRP Filter Functions.
+ * Copyright (C) 2013-2015
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "command.h"
+#include "prefix.h"
+#include "table.h"
+#include "thread.h"
+#include "memory.h"
+#include "log.h"
+#include "stream.h"
+#include "filter.h"
+#include "sockunion.h"
+#include "sockopt.h"
+#include "routemap.h"
+#include "if_rmap.h"
+#include "plist.h"
+#include "distribute.h"
+#include "md5.h"
+#include "keychain.h"
+#include "privs.h"
+#include "vrf.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_const.h"
+#include "eigrpd/eigrp_filter.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_memory.h"
+
+/*
+ * Distribute-list update functions.
+ */
+void
+eigrp_distribute_update (struct distribute *dist)
+{
+ struct interface *ifp;
+ struct eigrp_interface *ei = NULL;
+ struct access_list *alist;
+ struct prefix_list *plist;
+ //struct route_map *routemap;
+ struct eigrp *e;
+
+ /* if no interface address is present, set list to eigrp process struct */
+ e = eigrp_lookup();
+
+ /* Check if distribute-list was set for process or interface */
+ if (! dist->ifname)
+ {
+ /* access list IN for whole process */
+ if (dist->list[DISTRIBUTE_V4_IN])
+ {
+ alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_IN]);
+ zlog_info("<DEBUG DISTRIBUTE ACL IN FOUND: %s",alist->name);
+ if (alist)
+ e->list[EIGRP_FILTER_IN] = alist;
+ else
+ e->list[EIGRP_FILTER_IN] = NULL;
+ }
+ else
+ {
+ e->list[EIGRP_FILTER_IN] = NULL;
+ }
+
+ /* access list OUT for whole process */
+ if (dist->list[DISTRIBUTE_V4_OUT])
+ {
+ zlog_info("<DEBUG DISTRIBUTE ACL OUT FOUND: %s",dist->list[DISTRIBUTE_V4_OUT]);
+ alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_OUT]);
+ if (alist)
+ e->list[EIGRP_FILTER_OUT] = alist;
+ else
+ e->list[EIGRP_FILTER_OUT] = NULL;
+ }
+ else
+ {
+ e->list[EIGRP_FILTER_OUT] = NULL;
+ }
+
+ /* PREFIX_LIST IN for process */
+ if (dist->prefix[DISTRIBUTE_V4_IN])
+ {
+ zlog_info("<DEBUG DISTRIBUTE PREFIX IN FOUND: %s",dist->prefix[DISTRIBUTE_V4_IN]);
+ plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_IN]);
+ if (plist)
+ {
+ e->prefix[EIGRP_FILTER_IN] = plist;
+ }
+ else
+ e->prefix[EIGRP_FILTER_IN] = NULL;
+ } else
+ e->prefix[EIGRP_FILTER_IN] = NULL;
+
+ /* PREFIX_LIST OUT for process */
+ if (dist->prefix[DISTRIBUTE_V4_OUT])
+ {
+ zlog_info("<DEBUG DISTRIBUTE PREFIX OUT FOUND: %s",dist->prefix[DISTRIBUTE_V4_OUT]);
+ plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_OUT]);
+ if (plist)
+ {
+ e->prefix[EIGRP_FILTER_OUT] = plist;
+
+ }
+ else
+ e->prefix[EIGRP_FILTER_OUT] = NULL;
+ }
+ else
+ e->prefix[EIGRP_FILTER_OUT] = NULL;
+
+ //This is commented out, because the distribute.[ch] code
+ //changes looked poorly written from first glance
+ //commit was 133bdf2d
+ //TODO: DBS
+#if 0
+ /* route-map IN for whole process */
+ if (dist->route[DISTRIBUTE_V4_IN])
+ {
+ routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_IN]);
+ if (routemap)
+ e->routemap[EIGRP_FILTER_IN] = routemap;
+ else
+ e->routemap[EIGRP_FILTER_IN] = NULL;
+ }
+ else
+ {
+ e->routemap[EIGRP_FILTER_IN] = NULL;
+ }
+
+ /* route-map OUT for whole process */
+ if (dist->route[DISTRIBUTE_V4_OUT])
+ {
+ routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_OUT]);
+ if (routemap)
+ e->routemap[EIGRP_FILTER_OUT] = routemap;
+ else
+ e->routemap[EIGRP_FILTER_OUT] = NULL;
+ }
+ else
+ {
+ e->routemap[EIGRP_FILTER_OUT] = NULL;
+ }
+#endif
+ //TODO: check Graceful restart after 10sec
+
+ /* check if there is already GR scheduled */
+ if(e->t_distribute != NULL)
+ {
+ /* if is, cancel schedule */
+ thread_cancel(e->t_distribute);
+ }
+ /* schedule Graceful restart for whole process in 10sec */
+ e->t_distribute = thread_add_timer(master, eigrp_distribute_timer_process, e,(10));
+
+ return;
+ }
+
+ ifp = if_lookup_by_name (dist->ifname);
+ if (ifp == NULL)
+ return;
+
+ zlog_info("<DEBUG ACL 2");
+
+ /*struct eigrp_if_info * info = ifp->info;
+ ei = info->eigrp_interface;*/
+ struct listnode *node, *nnode;
+ struct eigrp_interface *ei2;
+ /* Find proper interface */
+ for (ALL_LIST_ELEMENTS (e->eiflist, node, nnode, ei2))
+ {
+ if(strcmp(ei2->ifp->name,ifp->name) == 0){
+ ei = ei2;
+ break;
+ }
+ }
+
+ if(ei == NULL)
+ {
+ zlog_info("Not Found eigrp interface %s",ifp->name);
+ }
+
+ /* Access-list for interface in */
+ if (dist->list[DISTRIBUTE_V4_IN])
+ {
+ zlog_info("<DEBUG ACL in");
+ alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_IN]);
+ if (alist){
+ ei->list[EIGRP_FILTER_IN] = alist;
+ }
+ else
+ ei->list[EIGRP_FILTER_IN] = NULL;
+ }
+ else
+ {
+ ei->list[EIGRP_FILTER_IN] = NULL;
+ }
+
+ /* Access-list for interface in */
+ if (dist->list[DISTRIBUTE_V4_OUT])
+ {
+ alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_OUT]);
+ if (alist)
+ ei->list[EIGRP_FILTER_OUT] = alist;
+ else
+ ei->list[EIGRP_FILTER_OUT] = NULL;
+
+ }
+ else
+ {
+ ei->list[EIGRP_FILTER_OUT] = NULL;
+ zlog_info("<DEBUG ACL out else");
+ }
+
+ /* Prefix-list for interface in */
+ if (dist->prefix[DISTRIBUTE_V4_IN])
+ {
+ plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_IN]);
+ if (plist)
+ ei->prefix[EIGRP_FILTER_IN] = plist;
+ else
+ ei->prefix[EIGRP_FILTER_IN] = NULL;
+ }
+ else
+ ei->prefix[EIGRP_FILTER_IN] = NULL;
+
+ /* Prefix-list for interface out */
+ if (dist->prefix[DISTRIBUTE_V4_OUT])
+ {
+ plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_OUT]);
+ if (plist)
+ ei->prefix[EIGRP_FILTER_OUT] = plist;
+ else
+ ei->prefix[EIGRP_FILTER_OUT] = NULL;
+ }
+ else
+ ei->prefix[EIGRP_FILTER_OUT] = NULL;
+
+#if 0
+ /* route-map IN for whole process */
+ if (dist->route[DISTRIBUTE_V4_IN])
+ {
+ zlog_info("<DEBUG ACL ALL in");
+ routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_IN]);
+ if (routemap)
+ ei->routemap[EIGRP_FILTER_IN] = routemap;
+ else
+ ei->routemap[EIGRP_FILTER_IN] = NULL;
+ }
+ else
+ {
+ ei->routemap[EIGRP_FILTER_IN] = NULL;
+ }
+
+ /* route-map OUT for whole process */
+ if (dist->route[DISTRIBUTE_V4_OUT])
+ {
+ routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_OUT]);
+ if (routemap)
+ ei->routemap[EIGRP_FILTER_OUT] = routemap;
+ else
+ ei->routemap[EIGRP_FILTER_OUT] = NULL;
+ }
+ else
+ {
+ ei->routemap[EIGRP_FILTER_OUT] = NULL;
+ }
+#endif
+ //TODO: check Graceful restart after 10sec
+
+ /* check if there is already GR scheduled */
+ if(ei->t_distribute != NULL)
+ {
+ /* if is, cancel schedule */
+ thread_cancel(ei->t_distribute);
+ }
+ /* schedule Graceful restart for interface in 10sec */
+ e->t_distribute = thread_add_timer(master, eigrp_distribute_timer_interface, ei,(10));
+
+}
+
+/*
+ * Function called by prefix-list and access-list update
+ */
+void
+eigrp_distribute_update_interface (struct interface *ifp)
+{
+ struct distribute *dist;
+
+ dist = distribute_lookup (ifp->name);
+ if (dist)
+ eigrp_distribute_update (dist);
+}
+
+/* Update all interface's distribute list.
+ * Function used in hook for prefix-list
+ */
+void
+eigrp_distribute_update_all (struct prefix_list *notused)
+{
+ struct interface *ifp;
+ struct listnode *node, *nnode;
+
+ for (ALL_LIST_ELEMENTS (vrf_iflist(VRF_DEFAULT), node, nnode, ifp))
+ eigrp_distribute_update_interface (ifp);
+}
+
+/*
+ * Function used in hook for acces-list
+ */
+void
+eigrp_distribute_update_all_wrapper(struct access_list *notused)
+{
+ eigrp_distribute_update_all(NULL);
+}
+
+/*
+ * @fn eigrp_distribute_timer_process
+ *
+ * @param[in] thread current execution thread timer is associated with
+ *
+ * @return int always returns 0
+ *
+ * @par
+ * Called when 10sec waiting time expire and
+ * executes Graceful restart for whole process
+ */
+int
+eigrp_distribute_timer_process (struct thread *thread)
+{
+ struct eigrp *eigrp;
+
+ eigrp = THREAD_ARG(thread);
+ eigrp->t_distribute = NULL;
+
+ /* execute GR for whole process */
+ eigrp_update_send_process_GR(eigrp, EIGRP_GR_FILTER, NULL);
+
+ return 0;
+}
+
+/*
+ * @fn eigrp_distribute_timer_interface
+ *
+ * @param[in] thread current execution thread timer is associated with
+ *
+ * @return int always returns 0
+ *
+ * @par
+ * Called when 10sec waiting time expire and
+ * executes Graceful restart for interface
+ */
+int
+eigrp_distribute_timer_interface (struct thread *thread)
+{
+ struct eigrp_interface *ei;
+
+ ei = THREAD_ARG(thread);
+ ei->t_distribute = NULL;
+
+ /* execute GR for interface */
+ eigrp_update_send_interface_GR(ei, EIGRP_GR_FILTER, NULL);
+
+ return 0;
+}
diff --git a/eigrpd/eigrp_filter.h b/eigrpd/eigrp_filter.h
new file mode 100644
index 000000000..01c776b17
--- /dev/null
+++ b/eigrpd/eigrp_filter.h
@@ -0,0 +1,44 @@
+/*
+ * EIGRP Filter Functions.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef EIGRPD_EIGRP_FILTER_H_
+#define EIGRPD_EIGRP_FILTER_H_
+
+extern void eigrp_distribute_update (struct distribute *);
+extern void eigrp_distribute_update_interface (struct interface *);
+extern void eigrp_distribute_update_all (struct prefix_list *);
+extern void eigrp_distribute_update_all_wrapper(struct access_list *);
+extern int eigrp_distribute_timer_process (struct thread *);
+extern int eigrp_distribute_timer_interface (struct thread *);
+
+#endif /* EIGRPD_EIGRP_FILTER_H_ */
diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c
new file mode 100644
index 000000000..0277dc830
--- /dev/null
+++ b/eigrpd/eigrp_fsm.c
@@ -0,0 +1,502 @@
+/*
+ * EIGRPd Finite State Machine (DUAL).
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ *
+ * This file contains functions for executing logic of finite state machine
+ *
+ * +------------ +
+ * | (7) |
+ * | v
+ * +=====================================+
+ * | |
+ * | Passive |
+ * | |
+ * +=====================================+
+ * ^ | ^ ^ ^ |
+ * (3)| | (1)| | (1)| |
+ * | (0)| | (3)| | (2)|
+ * | | | | | +---------------+
+ * | | | | | \
+ * +--------+ | | | +-----------------+ \
+ * / / / | \ \
+ * / / / +----+ \ \
+ * | | | | | |
+ * | v | | | v
+ * +===========+ (6) +===========+ +===========+ (6) +===========+
+ * | |------->| | (5) | |-------->| |
+ * | | (4) | |------>| | (4) | |
+ * | ACTIVE 0 |<-------| ACTIVE 1 | | ACTIVE 2 |<--------| ACTIVE 3 |
+ * +--| | +--| | +--| | +--| |
+ * | +===========+ | +===========+ | +===========+ | +===========+
+ * | ^ |(5) | ^ | ^ ^ | ^
+ * | | +---------|------|------------|----+ | | |
+ * +-------+ +------+ +---------+ +---------+
+ * (7) (7) (7) (7)
+ *
+ * 0- input event other than query from successor, FC not satisfied
+ * 1- last reply, FD is reset
+ * 2- query from successor, FC not satisfied
+ * 3- last reply, FC satisfied with current value of FDij
+ * 4- distance increase while in active state
+ * 5- query from successor while in active state
+ * 6- last reply, FC not satisfied with current value of FDij
+ * 7- state not changed, usually by receiving not last reply
+ *
+ */
+
+#include <thread.h>
+#include <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "log.h"
+#include "linklist.h"
+#include "vty.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+
+/*
+ * Prototypes
+ */
+int
+eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *);
+int
+eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *);
+int
+eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *);
+int
+eigrp_fsm_event_lr(struct eigrp_fsm_action_message *);
+int
+eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *);
+int
+eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *);
+int
+eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *);
+int
+eigrp_fsm_event_qact(struct eigrp_fsm_action_message *);
+
+//---------------------------------------------------------------------
+
+/*
+ * NSM - field of fields of struct containing one function each.
+ * Which function is used depends on actual state of FSM and occurred
+ * event(arrow in diagram). Usage:
+ * NSM[actual/starting state][occurred event].func
+ * Functions are should be executed within separate thread.
+ */
+struct {
+ int
+ (*func)(struct eigrp_fsm_action_message *);
+} NSM[EIGRP_FSM_STATE_MAX][EIGRP_FSM_EVENT_MAX] = { {
+//PASSIVE STATE
+ { eigrp_fsm_event_nq_fcn }, /* Event 0 */
+ { eigrp_fsm_event_keep_state }, /* Event 1 */
+ { eigrp_fsm_event_q_fcn }, /* Event 2 */
+ { eigrp_fsm_event_keep_state }, /* Event 3 */
+ { eigrp_fsm_event_keep_state }, /* Event 4 */
+ { eigrp_fsm_event_keep_state }, /* Event 5 */
+ { eigrp_fsm_event_keep_state }, /* Event 6 */
+ { eigrp_fsm_event_keep_state }, /* Event 7 */
+}, {
+//Active 0 state
+ { eigrp_fsm_event_keep_state }, /* Event 0 */
+ { eigrp_fsm_event_keep_state }, /* Event 1 */
+ { eigrp_fsm_event_keep_state }, /* Event 2 */
+ { eigrp_fsm_event_lr_fcs }, /* Event 3 */
+ { eigrp_fsm_event_keep_state }, /* Event 4 */
+ { eigrp_fsm_event_qact }, /* Event 5 */
+ { eigrp_fsm_event_lr_fcn }, /* Event 6 */
+ { eigrp_fsm_event_keep_state }, /* Event 7 */
+
+}, {
+//Active 1 state
+ { eigrp_fsm_event_keep_state }, /* Event 0 */
+ { eigrp_fsm_event_lr }, /* Event 1 */
+ { eigrp_fsm_event_keep_state }, /* Event 2 */
+ { eigrp_fsm_event_keep_state }, /* Event 3 */
+ { eigrp_fsm_event_dinc }, /* Event 4 */
+ { eigrp_fsm_event_qact }, /* Event 5 */
+ { eigrp_fsm_event_keep_state }, /* Event 6 */
+ { eigrp_fsm_event_keep_state }, /* Event 7 */
+}, {
+//Active 2 state
+ { eigrp_fsm_event_keep_state }, /* Event 0 */
+ { eigrp_fsm_event_keep_state }, /* Event 1 */
+ { eigrp_fsm_event_keep_state }, /* Event 2 */
+ { eigrp_fsm_event_lr_fcs }, /* Event 3 */
+ { eigrp_fsm_event_keep_state }, /* Event 4 */
+ { eigrp_fsm_event_keep_state }, /* Event 5 */
+ { eigrp_fsm_event_lr_fcn }, /* Event 6 */
+ { eigrp_fsm_event_keep_state }, /* Event 7 */
+}, {
+//Active 3 state
+ { eigrp_fsm_event_keep_state }, /* Event 0 */
+ { eigrp_fsm_event_lr }, /* Event 1 */
+ { eigrp_fsm_event_keep_state }, /* Event 2 */
+ { eigrp_fsm_event_keep_state }, /* Event 3 */
+ { eigrp_fsm_event_dinc }, /* Event 4 */
+ { eigrp_fsm_event_keep_state }, /* Event 5 */
+ { eigrp_fsm_event_keep_state }, /* Event 6 */
+ { eigrp_fsm_event_keep_state }, /* Event 7 */
+}, };
+
+/*
+ * Main function in which are make decisions which event occurred.
+ * msg - argument of type struct eigrp_fsm_action_message contain
+ * details about what happen
+ *
+ * Return number of occurred event (arrow in diagram).
+ *
+ */
+int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) {
+ // Loading base information from message
+ //struct eigrp *eigrp = msg->eigrp;
+ struct eigrp_prefix_entry *prefix = msg->prefix;
+ struct eigrp_neighbor_entry *entry = msg->entry;
+ u_char actual_state = prefix->state;
+
+ if (entry == NULL) {
+ entry = eigrp_neighbor_entry_new();
+ entry->adv_router = msg->adv_router;
+ entry->ei = msg->adv_router->ei;
+ entry->prefix = prefix;
+ msg->entry = entry;
+ }
+
+ // Dividing by actual state of prefix's FSM
+ switch (actual_state) {
+ case EIGRP_FSM_STATE_PASSIVE: {
+ //Calculate resultant metrics and insert to correct position in entries list
+ eigrp_topology_update_distance(msg);
+
+ struct eigrp_neighbor_entry * head =
+ (struct eigrp_neighbor_entry *) entry->prefix->entries->head->data;
+ //zlog_info ("flag: %d rdist: %u dist: %u pfdist: %u pdist: %u", head->flags, head->reported_distance, head->distance, prefix->fdistance, prefix->distance);
+ if (head->reported_distance < prefix->fdistance) {
+ return EIGRP_FSM_KEEP_STATE;
+ }
+ /*
+ * if best entry doesn't satisfy feasibility condition it means move to active state
+ * dependently if it was query from successor
+ */
+ else {
+ if (msg->packet_type == EIGRP_OPC_QUERY) {
+ return EIGRP_FSM_EVENT_Q_FCN;
+ } else {
+ return EIGRP_FSM_EVENT_NQ_FCN;
+ }
+ }
+
+ break;
+ }
+ case EIGRP_FSM_STATE_ACTIVE_0: {
+ eigrp_topology_update_distance(msg);
+
+ if (msg->packet_type == EIGRP_OPC_REPLY) {
+ listnode_delete(prefix->rij, entry->adv_router);
+ if (prefix->rij->count) {
+ return EIGRP_FSM_KEEP_STATE;
+ } else {
+ zlog_info("All reply received\n");
+ if (((struct eigrp_neighbor_entry *) prefix->entries->head->data)->reported_distance
+ < prefix->fdistance) {
+ return EIGRP_FSM_EVENT_LR_FCS;
+ }
+
+ return EIGRP_FSM_EVENT_LR_FCN;
+ }
+ } else if (msg->packet_type == EIGRP_OPC_QUERY
+ && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
+ return EIGRP_FSM_EVENT_QACT;
+ }
+
+ return EIGRP_FSM_KEEP_STATE;
+
+ break;
+ }
+ case EIGRP_FSM_STATE_ACTIVE_1: {
+ int change = eigrp_topology_update_distance(msg);
+
+ if (msg->packet_type == EIGRP_OPC_QUERY
+ && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
+ return EIGRP_FSM_EVENT_QACT;
+ } else if (msg->packet_type == EIGRP_OPC_REPLY) {
+ listnode_delete(prefix->rij, entry->adv_router);
+
+ if (change == 1
+ && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
+ return EIGRP_FSM_EVENT_DINC;
+ } else if (prefix->rij->count) {
+ return EIGRP_FSM_KEEP_STATE;
+ } else {
+ zlog_info("All reply received\n");
+ return EIGRP_FSM_EVENT_LR;
+ }
+ } else if (msg->packet_type == EIGRP_OPC_UPDATE && change == 1
+ && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
+ return EIGRP_FSM_EVENT_DINC;
+ }
+ return EIGRP_FSM_KEEP_STATE;
+
+ break;
+ }
+ case EIGRP_FSM_STATE_ACTIVE_2: {
+
+ eigrp_topology_update_distance(msg);
+
+ if (msg->packet_type == EIGRP_OPC_REPLY) {
+ listnode_delete(prefix->rij, entry->adv_router);
+ if (prefix->rij->count) {
+ return EIGRP_FSM_KEEP_STATE;
+ } else {
+ zlog_info("All reply received\n");
+ if (((struct eigrp_neighbor_entry *) prefix->entries->head->data)->reported_distance
+ < prefix->fdistance) {
+ return EIGRP_FSM_EVENT_LR_FCS;
+ }
+
+ return EIGRP_FSM_EVENT_LR_FCN;
+ }
+ }
+ return EIGRP_FSM_KEEP_STATE;
+
+ break;
+ }
+ case EIGRP_FSM_STATE_ACTIVE_3: {
+
+ int change = eigrp_topology_update_distance(msg);
+
+ if (msg->packet_type == EIGRP_OPC_REPLY) {
+ listnode_delete(prefix->rij, entry->adv_router);
+
+ if (change == 1
+ && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
+ return EIGRP_FSM_EVENT_DINC;
+ } else if (prefix->rij->count) {
+ return EIGRP_FSM_KEEP_STATE;
+ } else {
+ zlog_info("All reply received\n");
+ return EIGRP_FSM_EVENT_LR;
+ }
+ } else if (msg->packet_type == EIGRP_OPC_UPDATE && change == 1
+ && (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
+ return EIGRP_FSM_EVENT_DINC;
+ }
+ return EIGRP_FSM_KEEP_STATE;
+
+ break;
+ }
+ }
+
+ return EIGRP_FSM_KEEP_STATE;
+}
+
+/*
+ * Function made to execute in separate thread.
+ * Load argument from thread and execute proper NSM function
+ */
+int eigrp_fsm_event(struct eigrp_fsm_action_message *msg, int event) {
+
+ zlog_info("EIGRP AS: %d State: %d Event: %d Network: %s\n", msg->eigrp->AS,
+ msg->prefix->state, event, eigrp_topology_ip_string(msg->prefix));
+ (*(NSM[msg->prefix->state][event].func))(msg);
+
+ return 1;
+}
+/*
+ * Function of event 0.
+ *
+ */
+int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg) {
+ struct eigrp *eigrp = msg->eigrp;
+ struct eigrp_prefix_entry *prefix = msg->prefix;
+ struct list *successors = eigrp_topology_get_successor(prefix);
+ prefix->state = EIGRP_FSM_STATE_ACTIVE_1;
+ prefix->rdistance = prefix->distance = prefix->fdistance =
+ ((struct eigrp_neighbor_entry *) successors->head->data)->distance;
+ prefix->reported_metric =
+ ((struct eigrp_neighbor_entry *) successors->head->data)->total_metric;
+
+ if (eigrp_nbr_count_get()) {
+ prefix->req_action |= EIGRP_FSM_NEED_QUERY;
+ listnode_add(eigrp->topology_changes_internalIPV4,prefix);
+ } else {
+ eigrp_fsm_event_lr(msg); //in the case that there are no more neighbors left
+ }
+
+ return 1;
+}
+
+int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg) {
+ struct eigrp *eigrp = msg->eigrp;
+ struct eigrp_prefix_entry *prefix = msg->prefix;
+ struct list *successors = eigrp_topology_get_successor(prefix);
+ prefix->state = EIGRP_FSM_STATE_ACTIVE_3;
+ prefix->rdistance = prefix->distance = prefix->fdistance =
+ ((struct eigrp_neighbor_entry *) successors->head->data)->distance;
+ prefix->reported_metric =
+ ((struct eigrp_neighbor_entry *) successors->head->data)->total_metric;
+ if (eigrp_nbr_count_get()) {
+ prefix->req_action |= EIGRP_FSM_NEED_QUERY;
+ listnode_add(eigrp->topology_changes_internalIPV4,prefix);
+ } else {
+ eigrp_fsm_event_lr(msg); //in the case that there are no more neighbors left
+ }
+
+ return 1;
+}
+
+int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg) {
+
+ struct eigrp_prefix_entry *prefix = msg->prefix;
+
+ if (prefix->state == EIGRP_FSM_STATE_PASSIVE) {
+ if (!eigrp_metrics_is_same(&prefix->reported_metric,
+ &((struct eigrp_neighbor_entry *) prefix->entries->head->data)->total_metric)) {
+ prefix->rdistance =
+ prefix->fdistance =
+ prefix->distance =
+ ((struct eigrp_neighbor_entry *) prefix->entries->head->data)->distance;
+ prefix->reported_metric =
+ ((struct eigrp_neighbor_entry *) prefix->entries->head->data)->total_metric;
+ if (msg->packet_type == EIGRP_OPC_QUERY)
+ eigrp_send_reply(msg->adv_router, prefix);
+ prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
+ listnode_add((eigrp_lookup())->topology_changes_internalIPV4,prefix);
+ }
+ eigrp_topology_update_node_flags(prefix);
+ eigrp_update_routing_table(prefix);
+ }
+
+ if (msg->packet_type == EIGRP_OPC_QUERY)
+ eigrp_send_reply(msg->adv_router, prefix);
+
+ return 1;
+}
+
+int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg) {
+ struct eigrp *eigrp = msg->eigrp;
+ struct eigrp_prefix_entry *prefix = msg->prefix;
+ prefix->fdistance =
+ prefix->distance =
+ prefix->rdistance =
+ ((struct eigrp_neighbor_entry *) (prefix->entries->head->data))->distance;
+ prefix->reported_metric =
+ ((struct eigrp_neighbor_entry *) (prefix->entries->head->data))->total_metric;
+ if (prefix->state == EIGRP_FSM_STATE_ACTIVE_3)
+ eigrp_send_reply(
+ ((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor(
+ prefix)->head->data))->adv_router, prefix);
+ prefix->state = EIGRP_FSM_STATE_PASSIVE;
+ prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
+ listnode_add(eigrp->topology_changes_internalIPV4,prefix);
+ eigrp_topology_update_node_flags(prefix);
+ eigrp_update_routing_table(prefix);
+ eigrp_update_topology_table_prefix(eigrp->topology_table, prefix);
+
+ return 1;
+}
+
+int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg) {
+
+ msg->prefix->state =
+ msg->prefix->state == EIGRP_FSM_STATE_ACTIVE_1 ?
+ EIGRP_FSM_STATE_ACTIVE_0 : EIGRP_FSM_STATE_ACTIVE_2;
+ msg->prefix->distance =
+ ((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor(
+ msg->prefix)->head->data))->distance;
+ if (!msg->prefix->rij->count) {
+ (*(NSM[msg->prefix->state][eigrp_get_fsm_event(msg)].func))(msg);
+ }
+
+ return 1;
+}
+
+int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg) {
+ struct eigrp *eigrp = msg->eigrp;
+ struct eigrp_prefix_entry *prefix = msg->prefix;
+ prefix->state = EIGRP_FSM_STATE_PASSIVE;
+ prefix->distance =
+ prefix->rdistance =
+ ((struct eigrp_neighbor_entry *) (prefix->entries->head->data))->distance;
+ prefix->reported_metric =
+ ((struct eigrp_neighbor_entry *) (prefix->entries->head->data))->total_metric;
+ prefix->fdistance =
+ prefix->fdistance > prefix->distance ?
+ prefix->distance : prefix->fdistance;
+ if (prefix->state == EIGRP_FSM_STATE_ACTIVE_2)
+ eigrp_send_reply(
+ ((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor(
+ prefix)->head->data))->adv_router, prefix);
+ prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
+ listnode_add(eigrp->topology_changes_internalIPV4,prefix);
+ eigrp_topology_update_node_flags(prefix);
+ eigrp_update_routing_table(prefix);
+ eigrp_update_topology_table_prefix(eigrp->topology_table, prefix);
+
+ return 1;
+}
+
+int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg) {
+ struct eigrp *eigrp = msg->eigrp;
+ struct eigrp_prefix_entry *prefix = msg->prefix;
+ prefix->state =
+ prefix->state == EIGRP_FSM_STATE_ACTIVE_0 ?
+ EIGRP_FSM_STATE_ACTIVE_1 : EIGRP_FSM_STATE_ACTIVE_3;
+ struct eigrp_neighbor_entry *best_successor =
+ ((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor(
+ prefix)->head->data));
+ prefix->rdistance = prefix->distance = best_successor->distance;
+ prefix->reported_metric = best_successor->total_metric;
+ if (eigrp_nbr_count_get()) {
+ prefix->req_action |= EIGRP_FSM_NEED_QUERY;
+ listnode_add(eigrp->topology_changes_internalIPV4,prefix);
+ } else {
+ eigrp_fsm_event_lr(msg); //in the case that there are no more neighbors left
+ }
+
+ return 1;
+}
+
+int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg) {
+ msg->prefix->state = EIGRP_FSM_STATE_ACTIVE_2;
+ msg->prefix->distance =
+ ((struct eigrp_neighbor_entry *) (eigrp_topology_get_successor(
+ msg->prefix)->head->data))->distance;
+ return 1;
+}
diff --git a/eigrpd/eigrp_fsm.h b/eigrpd/eigrp_fsm.h
new file mode 100644
index 000000000..0677c09d7
--- /dev/null
+++ b/eigrpd/eigrp_fsm.h
@@ -0,0 +1,37 @@
+/*
+ * EIGRP Finite State Machine (DUAL).
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_FSM_H
+#define _ZEBRA_EIGRP_FSM_H
+
+
+extern int eigrp_get_fsm_event (struct eigrp_fsm_action_message *);
+extern int eigrp_fsm_event (struct eigrp_fsm_action_message *, int);
+
+
+#endif /* _ZEBRA_EIGRP_DUAL_H */
diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c
new file mode 100644
index 000000000..df4ed1069
--- /dev/null
+++ b/eigrpd/eigrp_hello.c
@@ -0,0 +1,774 @@
+/*
+ * EIGRP Sending and Receiving EIGRP Hello Packets.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "vty.h"
+#include "md5.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_macros.h"
+
+/* Packet Type String. */
+static const struct message eigrp_general_tlv_type_str[] =
+{
+ { EIGRP_TLV_PARAMETER, "PARAMETER" },
+ { EIGRP_TLV_AUTH, "AUTH" },
+ { EIGRP_TLV_SEQ, "SEQ" },
+ { EIGRP_TLV_SW_VERSION, "SW_VERSION" },
+ { EIGRP_TLV_NEXT_MCAST_SEQ, "NEXT_MCAST_SEQ" },
+ { EIGRP_TLV_PEER_TERMINATION, "PEER_TERMINATION" },
+ { EIGRP_TLV_PEER_MTRLIST, "PEER_MTRLIST" },
+ { EIGRP_TLV_PEER_TIDLIST, "PEER_TIDLIST" },
+};
+
+static const size_t eigrp_general_tlv_type_str_max = sizeof(eigrp_general_tlv_type_str) /
+ sizeof(eigrp_general_tlv_type_str[0]);
+
+
+/*
+ * @fn eigrp_hello_timer
+ *
+ * @param[in] thread current execution thread timer is associated with
+ *
+ * @return int always returns 0
+ *
+ * @par
+ * Called once per "hello" time interval, default 5 seconds
+ * Sends hello packet via multicast for all interfaces eigrp
+ * is configured for
+ */
+int
+eigrp_hello_timer (struct thread *thread)
+{
+ struct eigrp_interface *ei;
+
+ ei = THREAD_ARG(thread);
+ ei->t_hello = NULL;
+
+ if (IS_DEBUG_EIGRP(0, TIMERS))
+ zlog (NULL, LOG_DEBUG, "Start Hello Timer (%s) Expire [%u]",
+ IF_NAME(ei), EIGRP_IF_PARAM(ei, v_hello));
+
+ /* Sending hello packet. */
+ eigrp_hello_send(ei, EIGRP_HELLO_NORMAL, NULL);
+
+ /* Hello timer set. */
+ ei->t_hello = thread_add_timer(master, eigrp_hello_timer, ei,
+ EIGRP_IF_PARAM(ei, v_hello));
+
+ return 0;
+}
+
+/**
+ * @fn eigrp_hello_parameter_decode
+ *
+ * @param[in] nbr neighbor the ACK should be sent to
+ * @param[in] param pointer packet TLV is stored to
+ *
+ * @return u_int16_t number of bytes added to packet stream
+ *
+ * @par
+ * Encode Parameter TLV, used to convey metric weights and the hold time.
+ *
+ * @usage
+ * Note the addition of K6 for the new extended metrics, and does not apply to
+ * older TLV packet formats.
+ */
+static void
+eigrp_hello_parameter_decode (struct eigrp_neighbor *nbr,
+ struct eigrp_tlv_hdr_type *tlv)
+{
+ struct eigrp *eigrp = nbr->ei->eigrp;
+ struct TLV_Parameter_Type *param = (struct TLV_Parameter_Type *)tlv;
+
+ /* copy over the values passed in by the neighbor */
+ nbr->K1 = param->K1;
+ nbr->K2 = param->K2;
+ nbr->K3 = param->K3;
+ nbr->K4 = param->K4;
+ nbr->K5 = param->K5;
+ nbr->K6 = param->K6;
+ nbr->v_holddown = ntohs(param->hold_time);
+
+ /*
+ * Check K1-K5 have the correct values to be able to become neighbors
+ * K6 does not have to match
+ */
+ if ((eigrp->k_values[0] == nbr->K1) &&
+ (eigrp->k_values[1] == nbr->K2) &&
+ (eigrp->k_values[2] == nbr->K3) &&
+ (eigrp->k_values[3] == nbr->K4) &&
+ (eigrp->k_values[4] == nbr->K5))
+ {
+
+ if (eigrp_nbr_state_get(nbr) == EIGRP_NEIGHBOR_DOWN)
+ {
+ zlog_info("Neighbor %s (%s) is pending: new adjacency",
+ inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
+
+ /* Expedited hello sent */
+ eigrp_hello_send(nbr->ei, EIGRP_HELLO_NORMAL, NULL);
+
+// if(ntohl(nbr->ei->address->u.prefix4.s_addr) > ntohl(nbr->src.s_addr))
+ eigrp_update_send_init(nbr);
+
+ eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING);
+ }
+ }
+ else
+ {
+ if (eigrp_nbr_state_get(nbr) != EIGRP_NEIGHBOR_DOWN)
+ {
+ if ((param->K1 & param->K2 & param->K3 & param->K4 & param->K5) == 255)
+ {
+ zlog_info ("Neighbor %s (%s) is down: Interface PEER-TERMINATION received",
+ inet_ntoa (nbr->src),ifindex2ifname (nbr->ei->ifp->ifindex));
+ eigrp_nbr_delete (nbr);
+ }
+ else
+ {
+ zlog_info ("Neighbor %s (%s) going down: Kvalue mismatch",
+ inet_ntoa (nbr->src),ifindex2ifname (nbr->ei->ifp->ifindex));
+ eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
+ }
+ }
+ }
+}
+
+static u_char
+eigrp_hello_authentication_decode(struct stream *s, struct eigrp_tlv_hdr_type *tlv_header, struct eigrp_neighbor *nbr)
+{
+
+ struct TLV_MD5_Authentication_Type *md5;
+
+ md5 = (struct TLV_MD5_Authentication_Type *) tlv_header;
+
+ if(md5->auth_type == EIGRP_AUTH_TYPE_MD5)
+ return eigrp_check_md5_digest(s, md5, nbr, EIGRP_AUTH_BASIC_HELLO_FLAG);
+ else if (md5->auth_type == EIGRP_AUTH_TYPE_SHA256)
+ return eigrp_check_sha256_digest(s, (struct TLV_SHA256_Authentication_Type *) tlv_header, nbr, EIGRP_AUTH_BASIC_HELLO_FLAG);
+
+ return 0;
+}
+
+/**
+ * @fn eigrp_sw_version_decode
+ *
+ * @param[in] nbr neighbor the ACK shoudl be sent to
+ * @param[in] param pointer to TLV software version information
+ *
+ * @return void
+ *
+ * @par
+ * Read the software version in the specified location.
+ * This consists of two bytes of OS version, and two bytes of EIGRP
+ * revision number.
+ */
+static void
+eigrp_sw_version_decode (struct eigrp_neighbor *nbr,
+ struct eigrp_tlv_hdr_type *tlv)
+{
+ struct TLV_Software_Type *version = (struct TLV_Software_Type *)tlv;
+
+ nbr->os_rel_major = version->vender_major;
+ nbr->os_rel_minor = version->vender_minor;
+ nbr->tlv_rel_major = version->eigrp_major;
+ nbr->tlv_rel_minor = version->eigrp_minor;
+ return;
+}
+
+/**
+ * @fn eigrp_peer_termination_decode
+ *
+ * @param[in] nbr neighbor the ACK shoudl be sent to
+ * @param[in] tlv pointer to TLV software version information
+ *
+ * @return void
+ *
+ * @par
+ * Read the address in the TLV and match to out address. If
+ * a match is found, move the sending neighbor to the down state. If
+ * out address is not in the TLV, then ignore the peer termination
+ */
+static void
+eigrp_peer_termination_decode (struct eigrp_neighbor *nbr,
+ struct eigrp_tlv_hdr_type *tlv)
+{
+ struct TLV_Peer_Termination_type *param = (struct TLV_Peer_Termination_type *)tlv;
+
+ uint32_t my_ip = nbr->ei->address->u.prefix4.s_addr;
+ uint32_t received_ip = param->neighbor_ip;
+
+ if(my_ip == received_ip)
+ {
+ zlog_info ("Neighbor %s (%s) is down: Peer Termination received",
+ inet_ntoa (nbr->src),ifindex2ifname (nbr->ei->ifp->ifindex));
+ /* set neighbor to DOWN */
+ nbr->state = EIGRP_NEIGHBOR_DOWN;
+ /* delete neighbor */
+ eigrp_nbr_delete (nbr);
+ }
+}
+
+/**
+ * @fn eigrp_peer_termination_encode
+ *
+ * @param[in,out] s packet stream TLV is stored to
+ * @param[in] nbr_addr pointer to neighbor address for Peer Termination TLV
+ *
+ * @return u_int16_t number of bytes added to packet stream
+ *
+ * @par
+ * Function used to encode Peer Termination TLV to Hello packet.
+ */
+static u_int16_t
+eigrp_peer_termination_encode (struct stream *s, struct in_addr *nbr_addr)
+{
+ u_int16_t length = EIGRP_TLV_PEER_TERMINATION_LEN;
+
+ /* fill in type and length */
+ stream_putw(s, EIGRP_TLV_PEER_TERMINATION);
+ stream_putw(s, length);
+
+ /* fill in unknown field 0x04 */
+ stream_putc(s, 0x04);
+
+ /* finally neighbor IP address */
+ stream_put_ipv4(s, nbr_addr->s_addr);
+
+ return(length);
+}
+
+/*
+ * @fn eigrp_hello_receive
+ *
+ * @param[in] eigrp eigrp routing process
+ * @param[in] iph pointer to ip header
+ * @param[in] eigrph pointer to eigrp header
+ * @param[in] s input ip stream
+ * @param[in] ei eigrp interface packet arrived on
+ * @param[in] size size of eigrp packet
+ *
+ * @return void
+ *
+ * @par
+ * This is the main worker function for processing hello packets. It
+ * will validate the peer associated with the src ip address of the ip
+ * header, and then decode each of the general TLVs which the packet
+ * may contain.
+ *
+ * @usage
+ * Not all TLVs are current decoder. This is a work in progress..
+ */
+void
+eigrp_hello_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
+ struct stream *s, struct eigrp_interface *ei, int size)
+{
+ struct eigrp_tlv_hdr_type *tlv_header;
+ struct eigrp_neighbor *nbr;
+ uint16_t type;
+ uint16_t length;
+
+ /* get neighbor struct */
+ nbr = eigrp_nbr_get(ei, eigrph, iph);
+
+ /* neighbor must be valid, eigrp_nbr_get creates if none existed */
+ assert(nbr);
+
+ if (IS_DEBUG_EIGRP_PACKET(eigrph->opcode - 1, RECV))
+ zlog_debug("Processing Hello size[%u] int(%s) nbr(%s)",
+ size, ifindex2ifname(nbr->ei->ifp->ifindex),
+ inet_ntoa(nbr->src));
+
+ size -= EIGRP_HEADER_LEN;
+ if (size < 0)
+ return;
+
+ tlv_header = (struct eigrp_tlv_hdr_type *)eigrph->tlv;
+
+ do {
+ type = ntohs(tlv_header->type);
+ length = ntohs(tlv_header->length);
+
+ if ((length > 0) && (length <= size))
+ {
+ if (IS_DEBUG_EIGRP_PACKET(0, RECV))
+ zlog_debug(" General TLV(%s)", LOOKUP(eigrp_general_tlv_type_str, type));
+
+ // determine what General TLV is being processed
+ switch (type)
+ {
+ case EIGRP_TLV_PARAMETER:
+ eigrp_hello_parameter_decode(nbr, tlv_header);
+ break;
+ case EIGRP_TLV_AUTH:
+ {
+ if(eigrp_hello_authentication_decode(s,tlv_header,nbr) == 0)
+ return;
+ else
+ break;
+ break;
+ }
+ case EIGRP_TLV_SEQ:
+ break;
+ case EIGRP_TLV_SW_VERSION:
+ eigrp_sw_version_decode(nbr, tlv_header);
+ break;
+ case EIGRP_TLV_NEXT_MCAST_SEQ:
+ break;
+ case EIGRP_TLV_PEER_TERMINATION:
+ eigrp_peer_termination_decode(nbr, tlv_header);
+ break;
+ case EIGRP_TLV_PEER_MTRLIST:
+ case EIGRP_TLV_PEER_TIDLIST:
+ break;
+ default:
+ break;
+ }
+ }
+
+ tlv_header = (struct eigrp_tlv_hdr_type *)(((char *)tlv_header) + length);
+ size -= length;
+
+ } while (size > 0);
+
+
+ /*If received packet is hello with Parameter TLV*/
+ if (ntohl(eigrph->ack) == 0)
+ {
+ /* increment statistics. */
+ ei->hello_in++;
+ eigrp_nbr_state_update(nbr);
+
+ }
+
+ if (IS_DEBUG_EIGRP_PACKET(0, RECV))
+ zlog_debug("Hello Packet received from %s", inet_ntoa(nbr->src));
+
+}
+
+/**
+ * @fn eigrp_sw_version_encode
+ *
+ * @param[in,out] s packet stream TLV is stored to
+ *
+ * @return u_int16_t number of bytes added to packet stream
+ *
+ * @par
+ * Store the software version in the specified location.
+ * This consists of two bytes of OS version, and two bytes of EIGRP
+ * revision number.
+ */
+static u_int16_t
+eigrp_sw_version_encode (struct stream *s)
+{
+ u_int16_t length = EIGRP_TLV_SW_VERSION_LEN;
+
+ // setup the tlv fields
+ stream_putw(s, EIGRP_TLV_SW_VERSION);
+ stream_putw(s, length);
+
+ // encode the version of quagga we're running
+ // DVS: need to figure out a cleaner way to do this
+ stream_putc(s, 0); //!< major os version
+ stream_putc(s, 99); //!< minor os version
+
+ /* and the core eigrp version */
+ stream_putc(s, EIGRP_MAJOR_VERSION);
+ stream_putc(s, EIGRP_MINOR_VERSION);
+
+ return(length);
+}
+
+/**
+ * @fn eigrp_tidlist_encode
+ *
+ * @param[in,out] s packet stream TLV is stored to
+ *
+ * @return void
+ *
+ * @par
+ * If doing mutli-topology, then store the supported TID list.
+ * This is currently a place holder function
+ */
+static u_int16_t
+eigrp_tidlist_encode (struct stream *s)
+{
+ //u_int16_t length = EIGRP_TLV_SW_VERSION_LEN;
+ return 0;
+}
+
+/**
+ * @fn eigrp_sequence_encode
+ *
+ * @param[in,out] s packet stream TLV is stored to
+ *
+ * @return u_int16_t number of bytes added to packet stream
+ *
+ * @par
+ * Part of conditional receive process
+ *
+ */
+static u_int16_t
+eigrp_sequence_encode (struct stream *s)
+{
+ u_int16_t length = EIGRP_TLV_SEQ_BASE_LEN;
+ struct eigrp *eigrp;
+ struct eigrp_interface *ei;
+ struct listnode *node, *node2, *nnode2;
+ struct eigrp_neighbor *nbr;
+ size_t backup_end, size_end;
+ int found;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ return 0;
+ }
+
+ // add in the parameters TLV
+ backup_end = stream_get_endp(s);
+ stream_putw(s, EIGRP_TLV_SEQ);
+ size_end = s->endp;
+ stream_putw(s, 0x0000);
+ stream_putc(s, IPV4_MAX_BYTELEN);
+
+ found = 0;
+ for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+ {
+ for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
+ {
+ if(nbr->multicast_queue->count > 0)
+ {
+ length += (u_int16_t) stream_put_ipv4(s,nbr->src.s_addr);
+ found = 1;
+ }
+ }
+ }
+
+ if(found == 0)
+ {
+ stream_set_endp(s,backup_end);
+ return 0;
+ }
+
+ backup_end = stream_get_endp (s);
+ stream_set_endp (s,size_end);
+ stream_putw (s, length);
+ stream_set_endp (s, backup_end);
+
+ return length;
+}
+
+/**
+ * @fn eigrp_sequence_encode
+ *
+ * @param[in,out] s packet stream TLV is stored to
+ *
+ * @return u_int16_t number of bytes added to packet stream
+ *
+ * @par
+ * Part of conditional receive process
+ *
+ */
+static u_int16_t
+eigrp_next_sequence_encode (struct stream *s)
+{
+ u_int16_t length = EIGRP_NEXT_SEQUENCE_TLV_SIZE;
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ return 0;
+ }
+
+ // add in the parameters TLV
+ stream_putw(s, EIGRP_TLV_NEXT_MCAST_SEQ);
+ stream_putw(s, EIGRP_NEXT_SEQUENCE_TLV_SIZE);
+ stream_putl(s,eigrp->sequence_number+1);
+
+ return length;
+}
+
+/**
+ * @fn eigrp_hello_parameter_encode
+ *
+ * @param[in] ei pointer to interface hello packet came in on
+ * @param[in,out] s packet stream TLV is stored to
+ *
+ * @return u_int16_t number of bytes added to packet stream
+ *
+ * @par
+ * Encode Parameter TLV, used to convey metric weights and the hold time.
+ *
+ * @usage
+ * Note the addition of K6 for the new extended metrics, and does not apply to
+ * older TLV packet formats.
+ */
+static u_int16_t
+eigrp_hello_parameter_encode (struct eigrp_interface *ei, struct stream *s, u_char flags)
+{
+ u_int16_t length = EIGRP_TLV_PARAMETER_LEN;
+
+ // add in the parameters TLV
+ stream_putw(s, EIGRP_TLV_PARAMETER);
+ stream_putw(s, EIGRP_TLV_PARAMETER_LEN);
+
+ //if graceful shutdown is needed to be announced, send all 255 in K values
+ if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN)
+ {
+ stream_putc(s, 0xff); /* K1 */
+ stream_putc(s, 0xff); /* K2 */
+ stream_putc(s, 0xff); /* K3 */
+ stream_putc(s, 0xff); /* K4 */
+ stream_putc(s, 0xff); /* K5 */
+ stream_putc(s, 0xff); /* K6 */
+ }
+ else // set k values
+ {
+ stream_putc(s, ei->eigrp->k_values[0]); /* K1 */
+ stream_putc(s, ei->eigrp->k_values[1]); /* K2 */
+ stream_putc(s, ei->eigrp->k_values[2]); /* K3 */
+ stream_putc(s, ei->eigrp->k_values[3]); /* K4 */
+ stream_putc(s, ei->eigrp->k_values[4]); /* K5 */
+ stream_putc(s, ei->eigrp->k_values[5]); /* K6 */
+ }
+
+ // and set hold time value..
+ stream_putw(s, IF_DEF_PARAMS(ei->ifp)->v_wait);
+
+ return length;
+}
+
+/**
+ * @fn eigrp_hello_encode
+ *
+ * @param[in] ei pointer to interface hello packet came in on
+ * @param[in] s packet stream TLV is stored to
+ * @param[in] ack if non-zero, neigbors sequence packet to ack
+ * @param[in] flags type of hello packet
+ * @param[in] nbr_addr pointer to neighbor address for Peer Termination TLV
+ *
+ * @return eigrp_packet pointer initialize hello packet
+ *
+ * @par
+ * Allocate an EIGRP hello packet, and add in the the approperate TLVs
+ *
+ */
+static struct eigrp_packet *
+eigrp_hello_encode (struct eigrp_interface *ei, in_addr_t addr, u_int32_t ack, u_char flags, struct in_addr *nbr_addr)
+{
+ struct eigrp_packet *ep;
+ u_int16_t length = EIGRP_HEADER_LEN;
+
+ // allocate a new packet to be sent
+ ep = eigrp_packet_new(ei->ifp->mtu);
+
+ if (ep)
+ {
+ // encode common header feilds
+ eigrp_packet_header_init(EIGRP_OPC_HELLO, ei, ep->s, 0, 0, ack);
+
+ // encode Authentication TLV
+ if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+ {
+ length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei);
+ }
+ else if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_SHA256) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+ {
+ length += eigrp_add_authTLV_SHA256_to_stream(ep->s,ei);
+ }
+
+ /* encode appropriate parameters to Hello packet */
+ if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN)
+ length += eigrp_hello_parameter_encode(ei, ep->s, EIGRP_HELLO_GRACEFUL_SHUTDOWN);
+ else
+ length += eigrp_hello_parameter_encode(ei, ep->s, EIGRP_HELLO_NORMAL);
+
+ // figure out the version of code we're running
+ length += eigrp_sw_version_encode(ep->s);
+
+ if(flags & EIGRP_HELLO_ADD_SEQUENCE)
+ {
+ length += eigrp_sequence_encode(ep->s);
+ length += eigrp_next_sequence_encode(ep->s);
+ }
+
+ // add in the TID list if doing multi-topology
+ length += eigrp_tidlist_encode(ep->s);
+
+ /* encode Peer Termination TLV if needed */
+ if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR)
+ length += eigrp_peer_termination_encode(ep->s, nbr_addr);
+
+ // Set packet length
+ ep->length = length;
+
+ // set soruce address for the hello packet
+ ep->dst.s_addr = addr;
+
+ if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+ {
+ eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_BASIC_HELLO_FLAG);
+ }
+ else if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_SHA256) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+ {
+ eigrp_make_sha256_digest(ei,ep->s, EIGRP_AUTH_BASIC_HELLO_FLAG);
+ }
+
+ // EIGRP Checksum
+ eigrp_packet_checksum(ei, ep->s, length);
+ }
+
+ return(ep);
+}
+
+/**
+ * @fn eigrp_hello_send
+ *
+ * @param[in] nbr neighbor the ACK should be sent to
+ *
+ * @return void
+ *
+ * @par
+ * Send (unicast) a hello packet with the destination address
+ * associated with the neighbor. The eigrp header ACK feild will be
+ * updated to the neighbor's sequence number to acknolodge any
+ * outstanding packets
+ */
+void
+eigrp_hello_send_ack (struct eigrp_neighbor *nbr)
+{
+ struct eigrp_packet *ep;
+
+ /* if packet succesfully created, add it to the interface queue */
+ ep = eigrp_hello_encode(nbr->ei, nbr->src.s_addr, nbr->recv_sequence_number, EIGRP_HELLO_NORMAL, NULL);
+
+ if (ep)
+ {
+ if (IS_DEBUG_EIGRP_PACKET(0, SEND))
+ zlog_debug("Queueing [Hello] Ack Seq [%u] nbr [%s]",
+ nbr->recv_sequence_number, inet_ntoa(nbr->src));
+
+ /* Add packet to the top of the interface output queue*/
+ eigrp_fifo_push_head(nbr->ei->obuf, ep);
+
+ /* Hook thread to write packet. */
+ if (nbr->ei->on_write_q == 0)
+ {
+ listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
+ nbr->ei->on_write_q = 1;
+ }
+ if (nbr->ei->eigrp->t_write == NULL)
+ nbr->ei->eigrp->t_write =
+ thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd);
+ }
+}
+
+/**
+ * @fn eigrp_hello_send
+ *
+ * @param[in] ei pointer to interface hello should be sent
+ * @param[in] flags type of hello packet
+ * @param[in] nbr_addr pointer to neighbor address for Peer Termination TLV
+ *
+ * @return void
+ *
+ * @par
+ * Build and enqueue a generic (multicast) periodic hello packet for
+ * sending. If no packets are currently queues, the packet will be
+ * sent immadiatly
+ */
+void
+eigrp_hello_send (struct eigrp_interface *ei, u_char flags, struct in_addr *nbr_addr)
+{
+ struct eigrp_packet *ep = NULL;
+
+ /* If this is passive interface, do not send EIGRP Hello.
+ if ((EIGRP_IF_PASSIVE_STATUS (ei) == EIGRP_IF_PASSIVE) ||
+ (ei->type != EIGRP_IFTYPE_NBMA))
+ return;
+ */
+
+ if (IS_DEBUG_EIGRP_PACKET(0, SEND))
+ zlog_debug("Queueing [Hello] Interface(%s)", IF_NAME(ei));
+
+ /* if packet was succesfully created, then add it to the interface queue */
+ ep = eigrp_hello_encode(ei, htonl(EIGRP_MULTICAST_ADDRESS), 0, flags, nbr_addr);
+
+ if (ep)
+ {
+ // Add packet to the top of the interface output queue
+ eigrp_fifo_push_head(ei->obuf, ep);
+
+ /* Hook thread to write packet. */
+ if (ei->on_write_q == 0)
+ {
+ listnode_add(ei->eigrp->oi_write_q, ei);
+ ei->on_write_q = 1;
+ }
+
+ if (ei->eigrp->t_write == NULL)
+ {
+ if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN)
+ {
+ ei->eigrp->t_write =
+ thread_execute(master, eigrp_write, ei->eigrp, ei->eigrp->fd);
+ }
+ else
+ {
+ ei->eigrp->t_write =
+ thread_add_write(master, eigrp_write, ei->eigrp, ei->eigrp->fd);
+ }
+ }
+ }
+}
diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c
new file mode 100644
index 000000000..18573caa0
--- /dev/null
+++ b/eigrpd/eigrp_interface.c
@@ -0,0 +1,613 @@
+/*
+ * EIGRP Interface Functions.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "memory.h"
+#include "command.h"
+#include "stream.h"
+#include "log.h"
+#include "keychain.h"
+#include "vrf.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_memory.h"
+
+static void
+eigrp_delete_from_if (struct interface *, struct eigrp_interface *);
+
+static void
+eigrp_add_to_if (struct interface *ifp, struct eigrp_interface *ei)
+{
+ struct route_node *rn;
+ struct prefix p;
+
+ p = *ei->address;
+ p.prefixlen = IPV4_MAX_PREFIXLEN;
+
+ rn = route_node_get (IF_OIFS (ifp), &p);
+ /* rn->info should either be NULL or equal to this ei
+ * as route_node_get may return an existing node
+ */
+ assert (!rn->info || rn->info == ei);
+ rn->info = ei;
+}
+
+struct eigrp_interface *
+eigrp_if_new (struct eigrp *eigrp, struct interface *ifp, struct prefix *p)
+{
+ struct eigrp_interface *ei;
+ int i;
+
+ if ((ei = eigrp_if_table_lookup (ifp, p)) == NULL)
+ {
+ ei = XCALLOC (MTYPE_EIGRP_IF, sizeof (struct eigrp_interface));
+ memset (ei, 0, sizeof (struct eigrp_interface));
+ }
+ else
+ return ei;
+
+ /* Set zebra interface pointer. */
+ ei->ifp = ifp;
+ ei->address = p;
+
+ eigrp_add_to_if (ifp, ei);
+ listnode_add (eigrp->eiflist, ei);
+
+ ei->type = EIGRP_IFTYPE_BROADCAST;
+
+ /* Initialize neighbor list. */
+ ei->nbrs = list_new ();
+
+ ei->crypt_seqnum = time (NULL);
+
+ /* Initialize lists */
+ for (i = 0; i < EIGRP_FILTER_MAX; i++)
+ {
+ ei->list[i] = NULL;
+ ei->prefix[i] = NULL;
+ ei->routemap[i] = NULL;
+ }
+
+ return ei;
+}
+
+/* lookup ei for specified prefix/ifp */
+struct eigrp_interface *
+eigrp_if_table_lookup (struct interface *ifp, struct prefix *prefix)
+{
+ struct prefix p;
+ struct route_node *rn;
+ struct eigrp_interface *rninfo = NULL;
+
+ p = *prefix;
+ p.prefixlen = IPV4_MAX_PREFIXLEN;
+
+ /* route_node_get implicitly locks */
+ if ((rn = route_node_lookup (IF_OIFS (ifp), &p)))
+ {
+ rninfo = (struct eigrp_interface *) rn->info;
+ route_unlock_node (rn);
+ }
+
+ return rninfo;
+}
+
+int
+eigrp_if_delete_hook (struct interface *ifp)
+{
+
+ struct route_node *rn;
+
+ route_table_finish (IF_OIFS (ifp));
+
+ for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn))
+ if (rn->info)
+ eigrp_del_if_params (rn->info);
+ route_table_finish (IF_OIFS_PARAMS (ifp));
+
+ XFREE (MTYPE_EIGRP_IF_INFO, ifp->info);
+ ifp->info = NULL;
+
+ return 0;
+}
+
+struct list *eigrp_iflist;
+
+void
+eigrp_if_init ()
+{
+ /* Initialize Zebra interface data structure. */
+ if_add_hook (IF_NEW_HOOK, eigrp_if_new_hook);
+ if_add_hook (IF_DELETE_HOOK, eigrp_if_delete_hook);
+}
+
+int
+eigrp_if_new_hook (struct interface *ifp)
+{
+ int rc = 0;
+
+ ifp->info = XCALLOC (MTYPE_EIGRP_IF_INFO, sizeof (struct eigrp_if_info));
+
+ IF_OIFS (ifp) = route_table_init ();
+ IF_OIFS_PARAMS (ifp) = route_table_init ();
+
+ IF_DEF_PARAMS (ifp) = eigrp_new_if_params ();
+
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello);
+ IF_DEF_PARAMS (ifp)->v_hello = (u_int32_t) EIGRP_HELLO_INTERVAL_DEFAULT;
+
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait);
+ IF_DEF_PARAMS (ifp)->v_wait = (u_int16_t) EIGRP_HOLD_INTERVAL_DEFAULT;
+
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), bandwidth);
+ IF_DEF_PARAMS (ifp)->bandwidth = (u_int32_t) EIGRP_BANDWIDTH_DEFAULT;
+
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), delay);
+ IF_DEF_PARAMS (ifp)->delay = (u_int32_t) EIGRP_DELAY_DEFAULT;
+
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), reliability);
+ IF_DEF_PARAMS (ifp)->reliability = (u_char) EIGRP_RELIABILITY_DEFAULT;
+
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), load);
+ IF_DEF_PARAMS (ifp)->load = (u_char) EIGRP_LOAD_DEFAULT;
+
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type);
+ IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_NONE;
+
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_keychain);
+ IF_DEF_PARAMS (ifp)->auth_keychain= NULL;
+
+ return rc;
+}
+
+struct eigrp_if_params *
+eigrp_new_if_params (void)
+{
+ struct eigrp_if_params *eip;
+
+ eip = XCALLOC (MTYPE_EIGRP_IF_PARAMS, sizeof (struct eigrp_if_params));
+ if (!eip)
+ return NULL;
+
+ UNSET_IF_PARAM (eip, passive_interface);
+ UNSET_IF_PARAM (eip, v_hello);
+ UNSET_IF_PARAM (eip, v_wait);
+ UNSET_IF_PARAM (eip, bandwidth);
+ UNSET_IF_PARAM (eip, delay);
+ UNSET_IF_PARAM (eip, reliability);
+ UNSET_IF_PARAM (eip, load);
+ UNSET_IF_PARAM (eip, auth_keychain);
+ UNSET_IF_PARAM (eip, auth_type);
+
+
+ return eip;
+}
+
+void
+eigrp_del_if_params (struct eigrp_if_params *eip)
+{
+ if(eip->auth_keychain)
+ free(eip->auth_keychain);
+
+ XFREE (MTYPE_EIGRP_IF_PARAMS, eip);
+}
+
+struct eigrp_if_params *
+eigrp_lookup_if_params (struct interface *ifp, struct in_addr addr)
+{
+ struct prefix_ipv4 p;
+ struct route_node *rn;
+
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_PREFIXLEN;
+ p.prefix = addr;
+
+ rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*) &p);
+
+ if (rn)
+ {
+ route_unlock_node (rn);
+ return rn->info;
+ }
+
+ return NULL;
+}
+
+int
+eigrp_if_up (struct eigrp_interface *ei)
+{
+ struct eigrp_prefix_entry *pe;
+ struct eigrp_neighbor_entry *ne;
+ struct eigrp_metrics metric;
+ struct eigrp_interface *ei2;
+ struct listnode *node, *nnode;
+ struct eigrp *eigrp = eigrp_lookup ();
+
+ if (ei == NULL)
+ return 0;
+
+ if (eigrp != NULL)
+ eigrp_adjust_sndbuflen (eigrp, ei->ifp->mtu);
+ else
+ zlog_warn ("%s: eigrp_lookup () returned NULL", __func__);
+ eigrp_if_stream_set (ei);
+
+ /* Set multicast memberships appropriately for new state. */
+ eigrp_if_set_multicast (ei);
+
+ thread_add_event (master, eigrp_hello_timer, ei, (1));
+
+ /*Prepare metrics*/
+ metric.bandwith = eigrp_bandwidth_to_scaled (EIGRP_IF_PARAM (ei,bandwidth));
+ metric.delay = eigrp_delay_to_scaled (EIGRP_IF_PARAM (ei,delay));
+ metric.load = EIGRP_IF_PARAM (ei,load);
+ metric.reliability = EIGRP_IF_PARAM (ei,reliability);
+ metric.mtu[0] = 0xDC;
+ metric.mtu[1] = 0x05;
+ metric.mtu[2] = 0x00;
+ metric.hop_count = 0;
+ metric.flags = 0;
+ metric.tag = 0;
+
+ /*Add connected entry to topology table*/
+
+ struct prefix_ipv4 *dest_addr = prefix_ipv4_new ();
+
+ dest_addr->family = AF_INET;
+ dest_addr->prefix = ei->connected->address->u.prefix4;
+ dest_addr->prefixlen = ei->connected->address->prefixlen;
+ apply_mask_ipv4 (dest_addr);
+ pe = eigrp_topology_table_lookup_ipv4 (eigrp->topology_table, dest_addr);
+
+ if (pe == NULL)
+ {
+ pe = eigrp_prefix_entry_new ();
+ pe->serno = eigrp->serno;
+ pe->destination_ipv4 = dest_addr;
+ pe->af = AF_INET;
+ pe->nt = EIGRP_TOPOLOGY_TYPE_CONNECTED;
+
+ pe->state = EIGRP_FSM_STATE_PASSIVE;
+ pe->fdistance = eigrp_calculate_metrics (eigrp, &metric);
+ pe->req_action |= EIGRP_FSM_NEED_UPDATE;
+ eigrp_prefix_entry_add (eigrp->topology_table, pe);
+ listnode_add(eigrp->topology_changes_internalIPV4, pe);
+ }
+ ne = eigrp_neighbor_entry_new ();
+ ne->ei = ei;
+ ne->reported_metric = metric;
+ ne->total_metric = metric;
+ ne->distance = eigrp_calculate_metrics (eigrp, &metric);
+ ne->reported_distance = 0;
+ ne->prefix = pe;
+ ne->adv_router = eigrp->neighbor_self;
+ ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
+ eigrp_neighbor_entry_add (pe, ne);
+
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei2))
+ {
+ if (ei2->nbrs->count != 0)
+ {
+ eigrp_update_send (ei2);
+ }
+ }
+
+ pe->req_action &= ~EIGRP_FSM_NEED_UPDATE;
+ listnode_delete(eigrp->topology_changes_internalIPV4, pe);
+
+ return 1;
+}
+
+int
+eigrp_if_down (struct eigrp_interface *ei)
+{
+ struct listnode *node, *nnode;
+ struct eigrp_neighbor *nbr;
+
+ if (ei == NULL)
+ return 0;
+
+ /* Shutdown packet reception and sending */
+ if(ei->t_hello)
+ THREAD_OFF (ei->t_hello);
+
+ eigrp_if_stream_unset (ei);
+
+ /*Set infinite metrics to routes learned by this interface and start query process*/
+ for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr))
+ {
+ eigrp_nbr_delete(nbr);
+ }
+
+ return 1;
+}
+
+void
+eigrp_if_stream_set (struct eigrp_interface *ei)
+{
+ /* set output fifo queue. */
+ if (ei->obuf == NULL)
+ ei->obuf = eigrp_fifo_new ();
+}
+
+void
+eigrp_if_stream_unset (struct eigrp_interface *ei)
+{
+ struct eigrp *eigrp = ei->eigrp;
+
+ if (ei->obuf)
+ {
+ eigrp_fifo_free (ei->obuf);
+ ei->obuf = NULL;
+
+ if (ei->on_write_q)
+ {
+ listnode_delete (eigrp->oi_write_q, ei);
+ if (list_isempty (eigrp->oi_write_q))
+ thread_cancel (eigrp->t_write);
+ ei->on_write_q = 0;
+ }
+ }
+}
+
+void
+eigrp_if_set_multicast (struct eigrp_interface *ei)
+{
+ if ((EIGRP_IF_PASSIVE_STATUS (ei) == EIGRP_IF_ACTIVE))
+ {
+ /* The interface should belong to the EIGRP-all-routers group. */
+ if (!EI_MEMBER_CHECK (ei, MEMBER_ALLROUTERS)
+ && (eigrp_if_add_allspfrouters (ei->eigrp, ei->address,
+ ei->ifp->ifindex) >= 0))
+ /* Set the flag only if the system call to join succeeded. */
+ EI_MEMBER_JOINED (ei, MEMBER_ALLROUTERS);
+ }
+ else
+ {
+ /* The interface should NOT belong to the EIGRP-all-routers group. */
+ if (EI_MEMBER_CHECK (ei, MEMBER_ALLROUTERS))
+ {
+ /* Only actually drop if this is the last reference */
+ if (EI_MEMBER_COUNT (ei, MEMBER_ALLROUTERS) == 1)
+ eigrp_if_drop_allspfrouters (ei->eigrp, ei->address,
+ ei->ifp->ifindex);
+ /* Unset the flag regardless of whether the system call to leave
+ the group succeeded, since it's much safer to assume that
+ we are not a member. */
+ EI_MEMBER_LEFT (ei, MEMBER_ALLROUTERS);
+ }
+ }
+}
+
+u_char
+eigrp_default_iftype (struct interface *ifp)
+{
+ if (if_is_pointopoint (ifp))
+ return EIGRP_IFTYPE_POINTOPOINT;
+ else if (if_is_loopback (ifp))
+ return EIGRP_IFTYPE_LOOPBACK;
+ else
+ return EIGRP_IFTYPE_BROADCAST;
+}
+
+void
+eigrp_if_free (struct eigrp_interface *ei, int source)
+{
+
+ if (source == INTERFACE_DOWN_BY_VTY)
+ {
+ THREAD_OFF (ei->t_hello);
+ eigrp_hello_send(ei,EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL);
+ }
+
+ eigrp_if_down (ei);
+
+ list_delete (ei->nbrs);
+ eigrp_delete_from_if (ei->ifp, ei);
+ listnode_delete (ei->eigrp->eiflist, ei);
+
+ thread_cancel_event (master, ei);
+
+ memset (ei, 0, sizeof (*ei));
+ XFREE (MTYPE_EIGRP_IF, ei);
+}
+
+static void
+eigrp_delete_from_if (struct interface *ifp, struct eigrp_interface *ei)
+{
+ struct route_node *rn;
+ struct prefix p;
+
+ p = *ei->address;
+ p.prefixlen = IPV4_MAX_PREFIXLEN;
+
+ rn = route_node_lookup (IF_OIFS (ei->ifp), &p);
+ assert (rn);
+ assert (rn->info);
+ rn->info = NULL;
+ route_unlock_node (rn);
+ route_unlock_node (rn);
+}
+
+/* Simulate down/up on the interface. This is needed, for example, when
+ the MTU changes. */
+void
+eigrp_if_reset (struct interface *ifp)
+{
+ struct route_node *rn;
+
+ for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+ {
+ struct eigrp_interface *ei;
+
+ if ((ei = rn->info) == NULL)
+ continue;
+
+ eigrp_if_down (ei);
+ eigrp_if_up (ei);
+ }
+}
+
+struct eigrp_interface *
+eigrp_if_lookup_by_local_addr (struct eigrp *eigrp, struct interface *ifp,
+ struct in_addr address)
+{
+ struct listnode *node;
+ struct eigrp_interface *ei;
+
+ for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+ {
+ if (ifp && ei->ifp != ifp)
+ continue;
+
+ if (IPV4_ADDR_SAME (&address, &ei->address->u.prefix4))
+ return ei;
+ }
+
+ return NULL;
+}
+
+/**
+ * @fn eigrp_if_lookup_by_name
+ *
+ * @param[in] eigrp EIGRP process
+ * @param[in] if_name Name of the interface
+ *
+ * @return struct eigrp_interface *
+ *
+ * @par
+ * Function is used for lookup interface by name.
+ */
+struct eigrp_interface *
+eigrp_if_lookup_by_name (struct eigrp *eigrp, const char *if_name)
+{
+ struct eigrp_interface *ei;
+ struct listnode *node;
+
+ /* iterate over all eigrp interfaces */
+ for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+ {
+ /* compare int name with eigrp interface's name */
+ if(strcmp(ei->ifp->name, if_name) == 0)
+ {
+ return ei;
+ }
+ }
+
+ return NULL;
+}
+
+/* determine receiving interface by ifp and source address */
+struct eigrp_interface *
+eigrp_if_lookup_recv_if (struct eigrp *eigrp, struct in_addr src,
+ struct interface *ifp)
+{
+ struct route_node *rn;
+ struct prefix_ipv4 addr;
+ struct eigrp_interface *ei, *match;
+
+ addr.family = AF_INET;
+ addr.prefix = src;
+ addr.prefixlen = IPV4_MAX_BITLEN;
+
+ match = NULL;
+
+ for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+ {
+ ei = rn->info;
+
+ if (!ei) /* oi can be NULL for PtP aliases */
+ continue;
+
+ if (if_is_loopback (ei->ifp))
+ continue;
+
+ if (prefix_match (CONNECTED_PREFIX (ei->connected),
+ (struct prefix *) &addr))
+ {
+ if ((match == NULL)
+ || (match->address->prefixlen < ei->address->prefixlen))
+ match = ei;
+ }
+ }
+
+ return match;
+}
+
+u_int32_t
+eigrp_bandwidth_to_scaled (u_int32_t bandwidth)
+{
+ u_int64_t temp_bandwidth = (256ull * 10000000) / bandwidth;
+
+ temp_bandwidth =
+ temp_bandwidth < EIGRP_MAX_METRIC ? temp_bandwidth : EIGRP_MAX_METRIC;
+
+ return (u_int32_t) temp_bandwidth;
+
+}
+
+u_int32_t
+eigrp_scaled_to_bandwidth (u_int32_t scaled)
+{
+ u_int64_t temp_scaled = scaled * (256ull * 10000000);
+
+ temp_scaled =
+ temp_scaled < EIGRP_MAX_METRIC ? temp_scaled : EIGRP_MAX_METRIC;
+
+ return (u_int32_t) temp_scaled;
+}
+
+u_int32_t
+eigrp_delay_to_scaled (u_int32_t delay)
+{
+ return delay * 256;
+}
+
+u_int32_t
+eigrp_scaled_to_delay (u_int32_t scaled)
+{
+ return scaled / 256;
+}
diff --git a/eigrpd/eigrp_interface.h b/eigrpd/eigrp_interface.h
new file mode 100644
index 000000000..c7de3b75b
--- /dev/null
+++ b/eigrpd/eigrp_interface.h
@@ -0,0 +1,73 @@
+/*
+ * EIGRP Interface Functions.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_INTERFACE_H_
+#define _ZEBRA_EIGRP_INTERFACE_H_
+
+/*Prototypes*/
+extern void eigrp_if_init (void);
+extern int eigrp_if_new_hook (struct interface *);
+extern int eigrp_if_delete_hook (struct interface *);
+
+extern void eigrp_del_if_params (struct eigrp_if_params *);
+extern struct eigrp_if_params *eigrp_new_if_params (void);
+extern struct eigrp_interface * eigrp_if_new (struct eigrp *, struct interface *,
+ struct prefix *);
+extern struct eigrp_interface * eigrp_if_table_lookup (struct interface *,
+ struct prefix *);
+extern struct eigrp_if_params *eigrp_lookup_if_params (struct interface *,
+ struct in_addr);
+extern int eigrp_if_up (struct eigrp_interface *);
+extern void eigrp_if_stream_set (struct eigrp_interface *);
+extern void eigrp_if_set_multicast (struct eigrp_interface *);
+extern u_char eigrp_default_iftype (struct interface *);
+extern void eigrp_if_free (struct eigrp_interface *, int);
+extern int eigrp_if_down (struct eigrp_interface *);
+extern void eigrp_if_stream_unset (struct eigrp_interface *);
+
+extern struct eigrp_interface *eigrp_if_lookup_by_local_addr (struct eigrp *,
+ struct interface *,
+ struct in_addr);
+extern struct eigrp_interface *eigrp_if_lookup_by_name (struct eigrp *, const char *);
+struct eigrp_interface * eigrp_if_lookup_recv_if (struct eigrp *, struct in_addr,
+ struct interface *);
+
+/* Simulate down/up on the interface. */
+extern void eigrp_if_reset (struct interface *);
+
+extern u_int32_t eigrp_bandwidth_to_scaled (u_int32_t);
+extern u_int32_t eigrp_scaled_to_bandwidth (u_int32_t);
+extern u_int32_t eigrp_delay_to_scaled (u_int32_t);
+extern u_int32_t eigrp_scaled_to_delay (u_int32_t);
+
+
+#endif /* ZEBRA_EIGRP_INTERFACE_H_ */
diff --git a/eigrpd/eigrp_macros.h b/eigrpd/eigrp_macros.h
new file mode 100644
index 000000000..dd22829e8
--- /dev/null
+++ b/eigrpd/eigrp_macros.h
@@ -0,0 +1,85 @@
+/*
+ * EIGRP Macros Definition.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_MACROS_H_
+#define _ZEBRA_EIGRP_MACROS_H_
+
+#define DECLARE_IF_PARAM(T, P) T P; u_char P##__config:1
+#define IF_EIGRP_IF_INFO(I) ((struct eigrp_if_info *)((I)->info))
+#define IF_OIFS(I) (IF_EIGRP_IF_INFO (I)->eifs)
+#define IF_OIFS_PARAMS(I) (IF_EIGRP_IF_INFO (I)->params)
+
+#define SET_IF_PARAM(S, P) ((S)->P##__config) = 1
+#define IF_DEF_PARAMS(I) (IF_EIGRP_IF_INFO (I)->def_params)
+
+#define UNSET_IF_PARAM(S, P) ((S)->P##__config) = 0
+
+#define EIGRP_IF_PARAM_CONFIGURED(S, P) ((S) && (S)->P##__config)
+#define EIGRP_IF_PARAM(O, P) \
+ (EIGRP_IF_PARAM_CONFIGURED ((O)->params, P)?\
+ (O)->params->P:IF_DEF_PARAMS((O)->ifp)->P)
+
+#define EIGRP_IF_PASSIVE_STATUS(O) \
+ (EIGRP_IF_PARAM_CONFIGURED((O)->params, passive_interface) ? \
+ (O)->params->passive_interface : \
+ (EIGRP_IF_PARAM_CONFIGURED(IF_DEF_PARAMS((O)->ifp), passive_interface) ? \
+ IF_DEF_PARAMS((O)->ifp)->passive_interface : \
+ (O)->eigrp->passive_interface_default))
+
+//------------------------------------------------------------------------------------------------------------------------------------
+
+#define EIGRP_IF_STRING_MAXLEN 40
+#define IF_NAME(I) eigrp_if_name_string ((I))
+
+//------------------------------------------------------------------------------------------------------------------------------------
+
+/*Macros for EIGRP interface multicast membership*/
+#define EI_MEMBER_FLAG(M) (1 << (M))
+#define EI_MEMBER_COUNT(O,M) (IF_EIGRP_IF_INFO(ei->ifp)->membership_counts[(M)])
+#define EI_MEMBER_CHECK(O,M) \
+ (CHECK_FLAG((O)->multicast_memberships, EI_MEMBER_FLAG(M)))
+#define EI_MEMBER_JOINED(O,M) \
+ do { \
+ SET_FLAG ((O)->multicast_memberships, EI_MEMBER_FLAG(M)); \
+ IF_EIGRP_IF_INFO((O)->ifp)->membership_counts[(M)]++; \
+ } while (0)
+#define EI_MEMBER_LEFT(O,M) \
+ do { \
+ UNSET_FLAG ((O)->multicast_memberships, EI_MEMBER_FLAG(M)); \
+ IF_EIGRP_IF_INFO((O)->ifp)->membership_counts[(M)]--; \
+ } while (0)
+
+//-----------------------------------------------------------------------------------------------------------------------------------
+/* Topology Macros */
+
+
+/* FSM macros*/
+#define EIGRP_FSM_EVENT_SCHEDULE(I,E) \
+ thread_add_event (master, eigrp_fsm_event, (I), (E))
+
+#endif /* _ZEBRA_EIGRP_MACROS_H_ */
diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c
new file mode 100644
index 000000000..85a97e79a
--- /dev/null
+++ b/eigrpd/eigrp_main.c
@@ -0,0 +1,231 @@
+/*
+ * EIGRP Main Routine.
+ * Copyright (C) 2013-2015
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <zebra.h>
+
+#include <lib/version.h>
+#include "getopt.h"
+#include "thread.h"
+#include "prefix.h"
+#include "linklist.h"
+#include "if.h"
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "filter.h"
+#include "plist.h"
+#include "stream.h"
+#include "log.h"
+#include "memory.h"
+#include "privs.h"
+#include "sigevent.h"
+#include "zclient.h"
+#include "keychain.h"
+#include "distribute.h"
+#include "libfrr.h"
+//#include "routemap.h"
+//#include "if_rmap.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_snmp.h"
+#include "eigrpd/eigrp_filter.h"
+//#include "eigrpd/eigrp_routemap.h"
+
+/* eigprd privileges */
+zebra_capabilities_t _caps_p [] =
+{
+ ZCAP_NET_RAW,
+ ZCAP_BIND,
+ ZCAP_NET_ADMIN,
+};
+
+struct zebra_privs_t eigrpd_privs =
+{
+#if defined (FRR_USER) && defined (FRR_GROUP)
+ .user = FRR_USER,
+ .group = FRR_GROUP,
+#endif
+#if defined (VTY_GROUP)
+ .vty_group = VTY_GROUP,
+#endif
+ .caps_p = _caps_p,
+ .cap_num_p = array_size (_caps_p),
+ .cap_num_i = 0
+};
+
+/* EIGRPd options. */
+struct option longopts[] =
+{
+ { 0 }
+};
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* SIGHUP handler. */
+static void
+sighup (void)
+{
+ zlog_info ("SIGHUP received");
+}
+
+/* SIGINT / SIGTERM handler. */
+static void
+sigint (void)
+{
+ zlog_notice ("Terminating on signal");
+ eigrp_terminate ();
+}
+
+/* SIGUSR1 handler. */
+static void
+sigusr1 (void)
+{
+ zlog_rotate ();
+}
+
+struct quagga_signal_t eigrp_signals[] =
+{
+ {
+ .signal = SIGHUP,
+ .handler = &sighup,
+ },
+ {
+ .signal = SIGUSR1,
+ .handler = &sigusr1,
+ },
+ {
+ .signal = SIGINT,
+ .handler = &sigint,
+ },
+ {
+ .signal = SIGTERM,
+ .handler = &sigint,
+ },
+};
+
+FRR_DAEMON_INFO(eigrpd, EIGRP,
+ .vty_port = EIGRP_VTY_PORT,
+
+ .proghelp = "Implementation of the EIGRP routing protocol.",
+
+ .signals = eigrp_signals,
+ .n_signals = array_size(eigrp_signals),
+
+ .privs = &eigrpd_privs,
+ )
+
+/* EIGRPd main routine. */
+int
+main (int argc, char **argv, char **envp)
+{
+ frr_preinit (&eigrpd_di, argc, argv);
+ frr_opt_add ("", longopts, "");
+
+ while (1)
+ {
+ int opt;
+
+ opt = frr_getopt (argc, argv, NULL);
+
+ if (opt == EOF)
+ break;
+
+ switch (opt)
+ {
+ case 0:
+ break;
+ default:
+ frr_help_exit (1);
+ break;
+ }
+ }
+
+ /* EIGRP master init. */
+ eigrp_master_init ();
+ eigrp_om->master = frr_init();
+ master = eigrp_om->master;
+
+ vrf_init ();
+
+ /*EIGRPd init*/
+ eigrp_if_init ();
+ eigrp_zebra_init ();
+ eigrp_debug_init ();
+
+ /* Get configuration file. */
+ /* EIGRP VTY inits */
+ eigrp_vty_init ();
+ keychain_init();
+ eigrp_vty_show_init ();
+ eigrp_vty_if_init ();
+
+#ifdef HAVE_SNMP
+ eigrp_snmp_init ();
+#endif /* HAVE_SNMP */
+
+ /* Access list install. */
+ access_list_init ();
+ access_list_add_hook (eigrp_distribute_update_all_wrapper);
+ access_list_delete_hook (eigrp_distribute_update_all_wrapper);
+
+ /* Prefix list initialize.*/
+ prefix_list_init ();
+ prefix_list_add_hook (eigrp_distribute_update_all);
+ prefix_list_delete_hook (eigrp_distribute_update_all);
+
+ /*eigrp_route_map_init();
+ route_map_add_hook (eigrp_rmap_update);
+ route_map_delete_hook (eigrp_rmap_update);*/
+ /*if_rmap_init (EIGRP_NODE);
+ if_rmap_hook_add (eigrp_if_rmap_update);
+ if_rmap_hook_delete (eigrp_if_rmap_update);*/
+
+ /* Distribute list install. */
+ distribute_list_init (EIGRP_NODE);
+ distribute_list_add_hook (eigrp_distribute_update);
+ distribute_list_delete_hook (eigrp_distribute_update);
+
+ frr_config_fork ();
+ frr_run(master);
+
+ /* Not reached. */
+ return (0);
+
+}
diff --git a/eigrpd/eigrp_memory.c b/eigrpd/eigrp_memory.c
new file mode 100644
index 000000000..dabc0774e
--- /dev/null
+++ b/eigrpd/eigrp_memory.c
@@ -0,0 +1,43 @@
+/* eigrpd memory type definitions
+ *
+ * Copyright (C) 2017 Donald Sharp
+ *
+ * This file is part of FRR
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "eigrp_memory.h"
+
+DEFINE_MGROUP(EIGRPD, "eigrpd")
+DEFINE_MTYPE(EIGRPD, EIGRP_TOP, "EIGRP structure")
+DEFINE_MTYPE(EIGRPD, EIGRP_IF, "EIGRP interface")
+DEFINE_MTYPE(EIGRPD, EIGRP_NEIGHBOR, "EIGRP neighbor")
+DEFINE_MTYPE(EIGRPD, EIGRP_IF_PARAMS, "EIGRP Interface Parameters")
+DEFINE_MTYPE(EIGRPD, EIGRP_IF_INFO, "EIGRP Interface Information")
+DEFINE_MTYPE(EIGRPD, EIGRP_FIFO, "EIGRP FIFO")
+DEFINE_MTYPE(EIGRPD, EIGRP_PACKET, "EIGRP Packet")
+DEFINE_MTYPE(EIGRPD, EIGRP_IPV4_INT_TLV, "EIGRP IPv4 TLV")
+DEFINE_MTYPE(EIGRPD, EIGRP_SEQ_TLV, "EIGRP SEQ TLV")
+DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_TLV, "EIGRP AUTH TLV")
+DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV")
+DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_ENTRY, "EIGRP Prefix")
+DEFINE_MTYPE(EIGRPD, EIGRP_NEIGHBOR_ENTRY, "EIGRP Neighbor Entry")
+DEFINE_MTYPE(EIGRPD, EIGRP_FSM_MSG, "EIGRP FSM Message")
diff --git a/eigrpd/eigrp_memory.h b/eigrpd/eigrp_memory.h
new file mode 100644
index 000000000..0cafdfb1b
--- /dev/null
+++ b/eigrpd/eigrp_memory.h
@@ -0,0 +1,44 @@
+/* eigrpd memory type declarations
+ *
+ * Copyright (C) 2017 Donald Sharp
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _FRR_EIGRP_MEMORY_H
+#define _FRR_EIGRP_MEMORY_H
+
+#include "memory.h"
+
+DECLARE_MGROUP(EIGRPD)
+DECLARE_MTYPE(EIGRP_TOP)
+DECLARE_MTYPE(EIGRP_IF)
+DECLARE_MTYPE(EIGRP_NEIGHBOR)
+DECLARE_MTYPE(EIGRP_IF_PARAMS)
+DECLARE_MTYPE(EIGRP_IF_INFO)
+DECLARE_MTYPE(EIGRP_FIFO)
+DECLARE_MTYPE(EIGRP_PACKET)
+DECLARE_MTYPE(EIGRP_IPV4_INT_TLV)
+DECLARE_MTYPE(EIGRP_SEQ_TLV)
+DECLARE_MTYPE(EIGRP_AUTH_TLV)
+DECLARE_MTYPE(EIGRP_AUTH_SHA256_TLV)
+DECLARE_MTYPE(EIGRP_PREFIX_ENTRY)
+DECLARE_MTYPE(EIGRP_NEIGHBOR_ENTRY)
+DECLARE_MTYPE(EIGRP_FSM_MSG)
+
+#endif /* _FRR_EIGRP_MEMORY_H */
diff --git a/eigrpd/eigrp_neighbor.c b/eigrpd/eigrp_neighbor.c
new file mode 100644
index 000000000..8dcf76dc4
--- /dev/null
+++ b/eigrpd/eigrp_neighbor.c
@@ -0,0 +1,384 @@
+/*
+ * EIGRP Neighbor Handling.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "memory.h"
+#include "command.h"
+#include "thread.h"
+#include "stream.h"
+#include "table.h"
+#include "log.h"
+#include "keychain.h"
+#include "vty.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_memory.h"
+
+struct eigrp_neighbor *
+eigrp_nbr_new (struct eigrp_interface *ei)
+{
+ struct eigrp_neighbor *nbr;
+
+ /* Allcate new neighbor. */
+ nbr = XCALLOC (MTYPE_EIGRP_NEIGHBOR, sizeof (struct eigrp_neighbor));
+
+ /* Relate neighbor to the interface. */
+ nbr->ei = ei;
+
+ /* Set default values. */
+
+ eigrp_nbr_state_set (nbr, EIGRP_NEIGHBOR_DOWN);
+
+ return nbr;
+}
+
+/**
+ *@fn void dissect_eigrp_sw_version (tvbuff_t *tvb, proto_tree *tree,
+ * proto_item *ti)
+ *
+ * @par
+ * Create a new neighbor structure and initalize it.
+ */
+static struct eigrp_neighbor *
+eigrp_nbr_add (struct eigrp_interface *ei, struct eigrp_header *eigrph,
+ struct ip *iph)
+{
+ struct eigrp_neighbor *nbr;
+
+ nbr = eigrp_nbr_new (ei);
+ nbr->src = iph->ip_src;
+
+// if (IS_DEBUG_EIGRP_EVENT)
+// zlog_debug("NSM[%s:%s]: start", IF_NAME (nbr->oi),
+// inet_ntoa (nbr->router_id));
+
+ return nbr;
+}
+
+struct eigrp_neighbor *
+eigrp_nbr_get (struct eigrp_interface *ei, struct eigrp_header *eigrph,
+ struct ip *iph)
+{
+ struct eigrp_neighbor *nbr;
+ struct listnode *node, *nnode;
+
+ for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr))
+ {
+ if (iph->ip_src.s_addr == nbr->src.s_addr)
+ {
+ return nbr;
+ }
+ }
+
+ nbr = eigrp_nbr_add (ei, eigrph, iph);
+ listnode_add (ei->nbrs, nbr);
+
+ return nbr;
+}
+
+/**
+ * @fn eigrp_nbr_lookup_by_addr
+ *
+ * @param[in] ei EIGRP interface
+ * @param[in] nbr_addr Address of neighbor
+ *
+ * @return void
+ *
+ * @par
+ * Function is used for neighbor lookup by address
+ * in specified interface.
+ */
+struct eigrp_neighbor *
+eigrp_nbr_lookup_by_addr (struct eigrp_interface *ei, struct in_addr *addr)
+{
+ struct eigrp_neighbor *nbr;
+ struct listnode *node, *nnode;
+
+ for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr))
+ {
+ if (addr->s_addr == nbr->src.s_addr)
+ {
+ return nbr;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * @fn eigrp_nbr_lookup_by_addr_process
+ *
+ * @param[in] eigrp EIGRP process
+ * @param[in] nbr_addr Address of neighbor
+ *
+ * @return void
+ *
+ * @par
+ * Function is used for neighbor lookup by address
+ * in whole EIGRP process.
+ */
+struct eigrp_neighbor *
+eigrp_nbr_lookup_by_addr_process (struct eigrp *eigrp, struct in_addr nbr_addr)
+{
+ struct eigrp_interface *ei;
+ struct listnode *node, *node2, *nnode2;
+ struct eigrp_neighbor *nbr;
+
+ /* iterate over all eigrp interfaces */
+ for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+ {
+ /* iterate over all neighbors on eigrp interface */
+ for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
+ {
+ /* compare if neighbor address is same as arg address */
+ if (nbr->src.s_addr == nbr_addr.s_addr)
+ {
+ return nbr;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/* Delete specified EIGRP neighbor from interface. */
+void
+eigrp_nbr_delete (struct eigrp_neighbor *nbr)
+{
+
+ eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
+ eigrp_topology_neighbor_down(nbr->ei->eigrp, nbr);
+
+ /* Cancel all events. *//* Thread lookup cost would be negligible. */
+ thread_cancel_event (master, nbr);
+ eigrp_fifo_free (nbr->multicast_queue);
+ eigrp_fifo_free (nbr->retrans_queue);
+ THREAD_OFF (nbr->t_holddown);
+
+ listnode_delete (nbr->ei->nbrs,nbr);
+ XFREE (MTYPE_EIGRP_NEIGHBOR, nbr);
+}
+
+int
+holddown_timer_expired (struct thread *thread)
+{
+ struct eigrp_neighbor *nbr;
+
+ nbr = THREAD_ARG (thread);
+
+ zlog_info ("Neighbor %s (%s) is down: holding time expired",
+ inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
+ nbr->state = EIGRP_NEIGHBOR_DOWN;
+ eigrp_nbr_delete (nbr);
+
+ return 0;
+}
+
+u_char
+eigrp_nbr_state_get (struct eigrp_neighbor *nbr)
+{
+ return(nbr->state);
+}
+
+void
+eigrp_nbr_state_set (struct eigrp_neighbor *nbr, u_char state)
+{
+
+ nbr->state = state;
+
+ if (eigrp_nbr_state_get(nbr) == EIGRP_NEIGHBOR_DOWN)
+ {
+ // reset all the seq/ack counters
+ nbr->recv_sequence_number = 0;
+ nbr->init_sequence_number = 0;
+ nbr->retrans_counter = 0;
+
+ // Kvalues
+ nbr->K1 = EIGRP_K1_DEFAULT;
+ nbr->K2 = EIGRP_K2_DEFAULT;
+ nbr->K3 = EIGRP_K3_DEFAULT;
+ nbr->K4 = EIGRP_K4_DEFAULT;
+ nbr->K5 = EIGRP_K5_DEFAULT;
+ nbr->K6 = EIGRP_K6_DEFAULT;
+
+ // hold time..
+ nbr->v_holddown = EIGRP_HOLD_INTERVAL_DEFAULT;
+ THREAD_OFF(nbr->t_holddown);
+
+ /* out with the old */
+ if (nbr->multicast_queue)
+ eigrp_fifo_free (nbr->multicast_queue);
+ if (nbr->retrans_queue)
+ eigrp_fifo_free (nbr->retrans_queue);
+
+ /* in with the new */
+ nbr->retrans_queue = eigrp_fifo_new ();
+ nbr->multicast_queue = eigrp_fifo_new ();
+
+ nbr->crypt_seqnum = 0;
+ }
+}
+
+const char *
+eigrp_nbr_state_str (struct eigrp_neighbor *nbr)
+{
+ const char *state;
+ switch (nbr->state)
+ {
+ case EIGRP_NEIGHBOR_DOWN:
+ state = "Down";
+ break;
+ case EIGRP_NEIGHBOR_PENDING:
+ state = "Waiting for Init";
+ break;
+ case EIGRP_NEIGHBOR_UP:
+ state = "Up";
+ break;
+ default:
+ state = "Unknown";
+ break;
+ }
+
+ return(state);
+}
+
+void
+eigrp_nbr_state_update (struct eigrp_neighbor *nbr)
+{
+ switch (nbr->state)
+ {
+ case EIGRP_NEIGHBOR_DOWN:
+ {
+ /*Start Hold Down Timer for neighbor*/
+// THREAD_OFF(nbr->t_holddown);
+// THREAD_TIMER_ON(master, nbr->t_holddown, holddown_timer_expired,
+// nbr, nbr->v_holddown);
+ break;
+ }
+ case EIGRP_NEIGHBOR_PENDING:
+ {
+ /*Reset Hold Down Timer for neighbor*/
+ THREAD_OFF(nbr->t_holddown);
+ THREAD_TIMER_ON(master, nbr->t_holddown, holddown_timer_expired, nbr,
+ nbr->v_holddown);
+ break;
+ }
+ case EIGRP_NEIGHBOR_UP:
+ {
+ /*Reset Hold Down Timer for neighbor*/
+ THREAD_OFF(nbr->t_holddown);
+ THREAD_TIMER_ON(master, nbr->t_holddown, holddown_timer_expired, nbr,
+ nbr->v_holddown);
+ break;
+ }
+ }
+}
+
+int eigrp_nbr_count_get(void){
+
+ struct eigrp_interface *iface;
+ struct listnode *node, *node2, *nnode2;
+ struct eigrp_neighbor *nbr;
+ struct eigrp *eigrp = eigrp_lookup();
+ u_int32_t counter;
+
+ if (eigrp == NULL)
+ {
+ zlog_debug("EIGRP Routing Process not enabled");
+ return 0;
+ }
+
+ counter=0;
+ for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface))
+ {
+ for (ALL_LIST_ELEMENTS(iface->nbrs, node2, nnode2, nbr))
+ {
+ if (nbr->state == EIGRP_NEIGHBOR_UP){
+ counter++;
+ }
+ }
+ }
+ return counter;
+}
+
+/**
+ * @fn eigrp_nbr_hard_restart
+ *
+ * @param[in] nbr Neighbor who would receive hard restart
+ * @param[in] vty Virtual terminal for log output
+ * @return void
+ *
+ * @par
+ * Function used for executing hard restart for neighbor:
+ * Send Hello packet with Peer Termination TLV with
+ * neighbor's address, set it's state to DOWN and delete the neighbor
+ */
+void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty)
+{
+ if(nbr == NULL)
+ {
+ zlog_err("Nbr Hard restart: Neighbor not specified.");
+ return;
+ }
+
+ zlog_debug ("Neighbor %s (%s) is down: manually cleared",
+ inet_ntoa (nbr->src),
+ ifindex2ifname (nbr->ei->ifp->ifindex));
+ if(vty != NULL)
+ {
+ vty_time_print (vty, 0);
+ vty_out (vty, "Neighbor %s (%s) is down: manually cleared%s",
+ inet_ntoa (nbr->src),
+ ifindex2ifname (nbr->ei->ifp->ifindex),
+ VTY_NEWLINE);
+ }
+
+ /* send Hello with Peer Termination TLV */
+ eigrp_hello_send(nbr->ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR, &(nbr->src));
+ /* set neighbor to DOWN */
+ nbr->state = EIGRP_NEIGHBOR_DOWN;
+ /* delete neighbor */
+ eigrp_nbr_delete (nbr);
+}
diff --git a/eigrpd/eigrp_neighbor.h b/eigrpd/eigrp_neighbor.h
new file mode 100644
index 000000000..e9ddc22f9
--- /dev/null
+++ b/eigrpd/eigrp_neighbor.h
@@ -0,0 +1,55 @@
+/*
+ * EIGRP Neighbor Handling.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_NEIGHBOR_H
+#define _ZEBRA_EIGRP_NEIGHBOR_H
+
+/* Prototypes */
+extern struct eigrp_neighbor *eigrp_nbr_get(struct eigrp_interface *,
+ struct eigrp_header *,
+ struct ip *);
+extern struct eigrp_neighbor *eigrp_nbr_new (struct eigrp_interface *);
+extern void eigrp_nbr_delete(struct eigrp_neighbor *);
+
+extern int holddown_timer_expired(struct thread *);
+
+extern int eigrp_neighborship_check(struct eigrp_neighbor *,struct TLV_Parameter_Type *);
+extern void eigrp_nbr_state_update(struct eigrp_neighbor *);
+extern void eigrp_nbr_state_set(struct eigrp_neighbor *, u_char state);
+extern u_char eigrp_nbr_state_get(struct eigrp_neighbor *);
+extern int eigrp_nbr_count_get(void);
+extern const char *eigrp_nbr_state_str(struct eigrp_neighbor *);
+extern struct eigrp_neighbor *eigrp_nbr_lookup_by_addr (struct eigrp_interface *, struct in_addr *);
+extern struct eigrp_neighbor *eigrp_nbr_lookup_by_addr_process (struct eigrp *, struct in_addr);
+extern void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty);
+
+#endif /* _ZEBRA_EIGRP_NEIGHBOR_H */
diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c
new file mode 100644
index 000000000..fba7717b9
--- /dev/null
+++ b/eigrpd/eigrp_network.c
@@ -0,0 +1,463 @@
+/*
+ * EIGRP Network Related Functions.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "sockunion.h"
+#include "log.h"
+#include "sockopt.h"
+#include "privs.h"
+#include "table.h"
+#include "vty.h"
+
+extern struct zebra_privs_t eigrpd_privs;
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_network.h"
+
+static int
+eigrp_network_match_iface(const struct connected *, const struct prefix *);
+static void
+eigrp_network_run_interface(struct eigrp *, struct prefix *, struct interface *);
+
+int
+eigrp_sock_init(void)
+{
+ int eigrp_sock;
+ int ret, hincl = 1;
+
+ if (eigrpd_privs.change(ZPRIVS_RAISE))
+ zlog_err("eigrp_sock_init: could not raise privs, %s",
+ safe_strerror(errno));
+
+ eigrp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP);
+ if (eigrp_sock < 0)
+ {
+ int save_errno = errno;
+ if (eigrpd_privs.change(ZPRIVS_LOWER))
+ zlog_err("eigrp_sock_init: could not lower privs, %s",
+ safe_strerror(errno));
+ zlog_err("eigrp_read_sock_init: socket: %s", safe_strerror(save_errno));
+ exit(1);
+ }
+
+#ifdef IP_HDRINCL
+ /* we will include IP header with packet */
+ ret = setsockopt(eigrp_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl));
+ if (ret < 0)
+ {
+ int save_errno = errno;
+ if (eigrpd_privs.change(ZPRIVS_LOWER))
+ zlog_err("eigrp_sock_init: could not lower privs, %s",
+ safe_strerror(errno));
+ zlog_warn("Can't set IP_HDRINCL option for fd %d: %s", eigrp_sock,
+ safe_strerror(save_errno));
+
+ }
+#elif defined (IPTOS_PREC_INTERNETCONTROL)
+#warning "IP_HDRINCL not available on this system"
+#warning "using IPTOS_PREC_INTERNETCONTROL"
+ ret = setsockopt_ipv4_tos (eigrp_sock, IPTOS_PREC_INTERNETCONTROL);
+ if (ret < 0)
+ {
+ int save_errno = errno;
+ if ( eigrpd_privs.change (ZPRIVS_LOWER) )
+ zlog_err ("eigrpd_sock_init: could not lower privs, %s",
+ safe_strerror (errno) );
+ zlog_warn ("can't set sockopt IP_TOS %d to socket %d: %s",
+ tos, eigrp_sock, safe_strerror (save_errno));
+ close (eigrp_sock); /* Prevent sd leak. */
+ return ret;
+ }
+#else /* !IPTOS_PREC_INTERNETCONTROL */
+#warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
+ zlog_warn ("IP_HDRINCL option not available");
+#endif /* IP_HDRINCL */
+
+ ret = setsockopt_ifindex(AF_INET, eigrp_sock, 1);
+
+ if (ret < 0)
+ zlog_warn("Can't set pktinfo option for fd %d", eigrp_sock);
+
+ if (eigrpd_privs.change(ZPRIVS_LOWER))
+ {
+ zlog_err("eigrp_sock_init: could not lower privs, %s",
+ safe_strerror(errno));
+ }
+
+ return eigrp_sock;
+}
+
+void
+eigrp_adjust_sndbuflen(struct eigrp * eigrp, unsigned int buflen)
+{
+ int newbuflen;
+ /* Check if any work has to be done at all. */
+ if (eigrp->maxsndbuflen >= buflen)
+ return;
+ if (eigrpd_privs.change(ZPRIVS_RAISE))
+ zlog_err("%s: could not raise privs, %s", __func__, safe_strerror(errno));
+ /* Now we try to set SO_SNDBUF to what our caller has requested
+ * (the MTU of a newly added interface). However, if the OS has
+ * truncated the actual buffer size to somewhat less size, try
+ * to detect it and update our records appropriately. The OS
+ * may allocate more buffer space, than requested, this isn't
+ * a error.
+ */
+ setsockopt_so_sendbuf(eigrp->fd, buflen);
+ newbuflen = getsockopt_so_sendbuf(eigrp->fd);
+ if (newbuflen < 0 || newbuflen < (int) buflen)
+ zlog_warn("%s: tried to set SO_SNDBUF to %u, but got %d", __func__, buflen,
+ newbuflen);
+ if (newbuflen >= 0)
+ eigrp->maxsndbuflen = (unsigned int) newbuflen;
+ else
+ zlog_warn("%s: failed to get SO_SNDBUF", __func__);
+ if (eigrpd_privs.change(ZPRIVS_LOWER))
+ zlog_err("%s: could not lower privs, %s", __func__, safe_strerror(errno));
+}
+
+int
+eigrp_if_ipmulticast(struct eigrp *top, struct prefix *p, unsigned int ifindex)
+{
+ u_char val;
+ int ret, len;
+
+ val = 0;
+ len = sizeof(val);
+
+ /* Prevent receiving self-origined multicast packets. */
+ ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *) &val, len);
+ if (ret < 0)
+ zlog_warn("can't setsockopt IP_MULTICAST_LOOP (0) for fd %d: %s", top->fd,
+ safe_strerror(errno));
+
+ /* Explicitly set multicast ttl to 1 -- endo. */
+ val = 1;
+ ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *) &val, len);
+ if (ret < 0)
+ zlog_warn("can't setsockopt IP_MULTICAST_TTL (1) for fd %d: %s", top->fd,
+ safe_strerror(errno));
+
+ ret = setsockopt_ipv4_multicast_if(top->fd, p->u.prefix4, ifindex);
+ if (ret < 0)
+ zlog_warn("can't setsockopt IP_MULTICAST_IF (fd %d, addr %s, "
+ "ifindex %u): %s", top->fd, inet_ntoa(p->u.prefix4), ifindex,
+ safe_strerror(errno));
+
+ return ret;
+}
+
+/* Join to the EIGRP multicast group. */
+int
+eigrp_if_add_allspfrouters(struct eigrp *top, struct prefix *p,
+ unsigned int ifindex)
+{
+ int ret;
+
+ ret = setsockopt_ipv4_multicast(top->fd, IP_ADD_MEMBERSHIP, p->u.prefix4,
+ htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
+ if (ret < 0)
+ zlog_warn("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, "
+ "ifindex %u, AllSPFRouters): %s; perhaps a kernel limit "
+ "on # of multicast group memberships has been exceeded?", top->fd,
+ inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno));
+ else
+ zlog_debug("interface %s [%u] join EIGRP Multicast group.",
+ inet_ntoa(p->u.prefix4), ifindex);
+
+ return ret;
+}
+
+int
+eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p,
+ unsigned int ifindex)
+{
+ int ret;
+
+ ret = setsockopt_ipv4_multicast(top->fd, IP_DROP_MEMBERSHIP, p->u.prefix4,
+ htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
+ if (ret < 0)
+ zlog_warn("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, "
+ "ifindex %u, AllSPFRouters): %s", top->fd, inet_ntoa(p->u.prefix4),
+ ifindex, safe_strerror(errno));
+ else
+ zlog_debug("interface %s [%u] leave EIGRP Multicast group.",
+ inet_ntoa(p->u.prefix4), ifindex);
+
+ return ret;
+}
+
+int
+eigrp_network_set(struct eigrp *eigrp, struct prefix_ipv4 *p)
+{
+ struct route_node *rn;
+ struct interface *ifp;
+ struct listnode *node;
+
+ zlog_debug ("A");
+ rn = route_node_get(eigrp->networks, (struct prefix *) p);
+ if (rn->info)
+ {
+ /* There is already same network statement. */
+ route_unlock_node(rn);
+ return 0;
+ }
+
+ struct prefix_ipv4 *pref = prefix_ipv4_new();
+ PREFIX_COPY_IPV4(pref,p);
+ rn->info = (void *) pref;
+
+ zlog_debug ("B");
+ /* Schedule Router ID Update. */
+// if (eigrp->router_id == 0)
+// eigrp_router_id_update(eigrp);
+ /* Run network config now. */
+ /* Get target interface. */
+ for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp))
+ {
+ zlog_debug("Setting up %s", ifp->name);
+ eigrp_network_run_interface(eigrp, (struct prefix *) p, ifp);
+ }
+ return 1;
+}
+
+/* Check whether interface matches given network
+ * returns: 1, true. 0, false
+ */
+static int
+eigrp_network_match_iface(const struct connected *co, const struct prefix *net)
+{
+ /* new approach: more elegant and conceptually clean */
+ return prefix_match(net, CONNECTED_PREFIX (co));
+}
+
+static void
+eigrp_network_run_interface(struct eigrp *eigrp, struct prefix *p,
+ struct interface *ifp)
+{
+ struct listnode *cnode;
+ struct connected *co;
+
+ /* if interface prefix is match specified prefix,
+ then create socket and join multicast group. */
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, co))
+ {
+
+ if (CHECK_FLAG (co->flags,ZEBRA_IFA_SECONDARY))
+ continue;
+
+ if (p->family == co->address->family
+ && !eigrp_if_table_lookup(ifp, co->address)
+ && eigrp_network_match_iface(co, p))
+ {
+ struct eigrp_interface *ei;
+
+ ei = eigrp_if_new(eigrp, ifp, co->address);
+ ei->connected = co;
+
+ ei->params = eigrp_lookup_if_params(ifp, ei->address->u.prefix4);
+
+ /* Relate eigrp interface to eigrp instance. */
+ ei->eigrp = eigrp;
+
+ /* update network type as interface flag */
+ /* If network type is specified previously,
+ skip network type setting. */
+ ei->type = IF_DEF_PARAMS (ifp)->type;
+
+ /* if router_id is not configured, dont bring up
+ * interfaces.
+ * eigrp_router_id_update() will call eigrp_if_update
+ * whenever r-id is configured instead.
+ */
+ if (if_is_operative(ifp))
+ eigrp_if_up(ei);
+ }
+ }
+}
+
+void
+eigrp_if_update(struct interface *ifp)
+{
+ struct listnode *node, *nnode;
+ struct route_node *rn;
+ struct eigrp *eigrp;
+
+ /*
+ * In the event there are multiple eigrp autonymnous systems running,
+ * we need to check eac one and add the interface as approperate
+ */
+ for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp))
+ {
+ /* EIGRP must be on and Router-ID must be configured. */
+ if (!eigrp || eigrp->router_id == 0)
+ continue;
+
+ /* Run each network for this interface. */
+ for (rn = route_top(eigrp->networks); rn; rn = route_next(rn))
+ if (rn->info != NULL)
+ {
+ eigrp_network_run_interface(eigrp, &rn->p, ifp);
+ }
+ }
+}
+
+int
+eigrp_network_unset(struct eigrp *eigrp, struct prefix_ipv4 *p)
+{
+ struct route_node *rn;
+ struct listnode *node, *nnode;
+ struct eigrp_interface *ei;
+ struct prefix *pref;
+
+ rn = route_node_lookup(eigrp->networks, (struct prefix *) p);
+ if (rn == NULL)
+ return 0;
+
+ pref = rn->info;
+ route_unlock_node (rn);
+
+ if (!IPV4_ADDR_SAME (&pref->u.prefix4, &p->prefix))
+ return 0;
+
+ prefix_ipv4_free(rn->info);
+ rn->info = NULL;
+ route_unlock_node(rn); /* initial reference */
+
+ /* Find interfaces that not configured already. */
+ for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei))
+ {
+ int found = 0;
+ struct connected *co = ei->connected;
+
+ for (rn = route_top(eigrp->networks); rn; rn = route_next(rn))
+ {
+ if (rn->info == NULL)
+ continue;
+
+ if (eigrp_network_match_iface(co, &rn->p))
+ {
+ zlog_debug("eigrp_network_unset()2");
+ found = 1;
+ route_unlock_node(rn);
+ break;
+ }
+ }
+
+ if (found == 0)
+ {
+ eigrp_if_free(ei, INTERFACE_DOWN_BY_VTY);
+ }
+ }
+
+ return 1;
+}
+
+u_int32_t
+eigrp_calculate_metrics(struct eigrp *eigrp, struct eigrp_metrics *metric)
+{
+ u_int64_t temp_metric;
+ temp_metric = 0;
+
+ if(metric->delay == EIGRP_MAX_METRIC)
+ return EIGRP_MAX_METRIC;
+
+ // EIGRP Metric = {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)}
+
+ if (eigrp->k_values[0])
+ temp_metric += (eigrp->k_values[0] * metric->bandwith);
+ if (eigrp->k_values[1])
+ temp_metric += ((eigrp->k_values[1] * metric->bandwith)
+ / (256 - metric->load));
+ if (eigrp->k_values[2])
+ temp_metric += (eigrp->k_values[2] * metric->delay);
+ if (eigrp->k_values[3] && !eigrp->k_values[4])
+ temp_metric *= eigrp->k_values[3];
+ if (!eigrp->k_values[3] && eigrp->k_values[4])
+ temp_metric *= (eigrp->k_values[4] / metric->reliability);
+ if (eigrp->k_values[3] && eigrp->k_values[4])
+ temp_metric *= ((eigrp->k_values[4] / metric->reliability)
+ + eigrp->k_values[3]);
+
+ if (temp_metric <= EIGRP_MAX_METRIC)
+ return (u_int32_t) temp_metric;
+ else
+ return EIGRP_MAX_METRIC;
+}
+
+u_int32_t
+eigrp_calculate_total_metrics(struct eigrp *eigrp,
+ struct eigrp_neighbor_entry *entry)
+{
+ entry->total_metric = entry->reported_metric;
+ u_int64_t temp_delay = (u_int64_t) entry->total_metric.delay
+ + (u_int64_t) EIGRP_IF_PARAM (entry->ei, delay);
+ entry->total_metric.delay =
+ temp_delay > EIGRP_MAX_METRIC ? EIGRP_MAX_METRIC : (u_int32_t) temp_delay;
+
+ u_int32_t bw = EIGRP_IF_PARAM (entry->ei,bandwidth);
+ entry->total_metric.bandwith =
+ entry->total_metric.bandwith > bw ? bw : entry->total_metric.bandwith;
+
+ return eigrp_calculate_metrics(eigrp, &entry->total_metric);
+}
+
+u_char
+eigrp_metrics_is_same(struct eigrp_metrics *metric1,
+ struct eigrp_metrics *metric2)
+{
+ if ((metric1->bandwith == metric2->bandwith)
+ && (metric1->delay == metric2->delay)
+ && (metric1->hop_count == metric2->hop_count)
+ && (metric1->load == metric2->load)
+ && (metric1->reliability == metric2->reliability)
+ && (metric1->mtu[0] == metric2->mtu[0])
+ && (metric1->mtu[1] == metric2->mtu[1])
+ && (metric1->mtu[2] == metric2->mtu[2]))
+ return 1;
+
+ return 0; // if different
+}
+void
+eigrp_external_routes_refresh (struct eigrp *eigrp, int type)
+{
+
+
+}
+
diff --git a/eigrpd/eigrp_network.h b/eigrpd/eigrp_network.h
new file mode 100644
index 000000000..87d128062
--- /dev/null
+++ b/eigrpd/eigrp_network.h
@@ -0,0 +1,52 @@
+/*
+ * EIGRP Network Related Functions.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_NETWORK_H
+#define _ZEBRA_EIGRP_NETWORK_H
+
+/* Prototypes */
+
+extern int eigrp_sock_init (void);
+extern int eigrp_if_ipmulticast (struct eigrp *, struct prefix *, unsigned int);
+extern int eigrp_network_set (struct eigrp *, struct prefix_ipv4 *);
+extern int eigrp_network_unset (struct eigrp *eigrp, struct prefix_ipv4 *p);
+
+extern int eigrp_hello_timer (struct thread *);
+extern void eigrp_if_update (struct interface *);
+extern int eigrp_if_add_allspfrouters (struct eigrp *, struct prefix *,
+ unsigned int);
+extern int eigrp_if_drop_allspfrouters (struct eigrp *top, struct prefix *p,
+ unsigned int ifindex);
+extern void eigrp_adjust_sndbuflen (struct eigrp *, unsigned int);
+
+extern u_int32_t eigrp_calculate_metrics (struct eigrp *, struct eigrp_metrics *);
+extern u_int32_t eigrp_calculate_total_metrics (struct eigrp *, struct eigrp_neighbor_entry *);
+extern u_char eigrp_metrics_is_same(struct eigrp_metrics *,struct eigrp_metrics *);
+extern void eigrp_external_routes_refresh (struct eigrp *, int);
+
+#endif /* EIGRP_NETWORK_H_ */
diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c
new file mode 100644
index 000000000..9a0a9897f
--- /dev/null
+++ b/eigrpd/eigrp_packet.c
@@ -0,0 +1,1441 @@
+/*
+ * EIGRP General Sending and Receiving of EIGRP Packets.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "vty.h"
+#include "keychain.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
+#include "sha256.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_memory.h"
+
+/* Packet Type String. */
+const struct message eigrp_packet_type_str[] =
+{
+ { EIGRP_OPC_UPDATE, "Update" },
+ { EIGRP_OPC_REQUEST, "Request" },
+ { EIGRP_OPC_QUERY, "Query" },
+ { EIGRP_OPC_REPLY, "Reply" },
+ { EIGRP_OPC_HELLO, "Hello" },
+ { EIGRP_OPC_IPXSAP, "IPX-SAP" },
+ { EIGRP_OPC_PROBE, "Probe" },
+ { EIGRP_OPC_ACK, "Ack" },
+ { EIGRP_OPC_SIAQUERY, "SIAQuery" },
+ { EIGRP_OPC_SIAREPLY, "SIAReply" },
+};
+const size_t eigrp_packet_type_str_max = sizeof(eigrp_packet_type_str) /
+ sizeof(eigrp_packet_type_str[0]);
+
+static unsigned char zeropad[16] = {0};
+
+/* Forward function reference*/
+static struct stream * eigrp_recv_packet (int, struct interface **, struct stream *);
+static int eigrp_verify_header (struct stream *, struct eigrp_interface *, struct ip *,
+ struct eigrp_header *);
+static int eigrp_check_network_mask (struct eigrp_interface *, struct in_addr);
+
+
+static int eigrp_retrans_count_exceeded(struct eigrp_packet *ep, struct eigrp_neighbor *nbr)
+{
+ return 1;
+}
+
+int
+eigrp_make_md5_digest (struct eigrp_interface *ei, struct stream *s, u_char flags)
+{
+ struct key *key = NULL;
+ struct keychain *keychain;
+
+ unsigned char digest[EIGRP_AUTH_TYPE_MD5_LEN];
+ MD5_CTX ctx;
+ u_char *ibuf;
+ size_t backup_get, backup_end;
+ struct TLV_MD5_Authentication_Type *auth_TLV;
+
+ ibuf = s->data;
+ backup_end = s->endp;
+ backup_get = s->getp;
+
+ auth_TLV = eigrp_authTLV_MD5_new();
+
+ stream_set_getp(s,EIGRP_HEADER_LEN);
+ stream_get(auth_TLV,s,EIGRP_AUTH_MD5_TLV_SIZE);
+ stream_set_getp(s, backup_get);
+
+ keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
+ if(keychain)
+ key = key_lookup_for_send(keychain);
+ else
+ return EIGRP_AUTH_TYPE_NONE;
+
+ memset(&ctx, 0, sizeof(ctx));
+ MD5Init(&ctx);
+
+ /* Generate a digest. Each situation needs different handling */
+ if(flags & EIGRP_AUTH_BASIC_HELLO_FLAG)
+ {
+ MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE);
+ MD5Update(&ctx, key->string, strlen(key->string));
+ if(strlen(key->string) < 16)
+ MD5Update(&ctx, zeropad, 16 - strlen(key->string));
+ }
+ else if(flags & EIGRP_AUTH_UPDATE_INIT_FLAG)
+ {
+ MD5Update(&ctx, ibuf, EIGRP_MD5_UPDATE_INIT_COMPUTE);
+ }
+ else if(flags & EIGRP_AUTH_UPDATE_FLAG)
+ {
+ MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE);
+ MD5Update(&ctx, key->string, strlen(key->string));
+ if(strlen(key->string) < 16)
+ MD5Update(&ctx, zeropad, 16 - strlen(key->string));
+ if(backup_end > (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE))
+ {
+ MD5Update(&ctx, ibuf + (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE),
+ backup_end - 20 - (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE));
+ }
+ }
+
+ MD5Final(digest, &ctx);
+
+
+ /* Append md5 digest to the end of the stream. */
+ memcpy(auth_TLV->digest,digest,EIGRP_AUTH_TYPE_MD5_LEN);
+
+ stream_set_endp(s,EIGRP_HEADER_LEN);
+ stream_put(s,auth_TLV,EIGRP_AUTH_MD5_TLV_SIZE);
+ stream_set_endp(s, backup_end);
+
+ eigrp_authTLV_MD5_free(auth_TLV);
+ return EIGRP_AUTH_TYPE_MD5_LEN;
+}
+
+int
+eigrp_check_md5_digest (struct stream *s, struct TLV_MD5_Authentication_Type *authTLV,struct eigrp_neighbor *nbr, u_char flags)
+{
+ MD5_CTX ctx;
+ unsigned char digest[EIGRP_AUTH_TYPE_MD5_LEN];
+ struct key *key = NULL;
+ struct keychain *keychain;
+ u_char *ibuf;
+ size_t backup_end;
+ struct TLV_MD5_Authentication_Type *auth_TLV;
+ struct eigrp_header *eigrph;
+
+
+ if (nbr && ntohl(nbr->crypt_seqnum) > ntohl(authTLV->key_sequence))
+ {
+ zlog_warn ("interface %s: eigrp_check_md5 bad sequence %d (expect %d)",
+ IF_NAME (nbr->ei),
+ ntohl(authTLV->key_sequence),
+ ntohl(nbr->crypt_seqnum));
+ return 0;
+ }
+
+ eigrph = (struct eigrp_header *) s->data;
+ eigrph->checksum = 0;
+
+ auth_TLV =(struct TLV_MD5_Authentication_Type *) (s->data + EIGRP_HEADER_LEN);
+ memcpy(auth_TLV->digest, "0", sizeof(auth_TLV->digest));
+
+ ibuf = s->data;
+ backup_end = s->endp;
+
+ keychain = keychain_lookup(IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain);
+ if(keychain)
+ key = key_lookup_for_send(keychain);
+
+ memset(&ctx, 0, sizeof(ctx));
+ MD5Init(&ctx);
+
+ /* Generate a digest. Each situation needs different handling */
+ if(flags & EIGRP_AUTH_BASIC_HELLO_FLAG)
+ {
+ MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE);
+ MD5Update(&ctx, key->string, strlen(key->string));
+ if(strlen(key->string) < 16)
+ MD5Update(&ctx, zeropad, 16 - strlen(key->string));
+ }
+ else if(flags & EIGRP_AUTH_UPDATE_INIT_FLAG)
+ {
+ MD5Update(&ctx, ibuf, EIGRP_MD5_UPDATE_INIT_COMPUTE);
+ }
+ else if(flags & EIGRP_AUTH_UPDATE_FLAG)
+ {
+ MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE);
+ MD5Update(&ctx, key->string, strlen(key->string));
+ if(strlen(key->string) < 16)
+ MD5Update(&ctx, zeropad, 16 - strlen(key->string));
+ if(backup_end > (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE))
+ {
+ MD5Update(&ctx, ibuf + (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE),
+ backup_end - 20 - (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE));
+ }
+ }
+
+ MD5Final(digest, &ctx);
+
+ /* compare the two */
+ if (memcmp (authTLV->digest, digest, EIGRP_AUTH_TYPE_MD5_LEN) == 0)
+ {
+ zlog_debug("VSETKO OK");
+ }
+ else
+ {
+ zlog_warn ("interface %s: eigrp_check_md5 checksum mismatch",
+ IF_NAME (nbr->ei));
+ return 0;
+ }
+
+ /* save neighbor's crypt_seqnum */
+ if (nbr)
+ nbr->crypt_seqnum = authTLV->key_sequence;
+
+ return 1;
+}
+
+int
+eigrp_make_sha256_digest (struct eigrp_interface *ei, struct stream *s, u_char flags)
+{
+ struct key *key = NULL;
+ struct keychain *keychain;
+ char *source_ip;
+
+ unsigned char digest[EIGRP_AUTH_TYPE_SHA256_LEN];
+ unsigned char buffer[1 + PLAINTEXT_LENGTH + 45 + 1] = { 0 };
+ HMAC_SHA256_CTX ctx;
+ void *ibuf;
+ size_t backup_get, backup_end;
+ struct TLV_SHA256_Authentication_Type *auth_TLV;
+
+ ibuf = s->data;
+ backup_end = s->endp;
+ backup_get = s->getp;
+
+ auth_TLV = eigrp_authTLV_SHA256_new ();
+
+ stream_set_getp(s,EIGRP_HEADER_LEN);
+ stream_get(auth_TLV,s,EIGRP_AUTH_SHA256_TLV_SIZE);
+ stream_set_getp(s, backup_get);
+
+ keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
+ if(keychain)
+ key = key_lookup_for_send(keychain);
+
+// saved_len[index] = strnzcpyn(saved_key[index], key,
+// PLAINTEXT_LENGTH + 1);
+
+ source_ip = calloc(16, sizeof(char));
+ inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, 16);
+
+ memset(&ctx, 0, sizeof(ctx));
+ buffer[0] = '\n';
+ memcpy(buffer + 1, key, strlen (key->string));
+ memcpy(buffer + 1 + strlen(key->string), source_ip, strlen(source_ip));
+ HMAC__SHA256_Init(&ctx, buffer, 1 + strlen (key->string) + strlen(source_ip));
+ HMAC__SHA256_Update(&ctx, ibuf, strlen(ibuf));
+ HMAC__SHA256_Final(digest, &ctx);
+
+
+ /* Put hmac-sha256 digest to it's place */
+ memcpy(auth_TLV->digest,digest,EIGRP_AUTH_TYPE_SHA256_LEN);
+
+ stream_set_endp(s,EIGRP_HEADER_LEN);
+ stream_put(s,auth_TLV,EIGRP_AUTH_SHA256_TLV_SIZE);
+ stream_set_endp(s, backup_end);
+
+ eigrp_authTLV_SHA256_free(auth_TLV);
+ free(source_ip);
+
+ return EIGRP_AUTH_TYPE_SHA256_LEN;
+}
+
+int
+eigrp_check_sha256_digest (struct stream *s, struct TLV_SHA256_Authentication_Type *authTLV,struct eigrp_neighbor *nbr, u_char flags)
+{
+
+ return 1;
+}
+/*
+ * eigrp_packet_dump
+ *
+ * This routing dumps the contents of the IP packet either received or
+ * built by EIGRP.
+ */
+static void
+eigrp_packet_dump (struct stream *s)
+{
+ // not yet...
+ return;
+}
+
+/*
+ * Converts a 24-bit integer represented as an unsigned char[3] *value
+ * in network byte order into uint32_t in host byte order
+ */
+//static uint32_t u24_32 (const unsigned char *value)
+//{
+// return (value[0] << 16) + (value[1] << 8) + value[2];
+//}
+//
+///*
+// * Converts an uint32_t value in host byte order into a 24-bit integer
+// * in network byte order represented by unsigned char[3] *result
+// */
+//static unsigned char * u32_24 (uint32_t value, unsigned char *result)
+//{
+// value = htonl(value & 0x00FFFFFF);
+// memcpy (result, (unsigned char *) &value + 1, 3);
+//
+// return result;
+//}
+
+int
+eigrp_write (struct thread *thread)
+{
+ struct eigrp *eigrp = THREAD_ARG(thread);
+ struct eigrp_header *eigrph;
+ struct eigrp_interface *ei;
+ struct eigrp_packet *ep;
+ struct sockaddr_in sa_dst;
+ struct ip iph;
+ struct msghdr msg;
+ struct iovec iov[2];
+ u_int16_t opcode = 0;
+
+ int ret;
+ int flags = 0;
+ struct listnode *node;
+#ifdef WANT_EIGRP_WRITE_FRAGMENT
+ static u_int16_t ipid = 0;
+#endif /* WANT_EIGRP_WRITE_FRAGMENT */
+#define EIGRP_WRITE_IPHL_SHIFT 2
+
+ eigrp->t_write = NULL;
+
+ node = listhead(eigrp->oi_write_q);
+ assert(node);
+ ei = listgetdata(node);
+ assert(ei);
+
+#ifdef WANT_EIGRP_WRITE_FRAGMENT
+ /* seed ipid static with low order bits of time */
+ if (ipid == 0)
+ ipid = (time(NULL) & 0xffff);
+#endif /* WANT_EIGRP_WRITE_FRAGMENT */
+
+ /* Get one packet from queue. */
+ ep = eigrp_fifo_head(ei->obuf);
+ assert(ep);
+ assert(ep->length >= EIGRP_HEADER_LEN);
+
+ if (ep->dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS))
+ eigrp_if_ipmulticast(eigrp, ei->address, ei->ifp->ifindex);
+
+ memset(&iph, 0, sizeof(struct ip));
+ memset(&sa_dst, 0, sizeof(sa_dst));
+
+ sa_dst.sin_family = AF_INET;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ sa_dst.sin_len = sizeof(sa_dst);
+#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
+ sa_dst.sin_addr = ep->dst;
+ sa_dst.sin_port = htons(0);
+
+ /* Set DONTROUTE flag if dst is unicast. */
+ if (!IN_MULTICAST(htonl(ep->dst.s_addr)))
+ flags = MSG_DONTROUTE;
+
+ iph.ip_hl = sizeof(struct ip) >> EIGRP_WRITE_IPHL_SHIFT;
+ /* it'd be very strange for header to not be 4byte-word aligned but.. */
+ if (sizeof(struct ip) > (unsigned int)(iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT))
+ iph.ip_hl++; /* we presume sizeof struct ip cant overflow ip_hl.. */
+
+ iph.ip_v = IPVERSION;
+ iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
+ iph.ip_len = (iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT) + ep->length;
+
+#if defined (__DragonFly__)
+ /*
+ * DragonFly's raw socket expects ip_len/ip_off in network byte order.
+ */
+ iph.ip_len = htons(iph.ip_len);
+#endif
+
+ iph.ip_off = 0;
+ iph.ip_ttl = EIGRP_IP_TTL;
+ iph.ip_p = IPPROTO_EIGRPIGP;
+ iph.ip_sum = 0;
+ iph.ip_src.s_addr = ei->address->u.prefix4.s_addr;
+ iph.ip_dst.s_addr = ep->dst.s_addr;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (caddr_t) &sa_dst;
+ msg.msg_namelen = sizeof(sa_dst);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+
+ iov[0].iov_base = (char*)&iph;
+ iov[0].iov_len = iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT;
+ iov[1].iov_base = STREAM_PNT(ep->s);
+ iov[1].iov_len = ep->length;
+
+ /* send final fragment (could be first) */
+ sockopt_iphdrincl_swab_htosys(&iph);
+ ret = sendmsg(eigrp->fd, &msg, flags);
+ sockopt_iphdrincl_swab_systoh(&iph);
+
+ if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND))
+ {
+ eigrph = (struct eigrp_header *) STREAM_DATA(ep->s);
+ opcode = eigrph->opcode;
+ zlog_debug("Sending [%s] to [%s] via [%s] ret [%d].",
+ LOOKUP(eigrp_packet_type_str, opcode), inet_ntoa(ep->dst),
+ IF_NAME(ei), ret);
+ }
+
+ if (ret < 0)
+ zlog_warn("*** sendmsg in eigrp_write failed to %s, "
+ "id %d, off %d, len %d, interface %s, mtu %u: %s",
+ inet_ntoa(iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len, ei->ifp->name,
+ ei->ifp->mtu, safe_strerror(errno));
+
+ /* Show debug sending packet. */
+ if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND) && (IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL)))
+ {
+ zlog_debug("-----------------------------------------------------");
+ eigrp_ip_header_dump(&iph);
+ stream_set_getp(ep->s, 0);
+ eigrp_packet_dump(ep->s);
+ zlog_debug("-----------------------------------------------------");
+ }
+
+ /* Now delete packet from queue. */
+ eigrp_packet_delete(ei);
+
+ if (eigrp_fifo_head(ei->obuf) == NULL)
+ {
+ ei->on_write_q = 0;
+ list_delete_node(eigrp->oi_write_q, node);
+ }
+
+ /* If packets still remain in queue, call write thread. */
+ if (!list_isempty(eigrp->oi_write_q))
+ eigrp->t_write = thread_add_write(master, eigrp_write, eigrp, eigrp->fd);
+
+ return 0;
+}
+
+/* Starting point of packet process function. */
+int
+eigrp_read (struct thread *thread)
+{
+ int ret;
+ struct stream *ibuf;
+ struct eigrp *eigrp;
+ struct eigrp_interface *ei;
+ struct ip *iph;
+ struct eigrp_header *eigrph;
+ struct interface *ifp;
+ struct eigrp_neighbor *nbr;
+
+ u_int16_t opcode = 0;
+ u_int16_t length = 0;
+
+ /* first of all get interface pointer. */
+ eigrp = THREAD_ARG(thread);
+
+ /* prepare for next packet. */
+ eigrp->t_read = thread_add_read(master, eigrp_read, eigrp, eigrp->fd);
+
+ stream_reset(eigrp->ibuf);
+ if (!(ibuf = eigrp_recv_packet(eigrp->fd, &ifp, eigrp->ibuf)))
+ {
+ /* This raw packet is known to be at least as big as its IP header. */
+ return -1;
+ }
+
+ /* Note that there should not be alignment problems with this assignment
+ because this is at the beginning of the stream data buffer. */
+ iph = (struct ip *)STREAM_DATA(ibuf);
+
+ //Substract IPv4 header size from EIGRP Packet itself
+ if(iph->ip_v == 4)
+ length = (iph->ip_len) - 20U;
+
+
+ /* IP Header dump. */
+ if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV) && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
+ eigrp_ip_header_dump(iph);
+
+ /* Note that sockopt_iphdrincl_swab_systoh was called in eigrp_recv_packet. */
+ if (ifp == NULL)
+ {
+ /* Handle cases where the platform does not support retrieving the ifindex,
+ and also platforms (such as Solaris 8) that claim to support ifindex
+ retrieval but do not. */
+ ifp = if_lookup_address((void *)&iph->ip_src, VRF_DEFAULT);
+
+ if (ifp == NULL)
+ return 0;
+ }
+
+ /* associate packet with eigrp interface */
+ ei = eigrp_if_lookup_recv_if(eigrp, iph->ip_src, ifp);
+
+ /* eigrp_verify_header() relies on a valid "ei" and thus can be called only
+ after the checks below are passed. These checks in turn access the
+ fields of unverified "eigrph" structure for their own purposes and
+ must remain very accurate in doing this.
+ */
+ if (!ei)
+ return 0;
+
+ /* Self-originated packet should be discarded silently. */
+ if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src) ||
+ (IPV4_ADDR_SAME(&iph->ip_src.s_addr, &ei->address->u.prefix4)))
+ {
+ if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
+ zlog_debug("eigrp_read[%s]: Dropping self-originated packet",
+ inet_ntoa(iph->ip_src));
+ return 0;
+ }
+
+ /* Advance from IP header to EIGRP header (iph->ip_hl has been verified
+ by eigrp_recv_packet() to be correct). */
+
+ stream_forward_getp(ibuf, (iph->ip_hl * 4));
+ eigrph = (struct eigrp_header *) STREAM_PNT(ibuf);
+
+ if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV) && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
+ eigrp_header_dump(eigrph);
+
+// if (MSG_OK != eigrp_packet_examin(eigrph, stream_get_endp(ibuf) - stream_get_getp(ibuf)))
+// return -1;
+
+ /* Now it is safe to access all fields of EIGRP packet header. */
+ /* associate packet with eigrp interface */
+ ei = eigrp_if_lookup_recv_if(eigrp, iph->ip_src, ifp);
+
+ /* eigrp_verify_header() relies on a valid "ei" and thus can be called only
+ after the checks below are passed. These checks in turn access the
+ fields of unverified "eigrph" structure for their own purposes and
+ must remain very accurate in doing this.
+ */
+ if (!ei)
+ return 0;
+
+ /* If incoming interface is passive one, ignore it. */
+ if (ei && EIGRP_IF_PASSIVE_STATUS(ei) == EIGRP_IF_PASSIVE)
+ {
+ char buf[3][INET_ADDRSTRLEN];
+
+ if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
+ zlog_debug("ignoring packet from router %s sent to %s, "
+ "received on a passive interface, %s",
+ inet_ntop(AF_INET, &eigrph->vrid, buf[0], sizeof(buf[0])),
+ inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])),
+ inet_ntop(AF_INET, &ei->address->u.prefix4,
+ buf[2], sizeof(buf[2])));
+
+ if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS))
+ {
+ /* Try to fix multicast membership.
+ * Some OS:es may have problems in this area,
+ * make sure it is removed.
+ */
+ EI_MEMBER_JOINED(ei, MEMBER_ALLROUTERS);
+ eigrp_if_set_multicast(ei);
+ }
+ return 0;
+ }
+
+ /* else it must be a local eigrp interface, check it was received on
+ * correct link
+ */
+ else if (ei->ifp != ifp)
+ {
+ if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
+ zlog_warn("Packet from [%s] received on wrong link %s",
+ inet_ntoa(iph->ip_src), ifp->name);
+ return 0;
+ }
+
+ /* Verify more EIGRP header fields. */
+ ret = eigrp_verify_header(ibuf, ei, iph, eigrph);
+ if (ret < 0)
+ {
+ if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
+ zlog_debug("eigrp_read[%s]: Header check failed, dropping.",
+ inet_ntoa(iph->ip_src));
+ return ret;
+ }
+
+ /* calcualte the eigrp packet length, and move the pounter to the
+ start of the eigrp TLVs */
+ opcode = eigrph->opcode;
+
+ if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
+ zlog_debug("Received [%s] length [%u] via [%s] src [%s] dst [%s]",
+ LOOKUP(eigrp_packet_type_str, opcode), length,
+ IF_NAME(ei), inet_ntoa(iph->ip_src), inet_ntoa(iph->ip_dst));
+
+ /* Read rest of the packet and call each sort of packet routine. */
+ stream_forward_getp(ibuf, EIGRP_HEADER_LEN);
+
+
+ /* New testing block of code for handling Acks */
+ if (ntohl(eigrph->ack) != 0)
+ {
+ nbr = eigrp_nbr_get(ei, eigrph, iph);
+
+ /* neighbor must be valid, eigrp_nbr_get creates if none existed */
+ assert(nbr);
+
+ struct eigrp_packet *ep;
+
+ ep = eigrp_fifo_tail(nbr->retrans_queue);
+ if (ep != NULL)
+ {
+ if (ntohl(eigrph->ack) == ep->sequence_number)
+ {
+ if((nbr->state == EIGRP_NEIGHBOR_PENDING) && (ntohl(eigrph->ack) == nbr->init_sequence_number))
+ {
+ eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_UP);
+ zlog_info("Neighbor adjacency became full");
+ nbr->init_sequence_number = 0;
+ nbr->recv_sequence_number = ntohl(eigrph->sequence);
+ eigrp_update_send_EOT(nbr);
+ }
+ ep = eigrp_fifo_pop_tail(nbr->retrans_queue);
+ /*eigrp_packet_free(ep);*/
+ if (nbr->retrans_queue->count > 0)
+ {
+ eigrp_send_packet_reliably(nbr);
+ }
+ }
+ }
+ ep = eigrp_fifo_tail(nbr->multicast_queue);
+ if (ep != NULL)
+ {
+ if (ntohl(eigrph->ack) == ep->sequence_number)
+ {
+ ep = eigrp_fifo_pop_tail(nbr->multicast_queue);
+ eigrp_packet_free(ep);
+ if (nbr->multicast_queue->count > 0)
+ {
+ eigrp_send_packet_reliably(nbr);
+ }
+ }
+ }
+ }
+
+
+ switch (opcode)
+ {
+ case EIGRP_OPC_HELLO:
+ eigrp_hello_receive(eigrp, iph, eigrph, ibuf, ei, length);
+ break;
+ case EIGRP_OPC_PROBE:
+ // eigrp_probe_receive(eigrp, iph, eigrph, ibuf, ei, length);
+ break;
+ case EIGRP_OPC_QUERY:
+ eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length);
+ break;
+ case EIGRP_OPC_REPLY:
+ eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length);
+ break;
+ case EIGRP_OPC_REQUEST:
+ // eigrp_request_receive(eigrp, iph, eigrph, ibuf, ei, length);
+ break;
+ case EIGRP_OPC_SIAQUERY:
+ eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length);
+ break;
+ case EIGRP_OPC_SIAREPLY:
+ eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length);
+ break;
+ case EIGRP_OPC_UPDATE:
+ eigrp_update_receive(eigrp, iph, eigrph, ibuf, ei, length);
+ break;
+ default:
+ zlog(NULL, LOG_WARNING,
+ "interface %s: EIGRP packet header type %d unsupported",
+ IF_NAME(ei), opcode);
+ break;
+ }
+
+ return 0;
+}
+
+static struct stream *
+eigrp_recv_packet (int fd, struct interface **ifp, struct stream *ibuf)
+{
+ int ret;
+ struct ip *iph;
+ u_int16_t ip_len;
+ unsigned int ifindex = 0;
+ struct iovec iov;
+ /* Header and data both require alignment. */
+ char buff[CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())];
+ struct msghdr msgh;
+
+ memset(&msgh, 0, sizeof(struct msghdr));
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_control = (caddr_t) buff;
+ msgh.msg_controllen = sizeof(buff);
+
+ ret = stream_recvmsg(ibuf, fd, &msgh, 0, (EIGRP_PACKET_MAX_LEN + 1));
+ if (ret < 0)
+ {
+ zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno));
+ return NULL;
+ }
+ if ((unsigned int) ret < sizeof(iph)) /* ret must be > 0 now */
+ {
+ zlog_warn("eigrp_recv_packet: discarding runt packet of length %d "
+ "(ip header size is %u)", ret, (u_int) sizeof(iph));
+ return NULL;
+ }
+
+ /* Note that there should not be alignment problems with this assignment
+ because this is at the beginning of the stream data buffer. */
+ iph = (struct ip *) STREAM_DATA(ibuf);
+ sockopt_iphdrincl_swab_systoh(iph);
+
+ ip_len = iph->ip_len;
+
+#if !defined (GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000)
+ /*
+ * Kernel network code touches incoming IP header parameters,
+ * before protocol specific processing.
+ *
+ * 1) Convert byteorder to host representation.
+ * --> ip_len, ip_id, ip_off
+ *
+ * 2) Adjust ip_len to strip IP header size!
+ * --> If user process receives entire IP packet via RAW
+ * socket, it must consider adding IP header size to
+ * the "ip_len" field of "ip" structure.
+ *
+ * For more details, see <netinet/ip_input.c>.
+ */
+ ip_len = ip_len + (iph->ip_hl << 2);
+#endif
+
+#if defined (__DragonFly__)
+ /*
+ * in DragonFly's raw socket, ip_len/ip_off are read
+ * in network byte order.
+ * As OpenBSD < 200311 adjust ip_len to strip IP header size!
+ */
+ ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2);
+#endif
+
+ ifindex = getsockopt_ifindex(AF_INET, &msgh);
+
+ *ifp = if_lookup_by_index(ifindex);
+
+ if (ret != ip_len)
+ {
+ zlog_warn("eigrp_recv_packet read length mismatch: ip_len is %d, "
+ "but recvmsg returned %d", ip_len, ret);
+ return NULL;
+ }
+
+ return ibuf;
+}
+
+struct eigrp_fifo *
+eigrp_fifo_new (void)
+{
+ struct eigrp_fifo *new;
+
+ new = XCALLOC(MTYPE_EIGRP_FIFO, sizeof(struct eigrp_fifo));
+ return new;
+}
+
+/* Free eigrp packet fifo. */
+void
+eigrp_fifo_free (struct eigrp_fifo *fifo)
+{
+ struct eigrp_packet *ep;
+ struct eigrp_packet *next;
+
+ for (ep = fifo->head; ep; ep = next)
+ {
+ next = ep->next;
+ eigrp_packet_free(ep);
+ }
+ fifo->head = fifo->tail = NULL;
+ fifo->count = 0;
+
+ XFREE(MTYPE_EIGRP_FIFO, fifo);
+}
+
+/* Free eigrp fifo entries without destroying fifo itself*/
+void
+eigrp_fifo_reset (struct eigrp_fifo *fifo)
+{
+ struct eigrp_packet *ep;
+ struct eigrp_packet *next;
+
+ for (ep = fifo->head; ep; ep = next)
+ {
+ next = ep->next;
+ eigrp_packet_free(ep);
+ }
+ fifo->head = fifo->tail = NULL;
+ fifo->count = 0;
+}
+
+struct eigrp_packet *
+eigrp_packet_new (size_t size)
+{
+ struct eigrp_packet *new;
+
+ new = XCALLOC(MTYPE_EIGRP_PACKET, sizeof(struct eigrp_packet));
+ new->s = stream_new(size);
+ new->retrans_counter = 0;
+
+ return new;
+}
+
+void
+eigrp_send_packet_reliably (struct eigrp_neighbor *nbr)
+{
+ struct eigrp_packet *ep;
+
+ ep = eigrp_fifo_tail(nbr->retrans_queue);
+
+ if (ep)
+ {
+ struct eigrp_packet *duplicate;
+ duplicate = eigrp_packet_duplicate(ep, nbr);
+ /* Add packet to the top of the interface output queue*/
+ eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
+
+ /*Start retransmission timer*/
+ THREAD_TIMER_ON(master, ep->t_retrans_timer, eigrp_unack_packet_retrans,
+ nbr, EIGRP_PACKET_RETRANS_TIME);
+
+ /*Increment sequence number counter*/
+ nbr->ei->eigrp->sequence_number++;
+
+ /* Hook thread to write packet. */
+ if (nbr->ei->on_write_q == 0)
+ {
+ listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
+ nbr->ei->on_write_q = 1;
+ }
+ if (nbr->ei->eigrp->t_write == NULL)
+ nbr->ei->eigrp->t_write =
+ thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd);
+ }
+}
+
+/* Calculate EIGRP checksum */
+void
+eigrp_packet_checksum (struct eigrp_interface *ei, struct stream *s,
+ u_int16_t length)
+{
+ struct eigrp_header *eigrph;
+
+ eigrph = (struct eigrp_header *) STREAM_DATA(s);
+
+ /* Calculate checksum. */
+ eigrph->checksum = in_cksum(eigrph, length);
+}
+
+/* Make EIGRP header. */
+void
+eigrp_packet_header_init (int type, struct eigrp_interface *ei, struct stream *s,
+ u_int32_t flags, u_int32_t sequence, u_int32_t ack)
+{
+ struct eigrp_header *eigrph;
+
+ eigrph = (struct eigrp_header *) STREAM_DATA(s);
+
+ eigrph->version = (u_char) EIGRP_HEADER_VERSION;
+ eigrph->opcode = (u_char) type;
+ eigrph->checksum = 0;
+
+ eigrph->vrid = htons(ei->eigrp->vrid);
+ eigrph->ASNumber = htons(ei->eigrp->AS);
+ eigrph->ack = htonl(ack);
+ eigrph->sequence = htonl(sequence);
+// if(flags == EIGRP_INIT_FLAG)
+// eigrph->sequence = htonl(3);
+ eigrph->flags = htonl(flags);
+
+ if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
+ zlog_debug("Packet Header Init Seq [%u] Ack [%u]",
+ htonl(eigrph->sequence), htonl(eigrph->ack));
+
+ stream_forward_endp(s, EIGRP_HEADER_LEN);
+}
+
+/* Add new packet to head of fifo. */
+void
+eigrp_fifo_push_head (struct eigrp_fifo *fifo, struct eigrp_packet *ep)
+{
+ ep->next = fifo->head;
+ ep->previous = NULL;
+
+ if (fifo->tail == NULL)
+ fifo->tail = ep;
+
+ if (fifo->count != 0)
+ fifo->head->previous = ep;
+
+ fifo->head = ep;
+
+ fifo->count++;
+}
+
+/* Return first fifo entry. */
+struct eigrp_packet *
+eigrp_fifo_head (struct eigrp_fifo *fifo)
+{
+ return fifo->head;
+}
+
+/* Return last fifo entry. */
+struct eigrp_packet *
+eigrp_fifo_tail (struct eigrp_fifo *fifo)
+{
+ return fifo->tail;
+}
+
+void
+eigrp_packet_delete (struct eigrp_interface *ei)
+{
+ struct eigrp_packet *ep;
+
+ ep = eigrp_fifo_pop (ei->obuf);
+
+ if (ep)
+ eigrp_packet_free(ep);
+}
+
+/* Delete first packet from fifo. */
+struct eigrp_packet *
+eigrp_fifo_pop (struct eigrp_fifo *fifo)
+{
+ struct eigrp_packet *ep;
+
+ ep = fifo->head;
+
+ if (ep)
+ {
+ fifo->head = ep->next;
+
+ if (fifo->head == NULL)
+ fifo->tail = NULL;
+ else
+ fifo->head->previous = NULL;
+
+ fifo->count--;
+ }
+
+ return ep;
+}
+
+void
+eigrp_packet_free (struct eigrp_packet *ep)
+{
+ if (ep->s)
+ stream_free(ep->s);
+
+ THREAD_OFF(ep->t_retrans_timer);
+
+ XFREE(MTYPE_EIGRP_PACKET, ep);
+
+ ep = NULL;
+}
+
+/* EIGRP Header verification. */
+static int
+eigrp_verify_header (struct stream *ibuf, struct eigrp_interface *ei,
+ struct ip *iph, struct eigrp_header *eigrph)
+{
+
+ /* Check network mask, Silently discarded. */
+ if (!eigrp_check_network_mask(ei, iph->ip_src))
+ {
+ zlog_warn("interface %s: eigrp_read network address is not same [%s]",
+ IF_NAME(ei), inet_ntoa(iph->ip_src));
+ return -1;
+ }
+//
+// /* Check authentication. The function handles logging actions, where required. */
+// if (! eigrp_check_auth(ei, eigrph))
+// return -1;
+
+ return 0;
+}
+
+/* Unbound socket will accept any Raw IP packets if proto is matched.
+ To prevent it, compare src IP address and i/f address with masking
+ i/f network mask. */
+static int
+eigrp_check_network_mask (struct eigrp_interface *ei, struct in_addr ip_src)
+{
+ struct in_addr mask, me, him;
+
+ if (ei->type == EIGRP_IFTYPE_POINTOPOINT)
+ return 1;
+
+ masklen2ip(ei->address->prefixlen, &mask);
+
+ me.s_addr = ei->address->u.prefix4.s_addr & mask.s_addr;
+ him.s_addr = ip_src.s_addr & mask.s_addr;
+
+ if (IPV4_ADDR_SAME(&me, &him))
+ return 1;
+
+ return 0;
+}
+
+int
+eigrp_unack_packet_retrans (struct thread *thread)
+{
+ struct eigrp_neighbor *nbr;
+ nbr = (struct eigrp_neighbor *) THREAD_ARG(thread);
+
+ struct eigrp_packet *ep;
+ ep = eigrp_fifo_tail(nbr->retrans_queue);
+
+ if (ep)
+ {
+ struct eigrp_packet *duplicate;
+ duplicate = eigrp_packet_duplicate(ep, nbr);
+
+ /* Add packet to the top of the interface output queue*/
+ eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
+
+ ep->retrans_counter++;
+ if(ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
+ return eigrp_retrans_count_exceeded(ep, nbr);
+
+ /*Start retransmission timer*/
+ ep->t_retrans_timer =
+ thread_add_timer(master, eigrp_unack_packet_retrans, nbr,EIGRP_PACKET_RETRANS_TIME);
+
+ /* Hook thread to write packet. */
+ if (nbr->ei->on_write_q == 0)
+ {
+ listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
+ nbr->ei->on_write_q = 1;
+ }
+ if (nbr->ei->eigrp->t_write == NULL)
+ nbr->ei->eigrp->t_write =
+ thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd);
+ }
+
+ return 0;
+}
+
+int
+eigrp_unack_multicast_packet_retrans (struct thread *thread)
+{
+ struct eigrp_neighbor *nbr;
+ nbr = (struct eigrp_neighbor *) THREAD_ARG(thread);
+
+ struct eigrp_packet *ep;
+ ep = eigrp_fifo_tail(nbr->multicast_queue);
+
+ if (ep)
+ {
+ struct eigrp_packet *duplicate;
+ duplicate = eigrp_packet_duplicate(ep, nbr);
+ /* Add packet to the top of the interface output queue*/
+ eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
+
+ ep->retrans_counter++;
+ if(ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
+ return eigrp_retrans_count_exceeded(ep, nbr);
+
+ /*Start retransmission timer*/
+ ep->t_retrans_timer =
+ thread_add_timer(master, eigrp_unack_multicast_packet_retrans, nbr,EIGRP_PACKET_RETRANS_TIME);
+
+ /* Hook thread to write packet. */
+ if (nbr->ei->on_write_q == 0)
+ {
+ listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
+ nbr->ei->on_write_q = 1;
+ }
+ if (nbr->ei->eigrp->t_write == NULL)
+ nbr->ei->eigrp->t_write =
+ thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd);
+ }
+
+ return 0;
+}
+
+/* Get packet from tail of fifo. */
+struct eigrp_packet *
+eigrp_fifo_pop_tail (struct eigrp_fifo *fifo)
+{
+ struct eigrp_packet *ep;
+
+ ep = fifo->tail;
+
+ if (ep)
+ {
+ fifo->tail = ep->previous;
+
+ if (fifo->tail == NULL)
+ fifo->head = NULL;
+ else
+ fifo->tail->next = NULL;
+
+ fifo->count--;
+ }
+
+ return ep;
+}
+
+struct eigrp_packet *
+eigrp_packet_duplicate (struct eigrp_packet *old, struct eigrp_neighbor *nbr)
+{
+ struct eigrp_packet *new;
+
+ new = eigrp_packet_new(nbr->ei->ifp->mtu);
+ new->length = old->length;
+ new->retrans_counter = old->retrans_counter;
+ new->dst = old->dst;
+ new->sequence_number = old->sequence_number;
+ stream_copy(new->s, old->s);
+
+ return new;
+}
+
+struct TLV_IPv4_Internal_type *
+eigrp_read_ipv4_tlv (struct stream *s)
+{
+ struct TLV_IPv4_Internal_type *tlv;
+
+ tlv = eigrp_IPv4_InternalTLV_new ();
+
+ tlv->type = stream_getw(s);
+ tlv->length = stream_getw(s);
+ tlv->forward.s_addr = stream_getl(s);
+ tlv->metric.delay = stream_getl(s);
+ tlv->metric.bandwith = stream_getl(s);
+ tlv->metric.mtu[0] = stream_getc(s);
+ tlv->metric.mtu[1] = stream_getc(s);
+ tlv->metric.mtu[2] = stream_getc(s);
+ tlv->metric.hop_count = stream_getc(s);
+ tlv->metric.reliability = stream_getc(s);
+ tlv->metric.load = stream_getc(s);
+ tlv->metric.tag = stream_getc(s);
+ tlv->metric.flags = stream_getc(s);
+
+ tlv->prefix_length = stream_getc(s);
+
+ if (tlv->prefix_length <= 8)
+ {
+ tlv->destination_part[0] = stream_getc(s);
+ tlv->destination.s_addr = (tlv->destination_part[0]);
+
+ }
+ else if (tlv->prefix_length > 8 && tlv->prefix_length <= 16)
+ {
+ tlv->destination_part[0] = stream_getc(s);
+ tlv->destination_part[1] = stream_getc(s);
+ tlv->destination.s_addr = ((tlv->destination_part[1] << 8)
+ + tlv->destination_part[0]);
+ }
+ else if (tlv->prefix_length > 16 && tlv->prefix_length <= 24)
+ {
+ tlv->destination_part[0] = stream_getc(s);
+ tlv->destination_part[1] = stream_getc(s);
+ tlv->destination_part[2] = stream_getc(s);
+ tlv->destination.s_addr = ((tlv->destination_part[2] << 16)
+ + (tlv->destination_part[1] << 8) + tlv->destination_part[0]);
+ }
+ else if (tlv->prefix_length > 24 && tlv->prefix_length <= 32)
+ {
+ tlv->destination_part[0] = stream_getc(s);
+ tlv->destination_part[1] = stream_getc(s);
+ tlv->destination_part[2] = stream_getc(s);
+ tlv->destination_part[3] = stream_getc(s);
+ tlv->destination.s_addr = ((tlv->destination_part[3] << 24)
+ + (tlv->destination_part[2] << 16) + (tlv->destination_part[1] << 8)
+ + tlv->destination_part[0]);
+ }
+ return tlv;
+}
+
+u_int16_t
+eigrp_add_internalTLV_to_stream (struct stream *s,
+ struct eigrp_prefix_entry *pe)
+{
+ u_int16_t length;
+
+ stream_putw(s, EIGRP_TLV_IPv4_INT);
+ if (pe->destination_ipv4->prefixlen <= 8)
+ {
+ stream_putw(s, 0x001A);
+ length = 0x001A;
+ }
+ if ((pe->destination_ipv4->prefixlen > 8)
+ && (pe->destination_ipv4->prefixlen <= 16))
+ {
+ stream_putw(s, 0x001B);
+ length = 0x001B;
+ }
+ if ((pe->destination_ipv4->prefixlen > 16)
+ && (pe->destination_ipv4->prefixlen <= 24))
+ {
+ stream_putw(s, 0x001C);
+ length = 0x001C;
+ }
+ if (pe->destination_ipv4->prefixlen > 24)
+ {
+ stream_putw(s, 0x001D);
+ length = 0x001D;
+ }
+
+ stream_putl(s, 0x00000000);
+
+ /*Metric*/
+ stream_putl(s, pe->reported_metric.delay);
+ stream_putl(s, pe->reported_metric.bandwith);
+ stream_putc(s, pe->reported_metric.mtu[2]);
+ stream_putc(s, pe->reported_metric.mtu[1]);
+ stream_putc(s, pe->reported_metric.mtu[0]);
+ stream_putc(s, pe->reported_metric.hop_count);
+ stream_putc(s, pe->reported_metric.reliability);
+ stream_putc(s, pe->reported_metric.load);
+ stream_putc(s, pe->reported_metric.tag);
+ stream_putc(s, pe->reported_metric.flags);
+
+ stream_putc(s, pe->destination_ipv4->prefixlen);
+
+ if (pe->destination_ipv4->prefixlen <= 8)
+ {
+ stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
+ }
+ if ((pe->destination_ipv4->prefixlen > 8)
+ && (pe->destination_ipv4->prefixlen <= 16))
+ {
+ stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
+ stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
+ }
+ if ((pe->destination_ipv4->prefixlen > 16)
+ && (pe->destination_ipv4->prefixlen <= 24))
+ {
+ stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
+ stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
+ stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF);
+ }
+ if (pe->destination_ipv4->prefixlen > 24)
+ {
+ stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
+ stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
+ stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF);
+ stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 24) & 0xFF);
+ }
+
+ return length;
+}
+
+u_int16_t
+eigrp_add_authTLV_MD5_to_stream (struct stream *s,
+ struct eigrp_interface *ei)
+{
+ struct key *key;
+ struct keychain *keychain;
+ struct TLV_MD5_Authentication_Type *authTLV;
+
+ authTLV = eigrp_authTLV_MD5_new();
+
+ authTLV->type = htons(EIGRP_TLV_AUTH);
+ authTLV->length = htons(EIGRP_AUTH_MD5_TLV_SIZE);
+ authTLV->auth_type = htons(EIGRP_AUTH_TYPE_MD5);
+ authTLV->auth_length = htons(EIGRP_AUTH_TYPE_MD5_LEN);
+ authTLV->key_sequence = 0;
+ memset(authTLV->Nullpad,0,sizeof(authTLV->Nullpad));
+
+
+ keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
+ if(keychain)
+ key = key_lookup_for_send(keychain);
+ else
+ {
+ free(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
+ IF_DEF_PARAMS (ei->ifp)->auth_keychain = NULL;
+ eigrp_authTLV_MD5_free(authTLV);
+ return 0;
+ }
+
+ if(key)
+ {
+ authTLV->key_id = htonl(key->index);
+ memset(authTLV->digest,0,EIGRP_AUTH_TYPE_MD5_LEN);
+ stream_put(s,authTLV, sizeof(struct TLV_MD5_Authentication_Type));
+ eigrp_authTLV_MD5_free(authTLV);
+ return EIGRP_AUTH_MD5_TLV_SIZE;
+ }
+
+ eigrp_authTLV_MD5_free(authTLV);
+
+ return 0;
+}
+
+u_int16_t
+eigrp_add_authTLV_SHA256_to_stream (struct stream *s,
+ struct eigrp_interface *ei)
+{
+ struct key *key;
+ struct keychain *keychain;
+ struct TLV_SHA256_Authentication_Type *authTLV;
+
+ authTLV = eigrp_authTLV_SHA256_new();
+
+ authTLV->type = htons(EIGRP_TLV_AUTH);
+ authTLV->length = htons(EIGRP_AUTH_SHA256_TLV_SIZE);
+ authTLV->auth_type = htons(EIGRP_AUTH_TYPE_SHA256);
+ authTLV->auth_length = htons(EIGRP_AUTH_TYPE_SHA256_LEN);
+ authTLV->key_sequence = 0;
+ memset(authTLV->Nullpad,0,sizeof(authTLV->Nullpad));
+
+
+ keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
+ if(keychain)
+ key = key_lookup_for_send(keychain);
+ else
+ {
+ free(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
+ IF_DEF_PARAMS (ei->ifp)->auth_keychain = NULL;
+ eigrp_authTLV_SHA256_free(authTLV);
+ return 0;
+ }
+
+ if(key)
+ {
+ authTLV->key_id = 0;
+ memset(authTLV->digest,0,EIGRP_AUTH_TYPE_SHA256_LEN);
+ stream_put(s,authTLV, sizeof(struct TLV_SHA256_Authentication_Type));
+ eigrp_authTLV_SHA256_free(authTLV);
+ return EIGRP_AUTH_SHA256_TLV_SIZE;
+ }
+
+ eigrp_authTLV_SHA256_free(authTLV);
+
+ return 0;
+
+}
+
+struct TLV_MD5_Authentication_Type *
+eigrp_authTLV_MD5_new ()
+{
+ struct TLV_MD5_Authentication_Type *new;
+
+ new = XCALLOC(MTYPE_EIGRP_AUTH_TLV, sizeof(struct TLV_MD5_Authentication_Type));
+
+ return new;
+}
+
+void
+eigrp_authTLV_MD5_free (struct TLV_MD5_Authentication_Type *authTLV)
+{
+
+ XFREE(MTYPE_EIGRP_AUTH_TLV, authTLV);
+}
+
+struct TLV_SHA256_Authentication_Type *
+eigrp_authTLV_SHA256_new ()
+{
+ struct TLV_SHA256_Authentication_Type *new;
+
+ new = XCALLOC(MTYPE_EIGRP_AUTH_SHA256_TLV, sizeof(struct TLV_SHA256_Authentication_Type));
+
+ return new;
+}
+
+void
+eigrp_authTLV_SHA256_free (struct TLV_SHA256_Authentication_Type *authTLV)
+{
+
+ XFREE(MTYPE_EIGRP_AUTH_SHA256_TLV, authTLV);
+}
+
+
+struct TLV_IPv4_Internal_type *
+eigrp_IPv4_InternalTLV_new ()
+{
+ struct TLV_IPv4_Internal_type *new;
+
+ new = XCALLOC(MTYPE_EIGRP_IPV4_INT_TLV,sizeof(struct TLV_IPv4_Internal_type));
+
+ return new;
+}
+
+void
+eigrp_IPv4_InternalTLV_free (struct TLV_IPv4_Internal_type *IPv4_InternalTLV)
+{
+
+ XFREE(MTYPE_EIGRP_IPV4_INT_TLV, IPv4_InternalTLV);
+}
+
+struct TLV_Sequence_Type *
+eigrp_SequenceTLV_new ()
+{
+ struct TLV_Sequence_Type *new;
+
+ new = XCALLOC(MTYPE_EIGRP_SEQ_TLV,sizeof(struct TLV_Sequence_Type));
+
+ return new;
+}
diff --git a/eigrpd/eigrp_packet.h b/eigrpd/eigrp_packet.h
new file mode 100644
index 000000000..b8b281516
--- /dev/null
+++ b/eigrpd/eigrp_packet.h
@@ -0,0 +1,143 @@
+/*
+ * EIGRP General Sending and Receiving of EIGRP Packets.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_PACKET_H
+#define _ZEBRA_EIGRP_PACKET_H
+
+/*Prototypes*/
+extern int eigrp_read (struct thread *);
+extern int eigrp_write (struct thread *);
+
+extern struct eigrp_packet *eigrp_packet_new (size_t);
+extern struct eigrp_packet *eigrp_packet_duplicate (struct eigrp_packet *, struct eigrp_neighbor *);
+extern void eigrp_packet_free (struct eigrp_packet *);
+extern void eigrp_packet_delete (struct eigrp_interface *);
+extern void eigrp_packet_header_init (int, struct eigrp_interface *, struct stream *,
+ u_int32_t, u_int32_t, u_int32_t);
+extern void eigrp_packet_checksum (struct eigrp_interface *, struct stream *, u_int16_t);
+
+extern struct eigrp_fifo *eigrp_fifo_new (void);
+extern struct eigrp_packet *eigrp_fifo_head (struct eigrp_fifo *);
+extern struct eigrp_packet *eigrp_fifo_tail (struct eigrp_fifo *);
+extern struct eigrp_packet *eigrp_fifo_pop (struct eigrp_fifo *);
+extern struct eigrp_packet *eigrp_fifo_pop_tail (struct eigrp_fifo *);
+extern void eigrp_fifo_push_head (struct eigrp_fifo *, struct eigrp_packet *);
+extern void eigrp_fifo_free (struct eigrp_fifo *);
+extern void eigrp_fifo_reset (struct eigrp_fifo *);
+
+extern void eigrp_send_packet_reliably (struct eigrp_neighbor *);
+
+extern struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv (struct stream *);
+extern u_int16_t eigrp_add_internalTLV_to_stream (struct stream *, struct eigrp_prefix_entry *);
+extern u_int16_t eigrp_add_authTLV_MD5_to_stream (struct stream *, struct eigrp_interface *);
+extern u_int16_t eigrp_add_authTLV_SHA256_to_stream (struct stream *, struct eigrp_interface *);
+
+extern int eigrp_unack_packet_retrans (struct thread *);
+extern int eigrp_unack_multicast_packet_retrans (struct thread *);
+
+/*
+ * untill there is reason to have their own header, these externs are found in
+ * eigrp_hello.c
+ */
+extern void eigrp_hello_send (struct eigrp_interface *, u_char, struct in_addr *);
+extern void eigrp_hello_send_ack (struct eigrp_neighbor *);
+extern void eigrp_hello_receive (struct eigrp *, struct ip *, struct eigrp_header *,
+ struct stream *, struct eigrp_interface *, int);
+extern int eigrp_hello_timer (struct thread *);
+
+/*
+ * These externs are found in eigrp_update.c
+ */
+extern void eigrp_update_send (struct eigrp_interface *);
+extern void eigrp_update_receive (struct eigrp *, struct ip *, struct eigrp_header *,
+ struct stream *, struct eigrp_interface *, int);
+extern void eigrp_update_send_all (struct eigrp *, struct eigrp_interface *);
+extern void eigrp_update_send_init (struct eigrp_neighbor *);
+extern void eigrp_update_send_EOT (struct eigrp_neighbor *);
+extern int eigrp_update_send_GR_thread(struct thread *);
+extern void eigrp_update_send_GR (struct eigrp_neighbor *, enum GR_type, struct vty *);
+extern void eigrp_update_send_interface_GR (struct eigrp_interface *, enum GR_type, struct vty *);
+extern void eigrp_update_send_process_GR (struct eigrp *, enum GR_type, struct vty *);
+
+/*
+ * These externs are found in eigrp_query.c
+ */
+
+extern void eigrp_send_query (struct eigrp_interface *);
+extern void eigrp_query_receive (struct eigrp *, struct ip *, struct eigrp_header *,
+ struct stream *, struct eigrp_interface *, int);
+extern u_int32_t eigrp_query_send_all (struct eigrp *);
+
+/*
+ * These externs are found in eigrp_reply.c
+ */
+extern void eigrp_send_reply (struct eigrp_neighbor *, struct eigrp_prefix_entry *);
+extern void eigrp_reply_receive (struct eigrp *, struct ip *, struct eigrp_header *,
+ struct stream *, struct eigrp_interface *, int);
+
+/*
+ * These externs are found in eigrp_siaquery.c
+ */
+extern void eigrp_send_siaquery (struct eigrp_neighbor *, struct eigrp_prefix_entry *);
+extern void eigrp_siaquery_receive (struct eigrp *, struct ip *, struct eigrp_header *,
+ struct stream *, struct eigrp_interface *, int);
+
+/*
+ * These externs are found in eigrp_siareply.c
+ */
+extern void eigrp_send_siareply (struct eigrp_neighbor *, struct eigrp_prefix_entry *);
+extern void eigrp_siareply_receive (struct eigrp *, struct ip *, struct eigrp_header *,
+ struct stream *, struct eigrp_interface *, int);
+
+extern struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new (void);
+extern void eigrp_authTLV_MD5_free (struct TLV_MD5_Authentication_Type *);
+extern struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new (void);
+extern void eigrp_authTLV_SHA256_free (struct TLV_SHA256_Authentication_Type *);
+
+extern int eigrp_make_md5_digest (struct eigrp_interface *, struct stream *,
+ u_char);
+extern int eigrp_check_md5_digest (struct stream *, struct TLV_MD5_Authentication_Type *,
+ struct eigrp_neighbor *, u_char);
+extern int eigrp_make_sha256_digest (struct eigrp_interface *, struct stream *, u_char);
+extern int eigrp_check_sha256_digest (struct stream *, struct TLV_SHA256_Authentication_Type *,
+ struct eigrp_neighbor *, u_char );
+
+
+extern struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new (void);
+extern void eigrp_IPv4_InternalTLV_free (struct TLV_IPv4_Internal_type *);
+
+extern struct TLV_Sequence_Type *eigrp_SequenceTLV_new (void);
+
+extern const struct message eigrp_packet_type_str[];
+extern const size_t eigrp_packet_type_str_max;
+
+#endif /* _ZEBRA_EIGRP_PACKET_H */
diff --git a/eigrpd/eigrp_pkt_tlv1.c b/eigrpd/eigrp_pkt_tlv1.c
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/eigrpd/eigrp_pkt_tlv1.c
diff --git a/eigrpd/eigrp_pkt_tlv2.c b/eigrpd/eigrp_pkt_tlv2.c
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/eigrpd/eigrp_pkt_tlv2.c
diff --git a/eigrpd/eigrp_query.c b/eigrpd/eigrp_query.c
new file mode 100644
index 000000000..d4bd37985
--- /dev/null
+++ b/eigrpd/eigrp_query.c
@@ -0,0 +1,226 @@
+/*
+ * EIGRP Sending and Receiving EIGRP Query Packets.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
+#include "vty.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_macros.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_memory.h"
+
+u_int32_t
+eigrp_query_send_all (struct eigrp *eigrp)
+{
+ struct eigrp_interface *iface;
+ struct listnode *node, *node2, *nnode2;
+ struct eigrp_prefix_entry *pe;
+ u_int32_t counter;
+
+ if (eigrp == NULL)
+ {
+ zlog_debug("EIGRP Routing Process not enabled");
+ return 0;
+ }
+
+ counter=0;
+ for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface))
+ {
+ eigrp_send_query(iface);
+ counter++;
+ }
+
+ for (ALL_LIST_ELEMENTS(eigrp->topology_changes_internalIPV4, node2, nnode2, pe))
+ {
+ if(pe->req_action & EIGRP_FSM_NEED_QUERY)
+ {
+ pe->req_action &= ~EIGRP_FSM_NEED_QUERY;
+ listnode_delete(eigrp->topology_changes_internalIPV4, pe);
+ }
+ }
+
+ return counter;
+}
+
+/*EIGRP QUERY read function*/
+void
+eigrp_query_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
+ struct stream * s, struct eigrp_interface *ei, int size)
+{
+ struct eigrp_neighbor *nbr;
+ struct TLV_IPv4_Internal_type *tlv;
+
+ u_int16_t type;
+
+ /* increment statistics. */
+ ei->query_in++;
+
+ /* get neighbor struct */
+ nbr = eigrp_nbr_get(ei, eigrph, iph);
+
+ /* neighbor must be valid, eigrp_nbr_get creates if none existed */
+ assert(nbr);
+
+ nbr->recv_sequence_number = ntohl(eigrph->sequence);
+
+ while (s->endp > s->getp)
+ {
+ type = stream_getw(s);
+ if (type == EIGRP_TLV_IPv4_INT)
+ {
+ stream_set_getp(s, s->getp - sizeof(u_int16_t));
+
+ tlv = eigrp_read_ipv4_tlv(s);
+
+ struct prefix_ipv4 *dest_addr;
+ dest_addr = prefix_ipv4_new();
+ dest_addr->prefix = tlv->destination;
+ dest_addr->prefixlen = tlv->prefix_length;
+ struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
+ eigrp->topology_table, dest_addr);
+
+ /* If the destination exists (it should, but one never know)*/
+ if (dest != NULL)
+ {
+ struct eigrp_fsm_action_message *msg;
+ msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
+ sizeof(struct eigrp_fsm_action_message));
+ struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(
+ dest->entries, nbr);
+ msg->packet_type = EIGRP_OPC_QUERY;
+ msg->eigrp = eigrp;
+ msg->data_type = EIGRP_TLV_IPv4_INT;
+ msg->adv_router = nbr;
+ msg->data.ipv4_int_type = tlv;
+ msg->entry = entry;
+ msg->prefix = dest;
+ int event = eigrp_get_fsm_event(msg);
+ eigrp_fsm_event(msg, event);
+ }
+ eigrp_IPv4_InternalTLV_free (tlv);
+ }
+ }
+ eigrp_hello_send_ack(nbr);
+ eigrp_query_send_all(eigrp);
+ eigrp_update_send_all(eigrp,nbr->ei);
+}
+
+void
+eigrp_send_query (struct eigrp_interface *ei)
+{
+ struct eigrp_packet *ep;
+ u_int16_t length = EIGRP_HEADER_LEN;
+ struct listnode *node, *nnode, *node2, *nnode2;
+ struct eigrp_neighbor *nbr;
+ struct eigrp_prefix_entry *pe;
+ char has_tlv;
+
+ ep = eigrp_packet_new(ei->ifp->mtu);
+
+ /* Prepare EIGRP INIT UPDATE header */
+ eigrp_packet_header_init(EIGRP_OPC_QUERY, ei, ep->s, 0,
+ ei->eigrp->sequence_number, 0);
+
+ // encode Authentication TLV, if needed
+ if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+ {
+ length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei);
+ }
+
+ has_tlv = 0;
+ for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node, nnode, pe))
+ {
+ if(pe->req_action & EIGRP_FSM_NEED_QUERY)
+ {
+ length += eigrp_add_internalTLV_to_stream(ep->s, pe);
+ for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr))
+ {
+ if(nbr->state == EIGRP_NEIGHBOR_UP)
+ {
+ listnode_add(pe->rij, nbr);
+ has_tlv = 1;
+ }
+ }
+ }
+ }
+
+ if(!has_tlv)
+ {
+ eigrp_packet_free(ep);
+ return;
+ }
+
+ if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+ {
+ eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
+ }
+
+ /* EIGRP Checksum */
+ eigrp_packet_checksum(ei, ep->s, length);
+
+ ep->length = length;
+ ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS);
+
+ /*This ack number we await from neighbor*/
+ ep->sequence_number = ei->eigrp->sequence_number;
+
+ for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr))
+ {
+ if (nbr->state == EIGRP_NEIGHBOR_UP)
+ {
+ /*Put packet to retransmission queue*/
+ eigrp_fifo_push_head(nbr->retrans_queue, ep);
+
+ if (nbr->retrans_queue->count == 1)
+ {
+ eigrp_send_packet_reliably(nbr);
+ }
+ }
+ }
+}
diff --git a/eigrpd/eigrp_reply.c b/eigrpd/eigrp_reply.c
new file mode 100644
index 000000000..ff40e2e5c
--- /dev/null
+++ b/eigrpd/eigrp_reply.c
@@ -0,0 +1,249 @@
+/*
+ * EIGRP Sending and Receiving EIGRP Reply Packets.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
+#include "vty.h"
+#include "keychain.h"
+#include "plist.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_macros.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_memory.h"
+
+void
+eigrp_send_reply (struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
+{
+ struct eigrp_packet *ep;
+ u_int16_t length = EIGRP_HEADER_LEN;
+
+ struct access_list *alist;
+ struct prefix_list *plist;
+ struct access_list *alist_i;
+ struct prefix_list *plist_i;
+ struct eigrp *e;
+ struct eigrp_prefix_entry *pe2;
+
+ //TODO: Work in progress
+ /* Filtering */
+ /* get list from eigrp process */
+ e = eigrp_lookup();
+ pe2 = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY, sizeof(struct eigrp_prefix_entry));
+ memcpy(pe2,pe,sizeof(struct eigrp_prefix_entry));
+ /* Get access-lists and prefix-lists from process and interface */
+ alist = e->list[EIGRP_FILTER_OUT];
+ plist = e->prefix[EIGRP_FILTER_OUT];
+ alist_i = nbr->ei->list[EIGRP_FILTER_OUT];
+ plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT];
+ zlog_info("REPLY Send: Filtering");
+
+ zlog_info("REPLY SEND Prefix: %s", inet_ntoa(nbr->src));
+ /* Check if any list fits */
+ if ((alist && access_list_apply (alist, (struct prefix *) pe2->destination_ipv4) == FILTER_DENY)||
+ (plist && prefix_list_apply (plist, (struct prefix *) pe2->destination_ipv4) == FILTER_DENY)||
+ (alist_i && access_list_apply (alist_i, (struct prefix *) pe2->destination_ipv4) == FILTER_DENY)||
+ (plist_i && prefix_list_apply (plist_i, (struct prefix *) pe2->destination_ipv4) == FILTER_DENY))
+ {
+ zlog_info("REPLY SEND: Setting Metric to max");
+ pe2->reported_metric.delay = EIGRP_MAX_METRIC;
+
+ } else {
+ zlog_info("REPLY SEND: Not setting metric");
+ }
+
+
+ /*
+ * End of filtering
+ */
+
+ ep = eigrp_packet_new(nbr->ei->ifp->mtu);
+
+ /* Prepare EIGRP INIT UPDATE header */
+ eigrp_packet_header_init(EIGRP_OPC_REPLY, nbr->ei, ep->s, 0,
+ nbr->ei->eigrp->sequence_number, 0);
+
+ // encode Authentication TLV, if needed
+ if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+ {
+ length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
+ }
+
+
+ length += eigrp_add_internalTLV_to_stream(ep->s, pe2);
+
+ if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+ {
+ eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
+ }
+
+ /* EIGRP Checksum */
+ eigrp_packet_checksum(nbr->ei, ep->s, length);
+
+ ep->length = length;
+ ep->dst.s_addr = nbr->src.s_addr;
+
+ /*This ack number we await from neighbor*/
+ ep->sequence_number = nbr->ei->eigrp->sequence_number;
+
+ /*Put packet to retransmission queue*/
+ eigrp_fifo_push_head(nbr->retrans_queue, ep);
+
+ if (nbr->retrans_queue->count == 1)
+ {
+ eigrp_send_packet_reliably(nbr);
+ }
+}
+
+/*EIGRP REPLY read function*/
+void
+eigrp_reply_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
+ struct stream * s, struct eigrp_interface *ei, int size)
+{
+ struct eigrp_neighbor *nbr;
+ struct TLV_IPv4_Internal_type *tlv;
+
+ struct access_list *alist;
+ struct prefix_list *plist;
+ struct access_list *alist_i;
+ struct prefix_list *plist_i;
+ struct eigrp *e;
+
+ u_int16_t type;
+
+ /* increment statistics. */
+ ei->reply_in++;
+
+ /* get neighbor struct */
+ nbr = eigrp_nbr_get(ei, eigrph, iph);
+
+ /* neighbor must be valid, eigrp_nbr_get creates if none existed */
+ assert(nbr);
+
+ nbr->recv_sequence_number = ntohl(eigrph->sequence);
+
+ while (s->endp > s->getp)
+ {
+ type = stream_getw(s);
+ if (type == EIGRP_TLV_IPv4_INT)
+ {
+ stream_set_getp(s, s->getp - sizeof(u_int16_t));
+
+ tlv = eigrp_read_ipv4_tlv(s);
+
+ struct prefix_ipv4 *dest_addr;
+ dest_addr = prefix_ipv4_new();
+ dest_addr->prefix = tlv->destination;
+ dest_addr->prefixlen = tlv->prefix_length;
+ struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
+ eigrp->topology_table, dest_addr);
+ /*
+ * Destination must exists
+ */
+ assert(dest);
+
+ struct eigrp_fsm_action_message *msg;
+ msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
+ sizeof(struct eigrp_fsm_action_message));
+ struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(
+ dest->entries, nbr);
+
+ /*
+ * Filtering
+ */
+ //TODO: Work in progress
+ /* get list from eigrp process */
+ e = eigrp_lookup();
+ /* Get access-lists and prefix-lists from process and interface */
+ alist = e->list[EIGRP_FILTER_IN];
+ plist = e->prefix[EIGRP_FILTER_IN];
+ alist_i = ei->list[EIGRP_FILTER_IN];
+ plist_i = ei->prefix[EIGRP_FILTER_IN];
+ zlog_info("REPLY Receive: Filtering");
+ zlog_info("REPLY RECEIVE Prefix: %s", inet_ntoa(dest_addr->prefix));
+ /* Check if any list fits */
+ if ((alist && access_list_apply (alist,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (plist && prefix_list_apply (plist,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (alist_i && access_list_apply (alist_i,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (plist_i && prefix_list_apply (plist_i,
+ (struct prefix *) dest_addr) == FILTER_DENY))
+ {
+ zlog_info("REPLY RECEIVE: Setting metric to max");
+ tlv->metric.delay = EIGRP_MAX_METRIC;
+ zlog_info("REPLY RECEIVE Prefix: %s", inet_ntoa(dest_addr->prefix));
+ } else {
+ zlog_info("REPLY RECEIVE: Not setting metric");
+ }
+ /*
+ * End of filtering
+ */
+
+ msg->packet_type = EIGRP_OPC_REPLY;
+ msg->eigrp = eigrp;
+ msg->data_type = EIGRP_TLV_IPv4_INT;
+ msg->adv_router = nbr;
+ msg->data.ipv4_int_type = tlv;
+ msg->entry = entry;
+ msg->prefix = dest;
+ int event = eigrp_get_fsm_event(msg);
+ eigrp_fsm_event(msg, event);
+
+
+ eigrp_IPv4_InternalTLV_free (tlv);
+ }
+ }
+ eigrp_hello_send_ack(nbr);
+}
+
diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c
new file mode 100644
index 000000000..9dd5b15af
--- /dev/null
+++ b/eigrpd/eigrp_routemap.c
@@ -0,0 +1,1244 @@
+/*
+ * EIGRP Filter Functions.
+ * Copyright (C) 2013-2015
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * Note: This file contains skeleton for all possible matches and sets,
+ * but they are hidden in comment block and not properly implemented.
+ * At this time, the only function we consider useful for our use
+ * in distribute command in EIGRP is matching destination IP (with both
+ * access and prefix list).
+ *
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "prefix.h"
+#include "if_rmap.h"
+#include "routemap.h"
+#include "command.h"
+#include "filter.h"
+#include "log.h"
+#include "sockunion.h" /* for inet_aton () */
+#include "plist.h"
+
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrp_const.h"
+#include "eigrpd/eigrp_macros.h"
+#include "eigrpd/eigrp_routemap.h"
+
+void
+eigrp_if_rmap_update (struct if_rmap *if_rmap)
+{
+ struct interface *ifp;
+ struct eigrp_interface *ei, *ei2;
+ struct listnode *node, *nnode;
+ struct route_map *rmap;
+ struct eigrp *e;
+
+ ifp = if_lookup_by_name (if_rmap->ifname);
+ if (ifp == NULL)
+ return;
+
+ ei=NULL;
+ e = eigrp_lookup();
+ for (ALL_LIST_ELEMENTS (e->eiflist, node, nnode, ei2))
+ {
+ if(strcmp(ei2->ifp->name,ifp->name) == 0){
+ ei = ei2;
+ break;
+ }
+ }
+
+ if (if_rmap->routemap[IF_RMAP_IN])
+ {
+ rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
+ if (rmap)
+ ei->routemap[IF_RMAP_IN] = rmap;
+ else
+ ei->routemap[IF_RMAP_IN] = NULL;
+ }
+ else
+ ei->routemap[EIGRP_FILTER_IN] = NULL;
+
+ if (if_rmap->routemap[IF_RMAP_OUT])
+ {
+ rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
+ if (rmap)
+ ei->routemap[IF_RMAP_OUT] = rmap;
+ else
+ ei->routemap[IF_RMAP_OUT] = NULL;
+ }
+ else
+ ei->routemap[EIGRP_FILTER_OUT] = NULL;
+}
+
+void
+eigrp_if_rmap_update_interface (struct interface *ifp)
+{
+ struct if_rmap *if_rmap;
+
+ if_rmap = if_rmap_lookup (ifp->name);
+ if (if_rmap)
+ eigrp_if_rmap_update (if_rmap);
+}
+
+void
+eigrp_routemap_update_redistribute (void)
+{
+ int i;
+ struct eigrp *e;
+
+ e = eigrp_lookup();
+
+ if (e)
+ {
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (e->route_map[i].name)
+ e->route_map[i].map =
+ route_map_lookup_by_name (e->route_map[i].name);
+ }
+ }
+}
+
+/* ARGSUSED */
+void
+eigrp_rmap_update (const char *notused)
+{
+ struct interface *ifp;
+ struct listnode *node, *nnode;
+
+ for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
+ eigrp_if_rmap_update_interface (ifp);
+
+ eigrp_routemap_update_redistribute ();
+}
+
+/* Add eigrp route map rule. */
+static int
+eigrp_route_match_add (struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg)
+{
+ int ret;
+ ret = route_map_add_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Delete rip route map rule. */
+static int
+eigrp_route_match_delete (struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg)
+{
+ int ret;
+ ret = route_map_delete_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Add eigrp route map rule. */
+static int
+eigrp_route_set_add (struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg)
+{
+ int ret;
+
+ ret = route_map_add_set (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ case RMAP_COMPILE_ERROR:
+ /* rip, ripng and other protocols share the set metric command
+ but only values from 0 to 16 are valid for rip and ripng
+ if metric is out of range for rip and ripng, it is not for
+ other protocols. Do not return an error */
+ if (strcmp(command, "metric")) {
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Delete eigrp route map rule. */
+static int
+eigrp_route_set_delete (struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg)
+{
+ int ret;
+
+ ret = route_map_delete_set (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Hook function for updating route_map assignment. */
+/* ARGSUSED */
+void
+eigrp_route_map_update (const char *notused)
+{
+ int i;
+ struct eigrp *e;
+ e = eigrp_lookup();
+
+ if (e)
+ {
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (e->route_map[i].name)
+ e->route_map[i].map =
+ route_map_lookup_by_name (e->route_map[i].name);
+ }
+ }
+}
+
+
+
+/* `match metric METRIC' */
+/* Match function return 1 if match is success else return zero. */
+static route_map_result_t
+route_match_metric (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+// u_int32_t *metric;
+// u_int32_t check;
+// struct rip_info *rinfo;
+// struct eigrp_neighbor_entry *te;
+// struct eigrp_prefix_entry *pe;
+// struct listnode *node, *node2, *nnode, *nnode2;
+// struct eigrp *e;
+//
+// e = eigrp_lookup();
+//
+// if (type == RMAP_EIGRP)
+// {
+// metric = rule;
+// rinfo = object;
+//
+// /* If external metric is available, the route-map should
+// work on this one (for redistribute purpose) */
+// /*check = (rinfo->external_metric) ? rinfo->external_metric :
+// rinfo->metric;*/
+//
+// if (check == *metric)
+// return RMAP_MATCH;
+// else
+// return RMAP_NOMATCH;
+// }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `match metric' match statement. `arg' is METRIC value */
+static void *
+route_match_metric_compile (const char *arg)
+{
+// u_int32_t *metric;
+//
+// metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+// *metric = atoi (arg);
+//
+// if(*metric > 0)
+// return metric;
+//
+// XFREE (MTYPE_ROUTE_MAP_COMPILED, metric);
+ return NULL;
+}
+
+/* Free route map's compiled `match metric' value. */
+static void
+route_match_metric_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for metric matching. */
+struct route_map_rule_cmd route_match_metric_cmd =
+{
+ "metric",
+ route_match_metric,
+ route_match_metric_compile,
+ route_match_metric_free
+};
+
+/* `match interface IFNAME' */
+/* Match function return 1 if match is success else return zero. */
+static route_map_result_t
+route_match_interface (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+// struct rip_info *rinfo;
+// struct interface *ifp;
+// char *ifname;
+//
+// if (type == RMAP_EIGRP)
+// {
+// ifname = rule;
+// ifp = if_lookup_by_name(ifname);
+//
+// if (!ifp)
+// return RMAP_NOMATCH;
+//
+// rinfo = object;
+//
+// /*if (rinfo->ifindex_out == ifp->ifindex || rinfo->ifindex == ifp->ifindex)
+// return RMAP_MATCH;
+// else
+// return RMAP_NOMATCH;*/
+// }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `match interface' match statement. `arg' is IFNAME value */
+/* XXX I don`t know if I need to check does interface exist? */
+static void *
+route_match_interface_compile (const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `match interface' value. */
+static void
+route_match_interface_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for interface matching. */
+struct route_map_rule_cmd route_match_interface_cmd =
+{
+ "interface",
+ route_match_interface,
+ route_match_interface_compile,
+ route_match_interface_free
+};
+
+/* `match ip next-hop IP_ACCESS_LIST' */
+
+/* Match function return 1 if match is success else return zero. */
+static route_map_result_t
+route_match_ip_next_hop (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+// struct access_list *alist;
+// struct rip_info *rinfo;
+// struct prefix_ipv4 p;
+//
+// if (type == RMAP_EIGRP)
+// {
+// rinfo = object;
+// p.family = AF_INET;
+// /*p.prefix = (rinfo->nexthop.s_addr) ? rinfo->nexthop : rinfo->from;*/
+// p.prefixlen = IPV4_MAX_BITLEN;
+//
+// alist = access_list_lookup (AFI_IP, (char *) rule);
+// if (alist == NULL)
+// return RMAP_NOMATCH;
+//
+// return (access_list_apply (alist, &p) == FILTER_DENY ?
+// RMAP_NOMATCH : RMAP_MATCH);
+// }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `ip next-hop' match statement. `arg' should be
+ access-list name. */
+static void *
+route_match_ip_next_hop_compile (const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `. */
+static void
+route_match_ip_next_hop_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip next-hop matching. */
+static struct route_map_rule_cmd route_match_ip_next_hop_cmd =
+{
+ "ip next-hop",
+ route_match_ip_next_hop,
+ route_match_ip_next_hop_compile,
+ route_match_ip_next_hop_free
+};
+
+/* `match ip next-hop prefix-list PREFIX_LIST' */
+
+static route_map_result_t
+route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+// struct prefix_list *plist;
+// struct rip_info *rinfo;
+// struct prefix_ipv4 p;
+//
+// if (type == RMAP_EIGRP)
+// {
+// rinfo = object;
+// p.family = AF_INET;
+// /*p.prefix = (rinfo->nexthop.s_addr) ? rinfo->nexthop : rinfo->from;*/
+// p.prefixlen = IPV4_MAX_BITLEN;
+//
+// plist = prefix_list_lookup (AFI_IP, (char *) rule);
+// if (plist == NULL)
+// return RMAP_NOMATCH;
+//
+// return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
+// RMAP_NOMATCH : RMAP_MATCH);
+// }
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_ip_next_hop_prefix_list_compile (const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+static void
+route_match_ip_next_hop_prefix_list_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd =
+{
+ "ip next-hop prefix-list",
+ route_match_ip_next_hop_prefix_list,
+ route_match_ip_next_hop_prefix_list_compile,
+ route_match_ip_next_hop_prefix_list_free
+};
+
+/* `match ip address IP_ACCESS_LIST' */
+
+/* Match function should return 1 if match is success else return
+ zero. */
+static route_map_result_t
+route_match_ip_address (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct access_list *alist;
+
+ if (type == RMAP_EIGRP)
+ {
+ alist = access_list_lookup (AFI_IP, (char *) rule);
+ if (alist == NULL)
+ return RMAP_NOMATCH;
+
+ return (access_list_apply (alist, prefix) == FILTER_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `ip address' match statement. `arg' should be
+ access-list name. */
+static void *
+route_match_ip_address_compile (const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+static void
+route_match_ip_address_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+static struct route_map_rule_cmd route_match_ip_address_cmd =
+{
+ "ip address",
+ route_match_ip_address,
+ route_match_ip_address_compile,
+ route_match_ip_address_free
+};
+
+/* `match ip address prefix-list PREFIX_LIST' */
+
+static route_map_result_t
+route_match_ip_address_prefix_list (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct prefix_list *plist;
+
+ if (type == RMAP_EIGRP)
+ {
+ plist = prefix_list_lookup (AFI_IP, (char *) rule);
+ if (plist == NULL)
+ return RMAP_NOMATCH;
+
+ return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_ip_address_prefix_list_compile (const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+static void
+route_match_ip_address_prefix_list_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
+{
+ "ip address prefix-list",
+ route_match_ip_address_prefix_list,
+ route_match_ip_address_prefix_list_compile,
+ route_match_ip_address_prefix_list_free
+};
+
+/* `match tag TAG' */
+/* Match function return 1 if match is success else return zero. */
+static route_map_result_t
+route_match_tag (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+// u_short *tag;
+// struct rip_info *rinfo;
+//
+// if (type == RMAP_EIGRP)
+// {
+// tag = rule;
+// rinfo = object;
+//
+// /* The information stored by rinfo is host ordered. */
+// /*if (rinfo->tag == *tag)
+// return RMAP_MATCH;
+// else
+// return RMAP_NOMATCH;*/
+// }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `match tag' match statement. `arg' is TAG value */
+static void *
+route_match_tag_compile (const char *arg)
+{
+// u_short *tag;
+//
+// tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
+// *tag = atoi (arg);
+//
+// return tag;
+}
+
+/* Free route map's compiled `match tag' value. */
+static void
+route_match_tag_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for tag matching. */
+struct route_map_rule_cmd route_match_tag_cmd =
+{
+ "tag",
+ route_match_tag,
+ route_match_tag_compile,
+ route_match_tag_free
+};
+
+/* Set metric to attribute. */
+static route_map_result_t
+route_set_metric (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+// if (type == RMAP_RIP)
+// {
+// struct rip_metric_modifier *mod;
+// struct rip_info *rinfo;
+//
+// mod = rule;
+// rinfo = object;
+//
+// /*if (mod->type == metric_increment)
+// rinfo->metric_out += mod->metric;
+// else if (mod->type == metric_decrement)
+// rinfo->metric_out -= mod->metric;
+// else if (mod->type == metric_absolute)
+// rinfo->metric_out = mod->metric;
+//
+// if ((signed int)rinfo->metric_out < 1)
+// rinfo->metric_out = 1;
+// if (rinfo->metric_out > RIP_METRIC_INFINITY)
+// rinfo->metric_out = RIP_METRIC_INFINITY;*/
+//
+// rinfo->metric_set = 1;
+// }
+ return RMAP_OKAY;
+}
+
+/* set metric compilation. */
+static void *
+route_set_metric_compile (const char *arg)
+{
+// int len;
+// const char *pnt;
+// int type;
+// long metric;
+// char *endptr = NULL;
+// struct rip_metric_modifier *mod;
+//
+// len = strlen (arg);
+// pnt = arg;
+//
+// if (len == 0)
+// return NULL;
+//
+// /* Examine first character. */
+// if (arg[0] == '+')
+// {
+// //type = metric_increment;
+// pnt++;
+// }
+// else if (arg[0] == '-')
+// {
+// //type = metric_decrement;
+// pnt++;
+// }
+// /*else
+// type = metric_absolute;*/
+//
+// /* Check beginning with digit string. */
+// if (*pnt < '0' || *pnt > '9')
+// return NULL;
+//
+// /* Convert string to integer. */
+// metric = strtol (pnt, &endptr, 10);
+//
+// if (metric == LONG_MAX || *endptr != '\0')
+// return NULL;
+// /*if (metric < 0 || metric > RIP_METRIC_INFINITY)
+// return NULL;*/
+//
+// mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED,
+// sizeof (struct rip_metric_modifier));
+// mod->type = type;
+// mod->metric = metric;
+
+// return mod;
+}
+
+/* Free route map's compiled `set metric' value. */
+static void
+route_set_metric_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+static struct route_map_rule_cmd route_set_metric_cmd =
+{
+ "metric",
+ route_set_metric,
+ route_set_metric_compile,
+ route_set_metric_free,
+};
+
+/* `set ip next-hop IP_ADDRESS' */
+
+/* Set nexthop to object. ojbect must be pointer to struct attr. */
+static route_map_result_t
+route_set_ip_nexthop (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+// struct in_addr *address;
+// struct rip_info *rinfo;
+//
+// if(type == RMAP_RIP)
+// {
+// /* Fetch routemap's rule information. */
+// address = rule;
+// rinfo = object;
+//
+// /* Set next hop value. */
+// rinfo->nexthop_out = *address;
+// }
+
+ return RMAP_OKAY;
+}
+
+/* Route map `ip nexthop' compile function. Given string is converted
+ to struct in_addr structure. */
+static void *
+route_set_ip_nexthop_compile (const char *arg)
+{
+// int ret;
+// struct in_addr *address;
+//
+// address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr));
+//
+// ret = inet_aton (arg, address);
+//
+// if (ret == 0)
+// {
+// XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+// return NULL;
+// }
+//
+// return address;
+}
+
+/* Free route map's compiled `ip nexthop' value. */
+static void
+route_set_ip_nexthop_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set. */
+static struct route_map_rule_cmd route_set_ip_nexthop_cmd =
+{
+ "ip next-hop",
+ route_set_ip_nexthop,
+ route_set_ip_nexthop_compile,
+ route_set_ip_nexthop_free
+};
+
+/* `set tag TAG' */
+
+/* Set tag to object. ojbect must be pointer to struct attr. */
+static route_map_result_t
+route_set_tag (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+// u_short *tag;
+// struct rip_info *rinfo;
+//
+// if(type == RMAP_RIP)
+// {
+// /* Fetch routemap's rule information. */
+// tag = rule;
+// rinfo = object;
+//
+// /* Set next hop value. */
+// rinfo->tag_out = *tag;
+// }
+
+ return RMAP_OKAY;
+}
+
+/* Route map `tag' compile function. Given string is converted
+ to u_short. */
+static void *
+route_set_tag_compile (const char *arg)
+{
+// u_short *tag;
+//
+// tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
+// *tag = atoi (arg);
+//
+// return tag;
+}
+
+/* Free route map's compiled `ip nexthop' value. */
+static void
+route_set_tag_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for tag set. */
+static struct route_map_rule_cmd route_set_tag_cmd =
+{
+ "tag",
+ route_set_tag,
+ route_set_tag_compile,
+ route_set_tag_free
+};
+
+#define MATCH_STR "Match values from routing table\n"
+#define SET_STR "Set values in destination routing protocol\n"
+
+DEFUN (match_metric,
+ match_metric_cmd,
+ "match metric <0-4294967295>",
+ MATCH_STR
+ "Match metric of route\n"
+ "Metric value\n")
+{
+ return eigrp_route_match_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_match_metric,
+ no_match_metric_cmd,
+ "no match metric",
+ NO_STR
+ MATCH_STR
+ "Match metric of route\n")
+{
+ if (argc == 0)
+ return eigrp_route_match_delete (vty, vty->index, "metric", NULL);
+
+ return eigrp_route_match_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_match_metric,
+ no_match_metric_val_cmd,
+ "no match metric <0-4294967295>",
+ NO_STR
+ MATCH_STR
+ "Match metric of route\n"
+ "Metric value\n")
+
+DEFUN (match_interface,
+ match_interface_cmd,
+ "match interface WORD",
+ MATCH_STR
+ "Match first hop interface of route\n"
+ "Interface name\n")
+{
+ return eigrp_route_match_add (vty, vty->index, "interface", argv[0]);
+}
+
+DEFUN (no_match_interface,
+ no_match_interface_cmd,
+ "no match interface",
+ NO_STR
+ MATCH_STR
+ "Match first hop interface of route\n")
+{
+ if (argc == 0)
+ return eigrp_route_match_delete (vty, vty->index, "interface", NULL);
+
+ return eigrp_route_match_delete (vty, vty->index, "interface", argv[0]);
+}
+
+ALIAS (no_match_interface,
+ no_match_interface_val_cmd,
+ "no match interface WORD",
+ NO_STR
+ MATCH_STR
+ "Match first hop interface of route\n"
+ "Interface name\n")
+
+DEFUN (match_ip_next_hop,
+ match_ip_next_hop_cmd,
+ "match ip next-hop (<1-199>|<1300-2699>|WORD)",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ return eigrp_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop,
+ no_match_ip_next_hop_cmd,
+ "no match ip next-hop",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n")
+{
+ if (argc == 0)
+ return eigrp_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+
+ return eigrp_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop,
+ no_match_ip_next_hop_val_cmd,
+ "no match ip next-hop (<1-199>|<1300-2699>|WORD)",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+
+DEFUN (match_ip_next_hop_prefix_list,
+ match_ip_next_hop_prefix_list_cmd,
+ "match ip next-hop prefix-list WORD",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ return eigrp_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop_prefix_list,
+ no_match_ip_next_hop_prefix_list_cmd,
+ "no match ip next-hop prefix-list",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n")
+{
+ if (argc == 0)
+ return eigrp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL);
+
+ return eigrp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop_prefix_list,
+ no_match_ip_next_hop_prefix_list_val_cmd,
+ "no match ip next-hop prefix-list WORD",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFUN (match_ip_address,
+ match_ip_address_cmd,
+ "match ip address (<1-199>|<1300-2699>|WORD)",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+
+{
+ return eigrp_route_match_add (vty, vty->index, "ip address", argv[0]);
+}
+
+DEFUN (no_match_ip_address,
+ no_match_ip_address_cmd,
+ "no match ip address",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n")
+{
+ if (argc == 0)
+ return eigrp_route_match_delete (vty, vty->index, "ip address", NULL);
+
+ return eigrp_route_match_delete (vty, vty->index, "ip address", argv[0]);
+}
+
+ALIAS (no_match_ip_address,
+ no_match_ip_address_val_cmd,
+ "no match ip address (<1-199>|<1300-2699>|WORD)",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+
+DEFUN (match_ip_address_prefix_list,
+ match_ip_address_prefix_list_cmd,
+ "match ip address prefix-list WORD",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ return eigrp_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_address_prefix_list,
+ no_match_ip_address_prefix_list_cmd,
+ "no match ip address prefix-list",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n")
+{
+ if (argc == 0)
+ return eigrp_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
+
+ return eigrp_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_address_prefix_list,
+ no_match_ip_address_prefix_list_val_cmd,
+ "no match ip address prefix-list WORD",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFUN (match_tag,
+ match_tag_cmd,
+ "match tag <0-65535>",
+ MATCH_STR
+ "Match tag of route\n"
+ "Metric value\n")
+{
+ return eigrp_route_match_add (vty, vty->index, "tag", argv[0]);
+}
+
+DEFUN (no_match_tag,
+ no_match_tag_cmd,
+ "no match tag",
+ NO_STR
+ MATCH_STR
+ "Match tag of route\n")
+{
+ if (argc == 0)
+ return eigrp_route_match_delete (vty, vty->index, "tag", NULL);
+
+ return eigrp_route_match_delete (vty, vty->index, "tag", argv[0]);
+}
+
+ALIAS (no_match_tag,
+ no_match_tag_val_cmd,
+ "no match tag <0-65535>",
+ NO_STR
+ MATCH_STR
+ "Match tag of route\n"
+ "Metric value\n")
+
+/* set functions */
+
+DEFUN (set_metric,
+ set_metric_cmd,
+ "set metric <0-4294967295>",
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n")
+{
+ return eigrp_route_set_add (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (set_metric,
+ set_metric_addsub_cmd,
+ "set metric <+/-metric>",
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Add or subtract metric\n")
+
+DEFUN (no_set_metric,
+ no_set_metric_cmd,
+ "no set metric",
+ NO_STR
+ SET_STR
+ "Metric value for destination routing protocol\n")
+{
+ if (argc == 0)
+ return eigrp_route_set_delete (vty, vty->index, "metric", NULL);
+
+ return eigrp_route_set_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_set_metric,
+ no_set_metric_val_cmd,
+ "no set metric (<0-4294967295>|<+/-metric>)",
+ NO_STR
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n"
+ "Add or subtract metric\n")
+
+DEFUN (set_ip_nexthop,
+ set_ip_nexthop_cmd,
+ "set ip next-hop A.B.C.D",
+ SET_STR
+ IP_STR
+ "Next hop address\n"
+ "IP address of next hop\n")
+{
+ union sockunion su;
+ int ret;
+
+ ret = str2sockunion (argv[0], &su);
+ if (ret < 0)
+ {
+ vty_out (vty, "%% Malformed next-hop address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return eigrp_route_set_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_set_ip_nexthop,
+ no_set_ip_nexthop_cmd,
+ "no set ip next-hop",
+ NO_STR
+ SET_STR
+ IP_STR
+ "Next hop address\n")
+{
+ if (argc == 0)
+ return eigrp_route_set_delete (vty, vty->index, "ip next-hop", NULL);
+
+ return eigrp_route_set_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_set_ip_nexthop,
+ no_set_ip_nexthop_val_cmd,
+ "no set ip next-hop A.B.C.D",
+ NO_STR
+ SET_STR
+ IP_STR
+ "Next hop address\n"
+ "IP address of next hop\n")
+
+DEFUN (set_tag,
+ set_tag_cmd,
+ "set tag <0-65535>",
+ SET_STR
+ "Tag value for routing protocol\n"
+ "Tag value\n")
+{
+ return eigrp_route_set_add (vty, vty->index, "tag", argv[0]);
+}
+
+DEFUN (no_set_tag,
+ no_set_tag_cmd,
+ "no set tag",
+ NO_STR
+ SET_STR
+ "Tag value for routing protocol\n")
+{
+ if (argc == 0)
+ return eigrp_route_set_delete (vty, vty->index, "tag", NULL);
+
+ return eigrp_route_set_delete (vty, vty->index, "tag", argv[0]);
+}
+
+ALIAS (no_set_tag,
+ no_set_tag_val_cmd,
+ "no set tag <0-65535>",
+ NO_STR
+ SET_STR
+ "Tag value for routing protocol\n"
+ "Tag value\n")
+
+
+/* Route-map init */
+void
+eigrp_route_map_init ()
+{
+ route_map_init ();
+ route_map_init_vty ();
+ route_map_add_hook (eigrp_route_map_update);
+ route_map_delete_hook (eigrp_route_map_update);
+
+ /*route_map_install_match (&route_match_metric_cmd);
+ route_map_install_match (&route_match_interface_cmd);*/
+ /*route_map_install_match (&route_match_ip_next_hop_cmd);
+ route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
+ route_map_install_match (&route_match_ip_address_cmd);
+ route_map_install_match (&route_match_ip_address_prefix_list_cmd);*/
+ /*route_map_install_match (&route_match_tag_cmd);*/
+
+ /*route_map_install_set (&route_set_metric_cmd);
+ route_map_install_set (&route_set_ip_nexthop_cmd);
+ route_map_install_set (&route_set_tag_cmd);*/
+
+ /*install_element (RMAP_NODE, &route_match_metric_cmd);
+ install_element (RMAP_NODE, &no_match_metric_cmd);
+ install_element (RMAP_NODE, &no_match_metric_val_cmd);
+ install_element (RMAP_NODE, &route_match_interface_cmd);
+ install_element (RMAP_NODE, &no_match_interface_cmd);
+ install_element (RMAP_NODE, &no_match_interface_val_cmd);
+ install_element (RMAP_NODE, &route_match_ip_next_hop_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd);
+ install_element (RMAP_NODE, &route_match_ip_next_hop_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd);*/
+ /*install_element (RMAP_NODE, &route_match_ip_address_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_val_cmd);
+ install_element (RMAP_NODE, &route_match_ip_address_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);*/
+ /*install_element (RMAP_NODE, &route_match_tag_cmd);
+ install_element (RMAP_NODE, &no_match_tag_cmd);
+ install_element (RMAP_NODE, &no_match_tag_val_cmd);*/
+
+ /*install_element (RMAP_NODE, &set_metric_cmd);
+ install_element (RMAP_NODE, &set_metric_addsub_cmd);
+ install_element (RMAP_NODE, &no_set_metric_cmd);
+ install_element (RMAP_NODE, &no_set_metric_val_cmd);
+ install_element (RMAP_NODE, &set_ip_nexthop_cmd);
+ install_element (RMAP_NODE, &no_set_ip_nexthop_cmd);
+ install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd);
+ install_element (RMAP_NODE, &set_tag_cmd);
+ install_element (RMAP_NODE, &no_set_tag_cmd);
+ install_element (RMAP_NODE, &no_set_tag_val_cmd);*/
+}
diff --git a/eigrpd/eigrp_routemap.h b/eigrpd/eigrp_routemap.h
new file mode 100644
index 000000000..0fee25b9a
--- /dev/null
+++ b/eigrpd/eigrp_routemap.h
@@ -0,0 +1,18 @@
+/*
+ * eigrp_routemap.h
+ *
+ * Created on: Nov 19, 2015
+ * Author: root
+ */
+
+#ifndef EIGRPD_EIGRP_ROUTEMAP_H_
+#define EIGRPD_EIGRP_ROUTEMAP_H_
+
+extern void eigrp_route_map_update (const char *);
+extern void eigrp_route_map_init ();
+extern void eigrp_if_rmap_update (struct if_rmap *);
+extern void eigrp_if_rmap_update_interface (struct interface *);
+extern void eigrp_routemap_update_redistribute (void);
+extern void eigrp_rmap_update (const char *);
+
+#endif /* EIGRPD_EIGRP_ROUTEMAP_H_ */
diff --git a/eigrpd/eigrp_siaquery.c b/eigrpd/eigrp_siaquery.c
new file mode 100644
index 000000000..030a86c1c
--- /dev/null
+++ b/eigrpd/eigrp_siaquery.c
@@ -0,0 +1,164 @@
+/*
+ * EIGRP Sending and Receiving EIGRP SIA-Query Packets.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
+#include "vty.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_macros.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_memory.h"
+
+/*EIGRP SIA-QUERY read function*/
+void
+eigrp_siaquery_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
+ struct stream * s, struct eigrp_interface *ei, int size)
+{
+ struct eigrp_neighbor *nbr;
+ struct TLV_IPv4_Internal_type *tlv;
+
+ u_int16_t type;
+
+ /* increment statistics. */
+ ei->siaQuery_in++;
+
+ /* get neighbor struct */
+ nbr = eigrp_nbr_get(ei, eigrph, iph);
+
+ /* neighbor must be valid, eigrp_nbr_get creates if none existed */
+ assert(nbr);
+
+ nbr->recv_sequence_number = ntohl(eigrph->sequence);
+
+ while (s->endp > s->getp)
+ {
+ type = stream_getw(s);
+ if (type == EIGRP_TLV_IPv4_INT)
+ {
+ stream_set_getp(s, s->getp - sizeof(u_int16_t));
+
+ tlv = eigrp_read_ipv4_tlv(s);
+
+ struct prefix_ipv4 *dest_addr;
+ dest_addr = prefix_ipv4_new();
+ dest_addr->prefix = tlv->destination;
+ dest_addr->prefixlen = tlv->prefix_length;
+ struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
+ eigrp->topology_table, dest_addr);
+
+ /* If the destination exists (it should, but one never know)*/
+ if (dest != NULL)
+ {
+ struct eigrp_fsm_action_message *msg;
+ msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
+ sizeof(struct eigrp_fsm_action_message));
+ struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(
+ dest->entries, nbr);
+ msg->packet_type = EIGRP_OPC_SIAQUERY;
+ msg->eigrp = eigrp;
+ msg->data_type = EIGRP_TLV_IPv4_INT;
+ msg->adv_router = nbr;
+ msg->data.ipv4_int_type = tlv;
+ msg->entry = entry;
+ msg->prefix = dest;
+ int event = eigrp_get_fsm_event(msg);
+ eigrp_fsm_event(msg, event);
+ }
+ eigrp_IPv4_InternalTLV_free (tlv);
+ }
+ }
+ eigrp_hello_send_ack(nbr);
+}
+
+
+void
+eigrp_send_siaquery (struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
+{
+ struct eigrp_packet *ep;
+ u_int16_t length = EIGRP_HEADER_LEN;
+
+ ep = eigrp_packet_new(nbr->ei->ifp->mtu);
+
+ /* Prepare EIGRP INIT UPDATE header */
+ eigrp_packet_header_init(EIGRP_OPC_SIAQUERY, nbr->ei, ep->s, 0,
+ nbr->ei->eigrp->sequence_number, 0);
+
+ // encode Authentication TLV, if needed
+ if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+ {
+ length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
+ }
+
+ length += eigrp_add_internalTLV_to_stream(ep->s, pe);
+
+ if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+ {
+ eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
+ }
+
+ /* EIGRP Checksum */
+ eigrp_packet_checksum(nbr->ei, ep->s, length);
+
+ ep->length = length;
+ ep->dst.s_addr = nbr->src.s_addr;
+
+ /*This ack number we await from neighbor*/
+ ep->sequence_number = nbr->ei->eigrp->sequence_number;
+
+ if (nbr->state == EIGRP_NEIGHBOR_UP)
+ {
+ /*Put packet to retransmission queue*/
+ eigrp_fifo_push_head(nbr->retrans_queue, ep);
+
+ if (nbr->retrans_queue->count == 1)
+ {
+ eigrp_send_packet_reliably(nbr);
+ }
+ }
+}
diff --git a/eigrpd/eigrp_siareply.c b/eigrpd/eigrp_siareply.c
new file mode 100644
index 000000000..b49409061
--- /dev/null
+++ b/eigrpd/eigrp_siareply.c
@@ -0,0 +1,165 @@
+/*
+ * EIGRP Sending and Receiving EIGRP SIA-Reply Packets.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
+#include "vty.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_macros.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_memory.h"
+
+/*EIGRP SIA-REPLY read function*/
+void
+eigrp_siareply_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
+ struct stream * s, struct eigrp_interface *ei, int size)
+{
+ struct eigrp_neighbor *nbr;
+ struct TLV_IPv4_Internal_type *tlv;
+
+ u_int16_t type;
+
+ /* increment statistics. */
+ ei->siaReply_in++;
+
+ /* get neighbor struct */
+ nbr = eigrp_nbr_get(ei, eigrph, iph);
+
+ /* neighbor must be valid, eigrp_nbr_get creates if none existed */
+ assert(nbr);
+
+ nbr->recv_sequence_number = ntohl(eigrph->sequence);
+
+ while (s->endp > s->getp)
+ {
+ type = stream_getw(s);
+ if (type == EIGRP_TLV_IPv4_INT)
+ {
+ stream_set_getp(s, s->getp - sizeof(u_int16_t));
+
+ tlv = eigrp_read_ipv4_tlv(s);
+
+ struct prefix_ipv4 *dest_addr;
+ dest_addr = prefix_ipv4_new();
+ dest_addr->prefix = tlv->destination;
+ dest_addr->prefixlen = tlv->prefix_length;
+ struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
+ eigrp->topology_table, dest_addr);
+
+ /* If the destination exists (it should, but one never know)*/
+ if (dest != NULL)
+ {
+ struct eigrp_fsm_action_message *msg;
+ msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
+ sizeof(struct eigrp_fsm_action_message));
+ struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(
+ dest->entries, nbr);
+ msg->packet_type = EIGRP_OPC_SIAQUERY;
+ msg->eigrp = eigrp;
+ msg->data_type = EIGRP_TLV_IPv4_INT;
+ msg->adv_router = nbr;
+ msg->data.ipv4_int_type = tlv;
+ msg->entry = entry;
+ msg->prefix = dest;
+ int event = eigrp_get_fsm_event(msg);
+ eigrp_fsm_event(msg, event);
+ }
+ eigrp_IPv4_InternalTLV_free (tlv);
+ }
+ }
+ eigrp_hello_send_ack(nbr);
+}
+
+void
+eigrp_send_siareply (struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
+{
+ struct eigrp_packet *ep;
+ u_int16_t length = EIGRP_HEADER_LEN;
+
+ ep = eigrp_packet_new(nbr->ei->ifp->mtu);
+
+ /* Prepare EIGRP INIT UPDATE header */
+ eigrp_packet_header_init(EIGRP_OPC_SIAREPLY, nbr->ei, ep->s, 0,
+ nbr->ei->eigrp->sequence_number, 0);
+
+ // encode Authentication TLV, if needed
+ if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+ {
+ length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
+ }
+
+ length += eigrp_add_internalTLV_to_stream(ep->s, pe);
+
+ if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+ {
+ eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
+ }
+
+ /* EIGRP Checksum */
+ eigrp_packet_checksum(nbr->ei, ep->s, length);
+
+ ep->length = length;
+ ep->dst.s_addr = nbr->src.s_addr;
+
+ /*This ack number we await from neighbor*/
+ ep->sequence_number = nbr->ei->eigrp->sequence_number;
+
+ if (nbr->state == EIGRP_NEIGHBOR_UP)
+ {
+ /*Put packet to retransmission queue*/
+ eigrp_fifo_push_head(nbr->retrans_queue, ep);
+
+ if (nbr->retrans_queue->count == 1)
+ {
+ eigrp_send_packet_reliably(nbr);
+ }
+ }
+}
+
+
diff --git a/eigrpd/eigrp_snmp.c b/eigrpd/eigrp_snmp.c
new file mode 100644
index 000000000..f5dd69f1b
--- /dev/null
+++ b/eigrpd/eigrp_snmp.c
@@ -0,0 +1,1395 @@
+/*
+ * EIGRP SNMP Support.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_SNMP
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
+#include "keychain.h"
+#include "smux.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_snmp.h"
+
+
+struct list *eigrp_snmp_iflist;
+
+/* Declare static local variables for convenience. */
+SNMP_LOCAL_VARIABLES
+
+/* EIGRP-MIB - 1.3.6.1.4.1.9.9.449.1*/
+#define EIGRPMIB 1,3,6,1,4,1,9,9,449,1
+
+/* EIGRP-MIB instances. */
+oid eigrp_oid [] = { EIGRPMIB };
+
+/* EIGRP VPN entry */
+#define EIGRPVPNID 1
+#define EIGRPVPNNAME 2
+
+/* EIGRP Traffic statistics entry */
+#define EIGRPASNUMBER 1
+#define EIGRPNBRCOUNT 2
+#define EIGRPHELLOSSENT 3
+#define EIGRPHELLOSRCVD 4
+#define EIGRPUPDATESSENT 5
+#define EIGRPUPDATESRCVD 6
+#define EIGRPQUERIESSENT 7
+#define EIGRPQUERIESRCVD 8
+#define EIGRPREPLIESSENT 9
+#define EIGRPREPLIESRCVD 10
+#define EIGRPACKSSENT 11
+#define EIGRPACKSRCVD 12
+#define EIGRPINPUTQHIGHMARK 13
+#define EIGRPINPUTQDROPS 14
+#define EIGRPSIAQUERIESSENT 15
+#define EIGRPSIAQUERIESRCVD 16
+#define EIGRPASROUTERIDTYPE 17
+#define EIGRPASROUTERID 18
+#define EIGRPTOPOROUTES 19
+#define EIGRPHEADSERIAL 20
+#define EIGRPNEXTSERIAL 21
+#define EIGRPXMITPENDREPLIES 22
+#define EIGRPXMITDUMMIES 23
+
+/* EIGRP topology entry */
+#define EIGRPDESTNETTYPE 1
+#define EIGRPDESTNET 2
+#define EIGRPDESTNETPREFIXLEN 4
+#define EIGRPACTIVE 5
+#define EIGRPSTUCKINACTIVE 6
+#define EIGRPDESTSUCCESSORS 7
+#define EIGRPFDISTANCE 8
+#define EIGRPROUTEORIGINTYPE 9
+#define EIGRPROUTEORIGINADDRTYPE 10
+#define EIGRPROUTEORIGINADDR 11
+#define EIGRPNEXTHOPADDRESSTYPE 12
+#define EIGRPNEXTHOPADDRESS 13
+#define EIGRPNEXTHOPINTERFACE 14
+#define EIGRPDISTANCE 15
+#define EIGRPREPORTDISTANCE 16
+
+/* EIGRP peer entry */
+#define EIGRPHANDLE 1
+#define EIGRPPEERADDRTYPE 2
+#define EIGRPPEERADDR 3
+#define EIGRPPEERIFINDEX 4
+#define EIGRPHOLDTIME 5
+#define EIGRPUPTIME 6
+#define EIGRPSRTT 7
+#define EIGRPRTO 8
+#define EIGRPPKTSENQUEUED 9
+#define EIGRPLASTSEQ 10
+#define EIGRPVERSION 11
+#define EIGRPRETRANS 12
+#define EIGRPRETRIES 13
+
+/* EIGRP interface entry */
+#define EIGRPPEERCOUNT 3
+#define EIGRPXMITRELIABLEQ 4
+#define EIGRPXMITUNRELIABLEQ 5
+#define EIGRPMEANSRTT 6
+#define EIGRPPACINGRELIABLE 7
+#define EIGRPPACINGUNRELIABLE 8
+#define EIGRPMFLOWTIMER 9
+#define EIGRPPENDINGROUTES 10
+#define EIGRPHELLOINTERVAL 11
+#define EIGRPXMITNEXTSERIAL 12
+#define EIGRPUMCASTS 13
+#define EIGRPRMCASTS 14
+#define EIGRPUUCASTS 15
+#define EIGRPRUCASTS 16
+#define EIGRPMCASTEXCEPTS 17
+#define EIGRPCRPKTS 18
+#define EIGRPACKSSUPPRESSED 19
+#define EIGRPRETRANSSENT 20
+#define EIGRPOOSRCVD 21
+#define EIGRPAUTHMODE 22
+#define EIGRPAUTHKEYCHAIN 23
+
+/* SNMP value hack. */
+#define COUNTER ASN_COUNTER
+#define INTEGER ASN_INTEGER
+#define GAUGE ASN_GAUGE
+#define TIMETICKS ASN_TIMETICKS
+#define IPADDRESS ASN_IPADDRESS
+#define STRING ASN_OCTET_STR
+#define IPADDRESSPREFIXLEN ASN_INTEGER
+#define IPADDRESSTYPE ASN_INTEGER
+#define INTERFACEINDEXORZERO ASN_INTEGER
+#define UINTEGER ASN_UNSIGNED
+
+
+
+
+/* Hook functions. */
+static u_char *eigrpVpnEntry (struct variable *, oid *, size_t *,
+ int, size_t *, WriteMethod **);
+static u_char *eigrpTraffStatsEntry (struct variable *, oid *, size_t *, int,
+ size_t *, WriteMethod **);
+static u_char *eigrpTopologyEntry (struct variable *, oid *, size_t *,
+ int, size_t *, WriteMethod **);
+static u_char *eigrpPeerEntry (struct variable *, oid *, size_t *, int,
+ size_t *, WriteMethod **);
+static u_char *eigrpInterfaceEntry (struct variable *, oid *, size_t *, int,
+ size_t *, WriteMethod **);
+
+
+struct variable eigrp_variables[] =
+{
+ /* EIGRP vpn variables */
+ {EIGRPVPNID, INTEGER, NOACCESS, eigrpVpnEntry,
+ 4, {1, 1, 1, 1}},
+ {EIGRPVPNNAME, STRING, RONLY, eigrpVpnEntry,
+ 4, {1, 1, 1, 2}},
+
+ /* EIGRP traffic stats variables */
+ {EIGRPASNUMBER, UINTEGER, NOACCESS, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 1}},
+ {EIGRPNBRCOUNT, UINTEGER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 2}},
+ {EIGRPHELLOSSENT, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 3}},
+ {EIGRPHELLOSRCVD, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 4}},
+ {EIGRPUPDATESSENT, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 5}},
+ {EIGRPUPDATESRCVD, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 6}},
+ {EIGRPQUERIESSENT, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 7}},
+ {EIGRPQUERIESRCVD, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 8}},
+ {EIGRPREPLIESSENT, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 9}},
+ {EIGRPREPLIESRCVD, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 10}},
+ {EIGRPACKSSENT, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 11}},
+ {EIGRPACKSRCVD, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 12}},
+ {EIGRPINPUTQHIGHMARK, INTEGER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 13}},
+ {EIGRPINPUTQDROPS, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 14}},
+ {EIGRPSIAQUERIESSENT, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 15}},
+ {EIGRPSIAQUERIESRCVD, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 16}},
+ {EIGRPASROUTERIDTYPE, IPADDRESSTYPE, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 17}},
+ {EIGRPASROUTERID, IPADDRESS, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 18}},
+ {EIGRPTOPOROUTES, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 19}},
+ {EIGRPHEADSERIAL, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 20}},
+ {EIGRPNEXTSERIAL, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 21}},
+ {EIGRPXMITPENDREPLIES, INTEGER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 22}},
+ {EIGRPXMITDUMMIES, COUNTER, RONLY, eigrpTraffStatsEntry,
+ 4, {2, 1, 1, 23}},
+
+ /* EIGRP topology variables */
+ {EIGRPDESTNETTYPE, IPADDRESSTYPE, NOACCESS, eigrpTopologyEntry,
+ 4, {3, 1, 1, 1}},
+ {EIGRPDESTNET, IPADDRESSPREFIXLEN, NOACCESS, eigrpTopologyEntry,
+ 4, {3, 1, 1, 2}},
+ {EIGRPDESTNETPREFIXLEN, IPADDRESSTYPE, NOACCESS, eigrpTopologyEntry,
+ 4, {3, 1, 1, 4}},
+ {EIGRPACTIVE, INTEGER, RONLY, eigrpTopologyEntry,
+ 4, {3, 1, 1, 5}},
+ {EIGRPSTUCKINACTIVE, INTEGER, RONLY, eigrpTopologyEntry,
+ 4, {3, 1, 1, 6}},
+ {EIGRPDESTSUCCESSORS, INTEGER, RONLY, eigrpTopologyEntry,
+ 4, {3, 1, 1, 7}},
+ {EIGRPFDISTANCE, INTEGER, RONLY, eigrpTopologyEntry,
+ 4, {3, 1, 1, 8}},
+ {EIGRPROUTEORIGINTYPE, STRING, RONLY, eigrpTopologyEntry,
+ 4, {3, 1, 1, 9}},
+ {EIGRPROUTEORIGINADDRTYPE, IPADDRESSTYPE, RONLY, eigrpTopologyEntry,
+ 4, {3, 1, 1, 10}},
+ {EIGRPROUTEORIGINADDR, IPADDRESS, RONLY, eigrpTopologyEntry,
+ 4, {3, 1, 1, 11}},
+ {EIGRPNEXTHOPADDRESSTYPE, IPADDRESSTYPE, RONLY, eigrpTopologyEntry,
+ 4, {3, 1, 1, 12}},
+ {EIGRPNEXTHOPADDRESS, IPADDRESS, RONLY, eigrpTopologyEntry,
+ 4, {3, 1, 1, 13}},
+ {EIGRPNEXTHOPINTERFACE, STRING, RONLY, eigrpTopologyEntry,
+ 4, {3, 1, 1, 14}},
+ {EIGRPDISTANCE, INTEGER, RONLY, eigrpTopologyEntry,
+ 4, {3, 1, 1, 15}},
+ {EIGRPREPORTDISTANCE, INTEGER, RONLY, eigrpTopologyEntry,
+ 4, {3, 1, 1, 16}},
+
+ /* EIGRP peer variables */
+ {EIGRPHANDLE, INTEGER, NOACCESS, eigrpPeerEntry,
+ 4, {4, 1, 1, 1}},
+ {EIGRPPEERADDRTYPE, IPADDRESSTYPE, RONLY, eigrpPeerEntry,
+ 4, {4, 1, 1, 2}},
+ {EIGRPPEERADDR, IPADDRESS, RONLY, eigrpPeerEntry,
+ 4, {4, 1, 1, 3}},
+ {EIGRPPEERIFINDEX, INTERFACEINDEXORZERO, RONLY, eigrpPeerEntry,
+ 4, {4, 1, 1, 4}},
+ {EIGRPHOLDTIME, INTEGER, RONLY, eigrpPeerEntry,
+ 4, {4, 1, 1, 5}},
+ {EIGRPUPTIME, STRING, RONLY, eigrpPeerEntry,
+ 4, {4, 1, 1, 6}},
+ {EIGRPSRTT, INTEGER, RONLY, eigrpPeerEntry,
+ 4, {4, 1, 1, 7}},
+ {EIGRPRTO, INTEGER, RONLY, eigrpPeerEntry,
+ 4, {4, 1, 1, 8}},
+ {EIGRPPKTSENQUEUED, INTEGER, RONLY, eigrpPeerEntry,
+ 4, {4, 1, 1, 9}},
+ {EIGRPLASTSEQ, INTEGER, RONLY, eigrpPeerEntry,
+ 4, {4, 1, 1, 10}},
+ {EIGRPVERSION, STRING, RONLY, eigrpPeerEntry,
+ 4, {4, 1, 1, 11}},
+ {EIGRPRETRANS, COUNTER, RONLY, eigrpPeerEntry,
+ 4, {4, 1, 1, 12}},
+ {EIGRPRETRIES, INTEGER, RONLY, eigrpPeerEntry,
+ 4, {4, 1, 1, 13}},
+
+ /* EIGRP interface variables */
+ {EIGRPPEERCOUNT, GAUGE, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 3}},
+ {EIGRPXMITRELIABLEQ, GAUGE, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 4}},
+ {EIGRPXMITUNRELIABLEQ, GAUGE, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 5}},
+ {EIGRPMEANSRTT, INTEGER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 6}},
+ {EIGRPPACINGRELIABLE, INTEGER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 7}},
+ {EIGRPPACINGUNRELIABLE, INTEGER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 8}},
+ {EIGRPMFLOWTIMER, INTEGER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 9}},
+ {EIGRPPENDINGROUTES, GAUGE, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 10}},
+ {EIGRPHELLOINTERVAL, INTEGER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 11}},
+ {EIGRPXMITNEXTSERIAL, COUNTER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 12}},
+ {EIGRPUMCASTS, COUNTER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 13}},
+ {EIGRPRMCASTS, COUNTER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 14}},
+ {EIGRPUUCASTS, COUNTER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 15}},
+ {EIGRPRUCASTS, COUNTER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 16}},
+ {EIGRPMCASTEXCEPTS, COUNTER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 17}},
+ {EIGRPCRPKTS, COUNTER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 18}},
+ {EIGRPACKSSUPPRESSED, COUNTER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 19}},
+ {EIGRPRETRANSSENT, COUNTER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 20}},
+ {EIGRPOOSRCVD, COUNTER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 21}},
+ {EIGRPAUTHMODE, INTEGER, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 22}},
+ {EIGRPAUTHKEYCHAIN, STRING, RONLY, eigrpInterfaceEntry,
+ 4, {5, 1, 1, 23}}
+};
+
+static struct eigrp_neighbor *
+eigrp_snmp_nbr_lookup (struct eigrp *eigrp, struct in_addr *nbr_addr,
+ unsigned int *ifindex)
+{
+ struct listnode *node, *nnode, *node2, *nnode2;
+ struct eigrp_interface *ei;
+ struct eigrp_neighbor *nbr;
+
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
+ {
+ if (IPV4_ADDR_SAME (&nbr->src, nbr_addr))
+ {
+ return nbr;
+ }
+ }
+ }
+ return NULL;
+}
+
+static struct eigrp_neighbor *
+eigrp_snmp_nbr_lookup_next (struct in_addr *nbr_addr, unsigned int *ifindex,
+ int first)
+{
+ struct listnode *node, *nnode, *node2, *nnode2;
+ struct eigrp_interface *ei;
+ struct eigrp_neighbor *nbr;
+ struct route_node *rn;
+ struct eigrp_neighbor *min = NULL;
+ struct eigrp *eigrp = eigrp;
+
+ eigrp = eigrp_lookup ();
+
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
+ {
+ if (first)
+ {
+ if (! min)
+ min = nbr;
+ else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr))
+ min = nbr;
+ }
+ else if (ntohl (nbr->src.s_addr) > ntohl (nbr_addr->s_addr))
+ {
+ if (! min)
+ min = nbr;
+ else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr))
+ min = nbr;
+ }
+ }
+ }
+ if (min)
+ {
+ *nbr_addr = min->src;
+ *ifindex = 0;
+ return min;
+ }
+ return NULL;
+}
+
+static struct eigrp_neighbor *
+eigrpNbrLookup (struct variable *v, oid *name, size_t *length,
+ struct in_addr *nbr_addr, unsigned int *ifindex, int exact)
+{
+ unsigned int len;
+ int first;
+ struct eigrp_neighbor *nbr;
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+
+ if (! eigrp)
+ return NULL;
+
+ if (exact)
+ {
+ if (*length != v->namelen + IN_ADDR_SIZE + 1)
+ return NULL;
+
+ oid2in_addr (name + v->namelen, IN_ADDR_SIZE, nbr_addr);
+ *ifindex = name[v->namelen + IN_ADDR_SIZE];
+
+ return eigrp_snmp_nbr_lookup (eigrp, nbr_addr, ifindex);
+ }
+ else
+ {
+ first = 0;
+ len = *length - v->namelen;
+
+ if (len <= 0)
+ first = 1;
+
+ if (len > IN_ADDR_SIZE)
+ len = IN_ADDR_SIZE;
+
+ oid2in_addr (name + v->namelen, len, nbr_addr);
+
+ len = *length - v->namelen - IN_ADDR_SIZE;
+ if (len >= 1)
+ *ifindex = name[v->namelen + IN_ADDR_SIZE];
+
+ nbr = eigrp_snmp_nbr_lookup_next (nbr_addr, ifindex, first);
+
+ if (nbr)
+ {
+ *length = v->namelen + IN_ADDR_SIZE + 1;
+ oid_copy_addr (name + v->namelen, nbr_addr, IN_ADDR_SIZE);
+ name[v->namelen + IN_ADDR_SIZE] = *ifindex;
+ return nbr;
+ }
+ }
+ return NULL;
+}
+
+
+ static u_char *
+ eigrpVpnEntry (struct variable *v, oid *name, size_t *length,
+ int exact, size_t *var_len, WriteMethod **write_method)
+ {
+ struct eigrp *eigrp;
+
+
+ eigrp = eigrp_lookup ();
+
+ /* Check whether the instance identifier is valid */
+ if (smux_header_generic (v, name, length, exact, var_len, write_method)
+ == MATCH_FAILED)
+ return NULL;
+
+ /* Return the current value of the variable */
+ switch (v->magic)
+ {
+ case EIGRPVPNID: /* 1 */
+ /* The unique VPN identifier */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPVPNNAME: /* 2 */
+ /* The name given to the VPN */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ default:
+ return NULL;
+ }
+ return NULL;
+ }
+
+ static uint32_t
+ eigrp_neighbor_count(struct eigrp *eigrp)
+ {
+ uint32_t count;
+ struct eigrp_interface *ei;
+ struct listnode *node, *node2, *nnode2;
+ struct eigrp_neighbor *nbr;
+
+ if (eigrp == NULL)
+ {
+ return 0;
+ }
+
+ count = 0;
+ for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+ {
+ for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
+ {
+ if (nbr->state == EIGRP_NEIGHBOR_UP)
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+
+ static u_char *
+ eigrpTraffStatsEntry (struct variable *v, oid *name, size_t *length,
+ int exact, size_t *var_len, WriteMethod **write_method)
+ {
+ struct eigrp *eigrp;
+ struct eigrp_interface *ei;
+ struct listnode *node, *nnode;
+ int counter;
+
+
+ eigrp = eigrp_lookup ();
+
+ /* Check whether the instance identifier is valid */
+ if (smux_header_generic (v, name, length, exact, var_len, write_method)
+ == MATCH_FAILED)
+ return NULL;
+
+ /* Return the current value of the variable */
+ switch (v->magic)
+ {
+ case EIGRPASNUMBER: /* 1 */
+ /* AS-number of this EIGRP instance. */
+ if (eigrp)
+ return SNMP_INTEGER (eigrp->AS);
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPNBRCOUNT: /* 2 */
+ /* Neighbor count of this EIGRP instance */
+ if (eigrp)
+ return SNMP_INTEGER (eigrp_neighbor_count (eigrp));
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPHELLOSSENT: /* 3 */
+ /* Hello packets output count */
+ if (eigrp)
+ {
+ counter = 0;
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ counter += ei->hello_out;
+ }
+ return SNMP_INTEGER (counter);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPHELLOSRCVD: /* 4 */
+ /* Hello packets input count */
+ if (eigrp)
+ {
+ counter = 0;
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ counter += ei->hello_in;
+ }
+ return SNMP_INTEGER (counter);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPUPDATESSENT: /* 5 */
+ /* Update packets output count */
+ if (eigrp)
+ {
+ counter = 0;
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ counter += ei->update_out;
+ }
+ return SNMP_INTEGER (counter);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPUPDATESRCVD: /* 6 */
+ /* Update packets input count */
+ if (eigrp)
+ {
+ counter = 0;
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ counter += ei->update_in;
+ }
+ return SNMP_INTEGER (counter);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPQUERIESSENT: /* 7 */
+ /* Querry packets output count */
+ if (eigrp)
+ {
+ counter = 0;
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ counter += ei->query_out;
+ }
+ return SNMP_INTEGER (counter);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPQUERIESRCVD: /* 8 */
+ /* Querry packets input count */
+ if (eigrp)
+ {
+ counter = 0;
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ counter += ei->query_in;
+ }
+ return SNMP_INTEGER (counter);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPREPLIESSENT: /* 9 */
+ /* Reply packets output count */
+ if (eigrp)
+ {
+ counter = 0;
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ counter += ei->reply_out;
+ }
+ return SNMP_INTEGER (counter);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPREPLIESRCVD: /* 10 */
+ /* Reply packets input count */
+ if (eigrp)
+ {
+ counter = 0;
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ counter += ei->reply_in;
+ }
+ return SNMP_INTEGER (counter);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPACKSSENT: /* 11 */
+ /* Acknowledgement packets output count */
+ if (eigrp)
+ {
+ counter = 0;
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ counter += ei->ack_out;
+ }
+ return SNMP_INTEGER (counter);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPACKSRCVD: /* 12 */
+ /* Acknowledgement packets input count */
+ if (eigrp)
+ {
+ counter = 0;
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ counter += ei->ack_in;
+ }
+ return SNMP_INTEGER (counter);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPINPUTQHIGHMARK: /* 13 */
+ /* The highest number of EIGRP packets in the input queue */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPINPUTQDROPS: /* 14 */
+ /* The number of EIGRP packets dropped from the input queue */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPSIAQUERIESSENT: /* 15 */
+ /* SIA querry packets output count */
+ if (eigrp)
+ {
+ counter = 0;
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ counter += ei->siaQuery_out;
+ }
+ return SNMP_INTEGER (counter);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPSIAQUERIESRCVD: /* 16 */
+ /* SIA querry packets input count */
+ if (eigrp)
+ {
+ counter = 0;
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ counter += ei->siaQuery_in;
+ }
+ return SNMP_INTEGER (counter);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPASROUTERIDTYPE: /* 17 */
+ /* Whether the router ID is set manually or automatically */
+ if (eigrp)
+ if(eigrp->router_id_static!=0)
+ return SNMP_INTEGER(1);
+ else
+ return SNMP_INTEGER(1);
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPASROUTERID: /* 18 */
+ /* Router ID for this EIGRP AS */
+ if (eigrp)
+ if(eigrp->router_id_static!=0)
+ return SNMP_INTEGER (eigrp->router_id_static);
+ else
+ return SNMP_INTEGER (eigrp->router_id);
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPTOPOROUTES: /* 19 */
+ /* The total number of EIGRP derived routes currently existing
+ in the topology table for the AS */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPHEADSERIAL: /* 20 */
+ /* The serial number of the first route in the internal
+ sequence for an AS*/
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPNEXTSERIAL: /* 21 */
+ /* The serial number that would be assigned to the next new
+ or changed route in the topology table for the AS*/
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPXMITPENDREPLIES: /* 22 */
+ /* Total number of outstanding replies expected to queries
+ that have been sent to peers in the current AS*/
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPXMITDUMMIES: /* 23 */
+ /* Total number of currently existing dummies associated with the AS*/
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ default:
+ return NULL;
+ }
+ return NULL;
+ }
+ static u_char *
+ eigrpTopologyEntry (struct variable *v, oid *name, size_t *length,
+ int exact, size_t *var_len, WriteMethod **write_method)
+ {
+ struct eigrp *eigrp;
+ struct eigrp_interface *ei;
+ struct listnode *node, *nnode;
+
+
+ eigrp = eigrp_lookup ();
+
+ /* Check whether the instance identifier is valid */
+ if (smux_header_generic (v, name, length, exact, var_len, write_method)
+ == MATCH_FAILED)
+ return NULL;
+
+ /* Return the current value of the variable */
+ switch (v->magic)
+ {
+ case EIGRPDESTNETTYPE: /* 1 */
+ /* The format of the destination IP network number for a single
+ route in the topology table*/
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPDESTNET: /* 2 */
+ /* The destination IP network number for a single route in the topology table*/
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPDESTNETPREFIXLEN: /* 4 */
+ /* The prefix length associated with the destination IP network address
+ for a single route in the topology table in the AS*/
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPACTIVE: /* 5 */
+ /* A value of true(1) indicates the route to the destination network has failed
+ A value of false(2) indicates the route is stable (passive).*/
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPSTUCKINACTIVE: /* 6 */
+ /* A value of true(1) indicates that that this route which is in active state
+ has not received any replies to queries for alternate paths */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPDESTSUCCESSORS: /* 7 */
+ /* Next routing hop for a path to the destination IP network */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPFDISTANCE: /* 8 */
+ /* Minimum distance from this router to the destination IP network */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPROUTEORIGINTYPE: /* 9 */
+ /* Text string describing the internal origin of the EIGRP route */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPROUTEORIGINADDRTYPE: /* 10 */
+ /* The format of the IP address defined as the origin of this
+ topology route entry */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPROUTEORIGINADDR: /* 11 */
+ /* If the origin of the topology route entry is external to this router,
+ then this object is the IP address of the router from which it originated */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPNEXTHOPADDRESSTYPE: /* 12 */
+ /* The format of the next hop IP address */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPNEXTHOPADDRESS: /* 13 */
+ /* Next hop IP address for the route */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPNEXTHOPINTERFACE: /* 14 */
+ /* The interface through which the next hop IP address is reached */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPDISTANCE: /* 15 */
+ /* The computed distance to the destination network entry from this router */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPREPORTDISTANCE: /* 16 */
+ /* The computed distance to the destination network in the topology entry
+ reported to this router by the originator of this route */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ default:
+ return NULL;
+ }
+ return NULL;
+ }
+
+ static u_char *
+ eigrpPeerEntry (struct variable *v, oid *name, size_t *length,
+ int exact, size_t *var_len, WriteMethod **write_method)
+ {
+ struct eigrp *eigrp;
+ struct eigrp_interface *ei;
+ struct listnode *node, *nnode;
+ struct eigrp_neighbor *nbr;
+ struct in_addr nbr_addr;
+ unsigned int ifindex;
+
+ eigrp = eigrp_lookup ();
+
+ /* Check whether the instance identifier is valid */
+ if (smux_header_generic (v, name, length, exact, var_len, write_method)
+ == MATCH_FAILED)
+ return NULL;
+
+ memset (&nbr_addr, 0, sizeof (struct in_addr));
+ ifindex = 0;
+
+ nbr = eigrpNbrLookup (v, name, length, &nbr_addr, &ifindex, exact);
+ if (! nbr)
+ return NULL;
+ ei = nbr->ei;
+ if (! ei)
+ return NULL;
+
+ /* Return the current value of the variable */
+ switch (v->magic)
+ {
+ case EIGRPHANDLE: /* 1 */
+ /* The unique internal identifier for the peer in the AS */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPPEERADDRTYPE: /* 2 */
+ /* The format of the remote source IP address used by the peer */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPPEERADDR: /* 3 */
+ /* The source IP address used by the peer */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPPEERIFINDEX: /* 4 */
+ /* The ifIndex of the interface on this router */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPHOLDTIME: /* 5 */
+ /* How much time must pass without receiving a hello packet from this
+ EIGRP peer before this router declares the peer down */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPUPTIME: /* 6 */
+ /* The elapsed time since the EIGRP adjacency was first established */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPSRTT: /* 7 */
+ /* The computed smooth round trip time for packets to and from the peer */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPRTO: /* 8 */
+ /* The computed retransmission timeout for the peer */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPPKTSENQUEUED: /* 9 */
+ /* The number of any EIGRP packets currently enqueued */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPLASTSEQ: /* 10 */
+ /* sequence number of the last EIGRP packet sent to this peer */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPVERSION: /* 11 */
+ /* The EIGRP version information reported by the remote peer */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPRETRANS: /* 12 */
+ /* The cumulative number of retransmissions to this peer */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPRETRIES: /* 13 */
+ /* The number of times the current unacknowledged packet has been retried */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ default:
+ return NULL;
+ }
+ return NULL;
+ }
+ static u_char *
+ eigrpInterfaceEntry (struct variable *v, oid *name, size_t *length,
+ int exact, size_t *var_len, WriteMethod **write_method)
+ {
+ struct eigrp *eigrp;
+ struct eigrp_interface *ei;
+ struct listnode *node, *nnode;
+ struct keychain *keychain;
+ struct list *keylist;
+ int counter;
+
+
+ eigrp = eigrp_lookup ();
+
+ /* Check whether the instance identifier is valid */
+ if (smux_header_generic (v, name, length, exact, var_len, write_method)
+ == MATCH_FAILED)
+ return NULL;
+
+ /* Return the current value of the variable */
+ switch (v->magic)
+ {
+ case EIGRPPEERCOUNT: /* 3 */
+ /* The number of EIGRP adjacencies currently formed with
+ peers reached through this interface */
+ if (eigrp)
+ {
+ return SNMP_INTEGER (eigrp_neighbor_count (eigrp));
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPXMITRELIABLEQ: /* 4 */
+ /* The number of EIGRP packets currently waiting in the reliable
+ transport transmission queue */
+ if (eigrp)
+ {
+ return SNMP_INTEGER (1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPXMITUNRELIABLEQ: /* 5 */
+ /* The number of EIGRP packets currently waiting in the unreliable
+ transport transmission queue */
+ if (eigrp)
+ {
+ return SNMP_INTEGER (1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPMEANSRTT: /* 6 */
+ /* The average of all the computed smooth round trip time values
+ for a packet to and from all peers established on this interface */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPPACINGRELIABLE: /* 7 */
+ /* The configured time interval between EIGRP packet transmissions */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPPACINGUNRELIABLE: /* 8 */
+ /* The configured time interval between EIGRP packet transmissions
+ on the interface when the unreliable transport method is used */
+ if (eigrp)
+ {
+ return SNMP_INTEGER (1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPMFLOWTIMER: /* 9 */
+ /* The configured multicast flow control timer value */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPPENDINGROUTES: /* 10 */
+ /* The number of queued EIGRP routing updates awaiting transmission */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPHELLOINTERVAL: /* 11 */
+ /* The configured time interval between Hello packet transmissions */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPXMITNEXTSERIAL: /* 12 */
+ /* The serial number of the next EIGRP packet that is to be queued
+ for transmission */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPUMCASTS: /* 13 */
+ /* The total number of unreliable EIGRP multicast packets sent
+ on this interface */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPRMCASTS: /* 14 */
+ /* The total number of reliable EIGRP multicast packets sent
+ on this interface */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPUUCASTS: /* 15 */
+ /* The total number of unreliable EIGRP unicast packets sent
+ on this interface */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPRUCASTS: /* 16 */
+ /* The total number of reliable EIGRP unicast packets sent
+ on this interface */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPMCASTEXCEPTS: /* 17 */
+ /* The total number of EIGRP multicast exception transmissions */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPCRPKTS: /* 18 */
+ /* The total number EIGRP Conditional-Receive packets sent on this interface */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPACKSSUPPRESSED: /* 19 */
+ /* The total number of individual EIGRP acknowledgement packets that have been
+ suppressed and combined in an already enqueued outbound reliable packet on this interface */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPRETRANSSENT: /* 20 */
+ /* The total number EIGRP packet retransmissions sent on the interface */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPOOSRCVD: /* 21 */
+ /* The total number of out-of-sequence EIGRP packets received */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPAUTHMODE: /* 22 */
+ /* The EIGRP authentication mode of the interface */
+ if (eigrp)
+ {
+ return SNMP_INTEGER(1);
+ }
+ else
+ return SNMP_INTEGER (0);
+ break;
+ case EIGRPAUTHKEYCHAIN: /* 23 */
+ /* The name of the authentication key-chain configured
+ on this interface. */
+ keylist = keychain_list_get();
+ for (ALL_LIST_ELEMENTS (keylist, node, nnode, keychain))
+ {
+ return (u_char *) keychain->name;
+ }
+ if (eigrp && keychain)
+ {
+ *var_len = str_len (keychain->name);
+ return (u_char *) keychain->name;
+ }
+ else
+ return (u_char *) "TEST";
+ break;
+ default:
+ return NULL;
+ }
+ return NULL;
+ }
+
+
+ /* Register EIGRP-MIB. */
+ void
+ eigrp_snmp_init ()
+ {
+ eigrp_snmp_iflist = list_new ();
+ smux_init (eigrp_om->master);
+ REGISTER_MIB("ciscoEigrpMIB", eigrp_variables, variable, eigrp_oid);
+ }
+
+
+#endif
diff --git a/eigrpd/eigrp_snmp.h b/eigrpd/eigrp_snmp.h
new file mode 100644
index 000000000..ab14912c4
--- /dev/null
+++ b/eigrpd/eigrp_snmp.h
@@ -0,0 +1,36 @@
+/*
+ * EIGRP SNMP Support.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+
+#ifndef _ZEBRA_EIGRP_SNMP_H
+#define _ZEBRA_EIGRP_SNMP_H
+
+extern void eigrp_snmp_init (void);
+
+
+#endif /* _ZEBRA_EIGRP_SNMP_H */
diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h
new file mode 100644
index 000000000..6e90c8cba
--- /dev/null
+++ b/eigrpd/eigrp_structs.h
@@ -0,0 +1,533 @@
+/*
+ * EIGRP Definition of Data Structures.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_STRUCTS_H_
+#define _ZEBRA_EIGRP_STRUCTS_H_
+
+#include "filter.h"
+
+#include "eigrpd/eigrp_const.h"
+#include "eigrpd/eigrp_macros.h"
+
+/* EIGRP master for system wide configuration and variables. */
+struct eigrp_master
+{
+ /* EIGRP instance. */
+ struct list *eigrp;
+
+ /* EIGRP thread master. */
+ struct thread_master *master;
+
+ /* Zebra interface list. */
+ struct list *iflist;
+
+ /* EIGRP start time. */
+ time_t start_time;
+
+ /* Various EIGRP global configuration. */
+ u_char options;
+
+#define EIGRP_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */
+};
+
+struct eigrp_metrics
+{
+ u_int32_t delay;
+ u_int32_t bandwith;
+ unsigned char mtu[3];
+ u_char hop_count;
+ u_char reliability;
+ u_char load;
+ u_char tag;
+ u_char flags;
+};
+
+struct eigrp
+{
+ u_int16_t AS; /* Autonomous system number */
+ u_int16_t vrid; /* Virtual Router ID */
+ u_char k_values[6]; /*Array for K values configuration*/
+ u_char variance; /*Metric variance multiplier*/
+ u_char max_paths; /*Maximum allowed paths for 1 prefix*/
+
+ /*Name of this EIGRP instance*/
+ char *name;
+
+ /* EIGRP Router ID. */
+ u_int32_t router_id; /* Configured automatically. */
+ u_int32_t router_id_static; /* Configured manually. */
+
+ struct list *eiflist; /* eigrp interfaces */
+ u_char passive_interface_default; /* passive-interface default */
+
+ unsigned int fd;
+ unsigned int maxsndbuflen;
+
+ u_int32_t sequence_number; /*Global EIGRP sequence number*/
+
+ struct stream *ibuf;
+ struct list *oi_write_q;
+
+ /*Threads*/
+ struct thread *t_write;
+ struct thread *t_read;
+ struct thread *t_distribute; /* timer for distribute list */
+
+ struct route_table *networks; /* EIGRP config networks. */
+
+ struct list *topology_table;
+
+ u_int64_t serno; /* Global serial number counter for topology entry changes*/
+ u_int64_t serno_last_update; /* Highest serial number of information send by last update*/
+ struct list *topology_changes_internalIPV4;
+ struct list *topology_changes_externalIPV4;
+
+ /*Neighbor self*/
+ struct eigrp_neighbor *neighbor_self;
+
+ /*Configured metric for redistributed routes*/
+ struct eigrp_metrics dmetric[ZEBRA_ROUTE_MAX + 1];
+ int redistribute; /* Num of redistributed protocols. */
+
+ /* Access-list. */
+ struct access_list *list[EIGRP_FILTER_MAX];
+ /* Prefix-list. */
+ struct prefix_list *prefix[EIGRP_FILTER_MAX];
+ /* Route-map. */
+ struct route_map *routemap[EIGRP_FILTER_MAX];
+
+ /* For redistribute route map. */
+ struct
+ {
+ char *name;
+ struct route_map *map;
+ int metric_config;
+ u_int32_t metric;
+ } route_map[ZEBRA_ROUTE_MAX];
+
+ QOBJ_FIELDS
+};
+DECLARE_QOBJ_TYPE(eigrp)
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+/*EIGRP interface structure*/
+struct eigrp_interface
+{
+ /* This interface's parent eigrp instance. */
+ struct eigrp *eigrp;
+
+ /* Interface data from zebra. */
+ struct interface *ifp;
+
+ /* Packet send buffer. */
+ struct eigrp_fifo *obuf; /* Output queue */
+
+ /* To which multicast groups do we currently belong? */
+
+ /* Configured varables. */
+ struct eigrp_if_params *params;
+
+ u_char multicast_memberships;
+
+ /* EIGRP Network Type. */
+ u_char type;
+
+ struct prefix *address; /* Interface prefix */
+ struct connected *connected; /* Pointer to connected */
+
+ /* Neighbor information. */
+ struct list *nbrs; /* EIGRP Neighbor List */
+
+ /* Threads. */
+ struct thread *t_hello; /* timer */
+ struct thread *t_distribute; /* timer for distribute list */
+
+ int on_write_q;
+
+ /* Statistics fields. */
+ u_int32_t hello_in; /* Hello message input count. */
+ u_int32_t update_in; /* Update message input count. */
+ u_int32_t query_in; /* Querry message input count. */
+ u_int32_t reply_in; /* Reply message input count. */
+ u_int32_t hello_out; /* Hello message output count. */
+ u_int32_t update_out; /* Update message output count. */
+ u_int32_t query_out; /* Query message output count. */
+ u_int32_t reply_out; /* Reply message output count. */
+ u_int32_t siaQuery_in;
+ u_int32_t siaQuery_out;
+ u_int32_t siaReply_in;
+ u_int32_t siaReply_out;
+ u_int32_t ack_out;
+ u_int32_t ack_in;
+
+ u_int32_t crypt_seqnum; /* Cryptographic Sequence Number */
+
+ /* Access-list. */
+ struct access_list *list[EIGRP_FILTER_MAX];
+ /* Prefix-list. */
+ struct prefix_list *prefix[EIGRP_FILTER_MAX];
+ /* Route-map. */
+ struct route_map *routemap[EIGRP_FILTER_MAX];
+};
+
+struct eigrp_if_params
+{
+ DECLARE_IF_PARAM (u_char, passive_interface); /* EIGRP Interface is passive: no sending or receiving (no need to join multicast groups) */
+ DECLARE_IF_PARAM (u_int32_t, v_hello); /* Hello Interval */
+ DECLARE_IF_PARAM (u_int16_t, v_wait); /* Router Hold Time Interval */
+ DECLARE_IF_PARAM (u_char, type); /* type of interface */
+ DECLARE_IF_PARAM (u_int32_t, bandwidth);
+ DECLARE_IF_PARAM (u_int32_t, delay);
+ DECLARE_IF_PARAM (u_char, reliability);
+ DECLARE_IF_PARAM (u_char, load);
+
+ DECLARE_IF_PARAM (char *, auth_keychain ); /* Associated keychain with interface*/
+ DECLARE_IF_PARAM (int, auth_type); /* EIGRP authentication type */
+};
+
+enum
+{
+ MEMBER_ALLROUTERS = 0, MEMBER_MAX,
+};
+
+struct eigrp_if_info
+{
+ struct eigrp_if_params *def_params;
+ struct route_table *params;
+ struct route_table *eifs;
+ unsigned int membership_counts[MEMBER_MAX]; /* multicast group refcnts */
+};
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+
+/* Determines if it is first or last packet
+ * when packet consists of multiple packet
+ * chunks because of many route TLV
+ * (all won't fit into one packet) */
+enum Packet_part_type
+{
+ EIGRP_PACKET_PART_NA,
+ EIGRP_PACKET_PART_FIRST,
+ EIGRP_PACKET_PART_LAST
+};
+
+/* Neighbor Data Structure */
+struct eigrp_neighbor
+{
+ /* This neighbor's parent eigrp interface. */
+ struct eigrp_interface *ei;
+
+ /* EIGRP neighbor Information */
+ u_char state; /* neigbor status. */
+
+ u_int32_t recv_sequence_number; /* Last received sequence Number. */
+ u_int32_t init_sequence_number;
+
+ /*If packet is unacknowledged, we try to send it again 16 times*/
+ u_char retrans_counter;
+
+ struct in_addr src; /* Neighbor Src address. */
+
+ u_char os_rel_major; // system version - just for show
+ u_char os_rel_minor; // system version - just for show
+ u_char tlv_rel_major; // eigrp version - tells us what TLV format to use
+ u_char tlv_rel_minor; // eigrp version - tells us what TLV format to use
+
+ u_char K1;
+ u_char K2;
+ u_char K3;
+ u_char K4;
+ u_char K5;
+ u_char K6;
+
+ /* Timer values. */
+ u_int16_t v_holddown;
+
+ /* Threads. */
+ struct thread *t_holddown;
+ struct thread *t_nbr_send_gr; /* thread for sending multiple GR packet chunks */
+
+ struct eigrp_fifo *retrans_queue;
+ struct eigrp_fifo *multicast_queue;
+
+ u_int32_t crypt_seqnum; /* Cryptographic Sequence Number. */
+
+ /* prefixes not received from neighbor during Graceful restart */
+ struct list *nbr_gr_prefixes;
+ /* prefixes not yet send to neighbor during Graceful restart */
+ struct list *nbr_gr_prefixes_send;
+ /* if packet is first or last during Graceful restart */
+ enum Packet_part_type nbr_gr_packet_type;
+};
+
+//---------------------------------------------------------------------------------------------------------------------------------------------
+
+
+struct eigrp_packet
+{
+ struct eigrp_packet *next;
+ struct eigrp_packet *previous;
+
+ /* Pointer to data stream. */
+ struct stream *s;
+
+ /* IP destination address. */
+ struct in_addr dst;
+
+ /*Packet retransmission thread*/
+ struct thread *t_retrans_timer;
+
+ /*Packet retransmission counter*/
+ u_char retrans_counter;
+
+ u_int32_t sequence_number;
+
+ /* EIGRP packet length. */
+ u_int16_t length;
+};
+
+struct eigrp_fifo
+{
+ struct eigrp_packet *head;
+ struct eigrp_packet *tail;
+
+ unsigned long count;
+};
+
+struct eigrp_header
+{
+ u_char version;
+ u_char opcode;
+ u_int16_t checksum;
+ u_int32_t flags;
+ u_int32_t sequence;
+ u_int32_t ack;
+ u_int16_t vrid;
+ u_int16_t ASNumber;
+ char *tlv[0];
+
+}__attribute__((packed));
+
+
+/**
+ * Generic TLV type used for packet decoding.
+ *
+ * +-----+------------------+
+ * | | | |
+ * | Type| Len | Vector |
+ * | | | |
+ * +-----+------------------+
+ */
+struct eigrp_tlv_hdr_type
+{
+ u_int16_t type;
+ u_int16_t length;
+ uint8_t value[0];
+}__attribute__((packed));
+
+struct TLV_Parameter_Type
+{
+ u_int16_t type;
+ u_int16_t length;
+ u_char K1;
+ u_char K2;
+ u_char K3;
+ u_char K4;
+ u_char K5;
+ u_char K6;
+ u_int16_t hold_time;
+}__attribute__((packed));
+
+struct TLV_MD5_Authentication_Type
+{
+ u_int16_t type;
+ u_int16_t length;
+ u_int16_t auth_type;
+ u_int16_t auth_length;
+ u_int32_t key_id;
+ u_int32_t key_sequence;
+ u_char Nullpad[8];
+ u_char digest[EIGRP_AUTH_TYPE_MD5_LEN];
+
+}__attribute__((packed));
+
+struct TLV_SHA256_Authentication_Type
+{
+ u_int16_t type;
+ u_int16_t length;
+ u_int16_t auth_type;
+ u_int16_t auth_length;
+ u_int32_t key_id;
+ u_int32_t key_sequence;
+ u_char Nullpad[8];
+ u_char digest[EIGRP_AUTH_TYPE_SHA256_LEN];
+
+}__attribute__((packed));
+
+struct TLV_Sequence_Type
+{
+ u_int16_t type;
+ u_int16_t length;
+ u_char addr_length;
+ struct in_addr *addresses;
+}__attribute__((packed));
+
+struct TLV_Next_Multicast_Sequence
+{
+ u_int16_t type;
+ u_int16_t length;
+ u_int32_t multicast_sequence;
+}__attribute__((packed));
+
+struct TLV_Software_Type
+{
+ u_int16_t type;
+ u_int16_t length;
+ u_char vender_major;
+ u_char vender_minor;
+ u_char eigrp_major;
+ u_char eigrp_minor;
+}__attribute__((packed));
+
+struct TLV_IPv4_Internal_type
+{
+ u_int16_t type;
+ u_int16_t length;
+ struct in_addr forward;
+
+ /*Metrics*/
+ struct eigrp_metrics metric;
+
+ u_char prefix_length;
+
+ unsigned char destination_part[4];
+ struct in_addr destination;
+}__attribute__((packed));
+
+struct TLV_IPv4_External_type
+{
+ u_int16_t type;
+ u_int16_t length;
+ struct in_addr next_hop;
+ struct in_addr originating_router;
+ u_int32_t originating_as;
+ u_int32_t administrative_tag;
+ u_int32_t external_metric;
+ u_int16_t reserved;
+ u_char external_protocol;
+ u_char external_flags;
+
+ /*Metrics*/
+ struct eigrp_metrics metric;
+
+ u_char prefix_length;
+ unsigned char destination_part[4];
+ struct in_addr destination;
+}__attribute__((packed));
+
+/* EIGRP Peer Termination TLV - used for hard restart */
+struct TLV_Peer_Termination_type
+{
+ u_int16_t type;
+ u_int16_t length;
+ u_char unknown;
+ u_int32_t neighbor_ip;
+} __attribute__((packed));
+
+/* Who executed Graceful restart */
+enum GR_type
+{
+ EIGRP_GR_MANUAL,
+ EIGRP_GR_FILTER
+};
+
+//---------------------------------------------------------------------------------------------------------------------------------------------
+
+/* EIGRP Topology table node structure */
+struct eigrp_prefix_entry
+{
+ struct list *entries, *rij;
+ u_int32_t fdistance; // FD
+ u_int32_t rdistance; // RD
+ u_int32_t distance; // D
+ struct eigrp_metrics reported_metric; // RD for sending
+
+ u_char nt; //network type
+ u_char state; //route fsm state
+ u_char af; // address family
+ u_char req_action; // required action
+
+ struct prefix_ipv4 *destination_ipv4; // pointer to struct with ipv4 address
+ struct prefix_ipv6 *destination_ipv6; // pointer to struct with ipv6 address
+
+ //If network type is REMOTE_EXTERNAL, pointer will have reference to its external TLV
+ struct TLV_IPv4_External_type *extTLV;
+
+ u_int64_t serno; /*Serial number for this entry. Increased with each change of entry*/
+};
+
+/* EIGRP Topology table record structure */
+struct eigrp_neighbor_entry
+{
+ struct eigrp_prefix_entry *prefix;
+ u_int32_t reported_distance; //distance reported by neighbor
+ u_int32_t distance; //sum of reported distance and link cost to advertised neighbor
+
+ struct eigrp_metrics reported_metric;
+ struct eigrp_metrics total_metric;
+
+ struct eigrp_neighbor *adv_router; //ip address of advertising neighbor
+ u_char flags; //used for marking successor and FS
+
+ struct eigrp_interface *ei; //pointer for case of connected entry
+
+};
+
+//---------------------------------------------------------------------------------------------------------------------------------------------
+
+/* EIGRP Finite State Machine */
+
+struct eigrp_fsm_action_message
+{
+ u_char packet_type; //UPDATE, QUERY, SIAQUERY, SIAREPLY
+ struct eigrp *eigrp; // which thread sent mesg
+ struct eigrp_neighbor *adv_router; //advertising neighbor
+ struct eigrp_neighbor_entry *entry;
+ struct eigrp_prefix_entry *prefix;
+ int data_type; // internal or external tlv type
+ union{
+ struct TLV_IPv4_External_type *ipv4_ext_data;
+ struct TLV_IPv4_Internal_type *ipv4_int_type;
+ }data;
+};
+
+#endif /* _ZEBRA_EIGRP_STRUCTURES_H_ */
diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c
new file mode 100644
index 000000000..c8b53515b
--- /dev/null
+++ b/eigrpd/eigrp_topology.c
@@ -0,0 +1,586 @@
+/*
+ * EIGRP Topology Table.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "log.h"
+#include "linklist.h"
+#include "vty.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_memory.h"
+
+static int
+eigrp_prefix_entry_cmp(struct eigrp_prefix_entry *, struct eigrp_prefix_entry *);
+static void
+eigrp_prefix_entry_del(struct eigrp_prefix_entry *);
+static int
+eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *,
+ struct eigrp_neighbor_entry *);
+
+/*
+ * asdf;laksdjf;lajsdf;kasdjf;asdjf;
+ * asdfaskdjfa;sdkjf;adlskj
+ * Returns linkedlist used as topology table
+ * cmp - assigned function for comparing topology nodes
+ * del - assigned function executed before deleting topology node by list function
+ */
+struct list *
+eigrp_topology_new()
+{
+ struct list* new = list_new();
+ new->cmp = (int
+ (*)(void *, void *)) eigrp_prefix_entry_cmp;
+ new->del = (void
+ (*)(void *)) eigrp_prefix_entry_del;
+
+ return new;
+}
+
+/*
+ * Topology node comparison
+ */
+
+static int
+eigrp_prefix_entry_cmp(struct eigrp_prefix_entry *node1,
+ struct eigrp_prefix_entry *node2)
+{
+ if (node1->af == AF_INET)
+ {
+ if (node2->af == AF_INET)
+ {
+ if (node1->destination_ipv4->prefix.s_addr
+ < node2->destination_ipv4->prefix.s_addr)
+ {
+ return -1; // if it belong above node2
+ }
+ else
+ {
+ if (node1->destination_ipv4->prefix.s_addr
+ > node2->destination_ipv4->prefix.s_addr)
+ {
+ return 1; //if it belongs under node2
+ }
+ else
+ {
+ return 0; // same value... ERROR...in case of adding same prefix again
+ }
+ }
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ else
+ { // TODO check if the prefix dont exists
+ return 1; // add to end
+ }
+}
+
+/*
+ * Topology node delete
+ */
+
+static void
+eigrp_prefix_entry_del(struct eigrp_prefix_entry *node)
+{
+ list_delete_all_node(node->entries);
+ list_free(node->entries);
+}
+
+/*
+ * Returns new created toplogy node
+ * cmp - assigned function for comparing topology entry
+ */
+
+struct eigrp_prefix_entry *
+eigrp_prefix_entry_new()
+{
+ struct eigrp_prefix_entry *new;
+ new = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY, sizeof(struct eigrp_prefix_entry));
+ new->entries = list_new();
+ new->rij = list_new();
+ new->entries->cmp = (int
+ (*)(void *, void *)) eigrp_neighbor_entry_cmp;
+ new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC;
+ new->destination_ipv4 = NULL;
+ new->destination_ipv6 = NULL;
+
+ return new;
+}
+
+/*
+ * Topology entry comparison
+ */
+
+static int
+eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *entry1,
+ struct eigrp_neighbor_entry *entry2)
+{
+ if (entry1->distance < entry2->distance) // parameter used in list_add_sort ()
+ return -1; // actually set to sort by distance
+ if (entry1->distance > entry2->distance)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Returns new topology entry
+ */
+
+struct eigrp_neighbor_entry *
+eigrp_neighbor_entry_new()
+{
+ struct eigrp_neighbor_entry *new;
+
+ new = XCALLOC(MTYPE_EIGRP_NEIGHBOR_ENTRY,
+ sizeof(struct eigrp_neighbor_entry));
+ new->reported_distance = EIGRP_MAX_METRIC;
+ new->distance = EIGRP_MAX_METRIC;
+
+ return new;
+}
+
+/*
+ * Freeing topology table list
+ */
+
+void
+eigrp_topology_free(struct list *list)
+{
+ list_free(list);
+}
+
+/*
+ * Deleting all topology nodes in table
+ */
+
+void
+eigrp_topology_cleanup(struct list *topology)
+{
+ assert(topology);
+
+ eigrp_topology_delete_all(topology);
+}
+
+/*
+ * Adding topology node to topology table
+ */
+
+void
+eigrp_prefix_entry_add(struct list *topology, struct eigrp_prefix_entry *node)
+{
+ if (listnode_lookup(topology, node) == NULL)
+ {
+ listnode_add_sort(topology, node);
+ }
+}
+
+/*
+ * Adding topology entry to topology node
+ */
+
+void
+eigrp_neighbor_entry_add(struct eigrp_prefix_entry *node,
+ struct eigrp_neighbor_entry *entry)
+{
+ if (listnode_lookup(node->entries, entry) == NULL)
+ {
+ listnode_add_sort(node->entries, entry);
+ entry->prefix = node;
+ }
+}
+
+/*
+ * Deleting topology node from topology table
+ */
+
+void
+eigrp_prefix_entry_delete(struct list *topology,
+ struct eigrp_prefix_entry *node)
+{
+ if (listnode_lookup(topology, node) != NULL)
+ {
+ list_delete_all_node(node->entries);
+ list_free(node->entries);
+ list_free(node->rij);
+ listnode_delete(topology, node);
+ XFREE(MTYPE_EIGRP_PREFIX_ENTRY,node);
+ }
+}
+
+/*
+ * Deleting topology entry from topology node
+ */
+
+void
+eigrp_neighbor_entry_delete(struct eigrp_prefix_entry *node,
+ struct eigrp_neighbor_entry *entry)
+{
+ if (listnode_lookup(node->entries, entry) != NULL)
+ {
+ listnode_delete(node->entries, entry);
+ XFREE(MTYPE_EIGRP_NEIGHBOR_ENTRY,entry);
+ }
+}
+
+/*
+ * Deleting all nodes from topology table
+ */
+
+void
+eigrp_topology_delete_all(struct list *topology)
+{
+ list_delete_all_node(topology);
+}
+
+/*
+ * Return 0 if topology is not empty
+ * otherwise return 1
+ */
+
+unsigned int
+eigrp_topology_table_isempty(struct list *topology)
+{
+ if (topology->count)
+ return 1;
+ else
+ return 0;
+}
+
+struct eigrp_prefix_entry *
+eigrp_topology_table_lookup_ipv4(struct list *topology_table,
+ struct prefix_ipv4 * address)
+{
+ struct eigrp_prefix_entry *data;
+ struct listnode *node;
+ for (ALL_LIST_ELEMENTS_RO(topology_table, node, data))
+ {
+
+ if ((data->af == AF_INET)
+ && (data->destination_ipv4->prefix.s_addr == address->prefix.s_addr)
+ && (data->destination_ipv4->prefixlen == address->prefixlen))
+ return data;
+ }
+
+ return NULL;
+}
+/* TODO
+ struct eigrp_prefix_entry *
+ eigrp_topology_table_lookup_ipv6 (struct list *topology_table,
+ struct prefix_ipv6 * address)
+ {
+ struct eigrp_prefix_entry *data;
+ struct listnode *node, *nnode;
+ for (ALL_LIST_ELEMENTS (topology_table, node, nnode, data))
+ {
+
+ if (comparison)
+ return data;
+ }
+
+ return NULL;
+ }
+ */
+struct list *
+eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node)
+{
+ struct list *successors = list_new();
+ ;
+ struct eigrp_neighbor_entry *data;
+ struct listnode *node1, *node2;
+ for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data))
+ {
+ if (data->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)
+ {
+ listnode_add(successors, data);
+ }
+ }
+
+ return successors;
+}
+
+/*extern struct eigrp_neighbor_entry *
+ eigrp_topology_get_fsuccessor (struct eigrp_prefix_entry *table_node)
+ {
+ struct eigrp_neighbor_entry *data;
+ struct listnode *node, *nnode;
+ for (ALL_LIST_ELEMENTS (table_node->entries, node, nnode, data))
+ {
+ if ((data->flags & EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG) == 1)
+ {
+ return data;
+ }
+ }
+
+ return NULL;
+ }*/
+
+struct eigrp_neighbor_entry *
+eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *nbr)
+{
+ struct eigrp_neighbor_entry *data;
+ struct listnode *node, *nnode;
+ for (ALL_LIST_ELEMENTS(entries, node, nnode, data))
+ {
+ if (data->adv_router == nbr)
+ {
+ return data;
+ }
+ }
+
+ return NULL;
+}
+
+/* Lookup all prefixes from specified neighbor */
+struct list *
+eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp, struct eigrp_neighbor *nbr)
+{
+ struct listnode *node1, *node11, *node2, *node22;
+ struct eigrp_prefix_entry *prefix;
+ struct eigrp_neighbor_entry *entry;
+
+ /* create new empty list for prefixes storage */
+ struct list *prefixes = list_new();
+
+ /* iterate over all prefixes in topology table */
+ for (ALL_LIST_ELEMENTS(eigrp->topology_table, node1, node11, prefix))
+ {
+ /* iterate over all neighbor entry in prefix */
+ for (ALL_LIST_ELEMENTS(prefix->entries, node2, node22, entry))
+ {
+ /* if entry is from specified neighbor, add to list */
+ if (entry->adv_router == nbr)
+ {
+ listnode_add(prefixes, prefix);
+ }
+ }
+ }
+
+ /* return list of prefixes from specified neighbor */
+ return prefixes;
+}
+
+int
+eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg)
+{
+ struct eigrp *eigrp = msg->eigrp;
+ struct eigrp_prefix_entry *prefix = msg->prefix;
+ struct eigrp_neighbor_entry *entry = msg->entry;
+ int change = 0;
+ assert(entry);
+
+ struct TLV_IPv4_External_type *ext_data = NULL;
+ struct TLV_IPv4_Internal_type *int_data = NULL;
+ if (msg->data_type == EIGRP_TLV_IPv4_INT)
+ {
+ int_data = msg->data.ipv4_int_type;
+ if (eigrp_metrics_is_same(&int_data->metric,&entry->reported_metric))
+ {
+ return 0; // No change
+ }
+ change =
+ entry->reported_distance
+ < eigrp_calculate_metrics(eigrp, &int_data->metric) ? 1 :
+ entry->reported_distance
+ > eigrp_calculate_metrics(eigrp, &int_data->metric) ? 2 : 3; // Increase : Decrease : No change
+ entry->reported_metric = int_data->metric;
+ entry->reported_distance = eigrp_calculate_metrics(eigrp,
+ &int_data->metric);
+ entry->distance = eigrp_calculate_total_metrics(eigrp, entry);
+ }
+ else
+ {
+ ext_data = msg->data.ipv4_ext_data;
+ if (eigrp_metrics_is_same (&ext_data->metric, &entry->reported_metric))
+ return 0;
+ }
+ /*
+ * Move to correct position in list according to new distance
+ */
+ listnode_delete(prefix->entries, entry);
+ listnode_add_sort(prefix->entries, entry);
+
+ return change;
+}
+
+void
+eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
+{
+ struct list *table = eigrp->topology_table;
+ struct eigrp_prefix_entry *data;
+ struct listnode *node, *nnode;
+ for (ALL_LIST_ELEMENTS(table, node, nnode, data))
+ {
+ eigrp_topology_update_node_flags(data);
+ }
+}
+
+void
+eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest)
+{
+ struct listnode *node;
+ struct eigrp_neighbor_entry *entry;
+ struct eigrp * eigrp = eigrp_lookup();
+
+ for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry))
+ {
+ if ((entry->distance <= (u_int64_t)(dest->distance*eigrp->variance)) && entry->distance != EIGRP_MAX_METRIC) // is successor
+ {
+ entry->flags |= EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
+ entry->flags &= 0xfd; // 1111 1101 set fs flag to zero
+ }
+ else if (entry->reported_distance < dest->fdistance) // is feasible successor
+ {
+ entry->flags |= EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG;
+ entry->flags &= 0xfe; // 1111 1110 set successor flag to zero
+ }
+ else
+ {
+ entry->flags &= 0xfc; // 1111 1100 set successor and fs flag to zero
+ }
+ }
+}
+
+void
+eigrp_update_routing_table(struct eigrp_prefix_entry * prefix)
+{
+ struct listnode *node;
+ struct eigrp_neighbor_entry *entry;
+
+ for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry))
+ {
+ if (entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)
+ {
+ if (!(entry->flags & EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG))
+ {
+ eigrp_zebra_route_add(prefix->destination_ipv4, entry);
+ entry->flags += EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG;
+ }
+ }
+ else if (entry->flags & EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG)
+ {
+ eigrp_zebra_route_delete(prefix->destination_ipv4, entry);
+ entry->flags -= EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG;
+ }
+ }
+}
+
+void
+eigrp_topology_neighbor_down(struct eigrp *eigrp, struct eigrp_neighbor * nbr)
+{
+ struct listnode *node1, *node11, *node2, *node22;
+ struct eigrp_prefix_entry *prefix;
+ struct eigrp_neighbor_entry *entry;
+
+ for (ALL_LIST_ELEMENTS(eigrp->topology_table, node1, node11, prefix))
+ {
+ for (ALL_LIST_ELEMENTS(prefix->entries, node2, node22, entry))
+ {
+ if (entry->adv_router == nbr)
+ {
+ struct eigrp_fsm_action_message *msg;
+ msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
+ sizeof(struct eigrp_fsm_action_message));
+ struct TLV_IPv4_Internal_type * tlv = eigrp_IPv4_InternalTLV_new();
+ tlv->metric.delay = EIGRP_MAX_METRIC;
+ msg->packet_type = EIGRP_OPC_UPDATE;
+ msg->eigrp = eigrp;
+ msg->data_type = EIGRP_TLV_IPv4_INT;
+ msg->adv_router = nbr;
+ msg->data.ipv4_int_type = tlv;
+ msg->entry = entry;
+ msg->prefix = prefix;
+ int event = eigrp_get_fsm_event(msg);
+ eigrp_fsm_event(msg, event);
+ }
+ }
+ }
+
+ eigrp_query_send_all(eigrp);
+ eigrp_update_send_all(eigrp,nbr->ei);
+
+}
+
+void
+eigrp_update_topology_table_prefix(struct list * table, struct eigrp_prefix_entry * prefix)
+{
+ struct listnode *node1, *node2;
+
+ struct eigrp_neighbor_entry *entry;
+ for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry))
+ {
+ if(entry->distance == EIGRP_MAX_METRIC)
+ {
+ eigrp_neighbor_entry_delete(prefix,entry);
+ }
+ }
+ if(prefix->distance == EIGRP_MAX_METRIC && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED)
+ {
+ eigrp_prefix_entry_delete(table,prefix);
+ }
+}
+/*int
+ eigrp_topology_get_successor_count (struct eigrp_prefix_entry *prefix)
+ {
+
+ struct listnode *node;
+ struct eigrp_neighbor_entry *entry;
+
+ int count = 0;
+
+ for (ALL_LIST_ELEMENTS_RO (prefix->entries,node,entry))
+ {
+ if ((entry->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG) == EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)
+ {
+ count ++;
+ }
+ }
+
+ return count;
+ }
+ */
diff --git a/eigrpd/eigrp_topology.h b/eigrpd/eigrp_topology.h
new file mode 100644
index 000000000..9f1569ea6
--- /dev/null
+++ b/eigrpd/eigrp_topology.h
@@ -0,0 +1,75 @@
+/*
+ * EIGRP Topology Table.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_TOPOLOGY_H
+#define _ZEBRA_EIGRP_TOPOLOGY_H
+
+
+/* EIGRP Topology table related functions. */
+extern struct list *eigrp_topology_new (void);
+extern void eigrp_topology_init (struct list*);
+extern struct eigrp_prefix_entry *eigrp_prefix_entry_new (void);
+extern struct eigrp_neighbor_entry *eigrp_neighbor_entry_new (void);
+extern void eigrp_topology_free (struct list *);
+extern void eigrp_topology_cleanup (struct list *);
+extern void eigrp_prefix_entry_add (struct list *, struct eigrp_prefix_entry *);
+extern void eigrp_neighbor_entry_add (struct eigrp_prefix_entry *, struct eigrp_neighbor_entry *);
+extern void eigrp_prefix_entry_delete (struct list *, struct eigrp_prefix_entry *);
+extern void eigrp_neighbor_entry_delete (struct eigrp_prefix_entry *, struct eigrp_neighbor_entry *);
+extern void eigrp_topology_delete_all (struct list *);
+extern unsigned int eigrp_topology_table_isempty (struct list *);
+extern struct eigrp_prefix_entry *eigrp_topology_table_lookup_ipv4 (struct list *, struct prefix_ipv4 *);
+extern struct list *eigrp_topology_get_successor (struct eigrp_prefix_entry *);
+//extern struct eigrp_neighbor_entry *eigrp_topology_get_fsuccessor (struct eigrp_prefix_entry *);
+extern struct eigrp_neighbor_entry *eigrp_prefix_entry_lookup (struct list *, struct eigrp_neighbor *);
+extern struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *, struct eigrp_neighbor *);
+extern void eigrp_topology_update_all_node_flags (struct eigrp *);
+extern void eigrp_topology_update_node_flags (struct eigrp_prefix_entry *);
+extern int eigrp_topology_update_distance ( struct eigrp_fsm_action_message *);
+extern void eigrp_update_routing_table(struct eigrp_prefix_entry *);
+extern void eigrp_topology_neighbor_down(struct eigrp *, struct eigrp_neighbor *);
+extern void eigrp_update_topology_table_prefix(struct list *, struct eigrp_prefix_entry * );
+//extern int eigrp_topology_get_successor_count (struct eigrp_prefix_entry *);
+/* Set all stats to -1 (LSA_SPF_NOT_EXPLORED). */
+/*extern void eigrp_lsdb_clean_stat (struct eigrp_lsdb *lsdb);
+extern struct eigrp_lsa *eigrp_lsdb_lookup_by_id (struct eigrp_lsdb *, u_char,
+ struct in_addr, struct in_addr);
+extern struct eigrp_lsa *eigrp_lsdb_lookup_by_id_next (struct eigrp_lsdb *, u_char,
+ struct in_addr, struct in_addr,
+ int);
+extern unsigned long eigrp_lsdb_count_all (struct eigrp_lsdb *);
+extern unsigned long eigrp_lsdb_count (struct eigrp_lsdb *, int);
+extern unsigned long eigrp_lsdb_count_self (struct eigrp_lsdb *, int);
+extern unsigned int eigrp_lsdb_checksum (struct eigrp_lsdb *, int);
+extern unsigned long eigrp_lsdb_isempty (struct eigrp_lsdb *);
+*/
+#endif
diff --git a/eigrpd/eigrp_update.c b/eigrpd/eigrp_update.c
new file mode 100644
index 000000000..358d77c84
--- /dev/null
+++ b/eigrpd/eigrp_update.c
@@ -0,0 +1,1159 @@
+/*
+ * EIGRP Sending and Receiving EIGRP Update Packets.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
+#include "vty.h"
+#include "plist.h"
+#include "plist_int.h"
+#include "routemap.h"
+#include "vty.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_macros.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_memory.h"
+
+/**
+ * @fn remove_received_prefix_gr
+ *
+ * @param[in] nbr_prefixes List of neighbor prefixes
+ * @param[in] recv_prefix Prefix which needs to be removed from list
+ *
+ * @return void
+ *
+ * @par
+ * Function is used for removing received prefix
+ * from list of neighbor prefixes
+ */
+static void
+remove_received_prefix_gr (struct list *nbr_prefixes, struct eigrp_prefix_entry *recv_prefix)
+{
+ struct listnode *node1, *node11;
+ struct eigrp_prefix_entry *prefix;
+
+ /* iterate over all prefixes in list */
+ for (ALL_LIST_ELEMENTS(nbr_prefixes, node1, node11, prefix))
+ {
+ /* remove prefix from list if found */
+ if (prefix == recv_prefix)
+ {
+ listnode_delete(nbr_prefixes, prefix);
+ }
+ }
+}
+
+/**
+ * @fn eigrp_update_receive_GR_ask
+ *
+ * @param[in] eigrp EIGRP process
+ * @param[in] nbr Neighbor update of who we received
+ * @param[in] nbr_prefixes Prefixes which weren't advertised
+ *
+ * @return void
+ *
+ * @par
+ * Function is used for notifying FSM about prefixes which
+ * weren't advertised by neighbor:
+ * We will send message to FSM with prefix delay set to infinity.
+ */
+static void
+eigrp_update_receive_GR_ask (struct eigrp *eigrp, struct eigrp_neighbor *nbr, struct list *nbr_prefixes)
+{
+ struct listnode *node1;
+ struct eigrp_prefix_entry *prefix;
+ struct TLV_IPv4_Internal_type *tlv_max;
+
+ /* iterate over all prefixes which weren't advertised by neighbor */
+ for (ALL_LIST_ELEMENTS_RO(nbr_prefixes, node1, prefix))
+ {
+ zlog_debug("GR receive: Neighbor not advertised %s/%d",
+ inet_ntoa(prefix->destination_ipv4->prefix),
+ prefix->destination_ipv4->prefixlen);
+
+ /* create internal IPv4 TLV with infinite delay */
+ tlv_max = eigrp_IPv4_InternalTLV_new();
+ tlv_max->type = EIGRP_TLV_IPv4_INT;
+ tlv_max->length = 28U;
+ tlv_max->metric = prefix->reported_metric;
+ /* set delay to MAX */
+ tlv_max->metric.delay = EIGRP_MAX_METRIC;
+ tlv_max->destination = prefix->destination_ipv4->prefix;
+ tlv_max->prefix_length = prefix->destination_ipv4->prefixlen;
+
+
+ /* prepare message for FSM */
+ struct eigrp_fsm_action_message *fsm_msg;
+ fsm_msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
+ sizeof(struct eigrp_fsm_action_message));
+
+ struct eigrp_neighbor_entry *entry =
+ eigrp_prefix_entry_lookup(prefix->entries, nbr);
+
+ fsm_msg->packet_type = EIGRP_OPC_UPDATE;
+ fsm_msg->eigrp = eigrp;
+ fsm_msg->data_type = EIGRP_TLV_IPv4_INT;
+ fsm_msg->adv_router = nbr;
+ fsm_msg->data.ipv4_int_type = tlv_max;
+ fsm_msg->entry = entry;
+ fsm_msg->prefix = prefix;
+
+ /* send message to FSM */
+ int event = eigrp_get_fsm_event(fsm_msg);
+ eigrp_fsm_event(fsm_msg, event);
+
+ /* free memory used by TLV */
+ eigrp_IPv4_InternalTLV_free (tlv_max);
+ }
+}
+
+/*
+ * EIGRP UPDATE read function
+ */
+void
+eigrp_update_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
+ struct stream * s, struct eigrp_interface *ei, int size)
+{
+ struct eigrp_neighbor *nbr;
+ struct TLV_IPv4_Internal_type *tlv;
+ struct eigrp_prefix_entry *pe;
+ struct eigrp_neighbor_entry *ne;
+ u_int32_t flags;
+ u_int16_t type;
+ u_char same;
+ struct access_list *alist;
+ struct prefix_list *plist;
+ struct eigrp *e;
+ u_char graceful_restart;
+ u_char graceful_restart_final;
+ struct list *nbr_prefixes;
+
+ /* increment statistics. */
+ ei->update_in++;
+
+ /* get neighbor struct */
+ nbr = eigrp_nbr_get(ei, eigrph, iph);
+
+ /* neighbor must be valid, eigrp_nbr_get creates if none existed */
+ assert(nbr);
+
+ flags = ntohl(eigrph->flags);
+
+ if (flags & EIGRP_CR_FLAG)
+ {
+ return;
+ }
+
+ same = 0;
+ graceful_restart = 0;
+ graceful_restart_final = 0;
+ if((nbr->recv_sequence_number) == (ntohl(eigrph->sequence)))
+ same = 1;
+
+ nbr->recv_sequence_number = ntohl(eigrph->sequence);
+ if (IS_DEBUG_EIGRP_PACKET(0, RECV))
+ zlog_debug("Processing Update size[%u] int(%s) nbr(%s) seq [%u] flags [%0x]",
+ size, ifindex2ifname(nbr->ei->ifp->ifindex),
+ inet_ntoa(nbr->src),
+ nbr->recv_sequence_number, flags);
+
+
+ if((flags == (EIGRP_INIT_FLAG+EIGRP_RS_FLAG+EIGRP_EOT_FLAG)) && (!same))
+ {
+ /* Graceful restart Update received with all routes */
+
+ zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
+ inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
+
+ /* get all prefixes from neighbor from topology table */
+ nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
+ graceful_restart = 1;
+ graceful_restart_final = 1;
+ }
+ else if((flags == (EIGRP_INIT_FLAG+EIGRP_RS_FLAG)) && (!same))
+ {
+ /* Graceful restart Update received, routes also in next packet */
+
+ zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
+ inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
+
+ /* get all prefixes from neighbor from topology table */
+ nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
+ /* save prefixes to neighbor for later use */
+ nbr->nbr_gr_prefixes = nbr_prefixes;
+ graceful_restart = 1;
+ graceful_restart_final = 0;
+ }
+ else if((flags == (EIGRP_EOT_FLAG)) && (!same))
+ {
+ /* If there was INIT+RS Update packet before,
+ * consider this as GR EOT */
+
+ if(nbr->nbr_gr_prefixes != NULL)
+ {
+ /* this is final packet of GR */
+ nbr_prefixes = nbr->nbr_gr_prefixes;
+ nbr->nbr_gr_prefixes = NULL;
+
+ graceful_restart = 1;
+ graceful_restart_final = 1;
+ }
+
+ }
+ else if((flags == (0)) && (!same))
+ {
+ /* If there was INIT+RS Update packet before,
+ * consider this as GR not final packet */
+
+ if(nbr->nbr_gr_prefixes != NULL)
+ {
+ /* this is GR not final route packet */
+ nbr_prefixes = nbr->nbr_gr_prefixes;
+
+ graceful_restart = 1;
+ graceful_restart_final = 0;
+ }
+
+ }
+ else if((flags & EIGRP_INIT_FLAG) && (!same))
+ { /* When in pending state, send INIT update only if it wasn't
+ already sent before (only if init_sequence is 0) */
+ if((nbr->state == EIGRP_NEIGHBOR_PENDING) && (nbr->init_sequence_number == 0))
+ eigrp_update_send_init(nbr);
+
+ if (nbr->state == EIGRP_NEIGHBOR_UP)
+ {
+ eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
+ eigrp_topology_neighbor_down(nbr->ei->eigrp,nbr);
+ nbr->recv_sequence_number = ntohl(eigrph->sequence);
+ zlog_info("Neighbor %s (%s) is down: peer restarted",
+ inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
+ eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING);
+ zlog_info("Neighbor %s (%s) is pending: new adjacency",
+ inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
+ eigrp_update_send_init(nbr);
+ }
+ }
+
+ /*If there is topology information*/
+ while (s->endp > s->getp)
+ {
+ type = stream_getw(s);
+ if (type == EIGRP_TLV_IPv4_INT)
+ {
+ stream_set_getp(s, s->getp - sizeof(u_int16_t));
+
+ tlv = eigrp_read_ipv4_tlv(s);
+
+ /*searching if destination exists */
+ struct prefix_ipv4 *dest_addr;
+ dest_addr = prefix_ipv4_new();
+ dest_addr->prefix = tlv->destination;
+ dest_addr->prefixlen = tlv->prefix_length;
+ struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
+ eigrp->topology_table, dest_addr);
+
+ /*if exists it comes to DUAL*/
+ if (dest != NULL)
+ {
+ /* remove received prefix from neighbor prefix list if in GR */
+ if(graceful_restart)
+ remove_received_prefix_gr(nbr_prefixes, dest);
+
+ struct eigrp_fsm_action_message *msg;
+ msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
+ sizeof(struct eigrp_fsm_action_message));
+ struct eigrp_neighbor_entry *entry =
+ eigrp_prefix_entry_lookup(dest->entries, nbr);
+
+ msg->packet_type = EIGRP_OPC_UPDATE;
+ msg->eigrp = eigrp;
+ msg->data_type = EIGRP_TLV_IPv4_INT;
+ msg->adv_router = nbr;
+ msg->data.ipv4_int_type = tlv;
+ msg->entry = entry;
+ msg->prefix = dest;
+ int event = eigrp_get_fsm_event(msg);
+ eigrp_fsm_event(msg, event);
+ }
+ else
+ {
+ /*Here comes topology information save*/
+ pe = eigrp_prefix_entry_new();
+ pe->serno = eigrp->serno;
+ pe->destination_ipv4 = dest_addr;
+ pe->af = AF_INET;
+ pe->state = EIGRP_FSM_STATE_PASSIVE;
+ pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE;
+
+ ne = eigrp_neighbor_entry_new();
+ ne->ei = ei;
+ ne->adv_router = nbr;
+ ne->reported_metric = tlv->metric;
+ ne->reported_distance =
+ eigrp_calculate_metrics(eigrp,
+ &tlv->metric);
+ /*
+ * Filtering
+ */
+ e = eigrp_lookup();
+ /*
+ * Check if there is any access-list on interface (IN direction)
+ * and set distance to max
+ */
+ alist = ei->list[EIGRP_FILTER_IN];
+
+ if (alist) {
+ zlog_info ("ALIST PROC IN: %s", alist->name);
+ } else {
+ zlog_info("ALIST je prazdny");
+ }
+
+ /* Check if access-list fits */
+ if (alist && access_list_apply (alist,
+ (struct prefix *) dest_addr) == FILTER_DENY)
+ {
+ /* If yes, set reported metric to Max */
+ zlog_info("PROC IN: Nastavujem metriku na MAX");
+ ne->reported_metric.delay = EIGRP_MAX_METRIC;
+ zlog_info("PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix));
+ } else {
+ zlog_info("PROC IN: NENastavujem metriku ");
+ ne->distance = eigrp_calculate_total_metrics(eigrp, ne);
+ }
+
+ plist = e->prefix[EIGRP_FILTER_IN];
+
+ if (plist) {
+ zlog_info ("PLIST PROC IN: %s", plist->name);
+ } else {
+ zlog_info("PLIST PROC IN je prazdny");
+ }
+
+ /* Check if prefix-list fits */
+ if (plist && prefix_list_apply (plist,
+ (struct prefix *) dest_addr) == FILTER_DENY)
+ {
+ /* If yes, set reported metric to Max */
+ zlog_info("PLIST PROC IN: Nastavujem metriku na MAX");
+ ne->reported_metric.delay = EIGRP_MAX_METRIC;
+ zlog_info("PLIST PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix));
+ } else {
+ zlog_info("PLIST PROC IN: NENastavujem metriku ");
+ }
+
+ /*Get access-list from current interface */
+ zlog_info("Checking access_list on interface: %s",ei->ifp->name);
+ alist = ei->list[EIGRP_FILTER_IN];
+ if (alist) {
+ zlog_info ("ALIST INT IN: %s", alist->name);
+ } else {
+ zlog_info("ALIST INT IN je prazdny");
+ }
+
+ /* Check if access-list fits */
+ if (alist && access_list_apply (alist, (struct prefix *) dest_addr) == FILTER_DENY)
+ {
+ /* If yes, set reported metric to Max */
+ zlog_info("INT IN: Nastavujem metriku na MAX");
+ ne->reported_metric.delay = EIGRP_MAX_METRIC;
+ zlog_info("INT IN Prefix: %s", inet_ntoa(dest_addr->prefix));
+ } else {
+ zlog_info("INT IN: NENastavujem metriku ");
+ }
+
+ plist = ei->prefix[EIGRP_FILTER_IN];
+
+ if (plist) {
+ zlog_info ("PLIST INT IN: %s", plist->name);
+ } else {
+ zlog_info("PLIST INT IN je prazdny");
+ }
+
+ /* Check if prefix-list fits */
+ if (plist && prefix_list_apply (plist,
+ (struct prefix *) dest_addr) == FILTER_DENY)
+ {
+ /* If yes, set reported metric to Max */
+ zlog_info("PLIST INT IN: Nastavujem metriku na MAX");
+ ne->reported_metric.delay = EIGRP_MAX_METRIC;
+ zlog_info("PLIST INT IN Prefix: %s", inet_ntoa(dest_addr->prefix));
+ } else {
+ zlog_info("PLIST INT IN: NENastavujem metriku ");
+ }
+ /*
+ * End of filtering
+ */
+
+ ne->distance = eigrp_calculate_total_metrics(eigrp, ne);
+
+ zlog_info("<DEBUG PROC IN Distance: %x", ne->distance);
+ zlog_info("<DEBUG PROC IN Delay: %x", ne->total_metric.delay);
+
+ pe->fdistance = pe->distance = pe->rdistance =
+ ne->distance;
+ ne->prefix = pe;
+ ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
+
+ eigrp_prefix_entry_add(eigrp->topology_table, pe);
+ eigrp_neighbor_entry_add(pe, ne);
+ pe->distance = pe->fdistance = pe->rdistance =
+ ne->distance;
+ pe->reported_metric = ne->total_metric;
+ eigrp_topology_update_node_flags(pe);
+
+ pe->req_action |= EIGRP_FSM_NEED_UPDATE;
+ listnode_add(eigrp->topology_changes_internalIPV4, pe);
+ }
+ eigrp_IPv4_InternalTLV_free (tlv);
+ }
+ }
+
+ /* ask about prefixes not present in GR update,
+ * if this is final GR packet */
+ if(graceful_restart_final)
+ {
+ eigrp_update_receive_GR_ask(eigrp, nbr, nbr_prefixes);
+ }
+
+ /*
+ * We don't need to send separate Ack for INIT Update. INIT will be acked in EOT Update.
+ */
+ if ((nbr->state == EIGRP_NEIGHBOR_UP) && !(flags == EIGRP_INIT_FLAG))
+ {
+ eigrp_hello_send_ack(nbr);
+ }
+
+ eigrp_query_send_all(eigrp);
+ eigrp_update_send_all(eigrp, ei);
+}
+
+/*send EIGRP Update packet*/
+void
+eigrp_update_send_init (struct eigrp_neighbor *nbr)
+{
+ struct eigrp_packet *ep;
+ u_int16_t length = EIGRP_HEADER_LEN;
+
+ ep = eigrp_packet_new(nbr->ei->ifp->mtu);
+
+ /* Prepare EIGRP INIT UPDATE header */
+ if (IS_DEBUG_EIGRP_PACKET(0, RECV))
+ zlog_debug("Enqueuing Update Init Seq [%u] Ack [%u]",
+ nbr->ei->eigrp->sequence_number,
+ nbr->recv_sequence_number);
+
+ eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_INIT_FLAG,
+ nbr->ei->eigrp->sequence_number,
+ nbr->recv_sequence_number);
+
+ // encode Authentication TLV, if needed
+ if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+ {
+ length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
+ eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_INIT_FLAG);
+ }
+
+ /* EIGRP Checksum */
+ eigrp_packet_checksum(nbr->ei, ep->s, length);
+
+ ep->length = length;
+ ep->dst.s_addr = nbr->src.s_addr;
+
+ /*This ack number we await from neighbor*/
+ nbr->init_sequence_number = nbr->ei->eigrp->sequence_number;
+ ep->sequence_number = nbr->ei->eigrp->sequence_number;
+ if (IS_DEBUG_EIGRP_PACKET(0, RECV))
+ zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
+ ep->length, ep->sequence_number, inet_ntoa(ep->dst));
+
+ /*Put packet to retransmission queue*/
+ eigrp_fifo_push_head(nbr->retrans_queue, ep);
+
+ if (nbr->retrans_queue->count == 1)
+ {
+ eigrp_send_packet_reliably(nbr);
+ }
+}
+
+void
+eigrp_update_send_EOT (struct eigrp_neighbor *nbr)
+{
+ struct eigrp_packet *ep;
+// struct eigrp_packet *ep_multicast;
+ u_int16_t length = EIGRP_HEADER_LEN;
+ struct eigrp_neighbor_entry *te;
+ struct eigrp_prefix_entry *pe;
+ struct listnode *node, *node2, *nnode, *nnode2;
+ struct access_list *alist;
+ struct prefix_list *plist;
+ struct access_list *alist_i;
+ struct prefix_list *plist_i;
+ struct eigrp *e;
+ struct prefix_ipv4 *dest_addr;
+
+ ep = eigrp_packet_new(nbr->ei->ifp->mtu);
+
+ /* Prepare EIGRP EOT UPDATE header */
+ eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG,
+ nbr->ei->eigrp->sequence_number,
+ nbr->recv_sequence_number);
+
+ // encode Authentication TLV, if needed
+ if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+ {
+ length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
+ }
+
+ for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe))
+ {
+ for (ALL_LIST_ELEMENTS(pe->entries, node2, nnode2, te))
+ {
+ if ((te->ei == nbr->ei)
+ && (te->prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE))
+ continue;
+
+ /* Get destination address from prefix */
+ dest_addr = pe->destination_ipv4;
+
+ /*
+ * Filtering
+ */
+ //TODO: Work in progress
+ /* get list from eigrp process */
+ e = eigrp_lookup();
+ /* Get access-lists and prefix-lists from process and interface */
+ alist = e->list[EIGRP_FILTER_OUT];
+ plist = e->prefix[EIGRP_FILTER_OUT];
+ alist_i = nbr->ei->list[EIGRP_FILTER_OUT];
+ plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT];
+
+ /* Check if any list fits */
+ if ((alist && access_list_apply (alist,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (plist && prefix_list_apply (plist,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (alist_i && access_list_apply (alist_i,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (plist_i && prefix_list_apply (plist_i,
+ (struct prefix *) dest_addr) == FILTER_DENY))
+ {
+ zlog_info("PROC OUT EOT: Skipping");
+ //pe->reported_metric.delay = EIGRP_MAX_METRIC;
+ zlog_info("PROC OUT EOT Prefix: %s", inet_ntoa(dest_addr->prefix));
+ continue;
+ } else {
+ zlog_info("PROC OUT EOT: NENastavujem metriku ");
+ length += eigrp_add_internalTLV_to_stream(ep->s, pe);
+ }
+ /*
+ * End of filtering
+ */
+
+ /* NULL the pointer */
+ dest_addr = NULL;
+
+ }
+ }
+
+ if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+ {
+ eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
+ }
+
+ /* EIGRP Checksum */
+ eigrp_packet_checksum(nbr->ei, ep->s, length);
+
+ ep->length = length;
+ ep->dst.s_addr = nbr->src.s_addr;
+
+ /*This ack number we await from neighbor*/
+ ep->sequence_number = nbr->ei->eigrp->sequence_number;
+
+ if (IS_DEBUG_EIGRP_PACKET(0, RECV))
+ zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
+ ep->length, ep->sequence_number, inet_ntoa(ep->dst));
+
+ /*Put packet to retransmission queue*/
+ eigrp_fifo_push_head(nbr->retrans_queue, ep);
+
+ if (nbr->retrans_queue->count == 1)
+ {
+ eigrp_send_packet_reliably(nbr);
+ }
+
+}
+
+void
+eigrp_update_send (struct eigrp_interface *ei)
+{
+ struct eigrp_packet *ep;
+ struct listnode *node, *nnode;
+ struct eigrp_neighbor *nbr;
+ struct eigrp_prefix_entry *pe;
+ u_char has_tlv;
+ struct access_list *alist;
+ struct prefix_list *plist;
+ struct access_list *alist_i;
+ struct prefix_list *plist_i;
+ struct eigrp *e;
+ struct prefix_ipv4 *dest_addr;
+
+ u_int16_t length = EIGRP_HEADER_LEN;
+
+ ep = eigrp_packet_new(ei->ifp->mtu);
+
+ /* Prepare EIGRP INIT UPDATE header */
+ eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei, ep->s, 0,
+ ei->eigrp->sequence_number, 0);
+
+ // encode Authentication TLV, if needed
+ if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+ {
+ length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei);
+ }
+
+ has_tlv = 0;
+ for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node, nnode, pe))
+ {
+ if(pe->req_action & EIGRP_FSM_NEED_UPDATE)
+ {
+ /* Get destination address from prefix */
+ dest_addr = pe->destination_ipv4;
+
+ /*
+ * Filtering
+ */
+ //TODO: Work in progress
+ /* get list from eigrp process */
+ e = eigrp_lookup();
+ /* Get access-lists and prefix-lists from process and interface */
+ alist = e->list[EIGRP_FILTER_OUT];
+ plist = e->prefix[EIGRP_FILTER_OUT];
+ alist_i = ei->list[EIGRP_FILTER_OUT];
+ plist_i = ei->prefix[EIGRP_FILTER_OUT];
+
+ /* Check if any list fits */
+ if ((alist && access_list_apply (alist,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (plist && prefix_list_apply (plist,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (alist_i && access_list_apply (alist_i,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (plist_i && prefix_list_apply (plist_i,
+ (struct prefix *) dest_addr) == FILTER_DENY))
+ {
+ zlog_info("PROC OUT: Skipping");
+ //pe->reported_metric.delay = EIGRP_MAX_METRIC;
+ zlog_info("PROC OUT Prefix: %s", inet_ntoa(dest_addr->prefix));
+ continue;
+ } else {
+ zlog_info("PROC OUT: NENastavujem metriku ");
+ length += eigrp_add_internalTLV_to_stream(ep->s, pe);
+ has_tlv = 1;
+ }
+ /*
+ * End of filtering
+ */
+
+ /* NULL the pointer */
+ dest_addr = NULL;
+
+ }
+ }
+
+ if(!has_tlv)
+ {
+ eigrp_packet_free(ep);
+ return;
+ }
+
+ if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+ {
+ eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
+ }
+
+ /* EIGRP Checksum */
+ eigrp_packet_checksum(ei, ep->s, length);
+ ep->length = length;
+
+ ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS);
+
+ /*This ack number we await from neighbor*/
+ ep->sequence_number = ei->eigrp->sequence_number;
+
+ if (IS_DEBUG_EIGRP_PACKET(0, RECV))
+ zlog_debug("Enqueuing Update length[%u] Seq [%u]",
+ length, ep->sequence_number);
+
+ for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr))
+ {
+ if (nbr->state == EIGRP_NEIGHBOR_UP)
+ {
+ /*Put packet to retransmission queue*/
+ eigrp_fifo_push_head(nbr->retrans_queue, ep);
+
+ if (nbr->retrans_queue->count == 1)
+ {
+ eigrp_send_packet_reliably(nbr);
+ }
+ }
+ }
+}
+
+void
+eigrp_update_send_all (struct eigrp *eigrp, struct eigrp_interface *exception)
+{
+
+ struct eigrp_interface *iface;
+ struct listnode *node, *node2, *nnode2;
+ struct eigrp_prefix_entry *pe;
+
+ for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface))
+ {
+ if (iface != exception)
+ {
+ eigrp_update_send(iface);
+ }
+ }
+
+ for (ALL_LIST_ELEMENTS(eigrp->topology_changes_internalIPV4, node2, nnode2, pe))
+ {
+ if(pe->req_action & EIGRP_FSM_NEED_UPDATE)
+ {
+ pe->req_action &= ~EIGRP_FSM_NEED_UPDATE;
+ listnode_delete(eigrp->topology_changes_internalIPV4, pe);
+ zlog_debug("UPDATE COUNT: %d", eigrp->topology_changes_internalIPV4->count);
+ }
+ }
+}
+
+/**
+ * @fn eigrp_update_send_GR_part
+ *
+ * @param[in] nbr contains neighbor who would receive Graceful restart
+ *
+ * @return void
+ *
+ * @par
+ * Function used for sending Graceful restart Update packet
+ * and if there are multiple chunks, send only one of them.
+ * It is called from thread. Do not call it directly.
+ *
+ * Uses nbr_gr_packet_type from neighbor.
+ */
+static void
+eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
+{
+ struct eigrp_packet *ep;
+ u_int16_t length = EIGRP_HEADER_LEN;
+ struct listnode *node, *nnode;
+ struct eigrp_prefix_entry *pe;
+ struct prefix_ipv4 *dest_addr;
+ struct eigrp *e;
+ struct access_list *alist, *alist_i;
+ struct prefix_list *plist, *plist_i;
+ struct list *prefixes;
+ u_int32_t flags;
+ unsigned int send_prefixes;
+ struct TLV_IPv4_Internal_type *tlv_max;
+
+ /* get prefixes to send to neighbor */
+ prefixes = nbr->nbr_gr_prefixes_send;
+
+ send_prefixes = 0;
+ length = EIGRP_HEADER_LEN;
+
+ /* if there already were last packet chunk, we won't continue */
+ if(nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_LAST)
+ return;
+
+ /* if this is first packet chunk, we need to decide,
+ * if there will be one or more chunks */
+ if(nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_FIRST)
+ {
+ if(prefixes->count <= EIGRP_TLV_MAX_IPv4)
+ {
+ /* there will be only one chunk */
+ flags = EIGRP_INIT_FLAG + EIGRP_RS_FLAG + EIGRP_EOT_FLAG;
+ nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_LAST;
+ }
+ else
+ {
+ /* there will be more chunks */
+ flags = EIGRP_INIT_FLAG + EIGRP_RS_FLAG;
+ nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_NA;
+ }
+ }
+ else
+ {
+ /* this is not first chunk, and we need to decide,
+ * if there will be more chunks */
+ if(prefixes->count <= EIGRP_TLV_MAX_IPv4)
+ {
+ /* this is last chunk */
+ flags = EIGRP_EOT_FLAG;
+ nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_LAST;
+ }
+ else
+ {
+ /* there will be more chunks */
+ flags = 0;
+ nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_NA;
+ }
+ }
+
+ ep = eigrp_packet_new(nbr->ei->ifp->mtu);
+
+ /* Prepare EIGRP Graceful restart UPDATE header */
+ eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s,
+ flags,
+ nbr->ei->eigrp->sequence_number,
+ nbr->recv_sequence_number);
+
+ // encode Authentication TLV, if needed
+ if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+ {
+ length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
+ }
+
+ for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe))
+ {
+
+ /*
+ * Filtering
+ */
+ dest_addr = pe->destination_ipv4;
+ /* get list from eigrp process */
+ e = eigrp_lookup();
+ /* Get access-lists and prefix-lists from process and interface */
+ alist = e->list[EIGRP_FILTER_OUT];
+ plist = e->prefix[EIGRP_FILTER_OUT];
+ alist_i = nbr->ei->list[EIGRP_FILTER_OUT];
+ plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT];
+
+
+ /* Check if any list fits */
+ if ((alist && access_list_apply (alist,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (plist && prefix_list_apply (plist,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (alist_i && access_list_apply (alist_i,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (plist_i && prefix_list_apply (plist_i,
+ (struct prefix *) dest_addr) == FILTER_DENY))
+ {
+ /* do not send filtered route */
+ zlog_info("Filtered prefix %s won't be sent out.",
+ inet_ntoa(dest_addr->prefix));
+ }
+ else
+ {
+ /* sending route which wasn't filtered */
+ length += eigrp_add_internalTLV_to_stream(ep->s, pe);
+ send_prefixes++;
+ }
+
+
+
+ alist = e->list[EIGRP_FILTER_IN];
+ plist = e->prefix[EIGRP_FILTER_IN];
+ alist_i = nbr->ei->list[EIGRP_FILTER_IN];
+ plist_i = nbr->ei->prefix[EIGRP_FILTER_IN];
+
+
+ /* Check if any list fits */
+ if ((alist && access_list_apply (alist,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (plist && prefix_list_apply (plist,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (alist_i && access_list_apply (alist_i,
+ (struct prefix *) dest_addr) == FILTER_DENY)||
+ (plist_i && prefix_list_apply (plist_i,
+ (struct prefix *) dest_addr) == FILTER_DENY))
+ {
+ /* do not send filtered route */
+ zlog_info("Filtered prefix %s will be removed.",
+ inet_ntoa(dest_addr->prefix));
+
+ tlv_max = eigrp_IPv4_InternalTLV_new();
+ tlv_max->type = EIGRP_TLV_IPv4_INT;
+ tlv_max->length = 28U;
+ tlv_max->metric = pe->reported_metric;
+ /* set delay to MAX */
+ tlv_max->metric.delay = EIGRP_MAX_METRIC;
+ tlv_max->destination = pe->destination_ipv4->prefix;
+ tlv_max->prefix_length = pe->destination_ipv4->prefixlen;
+
+
+ /* prepare message for FSM */
+ struct eigrp_fsm_action_message *fsm_msg;
+ fsm_msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
+ sizeof(struct eigrp_fsm_action_message));
+
+ struct eigrp_neighbor_entry *entry =
+ eigrp_prefix_entry_lookup(pe->entries, nbr);
+
+ fsm_msg->packet_type = EIGRP_OPC_UPDATE;
+ fsm_msg->eigrp = e;
+ fsm_msg->data_type = EIGRP_TLV_IPv4_INT;
+ fsm_msg->adv_router = nbr;
+ fsm_msg->data.ipv4_int_type = tlv_max;
+ fsm_msg->entry = entry;
+ fsm_msg->prefix = pe;
+
+ /* send message to FSM */
+ int event = eigrp_get_fsm_event(fsm_msg);
+ eigrp_fsm_event(fsm_msg, event);
+
+ /* free memory used by TLV */
+ eigrp_IPv4_InternalTLV_free (tlv_max);
+ }
+ /*
+ * End of filtering
+ */
+
+ /* NULL the pointer */
+ dest_addr = NULL;
+
+ /* delete processed prefix from list */
+ listnode_delete(prefixes, pe);
+
+ /* if there are enough prefixes, send packet */
+ if(send_prefixes >= EIGRP_TLV_MAX_IPv4)
+ break;
+ }
+
+ /* compute Auth digest */
+ if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+ {
+ eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
+ }
+
+ /* EIGRP Checksum */
+ eigrp_packet_checksum(nbr->ei, ep->s, length);
+
+ ep->length = length;
+ ep->dst.s_addr = nbr->src.s_addr;
+
+ /*This ack number we await from neighbor*/
+ ep->sequence_number = nbr->ei->eigrp->sequence_number;
+
+ if (IS_DEBUG_EIGRP_PACKET(0, RECV))
+ zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
+ ep->length, ep->sequence_number, inet_ntoa(ep->dst));
+
+
+ /*Put packet to retransmission queue*/
+ eigrp_fifo_push_head(nbr->retrans_queue, ep);
+
+ if (nbr->retrans_queue->count == 1)
+ {
+ eigrp_send_packet_reliably(nbr);
+ }
+}
+
+/**
+ * @fn eigrp_update_send_GR_thread
+ *
+ * @param[in] thread contains neighbor who would receive Graceful restart
+ *
+ * @return int always 0
+ *
+ * @par
+ * Function used for sending Graceful restart Update packet
+ * in thread, it is prepared for multiple chunks of packet.
+ *
+ * Uses nbr_gr_packet_type and t_nbr_send_gr from neighbor.
+ */
+int
+eigrp_update_send_GR_thread(struct thread *thread)
+{
+ struct eigrp_neighbor *nbr;
+
+ /* get argument from thread */
+ nbr = THREAD_ARG(thread);
+ /* remove this thread pointer */
+ nbr->t_nbr_send_gr = NULL;
+
+ /* if there is packet waiting in queue,
+ * schedule this thread again with small delay */
+ if(nbr->retrans_queue->count > 0)
+ {
+ nbr->t_nbr_send_gr = thread_add_timer_msec(master, eigrp_update_send_GR_thread, nbr, 10);
+ return 0;
+ }
+
+ /* send GR EIGRP packet chunk */
+ eigrp_update_send_GR_part(nbr);
+
+ /* if it wasn't last chunk, schedule this thread again */
+ if(nbr->nbr_gr_packet_type != EIGRP_PACKET_PART_LAST)
+ nbr->t_nbr_send_gr = thread_execute(master, eigrp_update_send_GR_thread, nbr, 0);
+
+ return 0;
+}
+
+/**
+ * @fn eigrp_update_send_GR
+ *
+ * @param[in] nbr Neighbor who would receive Graceful restart
+ * @param[in] gr_type Who executed Graceful restart
+ * @param[in] vty Virtual terminal for log output
+ *
+ * @return void
+ *
+ * @par
+ * Function used for sending Graceful restart Update packet:
+ * Creates Update packet with INIT, RS, EOT flags and include
+ * all route except those filtered
+ */
+void
+eigrp_update_send_GR (struct eigrp_neighbor *nbr, enum GR_type gr_type, struct vty *vty)
+{
+ struct eigrp_prefix_entry *pe2;
+ struct listnode *node2, *nnode2;
+ struct list *prefixes;
+
+ if(gr_type == EIGRP_GR_FILTER)
+ {
+ /* function was called after applying filtration */
+ zlog_info("Neighbor %s (%s) is resync: route configuration changed",
+ inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
+ }
+ else if(gr_type == EIGRP_GR_MANUAL)
+ {
+ /* Graceful restart was called manually */
+ zlog_info("Neighbor %s (%s) is resync: manually cleared",
+ inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
+
+ if(vty != NULL)
+ {
+ vty_time_print (vty, 0);
+ vty_out (vty, "Neighbor %s (%s) is resync: manually cleared%s",
+ inet_ntoa (nbr->src),
+ ifindex2ifname (nbr->ei->ifp->ifindex),
+ VTY_NEWLINE);
+ }
+ }
+
+ prefixes = list_new();
+ /* add all prefixes from topology table to list */
+ for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node2, nnode2, pe2))
+ {
+ listnode_add(prefixes, pe2);
+ }
+
+ /* save prefixes to neighbor */
+ nbr->nbr_gr_prefixes_send = prefixes;
+ /* indicate, that this is first GR Update packet chunk */
+ nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_FIRST;
+ /* execute packet sending in thread */
+ nbr->t_nbr_send_gr = thread_execute(master, eigrp_update_send_GR_thread, nbr, 0);
+}
+
+/**
+ * @fn eigrp_update_send_interface_GR
+ *
+ * @param[in] ei Interface to neighbors of which the GR is sent
+ * @param[in] gr_type Who executed Graceful restart
+ * @param[in] vty Virtual terminal for log output
+ *
+ * @return void
+ *
+ * @par
+ * Function used for sending Graceful restart Update packet
+ * to all neighbors on specified interface.
+ */
+void
+eigrp_update_send_interface_GR (struct eigrp_interface *ei, enum GR_type gr_type, struct vty *vty)
+{
+ struct listnode *node;
+ struct eigrp_neighbor *nbr;
+
+ /* iterate over all neighbors on eigrp interface */
+ for (ALL_LIST_ELEMENTS_RO(ei->nbrs, node, nbr))
+ {
+ /* send GR to neighbor */
+ eigrp_update_send_GR(nbr, gr_type, vty);
+ }
+}
+
+/**
+ * @fn eigrp_update_send_process_GR
+ *
+ * @param[in] eigrp EIGRP process
+ * @param[in] gr_type Who executed Graceful restart
+ * @param[in] vty Virtual terminal for log output
+ *
+ * @return void
+ *
+ * @par
+ * Function used for sending Graceful restart Update packet
+ * to all neighbors in eigrp process.
+ */
+void
+eigrp_update_send_process_GR (struct eigrp *eigrp, enum GR_type gr_type, struct vty *vty)
+{
+ struct listnode *node;
+ struct eigrp_interface *ei;
+
+ /* iterate over all eigrp interfaces */
+ for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+ {
+ /* send GR to all neighbors on interface */
+ eigrp_update_send_interface_GR(ei, gr_type, vty);
+ }
+}
+
+
diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c
new file mode 100644
index 000000000..9208b8301
--- /dev/null
+++ b/eigrpd/eigrp_vty.c
@@ -0,0 +1,1584 @@
+/*
+ * EIGRP VTY Interface.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "thread.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "command.h"
+#include "plist.h"
+#include "log.h"
+#include "zclient.h"
+#include "keychain.h"
+#include "linklist.h"
+#include "distribute.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_const.h"
+
+
+static int
+config_write_network (struct vty *vty, struct eigrp *eigrp)
+{
+ struct route_node *rn;
+
+ /* `network area' print. */
+ for (rn = route_top (eigrp->networks); rn; rn = route_next (rn))
+ if (rn->info)
+ {
+ /* Network print. */
+ vty_out (vty, " network %s/%d %s",
+ inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, VTY_NEWLINE);
+ }
+
+ if (eigrp->max_paths != EIGRP_MAX_PATHS_DEFAULT)
+ vty_out (vty, " maximum-paths %d%s", eigrp->max_paths, VTY_NEWLINE);
+
+ if (eigrp->variance != EIGRP_VARIANCE_DEFAULT)
+ vty_out (vty, " variance %d%s", eigrp->variance, VTY_NEWLINE);
+
+ /*Separate EIGRP configuration from the rest of the config*/
+ vty_out (vty, "!%s", VTY_NEWLINE);
+
+ return 0;
+}
+
+static int
+config_write_interfaces (struct vty *vty, struct eigrp *eigrp)
+{
+ struct eigrp_interface *ei;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+ {
+ vty_out (vty, "interface %s%s", ei->ifp->name, VTY_NEWLINE);
+
+ if ((IF_DEF_PARAMS (ei->ifp)->auth_type) == EIGRP_AUTH_TYPE_MD5)
+ {
+ vty_out (vty, " ip authentication mode eigrp %d md5%s", eigrp->AS, VTY_NEWLINE);
+ }
+
+ if ((IF_DEF_PARAMS (ei->ifp)->auth_type) == EIGRP_AUTH_TYPE_SHA256)
+ {
+ vty_out (vty, " ip authentication mode eigrp %d hmac-sha-256%s", eigrp->AS, VTY_NEWLINE);
+ }
+
+ if(IF_DEF_PARAMS (ei->ifp)->auth_keychain)
+ {
+ vty_out (vty, " ip authentication key-chain eigrp %d %s%s",eigrp->AS,IF_DEF_PARAMS (ei->ifp)->auth_keychain, VTY_NEWLINE);
+ }
+
+ if ((IF_DEF_PARAMS (ei->ifp)->v_hello) != EIGRP_HELLO_INTERVAL_DEFAULT)
+ {
+ vty_out (vty, " ip hello-interval eigrp %d%s", IF_DEF_PARAMS (ei->ifp)->v_hello, VTY_NEWLINE);
+ }
+
+ if ((IF_DEF_PARAMS (ei->ifp)->v_wait) != EIGRP_HOLD_INTERVAL_DEFAULT)
+ {
+ vty_out (vty, " ip hold-time eigrp %d%s", IF_DEF_PARAMS (ei->ifp)->v_wait, VTY_NEWLINE);
+ }
+
+ /*Separate this EIGRP interface configuration from the others*/
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+static int
+eigrp_write_interface (struct vty *vty)
+{
+ int write=0;
+
+ return write;
+}
+
+/**
+ * Writes distribute lists to config
+ */
+static int
+config_write_eigrp_distribute (struct vty *vty, struct eigrp *eigrp)
+{
+ int write=0;
+
+ /* Distribute configuration. */
+ write += config_write_distribute (vty);
+
+ return write;
+}
+
+/**
+ * Writes 'router eigrp' section to config
+ */
+static int
+config_write_eigrp_router (struct vty *vty, struct eigrp *eigrp)
+{
+ int write=0;
+
+ /* `router eigrp' print. */
+ vty_out (vty, "router eigrp %d%s", eigrp->AS, VTY_NEWLINE);
+
+ write++;
+
+ if (!eigrp->networks)
+ return write;
+
+ /* Router ID print. */
+ if (eigrp->router_id_static != 0)
+ {
+ struct in_addr router_id_static;
+ router_id_static.s_addr = htonl(eigrp->router_id_static);
+ vty_out (vty, " eigrp router-id %s%s",
+ inet_ntoa (router_id_static), VTY_NEWLINE);
+ }
+
+ /* Network area print. */
+ config_write_network (vty, eigrp);
+
+ /* Distribute-list and default-information print. */
+ config_write_eigrp_distribute (vty, eigrp);
+
+ /*Separate EIGRP configuration from the rest of the config*/
+ vty_out (vty, "!%s", VTY_NEWLINE);
+
+ return write;
+}
+
+DEFUN (router_eigrp,
+ router_eigrp_cmd,
+ "router eigrp (1-65535)",
+ "Enable a routing process\n"
+ "Start EIGRP configuration\n"
+ "AS Number to use\n")
+{
+ struct eigrp *eigrp = eigrp_get (argv[2]->arg);
+ VTY_PUSH_CONTEXT(EIGRP_NODE, eigrp);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (no_router_eigrp,
+ no_router_eigrp_cmd,
+ "no router eigrp (1-65535)",
+ NO_STR
+ "Routing process\n"
+ "EIGRP configuration\n"
+ "AS number to use\n")
+{
+ vty->node = CONFIG_NODE;
+
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (eigrp_router_id,
+ eigrp_router_id_cmd,
+ "eigrp router-id A.B.C.D",
+ "EIGRP specific commands\n"
+ "Router ID for this EIGRP process\n"
+ "EIGRP Router-ID in IP address format\n")
+{
+ //struct eigrp *eigrp = vty->index;
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_router_id,
+ no_eigrp_router_id_cmd,
+ "no eigrp router-id A.B.C.D",
+ NO_STR
+ "EIGRP specific commands\n"
+ "Router ID for this EIGRP process\n"
+ "EIGRP Router-ID in IP address format\n")
+{
+ //struct eigrp *eigrp = vty->index;
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (eigrp_passive_interface,
+ eigrp_passive_interface_cmd,
+ "passive-interface <" INT_TYPES_CMD_STR ">",
+ "Suppress routing updates on an interface\n"
+ INT_TYPES_DESC)
+{
+ //struct eigrp *eigrp = vty->index;
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_passive_interface,
+ no_eigrp_passive_interface_cmd,
+ "no passive-interface <" INT_TYPES_CMD_STR ">",
+ NO_STR
+ "Suppress routing updates on an interface\n"
+ INT_TYPES_DESC)
+{
+ //struct eigrp *eigrp = vty->index;
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (eigrp_timers_active,
+ eigrp_timers_active_cmd,
+ "timers active-time <(1-65535)|disabled>",
+ "Adjust routing timers\n"
+ "Time limit for active state\n"
+ "Active state time limit in minutes\n"
+ "Disable time limit for active state\n")
+{
+ //struct eigrp *eigrp = vty->index;
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_timers_active,
+ no_eigrp_timers_active_cmd,
+ "no timers active-time <(1-65535)|disabled>",
+ NO_STR
+ "Adjust routing timers\n"
+ "Time limit for active state\n"
+ "Active state time limit in minutes\n"
+ "Disable time limit for active state\n")
+{
+ //struct eigrp *eigrp = vty->index;
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (eigrp_metric_weights,
+ eigrp_metric_weights_cmd,
+ "metric weights (0-255) (0-255) (0-255) (0-255) (0-255) ",
+ "Modify metrics and parameters for advertisement\n"
+ "Modify metric coefficients\n"
+ "K1\n"
+ "K2\n"
+ "K3\n"
+ "K4\n"
+ "K5\n")
+{
+ //struct eigrp *eigrp = vty->index;
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_metric_weights,
+ no_eigrp_metric_weights_cmd,
+ "no metric weights <0-255> <0-255> <0-255> <0-255> <0-255>",
+ NO_STR
+ "Modify metrics and parameters for advertisement\n"
+ "Modify metric coefficients\n"
+ "K1\n"
+ "K2\n"
+ "K3\n"
+ "K4\n"
+ "K5\n")
+{
+ //struct eigrp *eigrp = vty->index;
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (eigrp_network,
+ eigrp_network_cmd,
+ "network A.B.C.D/M",
+ "Enable routing on an IP network\n"
+ "EIGRP network prefix\n")
+{
+ VTY_DECLVAR_CONTEXT(eigrp, eigrp)
+ struct prefix_ipv4 p;
+ int ret;
+
+ VTY_GET_IPV4_PREFIX ("network prefix", p, argv[1]->arg);
+
+ ret = eigrp_network_set (eigrp, &p);
+
+ if (ret == 0)
+ {
+ vty_out (vty, "There is already same network statement.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_network,
+ no_eigrp_network_cmd,
+ "no network A.B.C.D/M",
+ NO_STR
+ "Disable routing on an IP network\n"
+ "EIGRP network prefix\n")
+{
+ VTY_DECLVAR_CONTEXT(eigrp, eigrp);
+ struct prefix_ipv4 p;
+ int ret;
+
+ VTY_GET_IPV4_PREFIX ("network prefix", p, argv[2]->arg);
+
+ ret = eigrp_network_unset (eigrp, &p);
+
+ if (ret == 0)
+ {
+ vty_out (vty,"Can't find specified network configuration.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (eigrp_neighbor,
+ eigrp_neighbor_cmd,
+ "neighbor A.B.C.D <" INT_TYPES_CMD_STR ">",
+ "Specify a neighbor router\n"
+ "Neighbor address\n"
+ INT_TYPES_DESC)
+{
+ //struct eigrp *eigrp = vty->index;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_neighbor,
+ no_eigrp_neighbor_cmd,
+ "no neighbor A.B.C.D <" INT_TYPES_CMD_STR ">",
+ NO_STR
+ "Specify a neighbor router\n"
+ "Neighbor address\n"
+ INT_TYPES_DESC)
+{
+ //struct eigrp *eigrp = vty->index;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_eigrp_topology,
+ show_ip_eigrp_topology_cmd,
+ "show ip eigrp topology",
+ SHOW_STR
+ IP_STR
+ "IP-EIGRP show commands\n"
+ "IP-EIGRP topology\n")
+{
+ struct eigrp *eigrp;
+ struct listnode *node, *nnode, *node2, *nnode2;
+ struct eigrp_prefix_entry *tn;
+ struct eigrp_neighbor_entry *te;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ show_ip_eigrp_topology_header (vty, eigrp);
+
+ for (ALL_LIST_ELEMENTS (eigrp->topology_table, node, nnode, tn))
+ {
+ show_ip_eigrp_prefix_entry (vty,tn);
+ for (ALL_LIST_ELEMENTS (tn->entries, node2, nnode2, te))
+ {
+ if (((te->flags & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG) == EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)||
+ ((te->flags & EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG) == EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG))
+ show_ip_eigrp_neighbor_entry (vty, eigrp, te);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_eigrp_topology_all_links,
+ show_ip_eigrp_topology_all_links_cmd,
+ "show ip eigrp topology all-links",
+ SHOW_STR
+ IP_STR
+ "IP-EIGRP show commands\n"
+ "IP-EIGRP topology\n"
+ "Show all links in topology table\n")
+{
+ struct eigrp *eigrp;
+ struct listnode *node, *nnode, *node2, *nnode2;
+ struct eigrp_prefix_entry *tn;
+ struct eigrp_neighbor_entry *te;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ show_ip_eigrp_topology_header (vty, eigrp);
+
+ for (ALL_LIST_ELEMENTS (eigrp->topology_table, node, nnode, tn))
+ {
+ show_ip_eigrp_prefix_entry (vty,tn);
+ for (ALL_LIST_ELEMENTS (tn->entries, node2, nnode2, te))
+ {
+ show_ip_eigrp_neighbor_entry (vty, eigrp, te);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (show_ip_eigrp_topology,
+ show_ip_eigrp_topology_detail_cmd,
+ "show ip eigrp topology <A.B.C.D|A.B.C.D/M|detail|summary>",
+ SHOW_STR
+ IP_STR
+ "IP-EIGRP show commands\n"
+ "IP-EIGRP topology\n"
+ "Netwok to display information about\n"
+ "IP prefix <network>/<length>, e.g., 192.168.0.0/16\n"
+ "Show all links in topology table\n"
+ "Show a summary of the topology table\n")
+
+DEFUN (show_ip_eigrp_interfaces,
+ show_ip_eigrp_interfaces_cmd,
+ "show ip eigrp interfaces",
+ SHOW_STR
+ IP_STR
+ "IP-EIGRP show commands\n"
+ "IP-EIGRP interfaces\n")
+{
+ struct eigrp_interface *ei;
+ struct eigrp *eigrp;
+ struct listnode *node;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ if (!argc)
+ {
+ show_ip_eigrp_interface_header (vty, eigrp);
+ }
+
+ int idx = 0;
+ for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+ {
+ if (argv_find (argv, argc, "detail", &idx))
+ {
+ show_ip_eigrp_interface_header (vty, eigrp);
+ }
+
+ // if ((strncmp (argv[1], "f", 1) == 0 && strncmp (eigrp_if_name_string (ei), "F",1) == 0) ||
+ // (strncmp (argv[1], "l", 1) == 0 && strncmp (eigrp_if_name_string (ei), "L",1) == 0) ||
+ // (strncmp (argv[1], "s", 1) == 0 && strncmp (eigrp_if_name_string (ei), "S",1) == 0))
+ // {
+ show_ip_eigrp_interface_sub (vty, eigrp, ei);
+ //}
+ idx = 0;
+ if (argv_find (argv, argc, "detail", &idx))
+ {
+ show_ip_eigrp_interface_detail (vty, eigrp, ei);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (show_ip_eigrp_interfaces,
+ show_ip_eigrp_interfaces_detail_cmd,
+ "show ip eigrp interfaces <" INT_TYPES_CMD_STR ">",
+ SHOW_STR
+ IP_STR
+ "IP-EIGRP show commands\n"
+ "IP-EIGRP interfaces\n"
+ INT_TYPES_DESC)
+
+DEFUN (show_ip_eigrp_neighbors,
+ show_ip_eigrp_neighbors_cmd,
+ "show ip eigrp neighbors",
+ SHOW_STR
+ IP_STR
+ "IP-EIGRP show commands\n"
+ "IP-EIGRP neighbors\n")
+{
+ struct eigrp *eigrp;
+ struct eigrp_interface *ei;
+ struct listnode *node, *node2, *nnode2;
+ struct eigrp_neighbor *nbr;
+ int detail = FALSE;
+ int idx = 0;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ detail = (argv_find(argv, argc, "detail", &idx));
+ show_ip_eigrp_neighbor_header (vty, eigrp);
+
+ for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+ {
+ for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
+ {
+ if (detail || (nbr->state == EIGRP_NEIGHBOR_UP))
+ show_ip_eigrp_neighbor_sub (vty, nbr, detail);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (show_ip_eigrp_neighbors,
+ show_ip_eigrp_neighbors_detail_cmd,
+ "show ip eigrp neighbors <" INT_TYPES_CMD_STR ">",
+ SHOW_STR
+ IP_STR
+ "IP-EIGRP show commands\n"
+ "IP-EIGRP neighbors\n"
+ INT_TYPES_DESC)
+
+DEFUN (eigrp_if_delay,
+ eigrp_if_delay_cmd,
+ "delay (1-16777215)",
+ "Specify interface throughput delay\n"
+ "Throughput delay (tens of microseconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct eigrp *eigrp;
+ u_int32_t delay;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+ }
+
+ delay = atoi (argv[1]->arg);
+
+ IF_DEF_PARAMS (ifp)->delay = delay;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_if_delay,
+ no_eigrp_if_delay_cmd,
+ "no delay (1-16777215)",
+ NO_STR
+ "Specify interface throughput delay\n"
+ "Throughput delay (tens of microseconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+ }
+
+ IF_DEF_PARAMS (ifp)->delay = EIGRP_DELAY_DEFAULT;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (eigrp_if_bandwidth,
+ eigrp_if_bandwidth_cmd,
+ "bandwidth (1-10000000)",
+ "Set bandwidth informational parameter\n"
+ "Bandwidth in kilobits\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ u_int32_t bandwidth;
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ bandwidth = atoi (argv[1]->arg);
+
+ IF_DEF_PARAMS (ifp)->bandwidth = bandwidth;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_if_bandwidth,
+ no_eigrp_if_bandwidth_cmd,
+ "bandwidth (1-10000000)",
+ "Set bandwidth informational parameter\n"
+ "Bandwidth in kilobits\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ u_int32_t bandwidth;
+ struct eigrp *eigrp;
+ struct eigrp_interface *ei;
+ struct listnode *node, *nnode, *node2, *nnode2;
+ struct eigrp_prefix_entry *pe;
+ struct eigrp_neighbor_entry *ne;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ bandwidth = atoi (argv[1]->arg);
+
+ IF_DEF_PARAMS (ifp)->bandwidth = bandwidth;
+
+ for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+ {
+ if (ei->ifp == ifp)
+ break;
+ }
+
+ for (ALL_LIST_ELEMENTS (eigrp->topology_table, node, nnode, pe))
+ {
+ for (ALL_LIST_ELEMENTS (pe->entries, node2, nnode2, ne))
+ {
+ if (ne->ei == ei)
+ break;
+ /*TODO: */
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (eigrp_if_ip_hellointerval,
+ eigrp_if_ip_hellointerval_cmd,
+ "ip hello-interval eigrp (1-65535)",
+ "Interface Internet Protocol config commands\n"
+ "Configures EIGRP hello interval\n"
+ "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
+ "Seconds between hello transmissions\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ u_int32_t hello;
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ hello = atoi (argv[3]->arg);
+
+ IF_DEF_PARAMS (ifp)->v_hello = hello;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_if_ip_hellointerval,
+ no_eigrp_if_ip_hellointerval_cmd,
+ "no ip hello-interval eigrp (1-65535)",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "Configures EIGRP hello interval\n"
+ "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
+ "Seconds between hello transmissions\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ IF_DEF_PARAMS (ifp)->v_hello = EIGRP_HELLO_INTERVAL_DEFAULT;
+
+ return CMD_SUCCESS;
+}
+
+
+
+DEFUN (eigrp_if_ip_holdinterval,
+ eigrp_if_ip_holdinterval_cmd,
+ "ip hold-time eigrp (1-65535)",
+ "Interface Internet Protocol config commands\n"
+ "Configures EIGRP hello interval\n"
+ "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
+ "Seconds before neighbor is considered down\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ u_int32_t hold;
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ hold = atoi (argv[3]->arg);
+
+ IF_DEF_PARAMS (ifp)->v_wait = hold;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (eigrp_ip_summary_address,
+ eigrp_ip_summary_address_cmd,
+ "ip summary-address eigrp (1-65535) A.B.C.D/M",
+ "Interface Internet Protocol config commands\n"
+ "Perform address summarization\n"
+ "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
+ "AS number\n"
+ "Summary <network>/<length>, e.g. 192.168.0.0/16\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ u_int32_t AS;
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ AS = atoi (argv[3]->arg);
+
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_ip_summary_address,
+ no_eigrp_ip_summary_address_cmd,
+ "no ip summary-address eigrp (1-65535) A.B.C.D/M",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "Perform address summarization\n"
+ "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
+ "AS number\n"
+ "Summary <network>/<length>, e.g. 192.168.0.0/16\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ u_int32_t AS;
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ AS = atoi (argv[4]->arg);
+
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+
+
+DEFUN (no_eigrp_if_ip_holdinterval,
+ no_eigrp_if_ip_holdinterval_cmd,
+ "no ip hold-time eigrp",
+ "No"
+ "Interface Internet Protocol config commands\n"
+ "Configures EIGRP hello interval\n"
+ "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
+ "Seconds before neighbor is considered down\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ IF_DEF_PARAMS (ifp)->v_wait = EIGRP_HOLD_INTERVAL_DEFAULT;
+
+ return CMD_SUCCESS;
+}
+
+static int
+str2auth_type (const char *str, struct interface *ifp)
+{
+ /* Sanity check. */
+ if (str == NULL)
+ return CMD_WARNING;
+
+ if(strncmp(str, "md5",3) == 0)
+ {
+ IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_MD5;
+ return CMD_SUCCESS;
+ }
+ else if(strncmp(str, "hmac-sha-256",12) == 0)
+ {
+ IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_SHA256;
+ return CMD_SUCCESS;
+ }
+
+ return CMD_WARNING;
+
+}
+
+DEFUN (eigrp_authentication_mode,
+ eigrp_authentication_mode_cmd,
+ "ip authentication mode eigrp (1-65535) <md5|hmac-sha-256>",
+ "Interface Internet Protocol config commands\n"
+ "Authentication subcommands\n"
+ "Mode\n"
+ "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
+ "Autonomous system number\n"
+ "Keyed message digest\n"
+ "HMAC SHA256 algorithm \n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+// if(strncmp(argv[2], "md5",3))
+// IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_MD5;
+// else if(strncmp(argv[2], "hmac-sha-256",12))
+// IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_SHA256;
+
+ return str2auth_type(argv[5]->arg, ifp);
+}
+
+DEFUN (no_eigrp_authentication_mode,
+ no_eigrp_authentication_mode_cmd,
+ "no ip authentication mode eigrp (1-65535) <md5|hmac-sha-256>",
+ "Disable\n"
+ "Interface Internet Protocol config commands\n"
+ "Authentication subcommands\n"
+ "Mode\n"
+ "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
+ "Autonomous system number\n"
+ "Keyed message digest\n"
+ "HMAC SHA256 algorithm \n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_NONE;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (eigrp_authentication_keychain,
+ eigrp_authentication_keychain_cmd,
+ "ip authentication key-chain eigrp (1-65535) WORD",
+ "Interface Internet Protocol config commands\n"
+ "Authentication subcommands\n"
+ "Key-chain\n"
+ "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
+ "Autonomous system number\n"
+ "Name of key-chain\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct eigrp *eigrp;
+ struct keychain *keychain;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ keychain = keychain_lookup (argv[4]->arg);
+ if(keychain != NULL)
+ {
+ if(IF_DEF_PARAMS (ifp)->auth_keychain)
+ {
+ free (IF_DEF_PARAMS (ifp)->auth_keychain);
+ IF_DEF_PARAMS (ifp)->auth_keychain = strdup(keychain->name);
+ }
+ else
+ IF_DEF_PARAMS (ifp)->auth_keychain = strdup(keychain->name);
+ }
+ else
+ vty_out(vty,"Key chain with specified name not found%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_authentication_keychain,
+ no_eigrp_authentication_keychain_cmd,
+ "no ip authentication key-chain eigrp (1-65535) WORD",
+ "Disable\n"
+ "Interface Internet Protocol config commands\n"
+ "Authentication subcommands\n"
+ "Key-chain\n"
+ "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
+ "Autonomous system number\n"
+ "Name of key-chain\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ if((IF_DEF_PARAMS (ifp)->auth_keychain != NULL) && (strcmp(IF_DEF_PARAMS (ifp)->auth_keychain,argv[5]->arg)==0))
+ {
+ free (IF_DEF_PARAMS (ifp)->auth_keychain);
+ IF_DEF_PARAMS (ifp)->auth_keychain = NULL;
+ }
+ else
+ vty_out(vty,"Key chain with specified name not configured on interface%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (eigrp_redistribute_source_metric,
+ eigrp_redistribute_source_metric_cmd,
+ "redistribute " FRR_REDIST_STR_EIGRPD
+ " metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)",
+ REDIST_STR
+ FRR_REDIST_HELP_STR_EIGRPD
+ "Metric for redistributed routes\n"
+ "Bandwidth metric in Kbits per second\n"
+ "EIGRP delay metric, in 10 microsecond units\n"
+ "EIGRP reliability metric where 255 is 100% reliable2 ?\n"
+ "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n"
+ "EIGRP MTU of the path\n")
+{
+ VTY_DECLVAR_CONTEXT(eigrp, eigrp);
+ struct eigrp_metrics metrics_from_command = { 0 };
+ int source;
+ int idx = 0;
+
+ /* Get distribute source. */
+ argv_find (argv, argc, "redistribute", &idx);
+ source = proto_redistnum(AFI_IP, argv[idx+1]->arg);
+ if (source < 0 )
+ return CMD_WARNING;
+
+ /* Get metrics values */
+
+ return eigrp_redistribute_set (eigrp, source, metrics_from_command);
+}
+
+
+DEFUN (no_eigrp_redistribute_source_metric,
+ no_eigrp_redistribute_source_metric_cmd,
+ "no redistribute " FRR_REDIST_STR_EIGRPD
+ " metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)",
+ "Disable\n"
+ REDIST_STR
+ FRR_REDIST_HELP_STR_EIGRPD
+ "Metric for redistributed routes\n"
+ "Bandwidth metric in Kbits per second\n"
+ "EIGRP delay metric, in 10 microsecond units\n"
+ "EIGRP reliability metric where 255 is 100% reliable2 ?\n"
+ "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n"
+ "EIGRP MTU of the path\n")
+{
+ VTY_DECLVAR_CONTEXT(eigrp, eigrp);
+ int source;
+ int idx = 0;
+
+ /* Get distribute source. */
+ argv_find (argv, argc, "redistribute", &idx);
+ source = proto_redistnum(AFI_IP, argv[idx+1]->arg);
+ if (source < 0 )
+ return CMD_WARNING;
+
+ /* Get metrics values */
+
+ return eigrp_redistribute_unset (eigrp, source);
+}
+
+DEFUN (eigrp_variance,
+ eigrp_variance_cmd,
+ "variance (1-128)",
+ "Control load balancing variance\n"
+ "Metric variance multiplier\n")
+{
+ struct eigrp *eigrp;
+ u_char variance;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+ variance = atoi(argv[1]->arg);
+
+ eigrp->variance = variance;
+
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (no_eigrp_variance,
+ no_eigrp_variance_cmd,
+ "no variance (1-128)",
+ "Disable\n"
+ "Control load balancing variance\n"
+ "Metric variance multiplier\n")
+{
+ struct eigrp *eigrp;
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ eigrp->variance = EIGRP_VARIANCE_DEFAULT;
+
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (eigrp_maximum_paths,
+ eigrp_maximum_paths_cmd,
+ "maximum-paths (1-32)",
+ "Forward packets over multiple paths\n"
+ "Number of paths\n")
+{
+ struct eigrp *eigrp;
+ u_char max;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ max = atoi(argv[1]->arg);
+
+ eigrp->max_paths = max;
+
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (no_eigrp_maximum_paths,
+ no_eigrp_maximum_paths_cmd,
+ "no maximum-paths <1-32>",
+ NO_STR
+ "Forward packets over multiple paths\n"
+ "Number of paths\n")
+{
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ eigrp->max_paths = EIGRP_MAX_PATHS_DEFAULT;
+
+ /*TODO: */
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Execute hard restart for all neighbors
+ */
+DEFUN (clear_ip_eigrp_neighbors,
+ clear_ip_eigrp_neighbors_cmd,
+ "clear ip eigrp neighbors",
+ CLEAR_STR
+ IP_STR
+ "Clear IP-EIGRP\n"
+ "Clear IP-EIGRP neighbors\n")
+{
+ struct eigrp *eigrp;
+ struct eigrp_interface *ei;
+ struct listnode *node, *node2, *nnode2;
+ struct eigrp_neighbor *nbr;
+
+ /* Check if eigrp process is enabled */
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ /* iterate over all eigrp interfaces */
+ for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+ {
+ /* send Goodbye Hello */
+ eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL);
+
+ /* iterate over all neighbors on eigrp interface */
+ for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
+ {
+ if (nbr->state != EIGRP_NEIGHBOR_DOWN)
+ {
+ zlog_debug ("Neighbor %s (%s) is down: manually cleared",
+ inet_ntoa (nbr->src),
+ ifindex2ifname (nbr->ei->ifp->ifindex));
+ vty_time_print (vty, 0);
+ vty_out (vty, "Neighbor %s (%s) is down: manually cleared%s",
+ inet_ntoa (nbr->src),
+ ifindex2ifname (nbr->ei->ifp->ifindex),
+ VTY_NEWLINE);
+
+ /* set neighbor to DOWN */
+ nbr->state = EIGRP_NEIGHBOR_DOWN;
+ /* delete neighbor */
+ eigrp_nbr_delete (nbr);
+ }
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Execute hard restart for all neighbors on interface
+ */
+DEFUN (clear_ip_eigrp_neighbors_int,
+ clear_ip_eigrp_neighbors_int_cmd,
+ "clear ip eigrp neighbors IFNAME",
+ CLEAR_STR
+ IP_STR
+ "Clear IP-EIGRP\n"
+ "Clear IP-EIGRP neighbors\n"
+ "Interface's name\n")
+{
+ struct eigrp *eigrp;
+ struct eigrp_interface *ei;
+ struct listnode *node2, *nnode2;
+ struct eigrp_neighbor *nbr;
+ int idx = 0;
+
+ /* Check if eigrp process is enabled */
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ /* lookup interface by specified name */
+ argv_find(argv, argc, "IFNAME", &idx);
+ ei = eigrp_if_lookup_by_name(eigrp, argv[idx]->arg);
+ if(ei == NULL)
+ {
+ vty_out (vty, " Interface (%s) doesn't exist%s", argv[idx]->arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* send Goodbye Hello */
+ eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL);
+
+ /* iterate over all neighbors on eigrp interface */
+ for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
+ {
+ if (nbr->state != EIGRP_NEIGHBOR_DOWN)
+ {
+ zlog_debug ("Neighbor %s (%s) is down: manually cleared",
+ inet_ntoa (nbr->src),
+ ifindex2ifname (nbr->ei->ifp->ifindex));
+ vty_time_print (vty, 0);
+ vty_out (vty, "Neighbor %s (%s) is down: manually cleared%s",
+ inet_ntoa (nbr->src),
+ ifindex2ifname (nbr->ei->ifp->ifindex),
+ VTY_NEWLINE);
+
+ /* set neighbor to DOWN */
+ nbr->state = EIGRP_NEIGHBOR_DOWN;
+ /* delete neighbor */
+ eigrp_nbr_delete (nbr);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Execute hard restart for neighbor specified by IP
+ */
+DEFUN (clear_ip_eigrp_neighbors_IP,
+ clear_ip_eigrp_neighbors_IP_cmd,
+ "clear ip eigrp neighbors A.B.C.D",
+ CLEAR_STR
+ IP_STR
+ "Clear IP-EIGRP\n"
+ "Clear IP-EIGRP neighbors\n"
+ "IP-EIGRP neighbor address\n")
+{
+ struct eigrp *eigrp;
+ struct eigrp_neighbor *nbr;
+ struct in_addr nbr_addr;
+
+ VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[4]->arg);
+
+ /* Check if eigrp process is enabled */
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ /* lookup neighbor in whole process */
+ nbr = eigrp_nbr_lookup_by_addr_process(eigrp, nbr_addr);
+
+ /* if neighbor doesn't exists, notify user and exit */
+ if(nbr == NULL)
+ {
+ vty_out (vty, "Neighbor with entered address doesn't exists.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* execute hard reset on neighbor */
+ eigrp_nbr_hard_restart(nbr, vty);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Execute graceful restart for all neighbors
+ */
+DEFUN (clear_ip_eigrp_neighbors_soft,
+ clear_ip_eigrp_neighbors_soft_cmd,
+ "clear ip eigrp neighbors soft",
+ CLEAR_STR
+ IP_STR
+ "Clear IP-EIGRP\n"
+ "Clear IP-EIGRP neighbors\n"
+ "Resync with peers without adjacency reset\n")
+{
+ struct eigrp *eigrp;
+
+ /* Check if eigrp process is enabled */
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ /* execute graceful restart on all neighbors */
+ eigrp_update_send_process_GR(eigrp, EIGRP_GR_MANUAL, vty);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Execute graceful restart for all neighbors on interface
+ */
+DEFUN (clear_ip_eigrp_neighbors_int_soft,
+ clear_ip_eigrp_neighbors_int_soft_cmd,
+ "clear ip eigrp neighbors IFNAME soft",
+ CLEAR_STR
+ IP_STR
+ "Clear IP-EIGRP\n"
+ "Clear IP-EIGRP neighbors\n"
+ "Interface's name\n"
+ "Resync with peer without adjacency reset\n")
+{
+ struct eigrp *eigrp;
+ struct eigrp_interface *ei;
+
+ /* Check if eigrp process is enabled */
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ /* lookup interface by specified name */
+ ei = eigrp_if_lookup_by_name(eigrp, argv[4]->arg);
+ if(ei == NULL)
+ {
+ vty_out (vty, " Interface (%s) doesn't exist%s", argv[4]->arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* execute graceful restart for all neighbors on interface */
+ eigrp_update_send_interface_GR(ei, EIGRP_GR_MANUAL, vty);
+ return CMD_SUCCESS;
+}
+
+/*
+ * Execute graceful restart for neighbor specified by IP
+ */
+DEFUN (clear_ip_eigrp_neighbors_IP_soft,
+ clear_ip_eigrp_neighbors_IP_soft_cmd,
+ "clear ip eigrp neighbors A.B.C.D soft",
+ CLEAR_STR
+ IP_STR
+ "Clear IP-EIGRP\n"
+ "Clear IP-EIGRP neighbors\n"
+ "IP-EIGRP neighbor address\n"
+ "Resync with peer without adjacency reset\n")
+{
+ struct eigrp *eigrp;
+ struct eigrp_neighbor *nbr;
+ struct in_addr nbr_addr;
+
+ VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[4]->arg);
+
+ /* Check if eigrp process is enabled */
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ {
+ vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ /* lookup neighbor in whole process */
+ nbr = eigrp_nbr_lookup_by_addr_process(eigrp, nbr_addr);
+
+ /* if neighbor doesn't exists, notify user and exit */
+ if(nbr == NULL)
+ {
+ vty_out (vty, "Neighbor with entered address doesn't exists.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* execute graceful restart on neighbor */
+ eigrp_update_send_GR(nbr, EIGRP_GR_MANUAL, vty);
+
+ return CMD_SUCCESS;
+}
+
+static struct cmd_node eigrp_node =
+{
+ EIGRP_NODE,
+ "%s(config-router)# ",
+ 1
+};
+
+/* Save EIGRP configuration */
+static int
+eigrp_config_write (struct vty *vty)
+{
+ struct eigrp *eigrp;
+
+ int write = 0;
+
+ eigrp = eigrp_lookup ();
+ if (eigrp != NULL)
+ {
+ /* Writes 'router eigrp' section to config */
+ config_write_eigrp_router (vty, eigrp);
+
+ /* Interface config print */
+ config_write_interfaces (vty, eigrp);
+//
+// /* static neighbor print. */
+// config_write_eigrp_nbr_nbma (vty, eigrp);
+//
+// /* Virtual-Link print. */
+// config_write_virtual_link (vty, eigrp);
+//
+// /* Default metric configuration. */
+// config_write_eigrp_default_metric (vty, eigrp);
+//
+// /* Distribute-list and default-information print. */
+// config_write_eigrp_distribute (vty, eigrp);
+//
+// /* Distance configuration. */
+// config_write_eigrp_distance (vty, eigrp)
+ }
+
+ return write;
+}
+
+void
+eigrp_vty_show_init (void)
+{
+ install_element (VIEW_NODE, &show_ip_eigrp_interfaces_cmd);
+
+ install_element (VIEW_NODE, &show_ip_eigrp_neighbors_cmd);
+
+ install_element (VIEW_NODE, &show_ip_eigrp_topology_cmd);
+
+ install_element (VIEW_NODE, &show_ip_eigrp_neighbors_detail_cmd);
+
+ install_element (VIEW_NODE, &show_ip_eigrp_interfaces_detail_cmd);
+
+ install_element (VIEW_NODE, &show_ip_eigrp_topology_all_links_cmd);
+
+ install_element (VIEW_NODE, &show_ip_eigrp_topology_detail_cmd);
+
+}
+
+/* eigrpd's interface node. */
+static struct cmd_node eigrp_interface_node =
+{
+ INTERFACE_NODE,
+ "%s(config-if)# ",
+ 1
+};
+
+void
+eigrp_vty_if_init (void)
+{
+ install_node (&eigrp_interface_node, eigrp_write_interface);
+ if_cmd_init();
+
+ /* Delay and bandwidth configuration commands*/
+ install_element (INTERFACE_NODE, &eigrp_if_delay_cmd);
+ install_element (INTERFACE_NODE, &no_eigrp_if_delay_cmd);
+ install_element (INTERFACE_NODE, &eigrp_if_bandwidth_cmd);
+ install_element (INTERFACE_NODE, &no_eigrp_if_bandwidth_cmd);
+
+ /*Hello-interval and hold-time interval configuration commands*/
+ install_element (INTERFACE_NODE, &eigrp_if_ip_holdinterval_cmd);
+ install_element (INTERFACE_NODE, &no_eigrp_if_ip_holdinterval_cmd);
+ install_element (INTERFACE_NODE, &eigrp_if_ip_hellointerval_cmd);
+ install_element (INTERFACE_NODE, &no_eigrp_if_ip_hellointerval_cmd);
+
+ /* "Authentication configuration commands */
+ install_element (INTERFACE_NODE, &eigrp_authentication_mode_cmd);
+ install_element (INTERFACE_NODE, &no_eigrp_authentication_mode_cmd);
+ install_element (INTERFACE_NODE, &eigrp_authentication_keychain_cmd);
+ install_element (INTERFACE_NODE, &no_eigrp_authentication_keychain_cmd);
+
+ /*EIGRP Summarization commands*/
+ install_element (INTERFACE_NODE, &eigrp_ip_summary_address_cmd);
+ install_element (INTERFACE_NODE, &no_eigrp_ip_summary_address_cmd);
+
+
+}
+
+static void
+eigrp_vty_zebra_init (void)
+{
+ install_element (EIGRP_NODE, &eigrp_redistribute_source_metric_cmd);
+ install_element (EIGRP_NODE, &no_eigrp_redistribute_source_metric_cmd);
+
+}
+
+/* Install EIGRP related vty commands. */
+void
+eigrp_vty_init (void)
+{
+ install_node (&eigrp_node, eigrp_config_write);
+
+ install_default (EIGRP_NODE);
+
+ install_element (CONFIG_NODE, &router_eigrp_cmd);
+ install_element (CONFIG_NODE, &no_router_eigrp_cmd);
+ install_element (EIGRP_NODE, &eigrp_network_cmd);
+ install_element (EIGRP_NODE, &no_eigrp_network_cmd);
+ install_element (EIGRP_NODE, &eigrp_variance_cmd);
+ install_element (EIGRP_NODE, &no_eigrp_variance_cmd);
+ install_element (EIGRP_NODE, &eigrp_router_id_cmd);
+ install_element (EIGRP_NODE, &no_eigrp_router_id_cmd);
+ install_element (EIGRP_NODE, &eigrp_passive_interface_cmd);
+ install_element (EIGRP_NODE, &no_eigrp_passive_interface_cmd);
+ install_element (EIGRP_NODE, &eigrp_timers_active_cmd);
+ install_element (EIGRP_NODE, &no_eigrp_timers_active_cmd);
+ install_element (EIGRP_NODE, &eigrp_metric_weights_cmd);
+ install_element (EIGRP_NODE, &no_eigrp_metric_weights_cmd);
+ install_element (EIGRP_NODE, &eigrp_maximum_paths_cmd);
+ install_element (EIGRP_NODE, &no_eigrp_maximum_paths_cmd);
+ install_element (EIGRP_NODE, &eigrp_neighbor_cmd);
+ install_element (EIGRP_NODE, &no_eigrp_neighbor_cmd);
+
+ /* commands for manual hard restart */
+ install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_cmd);
+ install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_int_cmd);
+ install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_IP_cmd);
+ /* commands for manual graceful restart */
+ install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_soft_cmd);
+ install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_int_soft_cmd);
+ install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_IP_soft_cmd);
+
+ eigrp_vty_zebra_init ();
+}
diff --git a/eigrpd/eigrp_vty.h b/eigrpd/eigrp_vty.h
new file mode 100644
index 000000000..56a40263f
--- /dev/null
+++ b/eigrpd/eigrp_vty.h
@@ -0,0 +1,42 @@
+/*
+ * EIGRP VTY Interface.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ * Frantisek Gazo
+ * Tomas Hvorkovy
+ * Martin Kontsek
+ * Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _QUAGGA_EIGRP_VTY_H
+#define _QUAGGA_EIGRP_VTY_H
+
+
+/* Prototypes. */
+extern void eigrp_vty_init (void);
+extern void eigrp_vty_show_init (void);
+extern void eigrp_vty_if_init (void);
+
+#endif /* _Quagga_EIGRP_VTY_H_ */
diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c
new file mode 100644
index 000000000..aef720898
--- /dev/null
+++ b/eigrpd/eigrp_zebra.c
@@ -0,0 +1,579 @@
+/*
+ * Zebra connect library for EIGRP.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "command.h"
+#include "network.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "table.h"
+#include "stream.h"
+#include "memory.h"
+#include "zclient.h"
+#include "filter.h"
+#include "plist.h"
+#include "log.h"
+#include "nexthop.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+
+static int eigrp_interface_add (int , struct zclient *, zebra_size_t, vrf_id_t);
+static int eigrp_interface_delete (int , struct zclient *,
+ zebra_size_t, vrf_id_t);
+static int eigrp_interface_address_add (int, struct zclient *,
+ zebra_size_t, vrf_id_t vrf_id);
+static int eigrp_interface_address_delete (int, struct zclient *,
+ zebra_size_t, vrf_id_t vrf_id);
+static int eigrp_interface_state_up (int, struct zclient *,
+ zebra_size_t, vrf_id_t vrf_id);
+static int eigrp_interface_state_down (int, struct zclient *,
+ zebra_size_t, vrf_id_t vrf_id);
+static struct interface * zebra_interface_if_lookup (struct stream *);
+
+static int eigrp_zebra_read_ipv4 (int , struct zclient *,
+ zebra_size_t, vrf_id_t vrf_id);
+
+/* Zebra structure to hold current status. */
+struct zclient *zclient = NULL;
+
+/* For registering threads. */
+extern struct thread_master *master;
+struct in_addr router_id_zebra;
+
+/* Router-id update message from zebra. */
+static int
+eigrp_router_id_update_zebra (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct eigrp *eigrp;
+ struct prefix router_id;
+ zebra_router_id_update_read (zclient->ibuf,&router_id);
+
+ router_id_zebra = router_id.u.prefix4;
+
+ eigrp = eigrp_lookup ();
+
+ if (eigrp != NULL)
+ eigrp_router_id_update (eigrp);
+
+ return 0;
+}
+
+
+void
+eigrp_zebra_init (void)
+{
+ zclient = zclient_new (master);
+
+ zclient_init (zclient, ZEBRA_ROUTE_EIGRP, 0);
+ zclient->router_id_update = eigrp_router_id_update_zebra;
+ zclient->interface_add = eigrp_interface_add;
+ zclient->interface_delete = eigrp_interface_delete;
+ zclient->interface_up = eigrp_interface_state_up;
+ zclient->interface_down = eigrp_interface_state_down;
+ zclient->interface_address_add = eigrp_interface_address_add;
+ zclient->interface_address_delete = eigrp_interface_address_delete;
+ zclient->redistribute_route_ipv4_add = eigrp_zebra_read_ipv4;
+ zclient->redistribute_route_ipv4_del = eigrp_zebra_read_ipv4;
+}
+
+
+/* Zebra route add and delete treatment. */
+static int
+eigrp_zebra_read_ipv4 (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct stream *s;
+ struct zapi_ipv4 api;
+ struct prefix_ipv4 p;
+ struct eigrp *eigrp;
+
+ s = zclient->ibuf;
+
+ /* Type, flags, message. */
+ api.type = stream_getc (s);
+ api.instance = stream_getw (s);
+ api.flags = stream_getc (s);
+ api.message = stream_getc (s);
+
+ /* IPv4 prefix. */
+ memset (&p, 0, sizeof (struct prefix_ipv4));
+ p.family = AF_INET;
+ p.prefixlen = stream_getc (s);
+ stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+ if (IPV4_NET127(ntohl(p.prefix.s_addr)))
+ return 0;
+
+ /* Nexthop, ifindex, distance, metric. */
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+ {
+ api.nexthop_num = stream_getc (s);
+ stream_get_ipv4 (s);
+ }
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
+ {
+ api.ifindex_num = stream_getc (s);
+ /* XXX assert(api.ifindex_num == 1); */
+ stream_getl (s); /* ifindex, unused */
+ }
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+ api.distance = stream_getc (s);
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+ api.metric = stream_getl (s);
+
+ eigrp = eigrp_lookup ();
+ if (eigrp == NULL)
+ return 0;
+
+ if (command == ZEBRA_IPV4_ROUTE_ADD)
+ {
+
+ }
+ else /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */
+ {
+
+ }
+
+ return 0;
+}
+
+/* Inteface addition message from zebra. */
+static int
+eigrp_interface_add (int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+
+ ifp = zebra_interface_add_read (zclient->ibuf, vrf_id);
+
+ assert (ifp->info);
+
+ if (!EIGRP_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type))
+ {
+ SET_IF_PARAM (IF_DEF_PARAMS (ifp), type);
+ IF_DEF_PARAMS (ifp)->type = eigrp_default_iftype (ifp);
+ }
+
+ eigrp_if_update (ifp);
+
+ return 0;
+}
+
+static int
+eigrp_interface_delete (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ struct stream *s;
+ struct route_node *rn;
+
+ s = zclient->ibuf;
+ /* zebra_interface_state_read () updates interface structure in iflist */
+ ifp = zebra_interface_state_read (s, vrf_id);
+
+ if (ifp == NULL)
+ return 0;
+
+ if (if_is_up (ifp))
+ zlog_warn ("Zebra: got delete of %s, but interface is still up",
+ ifp->name);
+
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
+ zlog_debug("Zebra: interface delete %s index %d flags %llx metric %d mtu %d",
+ ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
+
+ for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+ if (rn->info)
+ eigrp_if_free ((struct eigrp_interface *) rn->info, INTERFACE_DOWN_BY_ZEBRA);
+
+ ifp->ifindex = IFINDEX_INTERNAL;
+ return 0;
+}
+
+static int
+eigrp_interface_address_add (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct connected *c;
+
+ c = zebra_interface_address_read (command, zclient->ibuf, vrf_id);
+
+ if (c == NULL)
+ return 0;
+
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
+ {
+ char buf[128];
+ prefix2str (c->address, buf, sizeof (buf));
+ zlog_debug ("Zebra: interface %s address add %s", c->ifp->name, buf);
+ }
+
+ eigrp_if_update (c->ifp);
+
+ return 0;
+}
+
+static int
+eigrp_interface_address_delete (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct connected *c;
+ struct interface *ifp;
+ struct eigrp_interface *ei;
+ struct route_node *rn;
+ struct prefix p;
+
+ c = zebra_interface_address_read (command, zclient->ibuf, vrf_id);
+
+ if (c == NULL)
+ return 0;
+
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
+ {
+ char buf[128];
+ prefix2str (c->address, buf, sizeof (buf));
+ zlog_debug ("Zebra: interface %s address delete %s", c->ifp->name, buf);
+ }
+
+ ifp = c->ifp;
+ p = *c->address;
+ p.prefixlen = IPV4_MAX_PREFIXLEN;
+
+ rn = route_node_lookup (IF_OIFS (ifp), &p);
+ if (!rn)
+ {
+ connected_free (c);
+ return 0;
+ }
+
+ assert (rn->info);
+ ei = rn->info;
+
+ /* Call interface hook functions to clean up */
+ eigrp_if_free (ei, INTERFACE_DOWN_BY_ZEBRA);
+
+ connected_free (c);
+
+ return 0;
+}
+
+static int
+eigrp_interface_state_up (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ struct eigrp_interface *ei;
+ struct route_node *rn;
+
+ ifp = zebra_interface_if_lookup (zclient->ibuf);
+
+ if (ifp == NULL)
+ return 0;
+
+ /* Interface is already up. */
+ if (if_is_operative (ifp))
+ {
+ /* Temporarily keep ifp values. */
+ struct interface if_tmp;
+ memcpy (&if_tmp, ifp, sizeof (struct interface));
+
+ zebra_interface_if_set_value (zclient->ibuf, ifp);
+
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
+ zlog_debug ("Zebra: Interface[%s] state update.", ifp->name);
+
+ if (if_tmp.bandwidth != ifp->bandwidth)
+ {
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
+ zlog_debug ("Zebra: Interface[%s] bandwidth change %d -> %d.",
+ ifp->name, if_tmp.bandwidth, ifp->bandwidth);
+
+// eigrp_if_recalculate_output_cost (ifp);
+ }
+
+ if (if_tmp.mtu != ifp->mtu)
+ {
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
+ zlog_debug ("Zebra: Interface[%s] MTU change %u -> %u.",
+ ifp->name, if_tmp.mtu, ifp->mtu);
+
+ /* Must reset the interface (simulate down/up) when MTU changes. */
+ eigrp_if_reset (ifp);
+ }
+ return 0;
+ }
+
+ zebra_interface_if_set_value (zclient->ibuf, ifp);
+
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
+ zlog_debug ("Zebra: Interface[%s] state change to up.", ifp->name);
+
+ for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
+ {
+ if ((ei = rn->info) == NULL)
+ continue;
+
+ eigrp_if_up (ei);
+ }
+
+ return 0;
+}
+
+static int
+eigrp_interface_state_down (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ struct eigrp_interface *ei;
+ struct route_node *node;
+
+ ifp = zebra_interface_state_read (zclient->ibuf, vrf_id);
+
+ if (ifp == NULL)
+ return 0;
+
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_INTERFACE))
+ zlog_debug ("Zebra: Interface[%s] state change to down.", ifp->name);
+
+ for (node = route_top (IF_OIFS (ifp)); node; node = route_next (node))
+ {
+ if ((ei = node->info) == NULL)
+ continue;
+ eigrp_if_down (ei);
+ }
+
+ return 0;
+}
+
+static struct interface *
+zebra_interface_if_lookup (struct stream *s)
+{
+ char ifname_tmp[INTERFACE_NAMSIZ];
+
+ /* Read interface name. */
+ stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
+
+ /* And look it up. */
+ return if_lookup_by_name_len (ifname_tmp,
+ strnlen (ifname_tmp, INTERFACE_NAMSIZ));
+}
+
+void
+eigrp_zebra_route_add (struct prefix_ipv4 *p, struct eigrp_neighbor_entry *te)
+{
+ u_char message;
+ u_char flags;
+ int psize;
+ struct stream *s;
+
+ if (zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP])
+ {
+ message = 0;
+ flags = 0;
+
+ /* EIGRP pass nexthop and metric */
+ SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP);
+ SET_FLAG (message, ZAPI_MESSAGE_METRIC);
+
+ /* Distance value. */
+// distance = eigrp_distance_apply (p, er);
+// if (distance)
+// SET_FLAG (message, ZAPI_MESSAGE_DISTANCE);
+
+ /* Make packet. */
+ s = zclient->obuf;
+ stream_reset (s);
+
+ /* Put command, type, flags, message. */
+ zclient_create_header (s, ZEBRA_IPV4_ROUTE_ADD, VRF_DEFAULT);
+ stream_putc (s, ZEBRA_ROUTE_EIGRP);
+ stream_putc (s, flags);
+ stream_putc (s, message);
+ stream_putw (s, SAFI_UNICAST);
+
+ /* Put prefix information. */
+ psize = PSIZE (p->prefixlen);
+ stream_putc (s, p->prefixlen);
+ stream_write (s, (u_char *) & p->prefix, psize);
+
+ /* Nexthop count. */
+ stream_putc (s, 1);
+
+ /* Nexthop, ifindex, distance and metric information. */
+ stream_putc (s, NEXTHOP_TYPE_IPV4_IFINDEX);
+ stream_put_in_addr (s, &te->adv_router->src);
+ stream_putl (s, te->ei->ifp->ifindex);
+
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
+ {
+ char buf[2][INET_ADDRSTRLEN];
+ zlog_debug ("Zebra: Route add %s/%d nexthop %s",
+ inet_ntop(AF_INET, &p->prefix, buf[0], sizeof (buf[0])),
+ p->prefixlen,
+ inet_ntop(AF_INET, 0 /*&p->nexthop*/, buf[1], sizeof (buf[1])));
+ }
+
+ stream_putl (s, te->distance);
+ stream_putw_at (s, 0, stream_get_endp (s));
+
+ zclient_send_message (zclient);
+ }
+}
+
+void
+eigrp_zebra_route_delete (struct prefix_ipv4 *p, struct eigrp_neighbor_entry *te)
+{
+ u_char message;
+ u_char flags;
+ int psize;
+ struct stream *s;
+
+ if (zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP])
+ {
+ message = 0;
+ flags = 0;
+ /* Make packet. */
+ s = zclient->obuf;
+ stream_reset (s);
+
+ /* Put command, type, flags, message. */
+ zclient_create_header (s, ZEBRA_IPV4_ROUTE_DELETE, VRF_DEFAULT);
+ stream_putc (s, ZEBRA_ROUTE_EIGRP);
+ stream_putc (s, flags);
+ stream_putc (s, message);
+ stream_putw (s, SAFI_UNICAST);
+
+ /* Put prefix information. */
+ psize = PSIZE (p->prefixlen);
+ stream_putc (s, p->prefixlen);
+ stream_write (s, (u_char *) & p->prefix, psize);
+
+ /* Nexthop count. */
+ stream_putc (s, 1);
+
+ /* Nexthop, ifindex, distance and metric information. */
+ stream_putc (s, NEXTHOP_TYPE_IPV4_IFINDEX);
+ stream_put_in_addr (s, &te->adv_router->src);
+ stream_putl (s, te->ei->ifp->ifindex);
+
+ if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
+ {
+ char buf[2][INET_ADDRSTRLEN];
+ zlog_debug ("Zebra: Route del %s/%d nexthop %s",
+ inet_ntop (AF_INET, &p->prefix, buf[0], sizeof (buf[0])),
+ p->prefixlen,
+ inet_ntop (AF_INET, 0 /*&p->nexthop*/, buf[1], sizeof (buf[1])));
+ }
+
+
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
+ {
+ stream_putl (s, te->distance);
+ }
+
+ stream_putw_at (s, 0, stream_get_endp (s));
+
+ zclient_send_message (zclient);
+ }
+}
+
+vrf_bitmap_t
+eigrp_is_type_redistributed (int type)
+{
+ return (DEFAULT_ROUTE_TYPE (type)) ?
+ zclient->default_information : zclient->redist[AFI_IP][type];
+}
+
+int
+eigrp_redistribute_set (struct eigrp *eigrp, int type, struct eigrp_metrics metric)
+{
+
+ if (eigrp_is_type_redistributed (type))
+ {
+ if (eigrp_metrics_is_same(&metric, &eigrp->dmetric[type]))
+ {
+ eigrp->dmetric[type] = metric;
+ }
+
+ eigrp_external_routes_refresh (eigrp, type);
+
+// if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE))
+// zlog_debug ("Redistribute[%s]: Refresh Type[%d], Metric[%d]",
+// eigrp_redist_string(type),
+// metric_type (eigrp, type), metric_value (eigrp, type));
+ return CMD_SUCCESS;
+ }
+
+ eigrp->dmetric[type] = metric;
+
+ zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient,
+ AFI_IP, type, 0, VRF_DEFAULT);
+
+// if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
+// zlog_debug ("Redistribute[%s]: Start Type[%d], Metric[%d]",
+// ospf_redist_string(type),
+// metric_type (ospf, type), metric_value (ospf, type));
+
+ ++eigrp->redistribute;
+
+ return CMD_SUCCESS;
+}
+
+int
+eigrp_redistribute_unset (struct eigrp *eigrp, int type)
+{
+
+ if (eigrp_is_type_redistributed (type))
+ {
+ memset(&eigrp->dmetric[type], 0, sizeof(struct eigrp_metrics));
+ zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient,
+ AFI_IP, type, 0, VRF_DEFAULT);
+ --eigrp->redistribute;
+ }
+
+// if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
+// zlog_debug ("Redistribute[%s]: Start Type[%d], Metric[%d]",
+// ospf_redist_string(type),
+// metric_type (ospf, type), metric_value (ospf, type));
+
+ return CMD_SUCCESS;
+}
+
diff --git a/eigrpd/eigrp_zebra.h b/eigrpd/eigrp_zebra.h
new file mode 100644
index 000000000..f1c8e62e7
--- /dev/null
+++ b/eigrpd/eigrp_zebra.h
@@ -0,0 +1,43 @@
+/*
+ * Zebra connect library for EIGRP.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_ZEBRA_H_
+#define _ZEBRA_EIGRP_ZEBRA_H_
+
+#include "vty.h"
+#include "vrf.h"
+
+extern void eigrp_zebra_init (void);
+
+extern void eigrp_zebra_route_add (struct prefix_ipv4 *, struct eigrp_neighbor_entry *);
+extern void eigrp_zebra_route_delete (struct prefix_ipv4 *, struct eigrp_neighbor_entry *);
+extern int eigrp_redistribute_set (struct eigrp *, int, struct eigrp_metrics);
+extern int eigrp_redistribute_unset (struct eigrp *, int);
+extern vrf_bitmap_t eigrp_is_type_redistributed (int);
+
+#endif /* _ZEBRA_EIGRP_ZEBRA_H_ */
diff --git a/eigrpd/eigrpd.c b/eigrpd/eigrpd.c
new file mode 100644
index 000000000..cb60db16c
--- /dev/null
+++ b/eigrpd/eigrpd.c
@@ -0,0 +1,310 @@
+/*
+ * EIGRP Daemon Program.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "vty.h"
+#include "command.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+#include "if.h"
+#include "memory.h"
+#include "stream.h"
+#include "log.h"
+#include "sockunion.h" /* for inet_aton () */
+#include "zclient.h"
+#include "plist.h"
+#include "sockopt.h"
+#include "keychain.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_memory.h"
+
+DEFINE_QOBJ_TYPE(eigrp)
+
+static struct eigrp_master eigrp_master;
+
+struct eigrp_master *eigrp_om;
+
+static void eigrp_finish_final(struct eigrp *);
+static void eigrp_delete(struct eigrp *);
+static struct eigrp *eigrp_new(const char *);
+static void eigrp_add(struct eigrp *);
+
+extern struct zclient *zclient;
+extern struct in_addr router_id_zebra;
+
+
+/*
+ * void eigrp_router_id_update(struct eigrp *eigrp)
+ *
+ * Description:
+ * update routerid associated with this instance of EIGRP.
+ * If the id changes, then call if_update for each interface
+ * to resync the topology database with all neighbors
+ *
+ * Select the router ID based on these priorities:
+ * 1. Statically assigned router ID is always the first choice.
+ * 2. If there is no statically assigned router ID, then try to stick
+ * with the most recent value, since changing router ID's is very
+ * disruptive.
+ * 3. Last choice: just go with whatever the zebra daemon recommends.
+ *
+ * Note:
+ * router id for EIGRP is really just a 32 bit number. Cisco historically
+ * displays it in dotted decimal notation, and will pickup an IP address
+ * from an interface so it can be 'auto-configed" to a uniqe value
+ *
+ * This does not work for IPv6, and to make the code simpler, its
+ * stored and processed internerall as a 32bit number
+ */
+void
+eigrp_router_id_update (struct eigrp *eigrp)
+{
+ struct interface *ifp;
+ struct listnode *node;
+ u_int32_t router_id, router_id_old;
+
+ router_id_old = eigrp->router_id;
+
+ if (eigrp->router_id_static != 0)
+ router_id = eigrp->router_id_static;
+
+ else if (eigrp->router_id != 0)
+ router_id = eigrp->router_id;
+
+ else
+ router_id = router_id_zebra.s_addr;
+
+ eigrp->router_id = router_id;
+ if (router_id_old != router_id)
+ {
+// if (IS_DEBUG_EIGRP_EVENT)
+// zlog_debug("Router-ID[NEW:%s]: Update", inet_ntoa(eigrp->router_id));
+
+ /* update eigrp_interface's */
+ for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp))
+ eigrp_if_update(ifp);
+ }
+}
+
+void
+eigrp_master_init ()
+{
+ struct timeval tv;
+
+ memset(&eigrp_master, 0, sizeof(struct eigrp_master));
+
+ eigrp_om = &eigrp_master;
+ eigrp_om->eigrp = list_new();
+
+ monotime(&tv);
+ eigrp_om->start_time = tv.tv_sec;
+}
+
+
+/* Allocate new eigrp structure. */
+static struct eigrp *
+eigrp_new (const char *AS)
+{
+ struct eigrp *eigrp = XCALLOC(MTYPE_EIGRP_TOP, sizeof (struct eigrp));
+ int eigrp_socket;
+
+ /* init information relevant to peers */
+ eigrp->vrid = 0;
+ eigrp->AS = atoi(AS);
+ eigrp->router_id = 0L;
+ eigrp->router_id_static = 0L;
+ eigrp->sequence_number = 1;
+
+ /*Configure default K Values for EIGRP Process*/
+ eigrp->k_values[0] = EIGRP_K1_DEFAULT;
+ eigrp->k_values[1] = EIGRP_K2_DEFAULT;
+ eigrp->k_values[2] = EIGRP_K3_DEFAULT;
+ eigrp->k_values[3] = EIGRP_K4_DEFAULT;
+ eigrp->k_values[4] = EIGRP_K5_DEFAULT;
+ eigrp->k_values[5] = EIGRP_K6_DEFAULT;
+
+ /* init internal data structures */
+ eigrp->eiflist = list_new();
+ eigrp->passive_interface_default = EIGRP_IF_ACTIVE;
+ eigrp->networks = route_table_init();
+
+ if ((eigrp_socket = eigrp_sock_init()) < 0)
+ {
+ zlog_err("eigrp_new: fatal error: eigrp_sock_init was unable to open "
+ "a socket");
+ exit (1);
+ }
+
+ eigrp->fd = eigrp_socket;
+ eigrp->maxsndbuflen = getsockopt_so_sendbuf(eigrp->fd);
+
+ if ((eigrp->ibuf = stream_new(EIGRP_PACKET_MAX_LEN+1)) == NULL)
+ {
+ zlog_err("eigrp_new: fatal error: stream_new (%u) failed allocating ibuf",
+ EIGRP_PACKET_MAX_LEN+1);
+ exit(1);
+ }
+
+ eigrp->t_read = thread_add_read(master, eigrp_read, eigrp, eigrp->fd);
+ eigrp->oi_write_q = list_new();
+
+ eigrp->topology_table = eigrp_topology_new();
+
+ eigrp->neighbor_self = eigrp_nbr_new(NULL);
+ inet_aton("127.0.0.1", &eigrp->neighbor_self->src);
+
+ eigrp->variance = EIGRP_VARIANCE_DEFAULT;
+ eigrp->max_paths = EIGRP_MAX_PATHS_DEFAULT;
+
+ eigrp->serno = 0;
+ eigrp->serno_last_update = 0;
+ eigrp->topology_changes_externalIPV4 = list_new ();
+ eigrp->topology_changes_internalIPV4 = list_new ();
+
+ eigrp->list[EIGRP_FILTER_IN] = NULL;
+ eigrp->list[EIGRP_FILTER_OUT] = NULL;
+
+ eigrp->prefix[EIGRP_FILTER_IN] = NULL;
+ eigrp->prefix[EIGRP_FILTER_OUT] = NULL;
+
+ eigrp->routemap[EIGRP_FILTER_IN] = NULL;
+ eigrp->routemap[EIGRP_FILTER_OUT] = NULL;
+
+ QOBJ_REG(eigrp, eigrp);
+ return eigrp;
+}
+
+static void
+eigrp_add (struct eigrp *eigrp)
+{
+ listnode_add(eigrp_om->eigrp, eigrp);
+}
+
+static void
+eigrp_delete (struct eigrp *eigrp)
+{
+ listnode_delete(eigrp_om->eigrp, eigrp);
+}
+
+struct eigrp *
+eigrp_get (const char *AS)
+{
+ struct eigrp *eigrp;
+
+ eigrp = eigrp_lookup();
+ if (eigrp == NULL)
+ {
+ eigrp = eigrp_new(AS);
+ eigrp_add(eigrp);
+ }
+
+ return eigrp;
+}
+
+/* Shut down the entire process */
+void
+eigrp_terminate (void)
+{
+ struct eigrp *eigrp;
+ struct listnode *node, *nnode;
+
+ /* shutdown already in progress */
+ if (CHECK_FLAG(eigrp_om->options, EIGRP_MASTER_SHUTDOWN))
+ return;
+
+ SET_FLAG(eigrp_om->options, EIGRP_MASTER_SHUTDOWN);
+
+ /* exit immediately if EIGRP not actually running */
+ if (listcount(eigrp_om->eigrp) == 0)
+ exit(0);
+
+ for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp))
+ eigrp_finish(eigrp);
+}
+
+void
+eigrp_finish (struct eigrp *eigrp)
+{
+
+ eigrp_finish_final(eigrp);
+
+ /* eigrp being shut-down? If so, was this the last eigrp instance? */
+ if (CHECK_FLAG(eigrp_om->options, EIGRP_MASTER_SHUTDOWN)
+ && (listcount(eigrp_om->eigrp) == 0))
+ exit(0);
+
+ return;
+}
+
+/* Final cleanup of eigrp instance */
+static void
+eigrp_finish_final (struct eigrp *eigrp)
+{
+
+ close(eigrp->fd);
+
+ if (zclient)
+ zclient_free(zclient);
+
+ list_delete(eigrp->eiflist);
+ list_delete(eigrp->oi_write_q);
+ list_delete(eigrp->topology_changes_externalIPV4);
+ list_delete(eigrp->topology_changes_internalIPV4);
+
+ eigrp_topology_cleanup(eigrp->topology_table);
+ eigrp_topology_free(eigrp->topology_table);
+
+ eigrp_nbr_delete(eigrp->neighbor_self);
+
+ eigrp_delete(eigrp);
+
+ XFREE(MTYPE_EIGRP_TOP,eigrp);
+
+}
+
+/*Look for existing eigrp process*/
+struct eigrp *
+eigrp_lookup (void)
+{
+ if (listcount(eigrp_om->eigrp) == 0)
+ return NULL;
+
+ return listgetdata(listhead(eigrp_om->eigrp));
+}
diff --git a/eigrpd/eigrpd.conf.sample b/eigrpd/eigrpd.conf.sample
new file mode 100644
index 000000000..662e667d3
--- /dev/null
+++ b/eigrpd/eigrpd.conf.sample
@@ -0,0 +1,13 @@
+! -*- eigrpd -*-
+!
+! EIGRPDd sample configuration file
+!
+!
+hostname eigrpd
+password zebra
+!enable password please-set-at-here
+!
+!router eigrp 4453
+! network 192.168.1.0/24
+!
+log stdout
diff --git a/eigrpd/eigrpd.h b/eigrpd/eigrpd.h
new file mode 100644
index 000000000..61d4ba752
--- /dev/null
+++ b/eigrpd/eigrpd.h
@@ -0,0 +1,54 @@
+/*
+ * EIGRP main header.
+ * Copyright (C) 2013-2014
+ * Authors:
+ * Donnie Savage
+ * Jan Janovic
+ * Matej Perina
+ * Peter Orsag
+ * Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRPD_H
+#define _ZEBRA_EIGRPD_H
+
+#include <zebra.h>
+
+#include "filter.h"
+#include "log.h"
+
+/* Set EIGRP version is "classic" - wide metrics comes next */
+#define EIGRP_MAJOR_VERSION 1
+#define EIGRP_MINOR_VERSION 2
+
+/* Extern variables. */
+extern struct zclient *zclient;
+extern struct thread_master *master;
+extern struct eigrp_master *eigrp_om;
+
+/* Prototypes */
+ extern void eigrp_master_init (void);
+ extern void eigrp_terminate (void);
+ extern void eigrp_finish (struct eigrp *);
+ extern struct eigrp *eigrp_get (const char *);
+ extern struct eigrp *eigrp_lookup (void);
+ extern void eigrp_router_id_update (struct eigrp *);
+
+#endif /* _ZEBRA_EIGRPD_H */
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 1a8c7af42..55b1eb804 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -31,7 +31,8 @@ libfrr_la_SOURCES = \
spf_backoff.c \
libfrr.c \
strlcpy.c \
- strlcat.c
+ strlcat.c \
+ sha256.c
BUILT_SOURCES = route_types.h gitversion.h command_parse.h command_lex.h
@@ -55,6 +56,7 @@ pkginclude_HEADERS = \
spf_backoff.h \
srcdest_table.h \
libfrr.h \
+ sha256.h \
# end
noinst_HEADERS = \
diff --git a/lib/command.c b/lib/command.c
index bfff581d9..cae848a5c 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -1398,6 +1398,7 @@ cmd_exit (struct vty *vty)
case ZEBRA_NODE:
case BGP_NODE:
case RIP_NODE:
+ case EIGRP_NODE:
case RIPNG_NODE:
case OSPF_NODE:
case OSPF6_NODE:
@@ -1479,6 +1480,7 @@ DEFUN (config_end,
case ZEBRA_NODE:
case RIP_NODE:
case RIPNG_NODE:
+ case EIGRP_NODE:
case BGP_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
diff --git a/lib/command.h b/lib/command.h
index d62f7655e..c8172caa7 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -91,6 +91,7 @@ enum node_type
TABLE_NODE, /* rtm_table selection node. */
RIP_NODE, /* RIP protocol mode node. */
RIPNG_NODE, /* RIPng protocol mode node. */
+ EIGRP_NODE, /* EIGRP protocol mode node. */
BGP_NODE, /* BGP protocol mode which includes BGP4+ */
BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */
BGP_VPNV6_NODE, /* BGP MPLS-VPN PE exchange. */
@@ -356,6 +357,7 @@ struct cmd_element
#define REDIST_STR "Redistribute information from another routing protocol\n"
#define CLEAR_STR "Reset functions\n"
#define RIP_STR "RIP information\n"
+#define EIGRP_STR "EIGRP information\n"
#define BGP_STR "BGP information\n"
#define BGP_SOFT_STR "Soft reconfig inbound and outbound updates\n"
#define BGP_SOFT_IN_STR "Send route-refresh unless using 'soft-reconfiguration inbound'\n"
diff --git a/lib/libfrr.c b/lib/libfrr.c
index f9ac3158a..b7ce0679c 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -27,6 +27,7 @@
#include "version.h"
#include "memory_vty.h"
#include "zclient.h"
+#include "log_int.h"
const char frr_sysconfdir[] = SYSCONFDIR;
const char frr_vtydir[] = DAEMON_VTY_DIR;
@@ -303,7 +304,7 @@ struct thread_master *frr_init(void)
openzlog (di->progname, di->logname, di->instance,
LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
#if defined(HAVE_CUMULUS)
- zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
+ zlog_set_level (ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
#endif
zprivs_init(di->privs);
diff --git a/lib/log.c b/lib/log.c
index 0fd9621f3..c86eb61af 100644
--- 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"))
diff --git a/lib/route_types.txt b/lib/route_types.txt
index 5cb06ffb7..7625d1f69 100644
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -52,6 +52,7 @@ ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, "OSPFv3"
ZEBRA_ROUTE_ISIS, isis, isisd, 'I', 1, 1, "IS-IS"
ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP"
ZEBRA_ROUTE_PIM, pim, pimd, 'P', 1, 0, "PIM"
+ZEBRA_ROUTE_EIGRP, eigrp, eigrpd, 'E', 1, 0, "EIGRP"
ZEBRA_ROUTE_NHRP, nhrp, nhrpd, 'N', 1, 1, "NHRP"
# HSLS and OLSR both are AFI independent (so: 1, 1), however
# we want to disable for them for general Quagga distribution.
@@ -86,6 +87,7 @@ ZEBRA_ROUTE_OSPF6, "Open Shortest Path First (IPv6) (OSPFv3)"
ZEBRA_ROUTE_ISIS, "Intermediate System to Intermediate System (IS-IS)"
ZEBRA_ROUTE_BGP, "Border Gateway Protocol (BGP)"
ZEBRA_ROUTE_PIM, "Protocol Independent Multicast (PIM)"
+ZEBRA_ROUTE_EIGRP, "Enhanced Interior Gateway Routing Protocol (EIGRP)"
ZEBRA_ROUTE_NHRP, "Next Hop Resolution Protocol (NHRP)"
ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)"
ZEBRA_ROUTE_VNC, "Virtual Network Control (VNC)"
diff --git a/lib/sha256.c b/lib/sha256.c
new file mode 100644
index 000000000..c7588a5f1
--- /dev/null
+++ b/lib/sha256.c
@@ -0,0 +1,425 @@
+/*-
+ * Copyright 2005,2007,2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <zebra.h>
+#include "sha256.h"
+
+static inline uint32_t
+be32dec(const void *pp)
+{
+ const uint8_t *p = (uint8_t const *)pp;
+
+ return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +
+ ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
+}
+
+static inline void
+be32enc(void *pp, uint32_t x)
+{
+ uint8_t * p = (uint8_t *)pp;
+
+ p[3] = x & 0xff;
+ p[2] = (x >> 8) & 0xff;
+ p[1] = (x >> 16) & 0xff;
+ p[0] = (x >> 24) & 0xff;
+}
+
+/*
+ * Encode a length len/4 vector of (uint32_t) into a length len vector of
+ * (unsigned char) in big-endian form. Assumes len is a multiple of 4.
+ */
+static void
+be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len / 4; i++)
+ be32enc(dst + i * 4, src[i]);
+}
+
+/*
+ * Decode a big-endian length len vector of (unsigned char) into a length
+ * len/4 vector of (uint32_t). Assumes len is a multiple of 4.
+ */
+static void
+be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len / 4; i++)
+ dst[i] = be32dec(src + i * 4);
+}
+
+/* Elementary functions used by SHA256 */
+#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
+#define Maj(x, y, z) ((x & (y | z)) | (y & z))
+#define SHR(x, n) (x >> n)
+#define ROTR(x, n) ((x >> n) | (x << (32 - n)))
+#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
+#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
+
+/* SHA256 round function */
+#define RND(a, b, c, d, e, f, g, h, k) \
+ t0 = h + S1(e) + Ch(e, f, g) + k; \
+ t1 = S0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+
+/* Adjusted round function for rotating state */
+#define RNDr(S, W, i, k) \
+ RND(S[(64 - i) % 8], S[(65 - i) % 8], \
+ S[(66 - i) % 8], S[(67 - i) % 8], \
+ S[(68 - i) % 8], S[(69 - i) % 8], \
+ S[(70 - i) % 8], S[(71 - i) % 8], \
+ W[i] + k)
+
+/*
+ * SHA256 block compression function. The 256-bit state is transformed via
+ * the 512-bit input block to produce a new state.
+ */
+static void
+SHA256_Transform(uint32_t * state, const unsigned char block[64])
+{
+ uint32_t W[64];
+ uint32_t S[8];
+ uint32_t t0, t1;
+ int i;
+
+ /* 1. Prepare message schedule W. */
+ be32dec_vect(W, block, 64);
+ for (i = 16; i < 64; i++)
+ W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
+
+ /* 2. Initialize working variables. */
+ memcpy(S, state, 32);
+
+ /* 3. Mix. */
+ RNDr(S, W, 0, 0x428a2f98);
+ RNDr(S, W, 1, 0x71374491);
+ RNDr(S, W, 2, 0xb5c0fbcf);
+ RNDr(S, W, 3, 0xe9b5dba5);
+ RNDr(S, W, 4, 0x3956c25b);
+ RNDr(S, W, 5, 0x59f111f1);
+ RNDr(S, W, 6, 0x923f82a4);
+ RNDr(S, W, 7, 0xab1c5ed5);
+ RNDr(S, W, 8, 0xd807aa98);
+ RNDr(S, W, 9, 0x12835b01);
+ RNDr(S, W, 10, 0x243185be);
+ RNDr(S, W, 11, 0x550c7dc3);
+ RNDr(S, W, 12, 0x72be5d74);
+ RNDr(S, W, 13, 0x80deb1fe);
+ RNDr(S, W, 14, 0x9bdc06a7);
+ RNDr(S, W, 15, 0xc19bf174);
+ RNDr(S, W, 16, 0xe49b69c1);
+ RNDr(S, W, 17, 0xefbe4786);
+ RNDr(S, W, 18, 0x0fc19dc6);
+ RNDr(S, W, 19, 0x240ca1cc);
+ RNDr(S, W, 20, 0x2de92c6f);
+ RNDr(S, W, 21, 0x4a7484aa);
+ RNDr(S, W, 22, 0x5cb0a9dc);
+ RNDr(S, W, 23, 0x76f988da);
+ RNDr(S, W, 24, 0x983e5152);
+ RNDr(S, W, 25, 0xa831c66d);
+ RNDr(S, W, 26, 0xb00327c8);
+ RNDr(S, W, 27, 0xbf597fc7);
+ RNDr(S, W, 28, 0xc6e00bf3);
+ RNDr(S, W, 29, 0xd5a79147);
+ RNDr(S, W, 30, 0x06ca6351);
+ RNDr(S, W, 31, 0x14292967);
+ RNDr(S, W, 32, 0x27b70a85);
+ RNDr(S, W, 33, 0x2e1b2138);
+ RNDr(S, W, 34, 0x4d2c6dfc);
+ RNDr(S, W, 35, 0x53380d13);
+ RNDr(S, W, 36, 0x650a7354);
+ RNDr(S, W, 37, 0x766a0abb);
+ RNDr(S, W, 38, 0x81c2c92e);
+ RNDr(S, W, 39, 0x92722c85);
+ RNDr(S, W, 40, 0xa2bfe8a1);
+ RNDr(S, W, 41, 0xa81a664b);
+ RNDr(S, W, 42, 0xc24b8b70);
+ RNDr(S, W, 43, 0xc76c51a3);
+ RNDr(S, W, 44, 0xd192e819);
+ RNDr(S, W, 45, 0xd6990624);
+ RNDr(S, W, 46, 0xf40e3585);
+ RNDr(S, W, 47, 0x106aa070);
+ RNDr(S, W, 48, 0x19a4c116);
+ RNDr(S, W, 49, 0x1e376c08);
+ RNDr(S, W, 50, 0x2748774c);
+ RNDr(S, W, 51, 0x34b0bcb5);
+ RNDr(S, W, 52, 0x391c0cb3);
+ RNDr(S, W, 53, 0x4ed8aa4a);
+ RNDr(S, W, 54, 0x5b9cca4f);
+ RNDr(S, W, 55, 0x682e6ff3);
+ RNDr(S, W, 56, 0x748f82ee);
+ RNDr(S, W, 57, 0x78a5636f);
+ RNDr(S, W, 58, 0x84c87814);
+ RNDr(S, W, 59, 0x8cc70208);
+ RNDr(S, W, 60, 0x90befffa);
+ RNDr(S, W, 61, 0xa4506ceb);
+ RNDr(S, W, 62, 0xbef9a3f7);
+ RNDr(S, W, 63, 0xc67178f2);
+
+ /* 4. Mix local working variables into global state */
+ for (i = 0; i < 8; i++)
+ state[i] += S[i];
+
+ /* Clean the stack. */
+ memset(W, 0, 256);
+ memset(S, 0, 32);
+ t0 = t1 = 0;
+}
+
+static unsigned char PAD[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* Add padding and terminating bit-count. */
+static void
+SHA256_Pad(SHA256_CTX * ctx)
+{
+ unsigned char len[8];
+ uint32_t r, plen;
+
+ /*
+ * Convert length to a vector of bytes -- we do this now rather
+ * than later because the length will change after we pad.
+ */
+ be32enc_vect(len, ctx->count, 8);
+
+ /* Add 1--64 bytes so that the resulting length is 56 mod 64 */
+ r = (ctx->count[1] >> 3) & 0x3f;
+ plen = (r < 56) ? (56 - r) : (120 - r);
+ SHA256_Update(ctx, PAD, (size_t)plen);
+
+ /* Add the terminating bit-count */
+ SHA256_Update(ctx, len, 8);
+}
+
+/* SHA-256 initialization. Begins a SHA-256 operation. */
+void
+SHA256_Init(SHA256_CTX * ctx)
+{
+
+ /* Zero bits processed so far */
+ ctx->count[0] = ctx->count[1] = 0;
+
+ /* Magic initialization constants */
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+}
+
+/* Add bytes into the hash */
+void
+SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len)
+{
+ uint32_t bitlen[2];
+ uint32_t r;
+ const unsigned char *src = in;
+
+ /* Number of bytes left in the buffer from previous updates */
+ r = (ctx->count[1] >> 3) & 0x3f;
+
+ /* Convert the length into a number of bits */
+ bitlen[1] = ((uint32_t)len) << 3;
+ bitlen[0] = (uint32_t)(len >> 29);
+
+ /* Update number of bits */
+ if ((ctx->count[1] += bitlen[1]) < bitlen[1])
+ ctx->count[0]++;
+ ctx->count[0] += bitlen[0];
+
+ /* Handle the case where we don't need to perform any transforms */
+ if (len < 64 - r) {
+ memcpy(&ctx->buf[r], src, len);
+ return;
+ }
+
+ /* Finish the current block */
+ memcpy(&ctx->buf[r], src, 64 - r);
+ SHA256_Transform(ctx->state, ctx->buf);
+ src += 64 - r;
+ len -= 64 - r;
+
+ /* Perform complete blocks */
+ while (len >= 64) {
+ SHA256_Transform(ctx->state, src);
+ src += 64;
+ len -= 64;
+ }
+
+ /* Copy left over data into buffer */
+ memcpy(ctx->buf, src, len);
+}
+
+/*
+ * SHA-256 finalization. Pads the input data, exports the hash value,
+ * and clears the context state.
+ */
+void
+SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx)
+{
+
+ /* Add padding */
+ SHA256_Pad(ctx);
+
+ /* Write the hash */
+ be32enc_vect(digest, ctx->state, 32);
+
+ /* Clear the context state */
+ memset((void *)ctx, 0, sizeof(*ctx));
+}
+
+/* Initialize an HMAC-SHA256 operation with the given key. */
+void
+HMAC__SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen)
+{
+ unsigned char pad[64];
+ unsigned char khash[32];
+ const unsigned char * K = _K;
+ size_t i;
+
+ /* If Klen > 64, the key is really SHA256(K). */
+ if (Klen > 64) {
+ SHA256_Init(&ctx->ictx);
+ SHA256_Update(&ctx->ictx, K, Klen);
+ SHA256_Final(khash, &ctx->ictx);
+ K = khash;
+ Klen = 32;
+ }
+
+ /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
+ SHA256_Init(&ctx->ictx);
+ memset(pad, 0x36, 64);
+ for (i = 0; i < Klen; i++)
+ pad[i] ^= K[i];
+ SHA256_Update(&ctx->ictx, pad, 64);
+
+ /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
+ SHA256_Init(&ctx->octx);
+ memset(pad, 0x5c, 64);
+ for (i = 0; i < Klen; i++)
+ pad[i] ^= K[i];
+ SHA256_Update(&ctx->octx, pad, 64);
+
+ /* Clean the stack. */
+ memset(khash, 0, 32);
+}
+
+/* Add bytes to the HMAC-SHA256 operation. */
+void
+HMAC__SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len)
+{
+
+ /* Feed data to the inner SHA256 operation. */
+ SHA256_Update(&ctx->ictx, in, len);
+}
+
+/* Finish an HMAC-SHA256 operation. */
+void
+HMAC__SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx)
+{
+ unsigned char ihash[32];
+
+ /* Finish the inner SHA256 operation. */
+ SHA256_Final(ihash, &ctx->ictx);
+
+ /* Feed the inner hash to the outer SHA256 operation. */
+ SHA256_Update(&ctx->octx, ihash, 32);
+
+ /* Finish the outer SHA256 operation. */
+ SHA256_Final(digest, &ctx->octx);
+
+ /* Clean the stack. */
+ memset(ihash, 0, 32);
+}
+
+/**
+ * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
+ * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
+ * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
+ */
+void
+PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,
+ size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)
+{
+ HMAC_SHA256_CTX PShctx, hctx;
+ size_t i;
+ uint8_t ivec[4];
+ uint8_t U[32];
+ uint8_t T[32];
+ uint64_t j;
+ int k;
+ size_t clen;
+
+ /* Compute HMAC state after processing P and S. */
+ HMAC__SHA256_Init(&PShctx, passwd, passwdlen);
+ HMAC__SHA256_Update(&PShctx, salt, saltlen);
+
+ /* Iterate through the blocks. */
+ for (i = 0; i * 32 < dkLen; i++) {
+ /* Generate INT(i + 1). */
+ be32enc(ivec, (uint32_t)(i + 1));
+
+ /* Compute U_1 = PRF(P, S || INT(i)). */
+ memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));
+ HMAC__SHA256_Update(&hctx, ivec, 4);
+ HMAC__SHA256_Final(U, &hctx);
+
+ /* T_i = U_1 ... */
+ memcpy(T, U, 32);
+
+ for (j = 2; j <= c; j++) {
+ /* Compute U_j. */
+ HMAC__SHA256_Init(&hctx, passwd, passwdlen);
+ HMAC__SHA256_Update(&hctx, U, 32);
+ HMAC__SHA256_Final(U, &hctx);
+
+ /* ... xor U_j ... */
+ for (k = 0; k < 32; k++)
+ T[k] ^= U[k];
+ }
+
+ /* Copy as many bytes as necessary into buf. */
+ clen = dkLen - i * 32;
+ if (clen > 32)
+ clen = 32;
+ memcpy(&buf[i * 32], T, clen);
+ }
+
+ /* Clean PShctx, since we never called _Final on it. */
+ memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX));
+}
diff --git a/lib/sha256.h b/lib/sha256.h
new file mode 100644
index 000000000..502f3fc22
--- /dev/null
+++ b/lib/sha256.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright 2005,2007,2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libmd/sha256.h,v 1.2 2006/01/17 15:35:56 phk Exp $
+ */
+
+#ifndef _SHA256_H_
+#define _SHA256_H_
+
+typedef struct SHA256Context {
+ uint32_t state[8];
+ uint32_t count[2];
+ unsigned char buf[64];
+} SHA256_CTX;
+
+typedef struct HMAC_SHA256Context {
+ SHA256_CTX ictx;
+ SHA256_CTX octx;
+} HMAC_SHA256_CTX;
+
+void SHA256_Init(SHA256_CTX *);
+void SHA256_Update(SHA256_CTX *, const void *, size_t);
+void SHA256_Final(unsigned char [32], SHA256_CTX *);
+void HMAC__SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t);
+void HMAC__SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t);
+void HMAC__SHA256_Final(unsigned char [32], HMAC_SHA256_CTX *);
+
+/**
+ * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
+ * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
+ * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
+ */
+void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t,
+ uint64_t, uint8_t *, size_t);
+
+#endif /* !_SHA256_H_ */
diff --git a/lib/vty.c b/lib/vty.c
index 4d34fead8..649b65949 100644
--- 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
index 000000000..b28b81eed
--- /dev/null
+++ b/pkgsrc/eigrpd.sh.in
@@ -0,0 +1,44 @@
+#!/bin/sh
+#
+# eigrpd is part of the quagga routing beast
+#
+# PROVIDE: eigrpd
+# REQUIRE: zebra
+##
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin
+export PATH
+
+if [ -f /etc/rc.subr ]
+then
+ . /etc/rc.subr
+fi
+
+name="eigrpd"
+rcvar=$name
+required_files="@sysconfdir@/${name}.conf"
+command="@prefix@/sbin/${name}"
+command_args="-d"
+
+start_precmd="zebra_precmd"
+socket_dir=@localstatedir@
+pidfile="${socket_dir}/${name}.pid"
+
+zebra_precmd()
+{
+ rc_flags="$(
+ set -- $rc_flags
+ while [ $# -ne 0 ]; do
+ if [ X"$1" = X-P -o X"$1" = X-A ]; then
+ break
+ fi
+ shift
+ done
+ if [ $# -eq 0 ]; then
+ echo "-P 0"
+ fi
+ ) $rc_flags"
+}
+
+load_rc_config $name
+run_rc_command "$1"
diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am
index d02ec9661..c28b9cb71 100644
--- a/vtysh/Makefile.am
+++ b/vtysh/Makefile.am
@@ -71,6 +71,12 @@ if NHRPD
vtysh_scan += $(top_srcdir)/nhrpd/nhrp_vty.c
endif
+if EIGRPD
+vtysh_scan += $(top_srcdir)/eigrpd/eigrp_dump.c
+vtysh_scan += $(top_srcdir)/eigrpd/eigrp_routemap.c
+vtysh_scan += $(top_srcdir)/eigrpd/eigrp_vty.c
+endif
+
vtysh_cmd_FILES = $(vtysh_scan) \
$(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \
$(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index c1b1d705a..e46901b85 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -52,6 +52,7 @@ $ignore{'"router bgp " "(1-4294967295)"'} = "ignore";
$ignore{'"router bgp " "(1-4294967295)" " <view|vrf> WORD"'} = "ignore";
$ignore{'"router bgp [(1-4294967295) [<view|vrf> WORD]]"'} = "ignore";
$ignore{'"router isis WORD"'} = "ignore";
+$ignore('"router eigrp (1-65535)"'} = "ignore";
$ignore{'"router zebra"'} = "ignore";
$ignore{'"address-family ipv4"'} = "ignore";
$ignore{'"address-family ipv4 [<unicast|multicast|vpn|encap>]"'} = "ignore";
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 114022d19..afb742d90 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -75,6 +75,7 @@ struct vtysh_client vtysh_client[] =
{ .fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .next = NULL},
{ .fd = -1, .name = "pimd", .flag = VTYSH_PIMD, .next = NULL},
{ .fd = -1, .name = "nhrpd", .flag = VTYSH_NHRPD, .next = NULL},
+ { .fd = -1, .name = "eigrpd", .flag = VTYSH_EIGRPD, .next = NULL},
{ .fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL},
};
@@ -994,6 +995,12 @@ static struct cmd_node ospf_node =
"%s(config-router)# "
};
+static struct cmd_node eigrp_node =
+{
+ EIGRP_NODE,
+ "%s(config-router)# "
+};
+
static struct cmd_node ripng_node =
{
RIPNG_NODE,
@@ -1332,6 +1339,18 @@ DEFUNSH (VTYSH_OSPFD,
return CMD_SUCCESS;
}
+DEFUNSH (VTYSH_EIGRPD,
+ router_eigrp,
+ router_eigrp_cmd,
+ "router eigrp (1-65535)",
+ "Enable a routing process\n"
+ "Start EIGRP configuration\n"
+ "AS number to use\n")
+{
+ vty->node = EIGRP_NODE;
+ return CMD_SUCCESS;
+}
+
DEFUNSH (VTYSH_OSPF6D,
router_ospf6,
router_ospf6_cmd,
@@ -1515,6 +1534,7 @@ vtysh_exit (struct vty *vty)
case RIPNG_NODE:
case OSPF_NODE:
case OSPF6_NODE:
+ case EIGRP_NODE:
case LDP_NODE:
case LDP_L2VPN_NODE:
case ISIS_NODE:
@@ -1716,6 +1736,24 @@ DEFUNSH (VTYSH_OSPFD,
return vtysh_exit_ospfd (self, vty, argc, argv);
}
+DEFUNSH (VTYSH_EIGRPD,
+ vtysh_exit_eigrpd,
+ vtysh_exit_eigrpd_cmd,
+ "exit",
+ "Exit current mode and down to previous mode\n")
+{
+ return vtysh_exit (vty);
+}
+
+DEFUNSH (VTYSH_EIGRPD,
+ vtysh_quit_eigrpd,
+ vtysh_quit_eigrpd_cmd,
+ "quit",
+ "Exit current mode and down to previous mode\n")
+{
+ return vtysh_exit (vty);
+}
+
DEFUNSH (VTYSH_OSPF6D,
vtysh_exit_ospf6d,
vtysh_exit_ospf6d_cmd,
@@ -1799,7 +1837,7 @@ DEFUNSH (VTYSH_INTERFACE,
}
/* TODO Implement "no interface command in isisd. */
-DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD,
+DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_EIGRPD|VTYSH_LDPD,
vtysh_no_interface_cmd,
"no interface IFNAME",
NO_STR
@@ -1883,13 +1921,13 @@ DEFUNSH (VTYSH_VRF,
/* TODO Implement interface description commands in ripngd, ospf6d
* and isisd. */
-DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_LDPD,
+DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_EIGRPD|VTYSH_LDPD,
vtysh_interface_desc_cmd,
"description LINE...",
"Interface specific description\n"
"Characters describing this interface\n")
-DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD,
+DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_EIGRPD,
vtysh_no_interface_desc_cmd,
"no description",
NO_STR
@@ -3118,6 +3156,7 @@ vtysh_init_vty (void)
install_node (&bgp_vnc_nve_group_node, NULL);
install_node (&bgp_vnc_l2_group_node, NULL);
install_node (&ospf_node, NULL);
+ install_node (&eigrp_node, NULL);
install_node (&ripng_node, NULL);
install_node (&ospf6_node, NULL);
install_node (&ldp_node, NULL);
@@ -3158,6 +3197,7 @@ vtysh_init_vty (void)
vtysh_install_default (BGP_VNC_L2_GROUP_NODE);
#endif
vtysh_install_default (OSPF_NODE);
+ vtysh_install_default (EIGRP_NODE);
vtysh_install_default (RIPNG_NODE);
vtysh_install_default (OSPF6_NODE);
vtysh_install_default (LDP_NODE);
@@ -3187,6 +3227,8 @@ vtysh_init_vty (void)
install_element (RIPNG_NODE, &vtysh_quit_ripngd_cmd);
install_element (OSPF_NODE, &vtysh_exit_ospfd_cmd);
install_element (OSPF_NODE, &vtysh_quit_ospfd_cmd);
+ install_element (EIGRP_NODE, &vtysh_exit_eigrpd_cmd);
+ install_element (EIGRP_NODE, &vtysh_quit_eigrpd_cmd);
install_element (OSPF6_NODE, &vtysh_exit_ospf6d_cmd);
install_element (OSPF6_NODE, &vtysh_quit_ospf6d_cmd);
#if defined (HAVE_LDPD)
@@ -3251,6 +3293,7 @@ vtysh_init_vty (void)
install_element (RIP_NODE, &vtysh_end_all_cmd);
install_element (RIPNG_NODE, &vtysh_end_all_cmd);
install_element (OSPF_NODE, &vtysh_end_all_cmd);
+ install_element (EIGRP_NODE, &vtysh_end_all_cmd);
install_element (OSPF6_NODE, &vtysh_end_all_cmd);
install_element (LDP_NODE, &vtysh_end_all_cmd);
install_element (LDP_IPV4_NODE, &vtysh_end_all_cmd);
@@ -3298,6 +3341,7 @@ vtysh_init_vty (void)
install_element (VRF_NODE, &vtysh_exit_vrf_cmd);
install_element (VRF_NODE, &vtysh_quit_vrf_cmd);
+ install_element (CONFIG_NODE, &router_eigrp_cmd);
install_element (CONFIG_NODE, &router_rip_cmd);
install_element (CONFIG_NODE, &router_ripng_cmd);
install_element (CONFIG_NODE, &router_ospf_cmd);
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index 07ba8367d..340f85df1 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -36,6 +36,7 @@ DECLARE_MGROUP(MVTYSH)
#define VTYSH_LDPD 0x200
#define VTYSH_WATCHFRR 0x400
#define VTYSH_NHRPD 0x800
+#define VTYSH_EIGRPD 0x1000
/* commands in REALLYALL are crucial to correct vtysh operation */
#define VTYSH_REALLYALL ~0U