]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge remote-tracking branch 'origin/stable/3.0'
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 10 May 2017 00:39:35 +0000 (20:39 -0400)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 10 May 2017 00:39:35 +0000 (20:39 -0400)
224 files changed:
.gitignore
Makefile.am
bgpd/Makefile.am
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_debug.c
bgpd/bgp_fsm.c
bgpd/bgp_label.c [new file with mode: 0644]
bgpd/bgp_label.h [new file with mode: 0644]
bgpd/bgp_main.c
bgpd/bgp_nht.c
bgpd/bgp_open.c
bgpd/bgp_packet.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_table.h
bgpd/bgp_updgrp_adv.c
bgpd/bgp_updgrp_packet.c
bgpd/bgp_vty.c
bgpd/bgp_vty.h
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
bgpd/bgpd.c
bgpd/bgpd.conf.sample
bgpd/bgpd.conf.vnc.sample
bgpd/bgpd.h
bgpd/rfapi/rfapi_monitor.h
bgpd/rfapi/rfapi_rib.h
configure.ac
cumulus/.gitignore [deleted file]
cumulus/Makefile.am [deleted file]
cumulus/etc/default/frr [deleted file]
cumulus/etc/frr/Frr.conf [deleted file]
cumulus/etc/frr/daemons [deleted file]
cumulus/etc/frr/debian.conf [deleted file]
cumulus/etc/frr/vtysh.conf [deleted file]
cumulus/start-stop-daemon.c [deleted file]
debian/README.Debian
debian/README.Maintainer
debian/changelog
debian/control
debian/frr.dirs
debian/frr.install
defaults.h
doc/Building_FRR_on_Ubuntu1204.md
doc/Building_FRR_on_Ubuntu1404.md
doc/Building_FRR_on_Ubuntu1604.md
doc/Makefile.am
doc/bgpd.texi
doc/eigrpd.8.in [new file with mode: 0644]
doc/eigrpd.texi [new file with mode: 0644]
doc/install.texi
doc/nhrpd.texi
doc/vnc.texi
eigrpd/.gitignore [new file with mode: 0644]
eigrpd/EIGRP-MIB.txt [new file with mode: 0644]
eigrpd/Makefile.am [new file with mode: 0644]
eigrpd/eigrp_const.h [new file with mode: 0644]
eigrpd/eigrp_dump.c [new file with mode: 0644]
eigrpd/eigrp_dump.h [new file with mode: 0644]
eigrpd/eigrp_filter.c [new file with mode: 0644]
eigrpd/eigrp_filter.h [new file with mode: 0644]
eigrpd/eigrp_fsm.c [new file with mode: 0644]
eigrpd/eigrp_fsm.h [new file with mode: 0644]
eigrpd/eigrp_hello.c [new file with mode: 0644]
eigrpd/eigrp_interface.c [new file with mode: 0644]
eigrpd/eigrp_interface.h [new file with mode: 0644]
eigrpd/eigrp_macros.h [new file with mode: 0644]
eigrpd/eigrp_main.c [new file with mode: 0644]
eigrpd/eigrp_memory.c [new file with mode: 0644]
eigrpd/eigrp_memory.h [new file with mode: 0644]
eigrpd/eigrp_neighbor.c [new file with mode: 0644]
eigrpd/eigrp_neighbor.h [new file with mode: 0644]
eigrpd/eigrp_network.c [new file with mode: 0644]
eigrpd/eigrp_network.h [new file with mode: 0644]
eigrpd/eigrp_packet.c [new file with mode: 0644]
eigrpd/eigrp_packet.h [new file with mode: 0644]
eigrpd/eigrp_pkt_tlv1.c [new file with mode: 0644]
eigrpd/eigrp_pkt_tlv2.c [new file with mode: 0644]
eigrpd/eigrp_query.c [new file with mode: 0644]
eigrpd/eigrp_reply.c [new file with mode: 0644]
eigrpd/eigrp_routemap.c [new file with mode: 0644]
eigrpd/eigrp_routemap.h [new file with mode: 0644]
eigrpd/eigrp_siaquery.c [new file with mode: 0644]
eigrpd/eigrp_siareply.c [new file with mode: 0644]
eigrpd/eigrp_snmp.c [new file with mode: 0644]
eigrpd/eigrp_snmp.h [new file with mode: 0644]
eigrpd/eigrp_structs.h [new file with mode: 0644]
eigrpd/eigrp_topology.c [new file with mode: 0644]
eigrpd/eigrp_topology.h [new file with mode: 0644]
eigrpd/eigrp_update.c [new file with mode: 0644]
eigrpd/eigrp_vty.c [new file with mode: 0644]
eigrpd/eigrp_vty.h [new file with mode: 0644]
eigrpd/eigrp_zebra.c [new file with mode: 0644]
eigrpd/eigrp_zebra.h [new file with mode: 0644]
eigrpd/eigrpd.c [new file with mode: 0644]
eigrpd/eigrpd.conf.sample [new file with mode: 0644]
eigrpd/eigrpd.h [new file with mode: 0644]
isisd/Makefile.am
isisd/isis_adjacency.c
isisd/isis_adjacency.h
isisd/isis_bpf.c
isisd/isis_circuit.c
isisd/isis_circuit.h
isisd/isis_constants.h
isisd/isis_lsp.c
isisd/isis_lsp.h
isisd/isis_mt.c [new file with mode: 0644]
isisd/isis_mt.h [new file with mode: 0644]
isisd/isis_pdu.c
isisd/isis_pfpacket.c
isisd/isis_spf.c
isisd/isis_spf.h
isisd/isis_tlv.c
isisd/isis_tlv.h
isisd/isis_vty.c
isisd/isis_zebra.c
isisd/isisd.c
isisd/isisd.h
ldpd/Makefile.am
ldpd/adjacency.c
ldpd/control.c
ldpd/control.h
ldpd/interface.c
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c
ldpd/ldp_vty_conf.c
ldpd/ldp_vty_exec.c
ldpd/ldp_zebra.c
ldpd/ldpd.c
ldpd/ldpd.h
ldpd/ldpe.c
ldpd/ldpe.h
ldpd/log.c
ldpd/log.h
ldpd/logmsg.c [new file with mode: 0644]
ldpd/notification.c
ldpd/packet.c
lib/Makefile.am
lib/agentx.c
lib/command.c
lib/command.h
lib/command_lex.l
lib/frr_pthread.c [new file with mode: 0644]
lib/frr_pthread.h [new file with mode: 0644]
lib/frratomic.h [new file with mode: 0644]
lib/log.c
lib/memory.c
lib/memory.h
lib/mpls.h
lib/nexthop.c
lib/nexthop.h
lib/pqueue.c
lib/pqueue.h
lib/prefix.h
lib/privs.c
lib/route_types.txt
lib/sha256.c [new file with mode: 0644]
lib/sha256.h [new file with mode: 0644]
lib/sigevent.c
lib/stream.c
lib/stream.h
lib/thread.c
lib/thread.h
lib/vty.c
lib/zclient.c
lib/zclient.h
lib/zebra.h
m4/.gitignore
m4/ax_pthread.m4 [new file with mode: 0644]
ospfd/ospf_apiserver.c
ospfd/ospf_vty.c
pimd/pim_assert.c
pimd/pim_cmd.c
pimd/pim_hello.c
pimd/pim_hello.h
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_join.c
pimd/pim_msg.h
pimd/pim_neighbor.c
pimd/pim_neighbor.h
pimd/pim_pim.c
pimd/pim_register.c
pimd/pim_rp.c
pimd/pim_tlv.c
pimd/pim_tlv.h
pimd/pim_vty.c
pimd/pim_zebra.c
pimd/pim_zlookup.c
pimd/pimd.c
pimd/pimd.h
pkgsrc/eigrpd.sh.in [new file with mode: 0644]
redhat/frr.spec.in
tests/helpers/python/frrtest.py
tools/Makefile.am
tools/etc/default/frr [new file with mode: 0644]
tools/etc/frr/daemons [new file with mode: 0644]
tools/etc/frr/daemons.conf [new file with mode: 0644]
tools/etc/frr/frr.conf [new file with mode: 0644]
tools/etc/frr/vtysh.conf [new file with mode: 0644]
tools/etc/iproute2/rt_protos.d/frr.conf [new file with mode: 0644]
tools/frr
tools/start-stop-daemon.c [new file with mode: 0644]
vtysh/Makefile.am
vtysh/extract.pl.in
vtysh/vtysh.c
vtysh/vtysh.h
vtysh/vtysh_config.c
zebra/Makefile.am
zebra/interface.c
zebra/kernel_netlink.c
zebra/redistribute.c
zebra/rib.h
zebra/rt_netlink.c
zebra/rt_netlink.h
zebra/zebra_mpls.c
zebra/zebra_mpls.h
zebra/zebra_mpls_null.c
zebra/zebra_mpls_vty.c
zebra/zebra_rib.c
zebra/zebra_vrf.h
zebra/zserv.c

index 6f281112b00985d17c75c53f30e27f97b8177d80..76d396ef25c950ffa0dbe98d2d8fb69c2d28e73e 100644 (file)
@@ -72,4 +72,5 @@ GTAGS
 GSYMS
 GRTAGS
 GPATH
-
+*.la
+*.lo
index 89e7ea890e2be5b979a9d384993757f1bd78e628..d87b5943d87a421d5bb4cb484fd96d8a764e74b0 100644 (file)
@@ -2,13 +2,13 @@
 
 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
+         redhat @SOLARIS@ tests tools 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 snapcraft
 
 EXTRA_DIST = aclocal.m4 SERVICES REPORTING-BUGS \
        update-autotools \
index b6ed9a4d6db726e6d18ce453e901ce57ef2eef81..4ea045552510da7f7e3105c179562df75122be8a 100644 (file)
@@ -81,7 +81,7 @@ libbgp_a_SOURCES = \
        bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
        bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \
        bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \
-       bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c
+       bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c
 
 noinst_HEADERS = \
        bgp_memory.h \
@@ -92,7 +92,8 @@ noinst_HEADERS = \
        bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
        bgp_advertise.h bgp_vty.h bgp_mpath.h bgp_nht.h \
        bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \
-       $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h bgp_vpn.h
+       $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \
+        bgp_vpn.h bgp_label.h
 
 bgpd_SOURCES = bgp_main.c
 bgpd_LDADD = libbgp.a  $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@
index 1fccd25c8af40faf91f64b708823a1d21304248b..b2789cd47dcc4cfd542f8144994abc2fb9e4d3b3 100644 (file)
@@ -78,7 +78,8 @@ static const struct message attr_str [] =
 #if ENABLE_BGP_VNC
   { BGP_ATTR_VNC,              "VNC" },
 #endif
-  { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" }
+  { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" },
+  { BGP_ATTR_PREFIX_SID,        "PREFIX_SID" }
 };
 static const int attr_str_max = array_size(attr_str);
 
@@ -532,7 +533,10 @@ static struct hash *attrhash;
 static struct attr_extra *
 bgp_attr_extra_new (void)
 {
-  return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
+  struct attr_extra *extra;
+  extra = XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
+  extra->label_index = BGP_INVALID_LABEL_INDEX;
+  return extra;
 }
 
 void
@@ -676,6 +680,7 @@ attrhash_key_make (void *p)
       MIX(extra->mp_nexthop_global_in.s_addr);
       MIX(extra->originator_id.s_addr);
       MIX(extra->tag);
+      MIX(extra->label_index);
     }
   
   if (attr->aspath)
@@ -730,6 +735,7 @@ attrhash_cmp (const void *p1, const void *p2)
           && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
           && ae1->weight == ae2->weight
           && ae1->tag == ae2->tag
+          && ae1->label_index == ae2->label_index
           && ae1->mp_nexthop_len == ae2->mp_nexthop_len
           && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
           && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
@@ -1287,6 +1293,7 @@ const u_int8_t attr_flags_values [] = {
   [BGP_ATTR_AS4_PATH] =         BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_AS4_AGGREGATOR] =   BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_LARGE_COMMUNITIES]= BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+  [BGP_ATTR_PREFIX_SID] =       BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
 };
 static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
 
@@ -2274,6 +2281,106 @@ bgp_attr_encap(
   return 0;
 }
 
+/* Prefix SID attribute
+ * draft-ietf-idr-bgp-prefix-sid-05
+ */
+static bgp_attr_parse_ret_t
+bgp_attr_prefix_sid (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_update)
+{
+  struct peer *const peer = args->peer;
+  struct attr *const attr = args->attr;
+  int type;
+  int length;
+  u_int32_t label_index;
+  struct in6_addr ipv6_sid;
+  u_int32_t srgb_base;
+  u_int32_t srgb_range;
+  int srgb_count;
+
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID);
+
+  type = stream_getc (peer->ibuf);
+  length = stream_getw (peer->ibuf);
+
+  if (type == BGP_PREFIX_SID_LABEL_INDEX)
+    {
+      if (length != BGP_PREFIX_SID_LABEL_INDEX_LENGTH)
+        {
+          zlog_err ("Prefix SID label index length is %d instead of %d", length, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
+          return bgp_attr_malformed (args,
+                                     BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                     args->total);
+        }
+
+        /* Ignore flags and reserved */
+        stream_getc (peer->ibuf);
+        stream_getw (peer->ibuf);
+
+        /* Fetch the label index and see if it is valid. */
+        label_index = stream_getl (peer->ibuf);
+        if (label_index == BGP_INVALID_LABEL_INDEX)
+          return bgp_attr_malformed (args,
+                                     BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+                                    args->total);
+
+        /* Store label index; subsequently, we'll check on address-family */
+        (bgp_attr_extra_get (attr))->label_index = label_index;
+
+        /*
+         * Ignore the Label index attribute unless received for labeled-unicast
+         * SAFI.
+         */
+        if (!mp_update->length || mp_update->safi != SAFI_LABELED_UNICAST)
+          attr->extra->label_index = BGP_INVALID_LABEL_INDEX;
+    }
+
+  /* Placeholder code for the IPv6 SID type */
+  else if (type == BGP_PREFIX_SID_IPV6)
+    {
+      if (length != BGP_PREFIX_SID_IPV6_LENGTH)
+        {
+          zlog_err ("Prefix SID IPv6 length is %d instead of %d", length, BGP_PREFIX_SID_IPV6_LENGTH);
+          return bgp_attr_malformed (args,
+                                     BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                     args->total);
+        }
+
+        /* Ignore reserved */
+        stream_getc (peer->ibuf);
+        stream_getw (peer->ibuf);
+
+        stream_get (&ipv6_sid, peer->ibuf, 16);
+    }
+
+  /* Placeholder code for the Originator SRGB type */
+  else if (type == BGP_PREFIX_SID_ORIGINATOR_SRGB)
+    {
+      /* Ignore flags */
+      stream_getw (peer->ibuf);
+
+      length -= 2;
+
+      if (length % BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH)
+        {
+          zlog_err ("Prefix SID Originator SRGB length is %d, it must be a multiple of %d ",
+                    length, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH);
+          return bgp_attr_malformed (args,
+                                     BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                     args->total);
+        }
+
+      srgb_count = length / BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH;
+
+      for (int i = 0; i < srgb_count; i++)
+        {
+          stream_get (&srgb_base, peer->ibuf, 3);
+          stream_get (&srgb_range, peer->ibuf, 3);
+        }
+    }
+
+  return BGP_ATTR_PARSE_PROCEED;
+}
+
 /* BGP unknown attribute treatment. */
 static bgp_attr_parse_ret_t
 bgp_attr_unknown (struct bgp_attr_parser_args *args)
@@ -2572,6 +2679,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
         case BGP_ATTR_ENCAP:
           ret = bgp_attr_encap (type, peer, length, attr, flag, startp);
           break;
+        case BGP_ATTR_PREFIX_SID:
+          ret = bgp_attr_prefix_sid (&attr_args, mp_update);
+          break;
        default:
          ret = bgp_attr_unknown (&attr_args);
          break;
@@ -2740,6 +2850,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
 
   if (nh_afi == AFI_MAX)
     nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->extra->mp_nexthop_len);
+
   /* Nexthop */
   switch (nh_afi)
     {
@@ -2748,6 +2859,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
        {
        case SAFI_UNICAST:
        case SAFI_MULTICAST:
+       case SAFI_LABELED_UNICAST:
          bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
          stream_putc (s, 4);
          stream_put_ipv4 (s, attr->nexthop.s_addr);
@@ -2772,6 +2884,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
       {
       case SAFI_UNICAST:
       case SAFI_MULTICAST:
+      case SAFI_LABELED_UNICAST:
        {
          struct attr_extra *attre = attr->extra;
 
@@ -2875,6 +2988,11 @@ bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
     {
       bgp_packet_mpattr_route_type_5(s, p, prd, tag, attr);
     }
+  else if (safi == SAFI_LABELED_UNICAST)
+    {
+      /* Prefix write with label. */
+      stream_put_labeled_prefix(s, p, tag);
+    }
   else
     stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id);
 }
@@ -3112,7 +3230,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
           stream_putc (s, 4);
           stream_put_ipv4 (s, attr->nexthop.s_addr);
         }
-      else if (safi == SAFI_UNICAST && peer_cap_enhe(from))
+      else if (peer_cap_enhe(from))
         {
           /*
            * Likely this is the case when an IPv4 prefix was received with
@@ -3348,6 +3466,30 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
        }
     }
 
+  /* Label index attribute. */
+  if (safi == SAFI_LABELED_UNICAST)
+    {
+      if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID))
+        {
+          u_int32_t label_index;
+
+          assert (attr->extra);
+          label_index = attr->extra->label_index;
+
+          if (label_index != BGP_INVALID_LABEL_INDEX)
+            {
+              stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+              stream_putc (s, BGP_ATTR_PREFIX_SID);
+              stream_putc (s, 10);
+              stream_putc (s, BGP_PREFIX_SID_LABEL_INDEX);
+              stream_putw (s, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
+              stream_putc (s, 0); // reserved
+              stream_putw (s, 0); // flags
+              stream_putl (s, label_index);
+            }
+        }
+    }
+
   if ( send_as4_path )
     {
       /* If the peer is NOT As4 capable, AND */
@@ -3439,6 +3581,11 @@ bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
                             u_char *tag, int addpath_encode,
                              u_int32_t addpath_tx_id, struct attr *attr)
 {
+  u_char wlabel[3] = {0x80, 0x00, 0x00};
+
+  if (safi == SAFI_LABELED_UNICAST)
+    tag = wlabel;
+
   return bgp_packet_mpattr_prefix (s, afi, safi, p, prd,
                                    tag, addpath_encode, addpath_tx_id, attr);
 }
@@ -3626,6 +3773,24 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
     }
 
+  /* Prefix SID */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID))
+    {
+      assert (attr->extra);
+
+      if (attr->extra->label_index != BGP_INVALID_LABEL_INDEX)
+        {
+          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+          stream_putc (s, BGP_ATTR_PREFIX_SID);
+          stream_putc (s, 10);
+          stream_putc (s, BGP_PREFIX_SID_LABEL_INDEX);
+          stream_putc (s, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
+          stream_putc (s, 0); // reserved
+          stream_putw (s, 0); // flags
+          stream_putl (s, attr->extra->label_index);
+        }
+    }
+
   /* Return total size of attribute. */
   len = stream_get_endp (s) - cp - 2;
   stream_putw_at (s, cp, len);
index 015039c6cd671e4ce8ef0a345d36f7dbbaa88f58..3351ad2239c681239d3d63c9c31b5435e084de4a 100644 (file)
@@ -57,6 +57,14 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #define BGP_ATTR_NHLEN_VPNV6_GLOBAL       8+IPV6_MAX_BYTELEN
 #define BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL ((8+IPV6_MAX_BYTELEN) * 2)
 
+/* Prefix SID types */
+#define BGP_PREFIX_SID_LABEL_INDEX     1
+#define BGP_PREFIX_SID_IPV6            2
+#define BGP_PREFIX_SID_ORIGINATOR_SRGB 3
+
+#define BGP_PREFIX_SID_LABEL_INDEX_LENGTH      7
+#define BGP_PREFIX_SID_IPV6_LENGTH            19
+#define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH  6
 
 struct bgp_attr_encap_subtlv {
     struct bgp_attr_encap_subtlv       *next;          /* for chaining */
@@ -134,6 +142,9 @@ struct attr_extra
   /* route tag */
   route_tag_t tag;
 
+  /* Label index */
+  u_int32_t label_index;
+
   uint16_t                     encap_tunneltype;       /* grr */
   struct bgp_attr_encap_subtlv *encap_subtlvs;         /* rfc5512 */
 
@@ -160,7 +171,7 @@ struct attr
   unsigned long refcnt;
 
   /* Flag of attribute is set or not. */
-  u_int32_t flag;
+  uint64_t flag;
   
   /* Apart from in6_addr, the remaining static attributes */
   struct in_addr nexthop;
@@ -201,7 +212,7 @@ struct transit
   u_char *val;
 };
 
-#define ATTR_FLAG_BIT(X)  (1 << ((X) - 1))
+#define ATTR_FLAG_BIT(X)  (1ULL << ((X) - 1))
 
 #define BGP_CLUSTER_LIST_LENGTH(attr)                          \
   (((attr)->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) ?     \
index 232f53c778a7487f59f9f9d9745e9e5e2e2344e4..0bd74dbdc4ba6a9f9e8069e037e1a799dde175fd 100644 (file)
@@ -450,6 +450,13 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
     snprintf (buf + strlen (buf), size - strlen (buf), ", path %s",
              aspath_print (attr->aspath));
 
+  if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID)))
+    {
+      if (attr->extra->label_index != BGP_INVALID_LABEL_INDEX)
+        snprintf (buf + strlen (buf), size - strlen (buf), ", label-index %u",
+              attr->extra->label_index);
+    }
+
   if (strlen (buf) > 1)
     return 1;
   else
index 2bbdca595c512cd22909bfc938f7217871d5ff0a..b17888482489aacd11944cf0b532099ece4126dd 100644 (file)
@@ -1142,9 +1142,11 @@ bgp_stop (struct peer *peer)
   /* Reset prefix count */
   peer->pcount[AFI_IP][SAFI_UNICAST] = 0;
   peer->pcount[AFI_IP][SAFI_MULTICAST] = 0;
+  peer->pcount[AFI_IP][SAFI_LABELED_UNICAST] = 0;
   peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0;
   peer->pcount[AFI_IP6][SAFI_UNICAST] = 0;
   peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0;
+  peer->pcount[AFI_IP6][SAFI_LABELED_UNICAST] = 0;
 #endif /* 0 */
 
   if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) &&
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
new file mode 100644 (file)
index 0000000..e4186a5
--- /dev/null
@@ -0,0 +1,342 @@
+/* BGP carrying label information
+ * Copyright (C) 2013 Cumulus Networks, Inc.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "thread.h"
+#include "prefix.h"
+#include "zclient.h"
+#include "stream.h"
+#include "network.h"
+#include "log.h"
+#include "memory.h"
+#include "nexthop.h"
+#include "mpls.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_label.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_debug.h"
+
+extern struct zclient *zclient;
+
+int
+bgp_parse_fec_update (void)
+{
+  struct stream *s;
+  struct bgp_node *rn;
+  struct bgp *bgp;
+  struct bgp_table *table;
+  struct prefix p;
+  u_int32_t label;
+  afi_t afi;
+  safi_t safi;
+
+  s = zclient->ibuf;
+
+  memset(&p, 0, sizeof(struct prefix));
+  p.family = stream_getw(s);
+  p.prefixlen = stream_getc(s);
+  stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+  label = stream_getl(s);
+
+  /* hack for the bgp instance & SAFI = have to send/receive it */
+  afi = family2afi(p.family);
+  safi = SAFI_LABELED_UNICAST;
+  bgp = bgp_get_default();
+  if (!bgp)
+    {
+      zlog_debug("no default bgp instance");
+      return -1;
+    }
+
+  table = bgp->rib[afi][safi];
+  if (!table)
+    {
+      zlog_debug("no %u labeled-unicast table", p.family);
+      return -1;
+    }
+  rn = bgp_node_lookup(table, &p);
+  if (!rn)
+    {
+      zlog_debug("no node for the prefix");
+      return -1;
+    }
+
+  /* treat it as implicit withdraw - the label is invalid */
+  if (label == MPLS_INVALID_LABEL)
+    bgp_unset_valid_label(rn->local_label);
+  else
+    {
+      label_ntop(label, 1, rn->local_label);
+      bgp_set_valid_label(rn->local_label);
+    }
+  SET_FLAG(rn->flags, BGP_NODE_LABEL_CHANGED);
+  bgp_unlock_node (rn);
+  bgp_process (bgp, rn, afi, safi);
+  return 1;
+}
+
+u_char *
+bgp_adv_label (struct bgp_node *rn, struct bgp_info *ri, struct peer *to,
+          afi_t afi, safi_t safi)
+{
+  struct peer *from;
+  u_char *remote_label;
+  int reflect;
+
+  if (!rn || !ri || !to)
+    return NULL;
+
+  remote_label = ri->extra ? ri->extra->tag : NULL;
+  from = ri->peer;
+  reflect = ((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP));
+
+  if (reflect && !CHECK_FLAG(to->af_flags[afi][safi],
+                            PEER_FLAG_FORCE_NEXTHOP_SELF))
+    return remote_label;
+
+  if (CHECK_FLAG(to->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED))
+    return remote_label;
+
+  return rn->local_label;
+}
+
+void
+bgp_reg_dereg_for_label (struct bgp_node *rn, struct bgp_info *ri,
+                         int reg)
+{
+  struct stream *s;
+  struct prefix *p;
+  int command;
+  u_int16_t flags = 0;
+  size_t flags_pos = 0;
+
+  /* Check socket. */
+  if (!zclient || zclient->sock < 0)
+    return;
+
+  p = &(rn->p);
+  s = zclient->obuf;
+  stream_reset (s);
+  command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER;
+  zclient_create_header (s, command, VRF_DEFAULT);
+  flags_pos = stream_get_endp (s); /* save position of 'flags' */
+  stream_putw(s, flags); /* initial flags */
+  stream_putw(s, PREFIX_FAMILY(p));
+  stream_put_prefix(s, p);
+  if (reg)
+    {
+      assert (ri);
+      if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID))
+        {
+          assert (ri->attr->extra);
+
+          if (ri->attr->extra->label_index != BGP_INVALID_LABEL_INDEX)
+            {
+              flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
+              stream_putl (s, ri->attr->extra->label_index);
+            }
+        }
+      SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
+    }
+  else
+    UNSET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
+
+  /* Set length and flags */
+  stream_putw_at (s, 0, stream_get_endp (s));
+  stream_putw_at (s, flags_pos, flags);
+
+  zclient_send_message(zclient);
+}
+
+static int
+bgp_nlri_get_labels (struct peer *peer, u_char *pnt, u_char plen,
+                      u_char label[])
+{
+  u_char *data = pnt;
+  u_char *lim = pnt + plen;
+  u_char llen = 0;
+
+  for (; data < lim; data += BGP_LABEL_BYTES)
+    {
+      memcpy(label, data, BGP_LABEL_BYTES);
+      llen += 3;
+      if (bgp_is_withdraw_label(label) || label_bos(label))
+        break;
+    }
+  if (!(bgp_is_withdraw_label(label) || label_bos(label)))
+      zlog_warn("%s: [Update:RCVD] invalid label - no bottom of stack",
+                peer->host);
+
+  return llen;
+}
+
+int
+bgp_nlri_parse_label (struct peer *peer, struct attr *attr,
+                      struct bgp_nlri *packet)
+{
+  u_char *pnt;
+  u_char *lim;
+  struct prefix p;
+  int psize = 0;
+  int prefixlen;
+  afi_t afi;
+  safi_t safi;
+  int addpath_encoded;
+  u_int32_t addpath_id;
+  u_char label[3];
+  u_char llen;
+
+  /* Check peer status. */
+  if (peer->status != Established)
+    return 0;
+
+  pnt = packet->nlri;
+  lim = pnt + packet->length;
+  afi = packet->afi;
+  safi = packet->safi;
+  addpath_id = 0;
+
+  addpath_encoded = (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) &&
+                     CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV));
+
+  for (; pnt < lim; pnt += psize)
+    {
+      /* Clear prefix structure. */
+      memset (&p, 0, sizeof (struct prefix));
+      llen = 0;
+
+      if (addpath_encoded)
+        {
+
+          /* When packet overflow occurs return immediately. */
+          if (pnt + BGP_ADDPATH_ID_LEN > lim)
+            return -1;
+
+          addpath_id = ntohl(*((uint32_t*) pnt));
+          pnt += BGP_ADDPATH_ID_LEN;
+        }
+
+      /* Fetch prefix length. */
+      prefixlen = *pnt++;
+      p.family = afi2family (packet->afi);
+      psize = PSIZE (prefixlen);
+
+      /* sanity check against packet data */
+      if ((pnt + psize) > lim)
+        {
+          zlog_err ("%s [Error] Update packet error / L-U (prefix length %d exceeds packet size %u)",
+                    peer->host,
+                    prefixlen, (uint)(lim-pnt));
+          return -1;
+        }
+
+      /* Fill in the labels */
+      llen = bgp_nlri_get_labels(peer, pnt, psize, label);
+      // zlog_debug("rcvd label [%x/%x/%x], llen=%d\n", label[0], label[1], label[2], llen);
+      p.prefixlen = prefixlen - BSIZE(llen);
+
+      /* There needs to be at least one label */
+      if (prefixlen < 24)
+        {
+          zlog_err ("%s [Error] Update packet error"
+                    " (wrong label length %d)",
+                    peer->host, prefixlen);
+          bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+                           BGP_NOTIFY_UPDATE_INVAL_NETWORK);
+          return -1;
+        }
+
+      if ((afi == AFI_IP && p.prefixlen > 32)
+         || (afi == AFI_IP6 && p.prefixlen > 128))
+       return -1;
+
+      /* Fetch prefix from NLRI packet */
+      memcpy (&p.u.prefix, pnt + llen, psize - llen);
+
+      /* Check address. */
+      if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
+        {
+          if (IN_CLASSD (ntohl (p.u.prefix4.s_addr)))
+            {
+              /* From RFC4271 Section 6.3:
+               *
+               * If a prefix in the NLRI field is semantically incorrect
+               * (e.g., an unexpected multicast IP address), an error SHOULD
+               * be logged locally, and the prefix SHOULD be ignored.
+                */
+              zlog_err ("%s: IPv4 labeled-unicast NLRI is multicast address %s, ignoring",
+                        peer->host, inet_ntoa (p.u.prefix4));
+              continue;
+            }
+        }
+
+      /* Check address. */
+      if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
+        {
+          if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
+            {
+              char buf[BUFSIZ];
+
+              zlog_err ("%s: IPv6 labeled-unicast NLRI is link-local address %s, ignoring",
+                        peer->host, inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ));
+
+              continue;
+            }
+
+          if (IN6_IS_ADDR_MULTICAST (&p.u.prefix6))
+            {
+              char buf[BUFSIZ];
+
+              zlog_err ("%s: IPv6 unicast NLRI is multicast address %s, ignoring",
+                        peer->host, inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ));
+
+              continue;
+            }
+        }
+
+      if (attr)
+        {
+          bgp_update (peer, &p, addpath_id, attr, packet->afi, SAFI_LABELED_UNICAST,
+                      ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, 0, NULL);
+        }
+      else
+        {
+          bgp_withdraw (peer, &p, addpath_id, attr, packet->afi, SAFI_LABELED_UNICAST,
+                        ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, NULL);
+        }
+    }
+
+  /* Packet length consistency check. */
+  if (pnt != lim)
+    {
+      zlog_err ("%s [Error] Update packet error / L-U (%zu data remaining after parsing)",
+                peer->host, lim - pnt);
+      return -1;
+    }
+
+  return 0;
+}
diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h
new file mode 100644 (file)
index 0000000..49a7b94
--- /dev/null
@@ -0,0 +1,125 @@
+/* BGP carrying Label information
+ * Copyright (C) 2013 Cumulus Networks, Inc.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _BGP_LABEL_H
+#define _BGP_LABEL_H
+
+#define BGP_LABEL_BYTES 3
+#define BGP_LABEL_BITS 24
+#define BGP_WITHDRAW_LABEL 0x800000
+
+struct bgp_node;
+struct bgp_info;
+struct peer;
+
+extern void bgp_reg_dereg_for_label (struct bgp_node *rn, struct bgp_info *ri,
+                                     int reg);
+extern int bgp_parse_fec_update(void);
+extern u_char * bgp_adv_label(struct bgp_node *rn, struct bgp_info *ri,
+                             struct peer *to, afi_t afi, safi_t safi);
+
+extern int bgp_nlri_parse_label (struct peer *peer, struct attr *attr,
+                                 struct bgp_nlri *packet);
+
+static inline int
+bgp_labeled_safi (safi_t safi)
+{
+  if ((safi == SAFI_LABELED_UNICAST) || (safi == SAFI_MPLS_VPN))
+    return 1;
+  return 0;
+}
+
+static inline int
+bgp_is_withdraw_label (u_char *pkt)
+{
+  if ((pkt[0] == 0x80) && (pkt[1] == 0x00) && (pkt[2] == 0x00))
+      return 1;
+  return 0;
+}
+
+static inline u_char *
+bgp_encode_withdraw_label (u_char *pkt)
+{
+  *pkt++ = 0x80; *pkt++ = 0x00; *pkt++ = 0x00;
+  return pkt;
+}
+
+static inline int
+bgp_is_valid_label (u_char *t)
+{
+  if (!t)
+    return 0;
+  return (t[2] & 0x02);
+}
+
+static inline void
+bgp_set_valid_label (u_char *t)
+{
+  if (t)
+    t[2] |= 0x02;
+}
+
+static inline void
+bgp_unset_valid_label (u_char *t)
+{
+  if (t)
+    t[2] &= ~0x02;
+}
+
+static inline void
+bgp_register_for_label (struct bgp_node *rn, struct bgp_info *ri)
+{
+  bgp_reg_dereg_for_label (rn, ri, 1);
+}
+
+static inline void
+bgp_unregister_for_label (struct bgp_node *rn)
+{
+  bgp_reg_dereg_for_label (rn, NULL, 0);
+}
+
+/* Label stream to value */
+static inline u_int32_t
+label_pton (u_char t[])
+{
+  return ((((unsigned int) t[0]) << 12) | (((unsigned int) t[1]) << 4) |
+         ((unsigned int) ((t[2] & 0xF0) >> 4)));
+}
+
+/* Encode label values */
+static inline void
+label_ntop (u_int32_t l, int bos, u_char t[])
+{
+  t[0] = ((l & 0x000FF000) >> 12);
+  t[1] = ((l & 0x00000FF0) >> 4);
+  t[2] = ((l & 0x0000000F) << 4);
+  if (bos)
+    t[2] |= 0x01;
+}
+
+/* Return BOS value of label stream */
+static inline u_char
+label_bos (u_char t[])
+{
+  return (t[2] & 0x01);
+};
+
+#endif /* _BGP_LABEL_H */
index 1773070fe3551f3f27d3067caec7fc48515d89ad..3b844cf70ec8966e678e7085e1598e405e929248 100644 (file)
@@ -237,6 +237,8 @@ bgp_exit (int status)
     stream_free (bgp_nexthop_buf);
   if (bgp_ifindices_buf)
     stream_free (bgp_ifindices_buf);
+  if (bgp_label_buf)
+    stream_free (bgp_label_buf);
 
   /* reverse bgp_master_init */
   if (bm->master)
index b0362b5537dfb280c2e1a284d3f5bd4012e98475..1e8dc5d9744c95cb24aa4326082fc8c373778e17 100644 (file)
@@ -404,8 +404,9 @@ bgp_parse_nexthop_update (int command, vrf_id_t vrf_id)
     {
       char buf[PREFIX2STR_BUFFER];
       prefix2str(&p, buf, sizeof (buf));
-      zlog_debug("%d: NH update for %s - metric %d (cur %d) #nhops %d (cur %d)",
-                 vrf_id, buf, metric, bnc->metric, nexthop_num, bnc->nexthop_num);
+      zlog_debug("%d: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
+                 vrf_id, buf, metric, bnc->metric, nexthop_num, bnc->nexthop_num,
+                 bnc->flags);
     }
 
   if (metric != bnc->metric)
@@ -678,6 +679,8 @@ evaluate_paths (struct bgp_nexthop_cache *bnc)
   struct bgp *bgp = bnc->bgp;
   int afi;
   struct peer *peer = (struct peer *)bnc->nht_info;
+  struct bgp_table *table;
+  safi_t safi;
 
   if (BGP_DEBUG(nht, NHT))
     {
@@ -695,7 +698,10 @@ evaluate_paths (struct bgp_nexthop_cache *bnc)
        continue;
 
       rn = path->net;
+      assert (rn && bgp_node_table (rn));
       afi = family2afi(rn->p.family);
+      table = bgp_node_table (rn);
+      safi = table->safi;
 
       /* Path becomes valid/invalid depending on whether the nexthop
        * reachable/unreachable.
@@ -705,15 +711,13 @@ evaluate_paths (struct bgp_nexthop_cache *bnc)
        {
          if (CHECK_FLAG (path->flags, BGP_INFO_VALID))
            {
-             bgp_aggregate_decrement (bgp, &rn->p, path,
-                                      afi, SAFI_UNICAST);
+             bgp_aggregate_decrement (bgp, &rn->p, path, afi, safi);
              bgp_info_unset_flag (rn, path, BGP_INFO_VALID);
            }
          else
            {
              bgp_info_set_flag (rn, path, BGP_INFO_VALID);
-             bgp_aggregate_increment (bgp, &rn->p, path,
-                                      afi, SAFI_UNICAST);
+             bgp_aggregate_increment (bgp, &rn->p, path, afi, safi);
            }
        }
 
@@ -727,7 +731,7 @@ evaluate_paths (struct bgp_nexthop_cache *bnc)
          CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED))
        SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED);
 
-      bgp_process(bgp, rn, afi, SAFI_UNICAST);
+      bgp_process(bgp, rn, afi, safi);
     }
 
   if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED))
index 51079f31e03b77be43d733e250f41177cf1226b2..83fc3fe97765b9949cf6c76c55eb9d8ed0b5c2bb 100644 (file)
@@ -108,6 +108,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso
                   case SAFI_MULTICAST:
                     json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "multicast");
                   break;
+                  case SAFI_LABELED_UNICAST:
+                    json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "labeled-unicast");
+                  break;
                   case SAFI_MPLS_VPN:
                     json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "MPLS-labeled VPN");
                   break;
@@ -148,6 +151,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso
                   case SAFI_MULTICAST:
                     vty_out (vty, "SAFI Multicast");
                   break;
+                  case SAFI_LABELED_UNICAST:
+                    vty_out (vty, "SAFI Labeled-unicast");
+                  break;
                   case SAFI_MPLS_VPN:
                     vty_out (vty, "SAFI MPLS-labeled VPN");
                   break;
@@ -1143,10 +1149,12 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability)
     {
       if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] 
          && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST]
+         && ! peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST]
          && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
          && ! peer->afc_nego[AFI_IP][SAFI_ENCAP]
          && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
          && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]
+         && ! peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST]
          && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]
          && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP]
          && ! peer->afc_nego[AFI_L2VPN][SAFI_EVPN])
index 853fcc8697f6378a1d16ff8261b656dc07d2b4bc..0800dd74bafa5b6dd41d76e589544e5d3178b733 100644 (file)
@@ -55,6 +55,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_advertise.h"
 #include "bgpd/bgp_vty.h"
 #include "bgpd/bgp_updgrp.h"
+#include "bgpd/bgp_label.h"
 
 /* Set up BGP packet marker and packet type. */
 int
@@ -1153,8 +1154,10 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
     {
       peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST];
       peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST];
+      peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] = peer->afc[AFI_IP][SAFI_LABELED_UNICAST];
       peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST];
       peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST];
+      peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] = peer->afc[AFI_IP6][SAFI_LABELED_UNICAST];
     }
 
   /* When collision is detected and this peer is closed.  Retrun
@@ -1342,6 +1345,8 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet, i
       case SAFI_UNICAST:
       case SAFI_MULTICAST:
         return bgp_nlri_parse_ip (peer, mp_withdraw?NULL:attr, packet);
+      case SAFI_LABELED_UNICAST:
+        return bgp_nlri_parse_label (peer, mp_withdraw?NULL:attr, packet);
       case SAFI_MPLS_VPN:
         return bgp_nlri_parse_vpn (peer, mp_withdraw?NULL:attr, packet);
       case SAFI_ENCAP:
@@ -1386,6 +1391,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
   /* Set initial values. */
   memset (&attr, 0, sizeof (struct attr));
   memset (&extra, 0, sizeof (struct attr_extra));
+  extra.label_index = BGP_INVALID_LABEL_INDEX;
   memset (&nlris, 0, sizeof (nlris));
   attr.extra = &extra;
   memset (peer->rcvd_attr_str, 0, BUFSIZ);
index d3a6e7e9063a89f3fb386f8aa097c5404ead0acb..f327e34f2ac42bd39c5530ada904ea65e4375f6a 100644 (file)
@@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "thread.h"
 #include "workqueue.h"
 #include "queue.h"
+#include "mpls.h"
 #include "memory.h"
 #include "lib/json.h"
 
@@ -62,6 +63,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_mpath.h"
 #include "bgpd/bgp_nht.h"
 #include "bgpd/bgp_updgrp.h"
+#include "bgpd/bgp_label.h"
 
 #if ENABLE_BGP_VNC
 #include "bgpd/rfapi/rfapi_backend.h"
@@ -296,6 +298,11 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri)
     }
 }
 
+static int
+bgp_label_index_differs (struct bgp_info *ri1, struct bgp_info *ri2)
+{
+  return (!(ri1->attr->extra->label_index == ri2->attr->extra->label_index));
+}
 
 /* Set/unset bgp_info flags, adjusting any other state as needed.
  * This is here primarily to keep prefix-count in check.
@@ -1187,7 +1194,8 @@ subgroup_announce_reset_nhop (u_char family, struct attr *attr)
 }
 
 int
-subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
+subgroup_announce_check (struct bgp_node *rn, struct bgp_info *ri,
+                         struct update_subgroup *subgrp,
                         struct prefix *p, struct attr *attr)
 {
   struct bgp_filter *filter;
@@ -1261,6 +1269,21 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
        return 0;
       }
 
+  /* If it's labeled safi, make sure the route has a valid label. */
+  if (bgp_labeled_safi(safi))
+    {
+      u_char *tag = bgp_adv_label(rn, ri, peer, afi, safi);
+      if (!bgp_is_valid_label(tag))
+        {
+          if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
+           zlog_debug ("u%" PRIu64 ":s%" PRIu64 " %s/%d is filtered - no label (%p)",
+                  subgrp->update_group->id, subgrp->id,
+                 inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+                 p->prefixlen, tag);
+          return 0;
+        }
+    }
+
   /* Do not send back route to sender. */
   if (onlypeer && from == onlypeer)
     {
@@ -1804,7 +1827,7 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp,
   /* Announcement to the subgroup.  If the route is filtered withdraw it. */
   if (selected)
     {
-      if (subgroup_announce_check(selected, subgrp, p, &attr))
+      if (subgroup_announce_check(rn, selected, subgrp, p, &attr))
         bgp_adj_out_set_subgroup(rn, subgrp, &attr, selected);
       else
         bgp_adj_out_unset_subgroup(rn, subgrp, 1, selected->addpath_tx_id);
@@ -1914,7 +1937,40 @@ bgp_process_main (struct work_queue *wq, void *data)
   old_select = old_and_new.old;
   new_select = old_and_new.new;
 
-  /* Nothing to do. */
+  /* Do we need to allocate or free labels?
+   * Right now, since we only deal with per-prefix labels, it is not necessary
+   * to do this upon changes to best path except of the label index changes.
+   */
+  bgp_table_lock (bgp_node_table (rn));
+  if (bgp_labeled_safi (safi))
+    {
+      if (new_select)
+        {
+          if (!old_select ||
+              bgp_label_index_differs (new_select, old_select) ||
+              new_select->sub_type != old_select->sub_type)
+            {
+              if (new_select->sub_type == BGP_ROUTE_STATIC &&
+                  new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID) &&
+                  new_select->attr->extra->label_index != BGP_INVALID_LABEL_INDEX)
+                {
+                  if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
+                    bgp_unregister_for_label (rn);
+                  label_ntop (MPLS_IMP_NULL_LABEL, 1, rn->local_label);
+                  bgp_set_valid_label(rn->local_label);
+                }
+              else
+                bgp_register_for_label (rn, new_select);
+            }
+        }
+      else if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
+        bgp_unregister_for_label (rn);
+    }
+
+  /* If best route remains the same and this is not due to user-initiated
+   * clear, see exactly what needs to be done.
+   */
+
   if (old_select && old_select == new_select &&
       !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR) &&
       !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) &&
@@ -1926,10 +1982,26 @@ bgp_process_main (struct work_queue *wq, void *data)
               vnc_import_bgp_add_route(bgp, p, old_select);
               vnc_import_bgp_exterior_add_route(bgp, p, old_select);
 #endif
-        bgp_zebra_announce (p, old_select, bgp, afi, safi);
+          if (bgp_fibupd_safi(safi) &&
+              !bgp->name &&
+              !bgp_option_check (BGP_OPT_NO_FIB) &&
+              new_select->type == ZEBRA_ROUTE_BGP &&
+              new_select->sub_type == BGP_ROUTE_NORMAL)
+            bgp_zebra_announce (rn, p, old_select, bgp, afi, safi);
         }
       UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
       bgp_zebra_clear_route_change_flags (rn);
+
+      /* If there is a change of interest to peers, reannounce the route. */
+      if (CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED) ||
+          CHECK_FLAG (rn->flags, BGP_NODE_LABEL_CHANGED))
+        {
+          group_announce_route(bgp, afi, safi, rn, new_select);
+
+          UNSET_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED);
+          UNSET_FLAG (rn->flags, BGP_NODE_LABEL_CHANGED);
+         }
+
       UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
       return WQ_SUCCESS;
     }
@@ -1978,7 +2050,7 @@ bgp_process_main (struct work_queue *wq, void *data)
   group_announce_route(bgp, afi, safi, rn, new_select);
 
   /* FIB update. */
-  if ((safi == SAFI_UNICAST || safi == SAFI_MULTICAST) &&
+  if (bgp_fibupd_safi(safi) &&
       (bgp->inst_type != BGP_INSTANCE_TYPE_VIEW) &&
       !bgp_option_check (BGP_OPT_NO_FIB))
     {
@@ -1986,7 +2058,7 @@ bgp_process_main (struct work_queue *wq, void *data)
          && new_select->type == ZEBRA_ROUTE_BGP 
          && (new_select->sub_type == BGP_ROUTE_NORMAL ||
               new_select->sub_type == BGP_ROUTE_AGGREGATE))
-       bgp_zebra_announce (p, new_select, bgp, afi, safi);
+       bgp_zebra_announce (rn, p, new_select, bgp, afi, safi);
       else
        {
          /* Withdraw the route from the kernel. */
@@ -2406,6 +2478,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
   struct bgp_info *new;
   const char *reason;
   char pfx_buf[BGP_PRD_PATH_STRLEN];
+  char label_buf[20];
   int connected = 0;
   int do_loop_check = 1;
 #if ENABLE_BGP_VNC
@@ -2417,6 +2490,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
   bgp = peer->bgp;
   rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);
+  label_buf[0] = '\0';
+  if (bgp_labeled_safi(safi))
+    sprintf (label_buf, "label %u", label_pton(tag));
   
   /* When peer's soft reconfiguration enabled.  Record input packet in
      Adj-RIBs-In.  */
@@ -2516,6 +2592,8 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
       /* Same attribute comes in. */
       if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED) 
           && attrhash_cmp (ri->attr, attr_new)
+          && (!bgp_labeled_safi(safi) ||
+              memcmp ((bgp_info_extra_get (ri))->tag, tag, 3) == 0)
           && (overlay_index_equal(afi, ri, evpn==NULL?NULL:&evpn->eth_s_id,
                                   evpn==NULL?NULL:&evpn->gw_ip)))
        {
@@ -2524,9 +2602,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
              && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
            {
              if (bgp_debug_update(peer, p, NULL, 1))
-                zlog_debug ("%s rcvd %s", peer->host,
+                zlog_debug ("%s rcvd %s %s", peer->host,
                             bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
-                                      addpath_id, pfx_buf, sizeof (pfx_buf)));
+                                      addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf);
 
              if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED)
                {
@@ -2544,10 +2622,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                     peer->rcvd_attr_printed = 1;
                   }
 
-                 zlog_debug ("%s rcvd %s...duplicate ignored",
+                 zlog_debug ("%s rcvd %s %s...duplicate ignored",
                              peer->host,
                               bgp_debug_rdpfxpath2str (prd, p, addpath_id ?
-                                1 : 0, addpath_id, pfx_buf, sizeof (pfx_buf)));
+                                1 : 0, addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf);
                 }
 
              /* graceful restart STALE flag unset. */
@@ -2568,18 +2646,18 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
       if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
         {
           if (bgp_debug_update(peer, p, NULL, 1))
-            zlog_debug ("%s rcvd %s, flapped quicker than processing",
+            zlog_debug ("%s rcvd %s %s, flapped quicker than processing",
                         peer->host,
                         bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
-                                  addpath_id, pfx_buf, sizeof (pfx_buf)));
+                                  addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf);
           bgp_info_restore (rn, ri);
         }
 
       /* Received Logging. */
       if (bgp_debug_update(peer, p, NULL, 1))
-         zlog_debug ("%s rcvd %s", peer->host,
+         zlog_debug ("%s rcvd %s %s", peer->host,
                       bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
-                                        addpath_id, pfx_buf, sizeof (pfx_buf)));
+                                        addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf);
 
       /* graceful restart STALE flag unset. */
       if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
@@ -2637,7 +2715,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
       ri->attr = attr_new;
 
       /* Update MPLS tag.  */
-      if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN)
+      if (bgp_labeled_safi(safi))
         memcpy ((bgp_info_extra_get (ri))->tag, tag, 3);
 
 #if ENABLE_BGP_VNC
@@ -2678,8 +2756,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
            }
        }
 
-      /* Nexthop reachability check. */
-      if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST)
+      /* Nexthop reachability check - for unicast and labeled-unicast.. */
+      if ((afi == AFI_IP || afi == AFI_IP6) &&
+          (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST))
        {
          if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 &&
              ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
@@ -2759,16 +2838,16 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
           peer->rcvd_attr_printed = 1;
         }
 
-      zlog_debug ("%s rcvd %s", peer->host,
+      zlog_debug ("%s rcvd %s%s ", peer->host,
                   bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
-                                 addpath_id, pfx_buf, sizeof (pfx_buf)));
+                                 addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf);
     }
 
   /* Make new BGP info. */
   new = info_make(type, sub_type, 0, peer, attr_new, rn);
 
   /* Update MPLS tag. */
-  if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN)
+  if (bgp_labeled_safi(safi) || safi == SAFI_EVPN)
     memcpy ((bgp_info_extra_get (new))->tag, tag, 3);
 
   /* Update Overlay Index */
@@ -2778,7 +2857,8 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                            evpn==NULL?NULL:&evpn->gw_ip);
     }
   /* Nexthop reachability check. */
-  if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST)
+  if ((afi == AFI_IP || afi == AFI_IP6) &&
+       (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST))
     {
       if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 &&
          ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
@@ -2873,10 +2953,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
           peer->rcvd_attr_printed = 1;
         }
 
-      zlog_debug ("%s rcvd UPDATE about %s -- DENIED due to: %s",
+      zlog_debug ("%s rcvd UPDATE about %s %s -- DENIED due to: %s",
                   peer->host,
                   bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
-                             addpath_id, pfx_buf, sizeof (pfx_buf)), reason);
+                             addpath_id, pfx_buf, sizeof (pfx_buf)), label_buf, reason);
     }
 
   if (ri)
@@ -3702,9 +3782,9 @@ bgp_static_free (struct bgp_static *bgp_static)
   XFREE (MTYPE_BGP_STATIC, bgp_static);
 }
 
-static void
-bgp_static_update_main (struct bgp *bgp, struct prefix *p,
-                       struct bgp_static *bgp_static, afi_t afi, safi_t safi)
+void
+bgp_static_update (struct bgp *bgp, struct prefix *p,
+                   struct bgp_static *bgp_static, afi_t afi, safi_t safi)
 {
   struct bgp_node *rn;
   struct bgp_info *ri;
@@ -3732,6 +3812,13 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
   if (bgp_static->atomic)
     attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
 
+  /* Store label index, if required. */
+  if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX)
+    {
+      (bgp_attr_extra_get (&attr))->label_index = bgp_static->label_index;
+      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID);
+    }
+
   /* Apply route-map. */
   if (bgp_static->rmap.name)
     {
@@ -3818,9 +3905,11 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
 #endif
 
          /* Nexthop reachability check. */
-         if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
+         if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK) &&
+              safi == SAFI_UNICAST)
            {
-             if (bgp_find_or_add_nexthop (bgp, afi, ri, NULL, 0))
+             if (bgp_find_or_add_nexthop (bgp, afi, ri, NULL, 0) &&
+                  safi == SAFI_UNICAST)
                bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
              else
                {
@@ -3903,13 +3992,6 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
   bgp_attr_extra_free (&attr);
 }
 
-void
-bgp_static_update (struct bgp *bgp, struct prefix *p,
-                  struct bgp_static *bgp_static, afi_t afi, safi_t safi)
-{
-  bgp_static_update_main (bgp, p, bgp_static, afi, safi);
-}
-
 void
 bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi,
                     safi_t safi)
@@ -4158,7 +4240,8 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
    route should be installed as valid.  */
 static int
 bgp_static_set (struct vty *vty, const char *ip_str, 
-                afi_t afi, safi_t safi, const char *rmap, int backdoor)
+                afi_t afi, safi_t safi, const char *rmap, int backdoor,
+                u_int32_t label_index)
 {
   VTY_DECLVAR_CONTEXT(bgp, bgp);
   int ret;
@@ -4191,6 +4274,13 @@ bgp_static_set (struct vty *vty, const char *ip_str,
       /* Configuration change. */
       bgp_static = rn->info;
 
+      /* Label index cannot be changed. */
+      if (bgp_static->label_index != label_index)
+        {
+          vty_out (vty, "%% Label index cannot be changed%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+
       /* Check previous routes are installed into BGP.  */
       if (bgp_static->valid && bgp_static->backdoor != backdoor)
         need_update = 1;
@@ -4222,6 +4312,7 @@ bgp_static_set (struct vty *vty, const char *ip_str,
       bgp_static->valid = 0;
       bgp_static->igpmetric = 0;
       bgp_static->igpnexthop.s_addr = 0;
+      bgp_static->label_index = label_index;
       
       if (rmap)
        {
@@ -4748,7 +4839,8 @@ DEFUN (bgp_network,
 {
   int idx_ipv4_prefixlen = 1;
   return bgp_static_set (vty, argv[idx_ipv4_prefixlen]->arg,
-                        AFI_IP, bgp_node_safi (vty), NULL, 0);
+                        AFI_IP, bgp_node_safi (vty), NULL, 0,
+                         BGP_INVALID_LABEL_INDEX);
 }
 
 DEFUN (bgp_network_route_map,
@@ -4762,7 +4854,8 @@ DEFUN (bgp_network_route_map,
   int idx_ipv4_prefixlen = 1;
   int idx_word = 3;
   return bgp_static_set (vty, argv[idx_ipv4_prefixlen]->arg,
-                        AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0);
+                        AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0,
+                         BGP_INVALID_LABEL_INDEX);
 }
 
 DEFUN (bgp_network_backdoor,
@@ -4774,7 +4867,7 @@ DEFUN (bgp_network_backdoor,
 {
   int idx_ipv4_prefixlen = 1;
   return bgp_static_set (vty, argv[idx_ipv4_prefixlen]->arg, AFI_IP, SAFI_UNICAST,
-                         NULL, 1);
+                         NULL, 1, BGP_INVALID_LABEL_INDEX);
 }
 
 DEFUN (bgp_network_mask,
@@ -4798,7 +4891,7 @@ DEFUN (bgp_network_mask,
     }
 
   return bgp_static_set (vty, prefix_str,
-                        AFI_IP, bgp_node_safi (vty), NULL, 0);
+                        AFI_IP, bgp_node_safi (vty), NULL, 0, BGP_INVALID_LABEL_INDEX);
 }
 
 DEFUN (bgp_network_mask_route_map,
@@ -4825,7 +4918,7 @@ DEFUN (bgp_network_mask_route_map,
     }
 
   return bgp_static_set (vty, prefix_str,
-                        AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0);
+                        AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0, BGP_INVALID_LABEL_INDEX);
 }
 
 DEFUN (bgp_network_mask_backdoor,
@@ -4850,7 +4943,8 @@ DEFUN (bgp_network_mask_backdoor,
     }
 
   return bgp_static_set (vty, prefix_str, AFI_IP, SAFI_UNICAST,
-                         NULL, 1);
+                         NULL, 1,
+                         BGP_INVALID_LABEL_INDEX);
 }
 
 DEFUN (bgp_network_mask_natural,
@@ -4871,7 +4965,8 @@ DEFUN (bgp_network_mask_natural,
     }
 
   return bgp_static_set (vty, prefix_str,
-                        AFI_IP, bgp_node_safi (vty), NULL, 0);
+                        AFI_IP, bgp_node_safi (vty), NULL, 0,
+                         BGP_INVALID_LABEL_INDEX);
 }
 
 DEFUN (bgp_network_mask_natural_route_map,
@@ -4895,7 +4990,8 @@ DEFUN (bgp_network_mask_natural_route_map,
     }
 
   return bgp_static_set (vty, prefix_str,
-                        AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0);
+                        AFI_IP, bgp_node_safi (vty), argv[idx_word]->arg, 0,
+                         BGP_INVALID_LABEL_INDEX);
 }
 
 DEFUN (bgp_network_mask_natural_backdoor,
@@ -4917,7 +5013,39 @@ DEFUN (bgp_network_mask_natural_backdoor,
     }
 
   return bgp_static_set (vty, prefix_str, AFI_IP, SAFI_UNICAST,
-                         NULL, 1);
+                         NULL, 1, BGP_INVALID_LABEL_INDEX);
+}
+
+DEFUN (bgp_network_label_index,
+       bgp_network_label_index_cmd,
+       "network A.B.C.D/M label-index (0-4294967294)",
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Label index to associate with the prefix\n"
+       "Label index value\n")
+{
+  u_int32_t label_index;
+
+  VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg);
+  return bgp_static_set (vty, argv[1]->arg,
+                         AFI_IP, bgp_node_safi (vty), NULL, 0, label_index);
+}
+
+DEFUN (bgp_network_label_index_route_map,
+       bgp_network_label_index_route_map_cmd,
+       "network A.B.C.D/M label-index (0-4294967294) route-map WORD",
+       "Specify a network to announce via BGP\n"
+       "IP prefix\n"
+       "Label index to associate with the prefix\n"
+       "Label index value\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+{
+  u_int32_t label_index;
+
+  VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg);
+  return bgp_static_set (vty, argv[1]->arg,
+                         AFI_IP, bgp_node_safi (vty), argv[5]->arg, 0, label_index);
 }
 
 DEFUN (no_bgp_network,
@@ -4988,6 +5116,26 @@ DEFUN (no_bgp_network_mask_natural,
                           bgp_node_safi (vty));
 }
 
+ALIAS (no_bgp_network,
+       no_bgp_network_label_index_cmd,
+       "no network A.B.C.D/M label-index (0-4294967294)",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Label index to associate with the prefix\n"
+       "Label index value\n")
+
+ALIAS (no_bgp_network,
+       no_bgp_network_label_index_route_map_cmd,
+       "no network A.B.C.D/M label-index (0-4294967294) route-map WORD",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IP prefix\n"
+       "Label index to associate with the prefix\n"
+       "Label index value\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
 DEFUN (ipv6_bgp_network,
        ipv6_bgp_network_cmd,
        "network X:X::X:X/M",
@@ -4996,7 +5144,8 @@ DEFUN (ipv6_bgp_network,
 {
   int idx_ipv6_prefixlen = 1;
   return bgp_static_set (vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6, bgp_node_safi(vty),
-                         NULL, 0);
+                         NULL, 0,
+                         BGP_INVALID_LABEL_INDEX);
 }
 
 DEFUN (ipv6_bgp_network_route_map,
@@ -5010,7 +5159,40 @@ DEFUN (ipv6_bgp_network_route_map,
   int idx_ipv6_prefixlen = 1;
   int idx_word = 3;
   return bgp_static_set (vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6,
-                        bgp_node_safi (vty), argv[idx_word]->arg, 0);
+                        bgp_node_safi (vty), argv[idx_word]->arg, 0,
+                         BGP_INVALID_LABEL_INDEX);
+}
+
+DEFUN (ipv6_bgp_network_label_index,
+       ipv6_bgp_network_label_index_cmd,
+       "network X:X::X:X/M label-index (0-4294967294)",
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\n"
+       "Label index to associate with the prefix\n"
+       "Label index value\n")
+{
+  u_int32_t label_index;
+
+  VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg);
+  return bgp_static_set (vty, argv[1]->arg,
+                         AFI_IP6, bgp_node_safi (vty), NULL, 0, label_index);
+}
+
+DEFUN (ipv6_bgp_network_label_index_route_map,
+       ipv6_bgp_network_label_index_route_map_cmd,
+       "network X:X::X:X/M label-index (0-4294967294) route-map WORD",
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix\n"
+       "Label index to associate with the prefix\n"
+       "Label index value\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+{
+  u_int32_t label_index;
+
+  VTY_GET_INTEGER ("label-index", label_index, argv[3]->arg);
+  return bgp_static_set (vty, argv[1]->arg,
+                         AFI_IP6, bgp_node_safi (vty), argv[5]->arg, 0, label_index);
 }
 
 DEFUN (no_ipv6_bgp_network,
@@ -5026,6 +5208,26 @@ DEFUN (no_ipv6_bgp_network,
   return bgp_static_unset (vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6, bgp_node_safi(vty));
 }
 
+ALIAS (no_ipv6_bgp_network,
+       no_ipv6_bgp_network_label_index_cmd,
+       "no network X:X::X:X/M label-index (0-4294967294)",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix <network>/<length>\n"
+       "Label index to associate with the prefix\n"
+       "Label index value\n")
+
+ALIAS (no_ipv6_bgp_network,
+       no_ipv6_bgp_network_label_index_route_map_cmd,
+       "no network X:X::X:X/M label-index (0-4294967294) route-map WORD",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix\n"
+       "Label index to associate with the prefix\n"
+       "Label index value\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n")
+
 /* Aggreagete address:
 
   advertise-map  Set condition to advertise attribute
@@ -5555,9 +5757,11 @@ bgp_aggregate_unset (struct vty *vty, const char *prefix_str,
     }
 
   aggregate = rn->info;
-  if (aggregate->safi & SAFI_UNICAST)
+  if (aggregate->safi == SAFI_UNICAST)
     bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate);
-  if (aggregate->safi & SAFI_MULTICAST)
+  if (aggregate->safi == SAFI_LABELED_UNICAST)
+    bgp_aggregate_delete (bgp, &p, afi, SAFI_LABELED_UNICAST, aggregate);
+  if (aggregate->safi == SAFI_MULTICAST)
     bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate);
 
   /* Unlock aggregate address configuration. */
@@ -5613,9 +5817,11 @@ bgp_aggregate_set (struct vty *vty, const char *prefix_str,
   rn->info = aggregate;
 
   /* Aggregate address insert into BGP routing table. */
-  if (safi & SAFI_UNICAST)
+  if (safi == SAFI_UNICAST)
     bgp_aggregate_add (bgp, &p, afi, SAFI_UNICAST, aggregate);
-  if (safi & SAFI_MULTICAST)
+  if (safi == SAFI_LABELED_UNICAST)
+    bgp_aggregate_add (bgp, &p, afi, SAFI_LABELED_UNICAST, aggregate);
+  if (safi == SAFI_MULTICAST)
     bgp_aggregate_add (bgp, &p, afi, SAFI_MULTICAST, aggregate);
 
   return CMD_SUCCESS;
@@ -5654,9 +5860,8 @@ DEFUN (aggregate_address_mask,
 {
   int idx = 0;
   argv_find (argv, argc, "A.B.C.D", &idx);
-  char *prefix = argv[idx++]->arg;
-  argv_find (argv, argc, "A.B.C.D", &idx);
-  char *mask = argv[idx]->arg;
+  char *prefix = argv[idx]->arg;
+  char *mask = argv[idx+1]->arg;
   int as_set = argv_find (argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0;
   idx = 0;
   int summary_only = argv_find (argv, argc, "summary-only", &idx) ? AGGREGATE_SUMMARY_ONLY : 0;
@@ -5704,9 +5909,8 @@ DEFUN (no_aggregate_address_mask,
 {
   int idx = 0;
   argv_find (argv, argc, "A.B.C.D", &idx);
-  char *prefix = argv[idx++]->arg;
-  argv_find (argv, argc, "A.B.C.D", &idx);
-  char *mask = argv[idx]->arg;
+  char *prefix = argv[idx]->arg;
+  char *mask = argv[idx+1]->arg;
 
   char prefix_str[BUFSIZ];
   int ret = netmask_str2prefix_str (prefix, mask, prefix_str);
@@ -7439,6 +7643,25 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
       if (binfo->extra && binfo->extra->damp_info)
        bgp_damp_info_vty (vty, binfo, json_path);
 
+      /* Remove Label */
+      if (bgp_labeled_safi(safi) && binfo->extra)
+        {
+          uint32_t label = label_pton(binfo->extra->tag);
+          if (json_paths)
+            json_object_int_add(json_path, "remoteLabel", label);
+          else
+            vty_out(vty, "      Remote label: %d%s", label, VTY_NEWLINE);
+        }
+
+      /* Label Index */
+      if (attr->extra->label_index != BGP_INVALID_LABEL_INDEX)
+        {
+          if (json_paths)
+            json_object_int_add(json_path, "labelIndex", attr->extra->label_index);
+          else
+            vty_out(vty, "      Label Index: %d%s", attr->extra->label_index, VTY_NEWLINE);
+        }
+
       /* Line 8 display Addpath IDs */
       if (binfo->addpath_rx_id || binfo->addpath_tx_id)
         {
@@ -7932,6 +8155,18 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
               ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":" : "",
               buf2,
               p->prefixlen, VTY_NEWLINE);
+
+      if (bgp_labeled_safi(safi))
+        {
+          vty_out(vty, "Local label: ");
+          if (!bgp_is_valid_label(rn->local_label))
+            vty_out(vty, "not allocated%s", VTY_NEWLINE);
+          else
+            {
+              uint32_t label = label_pton(rn->local_label);
+              vty_out(vty, "%d%s", label, VTY_NEWLINE);
+            }
+        }
     }
 
   for (ri = rn->info; ri; ri = ri->next)
@@ -8213,7 +8448,7 @@ bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom,
 
 DEFUN (show_ip_bgp_large_community_list,
        show_ip_bgp_large_community_list_cmd,
-       "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] large-community-list <(1-500)|WORD> [json]",
+       "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]] large-community-list <(1-500)|WORD> [json]",
        SHOW_STR
        IP_STR
        BGP_STR
@@ -8224,6 +8459,7 @@ DEFUN (show_ip_bgp_large_community_list,
        "Address Family modifier\n"
        "Address Family modifier\n"
        "Address Family modifier\n"
+       "Address Family modifier\n"
        "Display routes matching the large-community-list\n"
        "large-community-list number\n"
        "large-community-list name\n"
@@ -8259,7 +8495,7 @@ DEFUN (show_ip_bgp_large_community_list,
 }
 DEFUN (show_ip_bgp_large_community,
        show_ip_bgp_large_community_cmd,
-       "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] large-community [AA:BB:CC] [json]",
+       "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]] large-community [AA:BB:CC] [json]",
        SHOW_STR
        IP_STR
        BGP_STR
@@ -8270,6 +8506,7 @@ DEFUN (show_ip_bgp_large_community,
        "Address Family modifier\n"
        "Address Family modifier\n"
        "Address Family modifier\n"
+       "Address Family modifier\n"
        "Display routes matching the large-communities\n"
        "List of large-community numbers\n"
        JSON_STR)
@@ -9210,7 +9447,7 @@ bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, u_c
 
 DEFUN (show_ip_bgp_instance_neighbor_prefix_counts,
        show_ip_bgp_instance_neighbor_prefix_counts_cmd,
-       "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] "
+       "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]] "
        "neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]",
        SHOW_STR
        IP_STR
@@ -9222,6 +9459,7 @@ DEFUN (show_ip_bgp_instance_neighbor_prefix_counts,
        "Address Family modifier\n"
        "Address Family modifier\n"
        "Address Family modifier\n"
+       "Address Family modifier\n"
        "Detailed information on TCP and BGP neighbor connections\n"
        "Neighbor to display information about\n"
        "Neighbor to display information about\n"
@@ -10545,6 +10783,9 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp,
                     p->prefixlen);
          }
 
+        if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX)
+         vty_out (vty, " label-index %u", bgp_static->label_index);
+
        if (bgp_static->rmap.name)
          vty_out (vty, " route-map %s", bgp_static->rmap.name);
        else 
@@ -10671,6 +10912,8 @@ bgp_route_init (void)
   install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd);
   install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd);
   install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_IPV4L_NODE, &no_bgp_network_label_index_cmd);
+  install_element (BGP_IPV4L_NODE, &no_bgp_network_label_index_route_map_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_table_map_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_network_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd);
@@ -10698,6 +10941,21 @@ bgp_route_init (void)
   install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd);
   install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd);
 
+  /* IPv4 labeled-unicast configuration.  */
+  install_element (BGP_IPV4L_NODE, &bgp_table_map_cmd);
+  install_element (BGP_IPV4L_NODE, &bgp_network_cmd);
+  install_element (BGP_IPV4L_NODE, &bgp_network_mask_cmd);
+  install_element (BGP_IPV4L_NODE, &bgp_network_mask_natural_cmd);
+  install_element (BGP_IPV4L_NODE, &bgp_network_route_map_cmd);
+  install_element (BGP_IPV4L_NODE, &bgp_network_mask_route_map_cmd);
+  install_element (BGP_IPV4L_NODE, &bgp_network_mask_natural_route_map_cmd);
+  install_element (BGP_IPV4L_NODE, &bgp_network_label_index_cmd);
+  install_element (BGP_IPV4L_NODE, &bgp_network_label_index_route_map_cmd);
+  install_element (BGP_IPV4L_NODE, &no_bgp_table_map_cmd);
+  install_element (BGP_IPV4L_NODE, &no_bgp_network_cmd);
+  install_element (BGP_IPV4L_NODE, &no_bgp_network_mask_cmd);
+  install_element (BGP_IPV4L_NODE, &no_bgp_network_mask_natural_cmd);
+
   install_element (VIEW_NODE, &show_ip_bgp_instance_all_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
@@ -10731,6 +10989,10 @@ bgp_route_init (void)
   install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd);
   install_element (BGP_IPV6_NODE, &no_bgp_table_map_cmd);
   install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd);
+  install_element (BGP_IPV6_NODE, &ipv6_bgp_network_label_index_cmd);
+  install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_label_index_cmd);
+  install_element (BGP_IPV6_NODE, &ipv6_bgp_network_label_index_route_map_cmd);
+  install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_label_index_route_map_cmd);
 
   install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd);
   install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd);
@@ -10738,6 +11000,12 @@ bgp_route_init (void)
   install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd);
   install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd);
 
+  install_element (BGP_IPV6L_NODE, &bgp_table_map_cmd);
+  install_element (BGP_IPV6L_NODE, &ipv6_bgp_network_cmd);
+  install_element (BGP_IPV6L_NODE, &ipv6_bgp_network_route_map_cmd);
+  install_element (BGP_IPV6L_NODE, &no_bgp_table_map_cmd);
+  install_element (BGP_IPV6L_NODE, &no_ipv6_bgp_network_cmd);
+
   install_element (BGP_NODE, &bgp_distance_cmd);
   install_element (BGP_NODE, &no_bgp_distance_cmd);
   install_element (BGP_NODE, &bgp_distance_source_cmd);
index e75978d003fd8ee03d3786e510db762142bf1462..9db84b2caede79c6df6ecc00d4f53018ea05cfd4 100644 (file)
@@ -85,7 +85,7 @@ struct bgp_info_extra
       } export;
 
       struct {
-         void *timer;
+         struct thread *timer;
          void *hme;            /* encap monitor, if this is a VPN route */
          struct prefix_rd rd;  /* import: route's route-distinguisher */
          u_char un_family;     /* family of cached un address, 0 if unset */
@@ -150,6 +150,7 @@ struct bgp_info
 #define BGP_INFO_COUNTED       (1 << 10)
 #define BGP_INFO_MULTIPATH      (1 << 11)
 #define BGP_INFO_MULTIPATH_CHG  (1 << 12)
+#define BGP_INFO_RIB_ATTR_CHG   (1 << 13)
 
   /* BGP route type.  This can be static, RIP, OSPF, BGP etc.  */
   u_char type;
@@ -179,6 +180,10 @@ struct bgp_static
   /* Backdoor configuration.  */
   int backdoor;
 
+  /* Label index configuration; applies to LU prefixes. */
+  u_int32_t label_index;
+#define BGP_INVALID_LABEL_INDEX   0xFFFFFFFF
+
   /* Import check status.  */
   u_char valid;
 
@@ -273,6 +278,16 @@ bgp_bump_version (struct bgp_node *node)
   node->version = bgp_table_next_version(bgp_node_table(node));
 }
 
+static inline int
+bgp_fibupd_safi (safi_t safi)
+{
+  if (safi == SAFI_UNICAST ||
+      safi == SAFI_MULTICAST ||
+      safi == SAFI_LABELED_UNICAST)
+    return 1;
+  return 0;
+}
+
 /* Prototypes. */
 extern void bgp_process_queue_init (void);
 extern void bgp_route_init (void);
@@ -370,7 +385,7 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp,
                                     struct bgp_node *rn,
                                     u_int32_t addpath_tx_id);
 
-extern int subgroup_announce_check(struct bgp_info *ri,
+extern int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri,
                                   struct update_subgroup *subgrp,
                                   struct prefix *p, struct attr *attr);
 
index 3c96dac617a656c0b105041c9abbc48075fd0b8b..a6b99a53d6ecfb0b9c1c6376a5db0b289c065421 100644 (file)
@@ -56,10 +56,14 @@ struct bgp_node
 
   struct bgp_node *prn;
 
+  u_char local_label[3];
+
   uint64_t version;
   u_char flags;
 #define BGP_NODE_PROCESS_SCHEDULED     (1 << 0)
 #define BGP_NODE_USER_CLEAR             (1 << 1)
+#define BGP_NODE_LABEL_CHANGED          (1 << 2)
+#define BGP_NODE_REGISTERED_FOR_LABEL   (1 << 3)
 };
 
 /*
index efb2046e1256a7b8e2e6655e0544cc809c1e7ffe..ac5f77474c79b55c6946b9ac954d6f399e146e8f 100644 (file)
@@ -618,7 +618,7 @@ subgroup_announce_table (struct update_subgroup *subgrp,
       if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) ||
           (addpath_capable && bgp_addpath_tx_path(peer, afi, safi, ri)))
        {
-         if (subgroup_announce_check (ri, subgrp, &rn->p, &attr))
+         if (subgroup_announce_check (rn, ri, subgrp, &rn->p, &attr))
            bgp_adj_out_set_subgroup (rn, subgrp, &attr, ri);
          else
            bgp_adj_out_unset_subgroup (rn, subgrp, 1, ri->addpath_tx_id);
index 8839de391e12d5beabefe063ab5a6f58706a17ec..9be1a50db750fdb2874b8bcc49745cca7663b019 100644 (file)
@@ -43,6 +43,7 @@
 #include "workqueue.h"
 #include "hash.h"
 #include "queue.h"
+#include "mpls.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_debug.h"
@@ -54,6 +55,7 @@
 #include "bgpd/bgp_nexthop.h"
 #include "bgpd/bgp_nht.h"
 #include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_label.h"
 
 /********************
  * PRIVATE FUNCTIONS
@@ -653,6 +655,7 @@ subgroup_update_packet (struct update_subgroup *subgrp)
   int addpath_encode = 0;
   u_int32_t addpath_tx_id = 0;
   struct prefix_rd *prd = NULL;
+  char label_buf[20];
 
   if (!subgrp)
     return NULL;
@@ -660,7 +663,6 @@ subgroup_update_packet (struct update_subgroup *subgrp)
   if (bpacket_queue_is_full (SUBGRP_INST (subgrp), SUBGRP_PKTQ (subgrp)))
     return NULL;
 
-
   peer = SUBGRP_PEER (subgrp);
   afi = SUBGRP_AFI (subgrp);
   safi = SUBGRP_SAFI (subgrp);
@@ -668,6 +670,7 @@ subgroup_update_packet (struct update_subgroup *subgrp)
   stream_reset (s);
   snlri = subgrp->scratch;
   stream_reset (snlri);
+  label_buf[0] = '\0';
 
   bpacket_attr_vec_arr_reset (&vecarr);
 
@@ -760,8 +763,9 @@ subgroup_update_packet (struct update_subgroup *subgrp)
 
          if (rn->prn)
            prd = (struct prefix_rd *) &rn->prn->p;
-         if (binfo && binfo->extra)
-           tag = binfo->extra->tag;
+          tag = bgp_adv_label(rn, binfo, peer, afi, safi);
+          if (bgp_labeled_safi(safi))
+            sprintf (label_buf, "label %u", label_pton(tag));
 
          if (stream_empty (snlri))
            mpattrlen_pos = bgp_packet_mpattr_start (snlri, afi, safi,
@@ -783,14 +787,26 @@ subgroup_update_packet (struct update_subgroup *subgrp)
             {
               zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE w/ attr: %s",
                 subgrp->update_group->id, subgrp->id, send_attr_str);
+              if (!stream_empty (snlri))
+                {
+                  iana_afi_t pkt_afi;
+                  safi_t pkt_safi;
+
+                  pkt_afi = afi_int2iana (afi);
+                  pkt_safi = safi_int2iana (safi);
+                  zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send MP_REACH for afi/safi %d/%d",
+                      subgrp->update_group->id, subgrp->id, pkt_afi, pkt_safi);
+                }
+
               send_attr_printed = 1;
             }
 
-          zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
+          zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s %s",
                       subgrp->update_group->id, subgrp->id,
                       bgp_debug_rdpfxpath2str (prd, &rn->p, addpath_encode,
                                                addpath_tx_id,
-                                               pfx_buf, sizeof (pfx_buf)));
+                                               pfx_buf, sizeof (pfx_buf)),
+                                               label_buf);
        }
 
       /* Synchnorize attribute.  */
@@ -824,7 +840,7 @@ subgroup_update_packet (struct update_subgroup *subgrp)
        packet = stream_dup (s);
       bgp_packet_set_size (packet);
       if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
-        zlog_debug ("u%" PRIu64 ":s%" PRIu64 " UPDATE len %zd numpfx %d",
+        zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE len %zd numpfx %d",
                 subgrp->update_group->id, subgrp->id,
                 (stream_get_endp(packet) - stream_get_getp(packet)), num_pfx);
       pkt = bpacket_queue_add (SUBGRP_PKTQ (subgrp), packet, &vecarr);
@@ -917,11 +933,20 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
          /* If first time, format the MP_UNREACH header */
          if (first_time)
            {
+              iana_afi_t pkt_afi;
+              safi_t pkt_safi;
+
+              pkt_afi = afi_int2iana (afi);
+              pkt_safi = safi_int2iana (safi);
+
              attrlen_pos = stream_get_endp (s);
              /* total attr length = 0 for now. reevaluate later */
              stream_putw (s, 0);
              mp_start = stream_get_endp (s);
              mplen_pos = bgp_packet_mpunreach_start (s, afi, safi);
+              if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
+                zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send MP_UNREACH for afi/safi %d/%d",
+                            subgrp->update_group->id, subgrp->id, pkt_afi, pkt_safi);
            }
 
          bgp_packet_mpunreach_prefix (s, &rn->p, afi, safi, prd, NULL,
@@ -968,7 +993,7 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
        }
       bgp_packet_set_size (s);
       if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
-        zlog_debug ("u%" PRIu64 ":s%" PRIu64 " UPDATE (withdraw) len %zd numpfx %d",
+        zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE (withdraw) len %zd numpfx %d",
                     subgrp->update_group->id, subgrp->id,
                     (stream_get_endp(s) - stream_get_getp(s)), num_pfx);
       pkt = bpacket_queue_add (SUBGRP_PKTQ (subgrp), stream_dup (s), NULL);
index 9d954e5007ef8c84a3cf0ed620dea9c135463d8d..4d983c38767edb991a5e8d00e78b6ff91bbd670f 100644 (file)
@@ -60,6 +60,73 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
 static struct peer_group *
 listen_range_exists (struct bgp *bgp, struct prefix *range, int exact);
+#if 0
+#define INSTALL_CMD_ON_AF_NODES(cmd) \
+  install_element(BGP_IPV4_NODE, cmd); \
+  install_element(BGP_IPV4M_NODE, cmd); \
+  install_element(BGP_IPV4L_NODE, cmd); \
+  install_element(BGP_IPV6_NODE, cmd); \
+  install_element(BGP_IPV6M_NODE, cmd); \
+  install_element(BGP_IPV6L_NODE, cmd); \
+  install_element(BGP_VPNV4_NODE, cmd);
+#endif
+static enum node_type
+bgp_node_type (afi_t afi, safi_t safi)
+{
+  switch (afi)
+    {
+    case AFI_IP:
+      switch (safi)
+        {
+        case SAFI_UNICAST:
+          return BGP_IPV4_NODE;
+          break;
+        case SAFI_MULTICAST:
+          return BGP_IPV4M_NODE;
+          break;
+        case SAFI_LABELED_UNICAST:
+          return BGP_IPV4L_NODE;
+          break;
+        case SAFI_MPLS_VPN:
+          return BGP_VPNV4_NODE;
+          break;
+        case SAFI_ENCAP:
+          return BGP_ENCAP_NODE;
+          break;
+       }
+      break;
+    case AFI_IP6:
+      switch (safi)
+        {
+        case SAFI_UNICAST:
+          return BGP_IPV6_NODE;
+          break;
+        case SAFI_MULTICAST:
+          return BGP_IPV6M_NODE;
+          break;
+        case SAFI_LABELED_UNICAST:
+          return BGP_IPV6L_NODE;
+          break;
+        case SAFI_MPLS_VPN:
+          return BGP_VPNV6_NODE;
+          break;
+        case SAFI_ENCAP:
+          return BGP_ENCAP_NODE;
+          break;
+        }
+      break;
+    case AFI_L2VPN:
+      return BGP_EVPN_NODE;
+      break;
+    case AFI_MAX:
+      // We should never be here but to clarify the switch statement..
+      return BGP_IPV4_NODE;
+      break;
+    }
+
+  // Impossible to happen
+  return BGP_IPV4_NODE;
+}
 
 /* Utility function to get address family from current node.  */
 afi_t
@@ -70,6 +137,7 @@ bgp_node_afi (struct vty *vty)
     {
     case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:
+    case BGP_IPV6L_NODE:
     case BGP_VPNV6_NODE:
     case BGP_ENCAPV6_NODE:
       afi = AFI_IP6;
@@ -107,6 +175,10 @@ bgp_node_safi (struct vty *vty)
     case BGP_EVPN_NODE:
       safi = SAFI_EVPN;
       break;
+    case BGP_IPV4L_NODE:
+    case BGP_IPV6L_NODE:
+      safi = SAFI_LABELED_UNICAST;
+      break;
     default:
       safi = SAFI_UNICAST;
       break;
@@ -160,7 +232,7 @@ argv_find_and_parse_afi(struct cmd_token **argv, int argc, int *index, afi_t *af
   return ret;
 }
 
-/* supports <unicast|multicast|vpn|encap> */
+/* supports <unicast|multicast|vpn|encap|labeled-unicast> */
 safi_t
 bgp_vty_safi_from_arg(const char *safi_str)
 {
@@ -173,6 +245,8 @@ bgp_vty_safi_from_arg(const char *safi_str)
     safi = SAFI_ENCAP;
   else if (strncmp (safi_str, "v", 1) == 0)
     safi = SAFI_MPLS_VPN;
+  else if (strncmp (safi_str, "l", 1) == 0)
+    safi = SAFI_LABELED_UNICAST;
   return safi;
 }
 
@@ -192,6 +266,12 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
       if (safi)
         *safi = SAFI_MULTICAST;
     }
+   else if (argv_find (argv, argc, "labeled-unicast", index))
+    {
+      ret = 1;
+      if (safi)
+        *safi = SAFI_LABELED_UNICAST;
+    }
   else if (argv_find (argv, argc, "vpn", index))
     {
       ret = 1;
@@ -223,12 +303,12 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
  * that is being parsed.
  *
  * The show commands are generally of the form:
- * "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] ..."
+ * "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]] ..."
  *
  * Since we use argv_find if the show command in particular doesn't have:
  * [ip]
  * [<view|vrf> WORD]
- * [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]]
+ * [<ipv4|ipv6> [<unicast|multicast|vpn|encap|labeled-unicast>]]
  * The command parsing should still be ok.
  *
  * vty  -> The vty for the command so we can output some useful data in
@@ -1495,6 +1575,12 @@ DEFUN (bgp_maxpaths,
   return bgp_maxpaths_config_vty(vty, BGP_PEER_EBGP, argv[idx_number]->arg, 0, 1);
 }
 
+ALIAS_HIDDEN (bgp_maxpaths,
+              bgp_maxpaths_hidden_cmd,
+              "maximum-paths (1-255)",
+              "Forward packets over multiple paths\n"
+              "Number of paths\n")
+
 DEFUN (bgp_maxpaths_ibgp,
        bgp_maxpaths_ibgp_cmd,
        "maximum-paths ibgp (1-255)",
@@ -1506,6 +1592,13 @@ DEFUN (bgp_maxpaths_ibgp,
   return bgp_maxpaths_config_vty(vty, BGP_PEER_IBGP, argv[idx_number]->arg, 0, 1);
 }
 
+ALIAS_HIDDEN (bgp_maxpaths_ibgp,
+              bgp_maxpaths_ibgp_hidden_cmd,
+              "maximum-paths ibgp (1-255)",
+              "Forward packets over multiple paths\n"
+              "iBGP-multipath\n"
+              "Number of paths\n")
+
 DEFUN (bgp_maxpaths_ibgp_cluster,
        bgp_maxpaths_ibgp_cluster_cmd,
        "maximum-paths ibgp (1-255) equal-cluster-length",
@@ -1519,6 +1612,14 @@ DEFUN (bgp_maxpaths_ibgp_cluster,
                                 BGP_FLAG_IBGP_MULTIPATH_SAME_CLUSTERLEN, 1);
 }
 
+ALIAS_HIDDEN (bgp_maxpaths_ibgp_cluster,
+              bgp_maxpaths_ibgp_cluster_hidden_cmd,
+              "maximum-paths ibgp (1-255) equal-cluster-length",
+              "Forward packets over multiple paths\n"
+              "iBGP-multipath\n"
+              "Number of paths\n"
+              "Match the cluster length\n")
+
 DEFUN (no_bgp_maxpaths,
        no_bgp_maxpaths_cmd,
        "no maximum-paths [(1-255)]",
@@ -1529,6 +1630,13 @@ DEFUN (no_bgp_maxpaths,
   return bgp_maxpaths_config_vty(vty, BGP_PEER_EBGP, NULL, 0, 0);
 }
 
+ALIAS_HIDDEN (no_bgp_maxpaths,
+              no_bgp_maxpaths_hidden_cmd,
+              "no maximum-paths [(1-255)]",
+              NO_STR
+              "Forward packets over multiple paths\n"
+              "Number of paths\n")
+
 DEFUN (no_bgp_maxpaths_ibgp,
        no_bgp_maxpaths_ibgp_cmd,
        "no maximum-paths ibgp [(1-255) [equal-cluster-length]]",
@@ -1541,6 +1649,15 @@ DEFUN (no_bgp_maxpaths_ibgp,
   return bgp_maxpaths_config_vty(vty, BGP_PEER_IBGP, NULL, 0, 0);
 }
 
+ALIAS_HIDDEN (no_bgp_maxpaths_ibgp,
+              no_bgp_maxpaths_ibgp_hidden_cmd,
+              "no maximum-paths ibgp [(1-255) [equal-cluster-length]]",
+              NO_STR
+              "Forward packets over multiple paths\n"
+              "iBGP-multipath\n"
+              "Number of paths\n"
+              "Match the cluster length\n")
+
 int
 bgp_config_write_maxpaths (struct vty *vty, struct bgp *bgp, afi_t afi,
                           safi_t safi, int *write)
@@ -3228,6 +3345,13 @@ DEFUN (neighbor_activate,
   return CMD_SUCCESS;
 }
 
+ALIAS_HIDDEN (neighbor_activate,
+              neighbor_activate_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> activate",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Enable the Address Family for this Neighbor\n")
+
 DEFUN (no_neighbor_activate,
        no_neighbor_activate_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> activate",
@@ -3252,6 +3376,14 @@ DEFUN (no_neighbor_activate,
   return CMD_SUCCESS;
 }
 
+ALIAS_HIDDEN (no_neighbor_activate,
+              no_neighbor_activate_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> activate",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Enable the Address Family for this Neighbor\n")
+
 DEFUN (neighbor_set_peer_group,
        neighbor_set_peer_group_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> peer-group WORD",
@@ -3318,6 +3450,14 @@ DEFUN (neighbor_set_peer_group,
   return bgp_vty_return (vty, ret);
 }
 
+ALIAS_HIDDEN (neighbor_set_peer_group,
+              neighbor_set_peer_group_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> peer-group WORD",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Member of the peer-group\n"
+              "Peer-group name\n")
+
 DEFUN (no_neighbor_set_peer_group,
        no_neighbor_set_peer_group_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> peer-group WORD",
@@ -3350,6 +3490,15 @@ DEFUN (no_neighbor_set_peer_group,
   return bgp_vty_return (vty, ret);
 }
 
+ALIAS_HIDDEN (no_neighbor_set_peer_group,
+              no_neighbor_set_peer_group_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> peer-group WORD",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Member of the peer-group\n"
+              "Peer-group name\n")
+
 static int
 peer_flag_modify_vty (struct vty *vty, const char *ip_str,
                       u_int16_t flag, int set)
@@ -3614,6 +3763,18 @@ DEFUN (neighbor_capability_orf_prefix,
                               bgp_node_safi (vty), flag);
 }
 
+ALIAS_HIDDEN (neighbor_capability_orf_prefix,
+              neighbor_capability_orf_prefix_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> capability orf prefix-list <both|send|receive>",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Advertise capability to the peer\n"
+              "Advertise ORF capability to the peer\n"
+              "Advertise prefixlist ORF capability to this neighbor\n"
+              "Capability to SEND and RECEIVE the ORF to/from this neighbor\n"
+              "Capability to RECEIVE the ORF from this neighbor\n"
+              "Capability to SEND the ORF to this neighbor\n")
+
 DEFUN (no_neighbor_capability_orf_prefix,
        no_neighbor_capability_orf_prefix_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> capability orf prefix-list <both|send|receive>",
@@ -3644,6 +3805,19 @@ DEFUN (no_neighbor_capability_orf_prefix,
                                 bgp_node_safi (vty), flag);
 }
 
+ALIAS_HIDDEN (no_neighbor_capability_orf_prefix,
+              no_neighbor_capability_orf_prefix_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> capability orf prefix-list <both|send|receive>",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Advertise capability to the peer\n"
+              "Advertise ORF capability to the peer\n"
+              "Advertise prefixlist ORF capability to this neighbor\n"
+              "Capability to SEND and RECEIVE the ORF to/from this neighbor\n"
+              "Capability to RECEIVE the ORF from this neighbor\n"
+              "Capability to SEND the ORF to this neighbor\n")
+
 /* neighbor next-hop-self. */
 DEFUN (neighbor_nexthop_self,
        neighbor_nexthop_self_cmd,
@@ -3657,6 +3831,13 @@ DEFUN (neighbor_nexthop_self,
                               bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF);
 }
 
+ALIAS_HIDDEN (neighbor_nexthop_self,
+              neighbor_nexthop_self_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Disable the next hop calculation for this neighbor\n")
+
 /* neighbor next-hop-self. */
 DEFUN (neighbor_nexthop_self_force,
        neighbor_nexthop_self_force_cmd,
@@ -3672,6 +3853,14 @@ DEFUN (neighbor_nexthop_self_force,
                               PEER_FLAG_FORCE_NEXTHOP_SELF);
 }
 
+ALIAS_HIDDEN (neighbor_nexthop_self_force,
+              neighbor_nexthop_self_force_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self force",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Disable the next hop calculation for this neighbor\n"
+              "Set the next hop to self for reflected routes\n")
+
 DEFUN (no_neighbor_nexthop_self,
        no_neighbor_nexthop_self_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self",
@@ -3686,6 +3875,14 @@ DEFUN (no_neighbor_nexthop_self,
                                 PEER_FLAG_NEXTHOP_SELF);
 }
 
+ALIAS_HIDDEN (no_neighbor_nexthop_self,
+              no_neighbor_nexthop_self_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Disable the next hop calculation for this neighbor\n")
+
 DEFUN (no_neighbor_nexthop_self_force,
        no_neighbor_nexthop_self_force_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self force",
@@ -3701,6 +3898,15 @@ DEFUN (no_neighbor_nexthop_self_force,
                                 PEER_FLAG_FORCE_NEXTHOP_SELF);
 }
 
+ALIAS_HIDDEN (no_neighbor_nexthop_self_force,
+              no_neighbor_nexthop_self_force_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self force",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Disable the next hop calculation for this neighbor\n"
+              "Set the next hop to self for reflected routes\n")
+
 /* neighbor as-override */
 DEFUN (neighbor_as_override,
        neighbor_as_override_cmd,
@@ -3715,6 +3921,13 @@ DEFUN (neighbor_as_override,
                                PEER_FLAG_AS_OVERRIDE);
 }
 
+ALIAS_HIDDEN (neighbor_as_override,
+              neighbor_as_override_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> as-override",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Override ASNs in outbound updates if aspath equals remote-as\n")
+
 DEFUN (no_neighbor_as_override,
        no_neighbor_as_override_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> as-override",
@@ -3729,6 +3942,14 @@ DEFUN (no_neighbor_as_override,
                                  PEER_FLAG_AS_OVERRIDE);
 }
 
+ALIAS_HIDDEN (no_neighbor_as_override,
+              no_neighbor_as_override_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> as-override",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Override ASNs in outbound updates if aspath equals remote-as\n")
+
 /* neighbor remove-private-AS. */
 DEFUN (neighbor_remove_private_as,
        neighbor_remove_private_as_cmd,
@@ -3743,6 +3964,13 @@ DEFUN (neighbor_remove_private_as,
                               PEER_FLAG_REMOVE_PRIVATE_AS);
 }
 
+ALIAS_HIDDEN (neighbor_remove_private_as,
+              neighbor_remove_private_as_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Remove private ASNs in outbound updates\n")
+
 DEFUN (neighbor_remove_private_as_all,
        neighbor_remove_private_as_all_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all",
@@ -3757,6 +3985,14 @@ DEFUN (neighbor_remove_private_as_all,
                                PEER_FLAG_REMOVE_PRIVATE_AS_ALL);
 }
 
+ALIAS_HIDDEN (neighbor_remove_private_as_all,
+              neighbor_remove_private_as_all_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Remove private ASNs in outbound updates\n"
+              "Apply to all AS numbers")
+
 DEFUN (neighbor_remove_private_as_replace_as,
        neighbor_remove_private_as_replace_as_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS replace-AS",
@@ -3771,6 +4007,14 @@ DEFUN (neighbor_remove_private_as_replace_as,
                                PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE);
 }
 
+ALIAS_HIDDEN (neighbor_remove_private_as_replace_as,
+              neighbor_remove_private_as_replace_as_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS replace-AS",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Remove private ASNs in outbound updates\n"
+              "Replace private ASNs with our ASN in outbound updates\n")
+
 DEFUN (neighbor_remove_private_as_all_replace_as,
        neighbor_remove_private_as_all_replace_as_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all replace-AS",
@@ -3786,6 +4030,15 @@ DEFUN (neighbor_remove_private_as_all_replace_as,
                                PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE);
 }
 
+ALIAS_HIDDEN (neighbor_remove_private_as_all_replace_as,
+              neighbor_remove_private_as_all_replace_as_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all replace-AS",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Remove private ASNs in outbound updates\n"
+              "Apply to all AS numbers\n"
+              "Replace private ASNs with our ASN in outbound updates\n")
+
 DEFUN (no_neighbor_remove_private_as,
        no_neighbor_remove_private_as_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS",
@@ -3800,6 +4053,14 @@ DEFUN (no_neighbor_remove_private_as,
                                 PEER_FLAG_REMOVE_PRIVATE_AS);
 }
 
+ALIAS_HIDDEN (no_neighbor_remove_private_as,
+              no_neighbor_remove_private_as_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Remove private ASNs in outbound updates\n")
+
 DEFUN (no_neighbor_remove_private_as_all,
        no_neighbor_remove_private_as_all_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all",
@@ -3815,6 +4076,15 @@ DEFUN (no_neighbor_remove_private_as_all,
                                 PEER_FLAG_REMOVE_PRIVATE_AS_ALL);
 }
 
+ALIAS_HIDDEN (no_neighbor_remove_private_as_all,
+              no_neighbor_remove_private_as_all_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Remove private ASNs in outbound updates\n"
+              "Apply to all AS numbers\n")
+
 DEFUN (no_neighbor_remove_private_as_replace_as,
        no_neighbor_remove_private_as_replace_as_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS replace-AS",
@@ -3830,6 +4100,15 @@ DEFUN (no_neighbor_remove_private_as_replace_as,
                                 PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE);
 }
 
+ALIAS_HIDDEN (no_neighbor_remove_private_as_replace_as,
+              no_neighbor_remove_private_as_replace_as_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS replace-AS",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Remove private ASNs in outbound updates\n"
+              "Replace private ASNs with our ASN in outbound updates\n")
+
 DEFUN (no_neighbor_remove_private_as_all_replace_as,
        no_neighbor_remove_private_as_all_replace_as_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all replace-AS",
@@ -3846,6 +4125,16 @@ DEFUN (no_neighbor_remove_private_as_all_replace_as,
                                 PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE);
 }
 
+ALIAS_HIDDEN (no_neighbor_remove_private_as_all_replace_as,
+              no_neighbor_remove_private_as_all_replace_as_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all replace-AS",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Remove private ASNs in outbound updates\n"
+              "Apply to all AS numbers\n"
+              "Replace private ASNs with our ASN in outbound updates\n")
+
 
 /* neighbor send-community. */
 DEFUN (neighbor_send_community,
@@ -3861,6 +4150,13 @@ DEFUN (neighbor_send_community,
                               PEER_FLAG_SEND_COMMUNITY);
 }
 
+ALIAS_HIDDEN (neighbor_send_community,
+              neighbor_send_community_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> send-community",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Send Community attribute to this neighbor\n")
+
 DEFUN (no_neighbor_send_community,
        no_neighbor_send_community_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community",
@@ -3875,6 +4171,14 @@ DEFUN (no_neighbor_send_community,
                                 PEER_FLAG_SEND_COMMUNITY);
 }
 
+ALIAS_HIDDEN (no_neighbor_send_community,
+              no_neighbor_send_community_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Send Community attribute to this neighbor\n")
+
 /* neighbor send-community extended. */
 DEFUN (neighbor_send_community_type,
        neighbor_send_community_type_cmd,
@@ -3914,6 +4218,18 @@ DEFUN (neighbor_send_community_type,
   return peer_af_flag_set_vty (vty, peer, bgp_node_afi (vty), bgp_node_safi (vty), flag);
 }
 
+ALIAS_HIDDEN (neighbor_send_community_type,
+              neighbor_send_community_type_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Send Community attribute to this neighbor\n"
+              "Send Standard and Extended Community attributes\n"
+              "Send Standard, Large and Extended Community attributes\n"
+              "Send Extended Community attributes\n"
+              "Send Standard Community attributes\n"
+              "Send Large Community attributes\n")
+
 DEFUN (no_neighbor_send_community_type,
        no_neighbor_send_community_type_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
@@ -3954,6 +4270,19 @@ DEFUN (no_neighbor_send_community_type,
                                  PEER_FLAG_SEND_LARGE_COMMUNITY));
 }
 
+ALIAS_HIDDEN (no_neighbor_send_community_type,
+              no_neighbor_send_community_type_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Send Community attribute to this neighbor\n"
+              "Send Standard and Extended Community attributes\n"
+              "Send Standard, Large and Extended Community attributes\n"
+              "Send Extended Community attributes\n"
+              "Send Standard Community attributes\n"
+              "Send Large Community attributes\n")
+
 /* neighbor soft-reconfig. */
 DEFUN (neighbor_soft_reconfiguration,
        neighbor_soft_reconfiguration_cmd,
@@ -3969,6 +4298,14 @@ DEFUN (neighbor_soft_reconfiguration,
                               PEER_FLAG_SOFT_RECONFIG);
 }
 
+ALIAS_HIDDEN (neighbor_soft_reconfiguration,
+              neighbor_soft_reconfiguration_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> soft-reconfiguration inbound",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Per neighbor soft reconfiguration\n"
+              "Allow inbound soft reconfiguration for this neighbor\n")
+
 DEFUN (no_neighbor_soft_reconfiguration,
        no_neighbor_soft_reconfiguration_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> soft-reconfiguration inbound",
@@ -3984,6 +4321,15 @@ DEFUN (no_neighbor_soft_reconfiguration,
                                 PEER_FLAG_SOFT_RECONFIG);
 }
 
+ALIAS_HIDDEN (no_neighbor_soft_reconfiguration,
+              no_neighbor_soft_reconfiguration_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> soft-reconfiguration inbound",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Per neighbor soft reconfiguration\n"
+              "Allow inbound soft reconfiguration for this neighbor\n")
+
 DEFUN (neighbor_route_reflector_client,
        neighbor_route_reflector_client_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> route-reflector-client",
@@ -4004,6 +4350,13 @@ DEFUN (neighbor_route_reflector_client,
                               PEER_FLAG_REFLECTOR_CLIENT);
 }
 
+ALIAS_HIDDEN (neighbor_route_reflector_client,
+              neighbor_route_reflector_client_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> route-reflector-client",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Configure a neighbor as Route Reflector client\n")
+
 DEFUN (no_neighbor_route_reflector_client,
        no_neighbor_route_reflector_client_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> route-reflector-client",
@@ -4018,6 +4371,14 @@ DEFUN (no_neighbor_route_reflector_client,
                                 PEER_FLAG_REFLECTOR_CLIENT);
 }
 
+ALIAS_HIDDEN (no_neighbor_route_reflector_client,
+              no_neighbor_route_reflector_client_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> route-reflector-client",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Configure a neighbor as Route Reflector client\n")
+
 /* neighbor route-server-client. */
 DEFUN (neighbor_route_server_client,
        neighbor_route_server_client_cmd,
@@ -4037,6 +4398,13 @@ DEFUN (neighbor_route_server_client,
                                PEER_FLAG_RSERVER_CLIENT);
 }
 
+ALIAS_HIDDEN (neighbor_route_server_client,
+              neighbor_route_server_client_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> route-server-client",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Configure a neighbor as Route Server client\n")
+
 DEFUN (no_neighbor_route_server_client,
        no_neighbor_route_server_client_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> route-server-client",
@@ -4051,6 +4419,14 @@ DEFUN (no_neighbor_route_server_client,
                                  PEER_FLAG_RSERVER_CLIENT);
 }
 
+ALIAS_HIDDEN (no_neighbor_route_server_client,
+              no_neighbor_route_server_client_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> route-server-client",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Configure a neighbor as Route Server client\n")
+
 DEFUN (neighbor_nexthop_local_unchanged,
        neighbor_nexthop_local_unchanged_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> nexthop-local unchanged",
@@ -4130,6 +4506,33 @@ DEFUN (neighbor_attr_unchanged,
   return peer_af_flag_set_vty (vty, peer, bgp_node_afi (vty), bgp_node_safi (vty), flags);
 }
 
+ALIAS_HIDDEN (neighbor_attr_unchanged,
+              neighbor_attr_unchanged_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> attribute-unchanged\
+              [<\
+                 as-path [<next-hop [med]|med [next-hop]>]|\
+                 next-hop [<as-path [med]|med [as-path]>]|\
+                 med [<as-path [next-hop]|next-hop [as-path]>]\
+              >]",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "BGP attribute is propagated unchanged to this neighbor\n"
+              "As-path attribute\n"
+              "Nexthop attribute\n"
+              "Med attribute\n"
+              "Med attribute\n"
+              "Nexthop attribute\n"
+              "Nexthop attribute\n"
+              "As-path attribute\n"
+              "Med attribute\n"
+              "Med attribute\n"
+              "As-path attribute\n"
+              "Med attribute\n"
+              "As-path attribute\n"
+              "Nexthop attribute\n"
+              "Nexthop attribute\n"
+              "As-path attribute\n")
+
 DEFUN (no_neighbor_attr_unchanged,
        no_neighbor_attr_unchanged_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> attribute-unchanged\
@@ -4181,6 +4584,34 @@ DEFUN (no_neighbor_attr_unchanged,
   return peer_af_flag_unset_vty (vty, peer, bgp_node_afi (vty), bgp_node_safi (vty), flags);
 }
 
+ALIAS_HIDDEN (no_neighbor_attr_unchanged,
+              no_neighbor_attr_unchanged_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> attribute-unchanged\
+              [<\
+                 as-path [<next-hop [med]|med [next-hop]>]|\
+                 next-hop [<as-path [med]|med [as-path]>]|\
+                 med [<as-path [next-hop]|next-hop [as-path]>]\
+              >]",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "BGP attribute is propagated unchanged to this neighbor\n"
+              "As-path attribute\n"
+              "Nexthop attribute\n"
+              "Med attribute\n"
+              "Med attribute\n"
+              "Nexthop attribute\n"
+              "Nexthop attribute\n"
+              "As-path attribute\n"
+              "Med attribute\n"
+              "Med attribute\n"
+              "As-path attribute\n"
+              "Med attribute\n"
+              "As-path attribute\n"
+              "Nexthop attribute\n"
+              "Nexthop attribute\n"
+              "As-path attribute\n")
+
 
 /* EBGP multihop configuration. */
 static int
@@ -4434,6 +4865,13 @@ DEFUN (neighbor_default_originate,
                                         bgp_node_safi (vty), NULL, 1);
 }
 
+ALIAS_HIDDEN (neighbor_default_originate,
+              neighbor_default_originate_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> default-originate",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Originate default route to this neighbor\n")
+
 DEFUN (neighbor_default_originate_rmap,
        neighbor_default_originate_rmap_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> default-originate route-map WORD",
@@ -4449,6 +4887,15 @@ DEFUN (neighbor_default_originate_rmap,
                                         bgp_node_safi (vty), argv[idx_word]->arg, 1);
 }
 
+ALIAS_HIDDEN (neighbor_default_originate_rmap,
+              neighbor_default_originate_rmap_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> default-originate route-map WORD",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Originate default route to this neighbor\n"
+              "Route-map to specify criteria to originate default\n"
+              "route-map name\n")
+
 DEFUN (no_neighbor_default_originate,
        no_neighbor_default_originate_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> default-originate [route-map WORD]",
@@ -4464,6 +4911,16 @@ DEFUN (no_neighbor_default_originate,
                                         bgp_node_safi (vty), NULL, 0);
 }
 
+ALIAS_HIDDEN (no_neighbor_default_originate,
+              no_neighbor_default_originate_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> default-originate [route-map WORD]",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Originate default route to this neighbor\n"
+              "Route-map to specify criteria to originate default\n"
+              "route-map name\n")
+
 
 /* Set neighbor's BGP port.  */
 static int
@@ -4573,6 +5030,14 @@ DEFUN (neighbor_weight,
                               argv[idx_number]->arg);
 }
 
+ALIAS_HIDDEN (neighbor_weight,
+              neighbor_weight_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> weight (0-65535)",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Set default weight for routes from this neighbor\n"
+              "default weight\n")
+
 DEFUN (no_neighbor_weight,
        no_neighbor_weight_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> weight [(0-65535)]",
@@ -4586,6 +5051,15 @@ DEFUN (no_neighbor_weight,
   return peer_weight_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty), bgp_node_safi (vty));
 }
 
+ALIAS_HIDDEN (no_neighbor_weight,
+              no_neighbor_weight_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> weight [(0-65535)]",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Set default weight for routes from this neighbor\n"
+              "default weight\n")
+
 
 /* Override capability negotiation. */
 DEFUN (neighbor_override_capability,
@@ -4971,6 +5445,18 @@ DEFUN (neighbor_distribute_list,
                                  bgp_node_safi (vty), argv[idx_acl]->arg, argv[idx_in_out]->arg);
 }
 
+ALIAS_HIDDEN (neighbor_distribute_list,
+              neighbor_distribute_list_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list <(1-199)|(1300-2699)|WORD> <in|out>",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Filter updates to/from this neighbor\n"
+              "IP access-list number\n"
+              "IP access-list number (expanded range)\n"
+              "IP Access-list name\n"
+              "Filter incoming updates\n"
+              "Filter outgoing updates\n")
+
 DEFUN (no_neighbor_distribute_list,
        no_neighbor_distribute_list_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list <(1-199)|(1300-2699)|WORD> <in|out>",
@@ -4990,6 +5476,19 @@ DEFUN (no_neighbor_distribute_list,
                                    bgp_node_safi (vty), argv[idx_in_out]->arg);
 }
 
+ALIAS_HIDDEN (no_neighbor_distribute_list,
+              no_neighbor_distribute_list_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list <(1-199)|(1300-2699)|WORD> <in|out>",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Filter updates to/from this neighbor\n"
+              "IP access-list number\n"
+              "IP access-list number (expanded range)\n"
+              "IP Access-list name\n"
+              "Filter incoming updates\n"
+              "Filter outgoing updates\n")
+
 /* Set prefix list to the peer. */
 static int
 peer_prefix_list_set_vty (struct vty *vty, const char *ip_str, afi_t afi,
@@ -5055,6 +5554,16 @@ DEFUN (neighbor_prefix_list,
                                   bgp_node_safi (vty), argv[idx_word]->arg, argv[idx_in_out]->arg);
 }
 
+ALIAS_HIDDEN (neighbor_prefix_list,
+              neighbor_prefix_list_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> prefix-list WORD <in|out>",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Filter updates to/from this neighbor\n"
+              "Name of a prefix list\n"
+              "Filter incoming updates\n"
+              "Filter outgoing updates\n")
+
 DEFUN (no_neighbor_prefix_list,
        no_neighbor_prefix_list_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> prefix-list WORD <in|out>",
@@ -5072,6 +5581,17 @@ DEFUN (no_neighbor_prefix_list,
                                     bgp_node_safi (vty), argv[idx_in_out]->arg);
 }
 
+ALIAS_HIDDEN (no_neighbor_prefix_list,
+              no_neighbor_prefix_list_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> prefix-list WORD <in|out>",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Filter updates to/from this neighbor\n"
+              "Name of a prefix list\n"
+              "Filter incoming updates\n"
+              "Filter outgoing updates\n")
+
 static int
 peer_aslist_set_vty (struct vty *vty, const char *ip_str,
                      afi_t afi, safi_t safi,
@@ -5137,6 +5657,16 @@ DEFUN (neighbor_filter_list,
                              bgp_node_safi (vty), argv[idx_word]->arg, argv[idx_in_out]->arg);
 }
 
+ALIAS_HIDDEN (neighbor_filter_list,
+              neighbor_filter_list_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> filter-list WORD <in|out>",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Establish BGP filters\n"
+              "AS path access-list name\n"
+              "Filter incoming routes\n"
+              "Filter outgoing routes\n")
+
 DEFUN (no_neighbor_filter_list,
        no_neighbor_filter_list_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> filter-list WORD <in|out>",
@@ -5154,6 +5684,17 @@ DEFUN (no_neighbor_filter_list,
                                bgp_node_safi (vty), argv[idx_in_out]->arg);
 }
 
+ALIAS_HIDDEN (no_neighbor_filter_list,
+              no_neighbor_filter_list_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> filter-list WORD <in|out>",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Establish BGP filters\n"
+              "AS path access-list name\n"
+              "Filter incoming routes\n"
+              "Filter outgoing routes\n")
+
 /* Set route-map to the peer. */
 static int
 peer_route_map_set_vty (struct vty *vty, const char *ip_str,
@@ -5219,6 +5760,16 @@ DEFUN (neighbor_route_map,
                                 bgp_node_safi (vty), argv[idx_word]->arg, argv[idx_in_out]->arg);
 }
 
+ALIAS_HIDDEN (neighbor_route_map,
+              neighbor_route_map_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> route-map WORD <in|out>",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Apply route map to neighbor\n"
+              "Name of route map\n"
+              "Apply map to incoming routes\n"
+              "Apply map to outbound routes\n")
+
 DEFUN (no_neighbor_route_map,
        no_neighbor_route_map_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> route-map WORD <in|out>",
@@ -5236,6 +5787,17 @@ DEFUN (no_neighbor_route_map,
                                   bgp_node_safi (vty), argv[idx_in_out]->arg);
 }
 
+ALIAS_HIDDEN (no_neighbor_route_map,
+              no_neighbor_route_map_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> route-map WORD <in|out>",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Apply route map to neighbor\n"
+              "Name of route map\n"
+              "Apply map to incoming routes\n"
+              "Apply map to outbound routes\n")
+
 /* Set unsuppress-map to the peer. */
 static int
 peer_unsuppress_map_set_vty (struct vty *vty, const char *ip_str, afi_t afi,
@@ -5284,6 +5846,14 @@ DEFUN (neighbor_unsuppress_map,
                                      bgp_node_safi (vty), argv[idx_word]->arg);
 }
 
+ALIAS_HIDDEN (neighbor_unsuppress_map,
+              neighbor_unsuppress_map_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> unsuppress-map WORD",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Route-map to selectively unsuppress suppressed routes\n"
+              "Name of route map\n")
+
 DEFUN (no_neighbor_unsuppress_map,
        no_neighbor_unsuppress_map_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> unsuppress-map WORD",
@@ -5298,6 +5868,15 @@ DEFUN (no_neighbor_unsuppress_map,
                                        bgp_node_safi (vty));
 }
 
+ALIAS_HIDDEN (no_neighbor_unsuppress_map,
+              no_neighbor_unsuppress_map_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> unsuppress-map WORD",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Route-map to selectively unsuppress suppressed routes\n"
+              "Name of route map\n")
+
 static int
 peer_maximum_prefix_set_vty (struct vty *vty, const char *ip_str, afi_t afi,
                             safi_t safi, const char *num_str,
@@ -5364,6 +5943,14 @@ DEFUN (neighbor_maximum_prefix,
                                      NULL);
 }
 
+ALIAS_HIDDEN (neighbor_maximum_prefix,
+              neighbor_maximum_prefix_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295)",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Maximum number of prefix accept from this peer\n"
+              "maximum no. of prefix limit\n")
+
 DEFUN (neighbor_maximum_prefix_threshold,
        neighbor_maximum_prefix_threshold_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) (1-100)",
@@ -5381,6 +5968,15 @@ DEFUN (neighbor_maximum_prefix_threshold,
                                      NULL);
 }
 
+ALIAS_HIDDEN (neighbor_maximum_prefix_threshold,
+              neighbor_maximum_prefix_threshold_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) (1-100)",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Maximum number of prefix accept from this peer\n"
+              "maximum no. of prefix limit\n"
+              "Threshold value (%) at which to generate a warning msg\n")
+
 DEFUN (neighbor_maximum_prefix_warning,
        neighbor_maximum_prefix_warning_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) warning-only",
@@ -5397,6 +5993,15 @@ DEFUN (neighbor_maximum_prefix_warning,
                                      NULL);
 }
 
+ALIAS_HIDDEN (neighbor_maximum_prefix_warning,
+              neighbor_maximum_prefix_warning_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) warning-only",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Maximum number of prefix accept from this peer\n"
+              "maximum no. of prefix limit\n"
+              "Only give warning message when limit is exceeded\n")
+
 DEFUN (neighbor_maximum_prefix_threshold_warning,
        neighbor_maximum_prefix_threshold_warning_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) (1-100) warning-only",
@@ -5414,6 +6019,16 @@ DEFUN (neighbor_maximum_prefix_threshold_warning,
                                      bgp_node_safi (vty), argv[idx_number]->arg, argv[idx_number_2]->arg, 1, NULL);
 }
 
+ALIAS_HIDDEN (neighbor_maximum_prefix_threshold_warning,
+              neighbor_maximum_prefix_threshold_warning_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) (1-100) warning-only",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Maximum number of prefix accept from this peer\n"
+              "maximum no. of prefix limit\n"
+              "Threshold value (%) at which to generate a warning msg\n"
+              "Only give warning message when limit is exceeded\n")
+
 DEFUN (neighbor_maximum_prefix_restart,
        neighbor_maximum_prefix_restart_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) restart (1-65535)",
@@ -5431,6 +6046,16 @@ DEFUN (neighbor_maximum_prefix_restart,
                                      bgp_node_safi (vty), argv[idx_number]->arg, NULL, 0, argv[idx_number_2]->arg);
 }
 
+ALIAS_HIDDEN (neighbor_maximum_prefix_restart,
+              neighbor_maximum_prefix_restart_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) restart (1-65535)",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Maximum number of prefix accept from this peer\n"
+              "maximum no. of prefix limit\n"
+              "Restart bgp connection after limit is exceeded\n"
+              "Restart interval in minutes")
+
 DEFUN (neighbor_maximum_prefix_threshold_restart,
        neighbor_maximum_prefix_threshold_restart_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) (1-100) restart (1-65535)",
@@ -5450,6 +6075,17 @@ DEFUN (neighbor_maximum_prefix_threshold_restart,
                                      bgp_node_safi (vty), argv[idx_number]->arg, argv[idx_number_2]->arg, 0, argv[idx_number_3]->arg);
 }
 
+ALIAS_HIDDEN (neighbor_maximum_prefix_threshold_restart,
+              neighbor_maximum_prefix_threshold_restart_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix (1-4294967295) (1-100) restart (1-65535)",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Maximum number of prefixes to accept from this peer\n"
+              "maximum no. of prefix limit\n"
+              "Threshold value (%) at which to generate a warning msg\n"
+              "Restart bgp connection after limit is exceeded\n"
+              "Restart interval in minutes\n")
+
 DEFUN (no_neighbor_maximum_prefix,
        no_neighbor_maximum_prefix_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix [(1-4294967295) [(1-100)] [restart (1-65535)] [warning-only]]",
@@ -5468,6 +6104,19 @@ DEFUN (no_neighbor_maximum_prefix,
                                        bgp_node_safi (vty));
 }
 
+ALIAS_HIDDEN (no_neighbor_maximum_prefix,
+              no_neighbor_maximum_prefix_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix [(1-4294967295) [(1-100)] [restart (1-65535)] [warning-only]]",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Maximum number of prefixes to accept from this peer\n"
+              "maximum no. of prefix limit\n"
+              "Threshold value (%) at which to generate a warning msg\n"
+              "Restart bgp connection after limit is exceeded\n"
+              "Restart interval in minutes\n"
+              "Only give warning message when limit is exceeded\n")
+
 
 /* "neighbor allowas-in" */
 DEFUN (neighbor_allowas_in,
@@ -5506,6 +6155,15 @@ DEFUN (neighbor_allowas_in,
   return bgp_vty_return (vty, ret);
 }
 
+ALIAS_HIDDEN (neighbor_allowas_in,
+              neighbor_allowas_in_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Accept as-path with my AS present in it\n"
+              "Number of occurances of AS number\n"
+              "Only accept my AS in the as-path if the route was originated in my AS\n")
+
 DEFUN (no_neighbor_allowas_in,
        no_neighbor_allowas_in_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]",
@@ -5529,6 +6187,16 @@ DEFUN (no_neighbor_allowas_in,
   return bgp_vty_return (vty, ret);
 }
 
+ALIAS_HIDDEN (no_neighbor_allowas_in,
+              no_neighbor_allowas_in_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "allow local ASN appears in aspath attribute\n"
+              "Number of occurances of AS number\n"
+              "Only accept my AS in the as-path if the route was originated in my AS\n")
+
 DEFUN (neighbor_ttl_security,
        neighbor_ttl_security_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> ttl-security hops (1-254)",
@@ -5601,6 +6269,13 @@ DEFUN (neighbor_addpath_tx_all_paths,
                               PEER_FLAG_ADDPATH_TX_ALL_PATHS);
 }
 
+ALIAS_HIDDEN (neighbor_addpath_tx_all_paths,
+              neighbor_addpath_tx_all_paths_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Use addpath to advertise all paths to a neighbor\n")
+
 DEFUN (no_neighbor_addpath_tx_all_paths,
        no_neighbor_addpath_tx_all_paths_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths",
@@ -5615,6 +6290,14 @@ DEFUN (no_neighbor_addpath_tx_all_paths,
                                 PEER_FLAG_ADDPATH_TX_ALL_PATHS);
 }
 
+ALIAS_HIDDEN (no_neighbor_addpath_tx_all_paths,
+              no_neighbor_addpath_tx_all_paths_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Use addpath to advertise all paths to a neighbor\n")
+
 DEFUN (neighbor_addpath_tx_bestpath_per_as,
        neighbor_addpath_tx_bestpath_per_as_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS",
@@ -5634,6 +6317,13 @@ DEFUN (neighbor_addpath_tx_bestpath_per_as,
                               PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS);
 }
 
+ALIAS_HIDDEN (neighbor_addpath_tx_bestpath_per_as,
+              neighbor_addpath_tx_bestpath_per_as_hidden_cmd,
+              "neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS",
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Use addpath to advertise the bestpath per each neighboring AS\n")
+
 DEFUN (no_neighbor_addpath_tx_bestpath_per_as,
        no_neighbor_addpath_tx_bestpath_per_as_cmd,
        "no neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS",
@@ -5648,32 +6338,26 @@ DEFUN (no_neighbor_addpath_tx_bestpath_per_as,
                                 PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS);
 }
 
+ALIAS_HIDDEN (no_neighbor_addpath_tx_bestpath_per_as,
+              no_neighbor_addpath_tx_bestpath_per_as_hidden_cmd,
+              "no neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS",
+              NO_STR
+              NEIGHBOR_STR
+              NEIGHBOR_ADDR_STR2
+              "Use addpath to advertise the bestpath per each neighboring AS\n")
+
 DEFUN_NOSH (address_family_ipv4_safi,
        address_family_ipv4_safi_cmd,
-       "address-family ipv4 [<unicast|multicast|vpn|encap>]",
+       "address-family ipv4 [<unicast|multicast|vpn|encap|labeled-unicast>]",
        "Enter Address Family command mode\n"
        "Address Family\n"
        BGP_SAFI_HELP_STR)
 {
-  int idx_safi = 2;
-  if (argc == (idx_safi + 1))
+
+  if (argc == 3)
     {
-      switch (bgp_vty_safi_from_arg(argv[idx_safi]->arg))
-        {
-        case SAFI_MULTICAST:
-          vty->node = BGP_IPV4M_NODE;
-          break;
-        case SAFI_ENCAP:
-          vty->node = BGP_ENCAP_NODE;
-          break;
-        case SAFI_MPLS_VPN:
-          vty->node = BGP_VPNV4_NODE;
-          break;
-        case SAFI_UNICAST:
-        default:
-          vty->node = BGP_IPV4_NODE;
-          break;
-        }
+      safi_t safi = bgp_vty_safi_from_arg(argv[2]->arg);
+      vty->node = bgp_node_type(AFI_IP, safi);
     }
   else
     vty->node = BGP_IPV4_NODE;
@@ -5683,30 +6367,15 @@ DEFUN_NOSH (address_family_ipv4_safi,
 
 DEFUN_NOSH (address_family_ipv6_safi,
        address_family_ipv6_safi_cmd,
-       "address-family ipv6 [<unicast|multicast|vpn|encap>]",
+       "address-family ipv6 [<unicast|multicast|vpn|encap|labeled-unicast>]",
        "Enter Address Family command mode\n"
        "Address Family\n"
        BGP_SAFI_HELP_STR)
 {
-  int idx_safi = 2;
-  if (argc == (idx_safi + 1))
+  if (argc == 3)
     {
-      switch (bgp_vty_safi_from_arg(argv[idx_safi]->arg))
-        {
-        case SAFI_MULTICAST:
-          vty->node = BGP_IPV6M_NODE;
-          break;
-        case SAFI_ENCAP:
-          vty->node = BGP_ENCAPV6_NODE;
-          break;
-        case SAFI_MPLS_VPN:
-          vty->node = BGP_VPNV6_NODE;
-          break;
-        case SAFI_UNICAST:
-        default:
-          vty->node = BGP_IPV6_NODE;
-          break;
-        }
+      safi_t safi = bgp_vty_safi_from_arg(argv[2]->arg);
+      vty->node = bgp_node_type(AFI_IP6, safi);
     }
   else
     vty->node = BGP_IPV6_NODE;
@@ -5779,9 +6448,11 @@ DEFUN_NOSH (exit_address_family,
 {
   if (vty->node == BGP_IPV4_NODE
       || vty->node == BGP_IPV4M_NODE
+      || vty->node == BGP_IPV4L_NODE
       || vty->node == BGP_VPNV4_NODE
       || vty->node == BGP_IPV6_NODE
       || vty->node == BGP_IPV6M_NODE
+      || vty->node == BGP_IPV6L_NODE
       || vty->node == BGP_VPNV6_NODE
       || vty->node == BGP_ENCAP_NODE
       || vty->node == BGP_ENCAPV6_NODE
@@ -6707,6 +7378,7 @@ bgp_show_summary_afi_safi (struct vty *vty, struct bgp *bgp, int afi, int safi,
   int afi_wildcard  = (afi == AFI_MAX);
   int safi_wildcard = (safi == SAFI_MAX);
   int is_wildcard   = (afi_wildcard || safi_wildcard);
+  bool json_output = false;
 
   if (use_json && is_wildcard)
     vty_out (vty, "{%s", VTY_NEWLINE);
@@ -6720,6 +7392,7 @@ bgp_show_summary_afi_safi (struct vty *vty, struct bgp *bgp, int afi, int safi,
         {
           if (bgp_show_summary_afi_safi_peer_exists (bgp, afi, safi))
             {
+              json_output = true;
               if (is_wildcard)
                 {
                   /*
@@ -6760,7 +7433,8 @@ bgp_show_summary_afi_safi (struct vty *vty, struct bgp *bgp, int afi, int safi,
 
   if (use_json && is_wildcard)
     vty_out (vty, "}%s", VTY_NEWLINE);
-
+  else if (use_json && !json_output)
+    vty_out (vty, "{}%s", VTY_NEWLINE);
 }
 
 static void
@@ -6886,6 +7560,8 @@ afi_safi_print (afi_t afi, safi_t safi)
     return "IPv4 Unicast";
   else if (afi == AFI_IP && safi == SAFI_MULTICAST)
     return "IPv4 Multicast";
+  else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
+    return "IPv4 labeled-unicast";
   else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
     return "IPv4 VPN";
   else if (afi == AFI_IP && safi == SAFI_ENCAP)
@@ -6894,6 +7570,8 @@ afi_safi_print (afi_t afi, safi_t safi)
     return "IPv6 Unicast";
   else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
     return "IPv6 Multicast";
+  else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
+    return "IPv6 labeled-unicast";
   else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
     return "IPv6 VPN";
   else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
@@ -6917,6 +7595,8 @@ afi_safi_json (afi_t afi, safi_t safi)
     return "ipv4Unicast";
   else if (afi == AFI_IP && safi == SAFI_MULTICAST)
     return "ipv4Multicast";
+  else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
+    return "ipv4LabeledUnicast";
   else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
     return "ipv4Vpn";
   else if (afi == AFI_IP && safi == SAFI_ENCAP)
@@ -6925,6 +7605,8 @@ afi_safi_json (afi_t afi, safi_t safi)
     return "ipv6Unicast";
   else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
     return "ipv6Multicast";
+  else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
+    return "ipv6LabeledUnicast";
   else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
     return "ipv6Vpn";
   else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
@@ -9499,6 +10181,12 @@ DEFUN (bgp_redistribute_ipv4,
   return bgp_redistribute_set (bgp, AFI_IP, type, 0);
 }
 
+ALIAS_HIDDEN (bgp_redistribute_ipv4,
+              bgp_redistribute_ipv4_hidden_cmd,
+              "redistribute " FRR_IP_REDIST_STR_BGPD,
+              "Redistribute information from another routing protocol\n"
+              FRR_IP_REDIST_HELP_STR_BGPD)
+
 DEFUN (bgp_redistribute_ipv4_rmap,
        bgp_redistribute_ipv4_rmap_cmd,
        "redistribute " FRR_IP_REDIST_STR_BGPD " route-map WORD",
@@ -9525,6 +10213,14 @@ DEFUN (bgp_redistribute_ipv4_rmap,
   return bgp_redistribute_set (bgp, AFI_IP, type, 0);
 }
 
+ALIAS_HIDDEN (bgp_redistribute_ipv4_rmap,
+              bgp_redistribute_ipv4_rmap_hidden_cmd,
+              "redistribute " FRR_IP_REDIST_STR_BGPD " route-map WORD",
+              "Redistribute information from another routing protocol\n"
+              FRR_IP_REDIST_HELP_STR_BGPD
+              "Route map reference\n"
+              "Pointer to route-map entries\n")
+
 DEFUN (bgp_redistribute_ipv4_metric,
        bgp_redistribute_ipv4_metric_cmd,
        "redistribute " FRR_IP_REDIST_STR_BGPD " metric (0-4294967295)",
@@ -9553,6 +10249,14 @@ DEFUN (bgp_redistribute_ipv4_metric,
   return bgp_redistribute_set (bgp, AFI_IP, type, 0);
 }
 
+ALIAS_HIDDEN (bgp_redistribute_ipv4_metric,
+              bgp_redistribute_ipv4_metric_hidden_cmd,
+              "redistribute " FRR_IP_REDIST_STR_BGPD " metric (0-4294967295)",
+              "Redistribute information from another routing protocol\n"
+              FRR_IP_REDIST_HELP_STR_BGPD
+              "Metric for redistributed routes\n"
+              "Default metric\n")
+
 DEFUN (bgp_redistribute_ipv4_rmap_metric,
        bgp_redistribute_ipv4_rmap_metric_cmd,
        "redistribute " FRR_IP_REDIST_STR_BGPD " route-map WORD metric (0-4294967295)",
@@ -9585,6 +10289,16 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric,
   return bgp_redistribute_set (bgp, AFI_IP, type, 0);
 }
 
+ALIAS_HIDDEN (bgp_redistribute_ipv4_rmap_metric,
+              bgp_redistribute_ipv4_rmap_metric_hidden_cmd,
+              "redistribute " FRR_IP_REDIST_STR_BGPD " route-map WORD metric (0-4294967295)",
+              "Redistribute information from another routing protocol\n"
+              FRR_IP_REDIST_HELP_STR_BGPD
+              "Route map reference\n"
+              "Pointer to route-map entries\n"
+              "Metric for redistributed routes\n"
+              "Default metric\n")
+
 DEFUN (bgp_redistribute_ipv4_metric_rmap,
        bgp_redistribute_ipv4_metric_rmap_cmd,
        "redistribute " FRR_IP_REDIST_STR_BGPD " metric (0-4294967295) route-map WORD",
@@ -9617,6 +10331,16 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap,
   return bgp_redistribute_set (bgp, AFI_IP, type, 0);
 }
 
+ALIAS_HIDDEN (bgp_redistribute_ipv4_metric_rmap,
+              bgp_redistribute_ipv4_metric_rmap_hidden_cmd,
+              "redistribute " FRR_IP_REDIST_STR_BGPD " metric (0-4294967295) route-map WORD",
+              "Redistribute information from another routing protocol\n"
+              FRR_IP_REDIST_HELP_STR_BGPD
+              "Metric for redistributed routes\n"
+              "Default metric\n"
+              "Route map reference\n"
+              "Pointer to route-map entries\n")
+
 DEFUN (bgp_redistribute_ipv4_ospf,
        bgp_redistribute_ipv4_ospf_cmd,
        "redistribute <ospf|table> (1-65535)",
@@ -9642,6 +10366,14 @@ DEFUN (bgp_redistribute_ipv4_ospf,
   return bgp_redistribute_set (bgp, AFI_IP, protocol, instance);
 }
 
+ALIAS_HIDDEN (bgp_redistribute_ipv4_ospf,
+              bgp_redistribute_ipv4_ospf_hidden_cmd,
+              "redistribute <ospf|table> (1-65535)",
+              "Redistribute information from another routing protocol\n"
+              "Open Shortest Path First (OSPFv2)\n"
+              "Non-main Kernel Routing Table\n"
+              "Instance ID/Table ID\n")
+
 DEFUN (bgp_redistribute_ipv4_ospf_rmap,
        bgp_redistribute_ipv4_ospf_rmap_cmd,
        "redistribute <ospf|table> (1-65535) route-map WORD",
@@ -9671,6 +10403,16 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap,
   return bgp_redistribute_set (bgp, AFI_IP, protocol, instance);
 }
 
+ALIAS_HIDDEN (bgp_redistribute_ipv4_ospf_rmap,
+              bgp_redistribute_ipv4_ospf_rmap_hidden_cmd,
+              "redistribute <ospf|table> (1-65535) route-map WORD",
+              "Redistribute information from another routing protocol\n"
+              "Open Shortest Path First (OSPFv2)\n"
+              "Non-main Kernel Routing Table\n"
+              "Instance ID/Table ID\n"
+              "Route map reference\n"
+              "Pointer to route-map entries\n")
+
 DEFUN (bgp_redistribute_ipv4_ospf_metric,
        bgp_redistribute_ipv4_ospf_metric_cmd,
        "redistribute <ospf|table> (1-65535) metric (0-4294967295)",
@@ -9703,6 +10445,16 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric,
   return bgp_redistribute_set (bgp, AFI_IP, protocol, instance);
 }
 
+ALIAS_HIDDEN (bgp_redistribute_ipv4_ospf_metric,
+              bgp_redistribute_ipv4_ospf_metric_hidden_cmd,
+              "redistribute <ospf|table> (1-65535) metric (0-4294967295)",
+              "Redistribute information from another routing protocol\n"
+              "Open Shortest Path First (OSPFv2)\n"
+              "Non-main Kernel Routing Table\n"
+              "Instance ID/Table ID\n"
+              "Metric for redistributed routes\n"
+              "Default metric\n")
+
 DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric,
        bgp_redistribute_ipv4_ospf_rmap_metric_cmd,
        "redistribute <ospf|table> (1-65535) route-map WORD metric (0-4294967295)",
@@ -9739,6 +10491,18 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric,
   return bgp_redistribute_set (bgp, AFI_IP, protocol, instance);
 }
 
+ALIAS_HIDDEN (bgp_redistribute_ipv4_ospf_rmap_metric,
+              bgp_redistribute_ipv4_ospf_rmap_metric_hidden_cmd,
+              "redistribute <ospf|table> (1-65535) route-map WORD metric (0-4294967295)",
+              "Redistribute information from another routing protocol\n"
+              "Open Shortest Path First (OSPFv2)\n"
+              "Non-main Kernel Routing Table\n"
+              "Instance ID/Table ID\n"
+              "Route map reference\n"
+              "Pointer to route-map entries\n"
+              "Metric for redistributed routes\n"
+              "Default metric\n")
+
 DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap,
        bgp_redistribute_ipv4_ospf_metric_rmap_cmd,
        "redistribute <ospf|table> (1-65535) metric (0-4294967295) route-map WORD",
@@ -9775,6 +10539,18 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap,
   return bgp_redistribute_set (bgp, AFI_IP, protocol, instance);
 }
 
+ALIAS_HIDDEN (bgp_redistribute_ipv4_ospf_metric_rmap,
+              bgp_redistribute_ipv4_ospf_metric_rmap_hidden_cmd,
+              "redistribute <ospf|table> (1-65535) metric (0-4294967295) route-map WORD",
+              "Redistribute information from another routing protocol\n"
+              "Open Shortest Path First (OSPFv2)\n"
+              "Non-main Kernel Routing Table\n"
+              "Instance ID/Table ID\n"
+              "Metric for redistributed routes\n"
+              "Default metric\n"
+              "Route map reference\n"
+              "Pointer to route-map entries\n")
+
 DEFUN (no_bgp_redistribute_ipv4_ospf,
        no_bgp_redistribute_ipv4_ospf_cmd,
        "no redistribute <ospf|table> (1-65535) [metric (0-4294967295)] [route-map WORD]",
@@ -9803,6 +10579,19 @@ DEFUN (no_bgp_redistribute_ipv4_ospf,
   return bgp_redistribute_unset (bgp, AFI_IP, protocol, instance);
 }
 
+ALIAS_HIDDEN (no_bgp_redistribute_ipv4_ospf,
+              no_bgp_redistribute_ipv4_ospf_hidden_cmd,
+              "no redistribute <ospf|table> (1-65535) [metric (0-4294967295)] [route-map WORD]",
+              NO_STR
+              "Redistribute information from another routing protocol\n"
+              "Open Shortest Path First (OSPFv2)\n"
+              "Non-main Kernel Routing Table\n"
+              "Instance ID/Table ID\n"
+              "Metric for redistributed routes\n"
+              "Default metric\n"
+              "Route map reference\n"
+              "Pointer to route-map entries\n")
+
 DEFUN (no_bgp_redistribute_ipv4,
        no_bgp_redistribute_ipv4_cmd,
        "no redistribute " FRR_IP_REDIST_STR_BGPD " [metric (0-4294967295)] [route-map WORD]",
@@ -9827,6 +10616,17 @@ DEFUN (no_bgp_redistribute_ipv4,
   return bgp_redistribute_unset (bgp, AFI_IP, type, 0);
 }
 
+ALIAS_HIDDEN (no_bgp_redistribute_ipv4,
+              no_bgp_redistribute_ipv4_hidden_cmd,
+              "no redistribute " FRR_IP_REDIST_STR_BGPD " [metric (0-4294967295)] [route-map WORD]",
+              NO_STR
+              "Redistribute information from another routing protocol\n"
+              FRR_IP_REDIST_HELP_STR_BGPD
+              "Metric for redistributed routes\n"
+              "Default metric\n"
+              "Route map reference\n"
+              "Pointer to route-map entries\n")
+
 DEFUN (bgp_redistribute_ipv6,
        bgp_redistribute_ipv6_cmd,
        "redistribute " FRR_IP6_REDIST_STR_BGPD,
@@ -10056,6 +10856,13 @@ static struct cmd_node bgp_ipv4_multicast_node =
   1,
 };
 
+static struct cmd_node bgp_ipv4_labeled_unicast_node =
+{
+  BGP_IPV4L_NODE,
+  "%s(config-router-af)# ",
+  1,
+};
+
 static struct cmd_node bgp_ipv6_unicast_node =
 {
   BGP_IPV6_NODE,
@@ -10070,6 +10877,13 @@ static struct cmd_node bgp_ipv6_multicast_node =
   1,
 };
 
+static struct cmd_node bgp_ipv6_labeled_unicast_node =
+{
+  BGP_IPV6L_NODE,
+  "%s(config-router-af)# ",
+  1,
+};
+
 static struct cmd_node bgp_vpnv4_node =
 {
   BGP_VPNV4_NODE,
@@ -10114,8 +10928,10 @@ bgp_vty_init (void)
   install_node (&bgp_node, bgp_config_write);
   install_node (&bgp_ipv4_unicast_node, NULL);
   install_node (&bgp_ipv4_multicast_node, NULL);
+  install_node (&bgp_ipv4_labeled_unicast_node, NULL);
   install_node (&bgp_ipv6_unicast_node, NULL);
   install_node (&bgp_ipv6_multicast_node, NULL);
+  install_node (&bgp_ipv6_labeled_unicast_node, NULL);
   install_node (&bgp_vpnv4_node, NULL);
   install_node (&bgp_vpnv6_node, NULL);
   install_node (&bgp_encap_node, NULL);
@@ -10126,8 +10942,10 @@ bgp_vty_init (void)
   install_default (BGP_NODE);
   install_default (BGP_IPV4_NODE);
   install_default (BGP_IPV4M_NODE);
+  install_default (BGP_IPV4L_NODE);
   install_default (BGP_IPV6_NODE);
   install_default (BGP_IPV6M_NODE);
+  install_default (BGP_IPV6L_NODE);
   install_default (BGP_VPNV4_NODE);
   install_default (BGP_VPNV6_NODE);
   install_default (BGP_ENCAP_NODE);
@@ -10196,22 +11014,34 @@ bgp_vty_init (void)
   install_element (BGP_NODE, &no_bgp_coalesce_time_cmd);
 
   /* "maximum-paths" commands. */
-  install_element (BGP_NODE, &bgp_maxpaths_cmd);
-  install_element (BGP_NODE, &no_bgp_maxpaths_cmd);
+  install_element (BGP_NODE, &bgp_maxpaths_hidden_cmd);
+  install_element (BGP_NODE, &no_bgp_maxpaths_hidden_cmd);
   install_element (BGP_IPV4_NODE, &bgp_maxpaths_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_cmd);
   install_element (BGP_IPV6_NODE, &bgp_maxpaths_cmd);
   install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_cmd);
-  install_element (BGP_NODE, &bgp_maxpaths_ibgp_cmd);
-  install_element(BGP_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
-  install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_cmd);
+  install_element (BGP_NODE, &bgp_maxpaths_ibgp_hidden_cmd);
+  install_element (BGP_NODE, &bgp_maxpaths_ibgp_cluster_hidden_cmd);
+  install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_hidden_cmd);
   install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cmd);
-  install_element(BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
+  install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_cmd);
   install_element (BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cmd);
-  install_element(BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
+  install_element (BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
   install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_cmd);
 
+  install_element (BGP_IPV4L_NODE, &bgp_maxpaths_cmd);
+  install_element (BGP_IPV4L_NODE, &no_bgp_maxpaths_cmd);
+  install_element (BGP_IPV6L_NODE, &bgp_maxpaths_cmd);
+  install_element (BGP_IPV6L_NODE, &no_bgp_maxpaths_cmd);
+
+  install_element (BGP_IPV4L_NODE, &bgp_maxpaths_ibgp_cmd);
+  install_element (BGP_IPV4L_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
+  install_element (BGP_IPV4L_NODE, &no_bgp_maxpaths_ibgp_cmd);
+  install_element (BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cmd);
+  install_element (BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cluster_cmd);
+  install_element (BGP_IPV6L_NODE, &no_bgp_maxpaths_ibgp_cmd);
+
   /* "timers bgp" commands. */
   install_element (BGP_NODE, &bgp_timers_cmd);
   install_element (BGP_NODE, &no_bgp_timers_cmd);
@@ -10337,11 +11167,13 @@ bgp_vty_init (void)
   install_element (BGP_NODE, &no_neighbor_password_cmd);
 
   /* "neighbor activate" commands. */
-  install_element (BGP_NODE, &neighbor_activate_cmd);
+  install_element (BGP_NODE, &neighbor_activate_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_activate_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_activate_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_activate_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_activate_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_activate_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_activate_cmd);
   install_element (BGP_ENCAP_NODE, &neighbor_activate_cmd);
@@ -10349,55 +11181,60 @@ bgp_vty_init (void)
   install_element (BGP_EVPN_NODE, &neighbor_activate_cmd);
 
   /* "no neighbor activate" commands. */
-  install_element (BGP_NODE, &no_neighbor_activate_cmd);
+  install_element (BGP_NODE, &no_neighbor_activate_hidden_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_activate_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_activate_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_activate_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd);
   install_element (BGP_VPNV6_NODE, &no_neighbor_activate_cmd);
   install_element (BGP_ENCAP_NODE, &no_neighbor_activate_cmd);
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_activate_cmd);
   install_element (BGP_EVPN_NODE, &no_neighbor_activate_cmd);
 
-  /* "neighbor peer-group" set commands.
-   * Long term we should only accept this command under BGP_NODE and not all of
-   * the afi/safi sub-contexts. For now though we need to accept it for backwards
-   * compatibility. This changed when we stopped requiring that peers be assigned
-   * to their peer-group under each address-family sub-context.
-   */
+  /* "neighbor peer-group" set commands. */
   install_element (BGP_NODE, &neighbor_set_peer_group_cmd);
-  install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd);
-  install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd);
-  install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd);
-  install_element (BGP_IPV6M_NODE, &neighbor_set_peer_group_cmd);
-  install_element (BGP_VPNV4_NODE, &neighbor_set_peer_group_cmd);
-  install_element (BGP_VPNV6_NODE, &neighbor_set_peer_group_cmd);
-  install_element (BGP_ENCAP_NODE, &neighbor_set_peer_group_cmd);
-  install_element (BGP_ENCAPV6_NODE, &neighbor_set_peer_group_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_IPV6M_NODE, &neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_VPNV6_NODE, &neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_ENCAP_NODE, &neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_ENCAPV6_NODE, &neighbor_set_peer_group_hidden_cmd);
 
   /* "no neighbor peer-group unset" commands. */
   install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd);
-  install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd);
-  install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd);
-  install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd);
-  install_element (BGP_IPV6M_NODE, &no_neighbor_set_peer_group_cmd);
-  install_element (BGP_VPNV4_NODE, &no_neighbor_set_peer_group_cmd);
-  install_element (BGP_VPNV6_NODE, &no_neighbor_set_peer_group_cmd);
-  install_element (BGP_ENCAP_NODE, &no_neighbor_set_peer_group_cmd);
-  install_element (BGP_ENCAPV6_NODE, &no_neighbor_set_peer_group_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_IPV6M_NODE, &no_neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_VPNV6_NODE, &no_neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_ENCAP_NODE, &no_neighbor_set_peer_group_hidden_cmd);
+  install_element (BGP_ENCAPV6_NODE, &no_neighbor_set_peer_group_hidden_cmd);
 
   /* "neighbor softreconfiguration inbound" commands.*/
-  install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd);
-  install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd);
+  install_element (BGP_NODE, &neighbor_soft_reconfiguration_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_soft_reconfiguration_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_soft_reconfiguration_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_soft_reconfiguration_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_soft_reconfiguration_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_soft_reconfiguration_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_soft_reconfiguration_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_soft_reconfiguration_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_soft_reconfiguration_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_soft_reconfiguration_cmd);
@@ -10408,16 +11245,20 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_soft_reconfiguration_cmd);
 
   /* "neighbor attribute-unchanged" commands.  */
-  install_element (BGP_NODE, &neighbor_attr_unchanged_cmd);
-  install_element (BGP_NODE, &no_neighbor_attr_unchanged_cmd);
+  install_element (BGP_NODE, &neighbor_attr_unchanged_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_attr_unchanged_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_attr_unchanged_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_attr_unchanged_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_attr_unchanged_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_attr_unchanged_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged_cmd);
@@ -10437,16 +11278,20 @@ bgp_vty_init (void)
   install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd);
 
   /* "neighbor next-hop-self" commands. */
-  install_element (BGP_NODE, &neighbor_nexthop_self_cmd);
-  install_element (BGP_NODE, &no_neighbor_nexthop_self_cmd);
+  install_element (BGP_NODE, &neighbor_nexthop_self_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_nexthop_self_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_nexthop_self_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_nexthop_self_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_nexthop_self_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_nexthop_self_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_nexthop_self_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_nexthop_self_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_nexthop_self_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_nexthop_self_cmd);
@@ -10457,46 +11302,54 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_nexthop_self_cmd);
 
   /* "neighbor next-hop-self force" commands. */
-  install_element (BGP_NODE, &neighbor_nexthop_self_force_cmd);
-  install_element (BGP_NODE, &no_neighbor_nexthop_self_force_cmd);
+  install_element (BGP_NODE, &neighbor_nexthop_self_force_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_nexthop_self_force_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_nexthop_self_force_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_force_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_force_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_force_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_nexthop_self_force_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_nexthop_self_force_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_force_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_force_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_nexthop_self_force_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_nexthop_self_force_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_nexthop_self_force_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_nexthop_self_force_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_force_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_force_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_nexthop_self_force_cmd);
   install_element (BGP_VPNV6_NODE, &no_neighbor_nexthop_self_force_cmd);
 
   /* "neighbor as-override" commands. */
-  install_element (BGP_NODE, &neighbor_as_override_cmd);
-  install_element (BGP_NODE, &no_neighbor_as_override_cmd);
+  install_element (BGP_NODE, &neighbor_as_override_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_as_override_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_as_override_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_as_override_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_as_override_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_as_override_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_as_override_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_as_override_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_as_override_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_as_override_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_as_override_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_as_override_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_as_override_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_as_override_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_as_override_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_as_override_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_as_override_cmd);
   install_element (BGP_VPNV6_NODE, &no_neighbor_as_override_cmd);
 
   /* "neighbor remove-private-AS" commands. */
-  install_element (BGP_NODE, &neighbor_remove_private_as_cmd);
-  install_element (BGP_NODE, &no_neighbor_remove_private_as_cmd);
-  install_element (BGP_NODE, &neighbor_remove_private_as_all_cmd);
-  install_element (BGP_NODE, &no_neighbor_remove_private_as_all_cmd);
-  install_element (BGP_NODE, &neighbor_remove_private_as_replace_as_cmd);
-  install_element (BGP_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
-  install_element (BGP_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
-  install_element (BGP_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
+  install_element (BGP_NODE, &neighbor_remove_private_as_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_remove_private_as_hidden_cmd);
+  install_element (BGP_NODE, &neighbor_remove_private_as_all_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_remove_private_as_all_hidden_cmd);
+  install_element (BGP_NODE, &neighbor_remove_private_as_replace_as_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_remove_private_as_replace_as_hidden_cmd);
+  install_element (BGP_NODE, &neighbor_remove_private_as_all_replace_as_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_remove_private_as_all_replace_as_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_remove_private_as_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_all_cmd);
@@ -10513,6 +11366,14 @@ bgp_vty_init (void)
   install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_all_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_all_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_replace_as_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_all_cmd);
@@ -10529,6 +11390,14 @@ bgp_vty_init (void)
   install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_all_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_all_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_replace_as_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_all_cmd);
@@ -10551,10 +11420,10 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_remove_private_as_cmd);
 
   /* "neighbor send-community" commands.*/
-  install_element (BGP_NODE, &neighbor_send_community_cmd);
-  install_element (BGP_NODE, &neighbor_send_community_type_cmd);
-  install_element (BGP_NODE, &no_neighbor_send_community_cmd);
-  install_element (BGP_NODE, &no_neighbor_send_community_type_cmd);
+  install_element (BGP_NODE, &neighbor_send_community_hidden_cmd);
+  install_element (BGP_NODE, &neighbor_send_community_type_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_send_community_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_send_community_type_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_send_community_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_send_community_type_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_send_community_cmd);
@@ -10563,6 +11432,10 @@ bgp_vty_init (void)
   install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_send_community_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_send_community_type_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_send_community_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_send_community_type_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd);
@@ -10571,6 +11444,10 @@ bgp_vty_init (void)
   install_element (BGP_IPV6M_NODE, &neighbor_send_community_type_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_type_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_send_community_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_send_community_type_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_send_community_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_send_community_type_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd);
@@ -10589,16 +11466,20 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_send_community_type_cmd);
 
   /* "neighbor route-reflector" commands.*/
-  install_element (BGP_NODE, &neighbor_route_reflector_client_cmd);
-  install_element (BGP_NODE, &no_neighbor_route_reflector_client_cmd);
+  install_element (BGP_NODE, &neighbor_route_reflector_client_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_route_reflector_client_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_route_reflector_client_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_route_reflector_client_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_route_reflector_client_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_route_reflector_client_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_route_reflector_client_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_route_reflector_client_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_route_reflector_client_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_route_reflector_client_cmd);
@@ -10609,16 +11490,20 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_route_reflector_client_cmd);
 
   /* "neighbor route-server" commands.*/
-  install_element (BGP_NODE, &neighbor_route_server_client_cmd);
-  install_element (BGP_NODE, &no_neighbor_route_server_client_cmd);
+  install_element (BGP_NODE, &neighbor_route_server_client_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_route_server_client_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_route_server_client_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_route_server_client_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_route_server_client_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_route_server_client_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_route_server_client_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_route_server_client_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_route_server_client_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_route_server_client_cmd);
@@ -10629,32 +11514,40 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_route_server_client_cmd);
 
   /* "neighbor addpath-tx-all-paths" commands.*/
-  install_element (BGP_NODE, &neighbor_addpath_tx_all_paths_cmd);
-  install_element (BGP_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_NODE, &neighbor_addpath_tx_all_paths_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_addpath_tx_all_paths_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_addpath_tx_all_paths_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_addpath_tx_all_paths_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_addpath_tx_all_paths_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_addpath_tx_all_paths_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_all_paths_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_addpath_tx_all_paths_cmd);
   install_element (BGP_VPNV6_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
 
   /* "neighbor addpath-tx-bestpath-per-AS" commands.*/
-  install_element (BGP_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
-  install_element (BGP_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_NODE, &neighbor_addpath_tx_bestpath_per_as_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_addpath_tx_bestpath_per_as_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
@@ -10676,16 +11569,20 @@ bgp_vty_init (void)
   install_element (BGP_NODE, &no_neighbor_capability_enhe_cmd);
 
   /* "neighbor capability orf prefix-list" commands.*/
-  install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd);
-  install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd);
+  install_element (BGP_NODE, &neighbor_capability_orf_prefix_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_capability_orf_prefix_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_capability_orf_prefix_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_capability_orf_prefix_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_capability_orf_prefix_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_capability_orf_prefix_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_capability_orf_prefix_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_capability_orf_prefix_cmd);
 
   /* "neighbor capability dynamic" commands.*/
   install_element (BGP_NODE, &neighbor_capability_dynamic_cmd);
@@ -10713,38 +11610,48 @@ bgp_vty_init (void)
   install_element (BGP_NODE, &no_neighbor_update_source_cmd);
 
   /* "neighbor default-originate" commands. */
-  install_element (BGP_NODE, &neighbor_default_originate_cmd);
-  install_element (BGP_NODE, &neighbor_default_originate_rmap_cmd);
-  install_element (BGP_NODE, &no_neighbor_default_originate_cmd);
+  install_element (BGP_NODE, &neighbor_default_originate_hidden_cmd);
+  install_element (BGP_NODE, &neighbor_default_originate_rmap_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_default_originate_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_default_originate_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_default_originate_rmap_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_default_originate_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_default_originate_rmap_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_default_originate_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_default_originate_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_default_originate_rmap_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_default_originate_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_default_originate_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_default_originate_rmap_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_default_originate_cmd);
 
   /* "neighbor port" commands. */
   install_element (BGP_NODE, &neighbor_port_cmd);
   install_element (BGP_NODE, &no_neighbor_port_cmd);
 
   /* "neighbor weight" commands. */
-  install_element (BGP_NODE, &neighbor_weight_cmd);
-  install_element (BGP_NODE, &no_neighbor_weight_cmd);
+  install_element (BGP_NODE, &neighbor_weight_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_weight_hidden_cmd);
 
   install_element (BGP_IPV4_NODE, &neighbor_weight_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_weight_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_weight_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_weight_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_weight_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_weight_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_weight_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_weight_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_weight_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_weight_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_weight_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_weight_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_weight_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_weight_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_weight_cmd);
@@ -10779,16 +11686,20 @@ bgp_vty_init (void)
   install_element (BGP_NODE, &no_neighbor_interface_cmd);
 
   /* "neighbor distribute" commands. */
-  install_element (BGP_NODE, &neighbor_distribute_list_cmd);
-  install_element (BGP_NODE, &no_neighbor_distribute_list_cmd);
+  install_element (BGP_NODE, &neighbor_distribute_list_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_distribute_list_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_distribute_list_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_distribute_list_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_distribute_list_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_distribute_list_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_distribute_list_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_distribute_list_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_distribute_list_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_distribute_list_cmd);
@@ -10799,16 +11710,20 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_distribute_list_cmd);
 
   /* "neighbor prefix-list" commands. */
-  install_element (BGP_NODE, &neighbor_prefix_list_cmd);
-  install_element (BGP_NODE, &no_neighbor_prefix_list_cmd);
+  install_element (BGP_NODE, &neighbor_prefix_list_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_prefix_list_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_prefix_list_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_prefix_list_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_prefix_list_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_prefix_list_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_prefix_list_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_prefix_list_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_prefix_list_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_prefix_list_cmd);
@@ -10819,16 +11734,20 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_prefix_list_cmd);
 
   /* "neighbor filter-list" commands. */
-  install_element (BGP_NODE, &neighbor_filter_list_cmd);
-  install_element (BGP_NODE, &no_neighbor_filter_list_cmd);
+  install_element (BGP_NODE, &neighbor_filter_list_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_filter_list_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_filter_list_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_filter_list_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_filter_list_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_filter_list_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_filter_list_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_filter_list_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_filter_list_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_filter_list_cmd);
@@ -10839,16 +11758,20 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_filter_list_cmd);
 
   /* "neighbor route-map" commands. */
-  install_element (BGP_NODE, &neighbor_route_map_cmd);
-  install_element (BGP_NODE, &no_neighbor_route_map_cmd);
+  install_element (BGP_NODE, &neighbor_route_map_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_route_map_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_route_map_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_route_map_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_route_map_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_route_map_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_route_map_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_route_map_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_route_map_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_route_map_cmd);
@@ -10859,16 +11782,20 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_route_map_cmd);
 
   /* "neighbor unsuppress-map" commands. */
-  install_element (BGP_NODE, &neighbor_unsuppress_map_cmd);
-  install_element (BGP_NODE, &no_neighbor_unsuppress_map_cmd);
+  install_element (BGP_NODE, &neighbor_unsuppress_map_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_unsuppress_map_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_unsuppress_map_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_unsuppress_map_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_unsuppress_map_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_unsuppress_map_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_unsuppress_map_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_unsuppress_map_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd);
@@ -10879,13 +11806,13 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_unsuppress_map_cmd);
 
   /* "neighbor maximum-prefix" commands. */
-  install_element (BGP_NODE, &neighbor_maximum_prefix_cmd);
-  install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_cmd);
-  install_element (BGP_NODE, &neighbor_maximum_prefix_warning_cmd);
-  install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_warning_cmd);
-  install_element (BGP_NODE, &neighbor_maximum_prefix_restart_cmd);
-  install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
-  install_element (BGP_NODE, &no_neighbor_maximum_prefix_cmd);
+  install_element (BGP_NODE, &neighbor_maximum_prefix_hidden_cmd);
+  install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_hidden_cmd);
+  install_element (BGP_NODE, &neighbor_maximum_prefix_warning_hidden_cmd);
+  install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_warning_hidden_cmd);
+  install_element (BGP_NODE, &neighbor_maximum_prefix_restart_hidden_cmd);
+  install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_restart_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_maximum_prefix_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_warning_cmd);
@@ -10900,6 +11827,13 @@ bgp_vty_init (void)
   install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_restart_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_warning_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_warning_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_restart_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_maximum_prefix_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd);
@@ -10914,6 +11848,13 @@ bgp_vty_init (void)
   install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_restart_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_warning_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_warning_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_restart_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_maximum_prefix_threshold_restart_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_maximum_prefix_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd);
@@ -10946,16 +11887,20 @@ bgp_vty_init (void)
   install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_cmd);
 
   /* "neighbor allowas-in" */
-  install_element (BGP_NODE, &neighbor_allowas_in_cmd);
-  install_element (BGP_NODE, &no_neighbor_allowas_in_cmd);
+  install_element (BGP_NODE, &neighbor_allowas_in_hidden_cmd);
+  install_element (BGP_NODE, &no_neighbor_allowas_in_hidden_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_allowas_in_cmd);
   install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd);
   install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd);
   install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd);
+  install_element (BGP_IPV4L_NODE, &neighbor_allowas_in_cmd);
+  install_element (BGP_IPV4L_NODE, &no_neighbor_allowas_in_cmd);
   install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd);
   install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd);
   install_element (BGP_IPV6M_NODE, &neighbor_allowas_in_cmd);
   install_element (BGP_IPV6M_NODE, &no_neighbor_allowas_in_cmd);
+  install_element (BGP_IPV6L_NODE, &neighbor_allowas_in_cmd);
+  install_element (BGP_IPV6L_NODE, &no_neighbor_allowas_in_cmd);
   install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd);
   install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_cmd);
@@ -10981,8 +11926,10 @@ bgp_vty_init (void)
   /* "exit-address-family" command. */
   install_element (BGP_IPV4_NODE, &exit_address_family_cmd);
   install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
+  install_element (BGP_IPV4L_NODE, &exit_address_family_cmd);
   install_element (BGP_IPV6_NODE, &exit_address_family_cmd);
   install_element (BGP_IPV6M_NODE, &exit_address_family_cmd);
+  install_element (BGP_IPV6L_NODE, &exit_address_family_cmd);
   install_element (BGP_VPNV4_NODE, &exit_address_family_cmd);
   install_element (BGP_VPNV6_NODE, &exit_address_family_cmd);
   install_element (BGP_ENCAP_NODE, &exit_address_family_cmd);
@@ -11032,18 +11979,18 @@ bgp_vty_init (void)
   install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd);
 
   /* "redistribute" commands.  */
-  install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd);
-  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_cmd);
-  install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_cmd);
-  install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_cmd);
-  install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd);
-  install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd);
-  install_element (BGP_NODE, &bgp_redistribute_ipv4_ospf_cmd);
-  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_ospf_cmd);
-  install_element (BGP_NODE, &bgp_redistribute_ipv4_ospf_rmap_cmd);
-  install_element (BGP_NODE, &bgp_redistribute_ipv4_ospf_metric_cmd);
-  install_element (BGP_NODE, &bgp_redistribute_ipv4_ospf_rmap_metric_cmd);
-  install_element (BGP_NODE, &bgp_redistribute_ipv4_ospf_metric_rmap_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_hidden_cmd);
+  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_hidden_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_hidden_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_hidden_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_metric_hidden_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_rmap_hidden_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_ospf_hidden_cmd);
+  install_element (BGP_NODE, &no_bgp_redistribute_ipv4_ospf_hidden_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_ospf_rmap_hidden_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_ospf_metric_hidden_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_ospf_rmap_metric_hidden_cmd);
+  install_element (BGP_NODE, &bgp_redistribute_ipv4_ospf_metric_rmap_hidden_cmd);
   install_element (BGP_IPV4_NODE, &bgp_redistribute_ipv4_cmd);
   install_element (BGP_IPV4_NODE, &no_bgp_redistribute_ipv4_cmd);
   install_element (BGP_IPV4_NODE, &bgp_redistribute_ipv4_rmap_cmd);
index 33d24d530e5db86c8b4438b6a2ff012f9a180efc..a0aabcbd2ce6d547d8015a7df86b0c16ecbe9e36 100644 (file)
@@ -28,8 +28,10 @@ struct bgp;
 
 #define BGP_AFI_CMD_STR         "<ipv4|ipv6>"
 #define BGP_AFI_HELP_STR        "Address Family\nAddress Family\n"
-#define BGP_SAFI_CMD_STR        "<unicast|multicast|vpn|encap>"
+#define BGP_SAFI_CMD_STR        "<unicast|multicast|vpn|encap|labeled-unicast>"
 #define BGP_SAFI_HELP_STR       \
+  "Address Family modifier\n"   \
+  "Address Family modifier\n"   \
   "Address Family modifier\n"   \
   "Address Family modifier\n"   \
   "Address Family modifier\n"   \
index 72bd081a7e75c4480dbd92d037538c7fbf4f15bd..d76eb951db3ff40b2f0989d3415460938547384d 100644 (file)
@@ -34,6 +34,7 @@ Boston, MA 02111-1307, USA.  */
 #include "lib/json.h"
 #include "lib/bfd.h"
 #include "filter.h"
+#include "mpls.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_route.h"
@@ -46,6 +47,7 @@ Boston, MA 02111-1307, USA.  */
 #include "bgpd/bgp_nexthop.h"
 #include "bgpd/bgp_nht.h"
 #include "bgpd/bgp_bfd.h"
+#include "bgpd/bgp_label.h"
 #if ENABLE_BGP_VNC
 # include "bgpd/rfapi/rfapi_backend.h"
 # include "bgpd/rfapi/vnc_export_bgp.h"
@@ -57,6 +59,7 @@ struct zclient *zclient = NULL;
 /* Growable buffer for nexthops sent to zebra */
 struct stream *bgp_nexthop_buf = NULL;
 struct stream *bgp_ifindices_buf = NULL;
+struct stream *bgp_label_buf = NULL;
 
 /* These array buffers are used in making a copy of the attributes for
    route-map apply. Arrays are being used here to minimize mallocs and
@@ -178,6 +181,14 @@ bgp_update_interface_nbrs (struct bgp *bgp, struct interface *ifp,
     }
 }
 
+static int
+bgp_read_fec_update (int command, struct zclient *zclient,
+                    zebra_size_t length)
+{
+  bgp_parse_fec_update();
+  return 0;
+}
+
 static void
 bgp_start_interface_nbrs (struct bgp *bgp, struct interface *ifp)
 {
@@ -1204,8 +1215,8 @@ bgp_table_map_apply (struct route_map *map, struct prefix *p,
 }
 
 void
-bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
-                    afi_t afi, safi_t safi)
+bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info,
+                    struct bgp *bgp, afi_t afi, safi_t safi)
 {
   u_int32_t flags;
   u_char distance;
@@ -1216,6 +1227,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
   struct bgp_info local_info;
   struct bgp_info *info_cp = &local_info;
   route_tag_t tag;
+  u_int32_t label;
 
   /* Don't try to install if we're not connected to Zebra or Zebra doesn't
    * know of this instance.
@@ -1271,7 +1283,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
       if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
           (sizeof (struct in_addr *) * nhcount))
         {
-          newsize = (sizeof (struct in_addr *) * nhcount);
+          newsize = sizeof (struct in_addr *) * nhcount;
           newsize = stream_resize (bgp_nexthop_buf, newsize);
           if (newsize == oldsize)
             {
@@ -1282,6 +1294,25 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
       stream_reset (bgp_nexthop_buf);
       nexthop = NULL;
 
+      /* For labeled unicast, each nexthop has a label too. Resize label
+       * buffer, if required.
+       */
+      if (safi == SAFI_LABELED_UNICAST)
+        {
+          if ((oldsize = stream_get_size (bgp_label_buf)) <
+              (sizeof (unsigned int) * nhcount))
+            {
+              newsize = (sizeof (unsigned int) * nhcount);
+              newsize = stream_resize (bgp_label_buf, newsize);
+              if (newsize == oldsize)
+                {
+                  zlog_err ("can't resize label buffer");
+                  return;
+                }
+            }
+          stream_reset (bgp_label_buf);
+        }
+
       /* Metric is currently based on the best-path only. */
       metric = info->attr->med;
 
@@ -1311,6 +1342,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
         {
           stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
           valid_nh_count++;
+          if (safi == SAFI_LABELED_UNICAST)
+            {
+              label = label_pton(info->extra->tag);
+              stream_put (bgp_label_buf, &label, sizeof (u_int32_t));
+            }
         }
 
       for (mpinfo = bgp_info_mpath_first (info); mpinfo;
@@ -1336,6 +1372,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
             continue;
 
           stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
+          if (safi == SAFI_LABELED_UNICAST)
+            {
+              label = label_pton(mpinfo->extra->tag);
+              stream_put (bgp_label_buf, &label, sizeof (u_int32_t));
+            }
           valid_nh_count++;
         }
 
@@ -1344,8 +1385,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
       api.type = ZEBRA_ROUTE_BGP;
       api.instance = 0;
       api.message = 0;
-      api.safi = safi;
+      api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi;
       SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      if (safi == SAFI_LABELED_UNICAST)
+        SET_FLAG (api.message, ZAPI_MESSAGE_LABEL);
 
       /* Note that this currently only applies to Null0 routes for aggregates.
        * ZEBRA_FLAG_BLACKHOLE signals zapi_ipv4_route to encode a special
@@ -1358,6 +1401,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
         api.nexthop_num = valid_nh_count;
 
       api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf);
+      if (safi == SAFI_LABELED_UNICAST)
+        {
+          api.label_num = valid_nh_count;
+          api.label = (unsigned int *)STREAM_DATA (bgp_label_buf);
+        }
+      else
+        {
+          api.label_num = 0;
+          api.label = NULL;
+        }
       api.ifindex_num = 0;
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
       api.metric = metric;
@@ -1379,14 +1432,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
       if (bgp_debug_zebra(p))
         {
           int i;
+          char label_buf[20];
           zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI
                      " count %d", (valid_nh_count ? "add":"delete"),
                      bgp->vrf_id,
                      inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
                      p->prefixlen, api.metric, api.tag, api.nexthop_num);
           for (i = 0; i < api.nexthop_num; i++)
-            zlog_debug("  IPv4 [nexthop %d] %s", i+1,
-                       inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1])));
+            {
+              label_buf[0] = '\0';
+              if (safi == SAFI_LABELED_UNICAST)
+                sprintf(label_buf, "label %u", api.label[i]);
+              zlog_debug("  nhop [%d]: %s %s",
+                         i+1,
+                         inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1])),
+                         label_buf);
+            }
         }
 
       zapi_ipv4_route (valid_nh_count ? ZEBRA_IPV4_ROUTE_ADD: ZEBRA_IPV4_ROUTE_DELETE,
@@ -1431,6 +1492,25 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
         }
       stream_reset (bgp_ifindices_buf);
 
+      /* For labeled unicast, each nexthop has a label too. Resize label
+       * buffer, if required.
+       */
+      if (safi == SAFI_LABELED_UNICAST)
+        {
+          if ((oldsize = stream_get_size (bgp_label_buf)) <
+              (sizeof (unsigned int) * nhcount))
+            {
+              newsize = (sizeof (unsigned int) * nhcount);
+              newsize = stream_resize (bgp_label_buf, newsize);
+              if (newsize == oldsize)
+                {
+                  zlog_err ("can't resize label buffer");
+                  return;
+                }
+            }
+          stream_reset (bgp_label_buf);
+        }
+
       ifindex = 0;
       nexthop = NULL;
 
@@ -1476,6 +1556,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
            }
           stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
           stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
+          if (safi == SAFI_LABELED_UNICAST)
+            {
+              label = label_pton(info->extra->tag);
+              stream_put (bgp_label_buf, &label, sizeof (u_int32_t));
+            }
           valid_nh_count++;
         }
 
@@ -1518,6 +1603,11 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
 
           stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
           stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
+          if (safi == SAFI_LABELED_UNICAST)
+            {
+              label = label_pton(mpinfo->extra->tag);
+              stream_put (bgp_label_buf, &label, sizeof (u_int32_t));
+            }
           valid_nh_count++;
         }
 
@@ -1527,8 +1617,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
       api.type = ZEBRA_ROUTE_BGP;
       api.instance = 0;
       api.message = 0;
-      api.safi = safi;
+      api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi;
       SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      if (safi == SAFI_LABELED_UNICAST)
+        SET_FLAG (api.message, ZAPI_MESSAGE_LABEL);
 
       /* Note that this currently only applies to Null0 routes for aggregates.
        * ZEBRA_FLAG_BLACKHOLE signals zapi_ipv6_route to encode a special
@@ -1544,6 +1636,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
       SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
       api.ifindex_num = valid_nh_count;
       api.ifindex = (ifindex_t *)STREAM_DATA (bgp_ifindices_buf);
+      if (safi == SAFI_LABELED_UNICAST)
+        {
+          api.label_num = valid_nh_count;
+          api.label = (unsigned int *)STREAM_DATA (bgp_label_buf);
+        }
+      else
+        {
+          api.label_num = 0;
+          api.label = NULL;
+        }
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
       api.metric = metric;
       api.tag = 0;
@@ -1566,13 +1668,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
           if (bgp_debug_zebra(p))
             {
               int i;
+              char label_buf[20];
               zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
                          valid_nh_count ? "add" : "delete", bgp->vrf_id,
                          inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
                          p->prefixlen, api.metric, api.tag);
               for (i = 0; i < api.nexthop_num; i++)
-                zlog_debug("  IPv6 [nexthop %d] %s", i+1,
-                           inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
+                {
+                  label_buf[0] = '\0';
+                  if (safi == SAFI_LABELED_UNICAST)
+                    sprintf(label_buf, "label %u", api.label[i]);
+                  zlog_debug("  nhop [%d]: %s if %s %s",
+                             i+1,
+                             inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])),
+                             ifindex2ifname (api.ifindex[i], bgp->vrf_id),
+                             label_buf);
+                }
             }
 
           if (valid_nh_count)
@@ -1588,13 +1699,22 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
           if (bgp_debug_zebra(p))
             {
               int i;
+              char label_buf[20];
               zlog_debug("Tx IPv6 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
                          valid_nh_count ? "add" : "delete", bgp->vrf_id,
                          inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
                          p->prefixlen, api.metric, api.tag);
               for (i = 0; i < api.nexthop_num; i++)
-                zlog_debug("  IPv6 [nexthop %d] %s", i+1,
-                           inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
+                {
+                  label_buf[0] = '\0';
+                  if (safi == SAFI_LABELED_UNICAST)
+                    sprintf(label_buf, "label %u", api.label[i]);
+                  zlog_debug("  nhop [%d]: %s if %s %s",
+                             i+1,
+                             inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])),
+                             ifindex2ifname (api.ifindex[i], bgp->vrf_id),
+                             label_buf);
+                }
             }
 
           zapi_ipv6_route (valid_nh_count ?
@@ -1626,7 +1746,7 @@ bgp_zebra_announce_table (struct bgp *bgp, afi_t afi, safi_t safi)
       if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
           && ri->type == ZEBRA_ROUTE_BGP
           && ri->sub_type == BGP_ROUTE_NORMAL)
-        bgp_zebra_announce (&rn->p, ri, bgp, afi, safi);
+        bgp_zebra_announce (rn, &rn->p, ri, bgp, afi, safi);
 }
 
 void
@@ -1673,10 +1793,14 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
       api.type = ZEBRA_ROUTE_BGP;
       api.instance = 0;
       api.message = 0;
-      api.safi = safi;
+      api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi;
       SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      if (safi == SAFI_LABELED_UNICAST)
+        SET_FLAG (api.message, ZAPI_MESSAGE_LABEL);
       api.nexthop_num = 0;
       api.nexthop = NULL;
+      api.label_num = 0;
+      api.label = NULL;
       api.ifindex_num = 0;
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
       api.metric = info->attr->med;
@@ -1712,11 +1836,14 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
       api.type = ZEBRA_ROUTE_BGP;
       api.instance = 0;
       api.message = 0;
-      api.safi = safi;
+      api.safi = (safi == SAFI_LABELED_UNICAST) ? SAFI_UNICAST : safi;
       SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      if (safi == SAFI_LABELED_UNICAST)
+        SET_FLAG (api.message, ZAPI_MESSAGE_LABEL);
       api.nexthop_num = 0;
       api.nexthop = NULL;
       api.ifindex_num = 0;
+      api.label_num = 0;
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
       api.metric = info->attr->med;
       api.tag = 0;
@@ -2141,9 +2268,11 @@ bgp_zebra_init (struct thread_master *master)
   zclient->redistribute_route_ipv6_del = zebra_read_ipv6;
   zclient->nexthop_update = bgp_read_nexthop_update;
   zclient->import_check_update = bgp_read_import_check_update;
+  zclient->fec_update = bgp_read_fec_update;
 
   bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE);
   bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE);
+  bgp_label_buf = stream_new(BGP_LABEL_BUF_SIZE);
 }
 
 void
index d22a00e8fbed3df2871828b248b7f809a1de6738..bc4e36352d077339e0a26c7b8bd0999396a80282 100644 (file)
@@ -23,9 +23,11 @@ Boston, MA 02111-1307, USA.  */
 
 #define BGP_NEXTHOP_BUF_SIZE (8 * sizeof (struct in_addr *))
 #define BGP_IFINDICES_BUF_SIZE (8 * sizeof (unsigned int))
+#define BGP_LABEL_BUF_SIZE (8 * sizeof (unsigned int))
 
 extern struct stream *bgp_nexthop_buf;
 extern struct stream *bgp_ifindices_buf;
+extern struct stream *bgp_label_buf;
 
 extern void bgp_zebra_init (struct thread_master *master);
 extern void bgp_zebra_destroy (void);
@@ -34,8 +36,8 @@ extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t,
                                      safi_t, int *);
 extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t,
                                   int *);
-extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *,
-                                afi_t, safi_t);
+extern void bgp_zebra_announce (struct bgp_node *, struct prefix *,
+                                struct bgp_info *, struct bgp *, afi_t, safi_t);
 extern void bgp_zebra_announce_table (struct bgp *, afi_t, safi_t);
 extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t);
 
index 9af26f5510065ddebee0d7064dbc7a5d178eece2..955ed2ab5e88ecc22685606167801ac28a39a989 100644 (file)
@@ -1636,6 +1636,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified)
                  PEER_FLAG_REFLECTOR_CLIENT);
       UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST],
                  PEER_FLAG_REFLECTOR_CLIENT);
+      UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_LABELED_UNICAST],
+                  PEER_FLAG_REFLECTOR_CLIENT);
       UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN],
                  PEER_FLAG_REFLECTOR_CLIENT);
       UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_ENCAP],
@@ -1644,6 +1646,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified)
                  PEER_FLAG_REFLECTOR_CLIENT);
       UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST],
                  PEER_FLAG_REFLECTOR_CLIENT);
+      UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_LABELED_UNICAST],
+                  PEER_FLAG_REFLECTOR_CLIENT);
       UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MPLS_VPN],
                  PEER_FLAG_REFLECTOR_CLIENT);
       UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP],
@@ -3611,10 +3615,12 @@ peer_active (struct peer *peer)
     return 0;
   if (peer->afc[AFI_IP][SAFI_UNICAST]
       || peer->afc[AFI_IP][SAFI_MULTICAST]
+      || peer->afc[AFI_IP][SAFI_LABELED_UNICAST]
       || peer->afc[AFI_IP][SAFI_MPLS_VPN]
       || peer->afc[AFI_IP][SAFI_ENCAP]
       || peer->afc[AFI_IP6][SAFI_UNICAST]
       || peer->afc[AFI_IP6][SAFI_MULTICAST]
+      || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]
       || peer->afc[AFI_IP6][SAFI_MPLS_VPN]
       || peer->afc[AFI_IP6][SAFI_ENCAP])
     return 1;
@@ -3627,10 +3633,12 @@ peer_active_nego (struct peer *peer)
 {
   if (peer->afc_nego[AFI_IP][SAFI_UNICAST]
       || peer->afc_nego[AFI_IP][SAFI_MULTICAST]
+      || peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST]
       || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
       || peer->afc_nego[AFI_IP][SAFI_ENCAP]
       || peer->afc_nego[AFI_IP6][SAFI_UNICAST]
       || peer->afc_nego[AFI_IP6][SAFI_MULTICAST]
+      || peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST]
       || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]
       || peer->afc_nego[AFI_IP6][SAFI_ENCAP])
     return 1;
@@ -5024,8 +5032,28 @@ int
 peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi)
 {
   struct peer_group *group;
+  struct peer *tmp_peer;
   struct listnode *node, *nnode;
 
+  /* If this is a peer-group we must first clear the flags for all of the
+   * peer-group members
+   */
+  if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      group = peer->group;
+      for (ALL_LIST_ELEMENTS (group->peer, node, nnode, tmp_peer))
+        {
+          if (CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN) ||
+              CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN))
+            {
+              tmp_peer->allowas_in[afi][safi] = 0;
+              peer_af_flag_unset (tmp_peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
+              peer_af_flag_unset (tmp_peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
+              peer_on_policy_change (tmp_peer, afi, safi, 0);
+            }
+        }
+    }
+
   if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN) ||
       CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN))
     {
@@ -5035,21 +5063,6 @@ peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi)
       peer_on_policy_change (peer, afi, safi, 0);
     }
 
-  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
-    return 0;
-
-  group = peer->group;
-  for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
-    {
-      if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN) ||
-          CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN))
-       {
-         peer->allowas_in[afi][safi] = 0;
-         peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
-         peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
-          peer_on_policy_change (peer, afi, safi, 0);
-       }
-    }
   return 0;
 }
 
@@ -7260,6 +7273,8 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi,
     {
       if (safi == SAFI_UNICAST)
        vty_out (vty, "ipv4 unicast");
+      else if (safi == SAFI_LABELED_UNICAST)
+        vty_out (vty, "ipv4 labeled-unicast");
       else if (safi == SAFI_MULTICAST)
        vty_out (vty, "ipv4 multicast");
       else if (safi == SAFI_MPLS_VPN)
@@ -7271,6 +7286,8 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi,
     {
       if (safi == SAFI_UNICAST)
        vty_out (vty, "ipv6 unicast");
+      else if (safi == SAFI_LABELED_UNICAST)
+        vty_out (vty, "ipv6 labeled-unicast");
       else if (safi == SAFI_MULTICAST)
         vty_out (vty, "ipv6 multicast");
       else if (safi == SAFI_MPLS_VPN)
@@ -7577,6 +7594,9 @@ bgp_config_write (struct vty *vty)
       /* IPv4 multicast configuration.  */
       write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MULTICAST);
 
+      /* IPv4 labeled-unicast configuration.  */
+      write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_LABELED_UNICAST);
+
       /* IPv4 VPN configuration.  */
       write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MPLS_VPN);
 
@@ -7589,6 +7609,9 @@ bgp_config_write (struct vty *vty)
       /* IPv6 multicast configuration.  */
       write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MULTICAST);
 
+      /* IPv6 labeled-unicast configuration.  */
+      write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_LABELED_UNICAST);
+
       /* IPv6 VPN configuration.  */
       write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MPLS_VPN);
 
index b6a8b6f100caf9a07acbd5b815b68dfcfe87d617..60a74a71ef0f3744cb9f09c401f206ce0f4b654b 100644 (file)
@@ -14,9 +14,12 @@ router bgp 7675
 ! bgp router-id 10.0.0.1
 ! network 10.0.0.0/8
 ! neighbor 10.0.0.2 remote-as 7675
-! neighbor 10.0.0.2 route-map set-nexthop out
 ! neighbor 10.0.0.2 ebgp-multihop
-! neighbor 10.0.0.2 next-hop-self
+!
+! address-family ipv4 unicast
+!  neighbor 10.0.0.2 route-map set-nexthop out
+!  neighbor 10.0.0.2 next-hop-self
+! exit-address-family
 !
 ! access-list all permit any
 !
index 863abde3a6dfdac833bc3c503627360c7b1cec08..a8a2dc5fa0a63dc39c3a306a179132b442183ff6 100644 (file)
@@ -19,13 +19,15 @@ router bgp 64512
     neighbor 192.1.1.2 description H192.1.1.2
     neighbor 192.1.1.2 update-source 192.1.1.1
     neighbor 192.1.1.2 advertisement-interval 1
-    no neighbor 192.1.1.2 activate
 
     neighbor 192.1.1.3 remote-as 64512
     neighbor 192.1.1.3 description H192.1.1.3
     neighbor 192.1.1.3 update-source 192.1.1.1
     neighbor 192.1.1.3 advertisement-interval 1
-    no neighbor 192.1.1.3 activate
+
+    address-family ipv4 unicast
+        no neighbor 192.1.1.2 activate
+        no neighbor 192.1.1.3 activate
 
     address-family vpnv4
         neighbor 192.1.1.2 activate
index a72974bc1d6e9c866df009c02a8313df3d34062b..ac09b97580f0a6d4ac36883719f500a977c95bd8 100644 (file)
@@ -76,6 +76,8 @@ enum bgp_af_index
   BGP_AF_IPV4_ENCAP,
   BGP_AF_IPV6_ENCAP,
   BGP_AF_L2VPN_EVPN,
+  BGP_AF_IPV4_LBL_UNICAST,
+  BGP_AF_IPV6_LBL_UNICAST,
   BGP_AF_MAX
 };
 
@@ -971,6 +973,7 @@ struct bgp_nlri
 #define BGP_ATTR_AS_PATHLIMIT                   21
 #define BGP_ATTR_ENCAP                          23
 #define BGP_ATTR_LARGE_COMMUNITIES              32
+#define BGP_ATTR_PREFIX_SID                     40
 #if ENABLE_BGP_VNC
 #define BGP_ATTR_VNC                           255
 #endif
@@ -1394,6 +1397,9 @@ afindex (afi_t afi, safi_t safi)
        case SAFI_MULTICAST:
          return BGP_AF_IPV4_MULTICAST;
          break;
+        case SAFI_LABELED_UNICAST:
+          return BGP_AF_IPV4_LBL_UNICAST;
+          break;
        case SAFI_MPLS_VPN:
          return BGP_AF_IPV4_VPN;
          break;
@@ -1414,7 +1420,10 @@ afindex (afi_t afi, safi_t safi)
        case SAFI_MULTICAST:
          return BGP_AF_IPV6_MULTICAST;
          break;
-       case SAFI_MPLS_VPN:
+        case SAFI_LABELED_UNICAST:
+          return BGP_AF_IPV6_LBL_UNICAST;
+          break;
+        case SAFI_MPLS_VPN:
          return BGP_AF_IPV6_VPN;
          break;
        case SAFI_ENCAP:
@@ -1456,6 +1465,7 @@ peer_afi_active_nego (const struct peer *peer, afi_t afi)
 {
   if (peer->afc_nego[afi][SAFI_UNICAST]
       || peer->afc_nego[afi][SAFI_MULTICAST]
+      || peer->afc_nego[afi][SAFI_LABELED_UNICAST]
       || peer->afc_nego[afi][SAFI_MPLS_VPN]
       || peer->afc_nego[afi][SAFI_ENCAP])
     return 1;
@@ -1470,10 +1480,12 @@ peer_group_af_configured (struct peer_group *group)
 
   if (peer->afc[AFI_IP][SAFI_UNICAST]
       || peer->afc[AFI_IP][SAFI_MULTICAST]
+      || peer->afc[AFI_IP][SAFI_LABELED_UNICAST]
       || peer->afc[AFI_IP][SAFI_MPLS_VPN]
       || peer->afc[AFI_IP][SAFI_ENCAP]
       || peer->afc[AFI_IP6][SAFI_UNICAST]
       || peer->afc[AFI_IP6][SAFI_MULTICAST]
+      || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]
       || peer->afc[AFI_IP6][SAFI_MPLS_VPN]
       || peer->afc[AFI_IP6][SAFI_ENCAP])
     return 1;
index be04b0f09d2d3555222280a04ba33ad4b34a1d2c..c42e57c566e38a7a3139e063881528c157c9e966 100644 (file)
@@ -40,7 +40,7 @@ struct rfapi_monitor_vpn
 #define RFAPI_MON_FLAG_NEEDCALLBACK    0x00000001      /* deferred callback */
 
   //int                                dcount; /* debugging counter */
-  void                         *timer;
+  struct thread                        *timer;
 };
 
 struct rfapi_monitor_encap
@@ -58,7 +58,7 @@ struct rfapi_monitor_eth
   struct rfapi_descriptor      *rfd;   /* which NVE requested the route */
   struct ethaddr               macaddr;
   uint32_t                     logical_net_id;
-  void                         *timer;
+  struct thread                *timer;
 };
 
 /*
index 74331a28d021f6865406fb63fb4a12fe055d5e6c..43a5d43ffaf98167e218e35ed04d0fbf04afe154 100644 (file)
@@ -78,7 +78,7 @@ struct rfapi_info
   struct bgp_tea_options       *tea_options;
   struct rfapi_un_option       *un_options;
   struct rfapi_vn_option       *vn_options;
-  void                         *timer;
+  struct thread                *timer;
 };
 
 /*
index d9bed28c95468b6a51a394b1b19413fbc798bad9..340b0a953ba7cdac033510c83f8ee549b3bb5caa 100755 (executable)
@@ -7,7 +7,7 @@
 ##
 AC_PREREQ(2.60)
 
-AC_INIT(frr, 3.0, [https://github.com/frrouting/frr/issues])
+AC_INIT(frr, 3.1-dev, [https://github.com/frrouting/frr/issues])
 PACKAGE_URL="https://frrouting.org/"
 PACKAGE_FULLNAME="FRRouting"
 AC_SUBST(PACKAGE_FULLNAME)
@@ -73,6 +73,10 @@ LIBS="$LIBS -ltcmalloc_minimal"
 esac],[tcmalloc_enabled=false])
 
 
+dnl Thanks autoconf, but we don't want a default -g -O2.  We have our own
+dnl flag determination logic.
+CFLAGS="${CFLAGS:-}"
+
 dnl --------------------
 dnl Check CC and friends
 dnl --------------------
@@ -85,6 +89,7 @@ AM_PROG_CC_C_O
 dnl remove autoconf default "-g -O2"
 CFLAGS="$orig_cflags"
 AC_PROG_CC_C99
+dnl NB: see C11 below
 
 AC_PROG_EGREP
 PKG_PROG_PKG_CONFIG
@@ -96,7 +101,7 @@ AC_CHECK_PROG([SED],[sed],[sed],[/bin/false])
 dnl try and enable CFLAGS that are useful for Quagga
 dnl - specifically, options to control warnings
 
-AC_USE_SYSTEM_EXTENSIONS()
+AC_USE_SYSTEM_EXTENSIONS
 AC_DEFUN([AC_C_FLAG], [{
        AC_LANG_PUSH(C)
        ac_c_flag_save="$CFLAGS"
@@ -122,6 +127,13 @@ dnl ICC won't bail on unknown options without -diag-error 10006
 dnl need to do this first so we get useful results for the other options
 AC_C_FLAG([-diag-error 10006])
 
+dnl AC_PROG_CC_C99 may change CC to include -std=gnu99 or something
+ac_cc="$CC"
+CC="${CC% -std=gnu99}"
+CC="${CC% -std=c99}"
+
+AC_C_FLAG([-std=gnu11], [CC="$ac_cc"], [CC="$CC -std=gnu11"])
+
 dnl if the user specified any CFLAGS, we don't add "-g -Os/-O2" here
 if test "z$orig_cflags" = "z"; then
   AC_C_FLAG([-g])
@@ -177,6 +189,18 @@ AC_LINK_IFELSE(
        ])
 AC_LANG_POP(C)
 
+dnl ----------
+dnl Essentials
+dnl ----------
+
+AX_PTHREAD([
+  CC="$PTHREAD_CC"
+  CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+  LIBS="$PTHREAD_LIBS $LIBS"
+], [
+  AC_MSG_FAILURE([This Quagga version needs pthreads])
+])
+
 dnl --------------
 dnl Check programs
 dnl --------------
@@ -224,6 +248,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,
@@ -289,6 +315,8 @@ AC_ARG_ENABLE(werror,
   AS_HELP_STRING([--enable-werror], [enable -Werror (recommended for developers only)]))
 AC_ARG_ENABLE(cumulus,
   AS_HELP_STRING([--enable-cumulus], [enable Cumulus Switch Special Extensions]))
+AC_ARG_ENABLE(datacenter,
+  AS_HELP_STRING([--enable-datacenter], [enable Compilation for Data Center Extensions]))
 AC_ARG_ENABLE(rr-semantics,
   AS_HELP_STRING([--disable-rr-semantics], [disable the v6 Route Replace semantics]))
 AC_ARG_ENABLE([protobuf],
@@ -343,11 +371,11 @@ dnl ----------
 AC_MSG_CHECKING(whether this OS has MPLS stack)
 case "$host" in
   *-linux*)
-      MPLS_METHOD="zebra_mpls_netlink.o"
+      MPLS_METHOD="zebra_mpls_netlink.o zebra_mpls.o"
       AC_MSG_RESULT(Linux MPLS)
   ;;
   *-openbsd*)
-      MPLS_METHOD="zebra_mpls_openbsd.o"
+      MPLS_METHOD="zebra_mpls_openbsd.o zebra_mpls.o"
       AC_MSG_RESULT(OpenBSD MPLS)
   ;;
   *)
@@ -357,12 +385,17 @@ case "$host" in
 esac
 AC_SUBST(MPLS_METHOD)
 
-if test "${enable_cumulus}" = "yes" ; then
-  AC_DEFINE(HAVE_CUMULUS,,Compile Special Cumulus Code in)
+if test "${enable_datacenter}" = "yes" ; then
+  AC_DEFINE(HAVE_DATACENTER,,Compile extensions for a DataCenter)
   DFLT_NAME="datacenter"
 else
   DFLT_NAME="traditional"
 fi
+
+if test "${enable_cumulus}" = "yes" ; then
+  AC_DEFINE(HAVE_CUMULUS,,Compile Special Cumulus Code in)
+fi
+
 AC_SUBST(DFLT_NAME)
 AC_DEFINE_UNQUOTED(DFLT_NAME,["$DFLT_NAME"], Name of the configuration default set)
 
@@ -539,6 +572,72 @@ AC_CHECK_HEADERS([stropts.h sys/ksym.h \
        linux/version.h asm/types.h \
        sys/cdefs.h])
 
+ac_stdatomic_ok=false
+AC_DEFINE(FRR_AUTOCONF_ATOMIC, 1, [did autoconf checks for atomic funcs])
+AC_CHECK_HEADER([stdatomic.h],[
+
+  AC_MSG_CHECKING([whether _Atomic qualifier works])
+  AC_LINK_IFELSE([AC_LANG_SOURCE([[
+#include <stdatomic.h>
+int main(int argc, char **argv) {
+  _Atomic int i = 0;
+  return i;
+}
+]])], [
+    AC_DEFINE(HAVE_STDATOMIC_H, 1, [found stdatomic.h])
+    AC_MSG_RESULT([yes])
+    ac_stdatomic_ok=true
+  ], [
+    AC_MSG_RESULT([no])
+  ])
+])
+
+AS_IF([$ac_stdatomic_ok], [true], [
+  AC_MSG_CHECKING([for __atomic_* builtins])
+  AC_LINK_IFELSE([AC_LANG_SOURCE([[
+int main(int argc, char **argv) {
+  volatile int i = 1;
+  __atomic_store_n (&i, 0, __ATOMIC_RELEASE);
+  return __atomic_load_n (&i, __ATOMIC_ACQUIRE);
+}
+]])], [
+    AC_DEFINE(HAVE___ATOMIC, 1, [found __atomic builtins])
+    AC_MSG_RESULT([yes])
+  ], [
+    AC_MSG_RESULT([no])
+
+    dnl FreeBSD 9 has a broken stdatomic.h where _Atomic doesn't work
+    AC_MSG_CHECKING([for __sync_* builtins])
+    AC_LINK_IFELSE([AC_LANG_SOURCE([[
+int main(int argc, char **argv) {
+  volatile int i = 1;
+  __sync_fetch_and_sub (&i, 1);
+  return __sync_val_compare_and_swap (&i, 0, 1);
+}
+]])], [
+      AC_DEFINE(HAVE___SYNC, 1, [found __sync builtins])
+      AC_MSG_RESULT([yes])
+
+      AC_MSG_CHECKING([for __sync_swap builtin])
+      AC_LINK_IFELSE([AC_LANG_SOURCE([[
+int main(int argc, char **argv) {
+  volatile int i = 1;
+  return __sync_swap (&i, 2);
+}
+]])], [
+        AC_DEFINE(HAVE___SYNC_SWAP, 1, [found __sync_swap builtin])
+        AC_MSG_RESULT([yes])
+      ], [
+        AC_MSG_RESULT([no])
+      ])
+
+    ], [
+      AC_MSG_RESULT([no])
+      AC_MSG_FAILURE([stdatomic.h unavailable and $CC has neither __atomic nor __sync builtins])
+    ])
+  ])
+])
+
 dnl Utility macro to avoid retyping includes all the time
 m4_define([FRR_INCLUDES],
 [#ifdef SUNOS_5
@@ -1210,6 +1309,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
@@ -1291,6 +1397,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)
@@ -1403,6 +1510,8 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
 ])
 
 
+AM_CONDITIONAL(SNMP, test "x$SNMP_METHOD" = "xagentx")
+
 dnl ---------------------------
 dnl sockaddr and netinet checks
 dnl ---------------------------
@@ -1502,6 +1611,12 @@ AC_TRY_COMPILE([#include <netinet/in.h>], [
   AC_MSG_RESULT(no)
 ])
 
+dnl --------------------------------------
+dnl checking for be32dec existence or not
+dnl --------------------------------------
+AC_CHECK_DECLS([be32enc, be32dec], [], [],
+              [#include <sys/endian.h>])
+
 dnl --------------------------------------
 dnl checking for clock_time monotonic struct and call
 dnl --------------------------------------
@@ -1731,10 +1846,10 @@ 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
-         cumulus/Makefile
          pkgsrc/Makefile
          fpm/Makefile
          redhat/frr.spec 
@@ -1750,6 +1865,7 @@ AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile
          doc/ospfd.8
          doc/ldpd.8
          doc/ripd.8
+         doc/eigrpd.8
          doc/ripngd.8
          doc/pimd.8
          doc/nhrpd.8
@@ -1758,7 +1874,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/cumulus/.gitignore b/cumulus/.gitignore
deleted file mode 100644 (file)
index 2a198f5..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-*.o
-ssd
diff --git a/cumulus/Makefile.am b/cumulus/Makefile.am
deleted file mode 100644 (file)
index 0278623..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-
-sbin_PROGRAMS = ssd
-EXTRA_DIST = etc/frr/debian.conf etc/frr/daemons etc/default/frr
-
-ssd_SOURCES = start-stop-daemon.c
diff --git a/cumulus/etc/default/frr b/cumulus/etc/default/frr
deleted file mode 100644 (file)
index ae960b9..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-MAX_INSTANCES=5
-MAX_FDS=1024
-ZEBRA_OPTIONS="-s 16777216 -A 127.0.0.1"
-BGPD_OPTIONS="-A 127.0.0.1"
-OSPFD_OPTIONS="-A 127.0.0.1"
-OSPF6D_OPTIONS="-A ::1"
-RIPD_OPTIONS="-A 127.0.0.1"
-RIPNGD_OPTIONS="-A ::1"
-ISISD_OPTIONS="-A 127.0.0.1"
diff --git a/cumulus/etc/frr/Frr.conf b/cumulus/etc/frr/Frr.conf
deleted file mode 100644 (file)
index 2cd05bf..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-log file /var/log/frr/frr.log
-log timestamp precision 6
diff --git a/cumulus/etc/frr/daemons b/cumulus/etc/frr/daemons
deleted file mode 100644 (file)
index 17dfc92..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file tells the frr package which daemons to start.
-#
-# Entries are in the format: <daemon>=(yes|no|priority)
-#   0, "no"  = disabled
-#   1, "yes" = highest priority
-#   2 .. 10  = lower priorities
-# Read /usr/share/doc/frr/README.Debian for details.
-#
-# Sample configurations for these daemons can be found in
-# /usr/share/doc/frr/examples/.
-#
-# ATTENTION:
-#
-# When activation a daemon at the first time, a config file, even if it is
-# empty, has to be present *and* be owned by the user and group "frr", else
-# the daemon will not be started by /etc/init.d/frr. The permissions should
-# be u=rw,g=r,o=.
-# When using "vtysh" such a config file is also needed. It should be owned by
-# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
-#
-# The watchfrr daemon is always started. Per default in monitoring-only but
-# that can be changed via /etc/frr/debian.conf.
-#
-zebra=no
-bgpd=no
-ospfd=no
-ospf6d=no
-ripd=no
-ripngd=no
-isisd=no
-pimd=no
-ldpd=no
-nhrpd=no
diff --git a/cumulus/etc/frr/debian.conf b/cumulus/etc/frr/debian.conf
deleted file mode 100644 (file)
index eed8379..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# If this option is set the /etc/init.d/frr script automatically loads
-# the config via "vtysh -b" when the servers are started.
-# Check /etc/pam.d/frr if you intend to use "vtysh"!
-#
-vtysh_enable=yes
-zebra_options="  -s 90000000 --daemon -A 127.0.0.1"
-bgpd_options="   --daemon -A 127.0.0.1"
-ospfd_options="  --daemon -A 127.0.0.1"
-ospf6d_options=" --daemon -A ::1"
-ripd_options="   --daemon -A 127.0.0.1"
-ripngd_options=" --daemon -A ::1"
-isisd_options="  --daemon -A 127.0.0.1"
-pimd_options="  --daemon -A 127.0.0.1"
-ldpd_options="  --daemon -A 127.0.0.1"
-nhrpd_options="  --daemon -A 127.0.0.1"
-
-# The list of daemons to watch is automatically generated by the init script.
-watchfrr_enable=yes
-watchfrr_options=(-adz -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB -t 30)
diff --git a/cumulus/etc/frr/vtysh.conf b/cumulus/etc/frr/vtysh.conf
deleted file mode 100644 (file)
index 80ceb00..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-service integrated-vtysh-config
-username cumulus nopassword
diff --git a/cumulus/start-stop-daemon.c b/cumulus/start-stop-daemon.c
deleted file mode 100644 (file)
index c123f87..0000000
+++ /dev/null
@@ -1,1063 +0,0 @@
-/*
- * A rewrite of the original Debian's start-stop-daemon Perl script
- * in C (faster - it is executed many times during system startup).
- *
- * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
- * public domain.  Based conceptually on start-stop-daemon.pl, by Ian
- * Jackson <ijackson@gnu.ai.mit.edu>.  May be used and distributed
- * freely for any purpose.  Changes by Christian Schwarz
- * <schwarz@monet.m.isar.de>, to make output conform to the Debian
- * Console Message Standard, also placed in public domain.  Minor
- * changes by Klee Dienes <klee@debian.org>, also placed in the Public
- * Domain.
- *
- * Changes by Ben Collins <bcollins@debian.org>, added --chuid, --background
- * and --make-pidfile options, placed in public domain aswell.
- *
- * Port to OpenBSD by Sontri Tomo Huynh <huynh.29@osu.edu>
- *                 and Andreas Schuldei <andreas@schuldei.org>
- *
- * Changes by Ian Jackson: added --retry (and associated rearrangements).
- *
- * Modified for Gentoo rc-scripts by Donny Davies <woodchip@gentoo.org>:
- *   I removed the BSD/Hurd/OtherOS stuff, added #include <stddef.h>
- *   and stuck in a #define VERSION "1.9.18".  Now it compiles without
- *   the whole automake/config.h dance.
- */
-
-#ifdef HAVE_LXC
-#define _GNU_SOURCE
-#include <sched.h>
-#endif /* HAVE_LXC */
-
-#include <stddef.h>
-#define VERSION "1.9.18"
-
-#define MIN_POLL_INTERVAL 20000 /*us*/
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <sys/time.h>
-#include <sys/queue.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <termios.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <assert.h>
-#include <ctype.h>
-#ifdef linux
-#include <linux/sched.h>
-#endif
-
-static int testmode = 0;
-static int quietmode = 0;
-static int exitnodo = 1;
-static int start = 0;
-static int stop = 0;
-static int background = 0;
-static int mpidfile = 0;
-static int signal_nr = 15;
-static const char *signal_str = NULL;
-static int user_id = -1;
-static int runas_uid = -1;
-static int runas_gid = -1;
-static const char *userspec = NULL;
-static char *changeuser = NULL;
-static const char *changegroup = NULL;
-static char *changeroot = NULL;
-static const char *cmdname = NULL;
-static char *execname = NULL;
-static char *startas = NULL;
-static const char *pidfile = NULL;
-static char what_stop[1024];
-static const char *schedule_str = NULL;
-static const char *progname = "";
-static int nicelevel = 0;
-
-static struct stat exec_stat;
-
-struct pid_list {
-       struct pid_list *next;
-       pid_t pid;
-};
-
-static struct pid_list *found = NULL;
-static struct pid_list *killed = NULL;
-
-struct schedule_item {
-       enum { sched_timeout, sched_signal, sched_goto, sched_forever } type;
-       int value; /* seconds, signal no., or index into array */
-       /* sched_forever is only seen within parse_schedule and callees */
-};
-
-static int schedule_length;
-static struct schedule_item *schedule = NULL;
-
-LIST_HEAD(namespace_head, namespace);
-
-struct namespace {
-       LIST_ENTRY(namespace) list;
-       const char *path;
-       int nstype;
-};
-
-static struct namespace_head namespace_head;
-
-static void *xmalloc(int size);
-static void push(struct pid_list **list, pid_t pid);
-static void do_help(void);
-static void parse_options(int argc, char * const *argv);
-static int pid_is_user(pid_t pid, uid_t uid);
-static int pid_is_cmd(pid_t pid, const char *name);
-static void check(pid_t pid);
-static void do_pidfile(const char *name);
-static void do_stop(int signal_nr, int quietmode,
-                   int *n_killed, int *n_notkilled, int retry_nr);
-static int pid_is_exec(pid_t pid, const struct stat *esb);
-
-#ifdef __GNUC__
-static void fatal(const char *format, ...)
-       __attribute__((noreturn, format(printf, 1, 2)));
-static void badusage(const char *msg)
-       __attribute__((noreturn));
-#else
-static void fatal(const char *format, ...);
-static void badusage(const char *msg);
-#endif
-
-/* This next part serves only to construct the TVCALC macro, which
- * is used for doing arithmetic on struct timeval's.  It works like this:
- *   TVCALC(result, expression);
- * where result is a struct timeval (and must be an lvalue) and
- * expression is the single expression for both components.  In this
- * expression you can use the special values TVELEM, which when fed a
- * const struct timeval* gives you the relevant component, and
- * TVADJUST.  TVADJUST is necessary when subtracting timevals, to make
- * it easier to renormalise.  Whenver you subtract timeval elements,
- * you must make sure that TVADJUST is added to the result of the
- * subtraction (before any resulting multiplication or what have you).
- * TVELEM must be linear in TVADJUST.
- */
-typedef long tvselector(const struct timeval*);
-static long tvselector_sec(const struct timeval *tv) { return tv->tv_sec; }
-static long tvselector_usec(const struct timeval *tv) { return tv->tv_usec; }
-#define TVCALC_ELEM(result, expr, sec, adj)                           \
-{                                                                    \
-  const long TVADJUST = adj;                                         \
-  long (*const TVELEM)(const struct timeval*) = tvselector_##sec;     \
-  (result).tv_##sec = (expr);                                        \
-}
-#define TVCALC(result,expr)                                          \
-do {                                                                 \
-  TVCALC_ELEM(result, expr, sec, (-1));                                      \
-  TVCALC_ELEM(result, expr, usec, (+1000000));                       \
-  (result).tv_sec += (result).tv_usec / 1000000;                     \
-  (result).tv_usec %= 1000000;                                       \
-} while(0)
-
-
-static void
-fatal(const char *format, ...)
-{
-       va_list arglist;
-
-       fprintf(stderr, "%s: ", progname);
-       va_start(arglist, format);
-       vfprintf(stderr, format, arglist);
-       va_end(arglist);
-       putc('\n', stderr);
-       exit(2);
-}
-
-
-static void *
-xmalloc(int size)
-{
-       void *ptr;
-
-       ptr = malloc(size);
-       if (ptr)
-               return ptr;
-       fatal("malloc(%d) failed", size);
-}
-
-static void
-xgettimeofday(struct timeval *tv)
-{
-       if (gettimeofday(tv,0) != 0)
-               fatal("gettimeofday failed: %s", strerror(errno));
-}
-
-static void
-push(struct pid_list **list, pid_t pid)
-{
-       struct pid_list *p;
-
-       p = xmalloc(sizeof(*p));
-       p->next = *list;
-       p->pid = pid;
-       *list = p;
-}
-
-static void
-clear(struct pid_list **list)
-{
-       struct pid_list *here, *next;
-
-       for (here = *list; here != NULL; here = next) {
-               next = here->next;
-               free(here);
-       }
-
-       *list = NULL;
-}
-
-#ifdef linux
-static const char *
-next_dirname(const char *s)
-{
-       const char *cur;
-
-       cur = (const char *)s;
-
-       if (*cur != '\0') {
-               for (; *cur != '/'; ++cur)
-                       if (*cur == '\0')
-                               return cur;
-
-               for (; *cur == '/'; ++cur)
-                       ;
-       }
-
-       return cur;
-}
-
-static void
-add_namespace(const char *path)
-{
-       int nstype;
-       const char *nsdirname, *nsname, *cur;
-       struct namespace *namespace;
-
-       cur = (const char *)path;
-       nsdirname = nsname = "";
-
-       while ((cur = next_dirname(cur))[0] != '\0') {
-               nsdirname = nsname;
-               nsname = cur;
-       }
-
-       if      (!memcmp(nsdirname, "ipcns/", strlen("ipcns/")))
-               nstype = CLONE_NEWIPC;
-       else if (!memcmp(nsdirname, "netns/", strlen("netns/")))
-               nstype = CLONE_NEWNET;
-       else if (!memcmp(nsdirname, "utcns/", strlen("utcns/")))
-               nstype = CLONE_NEWUTS;
-       else
-               badusage("invalid namepspace path");
-
-       namespace = xmalloc(sizeof(*namespace));
-       namespace->path = (const char *)path;
-       namespace->nstype = nstype;
-       LIST_INSERT_HEAD(&namespace_head, namespace, list);
-}
-#endif
-
-#ifdef HAVE_LXC
-static void
-set_namespaces()
-{
-       struct namespace *namespace;
-       int fd;
-
-       LIST_FOREACH(namespace, &namespace_head, list) {
-               if ((fd = open(namespace->path, O_RDONLY)) == -1)
-                       fatal("open namespace %s: %s", namespace->path, strerror(errno));
-               if (setns(fd, namespace->nstype) == -1)
-                       fatal("setns %s: %s", namespace->path, strerror(errno));
-       }
-}
-#else
-static void
-set_namespaces()
-{
-       if (!LIST_EMPTY(&namespace_head))
-               fatal("LCX namespaces not supported");
-}
-#endif
-
-static void
-do_help(void)
-{
-       printf(
-"start-stop-daemon " VERSION " for Debian - small and fast C version written by\n"
-"Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
-"\n"
-"Usage:\n"
-"  start-stop-daemon -S|--start options ... -- arguments ...\n"
-"  start-stop-daemon -K|--stop options ...\n"
-"  start-stop-daemon -H|--help\n"
-"  start-stop-daemon -V|--version\n"
-"\n"
-"Options (at least one of --exec|--pidfile|--user is required):\n"
-"  -x|--exec <executable>        program to start/check if it is running\n"
-"  -p|--pidfile <pid-file>       pid file to check\n"
-"  -c|--chuid <name|uid[:group|gid]>\n"
-"              change to this user/group before starting process\n"
-"  -u|--user <username>|<uid>    stop processes owned by this user\n"
-"  -n|--name <process-name>      stop processes with this name\n"
-"  -s|--signal <signal>          signal to send (default TERM)\n"
-"  -a|--startas <pathname>       program to start (default is <executable>)\n"
-"  -N|--nicelevel <incr>         add incr to the process's nice level\n"
-"  -b|--background               force the process to detach\n"
-"  -m|--make-pidfile             create the pidfile before starting\n"
-"  -R|--retry <schedule>         check whether processes die, and retry\n"
-"  -t|--test                     test mode, don't do anything\n"
-"  -o|--oknodo                   exit status 0 (not 1) if nothing done\n"
-"  -q|--quiet                    be more quiet\n"
-"  -v|--verbose                  be more verbose\n"
-"Retry <schedule> is <item>|/<item>/... where <item> is one of\n"
-" -<signal-num>|[-]<signal-name>  send that signal\n"
-" <timeout>                       wait that many seconds\n"
-" forever                         repeat remainder forever\n"
-"or <schedule> may be just <timeout>, meaning <signal>/<timeout>/KILL/<timeout>\n"
-"\n"
-"Exit status:  0 = done      1 = nothing done (=> 0 if --oknodo)\n"
-"              3 = trouble   2 = with --retry, processes wouldn't die\n");
-}
-
-
-static void
-badusage(const char *msg)
-{
-       if (msg)
-               fprintf(stderr, "%s: %s\n", progname, msg);
-       fprintf(stderr, "Try `%s --help' for more information.\n", progname);
-       exit(3);
-}
-
-struct sigpair {
-       const char *name;
-       int signal;
-};
-
-const struct sigpair siglist[] = {
-       { "ABRT",       SIGABRT },
-       { "ALRM",       SIGALRM },
-       { "FPE",        SIGFPE  },
-       { "HUP",        SIGHUP  },
-       { "ILL",        SIGILL  },
-       { "INT",        SIGINT  },
-       { "KILL",       SIGKILL },
-       { "PIPE",       SIGPIPE },
-       { "QUIT",       SIGQUIT },
-       { "SEGV",       SIGSEGV },
-       { "TERM",       SIGTERM },
-       { "USR1",       SIGUSR1 },
-       { "USR2",       SIGUSR2 },
-       { "CHLD",       SIGCHLD },
-       { "CONT",       SIGCONT },
-       { "STOP",       SIGSTOP },
-       { "TSTP",       SIGTSTP },
-       { "TTIN",       SIGTTIN },
-       { "TTOU",       SIGTTOU }
-};
-
-static int parse_integer (const char *string, int *value_r) {
-       unsigned long ul;
-       char *ep;
-
-       if (!string[0])
-               return -1;
-
-       ul= strtoul(string,&ep,10);
-       if (ul > INT_MAX || *ep != '\0')
-               return -1;
-
-       *value_r= ul;
-       return 0;
-}
-
-static int parse_signal (const char *signal_str, int *signal_nr)
-{
-       unsigned int i;
-
-       if (parse_integer(signal_str, signal_nr) == 0)
-               return 0;
-
-       for (i = 0; i < sizeof (siglist) / sizeof (siglist[0]); i++) {
-               if (strcmp (signal_str, siglist[i].name) == 0) {
-                       *signal_nr = siglist[i].signal;
-                       return 0;
-               }
-       }
-       return -1;
-}
-
-static void
-parse_schedule_item(const char *string, struct schedule_item *item) {
-       const char *after_hyph;
-
-       if (!strcmp(string,"forever")) {
-               item->type = sched_forever;
-       } else if (isdigit(string[0])) {
-               item->type = sched_timeout;
-               if (parse_integer(string, &item->value) != 0)
-                       badusage("invalid timeout value in schedule");
-       } else if ((after_hyph = string + (string[0] == '-')) &&
-                  parse_signal(after_hyph, &item->value) == 0) {
-               item->type = sched_signal;
-       } else {
-               badusage("invalid schedule item (must be [-]<signal-name>, "
-                        "-<signal-number>, <timeout> or `forever'");
-       }
-}
-
-static void
-parse_schedule(const char *schedule_str) {
-       char item_buf[20];
-       const char *slash;
-       int count, repeatat;
-       ptrdiff_t str_len;
-
-       count = 0;
-       for (slash = schedule_str; *slash; slash++)
-               if (*slash == '/')
-                       count++;
-
-       schedule_length = (count == 0) ? 4 : count+1;
-       schedule = xmalloc(sizeof(*schedule) * schedule_length);
-
-       if (count == 0) {
-               schedule[0].type = sched_signal;
-               schedule[0].value = signal_nr;
-               parse_schedule_item(schedule_str, &schedule[1]);
-               if (schedule[1].type != sched_timeout) {
-                       badusage ("--retry takes timeout, or schedule list"
-                                 " of at least two items");
-               }
-               schedule[2].type = sched_signal;
-               schedule[2].value = SIGKILL;
-               schedule[3]= schedule[1];
-       } else {
-               count = 0;
-               repeatat = -1;
-               while (schedule_str != NULL) {
-                       slash = strchr(schedule_str,'/');
-                       str_len = slash ? slash - schedule_str : (ptrdiff_t)strlen(schedule_str);
-                       if (str_len >= (ptrdiff_t)sizeof(item_buf))
-                               badusage("invalid schedule item: far too long"
-                                        " (you must delimit items with slashes)");
-                       memcpy(item_buf, schedule_str, str_len);
-                       item_buf[str_len] = 0;
-                       schedule_str = slash ? slash+1 : NULL;
-
-                       parse_schedule_item(item_buf, &schedule[count]);
-                       if (schedule[count].type == sched_forever) {
-                               if (repeatat >= 0)
-                                       badusage("invalid schedule: `forever'"
-                                                " appears more than once");
-                               repeatat = count;
-                               continue;
-                       }
-                       count++;
-               }
-               if (repeatat >= 0) {
-                       schedule[count].type = sched_goto;
-                       schedule[count].value = repeatat;
-                       count++;
-               }
-               assert(count == schedule_length);
-       }
-}
-
-static void
-parse_options(int argc, char * const *argv)
-{
-       static struct option longopts[] = {
-               { "help",         0, NULL, 'H'},
-               { "stop",         0, NULL, 'K'},
-               { "start",        0, NULL, 'S'},
-               { "version",      0, NULL, 'V'},
-               { "startas",      1, NULL, 'a'},
-               { "name",         1, NULL, 'n'},
-               { "oknodo",       0, NULL, 'o'},
-               { "pidfile",      1, NULL, 'p'},
-               { "quiet",        0, NULL, 'q'},
-               { "signal",       1, NULL, 's'},
-               { "test",         0, NULL, 't'},
-               { "user",         1, NULL, 'u'},
-               { "chroot",       1, NULL, 'r'},
-               { "namespace",    1, NULL, 'd'},
-               { "verbose",      0, NULL, 'v'},
-               { "exec",         1, NULL, 'x'},
-               { "chuid",        1, NULL, 'c'},
-               { "nicelevel",    1, NULL, 'N'},
-               { "background",   0, NULL, 'b'},
-               { "make-pidfile", 0, NULL, 'm'},
-               { "retry",        1, NULL, 'R'},
-               { NULL,         0, NULL, 0}
-       };
-       int c;
-
-       for (;;) {
-               c = getopt_long(argc, argv, "HKSVa:n:op:qr:d:s:tu:vx:c:N:bmR:",
-                               longopts, (int *) 0);
-               if (c == -1)
-                       break;
-               switch (c) {
-               case 'H':  /* --help */
-                       do_help();
-                       exit(0);
-               case 'K':  /* --stop */
-                       stop = 1;
-                       break;
-               case 'S':  /* --start */
-                       start = 1;
-                       break;
-               case 'V':  /* --version */
-                       printf("start-stop-daemon " VERSION "\n");
-                       exit(0);
-               case 'a':  /* --startas <pathname> */
-                       startas = optarg;
-                       break;
-               case 'n':  /* --name <process-name> */
-                       cmdname = optarg;
-                       break;
-               case 'o':  /* --oknodo */
-                       exitnodo = 0;
-                       break;
-               case 'p':  /* --pidfile <pid-file> */
-                       pidfile = optarg;
-                       break;
-               case 'q':  /* --quiet */
-                       quietmode = 1;
-                       break;
-               case 's':  /* --signal <signal> */
-                       signal_str = optarg;
-                       break;
-               case 't':  /* --test */
-                       testmode = 1;
-                       break;
-               case 'u':  /* --user <username>|<uid> */
-                       userspec = optarg;
-                       break;
-               case 'v':  /* --verbose */
-                       quietmode = -1;
-                       break;
-               case 'x':  /* --exec <executable> */
-                       execname = optarg;
-                       break;
-               case 'c':  /* --chuid <username>|<uid> */
-                       /* we copy the string just in case we need the
-                        * argument later. */
-                       changeuser = strdup(optarg);
-                       changeuser = strtok(changeuser, ":");
-                       changegroup = strtok(NULL, ":");
-                       break;
-               case 'r':  /* --chroot /new/root */
-                       changeroot = optarg;
-                       break;
-               case 'd': /* --namespace /.../<ipcns>|<netns>|<utsns>/name */
-#ifdef linux
-                       add_namespace(optarg);
-#endif
-                       break;
-               case 'N':  /* --nice */
-                       nicelevel = atoi(optarg);
-                       break;
-               case 'b':  /* --background */
-                       background = 1;
-                       break;
-               case 'm':  /* --make-pidfile */
-                       mpidfile = 1;
-                       break;
-               case 'R':  /* --retry <schedule>|<timeout> */
-                       schedule_str = optarg;
-                       break;
-               default:
-                       badusage(NULL);  /* message printed by getopt */
-               }
-       }
-
-       if (signal_str != NULL) {
-               if (parse_signal (signal_str, &signal_nr) != 0)
-                       badusage("signal value must be numeric or name"
-                                " of signal (KILL, INTR, ...)");
-       }
-
-       if (schedule_str != NULL) {
-               parse_schedule(schedule_str);
-       }
-
-       if (start == stop)
-               badusage("need one of --start or --stop");
-
-       if (!execname && !pidfile && !userspec && !cmdname)
-               badusage("need at least one of --exec, --pidfile, --user or --name");
-
-       if (!startas)
-               startas = execname;
-
-       if (start && !startas)
-               badusage("--start needs --exec or --startas");
-
-       if (mpidfile && pidfile == NULL)
-               badusage("--make-pidfile is only relevant with --pidfile");
-
-       if (background && !start)
-               badusage("--background is only relevant with --start");
-
-}
-
-static int
-pid_is_exec(pid_t pid, const struct stat *esb)
-{
-       struct stat sb;
-       char buf[32];
-
-       sprintf(buf, "/proc/%d/exe", pid);
-       if (stat(buf, &sb) != 0)
-               return 0;
-       return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
-}
-
-
-static int
-pid_is_user(pid_t pid, uid_t uid)
-{
-       struct stat sb;
-       char buf[32];
-
-       sprintf(buf, "/proc/%d", pid);
-       if (stat(buf, &sb) != 0)
-               return 0;
-       return (sb.st_uid == uid);
-}
-
-
-static int
-pid_is_cmd(pid_t pid, const char *name)
-{
-       char buf[32];
-       FILE *f;
-       int c;
-
-       sprintf(buf, "/proc/%d/stat", pid);
-       f = fopen(buf, "r");
-       if (!f)
-               return 0;
-       while ((c = getc(f)) != EOF && c != '(')
-               ;
-       if (c != '(') {
-               fclose(f);
-               return 0;
-       }
-       /* this hopefully handles command names containing ')' */
-       while ((c = getc(f)) != EOF && c == *name)
-               name++;
-       fclose(f);
-       return (c == ')' && *name == '\0');
-}
-
-
-static void
-check(pid_t pid)
-{
-       if (execname && !pid_is_exec(pid, &exec_stat))
-               return;
-       if (userspec && !pid_is_user(pid, user_id))
-               return;
-       if (cmdname && !pid_is_cmd(pid, cmdname))
-               return;
-       push(&found, pid);
-}
-
-static void
-do_pidfile(const char *name)
-{
-       FILE *f;
-       pid_t pid;
-
-       f = fopen(name, "r");
-       if (f) {
-               if (fscanf(f, "%d", &pid) == 1)
-                       check(pid);
-               fclose(f);
-       } else if (errno != ENOENT)
-               fatal("open pidfile %s: %s", name, strerror(errno));
-
-}
-
-/* WTA: this  needs to be an autoconf check for /proc/pid existance.
- */
-static void
-do_procinit(void)
-{
-       DIR *procdir;
-       struct dirent *entry;
-       int foundany;
-       pid_t pid;
-
-       procdir = opendir("/proc");
-       if (!procdir)
-               fatal("opendir /proc: %s", strerror(errno));
-
-       foundany = 0;
-       while ((entry = readdir(procdir)) != NULL) {
-               if (sscanf(entry->d_name, "%d", &pid) != 1)
-                       continue;
-               foundany++;
-               check(pid);
-       }
-       closedir(procdir);
-       if (!foundany)
-               fatal("nothing in /proc - not mounted?");
-}
-
-static void
-do_findprocs(void)
-{
-       clear(&found);
-       
-       if (pidfile)
-               do_pidfile(pidfile);
-       else
-               do_procinit();
-}
-
-/* return 1 on failure */
-static void
-do_stop(int signal_nr, int quietmode, int *n_killed, int *n_notkilled, int retry_nr)
-{
-       struct pid_list *p;
-
-       do_findprocs();
-       *n_killed = 0;
-       *n_notkilled = 0;
-       if (!found)
-               return;
-       clear(&killed);
-
-       for (p = found; p; p = p->next) {
-               if (testmode)
-                       printf("Would send signal %d to %d.\n",
-                              signal_nr, p->pid);
-               else if (kill(p->pid, signal_nr) == 0) {
-                       push(&killed, p->pid);
-                       (*n_killed)++;
-               } else {
-                       printf("%s: warning: failed to kill %d: %s\n",
-                              progname, p->pid, strerror(errno));
-                       (*n_notkilled)++;
-               }
-       }
-       if (quietmode < 0 && killed) {
-               printf("Stopped %s (pid", what_stop);
-               for (p = killed; p; p = p->next)
-                       printf(" %d", p->pid);
-               putchar(')');
-               if (retry_nr > 0)
-                       printf(", retry #%d", retry_nr);
-               printf(".\n");
-       }
-}
-
-
-static void
-set_what_stop(const char *str)
-{
-       strncpy(what_stop, str, sizeof(what_stop));
-       what_stop[sizeof(what_stop)-1] = '\0';
-}
-
-static int
-run_stop_schedule(void)
-{
-       int r, position, n_killed, n_notkilled, value, ratio, anykilled, retry_nr;
-       struct timeval stopat, before, after, interval, maxinterval;
-
-       if (testmode) {
-               if (schedule != NULL) {
-                       printf("Ignoring --retry in test mode\n");
-                       schedule = NULL;
-               }
-       }
-
-       if (cmdname)
-               set_what_stop(cmdname);
-       else if (execname)
-               set_what_stop(execname);
-       else if (pidfile)
-               sprintf(what_stop, "process in pidfile `%.200s'", pidfile);
-       else if (userspec)
-               sprintf(what_stop, "process(es) owned by `%.200s'", userspec);
-       else
-               fatal("internal error, please report");
-
-       anykilled = 0;
-       retry_nr = 0;
-
-       if (schedule == NULL) {
-               do_stop(signal_nr, quietmode, &n_killed, &n_notkilled, 0);
-               if (n_notkilled > 0 && quietmode <= 0)
-                       printf("%d pids were not killed\n", n_notkilled);
-               if (n_killed)
-                       anykilled = 1;
-               goto x_finished;
-       }
-
-       for (position = 0; position < schedule_length; ) {
-               value= schedule[position].value;
-               n_notkilled = 0;
-
-               switch (schedule[position].type) {
-
-               case sched_goto:
-                       position = value;
-                       continue;
-
-               case sched_signal:
-                       do_stop(value, quietmode, &n_killed, &n_notkilled, retry_nr++);
-                       if (!n_killed)
-                               goto x_finished;
-                       else
-                               anykilled = 1;
-                       goto next_item;
-
-               case sched_timeout:
- /* We want to keep polling for the processes, to see if they've exited,
-  * or until the timeout expires.
-  *
-  * This is a somewhat complicated algorithm to try to ensure that we
-  * notice reasonably quickly when all the processes have exited, but
-  * don't spend too much CPU time polling.  In particular, on a fast
-  * machine with quick-exiting daemons we don't want to delay system
-  * shutdown too much, whereas on a slow one, or where processes are
-  * taking some time to exit, we want to increase the polling
-  * interval.
-  *
-  * The algorithm is as follows: we measure the elapsed time it takes
-  * to do one poll(), and wait a multiple of this time for the next
-  * poll.  However, if that would put us past the end of the timeout
-  * period we wait only as long as the timeout period, but in any case
-  * we always wait at least MIN_POLL_INTERVAL (20ms).  The multiple
-  * (`ratio') starts out as 2, and increases by 1 for each poll to a
-  * maximum of 10; so we use up to between 30% and 10% of the
-  * machine's resources (assuming a few reasonable things about system
-  * performance).
-  */
-                       xgettimeofday(&stopat);
-                       stopat.tv_sec += value;
-                       ratio = 1;
-                       for (;;) {
-                               xgettimeofday(&before);
-                               if (timercmp(&before,&stopat,>))
-                                       goto next_item;
-
-                               do_stop(0, 1, &n_killed, &n_notkilled, 0);
-                               if (!n_killed)
-                                       goto x_finished;
-
-                               xgettimeofday(&after);
-
-                               if (!timercmp(&after,&stopat,<))
-                                       goto next_item;
-
-                               if (ratio < 10)
-                                       ratio++;
-
- TVCALC(interval,    ratio * (TVELEM(&after) - TVELEM(&before) + TVADJUST));
- TVCALC(maxinterval,          TVELEM(&stopat) - TVELEM(&after) + TVADJUST);
-
-                               if (timercmp(&interval,&maxinterval,>))
-                                       interval = maxinterval;
-
-                               if (interval.tv_sec == 0 &&
-                                   interval.tv_usec <= MIN_POLL_INTERVAL)
-                                       interval.tv_usec = MIN_POLL_INTERVAL;
-
-                               r = select(0,0,0,0,&interval);
-                               if (r < 0 && errno != EINTR)
-                                       fatal("select() failed for pause: %s",
-                                             strerror(errno));
-                       }
-
-               default:
-                       assert(!"schedule[].type value must be valid");
-
-               }
-
-       next_item:
-               position++;
-       }
-
-       if (quietmode <= 0)
-               printf("Program %s, %d process(es), refused to die.\n",
-                      what_stop, n_killed);
-
-       return 2;
-
-x_finished:
-       if (!anykilled) {
-               if (quietmode <= 0)
-                       printf("No %s found running; none killed.\n", what_stop);
-               return exitnodo;
-       } else {
-               return 0;
-       }
-}
-
-/*
-int main(int argc, char **argv) NONRETURNING;
-*/
-
-int
-main(int argc, char **argv)
-{
-       progname = argv[0];
-
-       LIST_INIT(&namespace_head);
-
-       parse_options(argc, argv);
-       argc -= optind;
-       argv += optind;
-
-       if (execname && stat(execname, &exec_stat))
-               fatal("stat %s: %s", execname, strerror(errno));
-
-       if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
-               struct passwd *pw;
-
-               pw = getpwnam(userspec);
-               if (!pw)
-                       fatal("user `%s' not found\n", userspec);
-
-               user_id = pw->pw_uid;
-       }
-
-       if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) {
-               struct group *gr = getgrnam(changegroup);
-               if (!gr)
-                       fatal("group `%s' not found\n", changegroup);
-               runas_gid = gr->gr_gid;
-       }
-       if (changeuser && sscanf(changeuser, "%d", &runas_uid) != 1) {
-               struct passwd *pw = getpwnam(changeuser);
-               if (!pw)
-                       fatal("user `%s' not found\n", changeuser);
-               runas_uid = pw->pw_uid;
-               if (changegroup == NULL) { /* pass the default group of this user */
-                       changegroup = ""; /* just empty */
-                       runas_gid = pw->pw_gid;
-               }
-       }
-
-       if (stop) {
-               int i = run_stop_schedule();
-               exit(i);
-       }
-
-       do_findprocs();
-
-       if (found) {
-               if (quietmode <= 0)
-                       printf("%s already running.\n", execname);
-               exit(exitnodo);
-       }
-       if (testmode) {
-               printf("Would start %s ", startas);
-               while (argc-- > 0)
-                       printf("%s ", *argv++);
-               if (changeuser != NULL) {
-                       printf(" (as user %s[%d]", changeuser, runas_uid);
-                       if (changegroup != NULL)
-                               printf(", and group %s[%d])", changegroup, runas_gid);
-                       else
-                               printf(")");
-               }
-               if (changeroot != NULL)
-                       printf(" in directory %s", changeroot);
-               if (nicelevel)
-                       printf(", and add %i to the priority", nicelevel);
-               printf(".\n");
-               exit(0);
-       }
-       if (quietmode < 0)
-               printf("Starting %s...\n", startas);
-       *--argv = startas;
-       if (changeroot != NULL) {
-               if (chdir(changeroot) < 0)
-                       fatal("Unable to chdir() to %s", changeroot);
-               if (chroot(changeroot) < 0)
-                       fatal("Unable to chroot() to %s", changeroot);
-       }
-       if (changeuser != NULL) {
-               if (setgid(runas_gid))
-                       fatal("Unable to set gid to %d", runas_gid);
-               if (initgroups(changeuser, runas_gid))
-                       fatal("Unable to set initgroups() with gid %d", runas_gid);
-               if (setuid(runas_uid))
-                       fatal("Unable to set uid to %s", changeuser);
-       }
-
-       if (background) { /* ok, we need to detach this process */
-               int i, fd;
-               if (quietmode < 0)
-                       printf("Detatching to start %s...", startas);
-               i = fork();
-               if (i<0) {
-                       fatal("Unable to fork.\n");
-               }
-               if (i) { /* parent */
-                       if (quietmode < 0)
-                               printf("done.\n");
-                       exit(0);
-               }
-                /* child continues here */
-                /* now close all extra fds */
-               for (i=getdtablesize()-1; i>=0; --i) close(i);
-                /* change tty */
-               fd = open("/dev/tty", O_RDWR);
-               ioctl(fd, TIOCNOTTY, 0);
-               close(fd);
-               chdir("/");
-               umask(022); /* set a default for dumb programs */
-               setpgid(0,0);  /* set the process group */
-               fd=open("/dev/null", O_RDWR); /* stdin */
-               dup(fd); /* stdout */
-               dup(fd); /* stderr */
-       }
-       if (nicelevel) {
-               errno = 0;
-               if (nice(nicelevel) < 0 && errno)
-                       fatal("Unable to alter nice level by %i: %s", nicelevel,
-                               strerror(errno));
-       }
-       if (mpidfile && pidfile != NULL) { /* user wants _us_ to make the pidfile :) */
-               FILE *pidf = fopen(pidfile, "w");
-               pid_t pidt = getpid();
-               if (pidf == NULL)
-                       fatal("Unable to open pidfile `%s' for writing: %s", pidfile,
-                               strerror(errno));
-               fprintf(pidf, "%d\n", pidt);
-               fclose(pidf);
-       }
-       set_namespaces();
-       execv(startas, argv);
-       fatal("Unable to start %s: %s", startas, strerror(errno));
-}
index 4cf35d7e325aefd91291159f4d8281fc4e9831fa..1b048033667d48a42884784873cfc5d995b6cf11 100644 (file)
@@ -83,7 +83,7 @@ into the kernel.
 =====================================================================
 
 If this message occurs the receive buffer should be increased by adding the
-following to /etc/sysctl.conf and "--nl-bufsize" to /etc/frr/debian.conf.
+following to /etc/sysctl.conf and "--nl-bufsize" to /etc/frr/daemons.conf.
 > net.core.rmem_default = 262144
 > net.core.rmem_max = 262144
 See message #4525 from 2005-05-09 in the quagga-users mailing list.
index aa8ac0cf35504be4c3e3d7242394be9a6ac47c91..84b68e1949800654d53331e715197a80b91d9072 100644 (file)
@@ -11,7 +11,7 @@ Files that keep their names
        /usr/bin/vtysh
 
 Files that got an -pj suffix
-       /etc/default/zebra      -> /etc/frr/debian.conf
+       /etc/default/zebra      -> /etc/frr/daemons.conf
        /etc/init.d/zebra       -> /etc/init.d/frr
        /etc/zebra/             -> /etc/frr/
        /usr/share/doc/zebra/   -> /usr/share/doc/frr/
index fe4ee6b33445e038939f84305db5b0fbbb5123df..4ea86929fcbdcaacc005e37ede4e41da8bf9eb6b 100644 (file)
@@ -1,3 +1,9 @@
+frr (3.1-dev) Released; urgency=medium
+
+  * New Enabled: PIM draft Unnumbered
+
+ -- frr <frog@lists.frrouting.org> Wed, 5 Apr 2017 22:29:42 -0500
+
 frr (3.0) Released; urgency=medium
 
   * New Enabled: BGP Shutdown Message
index 4ecbefc6d63228224b7539b6d906f61a35394953..3982aa41be91f4406d400a9c081b7bf61affdfa1 100644 (file)
@@ -12,7 +12,7 @@ Package: frr
 Architecture: any
 Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), iproute, ${misc:Depends}, libc-ares2
 Pre-Depends: adduser
-Conflicts: zebra, zebra-pj
+Conflicts: zebra, zebra-pj, quagga
 Replaces: zebra, zebra-pj
 Suggests: snmpd
 Description: BGP/OSPF/RIP routing daemon
index 58290080d00d9e510983ee466d8db3d636406a6d..56699b2daa261c39d5e82d9f840beee7f7df4b6e 100644 (file)
@@ -1,5 +1,6 @@
 etc/logrotate.d/
 etc/frr/
+etc/iproute2/rt_protos.d/
 usr/share/doc/frr/
 usr/share/doc/frr/examples/
 usr/share/lintian/overrides/
index 45b3b973be4945b5c8e3a74cf28b736d697f09c5..49aeb395bb3998f8b5ca981816c0041c7415da2d 100644 (file)
@@ -17,6 +17,6 @@ usr/share/man/man8/zebra.8
 usr/share/man/man8/isisd.8
 usr/share/man/man8/watchfrr.8
 usr/share/snmp/mibs/
-cumulus/etc/* etc/
+tools/etc/* etc/
 tools/*.service    lib/systemd/system
 debian/frr.conf  usr/lib/tmpfiles.d
index 57e35f3ce6c4ba69b50f7315ba48e2e7619cfb94..4a5cc8252a66af1c25570b9575db60f9e0faa43c 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "config.h"
 
-#ifdef HAVE_CUMULUS
+#ifdef HAVE_DATACENTER
 
 #define DFLT_BGP_IMPORT_CHECK                  1
 #define DFLT_BGP_TIMERS_CONNECT                        10
@@ -36,7 +36,7 @@
 #define DFLT_OSPF_LOG_ADJACENCY_CHANGES                1
 #define DFLT_OSPF6_LOG_ADJACENCY_CHANGES       1
 
-#else /* !HAVE_CUMULUS */
+#else /* !HAVE_DATACENTER */
 
 #define DFLT_BGP_IMPORT_CHECK                  0
 #define DFLT_BGP_TIMERS_CONNECT                        120
@@ -49,6 +49,6 @@
 #define DFLT_OSPF_LOG_ADJACENCY_CHANGES                0
 #define DFLT_OSPF6_LOG_ADJACENCY_CHANGES       0
 
-#endif /* !HAVE_CUMULUS */
+#endif /* !HAVE_DATACENTER */
 
 #endif /* _FRR_DEFAULTS_H */
index 521f0a0c2bb8c5cf40b8e96a6d746acca5c8e868..033e05bcdb9764ebf8f292123e0823877ac80fd0 100644 (file)
@@ -136,7 +136,7 @@ other settings)
 
     sudo install -m 755 tools/frr /etc/init.d/frr  
     sudo install -m 644 cumulus/etc/frr/daemons /etc/frr/daemons    
-    sudo install -m 644 cumulus/etc/frr/debian.conf /etc/frr/debian.conf    
+    sudo install -m 644 cumulus/etc/frr/daemons.conf /etc/frr/daemons.conf    
     sudo install -m 644 -o frr -g frr cumulus/etc/frr/vtysh.conf /etc/frr/vtysh.conf 
     
 ### Enable daemons 
index 2c5f132ad7f62cbff9db9736a7433929cc1021f1..11daecf19504d2e0fadd039e4df1740b71a03b25 100644 (file)
@@ -96,7 +96,7 @@ other settings)
 
     sudo install -m 755 tools/frr /etc/init.d/frr  
     sudo install -m 644 cumulus/etc/frr/daemons /etc/frr/daemons    
-    sudo install -m 644 cumulus/etc/frr/debian.conf /etc/frr/debian.conf    
+    sudo install -m 644 cumulus/etc/frr/daemons.conf /etc/frr/daemons.conf    
     sudo install -m 644 -o frr -g frr cumulus/etc/frr/vtysh.conf /etc/frr/vtysh.conf   
  
  
index 5715b701587bbaf0c8ff8c75d7e78fed983e32bd..09b5aa8b72cbf9bec8417accf46e296446f3a8c5 100644 (file)
@@ -119,7 +119,7 @@ Add the following lines to `/etc/modules-load.d/modules.conf`:
     sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service  
     sudo install -m 644 cumulus/etc/default/frr /etc/default/frr  
     sudo install -m 644 cumulus/etc/frr/daemons /etc/frr/daemons  
-    sudo install -m 644 cumulus/etc/frr/debian.conf /etc/frr/debian.conf  
+    sudo install -m 644 cumulus/etc/frr/daemons.conf /etc/frr/daemons.conf  
     sudo install -m 644 cumulus/etc/frr/Frr.conf /etc/frr/Frr.conf  
     sudo install -m 644 -o frr -g frr cumulus/etc/frr/vtysh.conf /etc/frr/vtysh.conf   
 
index d82a3073042aaf6add2497ab2118c4e467139832..318179e2552e828f24c23f4cfcabbf0849389777 100644 (file)
@@ -61,6 +61,7 @@ frr_TEXINFOS = appendix.texi basic.texi bgpd.texi isisd.texi filter.texi \
        vnc.texi \
        install.texi ipv6.texi kernel.texi main.texi \
        nhrpd.texi \
+       eigrpd.texi \
        ospf6d.texi ospfd.texi \
        overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \
        snmp.texi vtysh.texi routeserver.texi defines.texi $(figures_png) \
@@ -129,6 +130,10 @@ if ZEBRA
 man_MANS += zebra.8
 endif
 
+if EIGRPD
+man_MANS += eigrpd.8
+endif
+
 EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \
        \
        bgpd.8.in \
@@ -145,6 +150,7 @@ EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \
        watchfrr.8.in \
        zebra.8.in \
        frr.1.in \
+       eigrpd.8.in \
        \
        mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \
        mpls/opaque_lsa.txt mpls/ospfd.conf \
index 08cd4149a4d1d9757af5519c6797e20833762018..8e0da129493bd1d007fd3728aa8c9d423e756996 100644 (file)
@@ -526,7 +526,9 @@ This command adds the announcement network.
 @example
 @group
 router bgp 1
- network 10.0.0.0/8
+ address-family ipv4 unicast
+  network 10.0.0.0/8
+ exit-address-family
 @end group
 @end example
 This configuration example says that network 10.0.0.0/8 will be
@@ -1160,7 +1162,9 @@ communities attribute to the updates.
 @example
 router bgp 7675
  neighbor 192.168.0.1 remote-as 100
- neighbor 192.168.0.1 route-map RMAP in
+ address-family ipv4 unicast
+  neighbor 192.168.0.1 route-map RMAP in
+ exit-address-family
 !
 ip community-list 70 permit 7675:70
 ip community-list 70 deny
@@ -1191,7 +1195,9 @@ value 80.
 router bgp 100
  network 10.0.0.0/8
  neighbor 192.168.0.2 remote-as 7675
- neighbor 192.168.0.2 route-map RMAP out
+ address-family ipv4 unicast
+  neighbor 192.168.0.2 route-map RMAP out
+ exit-address-family
 !
 ip prefix-list PLIST permit 10.0.0.0/8
 !
@@ -1209,7 +1215,9 @@ limit the BGP routes announcement into the internal network.
 @example
 router bgp 7675
  neighbor 192.168.0.1 remote-as 100
- neighbor 192.168.0.1 route-map RMAP in
+ address-family ipv4 unicast
+  neighbor 192.168.0.1 route-map RMAP in
+ exit-address-family
 !
 ip community-list 1 permit 0:80 0:90
 !
@@ -1224,7 +1232,9 @@ filtering all of routes, we need to define permit any at last.
 @example
 router bgp 7675
  neighbor 192.168.0.1 remote-as 100
- neighbor 192.168.0.1 route-map RMAP in
+ address-family ipv4 unicast
+  neighbor 192.168.0.1 route-map RMAP in
+ exit-address-family
 !
 ip community-list standard FILTER deny 1:1
 ip community-list standard FILTER permit
@@ -1252,7 +1262,9 @@ community-list is used.  @code{deny} community-list is ignored.
 @example
 router bgp 7675
  neighbor 192.168.0.1 remote-as 100
- neighbor 192.168.0.1 route-map RMAP in
+ address-family ipv4 unicast
+  neighbor 192.168.0.1 route-map RMAP in
+ exit-address-family
 !
 ip community-list standard DEL permit 100:1 100:2
 !
@@ -1606,11 +1618,15 @@ to specify @command{neighbor A.B.C.D send-community} command.
 !
 router bgp 1
  neighbor 10.0.0.1 remote-as 1
- no neighbor 10.0.0.1 send-community
+ address-family ipv4 unicast
+  no neighbor 10.0.0.1 send-community
+ exit-address-family
 !
 router bgp 1
  neighbor 10.0.0.1 remote-as 1
- neighbor 10.0.0.1 send-community
+ address-family ipv4 unicast
+  neighbor 10.0.0.1 send-community
+ exit-address-family
 !
 @end example
 
@@ -1680,11 +1696,15 @@ bgp multiple-instance
 !
 router bgp 1 view 1
  neighbor 10.0.0.1 remote-as 2
- neighbor 10.0.0.1 distribute-list 1 in
+ address-family ipv4 unicast
+  neighbor 10.0.0.1 distribute-list 1 in
+ exit-address-family
 !
 router bgp 1 view 2
  neighbor 10.0.0.1 remote-as 2
- neighbor 10.0.0.1 distribute-list 2 in
+ address-family ipv4 unicast
+  neighbor 10.0.0.1 distribute-list 2 in
+ exit-address-family
 @end group
 @end example
 
@@ -1792,13 +1812,16 @@ Example of a session to an upstream, advertising only one prefix to it.
 @example
 router bgp 64512
  bgp router-id 10.236.87.1
- network 10.236.87.0/24
  neighbor upstream peer-group
  neighbor upstream remote-as 64515
  neighbor upstream capability dynamic
- neighbor upstream prefix-list pl-allowed-adv out
  neighbor 10.1.1.1 peer-group upstream
  neighbor 10.1.1.1 description ACME ISP
+
+ address-family ipv4 unicast
+  network 10.236.87.0/24
+  neighbor upstream prefix-list pl-allowed-adv out
+ exit-address-family
 !
 ip prefix-list pl-allowed-adv seq 5 permit 82.195.133.0/25
 ip prefix-list pl-allowed-adv seq 10 deny any
@@ -1816,18 +1839,9 @@ flaws.
 @example
 router bgp 64512
  bgp router-id 10.236.87.1
- network 10.123.456.0/24
- network 10.123.456.128/25 route-map rm-no-export
  neighbor upstream capability dynamic
- neighbor upstream route-map rm-upstream-out out
  neighbor cust capability dynamic
- neighbor cust route-map rm-cust-in in
- neighbor cust route-map rm-cust-out out
- neighbor cust send-community both
  neighbor peer capability dynamic
- neighbor peer route-map rm-peer-in in
- neighbor peer route-map rm-peer-out out
- neighbor peer send-community both
  neighbor 10.1.1.1 remote-as 64515
  neighbor 10.1.1.1 peer-group upstream
  neighbor 10.2.1.1 remote-as 64516
@@ -1835,19 +1849,31 @@ router bgp 64512
  neighbor 10.3.1.1 remote-as 64517
  neighbor 10.3.1.1 peer-group cust-default
  neighbor 10.3.1.1 description customer1
- neighbor 10.3.1.1 prefix-list pl-cust1-network in
  neighbor 10.4.1.1 remote-as 64518
  neighbor 10.4.1.1 peer-group cust
- neighbor 10.4.1.1 prefix-list pl-cust2-network in
  neighbor 10.4.1.1 description customer2
  neighbor 10.5.1.1 remote-as 64519
  neighbor 10.5.1.1 peer-group peer
- neighbor 10.5.1.1 prefix-list pl-peer1-network in
  neighbor 10.5.1.1 description peer AS 1
  neighbor 10.6.1.1 remote-as 64520
  neighbor 10.6.1.1 peer-group peer
- neighbor 10.6.1.1 prefix-list pl-peer2-network in
  neighbor 10.6.1.1 description peer AS 2
+
+ address-family ipv4 unicast
+  network 10.123.456.0/24
+  network 10.123.456.128/25 route-map rm-no-export
+  neighbor upstream route-map rm-upstream-out out
+  neighbor cust route-map rm-cust-in in
+  neighbor cust route-map rm-cust-out out
+  neighbor cust send-community both
+  neighbor peer route-map rm-peer-in in
+  neighbor peer route-map rm-peer-out out
+  neighbor peer send-community both
+  neighbor 10.3.1.1 prefix-list pl-cust1-network in
+  neighbor 10.4.1.1 prefix-list pl-cust2-network in
+  neighbor 10.5.1.1 prefix-list pl-peer1-network in
+  neighbor 10.6.1.1 prefix-list pl-peer2-network in
+ exit-address-family
 !
 ip prefix-list pl-default permit 0.0.0.0/0
 !
diff --git a/doc/eigrpd.8.in b/doc/eigrpd.8.in
new file mode 100644 (file)
index 0000000..ecac972
--- /dev/null
@@ -0,0 +1,122 @@
+.TH EIGRPD 8 "6 May 2017" "@PACKAGE_FULLNAME@ EIGRP daemon" "Version @PACKAGE_VERSION@"
+.SH NAME
+eigrpd \- a EIGRP routing engine for use with @PACKAGE_FULLNAME@.
+.SH SYNOPSIS
+.B eigrpd
+[
+.B \-dhrv
+] [
+.B \-f
+.I config-file
+] [
+.B \-i
+.I pid-file
+] [
+.B \-P
+.I port-number
+] [
+.B \-A
+.I vty-address
+] [
+.B \-u
+.I user
+] [
+.B \-g
+.I group
+] [
+.B \-M
+.I module:options
+]
+.SH DESCRIPTION
+.B eigrpd
+is a routing component that works with the
+.B @PACKAGE_FULLNAME@
+routing engine.
+.SH OPTIONS
+Options available for the
+.B eigrpd
+command:
+.SH OPTIONS
+.TP
+\fB\-d\fR, \fB\-\-daemon\fR
+Runs in daemon mode, forking and exiting from tty.
+.TP
+\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR
+Specifies the config file to use for startup. If not specified this
+option will default to \fB\fI@CFG_SYSCONF@/eigrpd.conf\fR.
+.TP
+\fB\-g\fR, \fB\-\-group \fR\fIgroup\fR
+Specify the group to run as. Default is \fI@enable_group@\fR.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+A brief message.
+.TP
+\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR
+When eigrpd starts its process identifier is written to
+\fB\fIpid-file\fR.  The init system uses the recorded PID to stop or
+restart eigrpd.  The default is \fB\fI@CFG_STATE@/eigrpd.pid\fR.
+.TP
+\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR 
+Specify the port that the eigrpd VTY will listen on. This defaults to
+2602, as specified in \fB\fI/etc/services\fR.
+.TP
+\fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR
+Specify the address that the eigrpd VTY will listen on. Default is all
+interfaces.
+.TP
+\fB\-u\fR, \fB\-\-user \fR\fIuser\fR
+Specify the user to run as. Default is \fI@enable_user@\fR.
+.TP
+\fB\-r\fR, \fB\-\-retain\fR 
+When the program terminates, retain routes added by \fBeigrpd\fR.
+.TP
+\fB\-M\fR, \fB\-\-module \fR\fImodule:options\fR
+Load a module at startup.  May be specified more than once.
+The \fBsnmp\fR module may be available for
+\fBeigrpd\fR, if the package was built with SNMP support.
+.TP
+\fB\-v\fR, \fB\-\-version\fR
+Print the version and exit.
+.SH FILES
+.TP
+.BI @CFG_SBIN@/eigrpd
+The default location of the 
+.B eigrpd
+binary.
+.TP
+.BI @CFG_SYSCONF@/eigrpd.conf
+The default location of the 
+.B eigrpd
+config file.
+.TP
+.BI $(PWD)/eigrpd.log 
+If the 
+.B eigrpd
+process is config'd to output logs to a file, then you will find this
+file in the directory where you started \fBeigrpd\fR.
+.SH WARNING
+This man page is intended to be a quick reference for command line
+options. The definitive document is the Info file \fB@PACKAGE_NAME@\fR.
+.SH DIAGNOSTICS
+The eigrpd process may log to standard output, to a VTY, to a log
+file, or through syslog to the system logs. \fBeigrpd\fR supports many
+debugging options, see the Info file, or the source for details.
+.SH "SEE ALSO"
+.BR bgpd (8),
+.BR ripd (8),
+.BR ripngd (8),
+.BR ospfd (8),
+.BR ospf6d (8),
+.BR isisd (8),
+.BR zebra (8),
+.BR vtysh (1)
+.SH BUGS
+.B eigrpd
+eats bugs for breakfast. If you have food for the maintainers try
+.BI @PACKAGE_BUGREPORT@
+.SH AUTHORS
+See
+.BI http://www.zebra.org
+and
+.BI @PACKAGE_URL@
+or the Info file for an accurate list of authors.
diff --git a/doc/eigrpd.texi b/doc/eigrpd.texi
new file mode 100644 (file)
index 0000000..a3a82bb
--- /dev/null
@@ -0,0 +1,216 @@
+@c -*-texinfo-*-
+@c This is part of the Frr Manual.
+@c @value{COPYRIGHT_STR}
+@c See file frr.texi for copying conditions.
+@node EIGRP
+@chapter EIGRP
+
+EIGRP -- Routing Information Protocol is widely deployed interior gateway
+routing protocol.  EIGRP was developed in the 1990's.  EIGRP is a
+@dfn{distance-vector} protocol and is based on the @dfn{dual} algorithms.
+As a distance-vector protocol, the EIGRP router send updates to its
+neighbors as networks change, thus allowing the convergence to a
+known topology.
+
+@command{eigrpd} supports EIGRP as described in RFC7868
+
+@menu
+* Starting and Stopping eigrpd::
+* EIGRP Configuration::
+* How to Announce EIGRP routes::
+* Show EIGRP Information::
+* EIGRP Debug Commands::
+@end menu
+
+@node Starting and Stopping eigrpd
+@section Starting and Stopping eigrpd
+
+The default configuration file name of @command{eigrpd}'s is
+@file{eigrpd.conf}.  When invocation @command{eigrpd} searches directory
+@value{INSTALL_PREFIX_ETC}.  If @file{eigrpd.conf} is not there next
+search current directory.  If an integrated config is specified
+configuration is written into frr.conf
+
+The EIGRP protocol requires interface information
+maintained by @command{zebra} daemon.  So running @command{zebra}
+is mandatory to run @command{eigrpd}.  Thus minimum sequence for running
+EIGRP is like below:
+
+@example
+@group
+# zebra -d
+# eigrpd -d
+@end group
+@end example
+
+Please note that @command{zebra} must be invoked before @command{eigrpd}.
+
+To stop @command{eigrpd}.  Please use @command{kill `cat
+/var/run/eigrpd.pid`}.  Certain signals have special meanings to @command{eigrpd}.
+
+@table @samp
+@item SIGHUP
+@item SIGUSR1
+Rotate @command{eigrpd} Rotate the logfile.
+@item SIGINT
+@itemx SIGTERM
+@command{eigrpd} sweeps all installed EIGRP routes then terminates properly.
+@end table
+
+@command{eigrpd} invocation options.  Common options that can be specified
+(@pxref{Common Invocation Options}).
+
+@table @samp
+@item -r
+@itemx --retain
+When the program terminates, retain routes added by @command{eigrpd}.
+@end table
+
+@node EIGRP Configuration
+@section EIGRP Configuration
+
+@deffn Command {router eigrp (1-65535)} {}
+The @code{router eigrp} command is necessary to enable EIGRP.  To disable
+EIGRP, use the @code{no router eigrp (1-65535)} command.  EIGRP must be enabled before carrying out any of the EIGRP commands.
+@end deffn
+
+@deffn Command {no router eigrp (1-65535)} {}
+Disable EIGRP.
+@end deffn
+
+@deffn {EIGRP Command} {network @var{network}} {}
+@deffnx {EIGRP Command} {no network @var{network}} {}
+Set the EIGRP enable interface by @var{network}.  The interfaces which
+have addresses matching with @var{network} are enabled.
+
+This group of commands either enables or disables EIGRP interfaces between
+certain numbers of a specified network address.  For example, if the
+network for 10.0.0.0/24 is EIGRP enabled, this would result in all the
+addresses from 10.0.0.0 to 10.0.0.255 being enabled for EIGRP.  The @code{no
+network} command will disable EIGRP for the specified network.
+@end deffn
+
+Below is very simple EIGRP configuration.  Interface @code{eth0} and
+interface which address match to @code{10.0.0.0/8} are EIGRP enabled.
+
+@example
+@group
+!
+router eigrp 1
+ network 10.0.0.0/8
+!
+@end group
+@end example
+
+Passive interface
+
+@deffn {EIGRP command} {passive-interface (@var{IFNAME}|default)} {}
+@deffnx {EIGRP command} {no passive-interface @var{IFNAME}} {}
+This command sets the specified interface to passive mode.  On passive mode
+interface, all receiving packets are ignored and eigrpd does
+not send either multicast or unicast EIGRP packets except to EIGRP neighbors
+specified with @code{neighbor} command. The interface may be specified
+as @var{default} to make eigrpd default to passive on all interfaces. 
+
+The default is to be passive on all interfaces.
+@end deffn
+
+@node How to Announce EIGRP route
+@section How to Announce EIGRP route
+
+@deffn {EIGRP command} {redistribute kernel} {}
+@deffnx {EIGRP command} {redistribute kernel metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)} {}
+@deffnx {EIGRP command} {no redistribute kernel} {}
+@code{redistribute kernel} redistributes routing information from
+kernel route entries into the EIGRP tables. @code{no redistribute kernel}
+disables the routes.
+@end deffn
+
+@deffn {EIGRP command} {redistribute static} {}
+@deffnx {EIGRP command} {redistribute static metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)} {}
+@deffnx {EIGRP command} {no redistribute static} {}
+@code{redistribute static} redistributes routing information from
+static route entries into the EIGRP tables. @code{no redistribute static}
+disables the routes.
+@end deffn
+
+@deffn {EIGRP command} {redistribute connected} {}
+@deffnx {EIGRP command} {redistribute connected metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)} {}
+@deffnx {EIGRP command} {no redistribute connected} {}
+Redistribute connected routes into the EIGRP tables.  @code{no
+redistribute connected} disables the connected routes in the EIGRP tables.
+This command redistribute connected of the interface which EIGRP disabled.
+The connected route on EIGRP enabled interface is announced by default.
+@end deffn
+
+@deffn {EIGRP command} {redistribute ospf} {}
+@deffnx {EIGRP command} {redistribute ospf metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)} {}
+@deffnx {EIGRP command} {no redistribute ospf} {}
+@code{redistribute ospf} redistributes routing information from
+ospf route entries into the EIGRP tables. @code{no redistribute ospf}
+disables the routes.
+@end deffn
+
+@deffn {EIGRP command} {redistribute bgp} {}
+@deffnx {EIGRP command} {redistribute bgp metric  (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)} {}
+@deffnx {EIGRP command} {no redistribute bgp} {}
+@code{redistribute bgp} redistributes routing information from
+bgp route entries into the EIGRP tables. @code{no redistribute bgp}
+disables the routes.
+@end deffn
+
+@node Show EIGRP Information
+@section Show EIGRP Information
+
+To display EIGRP routes.
+
+@deffn Command {show ip eigrp topology} {}
+Show EIGRP routes.
+@end deffn
+
+The command displays all EIGRP routes.
+
+@c Exmaple here.
+
+@deffn Command {show ip eigrp topology} {}
+The command displays current EIGRP status
+@end deffn
+
+@example
+@group
+eigrpd> @b{show ip eigrp topology}
+# show ip eigrp topo
+
+EIGRP Topology Table for AS(4)/ID(0.0.0.0)
+
+Codes: P - Passive, A - Active, U - Update, Q - Query, R - Reply
+       r - reply Status, s - sia Status
+
+P  10.0.2.0/24, 1 successors, FD is 256256, serno: 0 
+       via Connected, enp0s3
+@end group
+@end example
+
+@node EIGRP Debug Commands
+@section EIGRP Debug Commands
+
+Debug for EIGRP protocol.
+
+@deffn Command {debug eigrp packets} {}
+Debug eigrp packets
+@end deffn
+
+@code{debug eigrp} will show EIGRP packets that are sent and recevied.
+
+@deffn Command {debug eigrp transmit} {}
+Debug eigrp transmit events
+@end deffn
+
+@code{debug eigrp transmit} will display detailed information about the EIGRP transmit events.
+
+@deffn Command {show debugging eigrp} {}
+Display @command{eigrpd}'s debugging option.
+@end deffn
+
+@code{show debugging eigrp} will show all information currently set for eigrpd
+debug.
index d989928b8f394678032884e662a03c15937b44d3..9a98f46733173e3b76b77dbe98322254ae488446 100644 (file)
@@ -63,6 +63,9 @@ Do not build bgpd.
 @item --disable-bgp-announce
 Make @command{bgpd} which does not make bgp announcements at all.  This
 feature is good for using @command{bgpd} as a BGP announcement listener.
+@item --enable-datacenter
+Enable system defaults to work as if in a Data Center. See defaults.h
+for what is changed by this configure option.
 @item --enable-snmp
 Enable SNMP support.  By default, SNMP support is disabled.
 @item --disable-ospfapi
index 1820044aea3ba2812718f6e6f1b2dabf41589f63..069b46495c7c3d5b0627bb9b41c0a0148baa8fe5 100644 (file)
@@ -64,8 +64,10 @@ command defines the GRE subnet):
 @example
 @group
 router bgp 65555
+ address-family ipv4 unicast
    network 172.16.0.0/16
    redistribute nhrp
+ exit-address-family
 @end group
 @end example
 
index f375d3a7df30ecfb279107a35c2f43bd987ae0be..b1489942108691dcd6e6715ae21309a533297afe 100644 (file)
@@ -1115,18 +1115,21 @@ The configuration for @code{VNC-GW 1} is shown below.
 router bgp 64512
  bgp router-id 192.168.1.101
  bgp cluster-id 1.2.3.4
- redistribute vnc-direct
  neighbor 192.168.1.102 remote-as 64512
- no neighbor 192.168.1.102 activate
  neighbor 192.168.1.103 remote-as 64512
- no neighbor 192.168.1.103 activate
  neighbor 192.168.1.104 remote-as 64512
- no neighbor 192.168.1.104 activate
  neighbor 172.16.1.2 remote-as 64512
- neighbor 172.16.1.2 route-reflector-client
  neighbor 172.16.2.2 remote-as 64512
- neighbor 172.16.2.2 route-reflector-client
-!
+ !
+ address-family ipv4 unicast
+  redistribute vnc-direct
+  no neighbor 192.168.1.102 activate
+  no neighbor 192.168.1.103 activate
+  no neighbor 192.168.1.104 activate
+  neighbor 172.16.1.2 route-reflector-client
+  neighbor 172.16.2.2 route-reflector-client
+ exit-address-family
+ !
  address-family vpnv4 unicast
    neighbor 192.168.1.102 activate
    neighbor 192.168.1.103 activate
@@ -1148,16 +1151,21 @@ Configuration for @code{NVA 2}:
 router bgp 64512
  bgp router-id 192.168.1.104
  neighbor 192.168.1.101 remote-as 64512
- no neighbor 192.168.1.101 activate
  neighbor 192.168.1.102 remote-as 64512
- no neighbor 192.168.1.102 activate
  neighbor 192.168.1.103 remote-as 64512
- no neighbor 192.168.1.103 activate
+ !
+ address-family ipv4 unicast
+  no neighbor 192.168.1.101 activate
+  no neighbor 192.168.1.102 activate
+  no neighbor 192.168.1.103 activate
+ exit-address-family
+ !
  address-family vpnv4 unicast
    neighbor 192.168.1.101 activate
    neighbor 192.168.1.102 activate
    neighbor 192.168.1.103 activate
  exit-address-family
+ !
  vnc defaults
   response-lifetime 3600
   exit-vnc
@@ -1231,12 +1239,15 @@ router bgp 64512
     neighbor 192.168.1.101 remote-as 64512
     neighbor 192.168.1.101 port 7179
     neighbor 192.168.1.101 description iBGP-client-192-168-1-101
-    neighbor 192.168.1.101 route-reflector-client
 
     neighbor 192.168.1.102 remote-as 64512
     neighbor 192.168.1.102 port 7179
     neighbor 192.168.1.102 description iBGP-client-192-168-1-102
-    neighbor 192.168.1.102 route-reflector-client
+
+    address-family ipv4 unicast
+        neighbor 192.168.1.101 route-reflector-client
+        neighbor 192.168.1.102 route-reflector-client
+    exit-address-family
 
     address-family vpnv4
         neighbor 192.168.1.101 activate
diff --git a/eigrpd/.gitignore b/eigrpd/.gitignore
new file mode 100644 (file)
index 0000000..cd46e50
--- /dev/null
@@ -0,0 +1,18 @@
+Makefile
+Makefile.in
+*.o
+*.a
+eigrpd
+eigrpd.conf
+tags
+TAGS
+.deps
+.nfs*
+*.lo
+*.la
+*.libs
+.arch-inventory
+.arch-ids
+*~
+*.loT
+
diff --git a/eigrpd/EIGRP-MIB.txt b/eigrpd/EIGRP-MIB.txt
new file mode 100644 (file)
index 0000000..f6ea298
--- /dev/null
@@ -0,0 +1,1321 @@
+CISCO-EIGRP-MIB DEFINITIONS ::= BEGIN
+
+    IMPORTS
+        MODULE-IDENTITY,
+        OBJECT-TYPE,
+        NOTIFICATION-TYPE,
+        Unsigned32,
+        Gauge32,
+        Counter32,
+        Counter64
+            FROM SNMPv2-SMI
+        TruthValue,
+        TEXTUAL-CONVENTION
+            FROM SNMPv2-TC
+        SnmpAdminString
+            FROM SNMP-FRAMEWORK-MIB
+        MODULE-COMPLIANCE,
+        OBJECT-GROUP,
+        NOTIFICATION-GROUP
+            FROM SNMPv2-CONF
+        ciscoMgmt
+            FROM CISCO-SMI
+        InterfaceIndexOrZero,
+        ifIndex
+            FROM IF-MIB
+        InetAddressType,
+        InetAddress,
+        InetAddressPrefixLength
+            FROM INET-ADDRESS-MIB;
+
+ciscoEigrpMIB MODULE-IDENTITY
+    LAST-UPDATED        "200411160000Z"
+    ORGANIZATION        "Cisco Systems, Inc."
+    CONTACT-INFO        "Cisco Systems
+                         Customer Service
+
+                         Postal: 170 W Tasman Drive
+                                 San Jose, CA  95134
+                                 USA
+
+                         Tel: +1 800 553-NETS
+
+                         E-mail: cs-eigrp@cisco.com"
+    DESCRIPTION
+        "Enhanced Interior Gateway Protocol (EIGRP) is a Cisco
+         proprietary distance vector routing protocol.   It is based on
+         the Diffusing Update Algorithm (DUAL), which is a method of
+         finding loop-free paths through a network.   Directly
+         connected routers running EIGRP form neighbor adjacencies in
+         order to propagate best-path and alternate-path routing
+         information for configured and learned routes.
+
+         The tables defined within the MIB are closely aligned with how
+         the router command-line interface for EIGRP displays
+         information on EIGRP configurations, i.e., the topology table
+         contains objects associated with the EIGRP topology commands,
+         and the peer table contains objects associated withe EIGRP
+         neighbor commands, etc.
+
+         There are five main tables within this mib:
+
+            EIGRP VPN table
+               Contains information regarding which virtual private
+               networks (VPN) are configured with EIGRP.
+
+            EIGRP traffic statistics table
+               Contains counter & statistcs regarding specific types of
+               EIGRP packets sent and related collective information
+               per VPN and per autonomous system (AS).
+
+            EIGRP topology table
+               Contains information regarding EIGRP routes received in
+               updates and originated locally.   EIGRP sends and
+               receives routing updates from adjacent routers running
+               EIGRP with which it formed a peer relationship.
+
+            EIGRP peer (neighbor) table
+               Contains information about neighbor EIGRP routers with
+               which peer adjacencies have been established.   EIGRP
+               uses a Hello protocol to form neighbor relationships
+               with directly connected routers also running EIGRP.
+
+            EIGRP interfaces table
+               Contains information and statistics on each of the
+               interfaces on the router over which EIGRP has been
+               configured to run."
+
+
+    REVISION    "200411160000Z"
+    DESCRIPTION
+                "Initial version of the MIB module."
+    ::= { ciscoMgmt 449 }
+
+--
+-- Textual Conventions
+--
+
+    EigrpUpTimeString ::= TEXTUAL-CONVENTION
+        DISPLAY-HINT "8a"
+        STATUS       current
+        DESCRIPTION
+            "Specifies a timer value in days, hours, minutes,
+             and seconds in ASCII format.
+
+             If the up time is less than 24 hours, the number
+             of days will not be reflected and the string will
+             be formatted like this: 'hh:mm:ss', reflecting
+             hours, minutes, and seconds.
+
+             If the up time is greater than 24 hours, EIGRP is
+             less precise and the minutes and seconds are not
+             reflected.  Instead only the days and hours are shown
+             and the string will be formatted like this: 'xxxdxxh'." 
+        SYNTAX       OCTET STRING (SIZE (0..8))
+
+    EigrpVersionString ::= TEXTUAL-CONVENTION 
+        DISPLAY-HINT "1d.1d/1d.1d"
+        STATUS     current
+        DESCRIPTION
+            "Specifies an ASCII string representing the IOS major
+             and minor version followed by the EIGRP major and minor
+             version."
+        SYNTAX       OCTET STRING (SIZE (0..9))
+
+--
+-- Objects
+--
+
+    cEigrpMIBNotifications OBJECT IDENTIFIER ::= { ciscoEigrpMIB 0 }
+    cEigrpMIBObjects       OBJECT IDENTIFIER ::= { ciscoEigrpMIB 1 }
+    cEigrpMIBConformance   OBJECT IDENTIFIER ::= { ciscoEigrpMIB 2 }
+    cEigrpVpnInfo          OBJECT IDENTIFIER ::= { cEigrpMIBObjects 1 }
+    cEigrpAsInfo           OBJECT IDENTIFIER ::= { cEigrpMIBObjects 2 }
+    cEigrpTopologyInfo     OBJECT IDENTIFIER ::= { cEigrpMIBObjects 3 }
+    cEigrpPeerInfo         OBJECT IDENTIFIER ::= { cEigrpMIBObjects 4 }
+    cEigrpInterfaceInfo    OBJECT IDENTIFIER ::= { cEigrpMIBObjects 5 }
+
+    -- EIGRP VPN Base Table definition
+
+    cEigrpVpnTable OBJECT-TYPE
+        SYNTAX     SEQUENCE OF CEigrpVpnEntry
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "This table contains information on those VPN's configured
+             to run EIGRP.  The VPN creation on a router is independent
+             of the routing protocol to be used over it.   A VPN is
+             given a name and has a dedicated routing table associated
+             with it.  This routing table is identified internally
+             by a unique integer value."
+        ::= { cEigrpVpnInfo 1 }
+
+    cEigrpVpnEntry OBJECT-TYPE
+        SYNTAX     CEigrpVpnEntry
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "Information relating to a single VPN which is configured
+             to run EIGRP."
+        INDEX { cEigrpVpnId }
+        ::= { cEigrpVpnTable 1 }
+
+   CEigrpVpnEntry ::=
+       SEQUENCE {
+           cEigrpVpnId  Unsigned32,
+           cEigrpVpnName SnmpAdminString
+       }
+
+    cEigrpVpnId  OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "The unique VPN identifier.  This is a unique integer
+             relative to all other VPN's defined on the router.  It
+             also identifies internally the routing table instance."
+        ::= { cEigrpVpnEntry 1 }
+
+    cEigrpVpnName  OBJECT-TYPE
+        SYNTAX     SnmpAdminString
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The name given to the VPN."
+        ::= { cEigrpVpnEntry 2 }
+
+    --  EIGRP Traffic Stats table definition
+
+    cEigrpTraffStatsTable OBJECT-TYPE
+        SYNTAX     SEQUENCE OF CEigrpTraffStatsEntry
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "Table of EIGRP traffic statistics and information
+             associated with all EIGRP autonomous systems."
+        ::= { cEigrpAsInfo 1 }
+
+    cEigrpTraffStatsEntry OBJECT-TYPE
+        SYNTAX     CEigrpTraffStatsEntry
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "The set of statistics and information for a single EIGRP
+             Autonomous System."
+        INDEX { cEigrpVpnId, cEigrpAsNumber }
+        ::= { cEigrpTraffStatsTable 1 }
+
+    CEigrpTraffStatsEntry ::=
+        SEQUENCE {
+            cEigrpAsNumber        Unsigned32,
+            cEigrpNbrCount        Unsigned32,
+            cEigrpHellosSent      Counter32,
+            cEigrpHellosRcvd      Counter32,
+            cEigrpUpdatesSent     Counter32,
+            cEigrpUpdatesRcvd     Counter32,
+            cEigrpQueriesSent     Counter32,
+            cEigrpQueriesRcvd     Counter32,
+            cEigrpRepliesSent     Counter32,
+            cEigrpRepliesRcvd     Counter32,
+            cEigrpAcksSent        Counter32,
+            cEigrpAcksRcvd        Counter32,
+            cEigrpInputQHighMark  Unsigned32,
+            cEigrpInputQDrops     Counter32,
+            cEigrpSiaQueriesSent  Counter32,
+            cEigrpSiaQueriesRcvd  Counter32,
+            cEigrpAsRouterIdType  InetAddressType,
+            cEigrpAsRouterId      InetAddress,
+            cEigrpTopoRoutes      Counter32,
+            cEigrpHeadSerial      Counter64,
+            cEigrpNextSerial      Counter64,
+            cEigrpXmitPendReplies Unsigned32,
+            cEigrpXmitDummies     Unsigned32
+        }
+
+    cEigrpAsNumber  OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "The Autonomous System number which is unique integer
+             per VPN."
+        ::= { cEigrpTraffStatsEntry 1 }
+
+    cEigrpNbrCount  OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number of live EIGRP neighbors formed on all
+           interfaces whose IP addresses fall under networks configured
+           in the EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 2 }
+
+    cEigrpHellosSent  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number Hello packets that have been sent to all
+           EIGRP neighbors formed on all interfaces whose IP addresses
+           fall under networks configured for the EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 3 }
+
+    cEigrpHellosRcvd  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number Hello packets that have been received
+           from all EIGRP neighbors formed on all interfaces whose IP
+           addresses fall under networks configured for the
+           EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 4 }
+
+    cEigrpUpdatesSent  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number routing update packets that have been
+           sent to all EIGRP neighbors formed on all interfaces whose
+           IP addresses fall under networks configured for the
+           EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 5 }
+
+    cEigrpUpdatesRcvd  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number routing update packets that have been
+           received from all EIGRP neighbors formed on all interfaces
+           whose IP addresses fall under networks configured for the
+           EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 6 }
+
+    cEigrpQueriesSent  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number alternate route query packets that have
+           been sent to all EIGRP neighbors formed on all interfaces
+           whose IP addresses fall under networks configured for the
+           EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 7 }
+
+    cEigrpQueriesRcvd  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number alternate route query packets that
+           have been received from all EIGRP neighbors formed on
+           all interfaces whose IP addresses fall under networks
+           configured for the EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 8 }
+
+    cEigrpRepliesSent  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number query reply packets that have been sent
+           to all EIGRP neighbors formed on all interfaces whose IP
+           addresses fall under networks configured for the
+           EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 9 }
+
+    cEigrpRepliesRcvd  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number query reply packets that have been
+           received from all EIGRP neighbors formed on all interfaces
+           whose IP addresses fall under networks configured for the
+           EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 10 }
+
+    cEigrpAcksSent  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number packet acknowledgements that have been
+           sent to all EIGRP neighbors formed on all interfaces whose
+           IP addresses fall under networks configured for the
+           EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 11 }
+
+    cEigrpAcksRcvd  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number packet acknowledgements that have been
+           received from all EIGRP neighbors formed on all interfaces
+           whose IP addresses fall under networks configured for the
+           EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 12 }
+
+    cEigrpInputQHighMark  OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The highest number of EIGRP packets in the input queue
+             waiting to be processed internally addressed to this
+             AS."
+        ::= { cEigrpTraffStatsEntry 13 }
+
+    cEigrpInputQDrops  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The number of EIGRP packets dropped from the input
+           queue due to it being full within the AS."
+        ::= { cEigrpTraffStatsEntry 14 }
+
+    cEigrpSiaQueriesSent  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number of Stuck-In-Active (SIA) query packets
+           sent to all EIGRP neighbors formed on all interfaces whose
+           IP addresses fall under networks configured for the
+           EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 15 }
+
+    cEigrpSiaQueriesRcvd  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number of Stuck-In-Active (SIA) query packets
+           received from all EIGRP neighbors formed on all interfaces
+           whose IP addresses fall under networks configured for the
+           EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 16 }
+
+    cEigrpAsRouterIdType  OBJECT-TYPE
+        SYNTAX     InetAddressType
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The format of the router-id configured or automatically
+           selected for the EIGRP AS."
+        ::= { cEigrpTraffStatsEntry 17 }
+
+    cEigrpAsRouterId  OBJECT-TYPE
+        SYNTAX     InetAddress
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The router-id configured or automatically selected for the
+           EIGRP AS.   Each EIGRP routing process has a unique
+           router-id selected from each autonomous system configured.
+           The format is governed by object cEigrpAsRouterIdType."
+        ::= { cEigrpTraffStatsEntry 18 }
+
+    cEigrpTopoRoutes  OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "The total number of EIGRP derived routes currently existing
+           in the topology table for the AS."
+        ::= { cEigrpTraffStatsEntry 19 }
+
+    cEigrpHeadSerial  OBJECT-TYPE
+        SYNTAX     Counter64
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "Routes in a topology table for an AS are assigned serial
+             numbers and are sequenced internally as they are inserted
+             and deleted.   The serial number of the first route in
+             that internal sequence is called the head serial number.
+             Each AS has its own topology table, and its own serial
+             number space, each of which begins with the value 1.
+             A serial number of zero implies that there are no routes
+             in the topology."
+        ::= { cEigrpTraffStatsEntry 20 }
+
+    cEigrpNextSerial  OBJECT-TYPE
+        SYNTAX     Counter64
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The serial number that would be assigned to the next new
+             or changed route in the topology table for the AS."
+        ::= { cEigrpTraffStatsEntry 21 }
+
+    cEigrpXmitPendReplies  OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+           "When alternate route query packets are sent to adjacent
+           EIGRP peers in an AS, replies are expected.   This object
+           is the total number of outstanding replies expected to
+           queries that have been sent to peers in the current AS.
+           It remains at zero most of the time until an EIGRP route
+           becomes active."
+        ::= { cEigrpTraffStatsEntry 22 }
+
+    cEigrpXmitDummies  OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "A dummy is a temporary internal entity used as a place
+             holder in the topology table for an AS. They are not
+             transmitted in routing updates.  This is the total
+             number currently in existence associated with the AS."
+        ::= { cEigrpTraffStatsEntry 23 }
+
+    --  EIGRP topology table definition
+
+    cEigrpTopoTable OBJECT-TYPE
+        SYNTAX     SEQUENCE OF CEigrpTopoEntry
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "The table of EIGRP routes and their associated
+             attributes for an Autonomous System (AS) configured
+             in a VPN is called a topology table.  All route entries in
+             the topology table will be indexed by IP network type,
+             IP network number and network mask (prefix) size."
+        ::= { cEigrpTopologyInfo 1 }
+
+    cEigrpTopoEntry OBJECT-TYPE
+        SYNTAX     CEigrpTopoEntry
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "The entry for a single EIGRP topology table in the given
+             AS."
+        INDEX { cEigrpVpnId, cEigrpAsNumber, cEigrpDestNetType,
+                cEigrpDestNet, cEigrpDestNetPrefixLen }
+        ::= { cEigrpTopoTable 1 }
+
+    CEigrpTopoEntry ::=
+        SEQUENCE {
+            cEigrpDestNetType             InetAddressType,
+            cEigrpDestNet                 InetAddress,
+            cEigrpDestNetPrefixLen        InetAddressPrefixLength,
+            cEigrpActive                  TruthValue,
+            cEigrpStuckInActive           TruthValue,
+            cEigrpDestSuccessors          Unsigned32,
+            cEigrpFdistance               Unsigned32,
+            cEigrpRouteOriginType         SnmpAdminString,
+            cEigrpRouteOriginAddrType     InetAddressType,
+            cEigrpRouteOriginAddr         InetAddress,
+            cEigrpNextHopAddressType      InetAddressType,
+            cEigrpNextHopAddress          InetAddress,
+            cEigrpNextHopInterface        SnmpAdminString,
+            cEigrpDistance                Unsigned32,
+            cEigrpReportDistance          Unsigned32
+        }
+
+    cEigrpDestNetType OBJECT-TYPE
+        SYNTAX     InetAddressType
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "The format of the destination IP network number for
+             a single route in the topology table in the AS specified
+             in cEigrpDestNet."
+        ::= { cEigrpTopoEntry 1 }
+
+    cEigrpDestNet OBJECT-TYPE
+        SYNTAX     InetAddress
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "The destination IP network number for a single route in
+             the topology table in the AS.  The format is governed
+             by object cEigrpDestNetType."
+        ::= { cEigrpTopoEntry 2 }
+
+    cEigrpDestNetPrefixLen OBJECT-TYPE
+        SYNTAX     InetAddressPrefixLength
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "The prefix length associated with the destination IP
+             network address for a single route in the topology
+             table in the AS.  The format is governed by the object
+             cEigrpDestNetType."
+        ::= { cEigrpTopoEntry 4 }
+
+    cEigrpActive OBJECT-TYPE
+        SYNTAX     TruthValue
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "A value of true(1) indicates the route to the
+             destination network has failed and an active (query)
+             search for an alternative path is in progress.  A value
+             of false(2) indicates the route is stable (passive)."
+        ::= { cEigrpTopoEntry 5 }
+
+    cEigrpStuckInActive OBJECT-TYPE
+        SYNTAX     TruthValue
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "A value of true(1) indicates that that this route which is
+             in active state (cEigrpActive = true(1)) has not received
+             any replies to queries for alternate paths, and a second
+             EIGRP route query, called a stuck-in-active query, has
+             now been sent."
+        ::= { cEigrpTopoEntry 6 }
+
+    cEigrpDestSuccessors OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "A successor is the next routing hop for a path to the
+             destination IP network number for a single route in the
+             topology table in the AS.  There can be several
+             potential successors if there are multiple paths to the
+             destination.   This is the total number of successors for
+             a topology entry."
+        ::= { cEigrpTopoEntry 7 }
+
+    cEigrpFdistance OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+             "The feasibility (best) distance is the minimum distance
+             from this router to the destination IP network in
+             this topology entry.  The feasibility distance is
+             used in determining the best successor for a path to the
+             destination network."
+        ::= { cEigrpTopoEntry 8 }
+
+     cEigrpRouteOriginType OBJECT-TYPE
+        SYNTAX     SnmpAdminString
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+             "This is a text string describing the internal origin
+              of the EIGRP route represented by the topology entry."
+        ::= { cEigrpTopoEntry 9 }
+
+     cEigrpRouteOriginAddrType OBJECT-TYPE
+        SYNTAX     InetAddressType
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+             "The format of the IP address defined as the origin of
+             this topology route entry."
+        ::= { cEigrpTopoEntry 10 }
+
+     cEigrpRouteOriginAddr OBJECT-TYPE
+        SYNTAX     InetAddress
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+             "If the origin of the topology route entry is external
+              to this router, then this object is the IP address
+              of the router from which it originated.  The format 
+              is governed by object cEigrpRouteOriginAddrType."
+        ::= { cEigrpTopoEntry 11 }
+
+     cEigrpNextHopAddressType OBJECT-TYPE
+        SYNTAX     InetAddressType
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+             "The format of the next hop IP address for the route
+              represented by the topology entry."
+        ::= { cEigrpTopoEntry 12 }
+
+     cEigrpNextHopAddress OBJECT-TYPE
+        SYNTAX     InetAddress
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+             "This is the next hop IP address for the route represented
+              by the topology entry.   The next hop is where
+              network traffic will be routed to in order to reach
+              the destination network for this topology entry.  The
+              format is governed by cEigrpNextHopAddressType."
+        ::= { cEigrpTopoEntry 13 }
+
+     cEigrpNextHopInterface OBJECT-TYPE
+        SYNTAX     SnmpAdminString
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+             "The interface through which the next hop IP address
+              is reached to send network traffic to the destination
+              network represented by the topology entry."
+        ::= { cEigrpTopoEntry 14 }
+
+     cEigrpDistance OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+             "The computed distance to the destination network entry
+             from this router."
+        ::= { cEigrpTopoEntry 15 }
+
+     cEigrpReportDistance OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+             "The computed distance to the destination network in the
+              topology entry reported to this router by the originator
+              of this route."
+        ::= { cEigrpTopoEntry 16 }
+
+    --  EIGRP Peer table per VPN and AS (expansion table)
+
+    cEigrpPeerTable OBJECT-TYPE
+        SYNTAX     SEQUENCE OF CEigrpPeerEntry
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "The table of established EIGRP peers (neighbors) in the
+             selected autonomous system.   Peers are indexed by their
+             unique internal handle id, as well as the AS number and
+             VPN id.   The peer entry is removed from the table if
+             the peer is declared down."
+    ::= { cEigrpPeerInfo 1 }
+
+    cEigrpPeerEntry OBJECT-TYPE
+        SYNTAX     CEigrpPeerEntry
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "Statistics and operational parameters for a single peer
+             in the AS."
+        INDEX { cEigrpVpnId, cEigrpAsNumber, cEigrpHandle }
+        ::= { cEigrpPeerTable 1 }
+
+    CEigrpPeerEntry ::=
+        SEQUENCE {
+            cEigrpHandle        Unsigned32,
+            cEigrpPeerAddrType  InetAddressType,
+            cEigrpPeerAddr      InetAddress,
+            cEigrpPeerIfIndex   InterfaceIndexOrZero,
+            cEigrpHoldTime      Unsigned32,
+            cEigrpUpTime        EigrpUpTimeString,
+            cEigrpSrtt          Unsigned32,
+            cEigrpRto           Unsigned32,
+            cEigrpPktsEnqueued  Unsigned32,
+            cEigrpLastSeq       Unsigned32,
+            cEigrpVersion       EigrpVersionString,
+            cEigrpRetrans       Counter32,
+            cEigrpRetries       Unsigned32
+        }
+
+    cEigrpHandle OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "The unique internal identifier for the peer in the AS.
+             This is a unique value among peer entries in a selected
+             table."
+        ::= { cEigrpPeerEntry 1 }
+
+    cEigrpPeerAddrType OBJECT-TYPE
+        SYNTAX     InetAddressType
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The format of the remote source IP address used by the
+             peer to establish the EIGRP adjacency with this router."
+        ::= { cEigrpPeerEntry 2 }
+
+    cEigrpPeerAddr OBJECT-TYPE
+        SYNTAX     InetAddress
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The source IP address used by the peer to establish the
+             EIGRP adjacency with this router.  The format is
+             governed by object cEigrpPeerAddrType."
+        ::= { cEigrpPeerEntry 3 }
+
+    cEigrpPeerIfIndex OBJECT-TYPE
+        SYNTAX     InterfaceIndexOrZero
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The ifIndex of the interface on this router through
+             which this peer can be reached."
+        ::= { cEigrpPeerEntry 4 }
+
+    cEigrpHoldTime OBJECT-TYPE
+        SYNTAX     Unsigned32
+        UNITS      "seconds"
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The count-down timer indicating how much time must
+             pass without receiving a hello packet from this
+             EIGRP peer before this router declares the peer down.
+             A peer declared as down is removed from the table and
+             is no longer visible."
+        ::= { cEigrpPeerEntry 5 }
+
+    cEigrpUpTime OBJECT-TYPE
+        SYNTAX       EigrpUpTimeString
+        MAX-ACCESS   read-only
+        STATUS       current
+        DESCRIPTION
+            "The elapsed time since the EIGRP adjacency was first
+             established with the peer."
+        ::= { cEigrpPeerEntry 6 }
+
+    cEigrpSrtt OBJECT-TYPE
+        SYNTAX     Unsigned32
+        UNITS      "milliseconds"
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The computed smooth round trip time for packets to and
+             from the peer."
+        ::= { cEigrpPeerEntry 7 }
+
+    cEigrpRto OBJECT-TYPE
+        SYNTAX     Unsigned32
+        UNITS      "milliseconds"
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The computed retransmission timeout for the peer.
+             This value is computed over time as packets are sent to
+             the peer and acknowledgements are received from it,
+             and is the amount of time to wait before resending
+             a packet from the retransmission queue to the peer
+             when an expected acknowledgement has not been received."
+        ::= { cEigrpPeerEntry 8 }
+
+    cEigrpPktsEnqueued OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The number of any EIGRP packets currently enqueued
+             waiting to be sent to this peer."
+        ::= { cEigrpPeerEntry 9 }
+
+    cEigrpLastSeq OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "All transmitted EIGRP packets have a sequence number
+             assigned. This is the sequence number of the last EIGRP
+             packet sent to this peer."
+        ::= { cEigrpPeerEntry 10 }
+
+    cEigrpVersion OBJECT-TYPE
+        SYNTAX     EigrpVersionString
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The EIGRP version information reported by the remote
+             peer."
+        ::= { cEigrpPeerEntry 11 }
+
+    cEigrpRetrans OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The cumulative number of retransmissions to this peer
+             during the period that the peer adjacency has remained
+             up."
+        ::= { cEigrpPeerEntry 12 }
+
+    cEigrpRetries OBJECT-TYPE
+        SYNTAX     Unsigned32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The number of times the current unacknowledged packet
+             has been retried, i.e. resent to this peer to be
+             acknowledged."
+        ::= { cEigrpPeerEntry 13 }
+
+    --  EIGRP Interfaces table per VPN and AS
+
+    cEigrpInterfaceTable OBJECT-TYPE
+        SYNTAX     SEQUENCE OF CEigrpInterfaceEntry
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "The table of interfaces over which EIGRP is running, and
+             their associated statistics.   This table is independent
+             of whether any peer adjacencies have been formed over
+             the interfaces or not.   Interfaces running EIGRP are
+             determined by whether their assigned IP addresses fall
+             within configured EIGRP network statements."
+        ::= { cEigrpInterfaceInfo 1 }
+
+    cEigrpInterfaceEntry OBJECT-TYPE
+        SYNTAX     CEigrpInterfaceEntry
+        MAX-ACCESS not-accessible
+        STATUS     current
+        DESCRIPTION
+            "Information for a single interface running EIGRP in the
+             AS and VPN."
+        INDEX { cEigrpVpnId, cEigrpAsNumber, ifIndex }
+        ::= { cEigrpInterfaceTable 1 }
+
+    CEigrpInterfaceEntry ::=
+        SEQUENCE {
+            cEigrpPeerCount        Gauge32,
+            cEigrpXmitReliableQ    Gauge32,
+            cEigrpXmitUnreliableQ  Gauge32,
+            cEigrpMeanSrtt         Unsigned32,
+            cEigrpPacingReliable   Unsigned32,
+            cEigrpPacingUnreliable Unsigned32,
+            cEigrpMFlowTimer       Unsigned32,
+            cEigrpPendingRoutes    Gauge32,
+            cEigrpHelloInterval    Unsigned32,
+            cEigrpXmitNextSerial   Counter64,
+            cEigrpUMcasts          Counter32,
+            cEigrpRMcasts          Counter32,
+            cEigrpUUcasts          Counter32,
+            cEigrpRUcasts          Counter32,
+            cEigrpMcastExcepts     Counter32,
+            cEigrpCRpkts           Counter32,
+            cEigrpAcksSuppressed   Counter32,
+            cEigrpRetransSent       Counter32,
+            cEigrpOOSrcvd          Counter32,
+            cEigrpAuthMode         INTEGER,
+            cEigrpAuthKeyChain    SnmpAdminString
+         }
+
+    cEigrpPeerCount OBJECT-TYPE
+        SYNTAX     Gauge32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The number of EIGRP adjacencies currently formed with
+             peers reached through this interface."
+        ::= { cEigrpInterfaceEntry 3 }
+
+    cEigrpXmitReliableQ OBJECT-TYPE
+        SYNTAX     Gauge32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The number of EIGRP packets currently waiting in the
+             reliable transport (acknowledgement-required) 
+             transmission queue to be sent to a peer."
+        ::= { cEigrpInterfaceEntry 4 }
+
+    cEigrpXmitUnreliableQ OBJECT-TYPE
+        SYNTAX     Gauge32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The number EIGRP of packets currently waiting in
+             the unreliable transport (no acknowledgement required)
+             transmission queue."
+        ::= { cEigrpInterfaceEntry 5 }
+
+    cEigrpMeanSrtt OBJECT-TYPE
+        SYNTAX     Unsigned32
+        UNITS      "milliseconds"
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The average of all the computed smooth round trip time
+             values for a packet to and from all peers established on
+             this interface."
+        ::= { cEigrpInterfaceEntry 6 }
+
+    cEigrpPacingReliable OBJECT-TYPE
+        SYNTAX     Unsigned32
+        UNITS      "milliseconds"
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The configured time interval between EIGRP packet
+             transmissions on the interface when the reliable transport
+             method is used."
+        ::= { cEigrpInterfaceEntry 7 }
+
+    cEigrpPacingUnreliable OBJECT-TYPE
+        SYNTAX     Unsigned32
+        UNITS      "milliseconds"
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The configured time interval between EIGRP packet
+             transmissions on the interface when the unreliable
+             transport method is used."
+        ::= { cEigrpInterfaceEntry 8 }
+
+    cEigrpMFlowTimer OBJECT-TYPE
+        SYNTAX     Unsigned32
+        UNITS      "milliseconds"
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The configured multicast flow control timer value for
+             this interface."
+        ::= { cEigrpInterfaceEntry 9 }
+
+    cEigrpPendingRoutes OBJECT-TYPE
+        SYNTAX     Gauge32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The number of queued EIGRP routing updates awaiting
+             transmission on this interface."
+        ::= { cEigrpInterfaceEntry 10 }
+
+    cEigrpHelloInterval OBJECT-TYPE
+        SYNTAX     Unsigned32
+        UNITS      "seconds"
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The configured time interval between Hello packet
+             transmissions for this interface."
+        ::= { cEigrpInterfaceEntry 11 }
+
+    cEigrpXmitNextSerial OBJECT-TYPE
+        SYNTAX     Counter64
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The serial number of the next EIGRP packet that is to
+             be queued for transmission on this interface."
+        ::= { cEigrpInterfaceEntry 12 }
+
+    cEigrpUMcasts OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The total number of unreliable (no acknowledgement
+             required) EIGRP multicast packets sent on this
+             interface."
+        ::= { cEigrpInterfaceEntry 13 }
+
+    cEigrpRMcasts OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The total number of reliable (acknowledgement required)
+             EIGRP multicast packets sent on this interface."
+        ::= { cEigrpInterfaceEntry 14 }
+
+    cEigrpUUcasts OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The total number of unreliable (no acknowledgement
+             required) EIGRP unicast packets sent on this
+             interface."
+        ::= { cEigrpInterfaceEntry 15 }
+
+    cEigrpRUcasts OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The total number of reliable (acknowledgement required)
+             unicast packets sent on this interface."
+        ::= { cEigrpInterfaceEntry 16 }
+
+    cEigrpMcastExcepts OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The total number of EIGRP multicast exception
+             transmissions that have occurred on this interface."
+        ::= { cEigrpInterfaceEntry 17 }
+
+    cEigrpCRpkts OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The total number EIGRP Conditional-Receive packets sent on
+             this interface."
+        ::= { cEigrpInterfaceEntry 18 }
+
+    cEigrpAcksSuppressed OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The total number of individual EIGRP acknowledgement
+             packets that have been suppressed and combined in
+             an already enqueued outbound reliable packet on this
+             interface."
+        ::= { cEigrpInterfaceEntry 19 }
+
+    cEigrpRetransSent OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The total number EIGRP packet retransmissions sent on
+             the interface."
+        ::= { cEigrpInterfaceEntry 20 }
+
+    cEigrpOOSrcvd OBJECT-TYPE
+        SYNTAX     Counter32
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The total number of out-of-sequence EIGRP packets
+             received."
+        ::= { cEigrpInterfaceEntry 21 }
+
+    cEigrpAuthMode OBJECT-TYPE
+        SYNTAX     INTEGER {
+                       none(1),
+                       md5(2)
+                   }
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The EIGRP authentication mode of the interface.
+            none  :  no authentication enabled on the interface
+            md5   :  MD5 authentication enabled on the interface"
+        ::= { cEigrpInterfaceEntry 22 }
+
+    cEigrpAuthKeyChain OBJECT-TYPE
+        SYNTAX     SnmpAdminString
+        MAX-ACCESS read-only
+        STATUS     current
+        DESCRIPTION
+            "The name of the authentication key-chain configured
+             on this interface.   The key-chain is a reference to
+             which set of secret keys are to be accessed in order
+             to determine which secret key string to use.  The key
+             chain name is not the secret key string password and
+             can also be used in other routing protocols, such
+             as RIP and ISIS."
+        ::= { cEigrpInterfaceEntry 23 }
+
+    -- Notifications
+
+    cEigrpAuthFailureEvent NOTIFICATION-TYPE
+        OBJECTS { cEigrpPeerAddrType, cEigrpPeerAddr }
+        STATUS     current
+        DESCRIPTION
+            "This notification is sent when EIGRP MD5 authentication
+             is enabled on any interface and peer adjacencies are
+             formed, and any adjacencies go down as a result of an
+             authentication failure."
+        ::=  { cEigrpMIBNotifications 1 }
+
+    cEigrpRouteStuckInActive NOTIFICATION-TYPE
+        OBJECTS { cEigrpPeerAddrType, cEigrpPeerAddr,
+                  cEigrpStuckInActive }
+        STATUS     current
+        DESCRIPTION
+            "This notification is sent when a route in the topology
+             table is stuck in an active state.  During the query
+             phase for a new route to a destination network, a route
+             is described as being in the active state if when an
+             alternate path is actively being sought, no replies are
+             received to normal queries or stuck-in-active queries."
+        ::=  { cEigrpMIBNotifications 2 }
+
+    -- Conformance
+
+    cEigrpMIBCompliances
+        OBJECT IDENTIFIER ::= { cEigrpMIBConformance 1 }
+
+    cEigrpMIBGroups
+        OBJECT IDENTIFIER ::= { cEigrpMIBConformance 2 }
+
+    -- Compliance
+
+    cEigrpMIBCompliance MODULE-COMPLIANCE
+        STATUS     current
+        DESCRIPTION
+            "The compliance statement for entities which implement
+             the Cisco EIGRP Management MIB."
+        MODULE
+            MANDATORY-GROUPS {
+                cEigrpVpnDataGroup,
+                cEigrpTrafficStatsGroup,
+                cEigrpInterfaceDataGroup,
+                cEigrpPeerDataGroup,
+                cEigrpTopoDataGroup,
+                cEigrpNotificationsGroup
+            }
+
+            OBJECT cEigrpAsRouterIdType
+            SYNTAX INTEGER { ipv4(1) }
+            DESCRIPTION
+                "An implementation is only required to support
+                 IPv4 address type."
+
+            OBJECT cEigrpRouteOriginAddrType
+            SYNTAX INTEGER { ipv4(1) }
+            DESCRIPTION
+                "An implementation is only required to support
+                 IPv4 address type."
+
+            OBJECT cEigrpNextHopAddressType
+            SYNTAX INTEGER { ipv4(1) }
+            DESCRIPTION
+                "An implementation is only required to support
+                 IPv4 address type."
+
+            OBJECT cEigrpPeerAddrType
+            SYNTAX INTEGER { ipv4(1) }
+            DESCRIPTION
+                "An implementation is only required to support
+                 IPv4 address type."
+        ::= { cEigrpMIBCompliances 1 }
+
+    -- Units of Conformance
+
+    cEigrpVpnDataGroup OBJECT-GROUP
+        OBJECTS {
+            cEigrpVpnName
+        }
+        STATUS     current
+        DESCRIPTION
+            "The collection of VPN names which have been configured
+             with one or more EIGRP autonmous systems."
+        ::= { cEigrpMIBGroups 1 }
+
+    cEigrpTrafficStatsGroup OBJECT-GROUP
+        OBJECTS {
+            cEigrpHellosSent,
+            cEigrpHellosRcvd,
+            cEigrpUpdatesSent,
+            cEigrpUpdatesRcvd,
+            cEigrpQueriesSent,
+            cEigrpQueriesRcvd,
+            cEigrpRepliesSent,
+            cEigrpRepliesRcvd,
+            cEigrpAcksSent,
+            cEigrpAcksRcvd,
+            cEigrpInputQHighMark,
+            cEigrpInputQDrops,
+            cEigrpSiaQueriesSent,
+            cEigrpSiaQueriesRcvd
+        }
+        STATUS     current
+        DESCRIPTION
+            "A collection of objects providing management information
+             regarding collective EIGRP packet statistics for all EIGRP
+             autonomous systems configured."
+        ::= { cEigrpMIBGroups 2 }
+
+    cEigrpInterfaceDataGroup OBJECT-GROUP
+        OBJECTS {
+            cEigrpPeerCount,
+            cEigrpXmitReliableQ,
+            cEigrpXmitUnreliableQ,
+            cEigrpMeanSrtt,
+            cEigrpPacingReliable,
+            cEigrpPacingUnreliable,
+            cEigrpMFlowTimer,
+            cEigrpPendingRoutes,
+            cEigrpHelloInterval,
+            cEigrpXmitNextSerial,
+            cEigrpUMcasts,
+            cEigrpRMcasts,
+            cEigrpUUcasts,
+            cEigrpRUcasts,
+            cEigrpMcastExcepts,
+            cEigrpCRpkts,
+            cEigrpAcksSuppressed,
+            cEigrpRetransSent,
+            cEigrpOOSrcvd,
+            cEigrpAuthMode,
+            cEigrpAuthKeyChain
+        }
+        STATUS     current
+        DESCRIPTION
+            "A collection of objects providing management information
+             for interfaces over which EIGRP is configured and
+             running."
+        ::= { cEigrpMIBGroups 3 }
+
+    cEigrpPeerDataGroup OBJECT-GROUP
+        OBJECTS {
+            cEigrpNbrCount,
+            cEigrpPeerAddrType,
+            cEigrpPeerAddr,
+            cEigrpPeerIfIndex,
+            cEigrpHoldTime,
+            cEigrpUpTime,
+            cEigrpSrtt,
+            cEigrpRto,
+            cEigrpPktsEnqueued,
+            cEigrpLastSeq,
+            cEigrpVersion,
+            cEigrpRetrans,
+            cEigrpRetries
+        }
+        STATUS     current
+        DESCRIPTION
+            "A collection of objects providing management information
+             for EIGRP peer adjacencies formed in the EIGRP
+             autonoumous systems."
+        ::= { cEigrpMIBGroups 4 }
+
+    cEigrpTopoDataGroup OBJECT-GROUP
+        OBJECTS {
+            cEigrpAsRouterId,
+            cEigrpAsRouterIdType,
+            cEigrpTopoRoutes,
+            cEigrpHeadSerial,
+            cEigrpNextSerial,
+            cEigrpXmitPendReplies,
+            cEigrpXmitDummies,
+            cEigrpActive,
+            cEigrpStuckInActive,
+            cEigrpDestSuccessors,
+            cEigrpFdistance,
+            cEigrpRouteOriginType,
+            cEigrpRouteOriginAddrType,
+            cEigrpRouteOriginAddr,
+            cEigrpNextHopAddressType,
+            cEigrpNextHopAddress,
+            cEigrpNextHopInterface,
+            cEigrpDistance,
+            cEigrpReportDistance
+        }
+        STATUS     current
+        DESCRIPTION
+            "A collection of objects providing management information
+             for EIGRP topology routes derived within autonomous
+             systems and received in updates from EIGRP neighbors."
+        ::= { cEigrpMIBGroups 5 }
+
+    cEigrpNotificationsGroup NOTIFICATION-GROUP
+        NOTIFICATIONS {
+            cEigrpAuthFailureEvent,
+            cEigrpRouteStuckInActive
+        }
+        STATUS     current
+        DESCRIPTION
+            "Group of notifications on EIGRP routers."
+        ::= { cEigrpMIBGroups 6 }
+END
\ No newline at end of file
diff --git a/eigrpd/Makefile.am b/eigrpd/Makefile.am
new file mode 100644 (file)
index 0000000..9ee792e
--- /dev/null
@@ -0,0 +1,46 @@
+## 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 \
+       eigrp_fsm.h
+
+eigrpd_SOURCES = eigrp_main.c $(libeigrp_a_SOURCES)
+
+eigrpd_LDADD = ../lib/libfrr.la @LIBCAP@
+
+EXTRA_DIST = EIGRP-MIB.txt
+
+examplesdir = $(exampledir)
+dist_examples_DATA = eigrpd.conf.sample
diff --git a/eigrpd/eigrp_const.h b/eigrpd/eigrp_const.h
new file mode 100644 (file)
index 0000000..9397717
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * 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 << 0)
+#define EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG    (1 << 1)
+#define EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG       (1 << 2)
+#define EIGRP_NEIGHBOR_ENTRY_EXTERNAL_FLAG      (1 << 3)
+
+/*EIGRP FSM state count, event count*/
+#define EIGRP_FSM_STATE_MAX                  5
+#define EIGRP_FSM_EVENT_MAX                  16
+
+/*EEGRP FSM states*/
+enum eigrp_fsm_states {
+  EIGRP_FSM_STATE_PASSIVE,
+  EIGRP_FSM_STATE_ACTIVE_0,
+  EIGRP_FSM_STATE_ACTIVE_1,
+  EIGRP_FSM_STATE_ACTIVE_2,
+  EIGRP_FSM_STATE_ACTIVE_3,
+};
+
+/*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 */
+
+/**
+ * External routes originate from some other protocol - these are them
+ */
+#define NULL_PROTID            0               /*!< unknown protocol */
+#define IGRP_PROTID            1               /*!< IGRP.. whos your daddy! */
+#define EIGRP_PROTID           2               /*!< EIGRP - Just flat out the best */
+#define STATIC_PROTID          3               /*!< Staticly configured source */
+#define RIP_PROTID             4               /*!< Routing Information Protocol */
+#define HELLO_PROTID           5               /*!< Hello? RFC-891 you there? */
+#define OSPF_PROTID            6               /*!< OSPF - Open Shortest Path First */
+#define ISIS_PROTID            7               /*!< Intermediate System To Intermediate System */
+#define EGP_PROTID             8               /*!< Exterior Gateway Protocol */
+#define BGP_PROTID             9               /*!< Border Gateway Protocol */
+#define IDRP_PROTID            10              /*!< InterDomain Routing Protocol */
+#define CONN_PROTID            11              /*!< Connected source */
+
+/* 
+ * metric k-value defaults
+ */
+#define EIGRP_K1_DEFAULT       1               //!< unweighed inverse bandwidth
+#define EIGRP_K2_DEFAULT       0               //!< no loading term
+#define EIGRP_K3_DEFAULT       1               //!< unweighted delay
+#define EIGRP_K4_DEFAULT       0               //!< no reliability term
+#define EIGRP_K5_DEFAULT       0               //!< no reliability term
+#define EIGRP_K6_DEFAULT       0               //!< do not add in extended metrics
+
+
+/*
+ * EIGRP Fixed header
+ */
+#define EIGRP_HEADER_LEN        20U
+#define EIGRP_PACKET_MAX_LEN    65535U   /* includes IP Header size. */
+
+
+#define EIGRP_TLV_HDR_LENGTH    4
+
+/**
+ * EIGRP Packet Opcodes
+ */
+#define EIGRP_OPC_UPDATE        1       /*!< packet containing routing information */
+#define EIGRP_OPC_REQUEST       2       /*!< sent to request one or more routes */
+#define EIGRP_OPC_QUERY         3       /*!< sent when a routing is in active start */
+#define EIGRP_OPC_REPLY         4       /*!< sent in response to a query */
+#define EIGRP_OPC_HELLO         5       /*!< sent to maintain a peering session */
+#define EIGRP_OPC_IPXSAP        6       /*!< IPX SAP information */
+#define EIGRP_OPC_PROBE         7       /*!< for test purposes   */
+#define EIGRP_OPC_ACK           8       /*!< acknowledge         */
+#define EIGRP_OPC_SIAQUERY      10      /*!< QUERY - with relaxed restrictions */
+#define EIGRP_OPC_SIAREPLY      11      /*!< REPLY - may contain old routing information */
+
+/**
+ * EIGRP TLV Range definitions
+ *      PDM             TLV Range
+ *      General         0x0000
+ *      IPv4            0x0100                  ** TLVs for one and all
+ *      ATALK           0x0200                  ** legacy
+ *      IPX             0x0300                  ** discontinued
+ *      IPv6            0x0400                  ** legacy
+ *      Multiprotocol   0x0600                  ** wide metrics
+ *      MultiTopology   0x00f0                  ** deprecated
+ */
+#define EIGRP_TLV_RANGEMASK     0xfff0          /*!< should be 0xff00 - opps */
+#define EIGRP_TLV_GENERAL       0x0000
+
+/**
+ * 1.2 TLV Definitions  ** legacy
+ * These are considered legacyu and are only used for backward compability with
+ * older Cisco Routers.  They should not be your first choice for packet codings
+ */
+#define EIGRP_TLV_IPv4          0x0100          /*!< Classic IPv4 TLV encoding */
+#define EIGRP_TLV_ATALK         0x0200          /*!< Classic Appletalk TLV encoding*/
+#define EIGRP_TLV_IPX           0x0300          /*!< Classic IPX TLV encoding */
+#define EIGRP_TLV_IPv6          0x0400          /*!< Classic IPv6 TLV encoding */
+
+/**
+ * 2.0 Multi-Protocol TLV Definitions
+ * These are the current packet formats and should be used for packets
+ */
+#define EIGRP_TLV_MP            0x0600          /*!< Non-PDM specific encoding */
+
+/**
+ * TLV type definitions.  Generic (protocol-independent) TLV types are
+ * defined here.  Protocol-specific ones are defined elsewhere.
+ */
+#define EIGRP_TLV_PARAMETER             (EIGRP_TLV_GENERAL | 0x0001)    /*!< eigrp parameters */
+#define EIGRP_TLV_PARAMETER_LEN         (12U)
+#define EIGRP_TLV_AUTH                  (EIGRP_TLV_GENERAL | 0x0002)    /*!< authentication */
+#define EIGRP_TLV_SEQ                   (EIGRP_TLV_GENERAL | 0x0003)    /*!< sequenced packet */
+#define EIGRP_TLV_SEQ_BASE_LEN          (5U)
+#define EIGRP_TLV_SW_VERSION            (EIGRP_TLV_GENERAL | 0x0004)    /*!< software version */
+#define EIGRP_TLV_SW_VERSION_LEN        (8U)
+#define EIGRP_TLV_NEXT_MCAST_SEQ        (EIGRP_TLV_GENERAL | 0x0005)    /*!< sequence number */
+#define EIGRP_TLV_PEER_TERMINATION      (EIGRP_TLV_GENERAL | 0x0007)    /*!< peer termination */
+#define EIGRP_TLV_PEER_TERMINATION_LEN         (9U)
+#define EIGRP_TLV_PEER_TIDLIST          (EIGRP_TLV_GENERAL | 0x0008)    /*!< peer sub-topology list */
+
+/* Older cisco routers send TIDLIST value wrong, adding for backwards compatabily */
+#define EIGRP_TLV_PEER_MTRLIST          (EIGRP_TLV_GENERAL | 0x00f5)
+
+/**
+ * Route Based TLVs
+ */
+#define EIGRP_TLV_REQUEST               0x0001
+#define EIGRP_TLV_INTERNAL              0x0002
+#define EIGRP_TLV_EXTERNAL              0x0003
+#define EIGRP_TLV_COMMUNITY             0x0004
+#define EIGRP_TLV_TYPEMASK              0x000f
+
+#define EIGRP_TLV_IPv4_REQ              (EIGRP_TLV_IPv4 | EIGRP_TLV_REQUEST)
+#define EIGRP_TLV_IPv4_INT              (EIGRP_TLV_IPv4 | EIGRP_TLV_INTERNAL)
+#define EIGRP_TLV_IPv4_EXT              (EIGRP_TLV_IPv4 | EIGRP_TLV_EXTERNAL)
+#define EIGRP_TLV_IPv4_COM              (EIGRP_TLV_IPv4 | EIGRP_TLV_COMMUNITY)
+
+/* max number of TLV IPv4 prefixes in packet */
+#define EIGRP_TLV_MAX_IPv4                             25
+
+/**
+ *
+ * extdata flag field definitions
+ */
+#define EIGRP_OPAQUE_EXT        0x01    /*!< Route is external */
+#define EIGRP_OPAQUE_CD         0x02    /*!< Candidate default route */
+
+/**
+ * Address-Family types are taken from:
+ *       http://www.iana.org/assignments/address-family-numbers
+ * to provide a standards based exchange of AFI information between
+ * EIGRP routers.
+ */
+#define EIGRP_AF_IPv4           1       /*!< IPv4 (IP version 4) */
+#define EIGRP_AF_IPv6           2       /*!< IPv6 (IP version 6) */
+#define EIGRP_AF_IPX            11      /*!< IPX */
+#define EIGRP_AF_ATALK          12      /*!< Appletalk */
+#define EIGRP_SF_COMMON         16384   /*!< Cisco Service Family */
+#define EIGRP_SF_IPv4           16385   /*!< Cisco IPv4 Service Family */
+#define EIGRP_SF_IPv6           16386   /*!< Cisco IPv6 Service Family */
+
+/**
+ * Authentication types supported by EIGRP
+ */
+#define EIGRP_AUTH_TYPE_NONE            0
+#define EIGRP_AUTH_TYPE_TEXT            1
+#define EIGRP_AUTH_TYPE_MD5             2
+#define EIGRP_AUTH_TYPE_MD5_LEN         16
+#define EIGRP_AUTH_TYPE_SHA256          3
+#define EIGRP_AUTH_TYPE_SHA256_LEN      32
+
+/**
+ * opaque flag field definitions
+ */
+#define EIGRP_OPAQUE_SRCWD      0x01    /*!< Route Source Withdraw */
+#define EIGRP_OPAQUE_ACTIVE     0x04    /*!< Route is currently in active state */
+#define EIGRP_OPAQUE_REPL       0x08    /*!< Route is replicated from different tableid */
+
+/**
+ * pak flag bit field definitions - 0 (none)-7 source priority
+ */
+#define EIGRP_PRIV_DEFAULT      0x00    /* 0 (none)-7 source priority */
+#define EIGRP_PRIV_LOW          0x01
+#define EIGRP_PRIV_MEDIUM       0x04
+#define EIGRP_PRIV_HIGH         0x07
+
+/*
+ * Init bit definition. First unicast transmitted Update has this
+ * bit set in the flags field of the fixed header. It tells the neighbor
+ * to down-load his topology table.
+ */
+#define EIGRP_INIT_FLAG 0x01
+
+/*
+ * CR bit (Conditionally Received) definition in flags field on header. Any
+ * packets with the CR-bit set can be accepted by an EIGRP speaker if and
+ * only if a previous Hello was received with the SEQUENCE_TYPE TLV present.
+ *
+ * This allows multicasts to be transmitted in order and reliably at the
+ * same time as unicasts are transmitted.
+ */
+#define EIGRP_CR_FLAG 0x02
+
+/*
+ * RS bit.  The Restart flag is set in the hello and the init
+ * update packets during the nsf signaling period.  A nsf-aware
+ * router looks at the RS flag to detect if a peer is restarting
+ * and maintain the adjacency. A restarting router looks at
+ * this flag to determine if the peer is helping out with the restart.
+ */
+#define EIGRP_RS_FLAG 0x04
+
+/*
+ * EOT bit.  The End-of-Table flag marks the end of the start-up updates
+ * sent to a new peer.  A nsf restarting router looks at this flag to
+ * determine if it has finished receiving the start-up updates from all
+ * peers.  A nsf-aware router waits for this flag before cleaning up
+ * the stale routes from the restarting peer.
+ */
+#define EIGRP_EOT_FLAG 0x08
+
+/**
+ * EIGRP Virtual Router ID
+ *
+ * Define values to deal with EIGRP virtual router ids.  Virtual
+ * router IDs are stored in the upper short of the EIGRP fixed packet
+ * header.  The lower short of the packet header continues to be used
+ * as asystem number.
+ *
+ * Virtual Router IDs are PDM-independent.  All PDMs will use
+ * VRID_BASE to indicate the 'base' or 'legacy' EIGRP instance.
+ * All PDMs need to initialize their vrid to VRID_BASE for compatibility
+ * with legacy routers.
+ * Once IPv6 supports 'MTR Multicast', it will use the same VRID as
+ * IPv4.  No current plans to support VRIDs on IPX. :)
+ * Initial usage of VRID is to signal usage of Multicast topology for
+ * MTR.
+ *
+ * VRID_MCAST is a well known constant, other VRIDs will be determined
+ * programmatic...
+ *
+ * With the addition of SAF the VRID space has been divided into two
+ * segments 0x0000-0x7fff is for EIGRP and vNets, 0x8000-0xffff is
+ * for saf and its associated vNets.
+ */
+#define EIGRP_VRID_MASK         0x8001
+#define EIGRP_VRID_AF_BASE      0x0000
+#define EIGRP_VRID_MCAST_BASE   0x0001
+#define EIGRP_VRID_SF_BASE      0x8000
+
+/* Extended Attributes for a destination */
+#define EIGRP_ATTR_HDRLEN (2)
+#define EIGRP_ATTR_MAXDATA (512)
+
+#define EIGRP_ATTR_NOOP         0       /*!< No-Op used as offset padding */
+#define EIGRP_ATTR_SCALED       1       /*!< Scaled metric values */
+#define EIGRP_ATTR_TAG          2       /*!< Tag assigned by Admin for dest */
+#define EIGRP_ATTR_COMM         3       /*!< Community attribute for dest */
+#define EIGRP_ATTR_JITTER       4       /*!< Variation in path delay */
+#define EIGRP_ATTR_QENERGY      5       /*!< Non-Active energy usage along path */
+#define EIGRP_ATTR_ENERGY       6       /*!< Active energy usage along path */
+
+/*
+ * Begin EIGRP-BGP interoperability communities
+ */
+#define EIGRP_EXTCOMM_SOO_ASFMT         0x0003 /* Site-of-Origin, BGP AS format */
+#define EIGRP_EXTCOMM_SOO_ADRFMT        0x0103 /* Site-of-Origin, BGP/EIGRP addr format */
+
+/*
+ * EIGRP Specific communities
+ */
+#define EIGRP_EXTCOMM_EIGRP             0x8800 /* EIGRP route information appended*/
+#define EIGRP_EXTCOMM_DAD               0x8801 /* EIGRP AS + Delay           */
+#define EIGRP_EXTCOMM_VRHB              0x8802 /* EIGRP Vector: Reliability + Hop + BW */
+#define EIGRP_EXTCOMM_SRLM              0x8803 /* EIGRP System: Reserve +Load + MTU   */
+#define EIGRP_EXTCOMM_SAR               0x8804 /* EIGRP System: Remote AS + Remote ID  */
+#define EIGRP_EXTCOMM_RPM               0x8805 /* EIGRP Remote: Protocol + Metric    */
+#define EIGRP_EXTCOMM_VRR               0x8806 /* EIGRP Vecmet: Rsvd + (internal) Routerid */
+
+
+/*
+ * EIGRP Filter constants
+ */
+#define EIGRP_FILTER_IN  0
+#define EIGRP_FILTER_OUT 1
+#define EIGRP_FILTER_MAX 2
+
+/*
+ * EIGRP Filter constants
+ */
+#define EIGRP_HSROLE_DEFAULT   EIGRP_HSROLE_SPOKE
+#define EIGRP_HSROLE_HUB               0x01
+#define EIGRP_HSROLE_SPOKE             0x02
+
+#endif /* _ZEBRA_EIGRP_CONST_H_ */
diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c
new file mode 100644 (file)
index 0000000..21bef48
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * 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. */
+
+  /* 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;
+  }
+
+  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 = eigrp->router_id;
+
+  vty_out (vty, "%sEIGRP Topology Table for AS(%d)/ID(%s)%s%s",
+           VTY_NEWLINE, eigrp->AS, inet_ntoa(router_id), VTY_NEWLINE, VTY_NEWLINE);
+  vty_out (vty, "Codes: P - Passive, A - Active, U - Update, Q - Query, "
+           "R - Reply%s       r - reply Status, s - sia Status%s%s",
+           VTY_NEWLINE, VTY_NEWLINE,VTY_NEWLINE);
+}
+
+void
+show_ip_eigrp_prefix_entry (struct vty *vty, struct eigrp_prefix_entry *tn)
+{
+  vty_out (vty, "%-3c",(tn->state > 0) ? 'A' : 'P');
+  vty_out (vty, "%s/%u, ",inet_ntoa (tn->destination_ipv4->prefix),tn->destination_ipv4->prefixlen);
+  vty_out (vty, "%u successors, ",eigrp_topology_get_successor(tn)->count);
+  vty_out (vty, "FD is %u, serno: %lu %s",tn->fdistance, tn->serno, VTY_NEWLINE);
+}
+
+void
+show_ip_eigrp_neighbor_entry (struct vty *vty, struct eigrp *eigrp, struct eigrp_neighbor_entry *te)
+{
+  if (te->adv_router == eigrp->neighbor_self)
+    vty_out (vty, "%-7s%s, %s%s", " ", "via Connected",
+             eigrp_if_name_string (te->ei), VTY_NEWLINE);
+  else
+    {
+      vty_out (vty, "%-7s%s%s (%u/%u), %s%s",
+               " ", "via ", inet_ntoa (te->adv_router->src),
+               te->distance, te->reported_distance,
+               eigrp_if_name_string (te->ei), VTY_NEWLINE);
+    }
+}
+
+
+DEFUN (show_debugging_eigrp,
+       show_debugging_eigrp_cmd,
+       "show debugging eigrp",
+       SHOW_STR
+       DEBUG_STR
+       EIGRP_STR)
+{
+  int i;
+
+  vty_out (vty, "EIGRP debugging status:%s", VTY_NEWLINE);
+
+  /* Show debug status for events. */
+  if (IS_DEBUG_EIGRP(event,EVENT))
+    vty_out (vty, "  EIGRP event debugging is on%s", VTY_NEWLINE);
+
+  /* Show debug status for EIGRP Packets. */
+  for (i = 0; i < 11 ; i++)
+    {
+      if (i == 8)
+        continue;
+
+      if (IS_DEBUG_EIGRP_PACKET (i, SEND) && IS_DEBUG_EIGRP_PACKET (i, RECV))
+        {
+          vty_out (vty, "  EIGRP packet %s%s debugging is on%s",
+                   LOOKUP (eigrp_packet_type_str, i + 1),
+                   IS_DEBUG_EIGRP_PACKET (i, PACKET_DETAIL) ? " detail" : "",
+                   VTY_NEWLINE);
+        }
+      else
+        {
+          if (IS_DEBUG_EIGRP_PACKET (i, SEND))
+            vty_out (vty, "  EIGRP packet %s send%s debugging is on%s",
+                     LOOKUP (eigrp_packet_type_str, i + 1),
+                     IS_DEBUG_EIGRP_PACKET (i, PACKET_DETAIL) ? " detail" : "",
+                     VTY_NEWLINE);
+          if (IS_DEBUG_EIGRP_PACKET (i, RECV))
+            vty_out (vty, "  EIGRP packet %s receive%s debugging is on%s",
+                     LOOKUP (eigrp_packet_type_str, i + 1),
+                     IS_DEBUG_EIGRP_PACKET (i, PACKET_DETAIL) ? " detail" : "",
+                     VTY_NEWLINE);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+
+/*
+  [no] debug eigrp packet (hello|dd|ls-request|ls-update|ls-ack|all)
+  [send|recv [detail]]
+*/
+
+DEFUN (debug_eigrp_transmit,
+       debug_eigrp_transmit_cmd,
+       "debug eigrp transmit <send|recv|all> [detail]",
+       DEBUG_STR
+       EIGRP_STR
+       "EIGRP transmission events\n"
+       "packet sent\n"
+       "packet received\n"
+       "all packets\n"
+       "Detailed Information\n")
+{
+  int flag = 0;
+  int idx = 2;
+
+  /* send or recv. */
+  if (argv_find (argv, argc, "send", &idx))
+    flag = EIGRP_DEBUG_SEND;
+  else if (argv_find (argv, argc, "recv", &idx))
+    flag = EIGRP_DEBUG_RECV;
+  else if (argv_find (argv, argc, "all", &idx) == 0)
+    flag = EIGRP_DEBUG_SEND_RECV;
+
+  /* detail option */
+  if (argv_find (argv, argc, "detail", &idx) == 0)
+    flag = EIGRP_DEBUG_PACKET_DETAIL;
+
+  if (vty->node == CONFIG_NODE)
+    DEBUG_TRANSMIT_ON (0, flag);
+  else
+    TERM_DEBUG_TRANSMIT_ON (0, flag);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_eigrp_transmit,
+       no_debug_eigrp_transmit_cmd,
+       "no debug eigrp transmit <send|recv|all> [detail]",
+       NO_STR
+       UNDEBUG_STR
+       EIGRP_STR
+       "EIGRP transmission events\n"
+       "packet sent\n"
+       "packet received\n"
+       "all packets\n"
+       "Detailed Information\n")
+{
+  int flag = 0;
+  int idx = 3;
+
+  /* send or recv. */
+  if (argv_find (argv, argc, "send", &idx) == 0)
+    flag = EIGRP_DEBUG_SEND;
+  else if (argv_find (argv, argc, "recv", &idx) == 0)
+    flag = EIGRP_DEBUG_RECV;
+  else if (argv_find (argv, argc, "all", &idx) == 0)
+    flag = EIGRP_DEBUG_SEND_RECV;
+
+  /* detail option */
+  if (argv_find (argv, argc, "detail", &idx) == 0)
+    flag = EIGRP_DEBUG_PACKET_DETAIL;
+
+  if (vty->node == CONFIG_NODE)
+    DEBUG_TRANSMIT_OFF (0, flag);
+  else
+    TERM_DEBUG_TRANSMIT_OFF (0, flag);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_eigrp_packets,
+       debug_eigrp_packets_all_cmd,
+       "debug eigrp packets <siaquery|siareply|ack|hello|probe|query|reply|request|retry|stub|terse|update|all> [send|receive] [detail]",
+       DEBUG_STR
+       EIGRP_STR
+       "EIGRP packets\n"
+       "EIGRP SIA-Query packets\n"
+       "EIGRP SIA-Reply packets\n"
+       "EIGRP ack packets\n"
+       "EIGRP hello packets\n"
+       "EIGRP probe packets\n"
+       "EIGRP query packets\n"
+       "EIGRP reply packets\n"
+       "EIGRP request packets\n"
+       "EIGRP retransmissions\n"
+       "EIGRP stub packets\n"
+       "Display all EIGRP packets except Hellos\n"
+       "EIGRP update packets\n"
+       "Display all EIGRP packets\n"
+       "Send Packets\n"
+       "Receive Packets\n"
+       "Detail Information\n")
+{
+  int type = 0;
+  int flag = 0;
+  int i;
+  int idx = 0;
+
+  /* Check packet type. */
+  if (argv_find (argv, argc, "hello", &idx) == 0)
+    type = EIGRP_DEBUG_HELLO;
+  if (argv_find (argv, argc, "update", &idx) == 0)
+    type = EIGRP_DEBUG_UPDATE;
+  if (argv_find (argv, argc, "query", &idx) == 0)
+    type = EIGRP_DEBUG_QUERY;
+  if (argv_find (argv, argc, "ack", &idx) == 0)
+    type = EIGRP_DEBUG_ACK;
+  if (argv_find (argv, argc, "probe", &idx) == 0)
+    type = EIGRP_DEBUG_PROBE;
+  if (argv_find (argv, argc, "stub", &idx) == 0)
+    type = EIGRP_DEBUG_STUB;
+  if (argv_find (argv, argc, "reply", &idx) == 0)
+    type = EIGRP_DEBUG_REPLY;
+  if (argv_find (argv, argc, "request", &idx) == 0)
+    type = EIGRP_DEBUG_REQUEST;
+  if (argv_find (argv, argc, "siaquery", &idx) == 0)
+    type = EIGRP_DEBUG_SIAQUERY;
+  if (argv_find (argv, argc, "siareply", &idx) == 0)
+    type = EIGRP_DEBUG_SIAREPLY;
+  if (argv_find (argv, argc, "all", &idx) == 0)
+     type = EIGRP_DEBUG_PACKETS_ALL;
+
+
+  /* All packet types, both send and recv. */
+  flag = EIGRP_DEBUG_SEND_RECV;
+
+  /* send or recv. */
+  if (argv_find (argv, argc, "s", &idx) == 0)
+    flag = EIGRP_DEBUG_SEND;
+  else if (argv_find (argv, argc, "r", &idx) == 0)
+    flag = EIGRP_DEBUG_RECV;
+
+  /* detail. */
+  if (argv_find (argv, argc, "detail", &idx) == 0)
+    flag |= EIGRP_DEBUG_PACKET_DETAIL;
+
+  for (i = 0; i < 11; i++)
+    if (type & (0x01 << i))
+      {
+        if (vty->node == CONFIG_NODE)
+          DEBUG_PACKET_ON (i, flag);
+        else
+          TERM_DEBUG_PACKET_ON (i, flag);
+      }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_eigrp_packets,
+       no_debug_eigrp_packets_all_cmd,
+       "no debug eigrp packets <siaquery|siareply|ack|hello|probe|query|reply|request|retry|stub|terse|update|all> [send|receive] [detail]",
+       NO_STR
+       UNDEBUG_STR
+       EIGRP_STR
+       "EIGRP packets\n"
+       "EIGRP SIA-Query packets\n"
+       "EIGRP SIA-Reply packets\n"
+       "EIGRP ack packets\n"
+       "EIGRP hello packets\n"
+       "EIGRP probe packets\n"
+       "EIGRP query packets\n"
+       "EIGRP reply packets\n"
+       "EIGRP request packets\n"
+       "EIGRP retransmissions\n"
+       "EIGRP stub packets\n"
+       "Display all EIGRP packets except Hellos\n"
+       "EIGRP update packets\n"
+       "Display all EIGRP packets\n"
+       "Send Packets\n"
+       "Receive Packets\n"
+       "Detailed Information\n")
+{
+ int type = 0;
+ int flag = 0;
+ int i;
+ int idx = 0;
+
+ /* Check packet type. */
+ if (argv_find (argv, argc, "hello", &idx) == 0)
+   type = EIGRP_DEBUG_HELLO;
+ if (argv_find (argv, argc, "update", &idx) == 0)
+   type = EIGRP_DEBUG_UPDATE;
+ if (argv_find (argv, argc, "query", &idx) == 0)
+   type = EIGRP_DEBUG_QUERY;
+ if (argv_find (argv, argc, "ack", &idx) == 0)
+   type = EIGRP_DEBUG_ACK;
+ if (argv_find (argv, argc, "probe", &idx) == 0)
+   type = EIGRP_DEBUG_PROBE;
+ if (argv_find (argv, argc, "stub", &idx) == 0)
+   type = EIGRP_DEBUG_STUB;
+ if (argv_find (argv, argc, "reply", &idx) == 0)
+   type = EIGRP_DEBUG_REPLY;
+ if (argv_find (argv, argc, "request", &idx) == 0)
+   type = EIGRP_DEBUG_REQUEST;
+ if (argv_find (argv, argc, "siaquery", &idx) == 0)
+   type = EIGRP_DEBUG_SIAQUERY;
+ if (argv_find (argv, argc, "siareply", &idx) == 0)
+   type = EIGRP_DEBUG_SIAREPLY;
+
+ /* Default, both send and recv. */
+ flag = EIGRP_DEBUG_SEND_RECV;
+
+ /* send or recv. */
+ if (argv_find (argv, argc, "send", &idx) == 0)
+   flag = EIGRP_DEBUG_SEND;
+ else if (argv_find (argv, argc, "reply", &idx) == 0)
+   flag = EIGRP_DEBUG_RECV;
+
+ /* detail. */
+ if (argv_find (argv, argc, "detail", &idx) == 0)
+   flag |= EIGRP_DEBUG_PACKET_DETAIL;
+
+ for (i = 0; i < 11; i++)
+   if (type & (0x01 << i))
+     {
+       if (vty->node == CONFIG_NODE)
+         DEBUG_PACKET_OFF (i, flag);
+       else
+         TERM_DEBUG_PACKET_OFF (i, flag);
+     }
+
+ return CMD_SUCCESS;
+}
+
+/* Debug node. */
+static struct cmd_node eigrp_debug_node =
+{
+  DEBUG_NODE,
+  "",
+  1 /* VTYSH */
+};
+
+/* Initialize debug commands. */
+void
+eigrp_debug_init ()
+{
+  install_node (&eigrp_debug_node, config_write_debug);
+
+  install_element (ENABLE_NODE, &show_debugging_eigrp_cmd);
+  install_element (ENABLE_NODE, &debug_eigrp_packets_all_cmd);
+  install_element (ENABLE_NODE, &no_debug_eigrp_packets_all_cmd);
+  install_element (ENABLE_NODE, &debug_eigrp_transmit_cmd);
+  install_element (ENABLE_NODE, &no_debug_eigrp_transmit_cmd);
+
+  install_element (CONFIG_NODE, &show_debugging_eigrp_cmd);
+  install_element (CONFIG_NODE, &debug_eigrp_packets_all_cmd);
+  install_element (CONFIG_NODE, &no_debug_eigrp_packets_all_cmd);
+  install_element (CONFIG_NODE, &no_debug_eigrp_transmit_cmd);
+}
+
+
diff --git a/eigrpd/eigrp_dump.h b/eigrpd/eigrp_dump.h
new file mode 100644 (file)
index 0000000..54e6338
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * EIGRP Dump Functions and Debbuging.
+ * Copyright (C) 2013-2014
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRPD_DUMP_H_
+#define _ZEBRA_EIGRPD_DUMP_H_
+
+#define EIGRP_TIME_DUMP_SIZE           16
+
+/* general debug flags */
+extern unsigned long term_debug_eigrp;
+#define EIGRP_DEBUG_EVENT              0x01
+#define EIGRP_DEBUG_DETAIL             0x02
+#define EIGRP_DEBUG_TIMERS             0x04
+
+/* neighbor debug flags */
+extern unsigned long term_debug_eigrp_nei;
+#define EIGRP_DEBUG_NEI                                0x01
+
+/* packet debug flags */
+extern unsigned long term_debug_eigrp_packet[];
+#define EIGRP_DEBUG_UPDATE                     0x01
+#define EIGRP_DEBUG_REQUEST                    0x02
+#define EIGRP_DEBUG_QUERY                      0x04
+#define EIGRP_DEBUG_REPLY                      0x08
+#define EIGRP_DEBUG_HELLO                      0x10
+#define EIGRP_DEBUG_PROBE                      0x40
+#define EIGRP_DEBUG_ACK                        0x80
+#define EIGRP_DEBUG_SIAQUERY       0x200
+#define EIGRP_DEBUG_SIAREPLY       0x400
+#define EIGRP_DEBUG_STUB                       0x800
+#define EIGRP_DEBUG_PACKETS_ALL     0xfff
+
+extern unsigned long term_debug_eigrp_transmit;
+#define EIGRP_DEBUG_SEND                       0x01
+#define EIGRP_DEBUG_RECV                       0x02
+#define EIGRP_DEBUG_SEND_RECV          0x03
+#define EIGRP_DEBUG_PACKET_DETAIL      0x04
+
+/* zebra debug flags */
+extern unsigned long term_debug_eigrp_zebra;
+#define EIGRP_DEBUG_ZEBRA_INTERFACE    0x01
+#define EIGRP_DEBUG_ZEBRA_REDISTRIBUTE 0x02
+#define EIGRP_DEBUG_ZEBRA              0x03
+
+/* Macro for setting debug option. */
+#define CONF_DEBUG_NEI_ON(a, b)                conf_debug_eigrp_nei[a] |= (b)
+#define CONF_DEBUG_NEI_OFF(a, b)       conf_debug_eigrp_nei[a] &= ~(b)
+#define TERM_DEBUG_NEI_ON(a, b)                term_debug_eigrp_nei[a] |= (b)
+#define TERM_DEBUG_NEI_OFF(a, b)       term_debug_eigrp_nei[a] &= ~(b)
+#define DEBUG_NEI_ON(a, b) \
+    do { \
+      CONF_DEBUG_NEI_ON(a, b); \
+      TERM_DEBUG_NEI_ON(a, b); \
+    } while (0)
+#define DEBUG_NEI_OFF(a, b) \
+    do { \
+      CONF_DEBUG_NEI_OFF(a, b); \
+      TERM_DEBUG_NEI_OFF(a, b); \
+    } while (0)
+
+#define CONF_DEBUG_PACKET_ON(a, b)     conf_debug_eigrp_packet[a] |= (b)
+#define CONF_DEBUG_PACKET_OFF(a, b)    conf_debug_eigrp_packet[a] &= ~(b)
+#define TERM_DEBUG_PACKET_ON(a, b)     term_debug_eigrp_packet[a] |= (b)
+#define TERM_DEBUG_PACKET_OFF(a, b)    term_debug_eigrp_packet[a] &= ~(b)
+#define DEBUG_PACKET_ON(a, b) \
+    do { \
+      CONF_DEBUG_PACKET_ON(a, b); \
+      TERM_DEBUG_PACKET_ON(a, b); \
+    } while (0)
+#define DEBUG_PACKET_OFF(a, b) \
+    do { \
+      CONF_DEBUG_PACKET_OFF(a, b); \
+      TERM_DEBUG_PACKET_OFF(a, b); \
+    } while (0)
+
+#define CONF_DEBUG_TRANSMIT_ON(a, b)   conf_debug_eigrp_transmit |= (b)
+#define CONF_DEBUG_TRANSMIT_OFF(a, b)  conf_debug_eigrp_transmit &= ~(b)
+#define TERM_DEBUG_TRANSMIT_ON(a, b)   term_debug_eigrp_transmit |= (b)
+#define TERM_DEBUG_TRANSMIT_OFF(a, b)  term_debug_eigrp_transmit &= ~(b)
+#define DEBUG_TRANSMIT_ON(a, b) \
+    do { \
+      CONF_DEBUG_TRANSMIT_ON(a, b); \
+      TERM_DEBUG_TRANSMIT_ON(a, b); \
+    } while (0)
+#define DEBUG_TRANSMIT_OFF(a, b) \
+    do { \
+      CONF_DEBUG_TRANSMIT_OFF(a, b); \
+      TERM_DEBUG_TRANSMIT_OFF(a, b); \
+    } while (0)
+
+#define CONF_DEBUG_ON(a, b)            conf_debug_eigrp_ ## a |= (EIGRP_DEBUG_ ## b)
+#define CONF_DEBUG_OFF(a, b)           conf_debug_eigrp_ ## a &= ~(EIGRP_DEBUG_ ## b)
+#define TERM_DEBUG_ON(a, b)            term_debug_eigrp_ ## a |= (EIGRP_DEBUG_ ## b)
+#define TERM_DEBUG_OFF(a, b)           term_debug_eigrp_ ## a &= ~(EIGRP_DEBUG_ ## b)
+#define DEBUG_ON(a, b) \
+     do { \
+       CONF_DEBUG_ON(a, b); \
+       TERM_DEBUG_ON(a, b); \
+     } while (0)
+#define DEBUG_OFF(a, b) \
+     do { \
+       CONF_DEBUG_OFF(a, b); \
+       TERM_DEBUG_OFF(a, b); \
+     } while (0)
+
+/* Macro for checking debug option. */
+#define IS_DEBUG_EIGRP_PACKET(a, b) \
+       (term_debug_eigrp_packet[a] & EIGRP_DEBUG_ ## b)
+#define IS_DEBUG_EIGRP_TRANSMIT(a, b) \
+        (term_debug_eigrp_transmit & EIGRP_DEBUG_ ## b)
+#define IS_DEBUG_EIGRP_NEI(a, b) \
+       (term_debug_eigrp_nei & EIGRP_DEBUG_ ## b)
+#define IS_DEBUG_EIGRP(a, b) \
+       (term_debug_eigrp & EIGRP_DEBUG_ ## b)
+#define IS_DEBUG_EIGRP_EVENT IS_DEBUG_EIGRP(event, EVENT)
+
+
+/* Prototypes. */
+extern const char *eigrp_if_name_string (struct eigrp_interface *);
+extern const char *eigrp_if_ip_string (struct eigrp_interface *);
+extern const char *eigrp_neigh_ip_string (struct eigrp_neighbor *);
+extern const char *eigrp_topology_ip_string (struct eigrp_prefix_entry *);
+
+extern void eigrp_ip_header_dump(struct ip *);
+extern void eigrp_header_dump(struct eigrp_header *);
+
+extern void show_ip_eigrp_interface_header (struct vty *, struct eigrp *);
+extern void show_ip_eigrp_neighbor_header (struct vty *, struct eigrp *);
+extern void show_ip_eigrp_topology_header (struct vty *, struct eigrp *);
+extern void show_ip_eigrp_interface_detail (struct vty *, struct eigrp *,
+                                        struct eigrp_interface *);
+extern void show_ip_eigrp_interface_sub (struct vty *, struct eigrp *,
+                                        struct eigrp_interface *);
+extern void show_ip_eigrp_neighbor_sub (struct vty *, struct eigrp_neighbor *, int);
+extern void show_ip_eigrp_prefix_entry (struct vty *, struct eigrp_prefix_entry *);
+extern void show_ip_eigrp_neighbor_entry (struct vty *, struct eigrp *, struct eigrp_neighbor_entry *);
+
+extern void eigrp_debug_init (void);
+
+#endif /* _ZEBRA_EIGRPD_DUMP_H_ */
diff --git a/eigrpd/eigrp_filter.c b/eigrpd/eigrp_filter.c
new file mode 100644 (file)
index 0000000..236c53a
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * 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, VRF_DEFAULT);
+  if (ifp == NULL)
+    return;
+
+  zlog_info("<DEBUG ACL 2");
+
+  /*struct eigrp_if_info * info = ifp->info;
+  ei = info->eigrp_interface;*/
+  struct listnode *node, *nnode;
+  struct eigrp_interface *ei2;
+  /* Find proper interface */
+  for (ALL_LIST_ELEMENTS (e->eiflist, node, nnode, ei2))
+  {
+    if(strcmp(ei2->ifp->name,ifp->name) == 0){
+      ei = ei2;
+      break;
+    }
+  }
+
+  if(ei == NULL)
+    {
+      zlog_info("Not Found eigrp interface %s",ifp->name);
+    }
+
+  /* Access-list for interface in */
+  if (dist->list[DISTRIBUTE_V4_IN])
+    {
+      zlog_info("<DEBUG ACL in");
+      alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_IN]);
+      if (alist){
+        ei->list[EIGRP_FILTER_IN] = alist;
+      }
+      else
+        ei->list[EIGRP_FILTER_IN] = NULL;
+    }
+  else
+  {
+    ei->list[EIGRP_FILTER_IN] = NULL;
+  }
+
+  /* Access-list for interface in */
+  if (dist->list[DISTRIBUTE_V4_OUT])
+    {
+      alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_OUT]);
+      if (alist)
+        ei->list[EIGRP_FILTER_OUT] = alist;
+      else
+        ei->list[EIGRP_FILTER_OUT] = NULL;
+
+    }
+  else
+    {
+      ei->list[EIGRP_FILTER_OUT] = NULL;
+      zlog_info("<DEBUG ACL out else");
+    }
+
+  /* Prefix-list for interface in */
+  if (dist->prefix[DISTRIBUTE_V4_IN])
+    {
+      plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_IN]);
+      if (plist)
+        ei->prefix[EIGRP_FILTER_IN] = plist;
+      else
+        ei->prefix[EIGRP_FILTER_IN] = NULL;
+    }
+  else
+    ei->prefix[EIGRP_FILTER_IN] = NULL;
+
+  /* Prefix-list for interface out */
+  if (dist->prefix[DISTRIBUTE_V4_OUT])
+    {
+      plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_OUT]);
+      if (plist)
+        ei->prefix[EIGRP_FILTER_OUT] = plist;
+      else
+        ei->prefix[EIGRP_FILTER_OUT] = NULL;
+    }
+  else
+    ei->prefix[EIGRP_FILTER_OUT] = NULL;
+
+#if 0
+  /* route-map IN for whole process */
+  if (dist->route[DISTRIBUTE_V4_IN])
+    {
+      zlog_info("<DEBUG ACL ALL in");
+      routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_IN]);
+      if (routemap)
+        ei->routemap[EIGRP_FILTER_IN] = routemap;
+      else
+        ei->routemap[EIGRP_FILTER_IN] = NULL;
+    }
+  else
+    {
+      ei->routemap[EIGRP_FILTER_IN] = NULL;
+    }
+
+  /* route-map OUT for whole process */
+  if (dist->route[DISTRIBUTE_V4_OUT])
+    {
+      routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_OUT]);
+      if (routemap)
+        ei->routemap[EIGRP_FILTER_OUT] = routemap;
+      else
+        ei->routemap[EIGRP_FILTER_OUT] = NULL;
+    }
+  else
+    {
+      ei->routemap[EIGRP_FILTER_OUT] = NULL;
+    }
+#endif
+  //TODO: check Graceful restart after 10sec
+
+  /* check if there is already GR scheduled */
+  if(ei->t_distribute != NULL)
+    {
+      /* if is, cancel schedule */
+      thread_cancel(ei->t_distribute);
+    }
+  /* schedule Graceful restart for interface in 10sec */
+  e->t_distribute = thread_add_timer(master, eigrp_distribute_timer_interface, ei, 10);
+}
+
+/*
+ * Function called by prefix-list and access-list update
+ */
+void
+eigrp_distribute_update_interface (struct interface *ifp)
+{
+  struct distribute *dist;
+
+  dist = distribute_lookup (ifp->name);
+  if (dist)
+    eigrp_distribute_update (dist);
+}
+
+/* Update all interface's distribute list.
+ * Function used in hook for prefix-list
+ */
+void
+eigrp_distribute_update_all (struct prefix_list *notused)
+{
+  struct interface *ifp;
+  struct listnode *node, *nnode;
+
+  for (ALL_LIST_ELEMENTS (vrf_iflist(VRF_DEFAULT), node, nnode, ifp))
+    eigrp_distribute_update_interface (ifp);
+}
+
+/*
+ * Function used in hook for acces-list
+ */
+void
+eigrp_distribute_update_all_wrapper(struct access_list *notused)
+{
+  eigrp_distribute_update_all(NULL);
+}
+
+/*
+ * @fn eigrp_distribute_timer_process
+ *
+ * @param[in]   thread  current execution thread timer is associated with
+ *
+ * @return int  always returns 0
+ *
+ * @par
+ * Called when 10sec waiting time expire and
+ * executes Graceful restart for whole process
+ */
+int
+eigrp_distribute_timer_process (struct thread *thread)
+{
+  struct eigrp *eigrp;
+
+  eigrp = THREAD_ARG(thread);
+  eigrp->t_distribute = NULL;
+
+  /* execute GR for whole process */
+  eigrp_update_send_process_GR(eigrp, EIGRP_GR_FILTER, NULL);
+
+  return 0;
+}
+
+/*
+ * @fn eigrp_distribute_timer_interface
+ *
+ * @param[in]   thread  current execution thread timer is associated with
+ *
+ * @return int  always returns 0
+ *
+ * @par
+ * Called when 10sec waiting time expire and
+ * executes Graceful restart for interface
+ */
+int
+eigrp_distribute_timer_interface (struct thread *thread)
+{
+  struct eigrp_interface *ei;
+
+  ei = THREAD_ARG(thread);
+  ei->t_distribute = NULL;
+
+  /* execute GR for interface */
+  eigrp_update_send_interface_GR(ei, EIGRP_GR_FILTER, NULL);
+
+  return 0;
+}
diff --git a/eigrpd/eigrp_filter.h b/eigrpd/eigrp_filter.h
new file mode 100644 (file)
index 0000000..01c776b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * EIGRP Filter Functions.
+ * Copyright (C) 2013-2016
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *   Frantisek Gazo
+ *   Tomas Hvorkovy
+ *   Martin Kontsek
+ *   Lukas Koribsky
+ *
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef EIGRPD_EIGRP_FILTER_H_
+#define EIGRPD_EIGRP_FILTER_H_
+
+extern void eigrp_distribute_update (struct distribute *);
+extern void eigrp_distribute_update_interface (struct interface *);
+extern void eigrp_distribute_update_all (struct prefix_list *);
+extern void eigrp_distribute_update_all_wrapper(struct access_list *);
+extern int eigrp_distribute_timer_process (struct thread *);
+extern int eigrp_distribute_timer_interface (struct thread *);
+
+#endif /* EIGRPD_EIGRP_FILTER_H_ */
diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c
new file mode 100644 (file)
index 0000000..dc62edb
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * 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);
+
+  assert(successors);  // If this is NULL we have shit the bed, fun huh?
+
+  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
+    }
+
+  list_delete(successors);
+
+  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);
+
+  assert(successors);  // If this is NULL somebody poked us in the eye.
+
+  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
+    }
+
+  list_delete(successors);
+
+  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)
+    {
+      struct list *successors = eigrp_topology_get_successor(prefix);
+
+      assert(successors);  // It's like Napolean and Waterloo
+
+      eigrp_send_reply(((struct eigrp_neighbor_entry *)successors->head->data)->adv_router, prefix);
+      list_delete(successors);
+    }
+
+  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)
+{
+  struct list *successors = eigrp_topology_get_successor(msg->prefix);
+
+  assert(successors);  // Trump and his big hands
+
+  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 *)successors->head->data)->distance;
+  if (!msg->prefix->rij->count)
+    (*(NSM[msg->prefix->state][eigrp_get_fsm_event(msg)].func))(msg);
+
+
+  list_delete(successors);
+  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)
+    {
+      struct list *successors = eigrp_topology_get_successor(prefix);
+
+      assert(successors);  // Having a spoon and all you need is a knife
+
+      eigrp_send_reply(((struct eigrp_neighbor_entry *)successors->head->data)->adv_router, prefix);
+
+      list_delete(successors);
+    }
+  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;
+  struct list *successors = eigrp_topology_get_successor(prefix);
+
+  assert(successors);  // Routing without a stack
+
+  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 *) (successors->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
+    }
+
+  list_delete(successors);
+
+  return 1;
+}
+
+int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg)
+{
+  struct list *successors = eigrp_topology_get_successor(msg->prefix);
+
+  assert(successors);  // Cats and no Dogs
+
+  msg->prefix->state = EIGRP_FSM_STATE_ACTIVE_2;
+  msg->prefix->distance =
+    ((struct eigrp_neighbor_entry *) (successors->head->data))->distance;
+
+  list_delete(successors);
+  return 1;
+}
diff --git a/eigrpd/eigrp_fsm.h b/eigrpd/eigrp_fsm.h
new file mode 100644 (file)
index 0000000..0677c09
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * EIGRP Finite State Machine (DUAL).
+ * Copyright (C) 2013-2014
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_FSM_H
+#define _ZEBRA_EIGRP_FSM_H
+
+
+extern int eigrp_get_fsm_event (struct eigrp_fsm_action_message *);
+extern int eigrp_fsm_event (struct eigrp_fsm_action_message *, int);
+
+
+#endif /* _ZEBRA_EIGRP_DUAL_H */
diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c
new file mode 100644 (file)
index 0000000..240aa36
--- /dev/null
@@ -0,0 +1,779 @@
+/*
+ * 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_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, VRF_DEFAULT));
+
+          /* 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, VRF_DEFAULT));
+              eigrp_nbr_delete (nbr);
+            }
+          else
+            {
+              zlog_info ("Neighbor %s (%s) going down: Kvalue mismatch",
+                         inet_ntoa (nbr->src),ifindex2ifname (nbr->ei->ifp->ifindex, VRF_DEFAULT));
+              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, VRF_DEFAULT));
+      /* 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, VRF_DEFAULT), 
+               inet_ntoa(nbr->src));
+
+  size -= EIGRP_HEADER_LEN;
+  if (size < 0)
+    return;
+
+  tlv_header = (struct eigrp_tlv_hdr_type *)eigrph->tlv;
+
+  do {
+    type = ntohs(tlv_header->type);
+    length = ntohs(tlv_header->length);
+
+    if ((length > 0) && (length <= size))
+      {
+        if (IS_DEBUG_EIGRP_PACKET(0, RECV))
+          zlog_debug("  General TLV(%s)", LOOKUP(eigrp_general_tlv_type_str, type));
+
+        // determine what General TLV is being processed
+        switch (type)
+          {
+          case EIGRP_TLV_PARAMETER:
+            eigrp_hello_parameter_decode(nbr, tlv_header);
+            break;
+          case EIGRP_TLV_AUTH:
+            {
+              if(eigrp_hello_authentication_decode(s,tlv_header,nbr) == 0)
+                return;
+              else
+                break;
+              break;
+            }
+          case EIGRP_TLV_SEQ:
+            break;
+          case EIGRP_TLV_SW_VERSION:
+            eigrp_sw_version_decode(nbr, tlv_header);
+            break;
+         case EIGRP_TLV_NEXT_MCAST_SEQ:
+           break;
+          case EIGRP_TLV_PEER_TERMINATION:
+            eigrp_peer_termination_decode(nbr, tlv_header);
+            break;
+          case EIGRP_TLV_PEER_MTRLIST:
+         case EIGRP_TLV_PEER_TIDLIST:
+           break;
+          default:
+            break;
+          }
+      }
+
+    tlv_header = (struct eigrp_tlv_hdr_type *)(((char *)tlv_header) + length);
+    size -= length;
+
+  } while (size > 0);
+
+
+  /*If received packet is hello with Parameter TLV*/
+  if (ntohl(eigrph->ack) == 0)
+    {
+      /* increment statistics. */
+      ei->hello_in++;
+      eigrp_nbr_state_update(nbr);
+
+    }
+
+  if (IS_DEBUG_EIGRP_PACKET(0, RECV))
+    zlog_debug("Hello Packet received from %s", inet_ntoa(nbr->src));
+}
+
+/**
+ * @fn eigrp_sw_version_encode
+ *
+ * @param[in,out]      s       packet stream TLV is stored to
+ *
+ * @return u_int16_t   number of bytes added to packet stream
+ *
+ * @par
+ * Store the software version in the specified location.
+ * This consists of two bytes of OS version, and two bytes of EIGRP
+ * revision number.
+ */
+static u_int16_t
+eigrp_sw_version_encode (struct stream *s)
+{
+  u_int16_t length = EIGRP_TLV_SW_VERSION_LEN;
+
+  // setup the tlv fields
+  stream_putw(s, EIGRP_TLV_SW_VERSION);
+  stream_putw(s, length);
+
+  // encode the version of quagga we're running
+  // DVS: need to figure out a cleaner way to do this
+  stream_putc(s, 0);            //!< major os version
+  stream_putc(s, 99);           //!< minor os version
+
+  /* and the core eigrp version */
+  stream_putc(s, EIGRP_MAJOR_VERSION);
+  stream_putc(s, EIGRP_MINOR_VERSION);
+
+  return(length);
+}
+
+/**
+ * @fn eigrp_tidlist_encode
+ *
+ * @param[in,out]      s       packet stream TLV is stored to
+ *
+ * @return void
+ *
+ * @par
+ * If doing mutli-topology, then store the supported TID list.
+ * This is currently a place holder function
+ */
+static u_int16_t
+eigrp_tidlist_encode (struct stream *s)
+{
+  //u_int16_t length = EIGRP_TLV_SW_VERSION_LEN;
+  return 0;
+}
+
+/**
+ * @fn eigrp_sequence_encode
+ *
+ * @param[in,out]       s       packet stream TLV is stored to
+ *
+ * @return u_int16_t    number of bytes added to packet stream
+ *
+ * @par
+ * Part of conditional receive process
+ *
+ */
+static u_int16_t
+eigrp_sequence_encode (struct stream *s)
+{
+  u_int16_t length = EIGRP_TLV_SEQ_BASE_LEN;
+  struct eigrp *eigrp;
+  struct eigrp_interface *ei;
+  struct listnode *node, *node2, *nnode2;
+  struct eigrp_neighbor *nbr;
+  size_t backup_end, size_end;
+  int found;
+
+  eigrp = eigrp_lookup ();
+  if (eigrp == NULL)
+    {
+      return 0;
+    }
+
+  // add in the parameters TLV
+  backup_end = stream_get_endp(s);
+  stream_putw(s, EIGRP_TLV_SEQ);
+  size_end = s->endp;
+  stream_putw(s, 0x0000);
+  stream_putc(s, IPV4_MAX_BYTELEN);
+
+  found = 0;
+  for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+    {
+      for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
+        {
+          if(nbr->multicast_queue->count > 0)
+            {
+              length += (u_int16_t) stream_put_ipv4(s,nbr->src.s_addr);
+              found = 1;
+            }
+        }
+    }
+
+  if(found == 0)
+    {
+      stream_set_endp(s,backup_end);
+      return 0;
+    }
+
+  backup_end = stream_get_endp (s);
+  stream_set_endp (s,size_end);
+  stream_putw (s, length);
+  stream_set_endp (s, backup_end);
+
+  return length;
+}
+
+/**
+ * @fn eigrp_sequence_encode
+ *
+ * @param[in,out]       s       packet stream TLV is stored to
+ *
+ * @return u_int16_t    number of bytes added to packet stream
+ *
+ * @par
+ * Part of conditional receive process
+ *
+ */
+static u_int16_t
+eigrp_next_sequence_encode (struct stream *s)
+{
+  u_int16_t length = EIGRP_NEXT_SEQUENCE_TLV_SIZE;
+  struct eigrp *eigrp;
+
+  eigrp = eigrp_lookup ();
+  if (eigrp == NULL)
+    {
+      return 0;
+    }
+
+  // add in the parameters TLV
+  stream_putw(s, EIGRP_TLV_NEXT_MCAST_SEQ);
+  stream_putw(s, EIGRP_NEXT_SEQUENCE_TLV_SIZE);
+  stream_putl(s,eigrp->sequence_number+1);
+
+  return length;
+}
+
+/**
+ * @fn eigrp_hello_parameter_encode
+ *
+ * @param[in]          ei      pointer to interface hello packet came in on
+ * @param[in,out]      s       packet stream TLV is stored to
+ *
+ * @return u_int16_t   number of bytes added to packet stream
+ *
+ * @par
+ * Encode Parameter TLV, used to convey metric weights and the hold time.
+ *
+ * @usage
+ * Note the addition of K6 for the new extended metrics, and does not apply to
+ * older TLV packet formats.
+ */
+static u_int16_t
+eigrp_hello_parameter_encode (struct eigrp_interface *ei, struct stream *s, u_char flags)
+{
+  u_int16_t length = EIGRP_TLV_PARAMETER_LEN;
+
+  // add in the parameters TLV
+  stream_putw(s, EIGRP_TLV_PARAMETER);
+  stream_putw(s, EIGRP_TLV_PARAMETER_LEN);
+
+  //if graceful shutdown is needed to be announced, send all 255 in K values
+  if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN)
+    {
+      stream_putc(s, 0xff); /* K1 */
+      stream_putc(s, 0xff); /* K2 */
+      stream_putc(s, 0xff); /* K3 */
+      stream_putc(s, 0xff); /* K4 */
+      stream_putc(s, 0xff); /* K5 */
+      stream_putc(s, 0xff); /* K6 */
+    }
+  else // set k values
+    {
+      stream_putc(s, ei->eigrp->k_values[0]); /* K1 */
+      stream_putc(s, ei->eigrp->k_values[1]); /* K2 */
+      stream_putc(s, ei->eigrp->k_values[2]); /* K3 */
+      stream_putc(s, ei->eigrp->k_values[3]); /* K4 */
+      stream_putc(s, ei->eigrp->k_values[4]); /* K5 */
+      stream_putc(s, ei->eigrp->k_values[5]); /* K6 */
+    }
+
+  // and set hold time value..
+  stream_putw(s, IF_DEF_PARAMS(ei->ifp)->v_wait);
+
+  return length;
+}
+
+/**
+ * @fn eigrp_hello_encode
+ *
+ * @param[in]          ei      pointer to interface hello packet came in on
+ * @param[in]          s       packet stream TLV is stored to
+ * @param[in]          ack      if non-zero, neigbors sequence packet to ack
+ * @param[in]          flags  type of hello packet
+ * @param[in]          nbr_addr  pointer to neighbor address for Peer Termination TLV
+ *
+ * @return eigrp_packet                pointer initialize hello packet
+ *
+ * @par
+ * Allocate an EIGRP hello packet, and add in the the approperate TLVs
+ *
+ */
+static struct eigrp_packet *
+eigrp_hello_encode (struct eigrp_interface *ei, in_addr_t addr, u_int32_t ack,
+                    u_char flags, struct in_addr *nbr_addr)
+{
+  struct eigrp_packet *ep;
+  u_int16_t length = EIGRP_HEADER_LEN;
+
+  // allocate a new packet to be sent
+  ep = eigrp_packet_new(ei->ifp->mtu);
+
+  if (ep)
+    {
+      // encode common header feilds
+      eigrp_packet_header_init(EIGRP_OPC_HELLO, ei, ep->s, 0, 0, ack);
+
+      // encode Authentication TLV
+      if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
+         (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+        {
+          length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei);
+        }
+      else if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_SHA256) &&
+              (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+        {
+          length += eigrp_add_authTLV_SHA256_to_stream(ep->s,ei);
+        }
+
+      /* encode appropriate parameters to Hello packet */
+      if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN)
+        length += eigrp_hello_parameter_encode(ei, ep->s, EIGRP_HELLO_GRACEFUL_SHUTDOWN);
+      else
+        length += eigrp_hello_parameter_encode(ei, ep->s, EIGRP_HELLO_NORMAL);
+
+      // figure out the version of code we're running
+      length += eigrp_sw_version_encode(ep->s);
+
+      if(flags & EIGRP_HELLO_ADD_SEQUENCE)
+        {
+          length += eigrp_sequence_encode(ep->s);
+          length += eigrp_next_sequence_encode(ep->s);
+        }
+
+      // add in the TID list if doing multi-topology
+      length += eigrp_tidlist_encode(ep->s);
+
+      /* encode Peer Termination TLV if needed */
+      if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR)
+        length += eigrp_peer_termination_encode(ep->s, nbr_addr);
+
+      // Set packet length
+      ep->length = length;
+
+      // set soruce address for the hello packet
+      ep->dst.s_addr = addr;
+
+      if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
+         (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+        {
+          eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_BASIC_HELLO_FLAG);
+        }
+      else if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_SHA256) &&
+              (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+        {
+          eigrp_make_sha256_digest(ei,ep->s, EIGRP_AUTH_BASIC_HELLO_FLAG);
+        }
+
+      // EIGRP Checksum
+      eigrp_packet_checksum(ei, ep->s, length);
+    }
+
+  return(ep);
+}
+
+/**
+ * @fn eigrp_hello_send
+ *
+ * @param[in]          nbr     neighbor the ACK should be sent to
+ *
+ * @return void
+ *
+ * @par
+ *  Send (unicast) a hello packet with the destination address
+ *  associated with the neighbor.  The eigrp header ACK feild will be
+ *  updated to the neighbor's sequence number to acknolodge any
+ *  outstanding packets
+ */
+void
+eigrp_hello_send_ack (struct eigrp_neighbor *nbr)
+{
+  struct eigrp_packet *ep;
+
+  /* if packet succesfully created, add it to the interface queue */
+  ep = eigrp_hello_encode(nbr->ei, nbr->src.s_addr, nbr->recv_sequence_number, EIGRP_HELLO_NORMAL, NULL);
+
+  if (ep)
+    {
+      if (IS_DEBUG_EIGRP_PACKET(0, SEND))
+        zlog_debug("Queueing [Hello] Ack Seq [%u] nbr [%s]",
+                   nbr->recv_sequence_number, inet_ntoa(nbr->src));
+
+      /* Add packet to the top of the interface output queue*/
+      eigrp_fifo_push_head(nbr->ei->obuf, ep);
+
+      /* Hook thread to write packet. */
+      if (nbr->ei->on_write_q == 0)
+        {
+          listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
+          nbr->ei->on_write_q = 1;
+        }
+      if (nbr->ei->eigrp->t_write == NULL)
+        nbr->ei->eigrp->t_write =
+          thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd);
+    }
+}
+
+/**
+ * @fn eigrp_hello_send
+ *
+ * @param[in]          ei      pointer to interface hello should be sent
+ * @param[in]          flags type of hello packet
+ * @param[in]          nbr_addr  pointer to neighbor address for Peer Termination TLV
+ *
+ * @return void
+ *
+ * @par
+ * Build and enqueue a generic (multicast) periodic hello packet for
+ * sending.  If no packets are currently queues, the packet will be
+ * sent immadiatly
+ */
+void
+eigrp_hello_send (struct eigrp_interface *ei, u_char flags, struct in_addr *nbr_addr)
+{
+  struct eigrp_packet *ep = NULL;
+
+  /* If this is passive interface, do not send EIGRP Hello.
+     if ((EIGRP_IF_PASSIVE_STATUS (ei) == EIGRP_IF_PASSIVE) ||
+     (ei->type != EIGRP_IFTYPE_NBMA))
+     return;
+  */
+
+  if (IS_DEBUG_EIGRP_PACKET(0, SEND))
+    zlog_debug("Queueing [Hello] Interface(%s)", IF_NAME(ei));
+
+  /* if packet was succesfully created, then add it to the interface queue */
+  ep = eigrp_hello_encode(ei, htonl(EIGRP_MULTICAST_ADDRESS), 0, flags, nbr_addr);
+
+  if (ep)
+    {
+      // Add packet to the top of the interface output queue
+      eigrp_fifo_push_head(ei->obuf, ep);
+
+      /* Hook thread to write packet. */
+      if (ei->on_write_q == 0)
+        {
+          listnode_add(ei->eigrp->oi_write_q, ei);
+          ei->on_write_q = 1;
+        }
+
+      if (ei->eigrp->t_write == NULL)
+        {
+          if(flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN)
+            {
+              ei->eigrp->t_write =
+                thread_execute(master, eigrp_write, ei->eigrp, ei->eigrp->fd);
+            }
+          else
+            {
+              ei->eigrp->t_write =
+                thread_add_write(master, eigrp_write, ei->eigrp, ei->eigrp->fd);
+            }
+        }
+    }
+}
diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c
new file mode 100644 (file)
index 0000000..7fa135d
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ * 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)
+{
+  struct prefix_ipv4 dest_addr;
+  struct eigrp_prefix_entry *pe;
+  struct eigrp *eigrp = eigrp_lookup ();
+
+  if (source == INTERFACE_DOWN_BY_VTY)
+    {
+      THREAD_OFF (ei->t_hello);
+      eigrp_hello_send(ei,EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL);
+    }
+
+  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)
+    eigrp_prefix_entry_delete (eigrp->topology_table, pe);
+
+  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)
+{
+  uint64_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)
+{
+  uint64_t temp_scaled = scaled * (256ull * 10000000);
+
+  temp_scaled =
+    temp_scaled < EIGRP_MAX_METRIC ? temp_scaled : EIGRP_MAX_METRIC;
+
+  return (u_int32_t) temp_scaled;
+}
+
+u_int32_t
+eigrp_delay_to_scaled (u_int32_t delay)
+{
+  return delay * 256;
+}
+
+u_int32_t
+eigrp_scaled_to_delay (u_int32_t scaled)
+{
+  return scaled / 256;
+}
diff --git a/eigrpd/eigrp_interface.h b/eigrpd/eigrp_interface.h
new file mode 100644 (file)
index 0000000..c7de3b7
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * EIGRP Interface Functions.
+ * Copyright (C) 2013-2016
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *   Frantisek Gazo
+ *   Tomas Hvorkovy
+ *   Martin Kontsek
+ *   Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_INTERFACE_H_
+#define _ZEBRA_EIGRP_INTERFACE_H_
+
+/*Prototypes*/
+extern void eigrp_if_init (void);
+extern int eigrp_if_new_hook (struct interface *);
+extern int eigrp_if_delete_hook (struct interface *);
+
+extern void eigrp_del_if_params (struct eigrp_if_params *);
+extern struct eigrp_if_params *eigrp_new_if_params (void);
+extern struct eigrp_interface * eigrp_if_new (struct eigrp *, struct interface *,
+                                              struct prefix *);
+extern struct eigrp_interface * eigrp_if_table_lookup (struct interface *,
+                                                       struct prefix *);
+extern struct eigrp_if_params *eigrp_lookup_if_params (struct interface *,
+                                                struct in_addr);
+extern int eigrp_if_up (struct eigrp_interface *);
+extern void eigrp_if_stream_set (struct eigrp_interface *);
+extern void eigrp_if_set_multicast (struct eigrp_interface *);
+extern u_char eigrp_default_iftype (struct interface *);
+extern void eigrp_if_free (struct eigrp_interface *, int);
+extern int eigrp_if_down (struct eigrp_interface *);
+extern void eigrp_if_stream_unset (struct eigrp_interface *);
+
+extern struct eigrp_interface *eigrp_if_lookup_by_local_addr (struct eigrp *,
+                                                              struct interface *,
+                                                              struct in_addr);
+extern struct eigrp_interface *eigrp_if_lookup_by_name (struct eigrp *, const char *);
+struct eigrp_interface * eigrp_if_lookup_recv_if (struct eigrp *, struct in_addr,
+                                                  struct interface *);
+
+/* Simulate down/up on the interface. */
+extern void eigrp_if_reset (struct interface *);
+
+extern u_int32_t eigrp_bandwidth_to_scaled (u_int32_t);
+extern u_int32_t eigrp_scaled_to_bandwidth (u_int32_t);
+extern u_int32_t eigrp_delay_to_scaled (u_int32_t);
+extern u_int32_t eigrp_scaled_to_delay (u_int32_t);
+
+
+#endif /* ZEBRA_EIGRP_INTERFACE_H_ */
diff --git a/eigrpd/eigrp_macros.h b/eigrpd/eigrp_macros.h
new file mode 100644 (file)
index 0000000..dd22829
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * EIGRP Macros Definition.
+ * Copyright (C) 2013-2014
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_MACROS_H_
+#define _ZEBRA_EIGRP_MACROS_H_
+
+#define DECLARE_IF_PARAM(T, P) T P; u_char P##__config:1
+#define IF_EIGRP_IF_INFO(I) ((struct eigrp_if_info *)((I)->info))
+#define IF_OIFS(I)  (IF_EIGRP_IF_INFO (I)->eifs)
+#define IF_OIFS_PARAMS(I) (IF_EIGRP_IF_INFO (I)->params)
+
+#define SET_IF_PARAM(S, P) ((S)->P##__config) = 1
+#define IF_DEF_PARAMS(I) (IF_EIGRP_IF_INFO (I)->def_params)
+
+#define UNSET_IF_PARAM(S, P) ((S)->P##__config) = 0
+
+#define EIGRP_IF_PARAM_CONFIGURED(S, P) ((S) && (S)->P##__config)
+#define EIGRP_IF_PARAM(O, P) \
+        (EIGRP_IF_PARAM_CONFIGURED ((O)->params, P)?\
+                        (O)->params->P:IF_DEF_PARAMS((O)->ifp)->P)
+
+#define EIGRP_IF_PASSIVE_STATUS(O) \
+       (EIGRP_IF_PARAM_CONFIGURED((O)->params, passive_interface) ? \
+         (O)->params->passive_interface : \
+         (EIGRP_IF_PARAM_CONFIGURED(IF_DEF_PARAMS((O)->ifp), passive_interface) ? \
+           IF_DEF_PARAMS((O)->ifp)->passive_interface : \
+           (O)->eigrp->passive_interface_default))
+
+//------------------------------------------------------------------------------------------------------------------------------------
+
+#define EIGRP_IF_STRING_MAXLEN  40
+#define IF_NAME(I)      eigrp_if_name_string ((I))
+
+//------------------------------------------------------------------------------------------------------------------------------------
+
+/*Macros for EIGRP interface multicast membership*/
+#define EI_MEMBER_FLAG(M) (1 << (M))
+#define EI_MEMBER_COUNT(O,M) (IF_EIGRP_IF_INFO(ei->ifp)->membership_counts[(M)])
+#define EI_MEMBER_CHECK(O,M) \
+    (CHECK_FLAG((O)->multicast_memberships, EI_MEMBER_FLAG(M)))
+#define EI_MEMBER_JOINED(O,M) \
+  do { \
+    SET_FLAG ((O)->multicast_memberships, EI_MEMBER_FLAG(M)); \
+    IF_EIGRP_IF_INFO((O)->ifp)->membership_counts[(M)]++; \
+  } while (0)
+#define EI_MEMBER_LEFT(O,M) \
+  do { \
+    UNSET_FLAG ((O)->multicast_memberships, EI_MEMBER_FLAG(M)); \
+    IF_EIGRP_IF_INFO((O)->ifp)->membership_counts[(M)]--; \
+  } while (0)
+
+//-----------------------------------------------------------------------------------------------------------------------------------
+/* Topology Macros */
+
+
+/* FSM macros*/
+#define EIGRP_FSM_EVENT_SCHEDULE(I,E) \
+      thread_add_event (master, eigrp_fsm_event, (I), (E))
+
+#endif /* _ZEBRA_EIGRP_MACROS_H_ */
diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c
new file mode 100644 (file)
index 0000000..6a5e3b1
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * EIGRP Main Routine.
+ * Copyright (C) 2013-2015
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *   Frantisek Gazo
+ *   Tomas Hvorkovy
+ *   Martin Kontsek
+ *   Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <zebra.h>
+
+#include <lib/version.h>
+#include "getopt.h"
+#include "thread.h"
+#include "prefix.h"
+#include "linklist.h"
+#include "if.h"
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "filter.h"
+#include "plist.h"
+#include "stream.h"
+#include "log.h"
+#include "memory.h"
+#include "privs.h"
+#include "sigevent.h"
+#include "zclient.h"
+#include "keychain.h"
+#include "distribute.h"
+#include "libfrr.h"
+//#include "routemap.h"
+//#include "if_rmap.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_snmp.h"
+#include "eigrpd/eigrp_filter.h"
+//#include "eigrpd/eigrp_routemap.h"
+
+/* eigprd privileges */
+zebra_capabilities_t _caps_p [] = 
+{
+  ZCAP_NET_RAW,
+  ZCAP_BIND,
+  ZCAP_NET_ADMIN,
+};
+
+struct zebra_privs_t eigrpd_privs =
+{
+#if defined (FRR_USER) && defined (FRR_GROUP)
+  .user = FRR_USER,
+  .group = FRR_GROUP,
+#endif
+#if defined (VTY_GROUP)
+  .vty_group = VTY_GROUP,
+#endif
+  .caps_p = _caps_p,
+  .cap_num_p = array_size (_caps_p),
+  .cap_num_i = 0
+};
+
+/* EIGRPd options. */
+struct option longopts[] =
+  {
+    { 0 }
+  };
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* SIGHUP handler. */
+static void 
+sighup (void)
+{
+  zlog_info ("SIGHUP received");
+}
+
+/* SIGINT / SIGTERM handler. */
+static void
+sigint (void)
+{
+  zlog_notice ("Terminating on signal");
+  eigrp_terminate ();
+}
+
+/* SIGUSR1 handler. */
+static void
+sigusr1 (void)
+{
+  zlog_rotate ();
+}
+
+struct quagga_signal_t eigrp_signals[] =
+{
+  {
+    .signal = SIGHUP,
+    .handler = &sighup,
+  },
+  {
+    .signal = SIGUSR1,
+    .handler = &sigusr1,
+  },  
+  {
+    .signal = SIGINT,
+    .handler = &sigint,
+  },
+  {
+    .signal = SIGTERM,
+    .handler = &sigint,
+  },
+};
+
+FRR_DAEMON_INFO(eigrpd, EIGRP,
+                .vty_port = EIGRP_VTY_PORT,
+
+                .proghelp = "Implementation of the EIGRP routing protocol.",
+
+                .signals = eigrp_signals,
+                .n_signals = array_size(eigrp_signals),
+
+                .privs = &eigrpd_privs,
+                )
+
+/* EIGRPd main routine. */
+int
+main (int argc, char **argv, char **envp)
+{
+  frr_preinit (&eigrpd_di, argc, argv);
+  frr_opt_add ("", longopts, "");
+
+  while (1)
+    {
+      int opt;
+
+      opt = frr_getopt (argc, argv, NULL);
+
+      if (opt == EOF)
+        break;
+
+      switch (opt)
+        {
+        case 0:
+          break;
+        default:
+          frr_help_exit (1);
+          break;
+        }
+    }
+
+  /* EIGRP master init. */
+  eigrp_master_init ();
+  eigrp_om->master = frr_init();
+  master = eigrp_om->master;
+
+  vrf_init ();
+
+  /*EIGRPd init*/
+  eigrp_if_init ();
+  eigrp_zebra_init ();
+  eigrp_debug_init ();
+
+  /* Get configuration file. */
+  /* EIGRP VTY inits */
+  eigrp_vty_init ();
+  keychain_init();
+  eigrp_vty_show_init ();
+  eigrp_vty_if_init ();
+
+#ifdef HAVE_SNMP
+  eigrp_snmp_init ();
+#endif /* HAVE_SNMP */
+
+  /* Access list install. */
+  access_list_init ();
+  access_list_add_hook (eigrp_distribute_update_all_wrapper);
+  access_list_delete_hook (eigrp_distribute_update_all_wrapper);
+
+  /* Prefix list initialize.*/
+  prefix_list_init ();
+  prefix_list_add_hook (eigrp_distribute_update_all);
+  prefix_list_delete_hook (eigrp_distribute_update_all);
+
+  /*eigrp_route_map_init();
+    route_map_add_hook (eigrp_rmap_update);
+    route_map_delete_hook (eigrp_rmap_update);*/
+  /*if_rmap_init (EIGRP_NODE);
+    if_rmap_hook_add (eigrp_if_rmap_update);
+    if_rmap_hook_delete (eigrp_if_rmap_update);*/
+
+  /* Distribute list install. */
+  distribute_list_init (EIGRP_NODE);
+  distribute_list_add_hook (eigrp_distribute_update);
+  distribute_list_delete_hook (eigrp_distribute_update);
+
+  frr_config_fork ();
+  frr_run(master);
+
+  /* Not reached. */
+  return (0);
+  
+}
diff --git a/eigrpd/eigrp_memory.c b/eigrpd/eigrp_memory.c
new file mode 100644 (file)
index 0000000..dabc077
--- /dev/null
@@ -0,0 +1,43 @@
+/* eigrpd memory type definitions
+ *
+ * Copyright (C) 2017  Donald Sharp
+ *
+ * This file is part of FRR
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "eigrp_memory.h"
+
+DEFINE_MGROUP(EIGRPD, "eigrpd")
+DEFINE_MTYPE(EIGRPD, EIGRP_TOP,             "EIGRP structure")
+DEFINE_MTYPE(EIGRPD, EIGRP_IF,              "EIGRP interface")
+DEFINE_MTYPE(EIGRPD, EIGRP_NEIGHBOR,        "EIGRP neighbor")
+DEFINE_MTYPE(EIGRPD, EIGRP_IF_PARAMS,       "EIGRP Interface Parameters")
+DEFINE_MTYPE(EIGRPD, EIGRP_IF_INFO,         "EIGRP Interface Information")
+DEFINE_MTYPE(EIGRPD, EIGRP_FIFO,            "EIGRP FIFO")
+DEFINE_MTYPE(EIGRPD, EIGRP_PACKET,          "EIGRP Packet")
+DEFINE_MTYPE(EIGRPD, EIGRP_IPV4_INT_TLV,    "EIGRP IPv4 TLV")
+DEFINE_MTYPE(EIGRPD, EIGRP_SEQ_TLV,         "EIGRP SEQ TLV")
+DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_TLV,        "EIGRP AUTH TLV")
+DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV")
+DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_ENTRY,    "EIGRP Prefix")
+DEFINE_MTYPE(EIGRPD, EIGRP_NEIGHBOR_ENTRY,  "EIGRP Neighbor Entry")
+DEFINE_MTYPE(EIGRPD, EIGRP_FSM_MSG,         "EIGRP FSM Message")
diff --git a/eigrpd/eigrp_memory.h b/eigrpd/eigrp_memory.h
new file mode 100644 (file)
index 0000000..0cafdfb
--- /dev/null
@@ -0,0 +1,44 @@
+/* eigrpd memory type declarations
+ *
+ * Copyright (C) 2017  Donald Sharp
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _FRR_EIGRP_MEMORY_H
+#define _FRR_EIGRP_MEMORY_H
+
+#include "memory.h"
+
+DECLARE_MGROUP(EIGRPD)
+DECLARE_MTYPE(EIGRP_TOP)
+DECLARE_MTYPE(EIGRP_IF)
+DECLARE_MTYPE(EIGRP_NEIGHBOR)
+DECLARE_MTYPE(EIGRP_IF_PARAMS)
+DECLARE_MTYPE(EIGRP_IF_INFO)
+DECLARE_MTYPE(EIGRP_FIFO)
+DECLARE_MTYPE(EIGRP_PACKET)
+DECLARE_MTYPE(EIGRP_IPV4_INT_TLV)
+DECLARE_MTYPE(EIGRP_SEQ_TLV)
+DECLARE_MTYPE(EIGRP_AUTH_TLV)
+DECLARE_MTYPE(EIGRP_AUTH_SHA256_TLV)
+DECLARE_MTYPE(EIGRP_PREFIX_ENTRY)
+DECLARE_MTYPE(EIGRP_NEIGHBOR_ENTRY)
+DECLARE_MTYPE(EIGRP_FSM_MSG)
+  
+#endif /* _FRR_EIGRP_MEMORY_H */
diff --git a/eigrpd/eigrp_neighbor.c b/eigrpd/eigrp_neighbor.c
new file mode 100644 (file)
index 0000000..01b2e68
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * 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, VRF_DEFAULT));
+  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, VRF_DEFAULT));
+  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, VRF_DEFAULT),
+               VTY_NEWLINE);
+    }
+
+  /* send Hello with Peer Termination TLV */
+  eigrp_hello_send(nbr->ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR, &(nbr->src));
+  /* set neighbor to DOWN */
+  nbr->state = EIGRP_NEIGHBOR_DOWN;
+  /* delete neighbor */
+  eigrp_nbr_delete (nbr);
+}
diff --git a/eigrpd/eigrp_neighbor.h b/eigrpd/eigrp_neighbor.h
new file mode 100644 (file)
index 0000000..e9ddc22
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * EIGRP Neighbor Handling.
+ * Copyright (C) 2013-2016
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *   Frantisek Gazo
+ *   Tomas Hvorkovy
+ *   Martin Kontsek
+ *   Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_NEIGHBOR_H
+#define _ZEBRA_EIGRP_NEIGHBOR_H
+
+/* Prototypes */
+extern struct eigrp_neighbor *eigrp_nbr_get(struct eigrp_interface *,
+                                           struct eigrp_header *,
+                                           struct ip *);
+extern struct eigrp_neighbor *eigrp_nbr_new (struct eigrp_interface *);
+extern void eigrp_nbr_delete(struct eigrp_neighbor *);
+
+extern int holddown_timer_expired(struct thread *);
+
+extern int eigrp_neighborship_check(struct eigrp_neighbor *,struct TLV_Parameter_Type *);
+extern void eigrp_nbr_state_update(struct eigrp_neighbor *);
+extern void eigrp_nbr_state_set(struct eigrp_neighbor *, u_char state);
+extern u_char eigrp_nbr_state_get(struct eigrp_neighbor *);
+extern int eigrp_nbr_count_get(void);
+extern const char *eigrp_nbr_state_str(struct eigrp_neighbor *);
+extern struct eigrp_neighbor *eigrp_nbr_lookup_by_addr (struct eigrp_interface *, struct in_addr *);
+extern struct eigrp_neighbor *eigrp_nbr_lookup_by_addr_process (struct eigrp *, struct in_addr);
+extern void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty);
+
+#endif /* _ZEBRA_EIGRP_NEIGHBOR_H */
diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c
new file mode 100644 (file)
index 0000000..dff7f27
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * 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;
+
+  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;
+
+  /* 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))
+            {
+              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)
+{
+  uint64_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;
+  uint64_t temp_delay = (uint64_t) entry->total_metric.delay
+    + (uint64_t) EIGRP_IF_PARAM (entry->ei, delay);
+  entry->total_metric.delay =
+    temp_delay > EIGRP_MAX_METRIC ? EIGRP_MAX_METRIC : (u_int32_t) temp_delay;
+
+  u_int32_t bw = EIGRP_IF_PARAM (entry->ei,bandwidth);
+  entry->total_metric.bandwith =
+    entry->total_metric.bandwith > bw ? bw : entry->total_metric.bandwith;
+
+  return eigrp_calculate_metrics(eigrp, &entry->total_metric);
+}
+
+u_char
+eigrp_metrics_is_same(struct eigrp_metrics *metric1,
+                      struct eigrp_metrics *metric2)
+{
+  if ((metric1->bandwith == metric2->bandwith)
+      && (metric1->delay == metric2->delay)
+      && (metric1->hop_count == metric2->hop_count)
+      && (metric1->load == metric2->load)
+      && (metric1->reliability == metric2->reliability)
+      && (metric1->mtu[0] == metric2->mtu[0])
+      && (metric1->mtu[1] == metric2->mtu[1])
+      && (metric1->mtu[2] == metric2->mtu[2]))
+      return 1;
+
+  return 0; // if different
+}
+
+void
+eigrp_external_routes_refresh (struct eigrp *eigrp, int type)
+{
+
+}
+
diff --git a/eigrpd/eigrp_network.h b/eigrpd/eigrp_network.h
new file mode 100644 (file)
index 0000000..87d1280
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * EIGRP Network Related Functions.
+ * Copyright (C) 2013-2014
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_NETWORK_H
+#define _ZEBRA_EIGRP_NETWORK_H
+
+/* Prototypes */
+
+extern int eigrp_sock_init (void);
+extern int eigrp_if_ipmulticast (struct eigrp *, struct prefix *, unsigned int);
+extern int eigrp_network_set (struct eigrp *, struct prefix_ipv4 *);
+extern int eigrp_network_unset (struct eigrp *eigrp, struct prefix_ipv4 *p);
+
+extern int eigrp_hello_timer (struct thread *);
+extern void eigrp_if_update (struct interface *);
+extern int eigrp_if_add_allspfrouters (struct eigrp *, struct prefix *,
+                                       unsigned int);
+extern int eigrp_if_drop_allspfrouters (struct eigrp *top, struct prefix *p,
+                                        unsigned int ifindex);
+extern void eigrp_adjust_sndbuflen (struct eigrp *, unsigned int);
+
+extern u_int32_t eigrp_calculate_metrics (struct eigrp *, struct eigrp_metrics *);
+extern u_int32_t eigrp_calculate_total_metrics (struct eigrp *, struct eigrp_neighbor_entry *);
+extern u_char eigrp_metrics_is_same(struct eigrp_metrics *,struct eigrp_metrics *);
+extern void eigrp_external_routes_refresh (struct eigrp *, int);
+
+#endif /* EIGRP_NETWORK_H_ */
diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c
new file mode 100644 (file)
index 0000000..5b62e98
--- /dev/null
@@ -0,0 +1,1416 @@
+/*
+ * 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;
+}
+
+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)
+    {
+      struct connected *c;
+      /* 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. */
+      c = if_lookup_address((void *)&iph->ip_src, AF_INET, VRF_DEFAULT);
+
+      if (c == NULL)
+        return 0;
+
+      ifp = c->ifp;
+    }
+
+  /* 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_warn("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, VRF_DEFAULT);
+
+  if (ret != ip_len)
+    {
+      zlog_warn("eigrp_recv_packet read length mismatch: ip_len is %d, "
+                "but recvmsg returned %d", ip_len, ret);
+      return NULL;
+    }
+
+  return ibuf;
+}
+
+struct eigrp_fifo *
+eigrp_fifo_new (void)
+{
+  struct eigrp_fifo *new;
+
+  new = XCALLOC(MTYPE_EIGRP_FIFO, sizeof(struct eigrp_fifo));
+  return new;
+}
+
+/* Free eigrp packet fifo. */
+void
+eigrp_fifo_free (struct eigrp_fifo *fifo)
+{
+  struct eigrp_packet *ep;
+  struct eigrp_packet *next;
+
+  for (ep = fifo->head; ep; ep = next)
+    {
+      next = ep->next;
+      eigrp_packet_free(ep);
+    }
+  fifo->head = fifo->tail = NULL;
+  fifo->count = 0;
+
+  XFREE(MTYPE_EIGRP_FIFO, fifo);
+}
+
+/* Free eigrp fifo entries without destroying fifo itself*/
+void
+eigrp_fifo_reset (struct eigrp_fifo *fifo)
+{
+  struct eigrp_packet *ep;
+  struct eigrp_packet *next;
+
+  for (ep = fifo->head; ep; ep = next)
+    {
+      next = ep->next;
+      eigrp_packet_free(ep);
+    }
+  fifo->head = fifo->tail = NULL;
+  fifo->count = 0;
+}
+
+struct eigrp_packet *
+eigrp_packet_new (size_t size)
+{
+  struct eigrp_packet *new;
+
+  new = XCALLOC(MTYPE_EIGRP_PACKET, sizeof(struct eigrp_packet));
+  new->s = stream_new(size);
+  new->retrans_counter = 0;
+
+  return new;
+}
+
+void
+eigrp_send_packet_reliably (struct eigrp_neighbor *nbr)
+{
+  struct eigrp_packet *ep;
+
+  ep = eigrp_fifo_tail(nbr->retrans_queue);
+
+  if (ep)
+    {
+      struct eigrp_packet *duplicate;
+      duplicate = eigrp_packet_duplicate(ep, nbr);
+      /* Add packet to the top of the interface output queue*/
+      eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
+
+      /*Start retransmission timer*/
+      THREAD_TIMER_ON(master, ep->t_retrans_timer, eigrp_unack_packet_retrans,
+                      nbr, EIGRP_PACKET_RETRANS_TIME);
+
+      /*Increment sequence number counter*/
+      nbr->ei->eigrp->sequence_number++;
+
+      /* Hook thread to write packet. */
+      if (nbr->ei->on_write_q == 0)
+        {
+          listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
+          nbr->ei->on_write_q = 1;
+        }
+      if (nbr->ei->eigrp->t_write == NULL)
+        nbr->ei->eigrp->t_write =
+          thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd);
+    }
+}
+
+/* Calculate EIGRP checksum */
+void
+eigrp_packet_checksum (struct eigrp_interface *ei, struct stream *s,
+                       u_int16_t length)
+{
+  struct eigrp_header *eigrph;
+
+  eigrph = (struct eigrp_header *) STREAM_DATA(s);
+
+  /* Calculate checksum. */
+  eigrph->checksum = in_cksum(eigrph, length);
+}
+
+/* Make EIGRP header. */
+void
+eigrp_packet_header_init (int type, struct eigrp_interface *ei, struct stream *s,
+                          u_int32_t flags, u_int32_t sequence, u_int32_t ack)
+{
+  struct eigrp_header *eigrph;
+
+  eigrph = (struct eigrp_header *) STREAM_DATA(s);
+
+  eigrph->version = (u_char) EIGRP_HEADER_VERSION;
+  eigrph->opcode = (u_char) type;
+  eigrph->checksum = 0;
+
+  eigrph->vrid = htons(ei->eigrp->vrid);
+  eigrph->ASNumber = htons(ei->eigrp->AS);
+  eigrph->ack = htonl(ack);
+  eigrph->sequence = htonl(sequence);
+  //  if(flags == EIGRP_INIT_FLAG)
+  //    eigrph->sequence = htonl(3);
+  eigrph->flags = htonl(flags);
+
+  if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
+    zlog_debug("Packet Header Init Seq [%u] Ack [%u]",
+               htonl(eigrph->sequence), htonl(eigrph->ack));
+
+  stream_forward_endp(s, EIGRP_HEADER_LEN);
+}
+
+/* Add new packet to head of fifo. */
+void
+eigrp_fifo_push_head (struct eigrp_fifo *fifo, struct eigrp_packet *ep)
+{
+  ep->next = fifo->head;
+  ep->previous = NULL;
+
+  if (fifo->tail == NULL)
+    fifo->tail = ep;
+
+  if (fifo->count != 0)
+    fifo->head->previous = ep;
+
+  fifo->head = ep;
+
+  fifo->count++;
+}
+
+/* Return first fifo entry. */
+struct eigrp_packet *
+eigrp_fifo_head (struct eigrp_fifo *fifo)
+{
+  return fifo->head;
+}
+
+/* Return last fifo entry. */
+struct eigrp_packet *
+eigrp_fifo_tail (struct eigrp_fifo *fifo)
+{
+  return fifo->tail;
+}
+
+void
+eigrp_packet_delete (struct eigrp_interface *ei)
+{
+  struct eigrp_packet *ep;
+
+  ep = eigrp_fifo_pop (ei->obuf);
+
+  if (ep)
+    eigrp_packet_free(ep);
+}
+
+/* Delete first packet from fifo. */
+struct eigrp_packet *
+eigrp_fifo_pop (struct eigrp_fifo *fifo)
+{
+  struct eigrp_packet *ep;
+
+  ep = fifo->head;
+
+  if (ep)
+    {
+      fifo->head = ep->next;
+
+      if (fifo->head == NULL)
+        fifo->tail = NULL;
+      else
+        fifo->head->previous = NULL;
+
+      fifo->count--;
+    }
+
+  return ep;
+}
+
+void
+eigrp_packet_free (struct eigrp_packet *ep)
+{
+  if (ep->s)
+    stream_free(ep->s);
+
+  THREAD_OFF(ep->t_retrans_timer);
+
+  XFREE(MTYPE_EIGRP_PACKET, ep);
+
+  ep = NULL;
+}
+
+/* EIGRP Header verification. */
+static int
+eigrp_verify_header (struct stream *ibuf, struct eigrp_interface *ei,
+                     struct ip *iph, struct eigrp_header *eigrph)
+{
+  /* Check network mask, Silently discarded. */
+  if (!eigrp_check_network_mask(ei, iph->ip_src))
+    {
+      zlog_warn("interface %s: eigrp_read network address is not same [%s]",
+                IF_NAME(ei), inet_ntoa(iph->ip_src));
+      return -1;
+    }
+  //
+  //  /* Check authentication. The function handles logging actions, where required. */
+  //  if (! eigrp_check_auth(ei, eigrph))
+  //    return -1;
+
+  return 0;
+}
+
+/* Unbound socket will accept any Raw IP packets if proto is matched.
+   To prevent it, compare src IP address and i/f address with masking
+   i/f network mask. */
+static int
+eigrp_check_network_mask (struct eigrp_interface *ei, struct in_addr ip_src)
+{
+  struct in_addr mask, me, him;
+
+  if (ei->type == EIGRP_IFTYPE_POINTOPOINT)
+    return 1;
+
+  masklen2ip(ei->address->prefixlen, &mask);
+
+  me.s_addr = ei->address->u.prefix4.s_addr & mask.s_addr;
+  him.s_addr = ip_src.s_addr & mask.s_addr;
+
+  if (IPV4_ADDR_SAME(&me, &him))
+    return 1;
+
+  return 0;
+}
+
+int
+eigrp_unack_packet_retrans (struct thread *thread)
+{
+  struct eigrp_neighbor *nbr;
+  nbr = (struct eigrp_neighbor *) THREAD_ARG(thread);
+
+  struct eigrp_packet *ep;
+  ep = eigrp_fifo_tail(nbr->retrans_queue);
+
+  if (ep)
+    {
+      struct eigrp_packet *duplicate;
+      duplicate = eigrp_packet_duplicate(ep, nbr);
+
+      /* Add packet to the top of the interface output queue*/
+      eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
+
+      ep->retrans_counter++;
+      if(ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
+        return eigrp_retrans_count_exceeded(ep, nbr);
+
+      /*Start retransmission timer*/
+      ep->t_retrans_timer =
+          thread_add_timer(master, eigrp_unack_packet_retrans, nbr,EIGRP_PACKET_RETRANS_TIME);
+
+      /* Hook thread to write packet. */
+      if (nbr->ei->on_write_q == 0)
+        {
+          listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
+          nbr->ei->on_write_q = 1;
+        }
+      if (nbr->ei->eigrp->t_write == NULL)
+        nbr->ei->eigrp->t_write =
+          thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd);
+    }
+
+  return 0;
+}
+
+int
+eigrp_unack_multicast_packet_retrans (struct thread *thread)
+{
+  struct eigrp_neighbor *nbr;
+  nbr = (struct eigrp_neighbor *) THREAD_ARG(thread);
+
+  struct eigrp_packet *ep;
+  ep = eigrp_fifo_tail(nbr->multicast_queue);
+
+  if (ep)
+    {
+      struct eigrp_packet *duplicate;
+      duplicate = eigrp_packet_duplicate(ep, nbr);
+      /* Add packet to the top of the interface output queue*/
+      eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
+
+      ep->retrans_counter++;
+      if(ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
+        return eigrp_retrans_count_exceeded(ep, nbr);
+
+      /*Start retransmission timer*/
+      ep->t_retrans_timer =
+        thread_add_timer(master, eigrp_unack_multicast_packet_retrans, nbr,EIGRP_PACKET_RETRANS_TIME);
+
+      /* Hook thread to write packet. */
+      if (nbr->ei->on_write_q == 0)
+        {
+          listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
+          nbr->ei->on_write_q = 1;
+        }
+      if (nbr->ei->eigrp->t_write == NULL)
+        nbr->ei->eigrp->t_write =
+          thread_add_write(master, eigrp_write, nbr->ei->eigrp, nbr->ei->eigrp->fd);
+    }
+
+  return 0;
+}
+
+/* Get packet from tail of fifo. */
+struct eigrp_packet *
+eigrp_fifo_pop_tail (struct eigrp_fifo *fifo)
+{
+  struct eigrp_packet *ep;
+
+  ep = fifo->tail;
+
+  if (ep)
+    {
+      fifo->tail = ep->previous;
+
+      if (fifo->tail == NULL)
+        fifo->head = NULL;
+      else
+        fifo->tail->next = NULL;
+
+      fifo->count--;
+    }
+
+  return ep;
+}
+
+struct eigrp_packet *
+eigrp_packet_duplicate (struct eigrp_packet *old, struct eigrp_neighbor *nbr)
+{
+  struct eigrp_packet *new;
+
+  new = eigrp_packet_new(nbr->ei->ifp->mtu);
+  new->length = old->length;
+  new->retrans_counter = old->retrans_counter;
+  new->dst = old->dst;
+  new->sequence_number = old->sequence_number;
+  stream_copy(new->s, old->s);
+
+  return new;
+}
+
+struct TLV_IPv4_Internal_type *
+eigrp_read_ipv4_tlv (struct stream *s)
+{
+  struct TLV_IPv4_Internal_type *tlv;
+
+  tlv = eigrp_IPv4_InternalTLV_new ();
+
+  tlv->type = stream_getw(s);
+  tlv->length = stream_getw(s);
+  tlv->forward.s_addr = stream_getl(s);
+  tlv->metric.delay = stream_getl(s);
+  tlv->metric.bandwith = stream_getl(s);
+  tlv->metric.mtu[0] = stream_getc(s);
+  tlv->metric.mtu[1] = stream_getc(s);
+  tlv->metric.mtu[2] = stream_getc(s);
+  tlv->metric.hop_count = stream_getc(s);
+  tlv->metric.reliability = stream_getc(s);
+  tlv->metric.load = stream_getc(s);
+  tlv->metric.tag = stream_getc(s);
+  tlv->metric.flags = stream_getc(s);
+
+  tlv->prefix_length = stream_getc(s);
+
+  if (tlv->prefix_length <= 8)
+    {
+      tlv->destination_part[0] = stream_getc(s);
+      tlv->destination.s_addr = (tlv->destination_part[0]);
+    }
+  else if (tlv->prefix_length > 8 && tlv->prefix_length <= 16)
+    {
+      tlv->destination_part[0] = stream_getc(s);
+      tlv->destination_part[1] = stream_getc(s);
+      tlv->destination.s_addr = ((tlv->destination_part[1] << 8)
+                                 + tlv->destination_part[0]);
+    }
+  else if (tlv->prefix_length > 16 && tlv->prefix_length <= 24)
+    {
+      tlv->destination_part[0] = stream_getc(s);
+      tlv->destination_part[1] = stream_getc(s);
+      tlv->destination_part[2] = stream_getc(s);
+      tlv->destination.s_addr = ((tlv->destination_part[2] << 16) +
+                                 (tlv->destination_part[1] << 8) +
+                                 tlv->destination_part[0]);
+    }
+  else if (tlv->prefix_length > 24 && tlv->prefix_length <= 32)
+    {
+      tlv->destination_part[0] = stream_getc(s);
+      tlv->destination_part[1] = stream_getc(s);
+      tlv->destination_part[2] = stream_getc(s);
+      tlv->destination_part[3] = stream_getc(s);
+      tlv->destination.s_addr = ((tlv->destination_part[3] << 24) +
+                                 (tlv->destination_part[2] << 16) +
+                                 (tlv->destination_part[1] << 8) +
+                                 tlv->destination_part[0]);
+    }
+  return tlv;
+}
+
+u_int16_t
+eigrp_add_internalTLV_to_stream (struct stream *s,
+                                 struct eigrp_prefix_entry *pe)
+{
+  u_int16_t length;
+
+  stream_putw(s, EIGRP_TLV_IPv4_INT);
+  if (pe->destination_ipv4->prefixlen <= 8)
+    {
+      stream_putw(s, 0x001A);
+      length = 0x001A;
+    }
+  if ((pe->destination_ipv4->prefixlen > 8)
+      && (pe->destination_ipv4->prefixlen <= 16))
+    {
+      stream_putw(s, 0x001B);
+      length = 0x001B;
+    }
+  if ((pe->destination_ipv4->prefixlen > 16)
+      && (pe->destination_ipv4->prefixlen <= 24))
+    {
+      stream_putw(s, 0x001C);
+      length = 0x001C;
+    }
+  if (pe->destination_ipv4->prefixlen > 24)
+    {
+      stream_putw(s, 0x001D);
+      length = 0x001D;
+    }
+
+  stream_putl(s, 0x00000000);
+
+  /*Metric*/
+  stream_putl(s, pe->reported_metric.delay);
+  stream_putl(s, pe->reported_metric.bandwith);
+  stream_putc(s, pe->reported_metric.mtu[2]);
+  stream_putc(s, pe->reported_metric.mtu[1]);
+  stream_putc(s, pe->reported_metric.mtu[0]);
+  stream_putc(s, pe->reported_metric.hop_count);
+  stream_putc(s, pe->reported_metric.reliability);
+  stream_putc(s, pe->reported_metric.load);
+  stream_putc(s, pe->reported_metric.tag);
+  stream_putc(s, pe->reported_metric.flags);
+
+  stream_putc(s, pe->destination_ipv4->prefixlen);
+
+  if (pe->destination_ipv4->prefixlen <= 8)
+    {
+      stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
+    }
+  if ((pe->destination_ipv4->prefixlen > 8)
+      && (pe->destination_ipv4->prefixlen <= 16))
+    {
+      stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
+      stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
+    }
+  if ((pe->destination_ipv4->prefixlen > 16)
+      && (pe->destination_ipv4->prefixlen <= 24))
+    {
+      stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
+      stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
+      stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF);
+    }
+  if (pe->destination_ipv4->prefixlen > 24)
+    {
+      stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
+      stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
+      stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF);
+      stream_putc(s, (pe->destination_ipv4->prefix.s_addr >> 24) & 0xFF);
+    }
+
+  return length;
+}
+
+u_int16_t
+eigrp_add_authTLV_MD5_to_stream (struct stream *s,
+                                 struct eigrp_interface *ei)
+{
+  struct key *key;
+  struct keychain *keychain;
+  struct TLV_MD5_Authentication_Type *authTLV;
+
+  authTLV = eigrp_authTLV_MD5_new();
+
+  authTLV->type = htons(EIGRP_TLV_AUTH);
+  authTLV->length = htons(EIGRP_AUTH_MD5_TLV_SIZE);
+  authTLV->auth_type = htons(EIGRP_AUTH_TYPE_MD5);
+  authTLV->auth_length = htons(EIGRP_AUTH_TYPE_MD5_LEN);
+  authTLV->key_sequence = 0;
+  memset(authTLV->Nullpad,0,sizeof(authTLV->Nullpad));
+
+  keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
+  if(keychain)
+    key = key_lookup_for_send(keychain);
+  else
+    {
+      free(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
+      IF_DEF_PARAMS (ei->ifp)->auth_keychain = NULL;
+      eigrp_authTLV_MD5_free(authTLV);
+      return 0;
+    }
+
+  if(key)
+    {
+      authTLV->key_id = htonl(key->index);
+      memset(authTLV->digest,0,EIGRP_AUTH_TYPE_MD5_LEN);
+      stream_put(s,authTLV, sizeof(struct TLV_MD5_Authentication_Type));
+      eigrp_authTLV_MD5_free(authTLV);
+      return EIGRP_AUTH_MD5_TLV_SIZE;
+    }
+
+  eigrp_authTLV_MD5_free(authTLV);
+
+  return 0;
+}
+
+u_int16_t
+eigrp_add_authTLV_SHA256_to_stream (struct stream *s,
+                                    struct eigrp_interface *ei)
+{
+  struct key *key;
+  struct keychain *keychain;
+  struct TLV_SHA256_Authentication_Type *authTLV;
+
+  authTLV = eigrp_authTLV_SHA256_new();
+
+  authTLV->type = htons(EIGRP_TLV_AUTH);
+  authTLV->length = htons(EIGRP_AUTH_SHA256_TLV_SIZE);
+  authTLV->auth_type = htons(EIGRP_AUTH_TYPE_SHA256);
+  authTLV->auth_length = htons(EIGRP_AUTH_TYPE_SHA256_LEN);
+  authTLV->key_sequence = 0;
+  memset(authTLV->Nullpad,0,sizeof(authTLV->Nullpad));
+
+  keychain = keychain_lookup(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
+  if(keychain)
+    key = key_lookup_for_send(keychain);
+  else
+    {
+      free(IF_DEF_PARAMS (ei->ifp)->auth_keychain);
+      IF_DEF_PARAMS (ei->ifp)->auth_keychain = NULL;
+      eigrp_authTLV_SHA256_free(authTLV);
+      return 0;
+    }
+
+  if(key)
+    {
+      authTLV->key_id = 0;
+      memset(authTLV->digest,0,EIGRP_AUTH_TYPE_SHA256_LEN);
+      stream_put(s,authTLV, sizeof(struct TLV_SHA256_Authentication_Type));
+      eigrp_authTLV_SHA256_free(authTLV);
+      return EIGRP_AUTH_SHA256_TLV_SIZE;
+    }
+
+  eigrp_authTLV_SHA256_free(authTLV);
+
+  return 0;
+}
+
+struct TLV_MD5_Authentication_Type *
+eigrp_authTLV_MD5_new ()
+{
+  struct TLV_MD5_Authentication_Type *new;
+
+  new = XCALLOC(MTYPE_EIGRP_AUTH_TLV, sizeof(struct TLV_MD5_Authentication_Type));
+
+  return new;
+}
+
+void
+eigrp_authTLV_MD5_free (struct TLV_MD5_Authentication_Type *authTLV)
+{
+  XFREE(MTYPE_EIGRP_AUTH_TLV, authTLV);
+}
+
+struct TLV_SHA256_Authentication_Type *
+eigrp_authTLV_SHA256_new ()
+{
+  struct TLV_SHA256_Authentication_Type *new;
+
+  new = XCALLOC(MTYPE_EIGRP_AUTH_SHA256_TLV, sizeof(struct TLV_SHA256_Authentication_Type));
+
+  return new;
+}
+
+void
+eigrp_authTLV_SHA256_free (struct TLV_SHA256_Authentication_Type *authTLV)
+{
+  XFREE(MTYPE_EIGRP_AUTH_SHA256_TLV, authTLV);
+}
+
+struct TLV_IPv4_Internal_type *
+eigrp_IPv4_InternalTLV_new ()
+{
+  struct TLV_IPv4_Internal_type *new;
+
+  new = XCALLOC(MTYPE_EIGRP_IPV4_INT_TLV,sizeof(struct TLV_IPv4_Internal_type));
+
+  return new;
+}
+
+void
+eigrp_IPv4_InternalTLV_free (struct TLV_IPv4_Internal_type *IPv4_InternalTLV)
+{
+  XFREE(MTYPE_EIGRP_IPV4_INT_TLV, IPv4_InternalTLV);
+}
+
+struct TLV_Sequence_Type *
+eigrp_SequenceTLV_new ()
+{
+  struct TLV_Sequence_Type *new;
+
+  new = XCALLOC(MTYPE_EIGRP_SEQ_TLV,sizeof(struct TLV_Sequence_Type));
+
+  return new;
+}
diff --git a/eigrpd/eigrp_packet.h b/eigrpd/eigrp_packet.h
new file mode 100644 (file)
index 0000000..b8b2815
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * EIGRP General Sending and Receiving of EIGRP Packets.
+ * Copyright (C) 2013-2016
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *   Frantisek Gazo
+ *   Tomas Hvorkovy
+ *   Martin Kontsek
+ *   Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_PACKET_H
+#define _ZEBRA_EIGRP_PACKET_H
+
+/*Prototypes*/
+extern int eigrp_read (struct thread *);
+extern int eigrp_write (struct thread *);
+
+extern struct eigrp_packet *eigrp_packet_new (size_t);
+extern struct eigrp_packet *eigrp_packet_duplicate (struct eigrp_packet *, struct eigrp_neighbor *);
+extern void eigrp_packet_free (struct eigrp_packet *);
+extern void eigrp_packet_delete (struct eigrp_interface *);
+extern void eigrp_packet_header_init (int, struct eigrp_interface *, struct stream *,
+                                    u_int32_t, u_int32_t, u_int32_t);
+extern void eigrp_packet_checksum (struct eigrp_interface *, struct stream *, u_int16_t);
+
+extern struct eigrp_fifo *eigrp_fifo_new (void);
+extern struct eigrp_packet *eigrp_fifo_head (struct eigrp_fifo *);
+extern struct eigrp_packet *eigrp_fifo_tail (struct eigrp_fifo *);
+extern struct eigrp_packet *eigrp_fifo_pop (struct eigrp_fifo *);
+extern struct eigrp_packet *eigrp_fifo_pop_tail (struct eigrp_fifo *);
+extern void eigrp_fifo_push_head (struct eigrp_fifo *, struct eigrp_packet *);
+extern void eigrp_fifo_free (struct eigrp_fifo *);
+extern void eigrp_fifo_reset (struct eigrp_fifo *);
+
+extern void eigrp_send_packet_reliably (struct eigrp_neighbor *);
+
+extern struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv (struct stream *);
+extern u_int16_t eigrp_add_internalTLV_to_stream (struct stream *, struct eigrp_prefix_entry *);
+extern u_int16_t eigrp_add_authTLV_MD5_to_stream (struct stream *, struct eigrp_interface *);
+extern u_int16_t eigrp_add_authTLV_SHA256_to_stream (struct stream *, struct eigrp_interface *);
+
+extern int eigrp_unack_packet_retrans (struct thread *);
+extern int eigrp_unack_multicast_packet_retrans (struct thread *);
+
+/*
+ * untill there is reason to have their own header, these externs are found in
+ * eigrp_hello.c
+ */
+extern void eigrp_hello_send (struct eigrp_interface *, u_char, struct in_addr *);
+extern void eigrp_hello_send_ack (struct eigrp_neighbor *);
+extern void eigrp_hello_receive (struct eigrp *, struct ip *, struct eigrp_header *,
+                               struct stream *, struct eigrp_interface *, int);
+extern int  eigrp_hello_timer (struct thread *);
+
+/*
+ * These externs are found in eigrp_update.c
+ */
+extern void eigrp_update_send (struct eigrp_interface *);
+extern void eigrp_update_receive (struct eigrp *, struct ip *, struct eigrp_header *,
+                                struct stream *, struct eigrp_interface *, int);
+extern void eigrp_update_send_all (struct eigrp *, struct eigrp_interface *);
+extern void eigrp_update_send_init (struct eigrp_neighbor *);
+extern void eigrp_update_send_EOT (struct eigrp_neighbor *);
+extern int eigrp_update_send_GR_thread(struct thread *);
+extern void eigrp_update_send_GR (struct eigrp_neighbor *, enum GR_type, struct vty *);
+extern void eigrp_update_send_interface_GR (struct eigrp_interface *, enum GR_type, struct vty *);
+extern void eigrp_update_send_process_GR (struct eigrp *, enum GR_type, struct vty *);
+
+/*
+ * These externs are found in eigrp_query.c
+ */
+
+extern void eigrp_send_query (struct eigrp_interface *);
+extern void eigrp_query_receive (struct eigrp *, struct ip *, struct eigrp_header *,
+                                 struct stream *, struct eigrp_interface *, int);
+extern u_int32_t eigrp_query_send_all (struct eigrp *);
+
+/*
+ * These externs are found in eigrp_reply.c
+ */
+extern void eigrp_send_reply (struct eigrp_neighbor *, struct eigrp_prefix_entry *);
+extern void eigrp_reply_receive (struct eigrp *, struct ip *, struct eigrp_header *,
+                                 struct stream *, struct eigrp_interface *, int);
+
+/*
+ * These externs are found in eigrp_siaquery.c
+ */
+extern void eigrp_send_siaquery (struct eigrp_neighbor *, struct eigrp_prefix_entry *);
+extern void eigrp_siaquery_receive (struct eigrp *, struct ip *, struct eigrp_header *,
+                     struct stream *, struct eigrp_interface *, int);
+
+/*
+ * These externs are found in eigrp_siareply.c
+ */
+extern void eigrp_send_siareply (struct eigrp_neighbor *, struct eigrp_prefix_entry *);
+extern void eigrp_siareply_receive (struct eigrp *, struct ip *, struct eigrp_header *,
+                     struct stream *, struct eigrp_interface *, int);
+
+extern struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new (void);
+extern void eigrp_authTLV_MD5_free (struct TLV_MD5_Authentication_Type *);
+extern struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new (void);
+extern void eigrp_authTLV_SHA256_free (struct TLV_SHA256_Authentication_Type *);
+
+extern int eigrp_make_md5_digest (struct eigrp_interface *, struct stream *,
+                                  u_char);
+extern int eigrp_check_md5_digest (struct stream *, struct TLV_MD5_Authentication_Type *,
+                            struct eigrp_neighbor *, u_char);
+extern int eigrp_make_sha256_digest (struct eigrp_interface *, struct stream *, u_char);
+extern int eigrp_check_sha256_digest (struct stream *, struct TLV_SHA256_Authentication_Type *,
+                            struct eigrp_neighbor *, u_char );
+
+
+extern struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new (void);
+extern void eigrp_IPv4_InternalTLV_free (struct TLV_IPv4_Internal_type *);
+
+extern struct TLV_Sequence_Type *eigrp_SequenceTLV_new (void);
+
+extern const struct message eigrp_packet_type_str[];
+extern const size_t eigrp_packet_type_str_max;
+
+#endif /* _ZEBRA_EIGRP_PACKET_H */
diff --git a/eigrpd/eigrp_pkt_tlv1.c b/eigrpd/eigrp_pkt_tlv1.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/eigrpd/eigrp_pkt_tlv2.c b/eigrpd/eigrp_pkt_tlv2.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/eigrpd/eigrp_query.c b/eigrpd/eigrp_query.c
new file mode 100644 (file)
index 0000000..4488054
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * EIGRP Sending and Receiving EIGRP Query Packets.
+ * Copyright (C) 2013-2014
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
+#include "vty.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_macros.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_memory.h"
+
+u_int32_t
+eigrp_query_send_all (struct eigrp *eigrp)
+{
+  struct eigrp_interface *iface;
+  struct listnode *node, *node2, *nnode2;
+  struct eigrp_prefix_entry *pe;
+  u_int32_t counter;
+
+  if (eigrp == NULL)
+    {
+      zlog_debug("EIGRP Routing Process not enabled");
+      return 0;
+    }
+
+  counter=0;
+  for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface))
+    {
+      eigrp_send_query(iface);
+      counter++;
+    }
+
+  for (ALL_LIST_ELEMENTS(eigrp->topology_changes_internalIPV4, node2, nnode2, pe))
+    {
+      if(pe->req_action & EIGRP_FSM_NEED_QUERY)
+        {
+          pe->req_action &= ~EIGRP_FSM_NEED_QUERY;
+          listnode_delete(eigrp->topology_changes_internalIPV4, pe);
+        }
+    }
+
+  return counter;
+}
+
+/*EIGRP QUERY read function*/
+void
+eigrp_query_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
+                     struct stream * s, struct eigrp_interface *ei, int size)
+{
+  struct eigrp_neighbor *nbr;
+  struct TLV_IPv4_Internal_type *tlv;
+
+  u_int16_t type;
+
+  /* increment statistics. */
+  ei->query_in++;
+
+  /* get neighbor struct */
+  nbr = eigrp_nbr_get(ei, eigrph, iph);
+
+  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
+  assert(nbr);
+
+  nbr->recv_sequence_number = ntohl(eigrph->sequence);
+
+  while (s->endp > s->getp)
+    {
+      type = stream_getw(s);
+      if (type == EIGRP_TLV_IPv4_INT)
+        {
+          stream_set_getp(s, s->getp - sizeof(u_int16_t));
+
+          tlv = eigrp_read_ipv4_tlv(s);
+
+          struct prefix_ipv4 *dest_addr;
+          dest_addr = prefix_ipv4_new();
+          dest_addr->prefix = tlv->destination;
+          dest_addr->prefixlen = tlv->prefix_length;
+          struct eigrp_prefix_entry *dest =
+            eigrp_topology_table_lookup_ipv4(eigrp->topology_table, dest_addr);
+
+          /* If the destination exists (it should, but one never know)*/
+          if (dest != NULL)
+            {
+              struct eigrp_fsm_action_message *msg;
+              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
+                            sizeof(struct eigrp_fsm_action_message));
+              struct eigrp_neighbor_entry *entry =
+                eigrp_prefix_entry_lookup(dest->entries, nbr);
+              msg->packet_type = EIGRP_OPC_QUERY;
+              msg->eigrp = eigrp;
+              msg->data_type = EIGRP_TLV_IPv4_INT;
+              msg->adv_router = nbr;
+              msg->data.ipv4_int_type = tlv;
+              msg->entry = entry;
+              msg->prefix = dest;
+              int event = eigrp_get_fsm_event(msg);
+              eigrp_fsm_event(msg, event);
+            }
+          eigrp_IPv4_InternalTLV_free (tlv);
+        }
+    }
+  eigrp_hello_send_ack(nbr);
+  eigrp_query_send_all(eigrp);
+  eigrp_update_send_all(eigrp,nbr->ei);
+}
+
+void
+eigrp_send_query (struct eigrp_interface *ei)
+{
+  struct eigrp_packet *ep;
+  u_int16_t length = EIGRP_HEADER_LEN;
+  struct listnode *node, *nnode, *node2, *nnode2;
+  struct eigrp_neighbor *nbr;
+  struct eigrp_prefix_entry *pe;
+  char has_tlv;
+
+  ep = eigrp_packet_new(ei->ifp->mtu);
+
+  /* Prepare EIGRP INIT UPDATE header */
+  eigrp_packet_header_init(EIGRP_OPC_QUERY, ei, ep->s, 0,
+                           ei->eigrp->sequence_number, 0);
+
+  // encode Authentication TLV, if needed
+  if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
+     (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+    {
+      length += eigrp_add_authTLV_MD5_to_stream(ep->s,ei);
+    }
+
+  has_tlv = 0;
+  for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node, nnode, pe))
+    {
+      if(pe->req_action & EIGRP_FSM_NEED_QUERY)
+        {
+          length += eigrp_add_internalTLV_to_stream(ep->s, pe);
+          for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr))
+            {
+              if(nbr->state == EIGRP_NEIGHBOR_UP)
+                {
+                  listnode_add(pe->rij, nbr);
+                  has_tlv = 1;
+                }
+            }
+        }
+    }
+
+  if(!has_tlv)
+    {
+      eigrp_packet_free(ep);
+      return;
+    }
+
+  if((IF_DEF_PARAMS (ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
+     (IF_DEF_PARAMS (ei->ifp)->auth_keychain != NULL))
+    {
+      eigrp_make_md5_digest(ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
+    }
+
+  /* EIGRP Checksum */
+  eigrp_packet_checksum(ei, ep->s, length);
+
+  ep->length = length;
+  ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS);
+
+  /*This ack number we await from neighbor*/
+  ep->sequence_number = ei->eigrp->sequence_number;
+
+  for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr))
+    {
+      if (nbr->state == EIGRP_NEIGHBOR_UP)
+        {
+          /*Put packet to retransmission queue*/
+          eigrp_fifo_push_head(nbr->retrans_queue, ep);
+
+          if (nbr->retrans_queue->count == 1)
+            {
+              eigrp_send_packet_reliably(nbr);
+            }
+        }
+    }
+}
diff --git a/eigrpd/eigrp_reply.c b/eigrpd/eigrp_reply.c
new file mode 100644 (file)
index 0000000..0c5d9dd
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * 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) == PREFIX_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) == PREFIX_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) == PREFIX_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) == PREFIX_DENY))
+            {
+              zlog_info("REPLY RECEIVE: Setting metric to max");
+              tlv->metric.delay = EIGRP_MAX_METRIC;
+              zlog_info("REPLY RECEIVE Prefix: %s", inet_ntoa(dest_addr->prefix));
+            } else {
+            zlog_info("REPLY RECEIVE: Not setting metric");
+          }
+          /*
+           * End of filtering
+           */
+
+          msg->packet_type = EIGRP_OPC_REPLY;
+          msg->eigrp = eigrp;
+          msg->data_type = EIGRP_TLV_IPv4_INT;
+          msg->adv_router = nbr;
+          msg->data.ipv4_int_type = tlv;
+          msg->entry = entry;
+          msg->prefix = dest;
+          int event = eigrp_get_fsm_event(msg);
+          eigrp_fsm_event(msg, event);
+
+
+          eigrp_IPv4_InternalTLV_free (tlv);
+        }
+    }
+  eigrp_hello_send_ack(nbr);
+}
+
diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c
new file mode 100644 (file)
index 0000000..c4a33d5
--- /dev/null
@@ -0,0 +1,1243 @@
+/*
+ * EIGRP Filter Functions.
+ * Copyright (C) 2013-2015
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *   Frantisek Gazo
+ *   Tomas Hvorkovy
+ *   Martin Kontsek
+ *   Lukas Koribsky
+ *
+ * Note: This file contains skeleton for all possible matches and sets,
+ * but they are hidden in comment block and not properly implemented.
+ * At this time, the only function we consider useful for our use
+ * in distribute command in EIGRP is matching destination IP (with both
+ * access and prefix list).
+ *
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "prefix.h"
+#include "if_rmap.h"
+#include "routemap.h"
+#include "command.h"
+#include "filter.h"
+#include "log.h"
+#include "sockunion.h"          /* for inet_aton () */
+#include "plist.h"
+
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrp_const.h"
+#include "eigrpd/eigrp_macros.h"
+#include "eigrpd/eigrp_routemap.h"
+
+void
+eigrp_if_rmap_update (struct if_rmap *if_rmap)
+{
+  struct interface *ifp;
+  struct eigrp_interface *ei, *ei2;
+  struct listnode *node, *nnode;
+  struct route_map *rmap;
+  struct eigrp *e;
+
+  ifp = if_lookup_by_name (if_rmap->ifname);
+  if (ifp == NULL)
+    return;
+
+  ei = NULL;
+  e = eigrp_lookup();
+  for (ALL_LIST_ELEMENTS (e->eiflist, node, nnode, ei2))
+    {
+      if(strcmp(ei2->ifp->name,ifp->name) == 0){
+        ei = ei2;
+        break;
+      }
+    }
+
+  if (if_rmap->routemap[IF_RMAP_IN])
+    {
+      rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
+      if (rmap)
+        ei->routemap[IF_RMAP_IN] = rmap;
+      else
+        ei->routemap[IF_RMAP_IN] = NULL;
+    }
+  else
+    ei->routemap[EIGRP_FILTER_IN] = NULL;
+
+  if (if_rmap->routemap[IF_RMAP_OUT])
+    {
+      rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
+      if (rmap)
+        ei->routemap[IF_RMAP_OUT] = rmap;
+      else
+        ei->routemap[IF_RMAP_OUT] = NULL;
+    }
+  else
+    ei->routemap[EIGRP_FILTER_OUT] = NULL;
+}
+
+void
+eigrp_if_rmap_update_interface (struct interface *ifp)
+{
+  struct if_rmap *if_rmap;
+
+  if_rmap = if_rmap_lookup (ifp->name);
+  if (if_rmap)
+    eigrp_if_rmap_update (if_rmap);
+}
+
+void
+eigrp_routemap_update_redistribute (void)
+{
+  int i;
+  struct eigrp *e;
+
+  e = eigrp_lookup();
+
+  if (e)
+    {
+      for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+        {
+          if (e->route_map[i].name)
+            e->route_map[i].map =
+              route_map_lookup_by_name (e->route_map[i].name);
+        }
+    }
+}
+
+/* ARGSUSED */
+void
+eigrp_rmap_update (const char *notused)
+{
+  struct interface *ifp;
+  struct listnode *node, *nnode;
+
+  for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
+    eigrp_if_rmap_update_interface (ifp);
+
+  eigrp_routemap_update_redistribute ();
+}
+
+/* Add eigrp route map rule. */
+static int
+eigrp_route_match_add (struct vty *vty, struct route_map_index *index,
+                       const char *command, const char *arg)
+{
+  int ret;
+  ret = route_map_add_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+        {
+        case RMAP_RULE_MISSING:
+          vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        case RMAP_COMPILE_ERROR:
+          vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Delete rip route map rule. */
+static int
+eigrp_route_match_delete (struct vty *vty, struct route_map_index *index,
+                          const char *command, const char *arg)
+{
+  int ret;
+  ret = route_map_delete_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+        {
+        case RMAP_RULE_MISSING:
+          vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        case RMAP_COMPILE_ERROR:
+          vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Add eigrp route map rule. */
+static int
+eigrp_route_set_add (struct vty *vty, struct route_map_index *index,
+                     const char *command, const char *arg)
+{
+  int ret;
+
+  ret = route_map_add_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+        {
+        case RMAP_RULE_MISSING:
+          vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        case RMAP_COMPILE_ERROR:
+          /* rip, ripng and other protocols share the set metric command
+             but only values from 0 to 16 are valid for rip and ripng
+             if metric is out of range for rip and ripng, it is not for
+             other protocols. Do not return an error */
+          if (strcmp(command, "metric")) {
+            vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+            return CMD_WARNING;
+          }
+        }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Delete eigrp route map rule. */
+static int
+eigrp_route_set_delete (struct vty *vty, struct route_map_index *index,
+                        const char *command, const char *arg)
+{
+  int ret;
+
+  ret = route_map_delete_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+        {
+        case RMAP_RULE_MISSING:
+          vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        case RMAP_COMPILE_ERROR:
+          vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+    }
+  return CMD_SUCCESS;
+}
+
+/* Hook function for updating route_map assignment. */
+/* ARGSUSED */
+void
+eigrp_route_map_update (const char *notused)
+{
+  int i;
+  struct eigrp *e;
+  e = eigrp_lookup();
+
+  if (e)
+    {
+      for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+        {
+          if (e->route_map[i].name)
+            e->route_map[i].map =
+              route_map_lookup_by_name (e->route_map[i].name);
+        }
+    }
+}
+
+
+
+/* `match metric METRIC' */
+/* Match function return 1 if match is success else return zero. */
+static route_map_result_t
+route_match_metric (void *rule, struct prefix *prefix,
+                    route_map_object_t type, void *object)
+{
+  //  u_int32_t *metric;
+  //  u_int32_t  check;
+  //  struct rip_info *rinfo;
+  //  struct eigrp_neighbor_entry *te;
+  //  struct eigrp_prefix_entry *pe;
+  //  struct listnode *node, *node2, *nnode, *nnode2;
+  //  struct eigrp *e;
+  //
+  //  e = eigrp_lookup();
+  //
+  //  if (type == RMAP_EIGRP)
+  //    {
+  //      metric = rule;
+  //      rinfo = object;
+  //
+  //      /* If external metric is available, the route-map should
+  //         work on this one (for redistribute purpose)  */
+  //      /*check = (rinfo->external_metric) ? rinfo->external_metric :
+  //                                         rinfo->metric;*/
+  //
+  //      if (check == *metric)
+  //   return RMAP_MATCH;
+  //      else
+  //     return RMAP_NOMATCH;
+  //    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `match metric' match statement. `arg' is METRIC value */
+static void *
+route_match_metric_compile (const char *arg)
+{
+  //  u_int32_t *metric;
+  //
+  //  metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+  //  *metric = atoi (arg);
+  //
+  //  if(*metric > 0)
+  //    return metric;
+  //
+  //  XFREE (MTYPE_ROUTE_MAP_COMPILED, metric);
+  return NULL;
+}
+
+/* Free route map's compiled `match metric' value. */
+static void
+route_match_metric_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for metric matching. */
+struct route_map_rule_cmd route_match_metric_cmd =
+{
+  "metric",
+  route_match_metric,
+  route_match_metric_compile,
+  route_match_metric_free
+};
+
+/* `match interface IFNAME' */
+/* Match function return 1 if match is success else return zero. */
+static route_map_result_t
+route_match_interface (void *rule, struct prefix *prefix,
+                       route_map_object_t type, void *object)
+{
+  //  struct rip_info *rinfo;
+  //  struct interface *ifp;
+  //  char *ifname;
+  //
+  //  if (type == RMAP_EIGRP)
+  //    {
+  //      ifname = rule;
+  //      ifp = if_lookup_by_name(ifname);
+  //
+  //      if (!ifp)
+  //   return RMAP_NOMATCH;
+  //
+  //      rinfo = object;
+  //
+  //      /*if (rinfo->ifindex_out == ifp->ifindex || rinfo->ifindex == ifp->ifindex)
+  //   return RMAP_MATCH;
+  //      else
+  //   return RMAP_NOMATCH;*/
+  //    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `match interface' match statement. `arg' is IFNAME value */
+/* XXX I don`t know if I need to check does interface exist? */
+static void *
+route_match_interface_compile (const char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `match interface' value. */
+static void
+route_match_interface_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for interface matching. */
+struct route_map_rule_cmd route_match_interface_cmd =
+{
+  "interface",
+  route_match_interface,
+  route_match_interface_compile,
+  route_match_interface_free
+};
+
+/* `match ip next-hop IP_ACCESS_LIST' */
+
+/* Match function return 1 if match is success else return zero. */
+static route_map_result_t
+route_match_ip_next_hop (void *rule, struct prefix *prefix,
+                         route_map_object_t type, void *object)
+{
+  //  struct access_list *alist;
+  //  struct rip_info *rinfo;
+  //  struct prefix_ipv4 p;
+  //
+  //  if (type == RMAP_EIGRP)
+  //    {
+  //      rinfo = object;
+  //      p.family = AF_INET;
+  //      /*p.prefix = (rinfo->nexthop.s_addr) ? rinfo->nexthop : rinfo->from;*/
+  //      p.prefixlen = IPV4_MAX_BITLEN;
+  //
+  //      alist = access_list_lookup (AFI_IP, (char *) rule);
+  //      if (alist == NULL)
+  //     return RMAP_NOMATCH;
+  //
+  //      return (access_list_apply (alist, &p) == FILTER_DENY ?
+  //          RMAP_NOMATCH : RMAP_MATCH);
+  //    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `ip next-hop' match statement.  `arg' should be
+   access-list name. */
+static void *
+route_match_ip_next_hop_compile (const char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `. */
+static void
+route_match_ip_next_hop_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip next-hop matching. */
+static struct route_map_rule_cmd route_match_ip_next_hop_cmd =
+  {
+    "ip next-hop",
+    route_match_ip_next_hop,
+    route_match_ip_next_hop_compile,
+    route_match_ip_next_hop_free
+  };
+
+/* `match ip next-hop prefix-list PREFIX_LIST' */
+
+static route_map_result_t
+route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
+                                     route_map_object_t type, void *object)
+{
+  //  struct prefix_list *plist;
+  //  struct rip_info *rinfo;
+  //  struct prefix_ipv4 p;
+  //
+  //  if (type == RMAP_EIGRP)
+  //    {
+  //      rinfo = object;
+  //      p.family = AF_INET;
+  //      /*p.prefix = (rinfo->nexthop.s_addr) ? rinfo->nexthop : rinfo->from;*/
+  //      p.prefixlen = IPV4_MAX_BITLEN;
+  //
+  //      plist = prefix_list_lookup (AFI_IP, (char *) rule);
+  //      if (plist == NULL)
+  //        return RMAP_NOMATCH;
+  //
+  //      return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
+  //              RMAP_NOMATCH : RMAP_MATCH);
+  //    }
+  return RMAP_NOMATCH;
+}
+
+static void *
+route_match_ip_next_hop_prefix_list_compile (const char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+static void
+route_match_ip_next_hop_prefix_list_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd =
+{
+  "ip next-hop prefix-list",
+  route_match_ip_next_hop_prefix_list,
+  route_match_ip_next_hop_prefix_list_compile,
+  route_match_ip_next_hop_prefix_list_free
+};
+
+/* `match ip address IP_ACCESS_LIST' */
+
+/* Match function should return 1 if match is success else return
+   zero. */
+static route_map_result_t
+route_match_ip_address (void *rule, struct prefix *prefix,
+                        route_map_object_t type, void *object)
+{
+  struct access_list *alist;
+
+  if (type == RMAP_EIGRP)
+    {
+      alist = access_list_lookup (AFI_IP, (char *) rule);
+      if (alist == NULL)
+        return RMAP_NOMATCH;
+
+      return (access_list_apply (alist, prefix) == FILTER_DENY ?
+              RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `ip address' match statement.  `arg' should be
+   access-list name. */
+static void *
+route_match_ip_address_compile (const char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+static void
+route_match_ip_address_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+static struct route_map_rule_cmd route_match_ip_address_cmd =
+  {
+    "ip address",
+    route_match_ip_address,
+    route_match_ip_address_compile,
+    route_match_ip_address_free
+  };
+
+/* `match ip address prefix-list PREFIX_LIST' */
+
+static route_map_result_t
+route_match_ip_address_prefix_list (void *rule, struct prefix *prefix,
+                                    route_map_object_t type, void *object)
+{
+  struct prefix_list *plist;
+
+  if (type == RMAP_EIGRP)
+    {
+      plist = prefix_list_lookup (AFI_IP, (char *) rule);
+      if (plist == NULL)
+        return RMAP_NOMATCH;
+
+      return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+              RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+static void *
+route_match_ip_address_prefix_list_compile (const char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+static void
+route_match_ip_address_prefix_list_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
+  {
+    "ip address prefix-list",
+    route_match_ip_address_prefix_list,
+    route_match_ip_address_prefix_list_compile,
+    route_match_ip_address_prefix_list_free
+  };
+
+/* `match tag TAG' */
+/* Match function return 1 if match is success else return zero. */
+static route_map_result_t
+route_match_tag (void *rule, struct prefix *prefix,
+                 route_map_object_t type, void *object)
+{
+  //  u_short *tag;
+  //  struct rip_info *rinfo;
+  //
+  //  if (type == RMAP_EIGRP)
+  //    {
+  //      tag = rule;
+  //      rinfo = object;
+  //
+  //      /* The information stored by rinfo is host ordered. */
+  //      /*if (rinfo->tag == *tag)
+  //    return RMAP_MATCH;
+  //      else
+  //    return RMAP_NOMATCH;*/
+  //    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `match tag' match statement. `arg' is TAG value */
+static void *
+route_match_tag_compile (const char *arg)
+{
+  //  u_short *tag;
+  //
+  //  tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
+  //  *tag = atoi (arg);
+  //
+  //  return tag;
+}
+
+/* Free route map's compiled `match tag' value. */
+static void
+route_match_tag_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for tag matching. */
+struct route_map_rule_cmd route_match_tag_cmd =
+  {
+    "tag",
+    route_match_tag,
+    route_match_tag_compile,
+    route_match_tag_free
+  };
+
+/* Set metric to attribute. */
+static route_map_result_t
+route_set_metric (void *rule, struct prefix *prefix,
+                  route_map_object_t type, void *object)
+{
+  //  if (type == RMAP_RIP)
+  //    {
+  //      struct rip_metric_modifier *mod;
+  //      struct rip_info *rinfo;
+  //
+  //      mod = rule;
+  //      rinfo = object;
+  //
+  //      /*if (mod->type == metric_increment)
+  //    rinfo->metric_out += mod->metric;
+  //      else if (mod->type == metric_decrement)
+  //    rinfo->metric_out -= mod->metric;
+  //      else if (mod->type == metric_absolute)
+  //    rinfo->metric_out = mod->metric;
+  //
+  //      if ((signed int)rinfo->metric_out < 1)
+  //    rinfo->metric_out = 1;
+  //      if (rinfo->metric_out > RIP_METRIC_INFINITY)
+  //    rinfo->metric_out = RIP_METRIC_INFINITY;*/
+  //
+  //      rinfo->metric_set = 1;
+  //    }
+  return RMAP_OKAY;
+}
+
+/* set metric compilation. */
+static void *
+route_set_metric_compile (const char *arg)
+{
+  //  int len;
+  //  const char *pnt;
+  //  int type;
+  //  long metric;
+  //  char *endptr = NULL;
+  //  struct rip_metric_modifier *mod;
+  //
+  //  len = strlen (arg);
+  //  pnt = arg;
+  //
+  //  if (len == 0)
+  //    return NULL;
+  //
+  //  /* Examine first character. */
+  //  if (arg[0] == '+')
+  //    {
+  //      //type = metric_increment;
+  //      pnt++;
+  //    }
+  //  else if (arg[0] == '-')
+  //    {
+  //      //type = metric_decrement;
+  //      pnt++;
+  //    }
+  //  /*else
+  //    type = metric_absolute;*/
+  //
+  //  /* Check beginning with digit string. */
+  //  if (*pnt < '0' || *pnt > '9')
+  //    return NULL;
+  //
+  //  /* Convert string to integer. */
+  //  metric = strtol (pnt, &endptr, 10);
+  //
+  //  if (metric == LONG_MAX || *endptr != '\0')
+  //    return NULL;
+  //  /*if (metric < 0 || metric > RIP_METRIC_INFINITY)
+  //    return NULL;*/
+  //
+  //  mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED,
+  //    sizeof (struct rip_metric_modifier));
+  //  mod->type = type;
+  //  mod->metric = metric;
+
+  //  return mod;
+}
+
+/* Free route map's compiled `set metric' value. */
+static void
+route_set_metric_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+static struct route_map_rule_cmd route_set_metric_cmd =
+  {
+    "metric",
+    route_set_metric,
+    route_set_metric_compile,
+    route_set_metric_free,
+  };
+
+/* `set ip next-hop IP_ADDRESS' */
+
+/* Set nexthop to object.  ojbect must be pointer to struct attr. */
+static route_map_result_t
+route_set_ip_nexthop (void *rule, struct prefix *prefix,
+                      route_map_object_t type, void *object)
+{
+  //  struct in_addr *address;
+  //  struct rip_info *rinfo;
+  //
+  //  if(type == RMAP_RIP)
+  //    {
+  //      /* Fetch routemap's rule information. */
+  //      address = rule;
+  //      rinfo = object;
+  //
+  //      /* Set next hop value. */
+  //      rinfo->nexthop_out = *address;
+  //    }
+
+  return RMAP_OKAY;
+}
+
+/* Route map `ip nexthop' compile function.  Given string is converted
+   to struct in_addr structure. */
+static void *
+route_set_ip_nexthop_compile (const char *arg)
+{
+  //  int ret;
+  //  struct in_addr *address;
+  //
+  //  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr));
+  //
+  //  ret = inet_aton (arg, address);
+  //
+  //  if (ret == 0)
+  //    {
+  //      XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+  //      return NULL;
+  //    }
+  //
+  //  return address;
+}
+
+/* Free route map's compiled `ip nexthop' value. */
+static void
+route_set_ip_nexthop_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set. */
+static struct route_map_rule_cmd route_set_ip_nexthop_cmd =
+  {
+    "ip next-hop",
+    route_set_ip_nexthop,
+    route_set_ip_nexthop_compile,
+    route_set_ip_nexthop_free
+  };
+
+/* `set tag TAG' */
+
+/* Set tag to object.  ojbect must be pointer to struct attr. */
+static route_map_result_t
+route_set_tag (void *rule, struct prefix *prefix,
+               route_map_object_t type, void *object)
+{
+  //  u_short *tag;
+  //  struct rip_info *rinfo;
+  //
+  //  if(type == RMAP_RIP)
+  //    {
+  //      /* Fetch routemap's rule information. */
+  //      tag = rule;
+  //      rinfo = object;
+  //
+  //      /* Set next hop value. */
+  //      rinfo->tag_out = *tag;
+  //    }
+
+  return RMAP_OKAY;
+}
+
+/* Route map `tag' compile function.  Given string is converted
+   to u_short. */
+static void *
+route_set_tag_compile (const char *arg)
+{
+  //  u_short *tag;
+  //
+  //  tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
+  //  *tag = atoi (arg);
+  //
+  //  return tag;
+}
+
+/* Free route map's compiled `ip nexthop' value. */
+static void
+route_set_tag_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for tag set. */
+static struct route_map_rule_cmd route_set_tag_cmd =
+  {
+    "tag",
+    route_set_tag,
+    route_set_tag_compile,
+    route_set_tag_free
+  };
+
+#define MATCH_STR "Match values from routing table\n"
+#define SET_STR "Set values in destination routing protocol\n"
+
+DEFUN (match_metric,
+       match_metric_cmd,
+       "match metric <0-4294967295>",
+       MATCH_STR
+       "Match metric of route\n"
+       "Metric value\n")
+{
+  return eigrp_route_match_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_match_metric,
+       no_match_metric_cmd,
+       "no match metric",
+       NO_STR
+       MATCH_STR
+       "Match metric of route\n")
+{
+  if (argc == 0)
+    return eigrp_route_match_delete (vty, vty->index, "metric", NULL);
+
+  return eigrp_route_match_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_match_metric,
+       no_match_metric_val_cmd,
+       "no match metric <0-4294967295>",
+       NO_STR
+       MATCH_STR
+       "Match metric of route\n"
+       "Metric value\n")
+
+DEFUN (match_interface,
+       match_interface_cmd,
+       "match interface WORD",
+       MATCH_STR
+       "Match first hop interface of route\n"
+       "Interface name\n")
+{
+  return eigrp_route_match_add (vty, vty->index, "interface", argv[0]);
+}
+
+DEFUN (no_match_interface,
+       no_match_interface_cmd,
+       "no match interface",
+       NO_STR
+       MATCH_STR
+       "Match first hop interface of route\n")
+{
+  if (argc == 0)
+    return eigrp_route_match_delete (vty, vty->index, "interface", NULL);
+
+  return eigrp_route_match_delete (vty, vty->index, "interface", argv[0]);
+}
+
+ALIAS (no_match_interface,
+       no_match_interface_val_cmd,
+       "no match interface WORD",
+       NO_STR
+       MATCH_STR
+       "Match first hop interface of route\n"
+       "Interface name\n")
+
+DEFUN (match_ip_next_hop,
+       match_ip_next_hop_cmd,
+       "match ip next-hop (<1-199>|<1300-2699>|WORD)",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n")
+{
+  return eigrp_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop,
+       no_match_ip_next_hop_cmd,
+       "no match ip next-hop",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n")
+{
+  if (argc == 0)
+    return eigrp_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+
+  return eigrp_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop,
+       no_match_ip_next_hop_val_cmd,
+       "no match ip next-hop (<1-199>|<1300-2699>|WORD)",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n")
+
+DEFUN (match_ip_next_hop_prefix_list,
+       match_ip_next_hop_prefix_list_cmd,
+       "match ip next-hop prefix-list WORD",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return eigrp_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop_prefix_list,
+       no_match_ip_next_hop_prefix_list_cmd,
+       "no match ip next-hop prefix-list",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n")
+{
+  if (argc == 0)
+    return eigrp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL);
+
+  return eigrp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop_prefix_list,
+       no_match_ip_next_hop_prefix_list_val_cmd,
+       "no match ip next-hop prefix-list WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFUN (match_ip_address,
+       match_ip_address_cmd,
+       "match ip address (<1-199>|<1300-2699>|WORD)",
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n")
+{
+  return eigrp_route_match_add (vty, vty->index, "ip address", argv[0]);
+}
+
+DEFUN (no_match_ip_address,
+       no_match_ip_address_cmd,
+       "no match ip address",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n")
+{
+  if (argc == 0)
+    return eigrp_route_match_delete (vty, vty->index, "ip address", NULL);
+
+  return eigrp_route_match_delete (vty, vty->index, "ip address", argv[0]);
+}
+
+ALIAS (no_match_ip_address,
+       no_match_ip_address_val_cmd,
+       "no match ip address (<1-199>|<1300-2699>|WORD)",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n")
+
+DEFUN (match_ip_address_prefix_list,
+       match_ip_address_prefix_list_cmd,
+       "match ip address prefix-list WORD",
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return eigrp_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_address_prefix_list,
+       no_match_ip_address_prefix_list_cmd,
+       "no match ip address prefix-list",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n")
+{
+  if (argc == 0)
+    return eigrp_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
+
+  return eigrp_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_address_prefix_list,
+       no_match_ip_address_prefix_list_val_cmd,
+       "no match ip address prefix-list WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFUN (match_tag,
+       match_tag_cmd,
+       "match tag <0-65535>",
+       MATCH_STR
+       "Match tag of route\n"
+       "Metric value\n")
+{
+  return eigrp_route_match_add (vty, vty->index, "tag", argv[0]);
+}
+
+DEFUN (no_match_tag,
+       no_match_tag_cmd,
+       "no match tag",
+       NO_STR
+       MATCH_STR
+       "Match tag of route\n")
+{
+  if (argc == 0)
+    return eigrp_route_match_delete (vty, vty->index, "tag", NULL);
+
+  return eigrp_route_match_delete (vty, vty->index, "tag", argv[0]);
+}
+
+ALIAS (no_match_tag,
+       no_match_tag_val_cmd,
+       "no match tag <0-65535>",
+       NO_STR
+       MATCH_STR
+       "Match tag of route\n"
+       "Metric value\n")
+
+/* set functions */
+
+DEFUN (set_metric,
+       set_metric_cmd,
+       "set metric <0-4294967295>",
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n")
+{
+  return eigrp_route_set_add (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (set_metric,
+       set_metric_addsub_cmd,
+       "set metric <+/-metric>",
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Add or subtract metric\n")
+
+DEFUN (no_set_metric,
+       no_set_metric_cmd,
+       "no set metric",
+       NO_STR
+       SET_STR
+       "Metric value for destination routing protocol\n")
+{
+  if (argc == 0)
+    return eigrp_route_set_delete (vty, vty->index, "metric", NULL);
+
+  return eigrp_route_set_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_set_metric,
+       no_set_metric_val_cmd,
+       "no set metric (<0-4294967295>|<+/-metric>)",
+       NO_STR
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n"
+       "Add or subtract metric\n")
+
+DEFUN (set_ip_nexthop,
+       set_ip_nexthop_cmd,
+       "set ip next-hop A.B.C.D",
+       SET_STR
+       IP_STR
+       "Next hop address\n"
+       "IP address of next hop\n")
+{
+  union sockunion su;
+  int ret;
+
+  ret = str2sockunion (argv[0], &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Malformed next-hop address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return eigrp_route_set_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_set_ip_nexthop,
+       no_set_ip_nexthop_cmd,
+       "no set ip next-hop",
+       NO_STR
+       SET_STR
+       IP_STR
+       "Next hop address\n")
+{
+  if (argc == 0)
+    return eigrp_route_set_delete (vty, vty->index, "ip next-hop", NULL);
+
+  return eigrp_route_set_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_set_ip_nexthop,
+       no_set_ip_nexthop_val_cmd,
+       "no set ip next-hop A.B.C.D",
+       NO_STR
+       SET_STR
+       IP_STR
+       "Next hop address\n"
+       "IP address of next hop\n")
+
+DEFUN (set_tag,
+       set_tag_cmd,
+       "set tag <0-65535>",
+       SET_STR
+       "Tag value for routing protocol\n"
+       "Tag value\n")
+{
+  return eigrp_route_set_add (vty, vty->index, "tag", argv[0]);
+}
+
+DEFUN (no_set_tag,
+       no_set_tag_cmd,
+       "no set tag",
+       NO_STR
+       SET_STR
+       "Tag value for routing protocol\n")
+{
+  if (argc == 0)
+    return eigrp_route_set_delete (vty, vty->index, "tag", NULL);
+
+  return eigrp_route_set_delete (vty, vty->index, "tag", argv[0]);
+}
+
+ALIAS (no_set_tag,
+       no_set_tag_val_cmd,
+       "no set tag <0-65535>",
+       NO_STR
+       SET_STR
+       "Tag value for routing protocol\n"
+       "Tag value\n")
+
+
+/* Route-map init */
+void
+eigrp_route_map_init ()
+{
+  route_map_init ();
+  route_map_init_vty ();
+  route_map_add_hook (eigrp_route_map_update);
+  route_map_delete_hook (eigrp_route_map_update);
+  
+  /*route_map_install_match (&route_match_metric_cmd);
+    route_map_install_match (&route_match_interface_cmd);*/
+  /*route_map_install_match (&route_match_ip_next_hop_cmd);
+    route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
+    route_map_install_match (&route_match_ip_address_cmd);
+    route_map_install_match (&route_match_ip_address_prefix_list_cmd);*/
+  /*route_map_install_match (&route_match_tag_cmd);*/
+  
+  /*route_map_install_set (&route_set_metric_cmd);
+    route_map_install_set (&route_set_ip_nexthop_cmd);
+    route_map_install_set (&route_set_tag_cmd);*/
+  
+  /*install_element (RMAP_NODE, &route_match_metric_cmd);
+    install_element (RMAP_NODE, &no_match_metric_cmd);
+    install_element (RMAP_NODE, &no_match_metric_val_cmd);
+    install_element (RMAP_NODE, &route_match_interface_cmd);
+    install_element (RMAP_NODE, &no_match_interface_cmd);
+    install_element (RMAP_NODE, &no_match_interface_val_cmd);
+    install_element (RMAP_NODE, &route_match_ip_next_hop_cmd);
+    install_element (RMAP_NODE, &no_match_ip_next_hop_cmd);
+    install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd);
+    install_element (RMAP_NODE, &route_match_ip_next_hop_prefix_list_cmd);
+    install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+    install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd);*/
+  /*install_element (RMAP_NODE, &route_match_ip_address_cmd);
+    install_element (RMAP_NODE, &no_match_ip_address_cmd);
+    install_element (RMAP_NODE, &no_match_ip_address_val_cmd);
+    install_element (RMAP_NODE, &route_match_ip_address_prefix_list_cmd);
+    install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
+    install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);*/
+  /*install_element (RMAP_NODE, &route_match_tag_cmd);
+    install_element (RMAP_NODE, &no_match_tag_cmd);
+    install_element (RMAP_NODE, &no_match_tag_val_cmd);*/
+
+  /*install_element (RMAP_NODE, &set_metric_cmd);
+    install_element (RMAP_NODE, &set_metric_addsub_cmd);
+    install_element (RMAP_NODE, &no_set_metric_cmd);
+    install_element (RMAP_NODE, &no_set_metric_val_cmd);
+    install_element (RMAP_NODE, &set_ip_nexthop_cmd);
+    install_element (RMAP_NODE, &no_set_ip_nexthop_cmd);
+    install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd);
+    install_element (RMAP_NODE, &set_tag_cmd);
+    install_element (RMAP_NODE, &no_set_tag_cmd);
+    install_element (RMAP_NODE, &no_set_tag_val_cmd);*/
+}
diff --git a/eigrpd/eigrp_routemap.h b/eigrpd/eigrp_routemap.h
new file mode 100644 (file)
index 0000000..0fee25b
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * eigrp_routemap.h
+ *
+ *  Created on: Nov 19, 2015
+ *      Author: root
+ */
+
+#ifndef EIGRPD_EIGRP_ROUTEMAP_H_
+#define EIGRPD_EIGRP_ROUTEMAP_H_
+
+extern void eigrp_route_map_update (const char *);
+extern void eigrp_route_map_init ();
+extern void eigrp_if_rmap_update (struct if_rmap *);
+extern void eigrp_if_rmap_update_interface (struct interface *);
+extern void eigrp_routemap_update_redistribute (void);
+extern void eigrp_rmap_update (const char *);
+
+#endif /* EIGRPD_EIGRP_ROUTEMAP_H_ */
diff --git a/eigrpd/eigrp_siaquery.c b/eigrpd/eigrp_siaquery.c
new file mode 100644 (file)
index 0000000..b041300
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * EIGRP Sending and Receiving EIGRP SIA-Query Packets.
+ * Copyright (C) 2013-2014
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
+#include "vty.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_macros.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_memory.h"
+
+/*EIGRP SIA-QUERY read function*/
+void
+eigrp_siaquery_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
+                        struct stream * s, struct eigrp_interface *ei, int size)
+{
+  struct eigrp_neighbor *nbr;
+  struct TLV_IPv4_Internal_type *tlv;
+
+  u_int16_t type;
+
+  /* increment statistics. */
+  ei->siaQuery_in++;
+
+  /* get neighbor struct */
+  nbr = eigrp_nbr_get(ei, eigrph, iph);
+
+  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
+  assert(nbr);
+
+  nbr->recv_sequence_number = ntohl(eigrph->sequence);
+
+  while (s->endp > s->getp)
+    {
+      type = stream_getw(s);
+      if (type == EIGRP_TLV_IPv4_INT)
+        {
+          stream_set_getp(s, s->getp - sizeof(u_int16_t));
+
+          tlv = eigrp_read_ipv4_tlv(s);
+
+          struct prefix_ipv4 *dest_addr;
+          dest_addr = prefix_ipv4_new();
+          dest_addr->prefix = tlv->destination;
+          dest_addr->prefixlen = tlv->prefix_length;
+          struct eigrp_prefix_entry *dest =
+            eigrp_topology_table_lookup_ipv4(eigrp->topology_table, dest_addr);
+
+          /* If the destination exists (it should, but one never know)*/
+          if (dest != NULL)
+            {
+              struct eigrp_fsm_action_message *msg;
+              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
+                            sizeof(struct eigrp_fsm_action_message));
+              struct eigrp_neighbor_entry *entry =
+                eigrp_prefix_entry_lookup(dest->entries, nbr);
+              msg->packet_type = EIGRP_OPC_SIAQUERY;
+              msg->eigrp = eigrp;
+              msg->data_type = EIGRP_TLV_IPv4_INT;
+              msg->adv_router = nbr;
+              msg->data.ipv4_int_type = tlv;
+              msg->entry = entry;
+              msg->prefix = dest;
+              int event = eigrp_get_fsm_event(msg);
+              eigrp_fsm_event(msg, event);
+            }
+          eigrp_IPv4_InternalTLV_free (tlv);
+        }
+    }
+  eigrp_hello_send_ack(nbr);
+}
+
+void
+eigrp_send_siaquery (struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
+{
+  struct eigrp_packet *ep;
+  u_int16_t length = EIGRP_HEADER_LEN;
+
+  ep = eigrp_packet_new(nbr->ei->ifp->mtu);
+
+  /* Prepare EIGRP INIT UPDATE header */
+  eigrp_packet_header_init(EIGRP_OPC_SIAQUERY, nbr->ei, ep->s, 0,
+                           nbr->ei->eigrp->sequence_number, 0);
+
+  // encode Authentication TLV, if needed
+  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
+     (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+    {
+      length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
+    }
+
+  length += eigrp_add_internalTLV_to_stream(ep->s, pe);
+
+  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
+     (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+    {
+      eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
+    }
+
+  /* EIGRP Checksum */
+  eigrp_packet_checksum(nbr->ei, ep->s, length);
+
+  ep->length = length;
+  ep->dst.s_addr = nbr->src.s_addr;
+
+  /*This ack number we await from neighbor*/
+  ep->sequence_number = nbr->ei->eigrp->sequence_number;
+
+  if (nbr->state == EIGRP_NEIGHBOR_UP)
+    {
+      /*Put packet to retransmission queue*/
+      eigrp_fifo_push_head(nbr->retrans_queue, ep);
+
+      if (nbr->retrans_queue->count == 1)
+        {
+          eigrp_send_packet_reliably(nbr);
+        }
+    }
+}
diff --git a/eigrpd/eigrp_siareply.c b/eigrpd/eigrp_siareply.c
new file mode 100644 (file)
index 0000000..4c4793f
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * EIGRP Sending and Receiving EIGRP SIA-Reply Packets.
+ * Copyright (C) 2013-2014
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
+#include "vty.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_macros.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_memory.h"
+
+/*EIGRP SIA-REPLY read function*/
+void
+eigrp_siareply_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
+                        struct stream * s, struct eigrp_interface *ei, int size)
+{
+  struct eigrp_neighbor *nbr;
+  struct TLV_IPv4_Internal_type *tlv;
+
+  u_int16_t type;
+
+  /* increment statistics. */
+  ei->siaReply_in++;
+
+  /* get neighbor struct */
+  nbr = eigrp_nbr_get(ei, eigrph, iph);
+
+  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
+  assert(nbr);
+
+  nbr->recv_sequence_number = ntohl(eigrph->sequence);
+
+  while (s->endp > s->getp)
+    {
+      type = stream_getw(s);
+      if (type == EIGRP_TLV_IPv4_INT)
+        {
+          stream_set_getp(s, s->getp - sizeof(u_int16_t));
+
+          tlv = eigrp_read_ipv4_tlv(s);
+
+          struct prefix_ipv4 *dest_addr;
+          dest_addr = prefix_ipv4_new();
+          dest_addr->prefix = tlv->destination;
+          dest_addr->prefixlen = tlv->prefix_length;
+          struct eigrp_prefix_entry *dest =
+            eigrp_topology_table_lookup_ipv4(eigrp->topology_table, dest_addr);
+
+          /* If the destination exists (it should, but one never know)*/
+          if (dest != NULL)
+            {
+              struct eigrp_fsm_action_message *msg;
+              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
+                            sizeof(struct eigrp_fsm_action_message));
+              struct eigrp_neighbor_entry *entry =
+                eigrp_prefix_entry_lookup(dest->entries, nbr);
+              msg->packet_type = EIGRP_OPC_SIAQUERY;
+              msg->eigrp = eigrp;
+              msg->data_type = EIGRP_TLV_IPv4_INT;
+              msg->adv_router = nbr;
+              msg->data.ipv4_int_type = tlv;
+              msg->entry = entry;
+              msg->prefix = dest;
+              int event = eigrp_get_fsm_event(msg);
+              eigrp_fsm_event(msg, event);
+            }
+          eigrp_IPv4_InternalTLV_free (tlv);
+        }
+    }
+  eigrp_hello_send_ack(nbr);
+}
+
+void
+eigrp_send_siareply (struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
+{
+  struct eigrp_packet *ep;
+  u_int16_t length = EIGRP_HEADER_LEN;
+
+  ep = eigrp_packet_new(nbr->ei->ifp->mtu);
+
+  /* Prepare EIGRP INIT UPDATE header */
+  eigrp_packet_header_init(EIGRP_OPC_SIAREPLY, nbr->ei, ep->s, 0,
+                           nbr->ei->eigrp->sequence_number, 0);
+
+  // encode Authentication TLV, if needed
+  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
+     (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+    {
+      length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
+    }
+
+  length += eigrp_add_internalTLV_to_stream(ep->s, pe);
+
+  if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
+     (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+    {
+      eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
+    }
+
+  /* EIGRP Checksum */
+  eigrp_packet_checksum(nbr->ei, ep->s, length);
+
+  ep->length = length;
+  ep->dst.s_addr = nbr->src.s_addr;
+
+  /*This ack number we await from neighbor*/
+  ep->sequence_number = nbr->ei->eigrp->sequence_number;
+
+  if (nbr->state == EIGRP_NEIGHBOR_UP)
+    {
+      /*Put packet to retransmission queue*/
+      eigrp_fifo_push_head(nbr->retrans_queue, ep);
+
+      if (nbr->retrans_queue->count == 1)
+        {
+          eigrp_send_packet_reliably(nbr);
+        }
+    }
+}
+
+
diff --git a/eigrpd/eigrp_snmp.c b/eigrpd/eigrp_snmp.c
new file mode 100644 (file)
index 0000000..f18894b
--- /dev/null
@@ -0,0 +1,1389 @@
+/*
+ * EIGRP SNMP Support.
+ * Copyright (C) 2013-2014
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_SNMP
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "sockunion.h"
+#include "stream.h"
+#include "log.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
+#include "keychain.h"
+#include "smux.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_snmp.h"
+
+struct list *eigrp_snmp_iflist;
+
+/* Declare static local variables for convenience. */
+SNMP_LOCAL_VARIABLES
+
+/* EIGRP-MIB - 1.3.6.1.4.1.9.9.449.1*/
+#define EIGRPMIB 1,3,6,1,4,1,9,9,449,1
+
+/* EIGRP-MIB instances. */
+oid eigrp_oid [] = { EIGRPMIB };
+
+/* EIGRP VPN entry */
+#define EIGRPVPNID                                             1
+#define EIGRPVPNNAME                                           2
+
+/* EIGRP Traffic statistics entry */
+#define EIGRPASNUMBER                                  1
+#define EIGRPNBRCOUNT                                  2
+#define EIGRPHELLOSSENT                                        3
+#define EIGRPHELLOSRCVD                                        4
+#define EIGRPUPDATESSENT                               5
+#define EIGRPUPDATESRCVD                               6
+#define EIGRPQUERIESSENT                               7
+#define EIGRPQUERIESRCVD                               8
+#define EIGRPREPLIESSENT                               9
+#define EIGRPREPLIESRCVD                               10
+#define EIGRPACKSSENT                                  11
+#define EIGRPACKSRCVD                                  12
+#define EIGRPINPUTQHIGHMARK                            13
+#define EIGRPINPUTQDROPS                               14
+#define EIGRPSIAQUERIESSENT                            15
+#define EIGRPSIAQUERIESRCVD                            16
+#define EIGRPASROUTERIDTYPE                            17
+#define EIGRPASROUTERID                                        18
+#define EIGRPTOPOROUTES                                        19
+#define EIGRPHEADSERIAL                                        20
+#define EIGRPNEXTSERIAL                                        21
+#define EIGRPXMITPENDREPLIES                           22
+#define EIGRPXMITDUMMIES                               23
+
+/* EIGRP topology entry */
+#define EIGRPDESTNETTYPE                               1
+#define EIGRPDESTNET                                   2
+#define EIGRPDESTNETPREFIXLEN                          4
+#define EIGRPACTIVE                                    5
+#define EIGRPSTUCKINACTIVE                             6
+#define EIGRPDESTSUCCESSORS                            7
+#define EIGRPFDISTANCE                                 8
+#define EIGRPROUTEORIGINTYPE                           9
+#define EIGRPROUTEORIGINADDRTYPE                       10
+#define EIGRPROUTEORIGINADDR                           11
+#define EIGRPNEXTHOPADDRESSTYPE                                12
+#define EIGRPNEXTHOPADDRESS                            13
+#define EIGRPNEXTHOPINTERFACE                          14
+#define EIGRPDISTANCE                                  15
+#define EIGRPREPORTDISTANCE                            16
+
+/* EIGRP peer entry */
+#define EIGRPHANDLE                                                    1
+#define EIGRPPEERADDRTYPE                                      2
+#define EIGRPPEERADDR                                          3
+#define EIGRPPEERIFINDEX                                       4
+#define EIGRPHOLDTIME                                          5
+#define EIGRPUPTIME                                                    6
+#define EIGRPSRTT                                                      7
+#define EIGRPRTO                                                       8
+#define EIGRPPKTSENQUEUED                                      9
+#define EIGRPLASTSEQ                                           10
+#define EIGRPVERSION                                           11
+#define EIGRPRETRANS                                           12
+#define EIGRPRETRIES                                           13
+
+/* EIGRP interface entry */
+#define EIGRPPEERCOUNT                                         3
+#define EIGRPXMITRELIABLEQ                                     4
+#define EIGRPXMITUNRELIABLEQ                   5
+#define EIGRPMEANSRTT                                          6
+#define EIGRPPACINGRELIABLE                                    7
+#define EIGRPPACINGUNRELIABLE                  8
+#define EIGRPMFLOWTIMER                                                9
+#define EIGRPPENDINGROUTES                                     10
+#define EIGRPHELLOINTERVAL                                     11
+#define EIGRPXMITNEXTSERIAL                                    12
+#define EIGRPUMCASTS                                           13
+#define EIGRPRMCASTS                                           14
+#define EIGRPUUCASTS                                           15
+#define EIGRPRUCASTS                                           16
+#define EIGRPMCASTEXCEPTS                                      17
+#define EIGRPCRPKTS                                                    18
+#define EIGRPACKSSUPPRESSED                                    19
+#define EIGRPRETRANSSENT                                       20
+#define EIGRPOOSRCVD                                           21
+#define EIGRPAUTHMODE                                          22
+#define EIGRPAUTHKEYCHAIN                                      23
+
+/* SNMP value hack. */
+#define COUNTER                 ASN_COUNTER
+#define INTEGER                 ASN_INTEGER
+#define GAUGE                   ASN_GAUGE
+#define TIMETICKS               ASN_TIMETICKS
+#define IPADDRESS               ASN_IPADDRESS
+#define STRING                  ASN_OCTET_STR
+#define IPADDRESSPREFIXLEN      ASN_INTEGER
+#define IPADDRESSTYPE           ASN_INTEGER
+#define INTERFACEINDEXORZERO    ASN_INTEGER
+#define UINTEGER                ASN_UNSIGNED
+
+
+
+
+/* Hook functions. */
+static u_char *eigrpVpnEntry (struct variable *, oid *, size_t *,
+                              int, size_t *, WriteMethod **);
+static u_char *eigrpTraffStatsEntry (struct variable *, oid *, size_t *, int,
+                                     size_t *, WriteMethod **);
+static u_char *eigrpTopologyEntry (struct variable *, oid *, size_t *,
+                                   int, size_t *, WriteMethod **);
+static u_char *eigrpPeerEntry (struct variable *, oid *, size_t *, int,
+                               size_t *, WriteMethod **);
+static u_char *eigrpInterfaceEntry (struct variable *, oid *, size_t *, int,
+                                    size_t *, WriteMethod **);
+
+
+struct variable eigrp_variables[] =
+  {
+    /* EIGRP vpn variables */
+    {EIGRPVPNID,               INTEGER, NOACCESS, eigrpVpnEntry,
+     4, {1, 1, 1, 1}},
+    {EIGRPVPNNAME,             STRING, RONLY, eigrpVpnEntry,
+     4, {1, 1, 1, 2}},
+
+    /* EIGRP traffic stats variables */
+    {EIGRPASNUMBER,                    UINTEGER, NOACCESS, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 1}},
+    {EIGRPNBRCOUNT,                    UINTEGER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 2}},
+    {EIGRPHELLOSSENT,                  COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 3}},
+    {EIGRPHELLOSRCVD,                  COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 4}},
+    {EIGRPUPDATESSENT,                 COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 5}},
+    {EIGRPUPDATESRCVD,                 COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 6}},
+    {EIGRPQUERIESSENT,            COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 7}},
+    {EIGRPQUERIESRCVD,            COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 8}},
+    {EIGRPREPLIESSENT,                 COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 9}},
+    {EIGRPREPLIESRCVD,            COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 10}},
+    {EIGRPACKSSENT,               COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 11}},
+    {EIGRPACKSRCVD,               COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 12}},
+    {EIGRPINPUTQHIGHMARK,         INTEGER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 13}},
+    {EIGRPINPUTQDROPS,                 COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 14}},
+    {EIGRPSIAQUERIESSENT,              COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 15}},
+    {EIGRPSIAQUERIESRCVD,              COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 16}},
+    {EIGRPASROUTERIDTYPE,         IPADDRESSTYPE, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 17}},
+    {EIGRPASROUTERID,                  IPADDRESS, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 18}},
+    {EIGRPTOPOROUTES,                  COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 19}},
+    {EIGRPHEADSERIAL,                  COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 20}},
+    {EIGRPNEXTSERIAL,                  COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 21}},
+    {EIGRPXMITPENDREPLIES,             INTEGER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 22}},
+    {EIGRPXMITDUMMIES,                 COUNTER, RONLY, eigrpTraffStatsEntry,
+     4, {2, 1, 1, 23}},
+
+    /* EIGRP topology variables */
+    {EIGRPDESTNETTYPE,                 IPADDRESSTYPE, NOACCESS, eigrpTopologyEntry,
+     4, {3, 1, 1, 1}},
+    {EIGRPDESTNET,                             IPADDRESSPREFIXLEN, NOACCESS, eigrpTopologyEntry,
+     4, {3, 1, 1, 2}},
+    {EIGRPDESTNETPREFIXLEN,            IPADDRESSTYPE, NOACCESS, eigrpTopologyEntry,
+     4, {3, 1, 1, 4}},
+    {EIGRPACTIVE,                              INTEGER, RONLY, eigrpTopologyEntry,
+     4, {3, 1, 1, 5}},
+    {EIGRPSTUCKINACTIVE,               INTEGER, RONLY, eigrpTopologyEntry,
+     4, {3, 1, 1, 6}},
+    {EIGRPDESTSUCCESSORS,              INTEGER, RONLY, eigrpTopologyEntry,
+     4, {3, 1, 1, 7}},
+    {EIGRPFDISTANCE,                   INTEGER, RONLY, eigrpTopologyEntry,
+     4, {3, 1, 1, 8}},
+    {EIGRPROUTEORIGINTYPE,             STRING, RONLY, eigrpTopologyEntry,
+     4, {3, 1, 1, 9}},
+    {EIGRPROUTEORIGINADDRTYPE,    IPADDRESSTYPE, RONLY, eigrpTopologyEntry,
+     4, {3, 1, 1, 10}},
+    {EIGRPROUTEORIGINADDR,             IPADDRESS, RONLY, eigrpTopologyEntry,
+     4, {3, 1, 1, 11}},
+    {EIGRPNEXTHOPADDRESSTYPE,     IPADDRESSTYPE, RONLY, eigrpTopologyEntry,
+     4, {3, 1, 1, 12}},
+    {EIGRPNEXTHOPADDRESS,              IPADDRESS, RONLY, eigrpTopologyEntry,
+     4, {3, 1, 1, 13}},
+    {EIGRPNEXTHOPINTERFACE,       STRING, RONLY, eigrpTopologyEntry,
+     4, {3, 1, 1, 14}},
+    {EIGRPDISTANCE,                    INTEGER, RONLY, eigrpTopologyEntry,
+     4, {3, 1, 1, 15}},
+    {EIGRPREPORTDISTANCE,              INTEGER, RONLY, eigrpTopologyEntry,
+     4, {3, 1, 1, 16}},
+
+    /* EIGRP peer variables */
+    {EIGRPHANDLE,                      INTEGER, NOACCESS, eigrpPeerEntry,
+     4, {4, 1, 1, 1}},
+    {EIGRPPEERADDRTYPE,        IPADDRESSTYPE, RONLY, eigrpPeerEntry,
+     4, {4, 1, 1, 2}},
+    {EIGRPPEERADDR,                    IPADDRESS, RONLY, eigrpPeerEntry,
+     4, {4, 1, 1, 3}},
+    {EIGRPPEERIFINDEX,                 INTERFACEINDEXORZERO, RONLY, eigrpPeerEntry,
+     4, {4, 1, 1, 4}},
+    {EIGRPHOLDTIME,                    INTEGER, RONLY, eigrpPeerEntry,
+     4, {4, 1, 1, 5}},
+    {EIGRPUPTIME,                      STRING, RONLY, eigrpPeerEntry,
+     4, {4, 1, 1, 6}},
+    {EIGRPSRTT,                        INTEGER, RONLY, eigrpPeerEntry,
+     4, {4, 1, 1, 7}},
+    {EIGRPRTO,                         INTEGER, RONLY, eigrpPeerEntry,
+     4, {4, 1, 1, 8}},
+    {EIGRPPKTSENQUEUED,                        INTEGER, RONLY, eigrpPeerEntry,
+     4, {4, 1, 1, 9}},
+    {EIGRPLASTSEQ,                     INTEGER, RONLY, eigrpPeerEntry,
+     4, {4, 1, 1, 10}},
+    {EIGRPVERSION,                     STRING, RONLY, eigrpPeerEntry,
+     4, {4, 1, 1, 11}},
+    {EIGRPRETRANS,                     COUNTER, RONLY, eigrpPeerEntry,
+     4, {4, 1, 1, 12}},
+    {EIGRPRETRIES,                     INTEGER, RONLY, eigrpPeerEntry,
+     4, {4, 1, 1, 13}},
+
+    /* EIGRP interface variables */
+    {EIGRPPEERCOUNT,                   GAUGE, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 3}},
+    {EIGRPXMITRELIABLEQ,               GAUGE, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 4}},
+    {EIGRPXMITUNRELIABLEQ,             GAUGE, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 5}},
+    {EIGRPMEANSRTT,                    INTEGER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 6}},
+    {EIGRPPACINGRELIABLE,              INTEGER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 7}},
+    {EIGRPPACINGUNRELIABLE,       INTEGER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 8}},
+    {EIGRPMFLOWTIMER,                  INTEGER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 9}},
+    {EIGRPPENDINGROUTES,               GAUGE, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 10}},
+    {EIGRPHELLOINTERVAL,               INTEGER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 11}},
+    {EIGRPXMITNEXTSERIAL,              COUNTER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 12}},
+    {EIGRPUMCASTS,                     COUNTER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 13}},
+    {EIGRPRMCASTS,                     COUNTER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 14}},
+    {EIGRPUUCASTS,                     COUNTER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 15}},
+    {EIGRPRUCASTS,                     COUNTER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 16}},
+    {EIGRPMCASTEXCEPTS,        COUNTER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 17}},
+    {EIGRPCRPKTS,                              COUNTER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 18}},
+    {EIGRPACKSSUPPRESSED,              COUNTER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 19}},
+    {EIGRPRETRANSSENT,                 COUNTER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 20}},
+    {EIGRPOOSRCVD,                     COUNTER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 21}},
+    {EIGRPAUTHMODE,                    INTEGER, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 22}},
+    {EIGRPAUTHKEYCHAIN,        STRING, RONLY, eigrpInterfaceEntry,
+     4, {5, 1, 1, 23}}
+};
+
+static struct eigrp_neighbor *
+eigrp_snmp_nbr_lookup (struct eigrp *eigrp, struct in_addr *nbr_addr,
+                       unsigned int *ifindex)
+{
+  struct listnode *node, *nnode, *node2, *nnode2;
+  struct eigrp_interface *ei;
+  struct eigrp_neighbor *nbr;
+
+  for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+    {
+      for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
+        {
+          if (IPV4_ADDR_SAME (&nbr->src, nbr_addr))
+            {
+              return nbr;
+            }
+        }
+    }
+  return NULL;
+}
+
+static struct eigrp_neighbor *
+eigrp_snmp_nbr_lookup_next (struct in_addr *nbr_addr, unsigned int *ifindex,
+                            int first)
+{
+  struct listnode *node, *nnode, *node2, *nnode2;
+  struct eigrp_interface *ei;
+  struct eigrp_neighbor *nbr;
+  struct route_node *rn;
+  struct eigrp_neighbor *min = NULL;
+  struct eigrp *eigrp = eigrp;
+
+  eigrp = eigrp_lookup ();
+
+  for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+    {
+      for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
+        {
+          if (first)
+            {
+              if (! min)
+                min = nbr;
+              else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr))
+                min = nbr;
+            }
+          else if (ntohl (nbr->src.s_addr) > ntohl (nbr_addr->s_addr))
+            {
+              if (! min)
+                min = nbr;
+              else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr))
+                min = nbr;
+            }
+        }
+    }
+  if (min)
+    {
+      *nbr_addr = min->src;
+      *ifindex = 0;
+      return min;
+    }
+  return NULL;
+}
+
+static struct eigrp_neighbor *
+eigrpNbrLookup (struct variable *v, oid *name, size_t *length,
+                struct in_addr *nbr_addr, unsigned int *ifindex, int exact)
+{
+  unsigned int len;
+  int first;
+  struct eigrp_neighbor *nbr;
+  struct eigrp *eigrp;
+
+  eigrp = eigrp_lookup ();
+
+  if (! eigrp)
+    return NULL;
+
+  if (exact)
+    {
+      if (*length != v->namelen + IN_ADDR_SIZE + 1)
+        return NULL;
+
+      oid2in_addr (name + v->namelen, IN_ADDR_SIZE, nbr_addr);
+      *ifindex = name[v->namelen + IN_ADDR_SIZE];
+
+      return eigrp_snmp_nbr_lookup (eigrp, nbr_addr, ifindex);
+    }
+  else
+    {
+      first = 0;
+      len = *length - v->namelen;
+
+      if (len <= 0)
+        first = 1;
+
+      if (len > IN_ADDR_SIZE)
+        len = IN_ADDR_SIZE;
+
+      oid2in_addr (name + v->namelen, len, nbr_addr);
+
+      len = *length - v->namelen - IN_ADDR_SIZE;
+      if (len >= 1)
+        *ifindex = name[v->namelen + IN_ADDR_SIZE];
+
+      nbr = eigrp_snmp_nbr_lookup_next (nbr_addr, ifindex, first);
+
+      if (nbr)
+        {
+          *length = v->namelen + IN_ADDR_SIZE + 1;
+          oid_copy_addr (name + v->namelen, nbr_addr, IN_ADDR_SIZE);
+          name[v->namelen + IN_ADDR_SIZE] = *ifindex;
+          return nbr;
+        }
+    }
+  return NULL;
+}
+
+
+static u_char *
+eigrpVpnEntry (struct variable *v, oid *name, size_t *length,
+               int exact, size_t *var_len, WriteMethod **write_method)
+{
+  struct eigrp *eigrp;
+
+  eigrp = eigrp_lookup ();
+
+  /* Check whether the instance identifier is valid */
+  if (smux_header_generic (v, name, length, exact, var_len, write_method)
+      == MATCH_FAILED)
+    return NULL;
+
+  /* Return the current value of the variable */
+  switch (v->magic)
+    {
+    case EIGRPVPNID:           /* 1 */
+      /* The unique VPN identifier */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPVPNNAME:           /* 2 */
+      /* The name given to the VPN */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    default:
+      return NULL;
+    }
+  return NULL;
+}
+
+static uint32_t
+eigrp_neighbor_count(struct eigrp *eigrp)
+{
+  uint32_t count;
+  struct eigrp_interface *ei;
+  struct listnode *node, *node2, *nnode2;
+  struct eigrp_neighbor *nbr;
+
+  if (eigrp == NULL)
+    {
+      return 0;
+    }
+
+  count = 0;
+  for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+    {
+      for (ALL_LIST_ELEMENTS (ei->nbrs, node2, nnode2, nbr))
+        {
+          if (nbr->state == EIGRP_NEIGHBOR_UP)
+            count++;
+        }
+    }
+
+  return count;
+}
+
+
+static u_char *
+eigrpTraffStatsEntry (struct variable *v, oid *name, size_t *length,
+                      int exact, size_t *var_len, WriteMethod **write_method)
+{
+  struct eigrp *eigrp;
+  struct eigrp_interface *ei;
+  struct listnode *node, *nnode;
+  int counter;
+
+  eigrp = eigrp_lookup ();
+
+  /* Check whether the instance identifier is valid */
+  if (smux_header_generic (v, name, length, exact, var_len, write_method)
+      == MATCH_FAILED)
+    return NULL;
+
+  /* Return the current value of the variable */
+  switch (v->magic)
+    {
+    case EIGRPASNUMBER:                /* 1 */
+      /* AS-number of this EIGRP instance. */
+      if (eigrp)
+        return SNMP_INTEGER (eigrp->AS);
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPNBRCOUNT:           /* 2 */
+      /* Neighbor count of this EIGRP instance */
+      if (eigrp)
+        return SNMP_INTEGER (eigrp_neighbor_count (eigrp));
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPHELLOSSENT:           /* 3 */
+      /* Hello packets output count */
+      if (eigrp)
+        {
+          counter = 0;
+          for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+            {
+              counter += ei->hello_out;
+            }
+          return SNMP_INTEGER (counter);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPHELLOSRCVD:           /* 4 */
+      /* Hello packets input count */
+      if (eigrp)
+        {
+          counter = 0;
+          for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+            {
+              counter += ei->hello_in;
+            }
+          return SNMP_INTEGER (counter);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPUPDATESSENT:           /* 5 */
+      /* Update packets output count */
+      if (eigrp)
+        {
+          counter = 0;
+          for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+            {
+              counter += ei->update_out;
+            }
+          return SNMP_INTEGER (counter);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPUPDATESRCVD:           /* 6 */
+      /* Update packets input count */
+      if (eigrp)
+        {
+          counter = 0;
+          for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+            {
+              counter += ei->update_in;
+            }
+          return SNMP_INTEGER (counter);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPQUERIESSENT:           /* 7 */
+      /* Querry packets output count */
+      if (eigrp)
+        {
+          counter = 0;
+          for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+            {
+              counter += ei->query_out;
+            }
+          return SNMP_INTEGER (counter);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPQUERIESRCVD:           /* 8 */
+      /* Querry packets input count */
+      if (eigrp)
+        {
+          counter = 0;
+          for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+            {
+              counter += ei->query_in;
+            }
+          return SNMP_INTEGER (counter);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPREPLIESSENT:           /* 9 */
+      /* Reply packets output count */
+      if (eigrp)
+        {
+          counter = 0;
+          for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+            {
+              counter += ei->reply_out;
+            }
+          return SNMP_INTEGER (counter);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPREPLIESRCVD:           /* 10 */
+      /* Reply packets input count */
+      if (eigrp)
+        {
+          counter = 0;
+          for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+            {
+              counter += ei->reply_in;
+            }
+          return SNMP_INTEGER (counter);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPACKSSENT:           /* 11 */
+      /* Acknowledgement packets output count */
+      if (eigrp)
+        {
+          counter = 0;
+          for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+            {
+              counter += ei->ack_out;
+            }
+          return SNMP_INTEGER (counter);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPACKSRCVD:           /* 12 */
+      /* Acknowledgement packets input count */
+      if (eigrp)
+        {
+          counter = 0;
+          for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+            {
+              counter += ei->ack_in;
+            }
+          return SNMP_INTEGER (counter);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPINPUTQHIGHMARK:           /* 13 */
+      /* The highest number of EIGRP packets in the input queue */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPINPUTQDROPS:           /* 14 */
+      /* The number of EIGRP packets dropped from the input queue */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPSIAQUERIESSENT:           /* 15 */
+      /* SIA querry packets output count */
+      if (eigrp)
+        {
+          counter = 0;
+          for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+            {
+              counter += ei->siaQuery_out;
+            }
+          return SNMP_INTEGER (counter);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPSIAQUERIESRCVD:           /* 16 */
+      /* SIA querry packets input count */
+      if (eigrp)
+        {
+          counter = 0;
+          for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei))
+            {
+              counter += ei->siaQuery_in;
+            }
+          return SNMP_INTEGER (counter);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPASROUTERIDTYPE:           /* 17 */
+      /* Whether the router ID is set manually or automatically */
+      if (eigrp)
+        if(eigrp->router_id_static!=0)
+          return SNMP_INTEGER(1);
+        else
+          return SNMP_INTEGER(1);
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPASROUTERID:           /* 18 */
+      /* Router ID for this EIGRP AS */
+      if (eigrp)
+        if(eigrp->router_id_static!=0)
+          return  SNMP_INTEGER (eigrp->router_id_static);
+        else
+          return  SNMP_INTEGER (eigrp->router_id);
+      else
+        return  SNMP_INTEGER (0);
+      break;
+    case EIGRPTOPOROUTES:           /* 19 */
+      /* The total number of EIGRP derived routes currently existing
+         in the topology table for the AS */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPHEADSERIAL:           /* 20 */
+      /* The serial number of the first route in the internal
+         sequence for an AS*/
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPNEXTSERIAL:           /* 21 */
+      /* The serial number that would be assigned to the next new
+       or changed route in the topology table for the AS*/
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPXMITPENDREPLIES:           /* 22 */
+      /* Total number of outstanding replies expected to queries
+         that have been sent to peers in the current AS*/
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPXMITDUMMIES:           /* 23 */
+      /* Total number of currently existing dummies associated with the AS*/
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    default:
+      return NULL;
+    }
+  return NULL;
+}
+
+static u_char *
+eigrpTopologyEntry (struct variable *v, oid *name, size_t *length,
+                    int exact, size_t *var_len, WriteMethod **write_method)
+{
+  struct eigrp *eigrp;
+  struct eigrp_interface *ei;
+  struct listnode *node, *nnode;
+
+  eigrp = eigrp_lookup ();
+
+  /* Check whether the instance identifier is valid */
+  if (smux_header_generic (v, name, length, exact, var_len, write_method)
+      == MATCH_FAILED)
+    return NULL;
+
+  /* Return the current value of the variable */
+  switch (v->magic)
+    {
+    case EIGRPDESTNETTYPE:           /* 1 */
+      /* The format of the destination IP network number for a single
+         route in the topology table*/
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPDESTNET:           /* 2 */
+      /* The destination IP network number for a single route in the topology table*/
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPDESTNETPREFIXLEN:           /* 4 */
+      /* The prefix length associated with the destination IP network address
+         for a single route in the topology table in the AS*/
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPACTIVE:           /* 5 */
+      /* A value of true(1) indicates the route to the destination network has failed
+         A value of false(2) indicates the route is stable (passive).*/
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPSTUCKINACTIVE:           /* 6 */
+      /* A value of true(1) indicates that that this route which is in active state
+         has not received any replies to queries for alternate paths */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPDESTSUCCESSORS:           /* 7 */
+      /* Next routing hop for a path to the destination IP network */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPFDISTANCE:           /* 8 */
+      /* Minimum distance from this router to the destination IP network */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPROUTEORIGINTYPE:           /* 9 */
+      /* Text string describing the internal origin of the EIGRP route */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPROUTEORIGINADDRTYPE:           /* 10 */
+      /* The format of the IP address defined as the origin of this
+         topology route entry */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPROUTEORIGINADDR:           /* 11 */
+       /* If the origin of the topology route entry is external to this router,
+          then this object is the IP address of the router from which it originated */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPNEXTHOPADDRESSTYPE:           /* 12 */
+      /* The format of the next hop IP address */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPNEXTHOPADDRESS:           /* 13 */
+      /* Next hop IP address for the route */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPNEXTHOPINTERFACE:           /* 14 */
+      /* The interface through which the next hop IP address is reached */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPDISTANCE:           /* 15 */
+      /* The computed distance to the destination network entry from this router */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPREPORTDISTANCE:           /* 16 */
+      /* The computed distance to the destination network in the topology entry
+         reported to this router by the originator of this route */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    default:
+      return NULL;
+    }
+  return NULL;
+}
+
+static u_char *
+eigrpPeerEntry (struct variable *v, oid *name, size_t *length,
+                int exact, size_t *var_len, WriteMethod **write_method)
+{
+  struct eigrp *eigrp;
+  struct eigrp_interface *ei;
+  struct listnode *node, *nnode;
+  struct eigrp_neighbor *nbr;
+  struct in_addr nbr_addr;
+  unsigned int ifindex;
+
+  eigrp = eigrp_lookup ();
+
+  /* Check whether the instance identifier is valid */
+  if (smux_header_generic (v, name, length, exact, var_len, write_method)
+      == MATCH_FAILED)
+    return NULL;
+
+  memset (&nbr_addr, 0, sizeof (struct in_addr));
+  ifindex = 0;
+
+  nbr = eigrpNbrLookup (v, name, length, &nbr_addr, &ifindex, exact);
+  if (! nbr)
+    return NULL;
+  ei = nbr->ei;
+  if (! ei)
+    return NULL;
+
+  /* Return the current value of the variable */
+  switch (v->magic)
+    {
+    case EIGRPHANDLE:           /* 1 */
+      /* The unique internal identifier for the peer in the AS */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPPEERADDRTYPE:           /* 2 */
+      /* The format of the remote source IP address used by the peer */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPPEERADDR:           /* 3 */
+      /* The source IP address used by the peer */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPPEERIFINDEX:           /* 4 */
+      /* The ifIndex of the interface on this router */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPHOLDTIME:           /* 5 */
+      /* How much time must pass without receiving a hello packet from this
+         EIGRP peer before this router declares the peer down */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPUPTIME:           /* 6 */
+      /* The elapsed time since the EIGRP adjacency was first established */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPSRTT:           /* 7 */
+      /* The computed smooth round trip time for packets to and from the peer */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPRTO:           /* 8 */
+      /* The computed retransmission timeout for the peer */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPPKTSENQUEUED:           /* 9 */
+      /* The number of any EIGRP packets currently enqueued */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPLASTSEQ:           /* 10 */
+      /* sequence number of the last EIGRP packet sent to this peer */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPVERSION:           /* 11 */
+      /* The EIGRP version information reported by the remote peer */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPRETRANS:           /* 12 */
+      /* The cumulative number of retransmissions to this peer */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPRETRIES:           /* 13 */
+      /* The number of times the current unacknowledged packet has been retried */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    default:
+      return NULL;
+    }
+  return NULL;
+}
+
+static u_char *
+eigrpInterfaceEntry (struct variable *v, oid *name, size_t *length,
+                     int exact, size_t *var_len, WriteMethod **write_method)
+{
+  struct eigrp *eigrp;
+  struct eigrp_interface *ei;
+  struct listnode *node, *nnode;
+  struct keychain *keychain;
+  struct list *keylist;
+  int counter;
+
+  eigrp = eigrp_lookup ();
+
+  /* Check whether the instance identifier is valid */
+  if (smux_header_generic (v, name, length, exact, var_len, write_method)
+      == MATCH_FAILED)
+    return NULL;
+
+  /* Return the current value of the variable */
+  switch (v->magic)
+    {
+    case EIGRPPEERCOUNT:           /* 3 */
+      /* The number of EIGRP adjacencies currently formed with
+         peers reached through this interface */
+      if (eigrp)
+        {
+          return SNMP_INTEGER (eigrp_neighbor_count (eigrp));
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPXMITRELIABLEQ:           /* 4 */
+      /* The number of EIGRP packets currently waiting in the reliable
+         transport transmission queue */
+      if (eigrp)
+        {
+          return SNMP_INTEGER (1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPXMITUNRELIABLEQ:           /* 5 */
+      /* The number of EIGRP packets currently waiting in the unreliable
+         transport transmission queue */
+      if (eigrp)
+        {
+          return SNMP_INTEGER (1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPMEANSRTT:           /* 6 */
+      /* The average of all the computed smooth round trip time values
+         for a packet to and from all peers established on this interface */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPPACINGRELIABLE:           /* 7 */
+      /* The configured time interval between EIGRP packet transmissions */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPPACINGUNRELIABLE:           /* 8 */
+      /* The configured time interval between EIGRP packet transmissions
+         on the interface when the unreliable transport method is used */
+      if (eigrp)
+        {
+          return SNMP_INTEGER (1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPMFLOWTIMER:           /* 9 */
+      /* The configured multicast flow control timer value */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPPENDINGROUTES:           /* 10 */
+      /* The number of queued EIGRP routing updates awaiting transmission */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPHELLOINTERVAL:           /* 11 */
+      /* The configured time interval between Hello packet transmissions */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPXMITNEXTSERIAL:           /* 12 */
+      /* The serial number of the next EIGRP packet that is to be queued
+         for transmission */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPUMCASTS:           /* 13 */
+      /* The total number of unreliable EIGRP multicast packets sent
+         on this interface */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPRMCASTS:           /* 14 */
+      /* The total number of reliable EIGRP multicast packets sent
+         on this interface */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPUUCASTS:           /* 15 */
+      /* The total number of unreliable EIGRP unicast packets sent
+         on this interface */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPRUCASTS:           /* 16 */
+      /* The total number of reliable EIGRP unicast packets sent
+         on this interface */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPMCASTEXCEPTS:           /* 17 */
+      /* The total number of EIGRP multicast exception transmissions */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPCRPKTS:           /* 18 */
+      /* The total number EIGRP Conditional-Receive packets sent on this interface */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPACKSSUPPRESSED:           /* 19 */
+      /* The total number of individual EIGRP acknowledgement packets that have been
+         suppressed and combined in an already enqueued outbound reliable packet on this interface */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPRETRANSSENT:           /* 20 */
+      /* The total number EIGRP packet retransmissions sent on the interface */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPOOSRCVD:           /* 21 */
+      /* The total number of out-of-sequence EIGRP packets received */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPAUTHMODE:           /* 22 */
+      /* The EIGRP authentication mode of the interface */
+      if (eigrp)
+        {
+          return SNMP_INTEGER(1);
+        }
+      else
+        return SNMP_INTEGER (0);
+      break;
+    case EIGRPAUTHKEYCHAIN:            /* 23 */
+      /* The name of the authentication key-chain configured
+         on this interface. */
+      keylist = keychain_list_get();
+      for (ALL_LIST_ELEMENTS (keylist, node, nnode, keychain))
+        {
+          return (u_char *) keychain->name;
+        }
+      if (eigrp && keychain)
+        {
+          *var_len = str_len (keychain->name);
+          return (u_char *) keychain->name;
+        }
+      else
+        return (u_char *) "TEST";
+      break;
+    default:
+      return NULL;
+    }
+  return NULL;
+}
+
+/* Register EIGRP-MIB. */
+void
+eigrp_snmp_init ()
+{
+  eigrp_snmp_iflist = list_new ();
+  smux_init (eigrp_om->master);
+  REGISTER_MIB("ciscoEigrpMIB", eigrp_variables, variable, eigrp_oid);
+}
+#endif
diff --git a/eigrpd/eigrp_snmp.h b/eigrpd/eigrp_snmp.h
new file mode 100644 (file)
index 0000000..ab14912
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * EIGRP SNMP Support.
+ * Copyright (C) 2013-2014
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+
+#ifndef _ZEBRA_EIGRP_SNMP_H
+#define _ZEBRA_EIGRP_SNMP_H
+
+extern void eigrp_snmp_init (void);
+
+
+#endif /* _ZEBRA_EIGRP_SNMP_H */
diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h
new file mode 100644 (file)
index 0000000..b891475
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * EIGRP Definition of Data Structures.
+ * Copyright (C) 2013-2016
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *   Frantisek Gazo
+ *   Tomas Hvorkovy
+ *   Martin Kontsek
+ *   Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_STRUCTS_H_
+#define _ZEBRA_EIGRP_STRUCTS_H_
+
+#include "filter.h"
+
+#include "eigrpd/eigrp_const.h"
+#include "eigrpd/eigrp_macros.h"
+
+/* EIGRP master for system wide configuration and variables. */
+struct eigrp_master
+{
+  /* EIGRP instance. */
+  struct list *eigrp;
+
+  /* EIGRP thread master. */
+  struct thread_master *master;
+
+  /* Zebra interface list. */
+  struct list *iflist;
+
+  /* EIGRP start time. */
+  time_t start_time;
+
+  /* Various EIGRP global configuration. */
+  u_char options;
+
+#define EIGRP_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */
+};
+
+struct eigrp_metrics
+{
+  u_int32_t delay;
+  u_int32_t bandwith;
+  unsigned char mtu[3];
+  u_char hop_count;
+  u_char reliability;
+  u_char load;
+  u_char tag;
+  u_char flags;
+};
+
+struct eigrp
+{
+  u_int16_t AS;                        /* Autonomous system number */
+  u_int16_t vrid;              /* Virtual Router ID */
+  u_char    k_values[6];       /*Array for K values configuration*/
+  u_char variance;              /*Metric variance multiplier*/
+  u_char max_paths;             /*Maximum allowed paths for 1 prefix*/
+
+  /*Name of this EIGRP instance*/
+  char *name;
+
+  /* EIGRP Router ID. */
+  u_int32_t router_id; /* Configured automatically. */
+  u_int32_t router_id_static; /* Configured manually. */
+
+  struct list *eiflist; /* eigrp interfaces */
+  u_char passive_interface_default; /* passive-interface default */
+
+  unsigned int fd;
+  unsigned int maxsndbuflen;
+
+  u_int32_t sequence_number; /*Global EIGRP sequence number*/
+
+  struct stream *ibuf;
+  struct list *oi_write_q;
+
+  /*Threads*/
+  struct thread *t_write;
+  struct thread *t_read;
+  struct thread *t_distribute; /* timer for distribute list */
+
+  struct route_table *networks; /* EIGRP config networks. */
+
+  struct list *topology_table;
+
+  uint64_t serno; /* Global serial number counter for topology entry changes*/
+  uint64_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;
+
+  uint64_t serno; /*Serial number for this entry. Increased with each change of entry*/
+};
+
+/* EIGRP Topology table record structure */
+struct eigrp_neighbor_entry
+{
+  struct eigrp_prefix_entry *prefix;
+  u_int32_t reported_distance;                                 //distance reported by neighbor
+  u_int32_t distance;                                          //sum of reported distance and link cost to advertised neighbor
+
+  struct eigrp_metrics reported_metric;
+  struct eigrp_metrics total_metric;
+
+  struct eigrp_neighbor *adv_router;           //ip address of advertising neighbor
+  u_char flags;                                                        //used for marking successor and FS
+
+  struct eigrp_interface *ei;                          //pointer for case of connected entry
+
+};
+
+//---------------------------------------------------------------------------------------------------------------------------------------------
+
+/* EIGRP Finite State Machine */
+
+struct eigrp_fsm_action_message
+{
+  u_char packet_type;                                  //UPDATE, QUERY, SIAQUERY, SIAREPLY
+  struct eigrp *eigrp;                                 // which thread sent mesg
+  struct eigrp_neighbor *adv_router;   //advertising neighbor
+  struct eigrp_neighbor_entry *entry;
+  struct eigrp_prefix_entry *prefix;
+  int data_type; // internal or external tlv type
+  union{
+    struct TLV_IPv4_External_type *ipv4_ext_data;
+    struct TLV_IPv4_Internal_type *ipv4_int_type;
+  }data;
+};
+
+#endif /* _ZEBRA_EIGRP_STRUCTURES_H_ */
diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c
new file mode 100644 (file)
index 0000000..25beb63
--- /dev/null
@@ -0,0 +1,563 @@
+/*
+ * 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 *);
+
+/*
+ * 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)
+{
+  struct eigrp *eigrp = eigrp_lookup ();
+
+  /*
+   * Emergency removal of the node from this list.
+   * Whatever it is.
+   */
+  listnode_delete(eigrp->topology_changes_internalIPV4, 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;
+}
+
+/*
+ * For a future optimization, put the successor list into it's
+ * own separate list from the full list?
+ *
+ * That way we can clean up all the list_new and list_delete's
+ * that we are doing.  DBS
+ */
+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);
+        }
+    }
+
+  /*
+   * If we have no successors return NULL
+   */
+  if (!successors->count)
+    {
+      list_delete(successors);
+      successors = NULL;
+    }
+
+  return successors;
+}
+
+struct list *
+eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node,
+                                 unsigned int maxpaths)
+{
+  struct list *successors = eigrp_topology_get_successor(table_node);
+  
+  if (successors && successors->count > maxpaths)
+    {
+      do
+        {
+          struct listnode *node = listtail(successors);
+
+          list_delete_node(successors, node);
+
+        } while (successors->count > maxpaths);
+    }
+
+  return successors;
+}
+
+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 <= (uint64_t)(dest->distance*eigrp->variance)) &&
+          entry->distance != EIGRP_MAX_METRIC) // is successor
+        {
+          entry->flags |= EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
+          entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG;
+        }
+      else if (entry->reported_distance < dest->fdistance) // is feasible successor
+        {
+          entry->flags |= EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG;
+          entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
+        }
+      else
+        {
+          entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_FSUCCESSOR_FLAG;
+          entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
+        }
+    }
+}
+
+void
+eigrp_update_routing_table(struct eigrp_prefix_entry * prefix)
+{
+  struct eigrp *eigrp = eigrp_lookup();
+  struct list *successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
+  struct listnode *node;
+  struct eigrp_neighbor_entry *entry;
+
+  if (successors)
+    {
+      eigrp_zebra_route_add(prefix->destination_ipv4, successors);
+      for (ALL_LIST_ELEMENTS_RO (successors, node, entry))
+        entry->flags |= EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG;
+
+      list_delete(successors);
+    }
+  else
+    {
+      eigrp_zebra_route_delete(prefix->destination_ipv4);
+      for (ALL_LIST_ELEMENTS_RO (prefix->entries, node, 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);
+    }
+}
diff --git a/eigrpd/eigrp_topology.h b/eigrpd/eigrp_topology.h
new file mode 100644 (file)
index 0000000..cb1ac79
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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 list *eigrp_topology_get_successor_max (struct eigrp_prefix_entry *pe, unsigned int maxpaths);
+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 * );
+
+#endif
diff --git a/eigrpd/eigrp_update.c b/eigrpd/eigrp_update.c
new file mode 100644 (file)
index 0000000..ee873bb
--- /dev/null
@@ -0,0 +1,1173 @@
+/*
+ * 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 = NULL;
+
+  /* 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 = NULL;
+
+  /* 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, VRF_DEFAULT),
+               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, VRF_DEFAULT));
+
+      /* 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, VRF_DEFAULT));
+
+      /* 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, VRF_DEFAULT));
+            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, VRF_DEFAULT));
+            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) == PREFIX_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) == PREFIX_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);
+
+              /*
+               * This code is a guess.  I am not actually
+               * sure that we should be doing this here.
+               * But for the moment it installs routes
+               * into the rib.  Which is good?
+               */
+              struct eigrp_fsm_action_message *msg;
+              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
+                            sizeof(struct eigrp_fsm_action_message));
+
+              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 = ne;
+              msg->prefix = pe;
+              int event = eigrp_get_fsm_event(msg);
+              eigrp_fsm_event(msg, event);
+            }
+          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) == PREFIX_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) == PREFIX_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) == PREFIX_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) == PREFIX_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) == PREFIX_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) == PREFIX_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) == PREFIX_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) == PREFIX_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, VRF_DEFAULT));
+    }
+  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, VRF_DEFAULT));
+
+      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, VRF_DEFAULT),
+                   VTY_NEWLINE);
+        }
+    }
+
+  prefixes = list_new();
+  /* add all prefixes from topology table to list */
+  for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node2, nnode2, pe2))
+    {
+      listnode_add(prefixes, pe2);
+    }
+
+  /* save prefixes to neighbor */
+  nbr->nbr_gr_prefixes_send = prefixes;
+  /* indicate, that this is first GR Update packet chunk */
+  nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_FIRST;
+  /* execute packet sending in thread */
+  nbr->t_nbr_send_gr = thread_execute(master, eigrp_update_send_GR_thread, nbr, 0);
+}
+
+/**
+ * @fn eigrp_update_send_interface_GR
+ *
+ * @param[in]          ei                      Interface to neighbors of which the GR is sent
+ * @param[in]          gr_type         Who executed Graceful restart
+ * @param[in]          vty             Virtual terminal for log output
+ *
+ * @return void
+ *
+ * @par
+ * Function used for sending Graceful restart Update packet
+ * to all neighbors on specified interface.
+ */
+void
+eigrp_update_send_interface_GR (struct eigrp_interface *ei, enum GR_type gr_type, struct vty *vty)
+{
+  struct listnode *node;
+  struct eigrp_neighbor *nbr;
+
+  /* iterate over all neighbors on eigrp interface */
+  for (ALL_LIST_ELEMENTS_RO(ei->nbrs, node, nbr))
+    {
+      /* send GR to neighbor */
+      eigrp_update_send_GR(nbr, gr_type, vty);
+    }
+}
+
+/**
+ * @fn eigrp_update_send_process_GR
+ *
+ * @param[in]          eigrp           EIGRP process
+ * @param[in]          gr_type         Who executed Graceful restart
+ * @param[in]          vty             Virtual terminal for log output
+ *
+ * @return void
+ *
+ * @par
+ * Function used for sending Graceful restart Update packet
+ * to all neighbors in eigrp process.
+ */
+void
+eigrp_update_send_process_GR (struct eigrp *eigrp, enum GR_type gr_type, struct vty *vty)
+{
+  struct listnode *node;
+  struct eigrp_interface *ei;
+
+  /* iterate over all eigrp interfaces */
+  for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+    {
+      /* send GR to all neighbors on interface */
+      eigrp_update_send_interface_GR(ei, gr_type, vty);
+    }
+}
diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c
new file mode 100644 (file)
index 0000000..1fc8c54
--- /dev/null
@@ -0,0 +1,1572 @@
+/*
+ * 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_NOSH (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 IFNAME",
+       "Suppress routing updates on an interface\n"
+       "Interface to suppress on\n")
+{
+  VTY_DECLVAR_CONTEXT(eigrp, eigrp);
+  struct eigrp_interface *ei;
+  struct listnode *node;
+  char *ifname = argv[1]->arg;
+
+  for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+    {
+      if (strcmp (ifname, ei->ifp->name) == 0)
+        SET_IF_PARAM (IF_DEF_PARAMS (ei->ifp), passive_interface);
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_passive_interface,
+       no_eigrp_passive_interface_cmd,
+       "no passive-interface IFNAME",
+       NO_STR
+       "Suppress routing updates on an interface\n"
+       "Interface to suppress on\n")
+{
+  VTY_DECLVAR_CONTEXT(eigrp, eigrp);
+  struct eigrp_interface *ei;
+  struct listnode *node;
+  char *ifname = argv[2]->arg;
+
+  for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+    {
+      if (strcmp (ifname, ei->ifp->name) == 0)
+        UNSET_IF_PARAM (IF_DEF_PARAMS (ei->ifp), passive_interface);
+    }
+
+  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",
+       "Specify a neighbor router\n"
+       "Neighbor address\n")
+{
+  //struct eigrp *eigrp = vty->index;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_eigrp_neighbor,
+       no_eigrp_neighbor_cmd,
+       "no neighbor A.B.C.D",
+       NO_STR
+       "Specify a neighbor router\n"
+       "Neighbor address\n")
+{
+  //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 [IFNAME] [detail]",
+       SHOW_STR
+       IP_STR
+       "IP-EIGRP show commands\n"
+       "IP-EIGRP interfaces\n"
+       "Interface name to look at\n"
+       "Detailed information\n")
+{
+  struct eigrp_interface *ei;
+  struct eigrp *eigrp;
+  struct listnode *node;
+  int idx = 0;
+  bool detail = false;
+  const char *ifname = NULL;
+
+  eigrp = eigrp_lookup ();
+  if (eigrp == NULL)
+    {
+      vty_out (vty, "EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  if (argv_find (argv, argc, "IFNAME", &idx))
+    ifname = argv[idx]->arg;
+
+  if (argv_find (argv, argc, "detail", &idx))
+    detail = true;
+
+  if (!ifname)
+    show_ip_eigrp_interface_header (vty, eigrp);
+
+  for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+    {
+      if (!ifname || strcmp (ei->ifp->name, ifname) == 0)
+        {
+          show_ip_eigrp_interface_sub (vty, eigrp, ei);
+          if (detail)
+            show_ip_eigrp_interface_detail (vty, eigrp, ei);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_eigrp_neighbors,
+       show_ip_eigrp_neighbors_cmd,
+       "show ip eigrp neighbors [IFNAME] [detail]",
+       SHOW_STR
+       IP_STR
+       "IP-EIGRP show commands\n"
+       "IP-EIGRP neighbors\n"
+       "Interface to show on\n"
+       "Detailed Information\n")
+{
+  struct eigrp *eigrp;
+  struct eigrp_interface *ei;
+  struct listnode *node, *node2, *nnode2;
+  struct eigrp_neighbor *nbr;
+  bool detail = false;
+  int idx = 0;
+  const char *ifname = NULL;
+
+  eigrp = eigrp_lookup ();
+  if (eigrp == NULL)
+    {
+      vty_out (vty, " EIGRP Routing Process not enabled%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  if (argv_find(argv, argc, "IFNAME", &idx))
+    ifname = argv[idx]->arg;
+
+  detail = (argv_find(argv, argc, "detail", &idx));
+
+  show_ip_eigrp_neighbor_header (vty, eigrp);
+
+  for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
+    {
+      if (!ifname || strcmp(ei->ifp->name, ifname) == 0)
+        {
+          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;
+}
+
+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, VRF_DEFAULT));
+              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, VRF_DEFAULT),
+                       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, VRF_DEFAULT));
+          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, VRF_DEFAULT),
+                   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_topology_all_links_cmd);
+
+  install_element (VIEW_NODE, &show_ip_eigrp_topology_detail_cmd);
+
+}
+
+/* eigrpd's interface node. */
+static struct cmd_node eigrp_interface_node =
+{
+  INTERFACE_NODE,
+  "%s(config-if)# ",
+  1
+};
+
+void
+eigrp_vty_if_init (void)
+{
+  install_node (&eigrp_interface_node, eigrp_write_interface);
+  if_cmd_init();
+
+  /* Delay and bandwidth configuration commands*/
+  install_element (INTERFACE_NODE, &eigrp_if_delay_cmd);
+  install_element (INTERFACE_NODE, &no_eigrp_if_delay_cmd);
+  install_element (INTERFACE_NODE, &eigrp_if_bandwidth_cmd);
+  install_element (INTERFACE_NODE, &no_eigrp_if_bandwidth_cmd);
+
+  /*Hello-interval and hold-time interval configuration commands*/
+  install_element (INTERFACE_NODE, &eigrp_if_ip_holdinterval_cmd);
+  install_element (INTERFACE_NODE, &no_eigrp_if_ip_holdinterval_cmd);
+  install_element (INTERFACE_NODE, &eigrp_if_ip_hellointerval_cmd);
+  install_element (INTERFACE_NODE, &no_eigrp_if_ip_hellointerval_cmd);
+
+  /* "Authentication configuration commands */
+  install_element (INTERFACE_NODE, &eigrp_authentication_mode_cmd);
+  install_element (INTERFACE_NODE, &no_eigrp_authentication_mode_cmd);
+  install_element (INTERFACE_NODE, &eigrp_authentication_keychain_cmd);
+  install_element (INTERFACE_NODE, &no_eigrp_authentication_keychain_cmd);
+
+  /*EIGRP Summarization commands*/
+  install_element (INTERFACE_NODE, &eigrp_ip_summary_address_cmd);
+  install_element (INTERFACE_NODE, &no_eigrp_ip_summary_address_cmd);
+}
+
+static void
+eigrp_vty_zebra_init (void)
+{
+  install_element (EIGRP_NODE, &eigrp_redistribute_source_metric_cmd);
+  install_element (EIGRP_NODE, &no_eigrp_redistribute_source_metric_cmd);
+}
+
+/* Install EIGRP related vty commands. */
+void
+eigrp_vty_init (void)
+{
+  install_node (&eigrp_node, eigrp_config_write);
+
+  install_default (EIGRP_NODE);
+
+  install_element (CONFIG_NODE, &router_eigrp_cmd);
+  install_element (CONFIG_NODE, &no_router_eigrp_cmd);
+  install_element (EIGRP_NODE, &eigrp_network_cmd);
+  install_element (EIGRP_NODE, &no_eigrp_network_cmd);
+  install_element (EIGRP_NODE, &eigrp_variance_cmd);
+  install_element (EIGRP_NODE, &no_eigrp_variance_cmd);
+  install_element (EIGRP_NODE, &eigrp_router_id_cmd);
+  install_element (EIGRP_NODE, &no_eigrp_router_id_cmd);
+  install_element (EIGRP_NODE, &eigrp_passive_interface_cmd);
+  install_element (EIGRP_NODE, &no_eigrp_passive_interface_cmd);
+  install_element (EIGRP_NODE, &eigrp_timers_active_cmd);
+  install_element (EIGRP_NODE, &no_eigrp_timers_active_cmd);
+  install_element (EIGRP_NODE, &eigrp_metric_weights_cmd);
+  install_element (EIGRP_NODE, &no_eigrp_metric_weights_cmd);
+  install_element (EIGRP_NODE, &eigrp_maximum_paths_cmd);
+  install_element (EIGRP_NODE, &no_eigrp_maximum_paths_cmd);
+  install_element (EIGRP_NODE, &eigrp_neighbor_cmd);
+  install_element (EIGRP_NODE, &no_eigrp_neighbor_cmd);
+
+  /* commands for manual hard restart */
+  install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_cmd);
+  install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_int_cmd);
+  install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_IP_cmd);
+  /* commands for manual graceful restart */
+  install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_int_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_eigrp_neighbors_IP_soft_cmd);
+
+  eigrp_vty_zebra_init ();
+}
diff --git a/eigrpd/eigrp_vty.h b/eigrpd/eigrp_vty.h
new file mode 100644 (file)
index 0000000..56a4026
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * EIGRP VTY Interface.
+ * Copyright (C) 2013-2016
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *   Frantisek Gazo
+ *   Tomas Hvorkovy
+ *   Martin Kontsek
+ *   Lukas Koribsky
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _QUAGGA_EIGRP_VTY_H
+#define _QUAGGA_EIGRP_VTY_H
+
+
+/* Prototypes. */
+extern void eigrp_vty_init (void);
+extern void eigrp_vty_show_init (void);
+extern void eigrp_vty_if_init (void);
+
+#endif /* _Quagga_EIGRP_VTY_H_ */
diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c
new file mode 100644 (file)
index 0000000..627d564
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * 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;
+}
+
+static void
+eigrp_zebra_connected (struct zclient *zclient)
+{
+  zclient_send_reg_requests (zclient, VRF_DEFAULT);
+}
+
+void
+eigrp_zebra_init (void)
+{
+  zclient = zclient_new (master);
+
+  zclient_init (zclient, ZEBRA_ROUTE_EIGRP, 0);
+  zclient->zebra_connected = eigrp_zebra_connected;
+  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),
+                                VRF_DEFAULT);
+}
+
+void
+eigrp_zebra_route_add (struct prefix_ipv4 *p, struct list *successors)
+{
+  struct eigrp_neighbor_entry *te;
+  struct listnode *node;
+  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);
+
+      /* 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_putw (s, 0);
+      stream_putl (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, successors->count);
+
+      /* Nexthop, ifindex, distance and metric information. */
+      for (ALL_LIST_ELEMENTS_RO (successors, node, te))
+        {
+          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_putw_at (s, 0, stream_get_endp (s));
+
+      zclient_send_message (zclient);
+    }
+}
+
+void
+eigrp_zebra_route_delete (struct prefix_ipv4 *p)
+{
+  struct zapi_ipv4 api;
+
+  if (zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP])
+    {
+      api.vrf_id = VRF_DEFAULT;
+      api.type = ZEBRA_ROUTE_EIGRP;
+      api.instance = 0;
+      api.flags = 0;
+      api.message = 0;
+      api.safi = SAFI_UNICAST;
+      zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api);
+
+      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])));
+        }
+    }
+
+  return;
+}
+
+vrf_bitmap_t
+eigrp_is_type_redistributed (int type)
+{
+  return (DEFAULT_ROUTE_TYPE (type)) ?
+    zclient->default_information : zclient->redist[AFI_IP][type];
+}
+
+int
+eigrp_redistribute_set (struct eigrp *eigrp, int type, struct eigrp_metrics metric)
+{
+
+  if (eigrp_is_type_redistributed (type))
+    {
+      if (eigrp_metrics_is_same(&metric, &eigrp->dmetric[type]))
+        {
+          eigrp->dmetric[type] = metric;
+        }
+
+      eigrp_external_routes_refresh (eigrp, type);
+
+      //      if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE))
+      //        zlog_debug ("Redistribute[%s]: Refresh  Type[%d], Metric[%d]",
+      //                   eigrp_redist_string(type),
+      //                   metric_type (eigrp, type), metric_value (eigrp, type));
+      return CMD_SUCCESS;
+    }
+
+  eigrp->dmetric[type] = metric;
+
+  zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient,
+                        AFI_IP, type, 0, VRF_DEFAULT);
+
+  //  if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
+  //    zlog_debug ("Redistribute[%s]: Start  Type[%d], Metric[%d]",
+  //               ospf_redist_string(type),
+  //               metric_type (ospf, type), metric_value (ospf, type));
+
+  ++eigrp->redistribute;
+
+  return CMD_SUCCESS;
+}
+
+int
+eigrp_redistribute_unset (struct eigrp *eigrp, int type)
+{
+
+  if (eigrp_is_type_redistributed (type))
+    {
+      memset(&eigrp->dmetric[type], 0, sizeof(struct eigrp_metrics));
+      zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient,
+                            AFI_IP, type, 0, VRF_DEFAULT);
+      --eigrp->redistribute;
+    }
+
+  //  if (IS_DEBUG_EIGRP (zebra, ZEBRA_REDISTRIBUTE))
+  //    zlog_debug ("Redistribute[%s]: Start  Type[%d], Metric[%d]",
+  //               ospf_redist_string(type),
+  //               metric_type (ospf, type), metric_value (ospf, type));
+
+  return CMD_SUCCESS;
+}
+
diff --git a/eigrpd/eigrp_zebra.h b/eigrpd/eigrp_zebra.h
new file mode 100644 (file)
index 0000000..4cd6b1e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Zebra connect library for EIGRP.
+ * Copyright (C) 2013-2014
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRP_ZEBRA_H_
+#define _ZEBRA_EIGRP_ZEBRA_H_
+
+#include "vty.h"
+#include "vrf.h"
+
+extern void eigrp_zebra_init (void);
+
+extern void eigrp_zebra_route_add (struct prefix_ipv4 *, struct list *);
+extern void eigrp_zebra_route_delete (struct prefix_ipv4 *);
+extern int eigrp_redistribute_set (struct eigrp *, int, struct eigrp_metrics);
+extern int eigrp_redistribute_unset (struct eigrp *, int);
+extern vrf_bitmap_t eigrp_is_type_redistributed (int);
+
+#endif /* _ZEBRA_EIGRP_ZEBRA_H_ */
diff --git a/eigrpd/eigrpd.c b/eigrpd/eigrpd.c
new file mode 100644 (file)
index 0000000..8d7aa02
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * EIGRP Daemon Program.
+ * Copyright (C) 2013-2014
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "vty.h"
+#include "command.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+#include "if.h"
+#include "memory.h"
+#include "stream.h"
+#include "log.h"
+#include "sockunion.h"          /* for inet_aton () */
+#include "zclient.h"
+#include "plist.h"
+#include "sockopt.h"
+#include "keychain.h"
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_interface.h"
+#include "eigrpd/eigrp_zebra.h"
+#include "eigrpd/eigrp_vty.h"
+#include "eigrpd/eigrp_neighbor.h"
+#include "eigrpd/eigrp_packet.h"
+#include "eigrpd/eigrp_network.h"
+#include "eigrpd/eigrp_topology.h"
+#include "eigrpd/eigrp_memory.h"
+
+DEFINE_QOBJ_TYPE(eigrp)
+
+static struct eigrp_master eigrp_master;
+
+struct eigrp_master *eigrp_om;
+
+static void eigrp_finish_final(struct eigrp *);
+static void eigrp_delete(struct eigrp *);
+static struct eigrp *eigrp_new(const char *);
+static void eigrp_add(struct eigrp *);
+
+extern struct zclient *zclient;
+extern struct in_addr router_id_zebra;
+
+
+/*
+ * void eigrp_router_id_update(struct eigrp *eigrp)
+ *
+ * Description:
+ * update routerid associated with this instance of EIGRP.
+ * If the id changes, then call if_update for each interface
+ * to resync the topology database with all neighbors
+ *
+ * Select the router ID based on these priorities:
+ *   1. Statically assigned router ID is always the first choice.
+ *   2. If there is no statically assigned router ID, then try to stick
+ *      with the most recent value, since changing router ID's is very
+ *      disruptive.
+ *   3. Last choice: just go with whatever the zebra daemon recommends.
+ *
+ * Note:
+ * router id for EIGRP is really just a 32 bit number. Cisco historically
+ * displays it in dotted decimal notation, and will pickup an IP address
+ * from an interface so it can be 'auto-configed" to a uniqe value
+ *
+ * This does not work for IPv6, and to make the code simpler, its
+ * stored and processed internerall as a 32bit number
+ */
+void
+eigrp_router_id_update (struct eigrp *eigrp)
+{
+  struct interface *ifp;
+  struct listnode *node;
+  u_int32_t router_id, router_id_old;
+
+  router_id_old = eigrp->router_id;
+
+  if (eigrp->router_id_static != 0)
+    router_id = eigrp->router_id_static;
+
+  else if (eigrp->router_id != 0)
+    router_id = eigrp->router_id;
+
+  else
+    router_id = router_id_zebra.s_addr;
+
+  eigrp->router_id = router_id;
+  if (router_id_old != router_id)
+    {
+      //      if (IS_DEBUG_EIGRP_EVENT)
+      //        zlog_debug("Router-ID[NEW:%s]: Update", inet_ntoa(eigrp->router_id));
+
+      /* update eigrp_interface's */
+      for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp))
+        eigrp_if_update(ifp);
+    }
+}
+
+void
+eigrp_master_init ()
+{
+  struct timeval tv;
+
+  memset(&eigrp_master, 0, sizeof(struct eigrp_master));
+
+  eigrp_om = &eigrp_master;
+  eigrp_om->eigrp = list_new();
+
+  monotime(&tv);
+  eigrp_om->start_time = tv.tv_sec;
+}
+
+/* Allocate new eigrp structure. */
+static struct eigrp *
+eigrp_new (const char *AS)
+{
+  struct eigrp *eigrp = XCALLOC(MTYPE_EIGRP_TOP, sizeof (struct eigrp));
+  int eigrp_socket;
+
+  /* init information relevant to peers */
+  eigrp->vrid = 0;
+  eigrp->AS = atoi(AS);
+  eigrp->router_id = 0L;
+  eigrp->router_id_static = 0L;
+  eigrp->sequence_number = 1;
+
+  /*Configure default K Values for EIGRP Process*/
+  eigrp->k_values[0] = EIGRP_K1_DEFAULT;
+  eigrp->k_values[1] = EIGRP_K2_DEFAULT;
+  eigrp->k_values[2] = EIGRP_K3_DEFAULT;
+  eigrp->k_values[3] = EIGRP_K4_DEFAULT;
+  eigrp->k_values[4] = EIGRP_K5_DEFAULT;
+  eigrp->k_values[5] = EIGRP_K6_DEFAULT;
+
+  /* init internal data structures */
+  eigrp->eiflist = list_new();
+  eigrp->passive_interface_default = EIGRP_IF_ACTIVE;
+  eigrp->networks = route_table_init();
+
+  if ((eigrp_socket = eigrp_sock_init()) < 0)
+    {
+      zlog_err("eigrp_new: fatal error: eigrp_sock_init was unable to open "
+               "a socket");
+      exit (1);
+    }
+
+  eigrp->fd = eigrp_socket;
+  eigrp->maxsndbuflen = getsockopt_so_sendbuf(eigrp->fd);
+
+  if ((eigrp->ibuf = stream_new(EIGRP_PACKET_MAX_LEN+1)) == NULL)
+    {
+      zlog_err("eigrp_new: fatal error: stream_new (%u) failed allocating ibuf",
+               EIGRP_PACKET_MAX_LEN+1);
+      exit(1);
+    }
+
+  eigrp->t_read = thread_add_read(master, eigrp_read, eigrp, eigrp->fd);
+  eigrp->oi_write_q = list_new();
+
+  eigrp->topology_table = eigrp_topology_new();
+
+  eigrp->neighbor_self = eigrp_nbr_new(NULL);
+  inet_aton("127.0.0.1", &eigrp->neighbor_self->src);
+
+  eigrp->variance = EIGRP_VARIANCE_DEFAULT;
+  eigrp->max_paths = EIGRP_MAX_PATHS_DEFAULT;
+
+  eigrp->serno = 0;
+  eigrp->serno_last_update = 0;
+  eigrp->topology_changes_externalIPV4 = list_new ();
+  eigrp->topology_changes_internalIPV4 = list_new ();
+
+  eigrp->list[EIGRP_FILTER_IN] = NULL;
+  eigrp->list[EIGRP_FILTER_OUT] = NULL;
+
+  eigrp->prefix[EIGRP_FILTER_IN] = NULL;
+  eigrp->prefix[EIGRP_FILTER_OUT] = NULL;
+
+  eigrp->routemap[EIGRP_FILTER_IN] = NULL;
+  eigrp->routemap[EIGRP_FILTER_OUT] = NULL;
+
+  QOBJ_REG(eigrp, eigrp);
+  return eigrp;
+}
+
+static void
+eigrp_add (struct eigrp *eigrp)
+{
+  listnode_add(eigrp_om->eigrp, eigrp);
+}
+
+static void
+eigrp_delete (struct eigrp *eigrp)
+{
+  listnode_delete(eigrp_om->eigrp, eigrp);
+}
+
+struct eigrp *
+eigrp_get (const char *AS)
+{
+  struct eigrp *eigrp;
+
+  eigrp = eigrp_lookup();
+  if (eigrp == NULL)
+    {
+      eigrp = eigrp_new(AS);
+      eigrp_add(eigrp);
+    }
+
+  return eigrp;
+}
+
+/* Shut down the entire process */
+void
+eigrp_terminate (void)
+{
+  struct eigrp *eigrp;
+  struct listnode *node, *nnode;
+
+  /* shutdown already in progress */
+  if (CHECK_FLAG(eigrp_om->options, EIGRP_MASTER_SHUTDOWN))
+    return;
+
+  SET_FLAG(eigrp_om->options, EIGRP_MASTER_SHUTDOWN);
+
+  /* exit immediately if EIGRP not actually running */
+  if (listcount(eigrp_om->eigrp) == 0)
+    exit(0);
+
+  for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp))
+    eigrp_finish(eigrp);
+}
+
+void
+eigrp_finish (struct eigrp *eigrp)
+{
+
+  eigrp_finish_final(eigrp);
+
+  /* eigrp being shut-down? If so, was this the last eigrp instance? */
+  if (CHECK_FLAG(eigrp_om->options, EIGRP_MASTER_SHUTDOWN)
+      && (listcount(eigrp_om->eigrp) == 0))
+    exit(0);
+
+  return;
+}
+
+/* Final cleanup of eigrp instance */
+static void
+eigrp_finish_final (struct eigrp *eigrp)
+{
+
+  close(eigrp->fd);
+
+  if (zclient)
+    zclient_free(zclient);
+
+  list_delete(eigrp->eiflist);
+  list_delete(eigrp->oi_write_q);
+  list_delete(eigrp->topology_changes_externalIPV4);
+  list_delete(eigrp->topology_changes_internalIPV4);
+
+  eigrp_topology_cleanup(eigrp->topology_table);
+  eigrp_topology_free(eigrp->topology_table);
+
+  eigrp_nbr_delete(eigrp->neighbor_self);
+
+  eigrp_delete(eigrp);
+
+  XFREE(MTYPE_EIGRP_TOP,eigrp);
+}
+
+/*Look for existing eigrp process*/
+struct eigrp *
+eigrp_lookup (void)
+{
+  if (listcount(eigrp_om->eigrp) == 0)
+    return NULL;
+
+  return listgetdata(listhead(eigrp_om->eigrp));
+}
diff --git a/eigrpd/eigrpd.conf.sample b/eigrpd/eigrpd.conf.sample
new file mode 100644 (file)
index 0000000..662e667
--- /dev/null
@@ -0,0 +1,13 @@
+! -*- eigrpd -*-
+!
+! EIGRPDd sample configuration file
+!
+!
+hostname eigrpd
+password zebra
+!enable password please-set-at-here
+!
+!router eigrp 4453
+!  network 192.168.1.0/24
+!
+log stdout
diff --git a/eigrpd/eigrpd.h b/eigrpd/eigrpd.h
new file mode 100644 (file)
index 0000000..61d4ba7
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * EIGRP main header.
+ * Copyright (C) 2013-2014
+ * Authors:
+ *   Donnie Savage
+ *   Jan Janovic
+ *   Matej Perina
+ *   Peter Orsag
+ *   Peter Paluch
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EIGRPD_H
+#define _ZEBRA_EIGRPD_H
+
+#include <zebra.h>
+
+#include "filter.h"
+#include "log.h"
+
+/* Set EIGRP version is "classic" - wide metrics comes next */
+#define EIGRP_MAJOR_VERSION     1
+#define EIGRP_MINOR_VERSION    2
+
+/* Extern variables. */
+extern struct zclient *zclient;
+extern struct thread_master *master;
+extern struct eigrp_master *eigrp_om;
+
+/* Prototypes */
+ extern void eigrp_master_init (void);
+ extern void eigrp_terminate (void);
+ extern void eigrp_finish (struct eigrp *);
+ extern struct eigrp *eigrp_get (const char *);
+ extern struct eigrp *eigrp_lookup (void);
+ extern void eigrp_router_id_update (struct eigrp *);
+
+#endif /* _ZEBRA_EIGRPD_H */
index c97385f87a91c464efc5c008ccd3e241d0af7c93..2973820eedae7fd335b6465758e7f87744ebaa17 100644 (file)
@@ -16,7 +16,7 @@ libisis_a_SOURCES = \
        isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \
        isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \
        isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \
-       isis_vty.c
+       isis_vty.c isis_mt.c
 
 
 noinst_HEADERS = \
@@ -25,7 +25,7 @@ noinst_HEADERS = \
        isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \
        isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \
        iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \
-       isis_route.h isis_routemap.h isis_te.h
+       isis_route.h isis_routemap.h isis_te.h isis_mt.h
 
 isisd_SOURCES = \
        isis_main.c $(libisis_a_SOURCES) \
index f55092487437e6163d8b8859cc64830242bbd4ca..e3643868d36d1e4a44238f3f934ff9cea4285c01 100644 (file)
@@ -47,6 +47,7 @@
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_spf.h"
 #include "isisd/isis_events.h"
+#include "isisd/isis_mt.h"
 
 extern struct isis *isis;
 
@@ -148,6 +149,8 @@ isis_delete_adj (void *arg)
   if (adj->ipv6_addrs)
     list_delete (adj->ipv6_addrs);
 
+  adj_mt_finish(adj);
+
   XFREE (MTYPE_ISIS_ADJACENCY, adj);
   return;
 }
@@ -412,6 +415,12 @@ isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail)
       vty_out (vty, "    Circuit type: %s", circuit_t2string (adj->circuit_t));
       vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids));
       vty_out (vty, "%s", VTY_NEWLINE);
+      if (adj->mt_count != 1 || adj->mt_set[0] != ISIS_MT_IPV4_UNICAST)
+        {
+          vty_out (vty, "    Topologies:%s", VTY_NEWLINE);
+          for (unsigned int i = 0; i < adj->mt_count; i++)
+            vty_out (vty, "      %s%s", isis_mtid2str(adj->mt_set[i]), VTY_NEWLINE);
+        }
       vty_out (vty, "    SNPA: %s", snpa_print (adj->snpa));
       if (adj->circuit && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST))
       {
@@ -521,3 +530,20 @@ isis_adj_build_up_list (struct list *adjdb, struct list *list)
 
   return;
 }
+
+int
+isis_adj_usage2levels(enum isis_adj_usage usage)
+{
+  switch (usage)
+    {
+    case ISIS_ADJ_LEVEL1:
+      return IS_LEVEL_1;
+    case ISIS_ADJ_LEVEL2:
+      return IS_LEVEL_2;
+    case ISIS_ADJ_LEVEL1AND2:
+      return IS_LEVEL_1 | IS_LEVEL_2;
+    default:
+      break;
+    }
+  return 0;
+}
index 8539b03d6b9b3b22e1edb1a0c825928e2c506a1d..4f89e309601a077a2b97c9d61fc3b4977208f5b2 100644 (file)
@@ -97,6 +97,8 @@ struct isis_adjacency
   int flaps;                   /* number of adjacency flaps  */
   struct thread *t_expire;     /* expire after hold_time  */
   struct isis_circuit *circuit;        /* back pointer */
+  uint16_t *mt_set;             /* Topologies this adjacency is valid for */
+  unsigned int mt_count;              /* Number of entries in mt_set */
 };
 
 struct isis_adjacency *isis_adj_lookup (const u_char * sysid, struct list *adjdb);
@@ -112,5 +114,6 @@ int isis_adj_expire (struct thread *thread);
 void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail);
 void isis_adj_build_neigh_list (struct list *adjdb, struct list *list);
 void isis_adj_build_up_list (struct list *adjdb, struct list *list);
+int isis_adj_usage2levels(enum isis_adj_usage usage);
 
 #endif /* ISIS_ADJACENCY_H */
index 3a5eaf558514fde56db242cfbf950d81d2f1804a..0a1610b6f207f62249ba0ad9a77cfb83f4551e82 100644 (file)
@@ -212,16 +212,11 @@ isis_sock_init (struct isis_circuit *circuit)
       goto end;
     }
 
-  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+  if (if_is_broadcast(circuit->interface))
     {
       circuit->tx = isis_send_pdu_bcast;
       circuit->rx = isis_recv_pdu_bcast;
     }
-  else if (circuit->circ_type == CIRCUIT_T_P2P)
-    {
-      circuit->tx = isis_send_pdu_p2p;
-      circuit->rx = isis_recv_pdu_p2p;
-    }
   else
     {
       zlog_warn ("isis_sock_init(): unknown circuit type");
@@ -283,23 +278,6 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
   return ISIS_OK;
 }
 
-int
-isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
-{
-  int bytesread;
-
-  bytesread = stream_read (circuit->rcv_stream, circuit->fd, 
-                           circuit->interface->mtu);
-
-  if (bytesread < 0)
-    {
-      zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", safe_strerror (errno));
-      return ISIS_WARNING;
-    }
-
-  return ISIS_OK;
-}
-
 int
 isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
 {
@@ -327,7 +305,8 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
   else
     memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN);
   memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN);
-  eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
+  size_t frame_size = stream_get_endp(circuit->snd_stream) + LLC_LEN;
+  eth->ether_type = htons(isis_ethertype(frame_size));
 
   /*
    * Then the LLC
@@ -354,10 +333,4 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
   return ISIS_OK;
 }
 
-int
-isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
-{
-  return ISIS_OK;
-}
-
 #endif /* ISIS_METHOD == ISIS_METHOD_BPF */
index 6207ae189aeb28c612328c72705bf85f06f26ae9..6caf8200eeb14b0cbca81019e13f0cdcba0f6d15 100644 (file)
@@ -60,6 +60,7 @@
 #include "isisd/isis_csm.h"
 #include "isisd/isis_events.h"
 #include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
 
 DEFINE_QOBJ_TYPE(isis_circuit)
 
@@ -102,6 +103,8 @@ isis_circuit_new ()
 
   circuit->mtc = mpls_te_circuit_new();
 
+  circuit_mt_init(circuit);
+
   QOBJ_REG (circuit, isis_circuit);
 
   return circuit;
@@ -117,6 +120,8 @@ isis_circuit_del (struct isis_circuit *circuit)
 
   isis_circuit_if_unbind (circuit, circuit->interface);
 
+  circuit_mt_finish(circuit);
+
   /* and lastly the circuit itself */
   XFREE (MTYPE_ISIS_CIRCUIT, circuit);
 
@@ -1215,6 +1220,7 @@ isis_interface_config_write (struct vty *vty)
                        VTY_NEWLINE);
               write++;
             }
+          write += circuit_write_mt_settings(circuit, vty);
         }
       vty_out (vty, "!%s", VTY_NEWLINE);
     }
@@ -1382,6 +1388,22 @@ isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type)
   return 0;
 }
 
+int
+isis_circuit_mt_enabled_set (struct isis_circuit *circuit, uint16_t mtid,
+                             bool enabled)
+{
+  struct isis_circuit_mt_setting *setting;
+
+  setting = circuit_get_mt_setting(circuit, mtid);
+  if (setting->enabled != enabled)
+    {
+      setting->enabled = enabled;
+      lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+    }
+
+  return CMD_SUCCESS;
+}
+
 int
 isis_if_new_hook (struct interface *ifp)
 {
index bb0dc0f983cc3f48c127e8acef8204af79c9e885..16dfa6304ca2cee816cae8dc7869a11e4c459eef 100644 (file)
@@ -123,6 +123,7 @@ struct isis_circuit
   struct mpls_te_circuit *mtc; /* Support for MPLS-TE parameters - see isis_te.[c,h] */
   int ip_router;               /* Route IP ? */
   int is_passive;              /* Is Passive ? */
+  struct list *mt_settings;    /* IS-IS MT Settings */
   struct list *ip_addrs;       /* our IP addresses */
   int ipv6_router;             /* Route IPv6 ? */
   struct list *ipv6_link;      /* our link local IPv6 addresses */
@@ -187,4 +188,6 @@ int  isis_circuit_passwd_unset (struct isis_circuit *circuit);
 int  isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd);
 int  isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd);
 
+int isis_circuit_mt_enabled_set (struct isis_circuit *circuit, uint16_t mtid, bool enabled);
+
 #endif /* _ZEBRA_ISIS_CIRCUIT_H */
index 17616d671b55658aca033f7f1a72471b7fb00bf1..ec0f6fb62cfc14fe68999ee94d23f89b18cc66ac 100644 (file)
 #define ETH_ALEN 6
 #endif
 
+#define MAX_LLC_LEN 0x5ff
+#define ETHERTYPE_EXT_LLC 0x8870
+
+static inline uint16_t isis_ethertype(size_t len)
+{
+  if (len > MAX_LLC_LEN)
+    return ETHERTYPE_EXT_LLC;
+  return len;
+}
+
 #endif /* ISIS_CONSTANTS_H */
index f633a8fb78fb062602b684dcb1ef1aa11b25e0aa..955a73ef6128e169719cd4e17aafbb5ebb55af74 100644 (file)
@@ -53,6 +53,7 @@
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_spf.h"
 #include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
 
 /* staticly assigned vars for printing purposes */
 char lsp_bits_string[200];     /* FIXME: enough ? */
@@ -501,6 +502,7 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
       expected |= TLVFLAG_TE_IPV4_REACHABILITY;
       expected |= TLVFLAG_TE_ROUTER_ID;
     }
+  expected |= TLVFLAG_MT_ROUTER_INFORMATION;
   expected |= TLVFLAG_IPV4_ADDR;
   expected |= TLVFLAG_IPV4_INT_REACHABILITY;
   expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
@@ -826,6 +828,107 @@ lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost)
            lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
 }
 
+static void
+lsp_print_mt_reach(struct list *list, struct vty *vty,
+                   char dynhost, uint16_t mtid)
+{
+  struct listnode *node;
+  struct te_is_neigh *neigh;
+
+  for (ALL_LIST_ELEMENTS_RO (list, node, neigh))
+    {
+      u_char lspid[255];
+
+      lspid_print(neigh->neigh_id, lspid, dynhost, 0);
+      if (mtid == ISIS_MT_IPV4_UNICAST)
+        {
+          vty_out(vty, "  Metric      : %-8d IS-Extended   : %s%s",
+                  GET_TE_METRIC(neigh), lspid, VTY_NEWLINE);
+        }
+      else
+        {
+          vty_out(vty, "  Metric      : %-8d MT-Reach      : %s %s%s",
+                  GET_TE_METRIC(neigh), lspid,
+                  isis_mtid2str(mtid), VTY_NEWLINE);
+        }
+      if (IS_MPLS_TE(isisMplsTE))
+        mpls_te_print_detail(vty, neigh);
+    }
+}
+
+static void
+lsp_print_mt_ipv6_reach(struct list *list, struct vty *vty, uint16_t mtid)
+{
+  struct listnode *node;
+  struct ipv6_reachability *ipv6_reach;
+  struct in6_addr in6;
+  u_char buff[BUFSIZ];
+
+  for (ALL_LIST_ELEMENTS_RO (list, node, ipv6_reach))
+    {
+      memset (&in6, 0, sizeof (in6));
+      memcpy (in6.s6_addr, ipv6_reach->prefix,
+              PSIZE (ipv6_reach->prefix_len));
+      inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
+      if (mtid == ISIS_MT_IPV4_UNICAST)
+        {
+          if ((ipv6_reach->control_info &
+               CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
+            vty_out (vty, "  Metric      : %-8d IPv6-Internal : %s/%d%s",
+                     ntohl (ipv6_reach->metric),
+                     buff, ipv6_reach->prefix_len, VTY_NEWLINE);
+          else
+            vty_out (vty, "  Metric      : %-8d IPv6-External : %s/%d%s",
+                     ntohl (ipv6_reach->metric),
+                     buff, ipv6_reach->prefix_len, VTY_NEWLINE);
+        }
+      else
+        {
+          if ((ipv6_reach->control_info &
+               CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
+            vty_out (vty, "  Metric      : %-8d IPv6-MT-Int   : %s/%d %s%s",
+                     ntohl (ipv6_reach->metric),
+                     buff, ipv6_reach->prefix_len,
+                     isis_mtid2str(mtid), VTY_NEWLINE);
+          else
+            vty_out (vty, "  Metric      : %-8d IPv6-MT-Ext   : %s/%d %s%s",
+                     ntohl (ipv6_reach->metric),
+                     buff, ipv6_reach->prefix_len,
+                     isis_mtid2str(mtid), VTY_NEWLINE);
+        }
+    }
+}
+
+static void
+lsp_print_mt_ipv4_reach(struct list *list, struct vty *vty, uint16_t mtid)
+{
+  struct listnode *node;
+  struct te_ipv4_reachability *te_ipv4_reach;
+
+  for (ALL_LIST_ELEMENTS_RO (list, node, te_ipv4_reach))
+    {
+      if (mtid == ISIS_MT_IPV4_UNICAST)
+        {
+          /* FIXME: There should be better way to output this stuff. */
+          vty_out (vty, "  Metric      : %-8d IPv4-Extended : %s/%d%s",
+                   ntohl (te_ipv4_reach->te_metric),
+                   inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
+                                                te_ipv4_reach->control)),
+                   te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
+        }
+      else
+        {
+          /* FIXME: There should be better way to output this stuff. */
+          vty_out (vty, "  Metric      : %-8d IPv4-MT       : %s/%d %s%s",
+                   ntohl (te_ipv4_reach->te_metric),
+                   inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
+                                                te_ipv4_reach->control)),
+                   te_ipv4_reach->control & 0x3F,
+                   isis_mtid2str(mtid), VTY_NEWLINE);
+        }
+    }
+}
+
 void
 lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
 {
@@ -833,13 +936,12 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
   int i;
   struct listnode *lnode;
   struct is_neigh *is_neigh;
-  struct te_is_neigh *te_is_neigh;
   struct ipv4_reachability *ipv4_reach;
   struct in_addr *ipv4_addr;
-  struct te_ipv4_reachability *te_ipv4_reach;
-  struct ipv6_reachability *ipv6_reach;
-  struct in6_addr in6;
-  u_char buff[BUFSIZ];
+  struct mt_router_info *mt_router_info;
+  struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
+  struct tlv_mt_neighbors *mt_is_neigh;
+  struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
   u_char LSPid[255];
   u_char hostname[255];
   u_char ipv4_reach_prefix[20];
@@ -877,6 +979,14 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
        }
     }
 
+  for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode, mt_router_info))
+    {
+      vty_out (vty, "  MT          : %s%s%s",
+               isis_mtid2str(mt_router_info->mtid),
+               mt_router_info->overload ? " (overload)" : "",
+               VTY_NEWLINE);
+    }
+
   /* for the hostname tlv */
   if (lsp->tlv_data.hostname)
     {
@@ -946,49 +1056,31 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
               ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
               ipv4_reach_mask, VTY_NEWLINE);
     }
-  
+
   /* IPv6 tlv */
-  if (lsp->tlv_data.ipv6_reachs)
-    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach))
-    {
-      memset (&in6, 0, sizeof (in6));
-      memcpy (in6.s6_addr, ipv6_reach->prefix,
-             PSIZE (ipv6_reach->prefix_len));
-      inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
-      if ((ipv6_reach->control_info &
-          CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
-       vty_out (vty, "  Metric      : %-8d IPv6-Internal : %s/%d%s",
-                ntohl (ipv6_reach->metric),
-                buff, ipv6_reach->prefix_len, VTY_NEWLINE);
-      else
-       vty_out (vty, "  Metric      : %-8d IPv6-External : %s/%d%s",
-                ntohl (ipv6_reach->metric),
-                buff, ipv6_reach->prefix_len, VTY_NEWLINE);
-    }
+  lsp_print_mt_ipv6_reach(lsp->tlv_data.ipv6_reachs, vty,
+                          ISIS_MT_IPV4_UNICAST);
+
+  /* MT IPv6 reachability tlv */
+  for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_ipv6_reachs, lnode, mt_ipv6_reachs))
+    lsp_print_mt_ipv6_reach(mt_ipv6_reachs->list, vty, mt_ipv6_reachs->mtid);
 
   /* TE IS neighbor tlv */
-  if (lsp->tlv_data.te_is_neighs)
-    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
-    {
-      lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
-      vty_out (vty, "  Metric      : %-8d IS-Extended   : %s%s",
-              GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
-      if (IS_MPLS_TE(isisMplsTE))
-        mpls_te_print_detail(vty, te_is_neigh);
-    }
+  lsp_print_mt_reach(lsp->tlv_data.te_is_neighs, vty,
+                     dynhost, ISIS_MT_IPV4_UNICAST);
+
+  /* MT IS neighbor tlv */
+  for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_is_neighs, lnode, mt_is_neigh))
+    lsp_print_mt_reach(mt_is_neigh->list, vty, dynhost, mt_is_neigh->mtid);
 
   /* TE IPv4 tlv */
-  if (lsp->tlv_data.te_ipv4_reachs)
-    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode,
-                              te_ipv4_reach))
-    {
-      /* FIXME: There should be better way to output this stuff. */
-      vty_out (vty, "  Metric      : %-8d IPv4-Extended : %s/%d%s",
-              ntohl (te_ipv4_reach->te_metric),
-              inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
-                                           te_ipv4_reach->control)),
-              te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
-    }
+  lsp_print_mt_ipv4_reach(lsp->tlv_data.te_ipv4_reachs, vty,
+                          ISIS_MT_IPV4_UNICAST);
+
+  /* MT IPv4 reachability tlv */
+  for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.mt_ipv4_reachs, lnode, mt_ipv4_reachs))
+    lsp_print_mt_ipv4_reach(mt_ipv4_reachs->list, vty, mt_ipv4_reachs->mtid);
+
   vty_out (vty, "%s", VTY_NEWLINE);
 
   return;
@@ -1028,6 +1120,42 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
   return lsp_count;
 }
 
+static void
+_lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
+              int frag_thold,
+              unsigned int tlv_build_func (struct list *, struct stream *,
+                                           void *arg),
+              void *arg)
+{
+  while (*from && listcount(*from))
+    {
+      unsigned int count;
+
+      count = tlv_build_func(*from, lsp->pdu, arg);
+
+      if (listcount(*to) != 0 || count != listcount(*from))
+        {
+          struct listnode *node, *nnode;
+          void *elem;
+
+          for (ALL_LIST_ELEMENTS(*from, node, nnode, elem))
+            {
+              if (!count)
+                break;
+              listnode_add (*to, elem);
+              list_delete_node (*from, node);
+              --count;
+            }
+        }
+      else
+        {
+          list_free (*to);
+          *to = *from;
+          *from = NULL;
+        }
+    }
+}
+
 #define FRAG_THOLD(S,T) \
   ((STREAM_SIZE(S)*T)/100)
 
@@ -1085,64 +1213,6 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
   return;
 }
 
-/* Process IS_NEIGHBOURS TLV with TE subTLVs */
-void
-lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int frag_thold)
-{
-  int count, size = 0;
-  struct listnode *node, *nextnode;
-  struct te_is_neigh *elem;
-
-  /* Start computing real size of TLVs */
-  for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
-    size = size + elem->sub_tlvs_length + IS_NEIGHBOURS_LEN;
-
-  /* can we fit all ? */
-  if (!FRAG_NEEDED (lsp->pdu, frag_thold, size))
-    {
-      tlv_add_te_is_neighs (*from, lsp->pdu);
-      if (listcount (*to) != 0)
-        {
-          for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
-            {
-              listnode_add (*to, elem);
-              list_delete_node (*from, node);
-            }
-        }
-      else
-        {
-          list_free (*to);
-          *to = *from;
-          *from = NULL;
-        }
-    }
-  else
-    {
-      /* fit all we can */
-      /* Compute remaining place in LSP PDU */
-      count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
-        (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
-      /* Determine size of TE SubTLVs */
-      elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
-      count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
-      if (count > 0)
-        {
-          while (count > 0)
-            {
-              listnode_add (*to, listgetdata ((struct listnode *)listhead (*from)));
-              listnode_delete (*from, listgetdata ((struct listnode *)listhead (*from)));
-
-              elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
-              count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
-            }
-
-          tlv_add_te_is_neighs (*to, lsp->pdu);
-        }
-    }
-  lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
-  return;
-}
-
 static u_int16_t
 lsp_rem_lifetime (struct isis_area *area, int level)
 {
@@ -1278,6 +1348,24 @@ lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area,
     }
 }
 
+static struct list *
+tlv_get_ipv6_reach_list(struct isis_area *area, struct tlvs *tlv_data)
+{
+  uint16_t mtid = isis_area_ipv6_topology(area);
+  if (mtid == ISIS_MT_IPV4_UNICAST)
+    {
+      if (!tlv_data->ipv6_reachs)
+        {
+          tlv_data->ipv6_reachs = list_new();
+          tlv_data->ipv6_reachs->del = free_tlv;
+        }
+      return tlv_data->ipv6_reachs;
+    }
+
+  struct tlv_mt_ipv6_reachs *reachs = tlvs_get_mt_ipv6_reachs(tlv_data, mtid);
+  return reachs->list;
+}
+
 static void
 lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
                          struct tlvs *tlv_data)
@@ -1287,6 +1375,7 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
   struct prefix_ipv6 *ipv6;
   struct isis_ext_info *info;
   struct ipv6_reachability *ip6reach;
+  struct list *reach_list = NULL;
 
   er_table = get_ext_reach(area, AF_INET6, lsp->level);
   if (!er_table)
@@ -1300,11 +1389,9 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
       ipv6 = (struct prefix_ipv6*)&rn->p;
       info = rn->info;
 
-      if (tlv_data->ipv6_reachs == NULL)
-        {
-          tlv_data->ipv6_reachs = list_new();
-          tlv_data->ipv6_reachs->del = free_tlv;
-        }
+      if (!reach_list)
+        reach_list = tlv_get_ipv6_reach_list(area, tlv_data);
+
       ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
       if (info->metric > MAX_WIDE_PATH_METRIC)
         ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
@@ -1313,7 +1400,7 @@ lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
       ip6reach->control_info = DISTRIBUTION_EXTERNAL;
       ip6reach->prefix_len = ipv6->prefixlen;
       memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix));
-      listnode_add(tlv_data->ipv6_reachs, ip6reach);
+      listnode_add(reach_list, ip6reach);
     }
 }
 
@@ -1342,6 +1429,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
   struct te_ipv4_reachability *te_ipreach;
   struct isis_adjacency *nei;
   struct prefix_ipv6 *ipv6, ip6prefix;
+  struct list *ipv6_reachs = NULL;
   struct ipv6_reachability *ip6reach;
   struct tlvs tlv_data;
   struct isis_lsp *lsp0 = lsp;
@@ -1402,6 +1490,32 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
       tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
     }
 
+  if (area_is_mt(area))
+    {
+      lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
+      lsp->tlv_data.mt_router_info = list_new();
+      lsp->tlv_data.mt_router_info->del = free_tlv;
+
+      struct isis_area_mt_setting **mt_settings;
+      unsigned int mt_count;
+
+      mt_settings = area_mt_settings(area, &mt_count);
+      for (unsigned int i = 0; i < mt_count; i++)
+        {
+          struct mt_router_info *info;
+
+          info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
+          info->mtid = mt_settings[i]->mtid;
+          info->overload = mt_settings[i]->overload;
+          listnode_add(lsp->tlv_data.mt_router_info, info);
+          lsp_debug("ISIS (%s):   MT %s", area->area_tag, isis_mtid2str(info->mtid));
+        }
+      tlv_add_mt_router_info (lsp->tlv_data.mt_router_info, lsp->pdu);
+    }
+  else
+    {
+      lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)", area->area_tag);
+    }
   /* Dynamic Hostname */
   if (area->dynhostname)
     {
@@ -1551,12 +1665,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
       if (circuit->ipv6_router && circuit->ipv6_non_link &&
          circuit->ipv6_non_link->count > 0)
        {
+         if (!ipv6_reachs)
+           ipv6_reachs = tlv_get_ipv6_reach_list(area, &tlv_data);
 
-         if (tlv_data.ipv6_reachs == NULL)
-           {
-             tlv_data.ipv6_reachs = list_new ();
-             tlv_data.ipv6_reachs->del = free_tlv;
-           }
           for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
            {
              ip6reach =
@@ -1579,7 +1690,7 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
 
              memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr,
                      sizeof (ip6reach->prefix));
-             listnode_add (tlv_data.ipv6_reachs, ip6reach);
+             listnode_add (ipv6_reachs, ip6reach);
            }
        }
 
@@ -1658,10 +1769,8 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
                         /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
                         te_is_neigh->sub_tlvs_length = 0;
 
-                      listnode_add (tlv_data.te_is_neighs, te_is_neigh);
-                      lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor",
-                                area->area_tag, sysid_print(te_is_neigh->neigh_id),
-                                LSP_PSEUDO_ID(te_is_neigh->neigh_id));
+                      tlvs_add_mt_bcast(&tlv_data, circuit, level, te_is_neigh);
+                      XFREE(MTYPE_ISIS_TLV, te_is_neigh);
                     }
                }
            }
@@ -1718,9 +1827,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
                   else
                     /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
                     te_is_neigh->sub_tlvs_length = 0;
-                 listnode_add (tlv_data.te_is_neighs, te_is_neigh);
-                 lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag,
-                            sysid_print(te_is_neigh->neigh_id));
+
+                  tlvs_add_mt_p2p(&tlv_data, circuit, te_is_neigh);
+                  XFREE(MTYPE_ISIS_TLV, te_is_neigh);
                }
            }
           else
@@ -1766,35 +1875,62 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
                             lsp0, area, level);
     }
 
-  /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
-   * for now. lsp_tlv_fit() needs to be fixed to deal with variable length
-   * TLVs (sub TLVs!). */
   while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
     {
       if (lsp->tlv_data.te_ipv4_reachs == NULL)
        lsp->tlv_data.te_ipv4_reachs = list_new ();
-      lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
-                  &lsp->tlv_data.te_ipv4_reachs,
-                  TE_IPV4_REACH_LEN, area->lsp_frag_threshold,
-                  tlv_add_te_ipv4_reachs);
+      _lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs, &lsp->tlv_data.te_ipv4_reachs,
+                   area->lsp_frag_threshold, tlv_add_te_ipv4_reachs, NULL);
       if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
        lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
                             lsp0, area, level);
     }
 
+  struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
+  for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv4_reachs, node, mt_ipv4_reachs))
+    {
+      while (mt_ipv4_reachs->list && listcount(mt_ipv4_reachs->list))
+        {
+          struct tlv_mt_ipv4_reachs *frag_mt_ipv4_reachs;
+
+          frag_mt_ipv4_reachs = tlvs_get_mt_ipv4_reachs(&lsp->tlv_data, mt_ipv4_reachs->mtid);
+          _lsp_tlv_fit (lsp, &mt_ipv4_reachs->list, &frag_mt_ipv4_reachs->list,
+                        area->lsp_frag_threshold, tlv_add_te_ipv4_reachs,
+                        &mt_ipv4_reachs->mtid);
+          if (mt_ipv4_reachs->list && listcount(mt_ipv4_reachs->list))
+            lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
+                                 lsp0, area, level);
+        }
+    }
+
   while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
     {
       if (lsp->tlv_data.ipv6_reachs == NULL)
        lsp->tlv_data.ipv6_reachs = list_new ();
-      lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs,
-                  &lsp->tlv_data.ipv6_reachs,
-                  IPV6_REACH_LEN, area->lsp_frag_threshold,
-                  tlv_add_ipv6_reachs);
+      _lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs,
+                   area->lsp_frag_threshold, tlv_add_ipv6_reachs, NULL);
       if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
        lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
                             lsp0, area, level);
     }
 
+  struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
+  for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv6_reachs, node, mt_ipv6_reachs))
+    {
+      while (mt_ipv6_reachs->list && listcount(mt_ipv6_reachs->list))
+        {
+          struct tlv_mt_ipv6_reachs *frag_mt_ipv6_reachs;
+
+          frag_mt_ipv6_reachs = tlvs_get_mt_ipv6_reachs(&lsp->tlv_data, mt_ipv6_reachs->mtid);
+          _lsp_tlv_fit (lsp, &mt_ipv6_reachs->list, &frag_mt_ipv6_reachs->list,
+                        area->lsp_frag_threshold, tlv_add_ipv6_reachs,
+                        &mt_ipv6_reachs->mtid);
+          if (mt_ipv6_reachs->list && listcount(mt_ipv6_reachs->list))
+            lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
+                                 lsp0, area, level);
+        }
+    }
+
   while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
     {
       if (lsp->tlv_data.is_neighs == NULL)
@@ -1812,13 +1948,31 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
     {
       if (lsp->tlv_data.te_is_neighs == NULL)
        lsp->tlv_data.te_is_neighs = list_new ();
-      lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
-                  IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
-                  tlv_add_te_is_neighs);
+      _lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
+                   area->lsp_frag_threshold, tlv_add_te_is_neighs, NULL);
       if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
        lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
                             lsp0, area, level);
     }
+
+  struct tlv_mt_neighbors *mt_neighs;
+  for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_is_neighs, node, mt_neighs))
+    {
+      while (mt_neighs->list && listcount(mt_neighs->list))
+        {
+          struct tlv_mt_neighbors *frag_mt_neighs;
+
+          frag_mt_neighs = tlvs_get_mt_neighbors(&lsp->tlv_data, mt_neighs->mtid);
+          _lsp_tlv_fit (lsp, &mt_neighs->list, &frag_mt_neighs->list,
+                        area->lsp_frag_threshold, tlv_add_te_is_neighs,
+                        &mt_neighs->mtid);
+          if (mt_neighs->list && listcount(mt_neighs->list))
+            lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
+                                 lsp0, area, level);
+        }
+    }
+
+
   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
 
   free_tlvs (&tlv_data);
@@ -2255,7 +2409,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
     tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
 
   if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0)
-    tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu);
+    tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu, NULL);
 
   if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0)
     tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
index 24fae57a7bc421a082609d5a4f727b82fbb46ce6..6f697df62c7331fc5eeed5ada36912139002568c 100644 (file)
@@ -108,8 +108,6 @@ void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost);
 int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail,
                   char dynhost);
 const char *lsp_bits2string (u_char *);
-void lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from,
-                    struct list **to, int frag_thold);
 
 /* sets SRMflags for all active circuits of an lsp */
 void lsp_set_all_srmflags (struct isis_lsp *lsp);
diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c
new file mode 100644 (file)
index 0000000..d15da1d
--- /dev/null
@@ -0,0 +1,744 @@
+/*
+ * IS-IS Rout(e)ing protocol - Multi Topology Support
+ *
+ * Copyright (C) 2017 Christian Franke
+ *
+ * This file is part of FreeRangeRouting (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.
+ */
+#include <zebra.h>
+#include "isisd/isisd.h"
+#include "isisd/isis_memory.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_tlv.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_mt.h"
+
+DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
+DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
+DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
+DEFINE_MTYPE_STATIC(ISISD, MT_NEIGHBORS, "ISIS MT Neighbors for TLV")
+DEFINE_MTYPE_STATIC(ISISD, MT_IPV4_REACHS, "ISIS MT IPv4 Reachabilities for TLV")
+DEFINE_MTYPE_STATIC(ISISD, MT_IPV6_REACHS, "ISIS MT IPv6 Reachabilities for TLV")
+
+uint16_t isis_area_ipv6_topology(struct isis_area *area)
+{
+  struct isis_area_mt_setting *area_mt_setting;
+  area_mt_setting = area_lookup_mt_setting(area, ISIS_MT_IPV6_UNICAST);
+
+  if (area_mt_setting && area_mt_setting->enabled)
+    return ISIS_MT_IPV6_UNICAST;
+  return ISIS_MT_IPV4_UNICAST;
+}
+
+/* MT naming api */
+const char *isis_mtid2str(uint16_t mtid)
+{
+  static char buf[sizeof("65535")];
+
+  switch(mtid)
+    {
+      case ISIS_MT_IPV4_UNICAST:
+        return "ipv4-unicast";
+      case ISIS_MT_IPV4_MGMT:
+        return "ipv4-mgmt";
+      case ISIS_MT_IPV6_UNICAST:
+        return "ipv6-unicast";
+      case ISIS_MT_IPV4_MULTICAST:
+        return "ipv4-multicast";
+      case ISIS_MT_IPV6_MULTICAST:
+        return "ipv6-multicast";
+      case ISIS_MT_IPV6_MGMT:
+        return "ipv6-mgmt";
+      default:
+        snprintf(buf, sizeof(buf), "%" PRIu16, mtid);
+        return buf;
+    }
+}
+
+uint16_t isis_str2mtid(const char *name)
+{
+  if (!strcmp(name,"ipv4-unicast"))
+    return ISIS_MT_IPV4_UNICAST;
+  if (!strcmp(name,"ipv4-mgmt"))
+    return ISIS_MT_IPV4_MGMT;
+  if (!strcmp(name,"ipv6-unicast"))
+    return ISIS_MT_IPV6_UNICAST;
+  if (!strcmp(name,"ipv4-multicast"))
+    return ISIS_MT_IPV4_MULTICAST;
+  if (!strcmp(name,"ipv6-multicast"))
+    return ISIS_MT_IPV6_MULTICAST;
+  if (!strcmp(name,"ipv6-mgmt"))
+    return ISIS_MT_IPV6_MGMT;
+  return -1;
+}
+
+/* General MT settings api */
+
+struct mt_setting {
+       ISIS_MT_INFO_FIELDS;
+};
+
+static void *
+lookup_mt_setting(struct list *mt_list, uint16_t mtid)
+{
+  struct listnode *node;
+  struct mt_setting *setting;
+
+  for (ALL_LIST_ELEMENTS_RO(mt_list, node, setting))
+    {
+      if (setting->mtid == mtid)
+        return setting;
+    }
+  return NULL;
+}
+
+static void
+add_mt_setting(struct list **mt_list, void *setting)
+{
+  if (!*mt_list)
+    *mt_list = list_new();
+  listnode_add(*mt_list, setting);
+}
+
+/* Area specific MT settings api */
+
+struct isis_area_mt_setting*
+area_lookup_mt_setting(struct isis_area *area, uint16_t mtid)
+{
+  return lookup_mt_setting(area->mt_settings, mtid);
+}
+
+struct isis_area_mt_setting*
+area_new_mt_setting(struct isis_area *area, uint16_t mtid)
+{
+  struct isis_area_mt_setting *setting;
+
+  setting = XCALLOC(MTYPE_MT_AREA_SETTING, sizeof(*setting));
+  setting->mtid = mtid;
+  return setting;
+}
+
+static void
+area_free_mt_setting(void *setting)
+{
+  XFREE(MTYPE_MT_AREA_SETTING, setting);
+}
+
+void
+area_add_mt_setting(struct isis_area *area, struct isis_area_mt_setting *setting)
+{
+  add_mt_setting(&area->mt_settings, setting);
+}
+
+void
+area_mt_init(struct isis_area *area)
+{
+  struct isis_area_mt_setting *v4_unicast_setting;
+
+  /* MTID 0 is always enabled */
+  v4_unicast_setting = area_new_mt_setting(area, ISIS_MT_IPV4_UNICAST);
+  v4_unicast_setting->enabled = true;
+  add_mt_setting(&area->mt_settings, v4_unicast_setting);
+  area->mt_settings->del = area_free_mt_setting;
+}
+
+void
+area_mt_finish(struct isis_area *area)
+{
+  list_delete(area->mt_settings);
+  area->mt_settings = NULL;
+}
+
+struct isis_area_mt_setting *
+area_get_mt_setting(struct isis_area *area, uint16_t mtid)
+{
+  struct isis_area_mt_setting *setting;
+
+  setting = area_lookup_mt_setting(area, mtid);
+  if (!setting)
+    {
+      setting = area_new_mt_setting(area, mtid);
+      area_add_mt_setting(area, setting);
+    }
+  return setting;
+}
+
+int
+area_write_mt_settings(struct isis_area *area, struct vty *vty)
+{
+  int written = 0;
+  struct listnode *node;
+  struct isis_area_mt_setting *setting;
+
+  for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
+    {
+      const char *name = isis_mtid2str(setting->mtid);
+      if (name && setting->enabled)
+        {
+          if (setting->mtid == ISIS_MT_IPV4_UNICAST)
+            continue; /* always enabled, no need to write out config */
+          vty_out (vty, " topology %s%s%s", name,
+                   setting->overload ? " overload" : "",
+                   VTY_NEWLINE);
+          written++;
+        }
+    }
+  return written;
+}
+
+bool area_is_mt(struct isis_area *area)
+{
+  struct listnode *node, *node2;
+  struct isis_area_mt_setting *setting;
+  struct isis_circuit *circuit;
+  struct isis_circuit_mt_setting *csetting;
+
+  for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
+    {
+      if (setting->enabled && setting->mtid != ISIS_MT_IPV4_UNICAST)
+        return true;
+    }
+  for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+    {
+      for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node2, csetting))
+        {
+          if (!csetting->enabled && csetting->mtid == ISIS_MT_IPV4_UNICAST)
+            return true;
+        }
+    }
+
+  return false;
+}
+
+struct isis_area_mt_setting**
+area_mt_settings(struct isis_area *area, unsigned int *mt_count)
+{
+  static unsigned int size = 0;
+  static struct isis_area_mt_setting **rv = NULL;
+
+  unsigned int count = 0;
+  struct listnode *node;
+  struct isis_area_mt_setting *setting;
+
+  for (ALL_LIST_ELEMENTS_RO(area->mt_settings, node, setting))
+    {
+      if (!setting->enabled)
+        continue;
+
+      count++;
+      if (count > size)
+        {
+          rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
+          size = count;
+        }
+      rv[count-1] = setting;
+    }
+
+  *mt_count = count;
+  return rv;
+}
+
+/* Circuit specific MT settings api */
+
+struct isis_circuit_mt_setting*
+circuit_lookup_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
+{
+  return lookup_mt_setting(circuit->mt_settings, mtid);
+}
+
+struct isis_circuit_mt_setting*
+circuit_new_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
+{
+  struct isis_circuit_mt_setting *setting;
+
+  setting = XCALLOC(MTYPE_MT_CIRCUIT_SETTING, sizeof(*setting));
+  setting->mtid = mtid;
+  setting->enabled = true; /* Enabled is default for circuit */
+  return setting;
+}
+
+static void
+circuit_free_mt_setting(void *setting)
+{
+  XFREE(MTYPE_MT_CIRCUIT_SETTING, setting);
+}
+
+void
+circuit_add_mt_setting(struct isis_circuit *circuit,
+                       struct isis_circuit_mt_setting *setting)
+{
+  add_mt_setting(&circuit->mt_settings, setting);
+}
+
+void
+circuit_mt_init(struct isis_circuit *circuit)
+{
+  circuit->mt_settings = list_new();
+  circuit->mt_settings->del = circuit_free_mt_setting;
+}
+
+void
+circuit_mt_finish(struct isis_circuit *circuit)
+{
+  list_delete(circuit->mt_settings);
+  circuit->mt_settings = NULL;
+}
+
+struct isis_circuit_mt_setting*
+circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid)
+{
+  struct isis_circuit_mt_setting *setting;
+
+  setting = circuit_lookup_mt_setting(circuit, mtid);
+  if (!setting)
+    {
+      setting = circuit_new_mt_setting(circuit, mtid);
+      circuit_add_mt_setting(circuit, setting);
+    }
+  return setting;
+}
+
+int
+circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty)
+{
+  int written = 0;
+  struct listnode *node;
+  struct isis_circuit_mt_setting *setting;
+
+  for (ALL_LIST_ELEMENTS_RO (circuit->mt_settings, node, setting))
+    {
+      const char *name = isis_mtid2str(setting->mtid);
+      if (name && !setting->enabled)
+        {
+          vty_out (vty, " no isis topology %s%s", name, VTY_NEWLINE);
+          written++;
+        }
+    }
+  return written;
+}
+
+struct isis_circuit_mt_setting**
+circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count)
+{
+  static unsigned int size = 0;
+  static struct isis_circuit_mt_setting **rv = NULL;
+
+  struct isis_area_mt_setting **area_settings;
+  unsigned int area_count;
+
+  unsigned int count = 0;
+
+  struct listnode *node;
+  struct isis_circuit_mt_setting *setting;
+
+  area_settings = area_mt_settings(circuit->area, &area_count);
+
+  for (unsigned int i = 0; i < area_count; i++)
+    {
+      for (ALL_LIST_ELEMENTS_RO(circuit->mt_settings, node, setting))
+        {
+          if (setting->mtid != area_settings[i]->mtid)
+            continue;
+          break;
+        }
+      if (!setting)
+        setting = circuit_get_mt_setting(circuit, area_settings[i]->mtid);
+
+      if (!setting->enabled)
+        continue;
+
+      count++;
+      if (count > size)
+        {
+          rv = XREALLOC(MTYPE_TMP, rv, count * sizeof(*rv));
+          size = count;
+        }
+      rv[count-1] = setting;
+    }
+
+  *mt_count = count;
+  return rv;
+}
+
+/* ADJ specific MT API */
+static void adj_mt_set(struct isis_adjacency *adj, unsigned int index,
+                       uint16_t mtid)
+{
+  if (adj->mt_count < index + 1)
+    {
+      adj->mt_set = XREALLOC(MTYPE_MT_ADJ_INFO, adj->mt_set,
+                             (index + 1) * sizeof(*adj->mt_set));
+      adj->mt_count = index + 1;
+    }
+  adj->mt_set[index] = mtid;
+}
+
+bool
+tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
+                   struct isis_adjacency *adj)
+{
+  struct isis_circuit_mt_setting **mt_settings;
+  unsigned int circuit_mt_count;
+
+  unsigned int intersect_count = 0;
+
+  uint16_t *old_mt_set = NULL;
+  unsigned int old_mt_count;
+
+  old_mt_count = adj->mt_count;
+  if (old_mt_count)
+    {
+      old_mt_set = XCALLOC(MTYPE_TMP, old_mt_count * sizeof(*old_mt_set));
+      memcpy(old_mt_set, adj->mt_set, old_mt_count * sizeof(*old_mt_set));
+    }
+
+  mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count);
+  for (unsigned int i = 0; i < circuit_mt_count; i++)
+    {
+      if (!tlvs->mt_router_info)
+        {
+          /* Other end does not have MT enabled */
+          if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST && v4_usable)
+            adj_mt_set(adj, intersect_count++, ISIS_MT_IPV4_UNICAST);
+        }
+      else
+        {
+          struct listnode *node;
+          struct mt_router_info *info;
+          for (ALL_LIST_ELEMENTS_RO(tlvs->mt_router_info, node, info))
+            {
+              if (mt_settings[i]->mtid == info->mtid)
+                {
+                  bool usable;
+                  switch (info->mtid)
+                    {
+                      case ISIS_MT_IPV4_UNICAST:
+                      case ISIS_MT_IPV4_MGMT:
+                      case ISIS_MT_IPV4_MULTICAST:
+                        usable = v4_usable;
+                        break;
+                      case ISIS_MT_IPV6_UNICAST:
+                      case ISIS_MT_IPV6_MGMT:
+                      case ISIS_MT_IPV6_MULTICAST:
+                        usable = v6_usable;
+                        break;
+                      default:
+                        usable = true;
+                        break;
+                    }
+                  if (usable)
+                    adj_mt_set(adj, intersect_count++, info->mtid);
+                }
+            }
+        }
+    }
+  adj->mt_count = intersect_count;
+
+  bool changed = false;
+
+  if (adj->mt_count != old_mt_count)
+    changed = true;
+
+  if (!changed && old_mt_count
+      && memcmp(adj->mt_set, old_mt_set,
+                old_mt_count * sizeof(*old_mt_set)))
+    changed = true;
+
+  if (old_mt_count)
+    XFREE(MTYPE_TMP, old_mt_set);
+
+  return changed;
+}
+
+bool
+adj_has_mt(struct isis_adjacency *adj, uint16_t mtid)
+{
+  for (unsigned int i = 0; i < adj->mt_count; i++)
+    if (adj->mt_set[i] == mtid)
+      return true;
+  return false;
+}
+
+void
+adj_mt_finish(struct isis_adjacency *adj)
+{
+  XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
+  adj->mt_count = 0;
+}
+
+/* TLV Router info api */
+struct mt_router_info*
+tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid)
+{
+  return lookup_mt_setting(tlvs->mt_router_info, mtid);
+}
+
+/* TLV MT Neighbors api */
+struct tlv_mt_neighbors*
+tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
+{
+  return lookup_mt_setting(tlvs->mt_is_neighs, mtid);
+}
+
+static struct tlv_mt_neighbors*
+tlvs_new_mt_neighbors(uint16_t mtid)
+{
+  struct tlv_mt_neighbors *rv;
+
+  rv = XCALLOC(MTYPE_MT_NEIGHBORS, sizeof(*rv));
+  rv->mtid = mtid;
+  rv->list = list_new();
+
+  return rv;
+};
+
+static void
+tlvs_free_mt_neighbors(void *arg)
+{
+  struct tlv_mt_neighbors *neighbors = arg;
+
+  if (neighbors && neighbors->list)
+    list_delete(neighbors->list);
+  XFREE(MTYPE_MT_NEIGHBORS, neighbors);
+}
+
+static void
+tlvs_add_mt_neighbors(struct tlvs *tlvs, struct tlv_mt_neighbors *neighbors)
+{
+  add_mt_setting(&tlvs->mt_is_neighs, neighbors);
+  tlvs->mt_is_neighs->del = tlvs_free_mt_neighbors;
+}
+
+struct tlv_mt_neighbors*
+tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
+{
+  struct tlv_mt_neighbors *neighbors;
+
+  neighbors = tlvs_lookup_mt_neighbors(tlvs, mtid);
+  if (!neighbors)
+    {
+      neighbors = tlvs_new_mt_neighbors(mtid);
+      tlvs_add_mt_neighbors(tlvs, neighbors);
+    }
+  return neighbors;
+}
+
+/* TLV MT IPv4 reach api */
+struct tlv_mt_ipv4_reachs*
+tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
+{
+  return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid);
+}
+
+static struct tlv_mt_ipv4_reachs*
+tlvs_new_mt_ipv4_reachs(uint16_t mtid)
+{
+  struct tlv_mt_ipv4_reachs *rv;
+
+  rv = XCALLOC(MTYPE_MT_IPV4_REACHS, sizeof(*rv));
+  rv->mtid = mtid;
+  rv->list = list_new();
+
+  return rv;
+};
+
+static void
+tlvs_free_mt_ipv4_reachs(void *arg)
+{
+  struct tlv_mt_ipv4_reachs *reachs = arg;
+
+  if (reachs && reachs->list)
+    list_delete(reachs->list);
+  XFREE(MTYPE_MT_IPV4_REACHS, reachs);
+}
+
+static void
+tlvs_add_mt_ipv4_reachs(struct tlvs *tlvs, struct tlv_mt_ipv4_reachs *reachs)
+{
+  add_mt_setting(&tlvs->mt_ipv4_reachs, reachs);
+  tlvs->mt_ipv4_reachs->del = tlvs_free_mt_ipv4_reachs;
+}
+
+struct tlv_mt_ipv4_reachs*
+tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid)
+{
+  struct tlv_mt_ipv4_reachs *reachs;
+
+  reachs = tlvs_lookup_mt_ipv4_reachs(tlvs, mtid);
+  if (!reachs)
+    {
+      reachs = tlvs_new_mt_ipv4_reachs(mtid);
+      tlvs_add_mt_ipv4_reachs(tlvs, reachs);
+    }
+  return reachs;
+}
+
+/* TLV MT IPv6 reach api */
+struct tlv_mt_ipv6_reachs*
+tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
+{
+  return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid);
+}
+
+static struct tlv_mt_ipv6_reachs*
+tlvs_new_mt_ipv6_reachs(uint16_t mtid)
+{
+  struct tlv_mt_ipv6_reachs *rv;
+
+  rv = XCALLOC(MTYPE_MT_IPV6_REACHS, sizeof(*rv));
+  rv->mtid = mtid;
+  rv->list = list_new();
+
+  return rv;
+};
+
+static void
+tlvs_free_mt_ipv6_reachs(void *arg)
+{
+  struct tlv_mt_ipv6_reachs *reachs = arg;
+
+  if (reachs && reachs->list)
+    list_delete(reachs->list);
+  XFREE(MTYPE_MT_IPV6_REACHS, reachs);
+}
+
+static void
+tlvs_add_mt_ipv6_reachs(struct tlvs *tlvs, struct tlv_mt_ipv6_reachs *reachs)
+{
+  add_mt_setting(&tlvs->mt_ipv6_reachs, reachs);
+  tlvs->mt_ipv6_reachs->del = tlvs_free_mt_ipv6_reachs;
+}
+
+struct tlv_mt_ipv6_reachs*
+tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid)
+{
+  struct tlv_mt_ipv6_reachs *reachs;
+
+  reachs = tlvs_lookup_mt_ipv6_reachs(tlvs, mtid);
+  if (!reachs)
+    {
+      reachs = tlvs_new_mt_ipv6_reachs(mtid);
+      tlvs_add_mt_ipv6_reachs(tlvs, reachs);
+    }
+  return reachs;
+}
+
+static void
+mt_set_add(uint16_t **mt_set, unsigned int *size,
+           unsigned int *index, uint16_t mtid)
+{
+  for (unsigned int i = 0; i < *index; i++)
+    {
+      if ((*mt_set)[i] == mtid)
+        return;
+    }
+
+  if (*index >= *size)
+    {
+      *mt_set = XREALLOC(MTYPE_TMP, *mt_set, sizeof(**mt_set) * ((*index) + 1));
+      *size = (*index) + 1;
+    }
+
+  (*mt_set)[*index] = mtid;
+  *index = (*index) + 1;
+}
+
+static uint16_t *
+circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
+                     unsigned int *mt_count)
+{
+  static uint16_t *rv;
+  static unsigned int size;
+  struct listnode *node;
+  struct isis_adjacency *adj;
+
+  unsigned int count = 0;
+
+  if (circuit->circ_type != CIRCUIT_T_BROADCAST)
+    {
+      *mt_count = 0;
+      return NULL;
+    }
+
+  for (ALL_LIST_ELEMENTS_RO(circuit->u.bc.adjdb[level - 1], node, adj))
+    {
+      if (adj->adj_state != ISIS_ADJ_UP)
+        continue;
+      for (unsigned int i = 0; i < adj->mt_count; i++)
+        mt_set_add(&rv, &size, &count, adj->mt_set[i]);
+    }
+
+  *mt_count = count;
+  return rv;
+}
+
+static void
+tlvs_add_mt_set(struct isis_area *area,
+                struct tlvs *tlvs, unsigned int mt_count,
+                uint16_t *mt_set, struct te_is_neigh *neigh)
+{
+  for (unsigned int i = 0; i < mt_count; i++)
+    {
+      uint16_t mtid = mt_set[i];
+      struct te_is_neigh *ne_copy;
+
+      ne_copy = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ne_copy));
+      memcpy(ne_copy, neigh, sizeof(*ne_copy));
+
+      if (mt_set[i] == ISIS_MT_IPV4_UNICAST)
+        {
+          listnode_add(tlvs->te_is_neighs, ne_copy);
+          lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor",
+                    area->area_tag, sysid_print(ne_copy->neigh_id),
+                    LSP_PSEUDO_ID(ne_copy->neigh_id));
+        }
+      else
+        {
+          struct tlv_mt_neighbors *neighbors;
+
+          neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
+          neighbors->list->del = free_tlv;
+          listnode_add(neighbors->list, ne_copy);
+          lsp_debug("ISIS (%s): Adding %s.%02x as mt-style neighbor for %s",
+                    area->area_tag, sysid_print(ne_copy->neigh_id),
+                    LSP_PSEUDO_ID(ne_copy->neigh_id), isis_mtid2str(mtid));
+        }
+    }
+}
+
+void
+tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
+                  int level, struct te_is_neigh *neigh)
+{
+  unsigned int mt_count;
+  uint16_t *mt_set = circuit_bcast_mt_set(circuit, level,
+                                          &mt_count);
+
+  tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, neigh);
+}
+
+void
+tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
+                struct te_is_neigh *neigh)
+{
+  struct isis_adjacency *adj = circuit->u.p2p.neighbor;
+
+  tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, neigh);
+}
diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h
new file mode 100644 (file)
index 0000000..d4dc4c6
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * IS-IS Rout(e)ing protocol - Multi Topology Support
+ *
+ * Copyright (C) 2017 Christian Franke
+ *
+ * This file is part of FreeRangeRouting (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 ISIS_MT_H
+#define ISIS_MT_H
+
+#define ISIS_MT_MASK           0x0fff
+#define ISIS_MT_OL_MASK        0x8000
+
+#define ISIS_MT_IPV4_UNICAST   0
+#define ISIS_MT_IPV4_MGMT      1
+#define ISIS_MT_IPV6_UNICAST   2
+#define ISIS_MT_IPV4_MULTICAST 3
+#define ISIS_MT_IPV6_MULTICAST 4
+#define ISIS_MT_IPV6_MGMT      5
+
+#define ISIS_MT_NAMES \
+    "<ipv4-unicast" \
+    "|ipv4-mgmt" \
+    "|ipv6-unicast" \
+    "|ipv4-multicast" \
+    "|ipv6-multicast" \
+    "|ipv6-mgmt" \
+    ">"
+
+#define ISIS_MT_DESCRIPTIONS \
+    "IPv4 unicast topology\n" \
+    "IPv4 management topology\n" \
+    "IPv6 unicast topology\n" \
+    "IPv4 multicast topology\n" \
+    "IPv6 multicast topology\n" \
+    "IPv6 management topology\n"
+
+#define ISIS_MT_INFO_FIELDS \
+  uint16_t mtid;
+
+struct list;
+
+struct isis_area_mt_setting {
+  ISIS_MT_INFO_FIELDS
+  bool enabled;
+  bool overload;
+};
+
+struct isis_circuit_mt_setting {
+  ISIS_MT_INFO_FIELDS
+  bool enabled;
+};
+
+struct tlv_mt_neighbors {
+  ISIS_MT_INFO_FIELDS
+  struct list *list;
+};
+
+struct tlv_mt_ipv4_reachs {
+  ISIS_MT_INFO_FIELDS
+  struct list *list;
+};
+
+struct tlv_mt_ipv6_reachs {
+  ISIS_MT_INFO_FIELDS
+  struct list *list;
+};
+
+const char *isis_mtid2str(uint16_t mtid);
+uint16_t isis_str2mtid(const char *name);
+
+struct isis_adjacency;
+struct isis_area;
+struct isis_circuit;
+struct tlvs;
+struct te_is_neigh;
+
+uint16_t isis_area_ipv6_topology(struct isis_area *area);
+
+struct mt_router_info* tlvs_lookup_mt_router_info(struct tlvs *tlvs, uint16_t mtid);
+
+struct tlv_mt_neighbors* tlvs_lookup_mt_neighbors(struct tlvs *tlvs, uint16_t mtid);
+struct tlv_mt_neighbors* tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid);
+
+struct tlv_mt_ipv4_reachs* tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid);
+struct tlv_mt_ipv4_reachs* tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, uint16_t mtid);
+
+struct tlv_mt_ipv6_reachs* tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid);
+struct tlv_mt_ipv6_reachs* tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, uint16_t mtid);
+
+struct isis_area_mt_setting* area_lookup_mt_setting(struct isis_area *area,
+                                                    uint16_t mtid);
+struct isis_area_mt_setting* area_new_mt_setting(struct isis_area *area,
+                                                 uint16_t mtid);
+void area_add_mt_setting(struct isis_area *area,
+                         struct isis_area_mt_setting *setting);
+
+void area_mt_init(struct isis_area *area);
+void area_mt_finish(struct isis_area *area);
+struct isis_area_mt_setting* area_get_mt_setting(struct isis_area *area,
+                                                 uint16_t mtid);
+int area_write_mt_settings(struct isis_area *area, struct vty *vty);
+bool area_is_mt(struct isis_area *area);
+struct isis_area_mt_setting** area_mt_settings(struct isis_area *area,
+                                               unsigned int *mt_count);
+
+struct isis_circuit_mt_setting* circuit_lookup_mt_setting(
+                                                struct isis_circuit *circuit,
+                                                uint16_t mtid);
+struct isis_circuit_mt_setting* circuit_new_mt_setting(
+                                                struct isis_circuit *circuit,
+                                                uint16_t mtid);
+void circuit_add_mt_setting(struct isis_circuit *circuit,
+                            struct isis_circuit_mt_setting *setting);
+void circuit_mt_init(struct isis_circuit *circuit);
+void circuit_mt_finish(struct isis_circuit *circuit);
+struct isis_circuit_mt_setting* circuit_get_mt_setting(
+                                                struct isis_circuit *circuit,
+                                                uint16_t mtid);
+int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty);
+struct isis_circuit_mt_setting** circuit_mt_settings(struct isis_circuit *circuit,
+                                                     unsigned int *mt_count);
+bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
+                        struct isis_adjacency *adj);
+bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid);
+void adj_mt_finish(struct isis_adjacency *adj);
+void tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
+                       int level, struct te_is_neigh *neigh);
+void tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
+                     struct te_is_neigh *neigh);
+#endif
index 5fbf6c194ea72281d1e7729aa93503d73542e471..5232666bda42db0b9c98d9004a6f982d6da070a3 100644 (file)
@@ -53,6 +53,7 @@
 #include "isisd/isis_csm.h"
 #include "isisd/isis_events.h"
 #include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
 
 #define ISIS_MINIMUM_FIXED_HDR_LEN 15
 #define ISIS_MIN_PDU_LEN           13  /* partial seqnum pdu with id_len=2 */
 #define PNBBY 8
 #endif /* PNBBY */
 
-/* Utility mask array. */
-static const u_char maskbit[] = {
-  0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
-};
-
 /*
  * HELPER FUNCS
  */
@@ -92,69 +88,6 @@ area_match (struct list *left, struct list *right)
   return 0;                    /* mismatch */
 }
 
-/*
- * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() )
- * param ip1            the IS interface ip address structure
- * param ip2            the IIH's ip address
- * return  0            the IIH's IP is not in the IS's subnetwork
- *         1            the IIH's IP is in the IS's subnetwork
- */
-static int
-ip_same_subnet (struct prefix_ipv4 *ip1, struct in_addr *ip2)
-{
-  u_char *addr1, *addr2;
-  int shift, offset, offsetloop;
-  int len;
-
-  addr1 = (u_char *) & ip1->prefix.s_addr;
-  addr2 = (u_char *) & ip2->s_addr;
-  len = ip1->prefixlen;
-
-  shift = len % PNBBY;
-  offsetloop = offset = len / PNBBY;
-
-  while (offsetloop--)
-    if (addr1[offsetloop] != addr2[offsetloop])
-      return 0;
-
-  if (shift)
-    if (maskbit[shift] & (addr1[offset] ^ addr2[offset]))
-      return 0;
-
-  return 1;                    /* match  */
-}
-
-/*
- * Compares two set of ip addresses
- * param left     the local interface's ip addresses
- * param right    the iih interface's ip address
- * return         0   no match;
- *                1   match;
- */
-static int
-ip_match (struct list *left, struct list *right)
-{
-  struct prefix_ipv4 *ip1;
-  struct in_addr *ip2;
-  struct listnode *node1, *node2;
-
-  if ((left == NULL) || (right == NULL))
-    return 0;
-  
-  for (ALL_LIST_ELEMENTS_RO (left, node1, ip1))
-  {
-    for (ALL_LIST_ELEMENTS_RO (right, node2, ip2))
-    {
-      if (ip_same_subnet (ip1, ip2))
-       {
-         return 1;             /* match */
-       }
-    }
-
-  }
-  return 0;
-}
-
 /*
  * Checks whether we should accept a PDU of given level 
  */
@@ -471,6 +404,7 @@ process_p2p_hello (struct isis_circuit *circuit)
   expected |= TLVFLAG_NLPID;
   expected |= TLVFLAG_IPV4_ADDR;
   expected |= TLVFLAG_IPV6_ADDR;
+  expected |= TLVFLAG_MT_ROUTER_INFORMATION;
 
   auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
   retval = parse_tlvs (circuit->area->area_tag,
@@ -515,16 +449,14 @@ process_p2p_hello (struct isis_circuit *circuit)
     }
 
   /*
-   * check if it's own interface ip match iih ip addrs
+   * check if both ends have an IPv4 address
    */
-  if (found & TLVFLAG_IPV4_ADDR)
+  if (circuit->ip_addrs && listcount(circuit->ip_addrs)
+      && tlvs.ipv4_addrs && listcount(tlvs.ipv4_addrs))
     {
-      if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs))
-       v4_usable = 1;
-      else
-       zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap "
-                  "in P2P IIH from %s\n", circuit->interface->name);
+      v4_usable = 1;
     }
+
   if (found & TLVFLAG_IPV6_ADDR)
     {
       /* TBA: check that we have a linklocal ourselves? */
@@ -633,6 +565,8 @@ process_p2p_hello (struct isis_circuit *circuit)
   if (found & TLVFLAG_IPV6_ADDR)
     tlvs_to_adj_ipv6_addrs (&tlvs, adj);
 
+  bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
+
   /* lets take care of the expiry */
   THREAD_TIMER_OFF (adj->t_expire);
   THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
@@ -869,6 +803,13 @@ process_p2p_hello (struct isis_circuit *circuit)
       /* down - area mismatch */
       isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
     }
+
+  if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed)
+    {
+      lsp_regenerate_schedule(adj->circuit->area,
+                              isis_adj_usage2levels(adj->adj_usage), 0);
+    }
+
   /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
   /* FIXME - Missing parts */
 
@@ -1021,6 +962,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
   expected |= TLVFLAG_NLPID;
   expected |= TLVFLAG_IPV4_ADDR;
   expected |= TLVFLAG_IPV6_ADDR;
+  expected |= TLVFLAG_MT_ROUTER_INFORMATION;
 
   auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
   retval = parse_tlvs (circuit->area->area_tag,
@@ -1104,16 +1046,14 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
     }
 
   /*
-   * check if it's own interface ip match iih ip addrs
+   * check if both ends have an IPv4 address
    */
-  if (found & TLVFLAG_IPV4_ADDR)
+  if (circuit->ip_addrs && listcount(circuit->ip_addrs)
+      && tlvs.ipv4_addrs && listcount(tlvs.ipv4_addrs))
     {
-      if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs))
-       v4_usable = 1;
-      else
-       zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap "
-                  "in LAN IIH from %s\n", circuit->interface->name);
+      v4_usable = 1;
     }
+
   if (found & TLVFLAG_IPV6_ADDR)
     {
       /* TBA: check that we have a linklocal ourselves? */
@@ -1223,6 +1163,8 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
 
   adj->circuit_t = hdr.circuit_t;
 
+  bool mt_set_changed = tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
+
   /* lets take care of the expiry */
   THREAD_TIMER_OFF (adj->t_expire);
   THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
@@ -1266,6 +1208,9 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
                            "no LAN Neighbours TLV found");
   }
 
+  if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed)
+    lsp_regenerate_schedule(adj->circuit->area, level, 0);
+
 out:
   if (isis->debugs & DEBUG_ADJ_PACKETS)
     {
@@ -2337,6 +2282,37 @@ send_hello (struct isis_circuit *circuit, int level)
     if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
       return ISIS_WARNING;
 
+  /*
+   * MT Supported TLV
+   *
+   * TLV gets included if no topology is enabled on the interface,
+   * if one topology other than #0 is enabled, or if multiple topologies
+   * are enabled.
+   */
+  struct isis_circuit_mt_setting **mt_settings;
+  unsigned int mt_count;
+
+  mt_settings = circuit_mt_settings(circuit, &mt_count);
+  if ((mt_count == 0 && area_is_mt(circuit->area))
+      || (mt_count == 1 && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST)
+      || (mt_count > 1))
+    {
+      struct list *mt_info = list_new();
+      mt_info->del = free_tlv;
+
+      for (unsigned int i = 0; i < mt_count; i++)
+        {
+          struct mt_router_info *info;
+
+          info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
+          info->mtid = mt_settings[i]->mtid;
+          /* overload info is not valid in IIH, so it's not included here */
+          listnode_add(mt_info, info);
+        }
+      tlv_add_mt_router_info (mt_info, circuit->snd_stream);
+      list_free(mt_info);
+    }
+
   /* IPv6 Interface Address TLV */
   if (circuit->ipv6_router && circuit->ipv6_link &&
       listcount (circuit->ipv6_link) > 0)
index dd07a9c6f5758758178ce6a4c43167f7d7c0f96c..5c434b90d1721c379332fa13f90011e222402cc5 100644 (file)
@@ -371,7 +371,9 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
   stream_set_getp (circuit->snd_stream, 0);
   memset (&sa, 0, sizeof (struct sockaddr_ll));
   sa.sll_family = AF_PACKET;
-  sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
+
+  size_t frame_size = stream_get_endp(circuit->snd_stream) + LLC_LEN;
+  sa.sll_protocol = htons(isis_ethertype(frame_size));
   sa.sll_ifindex = circuit->interface->ifindex;
   sa.sll_halen = ETH_ALEN;
   /* RFC5309 section 4.1 recommends ALL_ISS */
@@ -418,7 +420,6 @@ isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
   stream_set_getp (circuit->snd_stream, 0);
   memset (&sa, 0, sizeof (struct sockaddr_ll));
   sa.sll_family = AF_PACKET;
-  sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
   sa.sll_ifindex = circuit->interface->ifindex;
   sa.sll_halen = ETH_ALEN;
   if (level == 1)
index 554fa563ad774c201250d765f06a88b39e1f809b..43dffdc863117da3842f8cbfec5f97d1426e75ec 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (C) 2001,2002   Sampo Saaristo
  *                           Tampere University of Technology      
  *                           Institute of Communications Engineering
+ * Copyright (C) 2017        Christian Franke <chris@opensourcerouting.org>
  *
  * This program is free software; you can redistribute it and/or modify it 
  * under the terms of the GNU General Public Licenseas published by the Free 
 #include "isis_spf.h"
 #include "isis_route.h"
 #include "isis_csm.h"
+#include "isis_mt.h"
+
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
+
+struct isis_spf_run {
+    struct isis_area *area;
+    int level;
+};
 
 /* 7.2.7 */
 static void
@@ -142,35 +151,24 @@ vtype2string (enum vertextype vtype)
     default:
       return "UNKNOWN";
     }
-  return NULL;                 /* Not reached */
+  return NULL; /* Not reached */
 }
 
 static const char *
 vid2string (struct isis_vertex *vertex, char * buff, int size)
 {
-  switch (vertex->type)
+  if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type))
     {
-    case VTYPE_PSEUDO_IS:
-    case VTYPE_PSEUDO_TE_IS:
       return print_sys_hostname (vertex->N.id);
-      break;
-    case VTYPE_NONPSEUDO_IS:
-    case VTYPE_NONPSEUDO_TE_IS:
-    case VTYPE_ES:
-      return print_sys_hostname (vertex->N.id);
-      break;
-    case VTYPE_IPREACH_INTERNAL:
-    case VTYPE_IPREACH_EXTERNAL:
-    case VTYPE_IPREACH_TE:
-    case VTYPE_IP6REACH_INTERNAL:
-    case VTYPE_IP6REACH_EXTERNAL:
+    }
+
+  if (VTYPE_IP(vertex->type))
+    {
       prefix2str ((struct prefix *) &vertex->N.prefix, buff, size);
-      break;
-    default:
-      return "UNKNOWN";
+      return buff;
     }
 
-  return (char *) buff;
+  return "UNKNOWN";
 }
 
 static struct isis_vertex *
@@ -181,26 +179,17 @@ isis_vertex_new (void *id, enum vertextype vtype)
   vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
 
   vertex->type = vtype;
-  switch (vtype)
+
+  if (VTYPE_IS(vtype) || VTYPE_ES(vtype))
     {
-    case VTYPE_ES:
-    case VTYPE_NONPSEUDO_IS:
-    case VTYPE_NONPSEUDO_TE_IS:
-      memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN);
-      break;
-    case VTYPE_PSEUDO_IS:
-    case VTYPE_PSEUDO_TE_IS:
       memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1);
-      break;
-    case VTYPE_IPREACH_INTERNAL:
-    case VTYPE_IPREACH_EXTERNAL:
-    case VTYPE_IPREACH_TE:
-    case VTYPE_IP6REACH_INTERNAL:
-    case VTYPE_IP6REACH_EXTERNAL:
-      memcpy (&vertex->N.prefix, (struct prefix *) id,
-             sizeof (struct prefix));
-      break;
-    default:
+    }
+  else if (VTYPE_IP(vtype))
+    {
+      memcpy (&vertex->N.prefix, (struct prefix *) id, sizeof (struct prefix));
+    }
+  else
+    {
       zlog_err ("WTF!");
     }
 
@@ -280,7 +269,7 @@ isis_spftree_del (struct isis_spftree *spftree)
   return;
 }
 
-void
+static void
 isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj)
 {
   struct listnode *node;
@@ -394,23 +383,24 @@ isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid)
  * Add this IS to the root of SPT
  */
 static struct isis_vertex *
-isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid)
+isis_spf_add_root (struct isis_spftree *spftree, u_char *sysid)
 {
   struct isis_vertex *vertex;
   struct isis_lsp *lsp;
 #ifdef EXTREME_DEBUG
   char buff[PREFIX2STR_BUFFER];
 #endif /* EXTREME_DEBUG */
+  u_char id[ISIS_SYS_ID_LEN + 1];
 
-  lsp = isis_root_system_lsp (spftree->area, level, sysid);
-  if (lsp == NULL)
-    zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
+  memcpy(id, sysid, ISIS_SYS_ID_LEN);
+  LSP_PSEUDO_ID(id) = 0;
 
-  if (!spftree->area->oldmetric)
-    vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS);
-  else
-    vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS);
+  lsp = isis_root_system_lsp (spftree->area, spftree->level, sysid);
+  if (lsp == NULL)
+    zlog_warn ("ISIS-Spf: could not find own l%d LSP!", spftree->level);
 
+  vertex = isis_vertex_new (id, spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS
+                                                         : VTYPE_NONPSEUDO_TE_IS);
   listnode_add (spftree->paths, vertex);
 
 #ifdef EXTREME_DEBUG
@@ -432,44 +422,51 @@ isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
   for (ALL_LIST_ELEMENTS_RO (list, node, vertex))
     {
       if (vertex->type != vtype)
-       continue;
-      switch (vtype)
-       {
-       case VTYPE_ES:
-       case VTYPE_NONPSEUDO_IS:
-       case VTYPE_NONPSEUDO_TE_IS:
-         if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN) == 0)
-           return vertex;
-         break;
-       case VTYPE_PSEUDO_IS:
-       case VTYPE_PSEUDO_TE_IS:
-         if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
-           return vertex;
-         break;
-       case VTYPE_IPREACH_INTERNAL:
-       case VTYPE_IPREACH_EXTERNAL:
-       case VTYPE_IPREACH_TE:
-       case VTYPE_IP6REACH_INTERNAL:
-       case VTYPE_IP6REACH_EXTERNAL:
-         p1 = (struct prefix *) id;
-         p2 = (struct prefix *) &vertex->N.id;
-         if (p1->family == p2->family && p1->prefixlen == p2->prefixlen &&
-             memcmp (&p1->u.prefix, &p2->u.prefix,
-                     PSIZE (p1->prefixlen)) == 0)
-           return vertex;
-         break;
-       }
+        continue;
+      if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type))
+        {
+          if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
+            return vertex;
+        }
+      if (VTYPE_IP(vertex->type))
+        {
+          p1 = (struct prefix *) id;
+          p2 = (struct prefix *) &vertex->N.id;
+          if (p1->family == p2->family
+              && p1->prefixlen == p2->prefixlen
+              && !memcmp(&p1->u.prefix, &p2->u.prefix, PSIZE (p1->prefixlen)))
+            {
+              return vertex;
+            }
+        }
     }
 
   return NULL;
 }
 
+/*
+ * Compares vertizes for sorting in the TENT list. Returns true
+ * if candidate should be considered before current, false otherwise.
+ */
+static bool
+tent_cmp (struct isis_vertex *current, struct isis_vertex *candidate)
+{
+  if (current->d_N > candidate->d_N)
+    return true;
+
+  if (current->d_N == candidate->d_N
+      && current->type > candidate->type)
+    return true;
+
+  return false;
+}
+
 /*
  * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
  */
 static struct isis_vertex *
 isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
-                  void *id, uint32_t cost, int depth, int family,
+                  void *id, uint32_t cost, int depth,
                   struct isis_adjacency *adj, struct isis_vertex *parent)
 {
   struct isis_vertex *vertex, *v;
@@ -515,17 +512,11 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
   for (node = listhead (spftree->tents); node; node = listnextnode (node))
     {
       v = listgetdata (node);
-      if (v->d_N > vertex->d_N)
-       {
-         listnode_add_before (spftree->tents, node, vertex);
-         break;
-       }
-      else if (v->d_N == vertex->d_N && v->type > vertex->type)
-       {
-         /*  Tie break, add according to type */
+      if (tent_cmp(v, vertex))
+        {
           listnode_add_before (spftree->tents, node, vertex);
-         break;
-       }
+          break;
+        }
     }
 
   if (node == NULL)
@@ -537,7 +528,7 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
 static void
 isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
                    void *id, struct isis_adjacency *adj, uint32_t cost,
-                   int family, struct isis_vertex *parent)
+                   struct isis_vertex *parent)
 {
   struct isis_vertex *vertex;
 
@@ -576,13 +567,13 @@ isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
       }
     }
 
-  isis_spf_add2tent (spftree, vtype, id, cost, 1, family, adj, parent);
+  isis_spf_add2tent (spftree, vtype, id, cost, 1, adj, parent);
   return;
 }
 
 static void
 process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
-          uint32_t dist, uint16_t depth, int family,
+          uint32_t dist, uint16_t depth,
           struct isis_vertex *parent)
 {
   struct isis_vertex *vertex;
@@ -670,7 +661,7 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
               (parent ? print_sys_hostname (parent->N.id) : "null"));
 #endif /* EXTREME_DEBUG */
 
-  isis_spf_add2tent (spftree, vtype, id, dist, depth, family, NULL, parent);
+  isis_spf_add2tent (spftree, vtype, id, dist, depth, NULL, parent);
   return;
 }
 
@@ -679,9 +670,10 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
  */
 static int
 isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
-                     uint32_t cost, uint16_t depth, int family,
+                     uint32_t cost, uint16_t depth,
                      u_char *root_sysid, struct isis_vertex *parent)
 {
+  bool pseudo_lsp = LSP_PSEUDO_ID(lsp->lsp_header->lsp_id);
   struct listnode *node, *fragnode = NULL;
   uint32_t dist;
   struct is_neigh *is_neigh;
@@ -692,8 +684,14 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
   struct prefix prefix;
   struct ipv6_reachability *ip6reach;
   static const u_char null_sysid[ISIS_SYS_ID_LEN];
+  struct mt_router_info *mt_router_info = NULL;
+
+  if (spftree->mtid != ISIS_MT_IPV4_UNICAST)
+    mt_router_info = tlvs_lookup_mt_router_info(&lsp->tlv_data, spftree->mtid);
 
-  if (!speaks (lsp->tlv_data.nlpids, family))
+  if (!pseudo_lsp
+      && (spftree->mtid == ISIS_MT_IPV4_UNICAST && !speaks(lsp->tlv_data.nlpids, spftree->family))
+      && !mt_router_info)
     return ISIS_OK;
 
 lspfragloop:
@@ -707,9 +705,13 @@ lspfragloop:
       zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id));
 #endif /* EXTREME_DEBUG */
 
-  if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
+  /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
+  if (pseudo_lsp
+      || (spftree->mtid == ISIS_MT_IPV4_UNICAST && !ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
+      || (mt_router_info && !mt_router_info->overload))
+
   {
-    if (lsp->tlv_data.is_neighs)
+    if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
     {
       for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
       {
@@ -717,95 +719,126 @@ lspfragloop:
         /* Two way connectivity */
         if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
           continue;
-        if (!memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
+        if (!pseudo_lsp && !memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
           continue;
         dist = cost + is_neigh->metrics.metric_default;
-        vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
-          : VTYPE_NONPSEUDO_IS;
-        process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
-            depth + 1, family, parent);
+        process_N (spftree, LSP_PSEUDO_ID(is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
+                                                              : VTYPE_NONPSEUDO_IS,
+                   (void *) is_neigh->neigh_id, dist, depth + 1, parent);
       }
     }
-    if (lsp->tlv_data.te_is_neighs)
-    {
-      for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node,
-            te_is_neigh))
+
+    struct list *te_is_neighs = NULL;
+    if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
+      {
+        te_is_neighs = lsp->tlv_data.te_is_neighs;
+      }
+    else
+      {
+        struct tlv_mt_neighbors *mt_neighbors;
+        mt_neighbors = tlvs_lookup_mt_neighbors(&lsp->tlv_data, spftree->mtid);
+        if (mt_neighbors)
+          te_is_neighs = mt_neighbors->list;
+      }
+    for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
       {
         if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
           continue;
-        if (!memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
+        if (!pseudo_lsp && !memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
           continue;
         dist = cost + GET_TE_METRIC(te_is_neigh);
-        vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
-          : VTYPE_NONPSEUDO_TE_IS;
-        process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
-            depth + 1, family, parent);
+        process_N (spftree, LSP_PSEUDO_ID(te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
+                                                                 : VTYPE_NONPSEUDO_TE_IS,
+                   (void *) te_is_neigh->neigh_id, dist, depth + 1, parent);
       }
-    }
   }
 
-  if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
-  {
-    prefix.family = AF_INET;
-    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, node, ipreach))
-    {
-      dist = cost + ipreach->metrics.metric_default;
-      vtype = VTYPE_IPREACH_INTERNAL;
-      prefix.u.prefix4 = ipreach->prefix;
-      prefix.prefixlen = ip_masklen (ipreach->mask);
-      apply_mask (&prefix);
-      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
-                 family, parent);
-    }
-  }
-  if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs)
+  if (!pseudo_lsp
+      && spftree->family == AF_INET
+      && spftree->mtid == ISIS_MT_IPV4_UNICAST)
   {
+    struct list *reachs[] = {lsp->tlv_data.ipv4_int_reachs,
+                              lsp->tlv_data.ipv4_ext_reachs};
+
     prefix.family = AF_INET;
-    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, node, ipreach))
-    {
-      dist = cost + ipreach->metrics.metric_default;
-      vtype = VTYPE_IPREACH_EXTERNAL;
-      prefix.u.prefix4 = ipreach->prefix;
-      prefix.prefixlen = ip_masklen (ipreach->mask);
-      apply_mask (&prefix);
-      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
-                 family, parent);
-    }
+    for (unsigned int i = 0; i < array_size(reachs); i++)
+      {
+        vtype = (reachs[i] == lsp->tlv_data.ipv4_int_reachs) ? VTYPE_IPREACH_INTERNAL
+                                                             : VTYPE_IPREACH_EXTERNAL;
+        for (ALL_LIST_ELEMENTS_RO (reachs[i], node, ipreach))
+          {
+            dist = cost + ipreach->metrics.metric_default;
+            prefix.u.prefix4 = ipreach->prefix;
+            prefix.prefixlen = ip_masklen (ipreach->mask);
+            apply_mask (&prefix);
+            process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+                       parent);
+          }
+      }
   }
-  if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs)
+
+  if (!pseudo_lsp && spftree->family == AF_INET)
   {
+    struct list *ipv4reachs = NULL;
+
+    if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
+      {
+        ipv4reachs = lsp->tlv_data.te_ipv4_reachs;
+      }
+    else
+      {
+        struct tlv_mt_ipv4_reachs *mt_reachs;
+        mt_reachs = tlvs_lookup_mt_ipv4_reachs(&lsp->tlv_data, spftree->mtid);
+        if (mt_reachs)
+          ipv4reachs = mt_reachs->list;
+      }
+
     prefix.family = AF_INET;
-    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs,
-                               node, te_ipv4_reach))
+    for (ALL_LIST_ELEMENTS_RO (ipv4reachs, node, te_ipv4_reach))
     {
       assert ((te_ipv4_reach->control & 0x3F) <= IPV4_MAX_BITLEN);
 
       dist = cost + ntohl (te_ipv4_reach->te_metric);
-      vtype = VTYPE_IPREACH_TE;
       prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start,
                                            te_ipv4_reach->control);
       prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
       apply_mask (&prefix);
-      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
-                 family, parent);
+      process_N (spftree, VTYPE_IPREACH_TE, (void *) &prefix, dist, depth + 1,
+                 parent);
     }
   }
-  if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
+
+  if (!pseudo_lsp
+      && spftree->family == AF_INET6)
   {
+    struct list *ipv6reachs = NULL;
+
+    if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
+      {
+        ipv6reachs = lsp->tlv_data.ipv6_reachs;
+      }
+    else
+      {
+        struct tlv_mt_ipv6_reachs *mt_reachs;
+        mt_reachs = tlvs_lookup_mt_ipv6_reachs(&lsp->tlv_data, spftree->mtid);
+        if (mt_reachs)
+          ipv6reachs = mt_reachs->list;
+      }
+
     prefix.family = AF_INET6;
-    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach))
+    for (ALL_LIST_ELEMENTS_RO (ipv6reachs, node, ip6reach))
     {
       assert (ip6reach->prefix_len <= IPV6_MAX_BITLEN);
 
       dist = cost + ntohl(ip6reach->metric);
       vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
-        VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
+              VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
       prefix.prefixlen = ip6reach->prefix_len;
       memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
               PSIZE (ip6reach->prefix_len));
       apply_mask (&prefix);
       process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
-                 family, parent);
+                 parent);
     }
   }
 
@@ -824,76 +857,8 @@ lspfragloop:
 }
 
 static int
-isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,
-                            struct isis_lsp *lsp, uint32_t cost,
-                            uint16_t depth, int family,
-                            u_char *root_sysid,
-                            struct isis_vertex *parent)
-{
-  struct listnode *node, *fragnode = NULL;
-  struct is_neigh *is_neigh;
-  struct te_is_neigh *te_is_neigh;
-  enum vertextype vtype;
-  uint32_t dist;
-
-pseudofragloop:
-
-  if (lsp->lsp_header->seq_num == 0)
-    {
-      zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
-                " - do not process");
-      return ISIS_WARNING;
-    }
-
-#ifdef EXTREME_DEBUG
-      zlog_debug ("ISIS-Spf: process_pseudo_lsp %s",
-                  print_sys_hostname(lsp->lsp_header->lsp_id));
-#endif /* EXTREME_DEBUG */
-
-  /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
-
-  if (lsp->tlv_data.is_neighs)
-    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
-      {
-       /* Two way connectivity */
-       if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
-         continue;
-        dist = cost + is_neigh->metrics.metric_default;
-        vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
-          : VTYPE_NONPSEUDO_IS;
-        process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
-            depth + 1, family, parent);
-      }
-  if (lsp->tlv_data.te_is_neighs)
-    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh))
-      {
-       /* Two way connectivity */
-       if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
-         continue;
-        dist = cost + GET_TE_METRIC(te_is_neigh);
-        vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
-          : VTYPE_NONPSEUDO_TE_IS;
-        process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
-            depth + 1, family, parent);
-      }
-
-  if (fragnode == NULL)
-    fragnode = listhead (lsp->lspu.frags);
-  else
-    fragnode = listnextnode (fragnode);
-
-  if (fragnode)
-    {
-      lsp = listgetdata (fragnode);
-      goto pseudofragloop;
-    }
-
-  return ISIS_OK;
-}
-
-static int
-isis_spf_preload_tent (struct isis_spftree *spftree, int level,
-                      int family, u_char *root_sysid,
+isis_spf_preload_tent (struct isis_spftree *spftree,
+                      u_char *root_sysid,
                       struct isis_vertex *parent)
 {
   struct isis_circuit *circuit;
@@ -908,21 +873,25 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
   static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2];
   struct prefix_ipv6 *ipv6;
+  struct isis_circuit_mt_setting *circuit_mt;
 
   for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit))
     {
+      circuit_mt = circuit_lookup_mt_setting(circuit, spftree->mtid);
+      if (circuit_mt && !circuit_mt->enabled)
+       continue;
       if (circuit->state != C_STATE_UP)
        continue;
-      if (!(circuit->is_type & level))
+      if (!(circuit->is_type & spftree->level))
        continue;
-      if (family == AF_INET && !circuit->ip_router)
+      if (spftree->family == AF_INET && !circuit->ip_router)
        continue;
-      if (family == AF_INET6 && !circuit->ipv6_router)
+      if (spftree->family == AF_INET6 && !circuit->ipv6_router)
        continue;
       /* 
        * Add IP(v6) addresses of this circuit
        */
-      if (family == AF_INET)
+      if (spftree->family == AF_INET)
        {
          prefix.family = AF_INET;
           for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
@@ -931,10 +900,10 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
              prefix.prefixlen = ipv4->prefixlen;
               apply_mask (&prefix);
              isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix,
-                                 NULL, 0, family, parent);
+                                 NULL, 0, parent);
            }
        }
-      if (family == AF_INET6)
+      if (spftree->family == AF_INET6)
        {
          prefix.family = AF_INET6;
          for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
@@ -943,7 +912,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
              prefix.u.prefix6 = ipv6->prefix;
               apply_mask (&prefix);
              isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
-                                 &prefix, NULL, 0, family, parent);
+                                 &prefix, NULL, 0, parent);
            }
        }
       if (circuit->circ_type == CIRCUIT_T_BROADCAST)
@@ -952,45 +921,48 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
           * Add the adjacencies
           */
          adj_list = list_new ();
-         adjdb = circuit->u.bc.adjdb[level - 1];
+         adjdb = circuit->u.bc.adjdb[spftree->level - 1];
          isis_adj_build_up_list (adjdb, adj_list);
          if (listcount (adj_list) == 0)
            {
              list_delete (adj_list);
              if (isis->debugs & DEBUG_SPF_EVENTS)
                zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s",
-                           level, circuit->interface->name);
+                           spftree->level, circuit->interface->name);
              continue;
            }
           for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj))
            {
-             if (!speaks (&adj->nlpids, family))
-                 continue;
+             if (!adj_has_mt(adj, spftree->mtid))
+               continue;
+             if (spftree->mtid == ISIS_MT_IPV4_UNICAST && !speaks (&adj->nlpids, spftree->family))
+               continue;
              switch (adj->sys_type)
                {
                case ISIS_SYSTYPE_ES:
-                 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
-                                     circuit->te_metric[level - 1],
-                                     family, parent);
+                 memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
+                 LSP_PSEUDO_ID (lsp_id) = 0;
+                 isis_spf_add_local (spftree, VTYPE_ES, lsp_id, adj,
+                                     circuit->te_metric[spftree->level - 1],
+                                     parent);
                  break;
                case ISIS_SYSTYPE_IS:
                case ISIS_SYSTYPE_L1_IS:
                case ISIS_SYSTYPE_L2_IS:
-                 isis_spf_add_local (spftree,
-                                      spftree->area->oldmetric ?
-                                      VTYPE_NONPSEUDO_IS :
-                                      VTYPE_NONPSEUDO_TE_IS,
-                                      adj->sysid, adj,
-                                      circuit->te_metric[level - 1],
-                                      family, parent);
                  memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
                  LSP_PSEUDO_ID (lsp_id) = 0;
                  LSP_FRAGMENT (lsp_id) = 0;
-                 lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
+                 isis_spf_add_local (spftree,
+                                      spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS
+                                                               : VTYPE_NONPSEUDO_TE_IS,
+                                      lsp_id, adj,
+                                      circuit->te_metric[spftree->level - 1],
+                                      parent);
+                 lsp = lsp_search (lsp_id, spftree->area->lspdb[spftree->level - 1]);
                   if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
                     zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency "
                         "L%d on %s (ID %u)",
-                       rawlspid_print (lsp_id), level,
+                       rawlspid_print (lsp_id), spftree->level,
                        circuit->interface->name, circuit->circuit_id);
                  break;
                case ISIS_SYSTYPE_UNKNOWN:
@@ -1002,7 +974,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
          /*
           * Add the pseudonode 
           */
-         if (level == 1)
+         if (spftree->level == 1)
            memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
          else
            memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
@@ -1011,55 +983,61 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
            {
              if (isis->debugs & DEBUG_SPF_EVENTS)
                zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)",
-                   level, circuit->interface->name, circuit->circuit_id);
+                   spftree->level, circuit->interface->name, circuit->circuit_id);
              continue;
            }
          adj = isis_adj_lookup (lsp_id, adjdb);
          /* if no adj, we are the dis or error */
-         if (!adj && !circuit->u.bc.is_dr[level - 1])
+         if (!adj && !circuit->u.bc.is_dr[spftree->level - 1])
            {
               zlog_warn ("ISIS-Spf: No adjacency found from root "
                   "to L%d DR %s on %s (ID %d)",
-                 level, rawlspid_print (lsp_id),
+                 spftree->level, rawlspid_print (lsp_id),
                  circuit->interface->name, circuit->circuit_id);
               continue;
            }
-         lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
+         lsp = lsp_search (lsp_id, spftree->area->lspdb[spftree->level - 1]);
          if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
            {
              zlog_warn ("ISIS-Spf: No lsp (%p) found from root "
                   "to L%d DR %s on %s (ID %d)",
-                  (void *)lsp, level, rawlspid_print (lsp_id),
+                  (void *)lsp, spftree->level, rawlspid_print (lsp_id),
                   circuit->interface->name, circuit->circuit_id);
               continue;
            }
-         isis_spf_process_pseudo_lsp (spftree, lsp,
-                                       circuit->te_metric[level - 1], 0,
-                                       family, root_sysid, parent);
+         isis_spf_process_lsp (spftree, lsp,
+                               circuit->te_metric[spftree->level - 1], 0,
+                               root_sysid, parent);
        }
       else if (circuit->circ_type == CIRCUIT_T_P2P)
        {
          adj = circuit->u.p2p.neighbor;
          if (!adj)
            continue;
+         if (!adj_has_mt(adj, spftree->mtid))
+           continue;
          switch (adj->sys_type)
            {
            case ISIS_SYSTYPE_ES:
-             isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
-                                 circuit->te_metric[level - 1], family,
+             memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
+             LSP_PSEUDO_ID (lsp_id) = 0;
+             isis_spf_add_local (spftree, VTYPE_ES, lsp_id, adj,
+                                 circuit->te_metric[spftree->level - 1],
                                  parent);
              break;
            case ISIS_SYSTYPE_IS:
            case ISIS_SYSTYPE_L1_IS:
            case ISIS_SYSTYPE_L2_IS:
-             if (speaks (&adj->nlpids, family))
+             memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
+             LSP_PSEUDO_ID (lsp_id) = 0;
+             LSP_FRAGMENT (lsp_id) = 0;
+             if (spftree->mtid != ISIS_MT_IPV4_UNICAST || speaks (&adj->nlpids, spftree->family))
                isis_spf_add_local (spftree,
-                                   spftree->area->oldmetric ?
-                                    VTYPE_NONPSEUDO_IS :
-                                   VTYPE_NONPSEUDO_TE_IS,
-                                    adj->sysid,
-                                   adj, circuit->te_metric[level - 1],
-                                   family, parent);
+                                   spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS
+                                                            : VTYPE_NONPSEUDO_TE_IS,
+                                   lsp_id,
+                                   adj, circuit->te_metric[spftree->level - 1],
+                                   parent);
              break;
            case ISIS_SYSTYPE_UNKNOWN:
            default:
@@ -1086,8 +1064,7 @@ isis_spf_preload_tent (struct isis_spftree *spftree, int level,
  * now we just put the child pointer(s) in place
  */
 static void
-add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
-             int level)
+add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex)
 {
   char buff[PREFIX2STR_BUFFER];
 
@@ -1102,11 +1079,11 @@ add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
              vertex->depth, vertex->d_N);
 #endif /* EXTREME_DEBUG */
 
-  if (vertex->type > VTYPE_ES)
+  if (VTYPE_IP(vertex->type))
     {
       if (listcount (vertex->Adj_N) > 0)
        isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N,
-                          vertex->depth, vertex->Adj_N, spftree->area, level);
+                          vertex->depth, vertex->Adj_N, spftree->area, spftree->level);
       else if (isis->debugs & DEBUG_SPF_EVENTS)
        zlog_debug ("ISIS-Spf: no adjacencies do not install route for "
                     "%s depth %d dist %d", vid2string (vertex, buff, sizeof (buff)),
@@ -1117,12 +1094,16 @@ add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
 }
 
 static void
-init_spt (struct isis_spftree *spftree)
+init_spt (struct isis_spftree *spftree, int mtid, int level, int family)
 {
   spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del;
   list_delete_all_node (spftree->tents);
   list_delete_all_node (spftree->paths);
   spftree->tents->del = spftree->paths->del = NULL;
+
+  spftree->mtid = mtid;
+  spftree->level = level;
+  spftree->family = family;
   return;
 }
 
@@ -1139,6 +1120,7 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
   struct route_table *table = NULL;
   struct timeval time_now;
   unsigned long long start_time, end_time;
+  uint16_t mtid;
 
   /* Get time that can't roll backwards. */
   monotime(&time_now);
@@ -1160,14 +1142,20 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
 
   isis_route_invalidate_table (area, table);
 
+  /* We only support ipv4-unicast and ipv6-unicast as topologies for now */
+  if (family == AF_INET6)
+    mtid = isis_area_ipv6_topology(area);
+  else
+    mtid = ISIS_MT_IPV4_UNICAST;
+
   /*
    * C.2.5 Step 0
    */
-  init_spt (spftree);
+  init_spt (spftree, mtid, level, family);
   /*              a) */
-  root_vertex = isis_spf_add_root (spftree, level, sysid);
+  root_vertex = isis_spf_add_root (spftree, sysid);
   /*              b) */
-  retval = isis_spf_preload_tent (spftree, level, family, sysid, root_vertex);
+  retval = isis_spf_preload_tent (spftree, sysid, root_vertex);
   if (retval != ISIS_OK)
     {
       zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid));
@@ -1196,37 +1184,22 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
 
       /* Remove from tent list and add to paths list */
       list_delete_node (spftree->tents, node);
-      add_to_paths (spftree, vertex, level);
-      switch (vertex->type)
+      add_to_paths (spftree, vertex);
+      if (VTYPE_IS(vertex->type))
         {
-       case VTYPE_PSEUDO_IS:
-       case VTYPE_NONPSEUDO_IS:
-       case VTYPE_PSEUDO_TE_IS:
-       case VTYPE_NONPSEUDO_TE_IS:
          memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
          LSP_FRAGMENT (lsp_id) = 0;
          lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
          if (lsp && lsp->lsp_header->rem_lifetime != 0)
            {
-             if (LSP_PSEUDO_ID (lsp_id))
-               {
-                 isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
-                                              vertex->depth, family, sysid,
-                                              vertex);
-               }
-             else
-               {
-                 isis_spf_process_lsp (spftree, lsp, vertex->d_N,
-                                       vertex->depth, family, sysid, vertex);
-               }
+             isis_spf_process_lsp (spftree, lsp, vertex->d_N,
+                                   vertex->depth, sysid, vertex);
            }
          else
            {
              zlog_warn ("ISIS-Spf: No LSP found for %s",
                         rawlspid_print (lsp_id));
            }
-         break;
-       default:;
        }
     }
 
@@ -1243,17 +1216,17 @@ out:
 }
 
 static int
-isis_run_spf_l1 (struct thread *thread)
+isis_run_spf_cb (struct thread *thread)
 {
-  struct isis_area *area;
+  struct isis_spf_run *run = THREAD_ARG (thread);
+  struct isis_area *area = run->area;
+  int level = run->level;
   int retval = ISIS_OK;
 
-  area = THREAD_ARG (thread);
-  assert (area);
+  XFREE(MTYPE_ISIS_SPF_RUN, run);
+  area->spf_timer[level - 1] = NULL;
 
-  area->spf_timer[0] = NULL;
-
-  if (!(area->is_type & IS_LEVEL_1))
+  if (!(area->is_type & level))
     {
       if (isis->debugs & DEBUG_SPF_EVENTS)
        zlog_warn ("ISIS-SPF (%s) area does not share level",
@@ -1262,43 +1235,26 @@ isis_run_spf_l1 (struct thread *thread)
     }
 
   if (isis->debugs & DEBUG_SPF_EVENTS)
-    zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
+    zlog_debug ("ISIS-Spf (%s) L%d SPF needed, periodic SPF",
+                area->area_tag, level);
 
   if (area->ip_circuits)
-    retval = isis_run_spf (area, 1, AF_INET, isis->sysid);
+    retval = isis_run_spf (area, level, AF_INET, isis->sysid);
   if (area->ipv6_circuits)
-    retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
+    retval = isis_run_spf (area, level, AF_INET6, isis->sysid);
 
   return retval;
 }
 
-static int
-isis_run_spf_l2 (struct thread *thread)
+static struct isis_spf_run*
+isis_run_spf_arg(struct isis_area *area, int level)
 {
-  struct isis_area *area;
-  int retval = ISIS_OK;
-
-  area = THREAD_ARG (thread);
-  assert (area);
+  struct isis_spf_run *run = XMALLOC(MTYPE_ISIS_SPF_RUN, sizeof(*run));
 
-  area->spf_timer[1] = NULL;
+  run->area = area;
+  run->level = level;
 
-  if (!(area->is_type & IS_LEVEL_2))
-    {
-      if (isis->debugs & DEBUG_SPF_EVENTS)
-       zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
-      return ISIS_WARNING;
-    }
-
-  if (isis->debugs & DEBUG_SPF_EVENTS)
-    zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
-
-  if (area->ip_circuits)
-    retval = isis_run_spf (area, 2, AF_INET, isis->sysid);
-  if (area->ipv6_circuits)
-    retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
-
-  return retval;
+  return run;
 }
 
 int
@@ -1323,16 +1279,9 @@ isis_spf_schedule (struct isis_area *area, int level)
       if (area->spf_timer[level - 1])
         return ISIS_OK;
 
-      if (level == 1)
-        {
-          THREAD_TIMER_MSEC_ON(master, area->spf_timer[0],
-                               isis_run_spf_l1, area, delay);
-        }
-      else
-        {
-          THREAD_TIMER_MSEC_ON(master, area->spf_timer[1],
-                               isis_run_spf_l2, area, delay);
-        }
+      THREAD_TIMER_MSEC_ON(master, area->spf_timer[level-1],
+                           isis_run_spf_cb, isis_run_spf_arg(area, level),
+                           delay);
       return ISIS_OK;
     }
 
@@ -1352,12 +1301,9 @@ isis_spf_schedule (struct isis_area *area, int level)
       return retval;
     }
 
-  if (level == 1)
-    THREAD_TIMER_ON (master, area->spf_timer[0], isis_run_spf_l1, area,
-                     area->min_spf_interval[0] - diff);
-  else
-    THREAD_TIMER_ON (master, area->spf_timer[1], isis_run_spf_l2, area,
-                     area->min_spf_interval[1] - diff);
+  THREAD_TIMER_ON (master, area->spf_timer[level-1],
+                   isis_run_spf_cb, isis_run_spf_arg(area, level),
+                   area->min_spf_interval[level-1] - diff);
 
   if (isis->debugs & DEBUG_SPF_EVENTS)
     zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
@@ -1427,14 +1373,23 @@ isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid)
 
 DEFUN (show_isis_topology,
        show_isis_topology_cmd,
-       "show isis topology",
+       "show isis topology [<level-1|level-2>]",
        SHOW_STR
        "IS-IS information\n"
-       "IS-IS paths to Intermediate Systems\n")
+       "IS-IS paths to Intermediate Systems\n"
+       "Paths to all level-1 routers in the area\n"
+       "Paths to all level-2 routers in the domain\n")
 {
+  int levels;
   struct listnode *node;
   struct isis_area *area;
-  int level;
+
+  if (argc < 4)
+    levels = ISIS_LEVEL1|ISIS_LEVEL2;
+  else if (!strcmp(argv[3]->arg, "level-1"))
+    levels = ISIS_LEVEL1;
+  else
+    levels = ISIS_LEVEL2;
 
   if (!isis->area_list || isis->area_list->count == 0)
     return CMD_SUCCESS;
@@ -1444,23 +1399,26 @@ DEFUN (show_isis_topology,
       vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
               VTY_NEWLINE);
 
-      for (level = 0; level < ISIS_LEVELS; level++)
+      for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
        {
-         if (area->ip_circuits > 0 && area->spftree[level]
-             && area->spftree[level]->paths->count > 0)
+         if ((level & levels) == 0)
+           continue;
+
+         if (area->ip_circuits > 0 && area->spftree[level-1]
+             && area->spftree[level-1]->paths->count > 0)
            {
              vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s",
-                      level + 1, VTY_NEWLINE);
-             isis_print_paths (vty, area->spftree[level]->paths, isis->sysid);
+                      level, VTY_NEWLINE);
+             isis_print_paths (vty, area->spftree[level-1]->paths, isis->sysid);
              vty_out (vty, "%s", VTY_NEWLINE);
            }
-         if (area->ipv6_circuits > 0 && area->spftree6[level]
-             && area->spftree6[level]->paths->count > 0)
+         if (area->ipv6_circuits > 0 && area->spftree6[level-1]
+             && area->spftree6[level-1]->paths->count > 0)
            {
              vty_out (vty,
                       "IS-IS paths to level-%d routers that speak IPv6%s",
-                      level + 1, VTY_NEWLINE);
-             isis_print_paths (vty, area->spftree6[level]->paths, isis->sysid);
+                      level, VTY_NEWLINE);
+             isis_print_paths (vty, area->spftree6[level-1]->paths, isis->sysid);
              vty_out (vty, "%s", VTY_NEWLINE);
            }
        }
@@ -1471,92 +1429,8 @@ DEFUN (show_isis_topology,
   return CMD_SUCCESS;
 }
 
-DEFUN (show_isis_topology_l1,
-       show_isis_topology_l1_cmd,
-       "show isis topology level-1",
-       SHOW_STR
-       "IS-IS information\n"
-       "IS-IS paths to Intermediate Systems\n"
-       "Paths to all level-1 routers in the area\n")
-{
-  struct listnode *node;
-  struct isis_area *area;
-
-  if (!isis->area_list || isis->area_list->count == 0)
-    return CMD_SUCCESS;
-
-  for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
-    {
-      vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
-              VTY_NEWLINE);
-
-      if (area->ip_circuits > 0 && area->spftree[0]
-         && area->spftree[0]->paths->count > 0)
-       {
-         vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
-                  VTY_NEWLINE);
-         isis_print_paths (vty, area->spftree[0]->paths, isis->sysid);
-         vty_out (vty, "%s", VTY_NEWLINE);
-       }
-      if (area->ipv6_circuits > 0 && area->spftree6[0]
-         && area->spftree6[0]->paths->count > 0)
-       {
-         vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
-                  VTY_NEWLINE);
-         isis_print_paths (vty, area->spftree6[0]->paths, isis->sysid);
-         vty_out (vty, "%s", VTY_NEWLINE);
-       }
-      vty_out (vty, "%s", VTY_NEWLINE);
-    }
-
-  return CMD_SUCCESS;
-}
-
-DEFUN (show_isis_topology_l2,
-       show_isis_topology_l2_cmd,
-       "show isis topology level-2",
-       SHOW_STR
-       "IS-IS information\n"
-       "IS-IS paths to Intermediate Systems\n"
-       "Paths to all level-2 routers in the domain\n")
-{
-  struct listnode *node;
-  struct isis_area *area;
-
-  if (!isis->area_list || isis->area_list->count == 0)
-    return CMD_SUCCESS;
-
-  for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
-    {
-      vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
-              VTY_NEWLINE);
-
-      if (area->ip_circuits > 0 && area->spftree[1]
-         && area->spftree[1]->paths->count > 0)
-       {
-         vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
-                  VTY_NEWLINE);
-         isis_print_paths (vty, area->spftree[1]->paths, isis->sysid);
-         vty_out (vty, "%s", VTY_NEWLINE);
-       }
-      if (area->ipv6_circuits > 0 && area->spftree6[1]
-         && area->spftree6[1]->paths->count > 0)
-       {
-         vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
-                  VTY_NEWLINE);
-         isis_print_paths (vty, area->spftree6[1]->paths, isis->sysid);
-         vty_out (vty, "%s", VTY_NEWLINE);
-       }
-      vty_out (vty, "%s", VTY_NEWLINE);
-    }
-
-  return CMD_SUCCESS;
-}
-
 void
 isis_spf_cmds_init ()
 {
   install_element (VIEW_NODE, &show_isis_topology_cmd);
-  install_element (VIEW_NODE, &show_isis_topology_l1_cmd);
-  install_element (VIEW_NODE, &show_isis_topology_l2_cmd);
 }
index fb534542d05dabde70039e96a2bab9bbe0d5f12a..9f06dbb602bdde9df1f7be6936ae65bf05d2cf3d 100644 (file)
@@ -38,6 +38,10 @@ enum vertextype
   VTYPE_IP6REACH_EXTERNAL
 };
 
+#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS)
+#define VTYPE_ES(t) ((t) == VTYPE_ES)
+#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL)
+
 /*
  * Triple <N, d(N), {Adj(N)}> 
  */
@@ -66,12 +70,14 @@ struct isis_spftree
   unsigned int runcount;        /* number of runs since uptime */
   time_t last_run_timestamp;    /* last run timestamp for scheduling */
   time_t last_run_duration;     /* last run duration in msec */
+
+  uint16_t mtid;
+  int family;
+  int level;
 };
 
 struct isis_spftree * isis_spftree_new (struct isis_area *area);
 void isis_spftree_del (struct isis_spftree *spftree);
-void isis_spftree_adj_del (struct isis_spftree *spftree,
-                           struct isis_adjacency *adj);
 void spftree_area_init (struct isis_area *area);
 void spftree_area_del (struct isis_area *area);
 void spftree_area_adj_del (struct isis_area *area,
index 4192fff9a852e79cbec843c4bcf3cde5b72822c7..b033e35a2e105356b84796fe1e1971298fc1ae37 100644 (file)
@@ -43,6 +43,7 @@
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
 
 void
 free_tlv (void *val)
@@ -61,10 +62,14 @@ free_tlvs (struct tlvs *tlvs)
 {
   if (tlvs->area_addrs)
     list_delete (tlvs->area_addrs);
+  if (tlvs->mt_router_info)
+    list_delete (tlvs->mt_router_info);
   if (tlvs->is_neighs)
     list_delete (tlvs->is_neighs);
   if (tlvs->te_is_neighs)
     list_delete (tlvs->te_is_neighs);
+  if (tlvs->mt_is_neighs)
+    list_delete (tlvs->mt_is_neighs);
   if (tlvs->es_neighs)
     list_delete (tlvs->es_neighs);
   if (tlvs->lsp_entries)
@@ -81,16 +86,293 @@ free_tlvs (struct tlvs *tlvs)
     list_delete (tlvs->ipv4_ext_reachs);
   if (tlvs->te_ipv4_reachs)
     list_delete (tlvs->te_ipv4_reachs);
+  if (tlvs->mt_ipv4_reachs)
+    list_delete (tlvs->mt_ipv4_reachs);
   if (tlvs->ipv6_addrs)
     list_delete (tlvs->ipv6_addrs);
   if (tlvs->ipv6_reachs)
     list_delete (tlvs->ipv6_reachs);
+  if (tlvs->mt_ipv6_reachs)
+    list_delete (tlvs->mt_ipv6_reachs);
 
   memset (tlvs, 0, sizeof (struct tlvs));
 
   return;
 }
 
+static int
+parse_mtid(uint16_t *mtid, bool read_mtid,
+           unsigned int *length, u_char **pnt)
+{
+  if (!read_mtid)
+    {
+      *mtid = ISIS_MT_IPV4_UNICAST;
+      return ISIS_OK;
+    }
+
+  uint16_t mtid_buf;
+
+  if (*length < sizeof(mtid_buf))
+    {
+      zlog_warn("ISIS-TLV: mt tlv too short to contain MT id");
+      return ISIS_WARNING;
+    }
+
+  memcpy(&mtid_buf, *pnt, sizeof(mtid_buf));
+  *pnt += sizeof(mtid_buf);
+  *length -= sizeof(mtid_buf);
+
+  *mtid = ntohs(mtid_buf) & ISIS_MT_MASK;
+  return ISIS_OK;
+}
+
+static int
+parse_mt_is_neighs(struct tlvs *tlvs, bool read_mtid,
+                   unsigned int length, u_char *pnt)
+{
+  struct list *neigh_list;
+  uint16_t mtid;
+  int rv;
+
+  rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
+  if (rv != ISIS_OK)
+    return rv;
+
+  if (mtid == ISIS_MT_IPV4_UNICAST)
+    {
+      if (!tlvs->te_is_neighs)
+        {
+          tlvs->te_is_neighs = list_new();
+          tlvs->te_is_neighs->del = free_tlv;
+        }
+      neigh_list = tlvs->te_is_neighs;
+    }
+  else
+    {
+      struct tlv_mt_neighbors *neighbors;
+
+      neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
+      neighbors->list->del = free_tlv;
+      neigh_list = neighbors->list;
+    }
+
+  while (length >= IS_NEIGHBOURS_LEN)
+    {
+      struct te_is_neigh *neigh = XCALLOC(MTYPE_ISIS_TLV, sizeof(*neigh));
+
+      memcpy(neigh, pnt, IS_NEIGHBOURS_LEN);
+      pnt += IS_NEIGHBOURS_LEN;
+      length -= IS_NEIGHBOURS_LEN;
+
+      if (neigh->sub_tlvs_length > length)
+        {
+          zlog_warn("ISIS-TLV: neighbor subtlv length exceeds TLV size");
+          XFREE(MTYPE_ISIS_TLV, neigh);
+          return ISIS_WARNING;
+        }
+
+      memcpy(neigh->sub_tlvs, pnt, neigh->sub_tlvs_length);
+      pnt += neigh->sub_tlvs_length;
+      length -= neigh->sub_tlvs_length;
+
+      listnode_add(neigh_list, neigh);
+    }
+
+  if (length)
+    {
+      zlog_warn("ISIS-TLV: TE/MT neighor TLV has trailing data");
+      return ISIS_WARNING;
+    }
+
+  return ISIS_OK;
+}
+
+static int
+parse_mt_ipv4_reachs(struct tlvs *tlvs, bool read_mtid,
+                     unsigned int length, u_char *pnt)
+{
+  struct list *reach_list;
+  uint16_t mtid;
+  int rv;
+
+  rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
+  if (rv != ISIS_OK)
+    return rv;
+
+  if (mtid == ISIS_MT_IPV4_UNICAST)
+    {
+      if (!tlvs->te_ipv4_reachs)
+        {
+          tlvs->te_ipv4_reachs = list_new();
+          tlvs->te_ipv4_reachs->del = free_tlv;
+        }
+      reach_list = tlvs->te_ipv4_reachs;
+    }
+  else
+    {
+      struct tlv_mt_ipv4_reachs *reachs;
+
+      reachs = tlvs_get_mt_ipv4_reachs(tlvs, mtid);
+      reachs->list->del = free_tlv;
+      reach_list = reachs->list;
+    }
+
+  while (length >= 5) /* Metric + Control */
+    {
+      struct te_ipv4_reachability *reach = XCALLOC(MTYPE_ISIS_TLV, TE_IPV4_REACH_LEN);
+
+      memcpy(reach, pnt, 5); /* Metric + Control */
+      pnt += 5;
+      length -= 5;
+
+      unsigned char prefixlen = reach->control & 0x3F;
+
+      if (prefixlen > IPV4_MAX_BITLEN)
+        {
+          zlog_warn("ISIS-TLV: invalid IPv4 extended reachability prefix length %d", prefixlen);
+          XFREE(MTYPE_ISIS_TLV, reach);
+          return ISIS_WARNING;
+        }
+
+      if (length < (unsigned int)PSIZE(prefixlen))
+        {
+          zlog_warn("ISIS-TLV: invalid IPv4 extended reachability prefix too long for tlv");
+          XFREE(MTYPE_ISIS_TLV, reach);
+          return ISIS_WARNING;
+        }
+
+      memcpy(&reach->prefix_start, pnt, PSIZE(prefixlen));
+      pnt += PSIZE(prefixlen);
+      length -= PSIZE(prefixlen);
+
+      if (reach->control & TE_IPV4_HAS_SUBTLV)
+        {
+          if (length < 1)
+            {
+              zlog_warn("ISIS-TLV: invalid IPv4 extended reachability SubTLV missing");
+              XFREE(MTYPE_ISIS_TLV, reach);
+              return ISIS_WARNING;
+            }
+
+          u_char subtlv_len = *pnt;
+          pnt++;
+          length--;
+
+          if (length < subtlv_len)
+            {
+              zlog_warn("ISIS-TLV: invalid IPv4 extended reachability SubTLVs have oversize");
+              XFREE(MTYPE_ISIS_TLV, reach);
+              return ISIS_WARNING;
+            }
+
+          /* Skip Sub-TLVs for now */
+          pnt += subtlv_len;
+          length -= subtlv_len;
+        }
+      listnode_add(reach_list, reach);
+    }
+
+  if (length)
+    {
+      zlog_warn("ISIS-TLV: TE/MT ipv4 reachability TLV has trailing data");
+      return ISIS_WARNING;
+    }
+
+  return ISIS_OK;
+}
+
+static int
+parse_mt_ipv6_reachs(struct tlvs *tlvs, bool read_mtid,
+                     unsigned int length, u_char *pnt)
+{
+  struct list *reach_list;
+  uint16_t mtid;
+  int rv;
+
+  rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
+  if (rv != ISIS_OK)
+    return rv;
+
+  if (mtid == ISIS_MT_IPV4_UNICAST)
+    {
+      if (!tlvs->ipv6_reachs)
+        {
+          tlvs->ipv6_reachs = list_new();
+          tlvs->ipv6_reachs->del = free_tlv;
+        }
+      reach_list = tlvs->ipv6_reachs;
+    }
+  else
+    {
+      struct tlv_mt_ipv6_reachs *reachs;
+
+      reachs = tlvs_get_mt_ipv6_reachs(tlvs, mtid);
+      reachs->list->del = free_tlv;
+      reach_list = reachs->list;
+    }
+
+  while (length >= 6) /* Metric + Control + Prefixlen */
+    {
+      struct ipv6_reachability *reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*reach));
+
+      memcpy(reach, pnt, 6); /* Metric + Control + Prefixlen */
+      pnt += 6;
+      length -= 6;
+
+      if (reach->prefix_len > IPV6_MAX_BITLEN)
+        {
+          zlog_warn("ISIS-TLV: invalid IPv6 reachability prefix length %d", reach->prefix_len);
+          XFREE(MTYPE_ISIS_TLV, reach);
+          return ISIS_WARNING;
+        }
+
+      if (length < (unsigned int)PSIZE(reach->prefix_len))
+        {
+          zlog_warn("ISIS-TLV: invalid IPv6 reachability prefix too long for tlv");
+          XFREE(MTYPE_ISIS_TLV, reach);
+          return ISIS_WARNING;
+        }
+
+      memcpy(&reach->prefix, pnt, PSIZE(reach->prefix_len));
+      pnt += PSIZE(reach->prefix_len);
+      length -= PSIZE(reach->prefix_len);
+
+      if (reach->control_info & CTRL_INFO_SUBTLVS)
+        {
+          if (length < 1)
+            {
+              zlog_warn("ISIS-TLV: invalid IPv6 reachability SubTLV missing");
+              XFREE(MTYPE_ISIS_TLV, reach);
+              return ISIS_WARNING;
+            }
+
+          u_char subtlv_len = *pnt;
+          pnt++;
+          length--;
+
+          if (length < subtlv_len)
+            {
+              zlog_warn("ISIS-TLV: invalid IPv6 reachability SubTLVs have oversize");
+              XFREE(MTYPE_ISIS_TLV, reach);
+              return ISIS_WARNING;
+            }
+
+          /* Skip Sub-TLVs for now */
+          pnt += subtlv_len;
+          length -= subtlv_len;
+        }
+      listnode_add(reach_list, reach);
+    }
+
+  if (length)
+    {
+      zlog_warn("ISIS-TLV: (MT) IPv6 reachability TLV has trailing data");
+      return ISIS_WARNING;
+    }
+
+  return ISIS_OK;
+}
+
 /*
  * Parses the tlvs found in the variant length part of the PDU.
  * Caller tells with flags in "expected" which TLV's it is interested in.
@@ -103,17 +385,13 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
   struct lan_neigh *lan_nei;
   struct area_addr *area_addr;
   struct is_neigh *is_nei;
-  struct te_is_neigh *te_is_nei;
   struct es_neigh *es_nei;
   struct lsp_entry *lsp_entry;
   struct in_addr *ipv4_addr;
   struct ipv4_reachability *ipv4_reach;
-  struct te_ipv4_reachability *te_ipv4_reach;
   struct in6_addr *ipv6_addr;
-  struct ipv6_reachability *ipv6_reach;
-  int prefix_octets;
   int value_len, retval = ISIS_OK;
-  u_char *start = stream, *pnt = stream, *endpnt;
+  u_char *start = stream, *pnt = stream;
 
   *found = 0;
   memset (tlvs, 0, sizeof (struct tlvs));
@@ -207,54 +485,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
          break;
 
        case TE_IS_NEIGHBOURS:
-         /* +-------+-------+-------+-------+-------+-------+-------+-------+
-          * |                        Neighbour ID                           | 7
-          * +---------------------------------------------------------------+
-          * |                        TE Metric                              | 3
-          * +---------------------------------------------------------------+
-          * |                        SubTLVs Length                         | 1
-          * +---------------------------------------------------------------+
-          * :                                                               :
-          */
          *found |= TLVFLAG_TE_IS_NEIGHS;
 #ifdef EXTREME_TLV_DEBUG
          zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d",
                     areatag, length);
 #endif /* EXTREME_TLV_DEBUG */
          if (TLVFLAG_TE_IS_NEIGHS & *expected)
-           {
-             while (length > value_len)
-               {
-                 te_is_nei = (struct te_is_neigh *) pnt;
-                 value_len += IS_NEIGHBOURS_LEN;
-                 pnt += IS_NEIGHBOURS_LEN;
-                  /* FIXME - subtlvs are handled here, for now we skip */
-                 /* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */
-                 /* So, it must be copied in a new te_is_neigh structure        */
-                 /* rather than just initialize pointer to the original LSP PDU */
-                 /* to avoid consider the rest of lspdu as subTLVs or buffer overflow */
-                 if (IS_MPLS_TE(isisMplsTE))
-                   {
-                     struct te_is_neigh *new = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh));
-                     memcpy(new->neigh_id, te_is_nei->neigh_id, ISIS_SYS_ID_LEN + 1);
-                     memcpy(new->te_metric, te_is_nei->te_metric, 3);
-                     new->sub_tlvs_length = te_is_nei->sub_tlvs_length;
-                     memcpy(new->sub_tlvs, pnt, te_is_nei->sub_tlvs_length);
-                      te_is_nei = new;
-                    }
-                 /* Skip SUB TLVs payload */
-                 value_len += te_is_nei->sub_tlvs_length;
-                 pnt += te_is_nei->sub_tlvs_length;
-
-                 if (!tlvs->te_is_neighs)
-                   tlvs->te_is_neighs = list_new ();
-                 listnode_add (tlvs->te_is_neighs, te_is_nei);
-               }
-           }
-         else
-           {
-             pnt += length;
-           }
+           retval = parse_mt_is_neighs(tlvs, false, length, pnt);
+         pnt += length;
+         break;
+
+       case MT_IS_NEIGHBOURS:
+         *found |= TLVFLAG_TE_IS_NEIGHS;
+#ifdef EXTREME_TLV_DEBUG
+         zlog_debug ("ISIS-TLV (%s): MT IS Neighbours length %d",
+                     areatag, length);
+#endif
+         if (TLVFLAG_TE_IS_NEIGHS & *expected)
+           retval = parse_mt_is_neighs(tlvs, true, length, pnt);
+         pnt += length;
          break;
 
        case ES_NEIGHBOURS:
@@ -577,71 +826,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
          break;
 
        case TE_IPV4_REACHABILITY:
-         /* +-------+-------+-------+-------+-------+-------+-------+-------+
-          * |                        TE Metric                              | 4
-          * +-------+-------+-------+-------+-------+-------+-------+-------+
-          * |  U/D  | sTLV? |               Prefix Mask Len                 | 1
-          * +-------+-------+-------+-------+-------+-------+-------+-------+
-          * |                           Prefix                              | 0-4
-          * +---------------------------------------------------------------+
-          * |                         sub tlvs                              |
-          * +---------------------------------------------------------------+
-          * :                                                               :
-          */
          *found |= TLVFLAG_TE_IPV4_REACHABILITY;
 #ifdef EXTREME_TLV_DEBUG
          zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
-                     areatag, length);
+                     areatag, length);
 #endif /* EXTREME_TLV_DEBUG */
-         endpnt = pnt + length;
          if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
-           {
-             while (length > value_len)
-               {
-                 te_ipv4_reach = (struct te_ipv4_reachability *) pnt;
-                 if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN)
-                   {
-                     zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach"
-                                "ability prefix length %d", areatag,
-                                te_ipv4_reach->control & 0x3F);
-                     retval = ISIS_WARNING;
-                     break;
-                   }
-                 if (!tlvs->te_ipv4_reachs)
-                   tlvs->te_ipv4_reachs = list_new ();
-                 listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
-
-                 /* Metric + Control-Byte + Prefix */
-                 unsigned int entry_len = 5 + PSIZE(te_ipv4_reach->control & 0x3F);
-                 value_len += entry_len;
-                 pnt += entry_len;
-
-                 if (te_ipv4_reach->control & TE_IPV4_HAS_SUBTLV)
-                   {
-                     if (length <= value_len)
-                       {
-                         zlog_warn("ISIS-TLV (%s): invalid IPv4 extended reachability SubTLV missing",
-                                   areatag);
-                         retval = ISIS_WARNING;
-                         break;
-                       }
-                     u_char subtlv_len = *pnt;
-                     value_len += subtlv_len + 1;
-                     pnt += subtlv_len + 1;
-                     if (length < value_len)
-                       {
-                         zlog_warn("ISIS-TLV (%s): invalid IPv4 extended reachability SubTLVs have oversize",
-                                   areatag);
-                         retval = ISIS_WARNING;
-                         break;
-                       }
-                   }
-               }
-           }
-
-         pnt = endpnt;
+           retval = parse_mt_ipv4_reachs(tlvs, false, length, pnt);
+         pnt += length;
+         break;
+       case MT_IPV4_REACHABILITY:
+         *found |= TLVFLAG_TE_IPV4_REACHABILITY;
+#ifdef EXTREME_TLV_DEBUG
+         zlog_debug ("ISIS-TLV (%s): IPv4 MT Reachability length %d",
+                     areatag, length);
+#endif /* EXTREME_TLV_DEBUG */
+         if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
+           retval = parse_mt_ipv4_reachs(tlvs, true, length, pnt);
+         pnt += length;
          break;
-
        case IPV6_ADDR:
          /* +-------+-------+-------+-------+-------+-------+-------+-------+
           * +                 IP version 6 address                          + 16
@@ -672,67 +875,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
          break;
 
        case IPV6_REACHABILITY:
-         /* +-------+-------+-------+-------+-------+-------+-------+-------+
-          * |                 Default Metric                                | 4 
-          * +-------+-------+-------+-------+-------+-------+-------+-------+
-          * |                        Control Informantion                   |
-          * +---------------------------------------------------------------+
-          * |                        IPv6 Prefix Length                     |--+
-          * +---------------------------------------------------------------+  |
-          * |                        IPv6 Prefix                            |<-+
-          * +---------------------------------------------------------------+
-          */
          *found |= TLVFLAG_IPV6_REACHABILITY;
-         endpnt = pnt + length;
-
+#ifdef EXTREME_TLV_DEBUG
+         zlog_debug ("ISIS-TLV (%s): IPv6 Reachability length %d",
+                     areatag, length);
+#endif /* EXTREME_TLV_DEBUG */
          if (*expected & TLVFLAG_IPV6_REACHABILITY)
-           {
-             while (length > value_len)
-               {
-                 ipv6_reach = (struct ipv6_reachability *) pnt;
-                 if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN)
-                   {
-                     zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach"
-                                "ability prefix length %d", areatag,
-                                ipv6_reach->prefix_len);
-                     retval = ISIS_WARNING;
-                     break;
-                   }
-
-                 prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
-                 value_len += prefix_octets + 6;
-                 pnt += prefix_octets + 6;
-
-                 if (ipv6_reach->control_info & CTRL_INFO_SUBTLVS)
-                   {
-                     if (length <= value_len)
-                       {
-                         zlog_warn("ISIS-TLV (%s): invalid IPv6 extended reachability SubTLV missing",
-                                   areatag);
-                         retval = ISIS_WARNING;
-                         break;
-                       }
-                     u_char subtlv_len = *pnt;
-                     value_len += subtlv_len + 1;
-                     pnt += subtlv_len + 1;
-                     if (length < value_len)
-                       {
-                         zlog_warn("ISIS-TLV (%s): invalid IPv6 extended reachability SubTLVs have oversize",
-                                   areatag);
-                         retval = ISIS_WARNING;
-                         break;
-                       }
-                   }
-                 /* FIXME: sub-tlvs */
-                 if (!tlvs->ipv6_reachs)
-                   tlvs->ipv6_reachs = list_new ();
-                 listnode_add (tlvs->ipv6_reachs, ipv6_reach);
-               }
-           }
-
-         pnt = endpnt;
+           retval = parse_mt_ipv6_reachs(tlvs, false, length, pnt);
+         pnt += length;
+         break;
+       case MT_IPV6_REACHABILITY:
+         *found |= TLVFLAG_IPV6_REACHABILITY;
+#ifdef EXTREME_TLV_DEBUG
+         zlog_debug ("ISIS-TLV (%s): IPv6 Reachability length %d",
+                     areatag, length);
+#endif /* EXTREME_TLV_DEBUG */
+         if (*expected & TLVFLAG_IPV6_REACHABILITY)
+           retval = parse_mt_ipv6_reachs(tlvs, true, length, pnt);
+         pnt += length;
          break;
-
        case WAY3_HELLO:
          /* +---------------------------------------------------------------+
           * |                  Adjacency state                              | 1
@@ -786,6 +947,42 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
          pnt += length;
          break;
 
+       case MT_ROUTER_INFORMATION:
+         *found |= TLVFLAG_MT_ROUTER_INFORMATION;
+         if (*expected & TLVFLAG_MT_ROUTER_INFORMATION)
+           {
+             if (!tlvs->mt_router_info)
+               {
+                 tlvs->mt_router_info = list_new();
+                 tlvs->mt_router_info->del = free_tlv;
+               }
+             while (length > value_len)
+               {
+                 uint16_t mt_info;
+                 struct mt_router_info *info;
+
+                 if (value_len + sizeof(mt_info) > length) {
+                   zlog_warn("ISIS-TLV (%s): TLV 229 is truncated.", areatag);
+                   pnt += length - value_len;
+                   break;
+                 }
+
+                 memcpy(&mt_info, pnt, sizeof(mt_info));
+                 pnt += sizeof(mt_info);
+                 value_len += sizeof(mt_info);
+
+                 mt_info = ntohs(mt_info);
+                 info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
+                 info->mtid = mt_info & ISIS_MT_MASK;
+                 info->overload = mt_info & ISIS_MT_OL_MASK;
+                 listnode_add(tlvs->mt_router_info, info);
+               }
+           }
+         else
+           {
+             pnt += length;
+           }
+         break;
        default:
          zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
                     areatag, type, length);
@@ -825,6 +1022,31 @@ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
   return ISIS_OK;
 }
 
+int
+tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream)
+{
+  struct listnode *node;
+  struct mt_router_info *info;
+
+  uint16_t value[127];
+  uint16_t *pos = value;
+
+  for (ALL_LIST_ELEMENTS_RO(mt_router_info, node, info))
+    {
+      uint16_t mt_info;
+
+      mt_info = info->mtid;
+      if (info->overload)
+        mt_info |= ISIS_MT_OL_MASK;
+
+      *pos = htons(mt_info);
+      pos++;
+    }
+
+  return add_tlv(MT_ROUTER_INFORMATION, (pos - value) * sizeof(*pos),
+                 (u_char*)value, stream);
+}
+
 int
 tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
 {
@@ -887,26 +1109,44 @@ tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
   return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
 }
 
-int
-tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
+static size_t
+max_tlv_size(struct stream *stream)
+{
+  size_t avail = stream_get_size (stream) - stream_get_endp(stream);
+
+  if (avail < 2)
+    return 0;
+
+  if (avail < 257)
+    return avail - 2;
+
+  return 255;
+}
+
+unsigned int
+tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream, void *arg)
 {
   struct listnode *node;
   struct te_is_neigh *te_is_neigh;
   u_char value[255];
   u_char *pos = value;
-  int retval;
+  uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST;
+  unsigned int consumed = 0;
+  size_t max_size = max_tlv_size(stream);
+
+  if (mtid != ISIS_MT_IPV4_UNICAST)
+    {
+      uint16_t mtid_conversion = ntohs(mtid);
+      memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
+      pos += sizeof(mtid_conversion);
+    }
 
   for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
     {
       /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */
-      if (pos - value + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > 255)
-        {
-          retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
-          if (retval != ISIS_OK)
-            return retval;
-          pos = value;
-        }
-      
+      if ((size_t)(pos - value) + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > max_size)
+        break;
+
       memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
       pos += ISIS_SYS_ID_LEN + 1;
       memcpy (pos, te_is_neigh->te_metric, 3);
@@ -920,9 +1160,17 @@ tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
           memcpy (pos, te_is_neigh->sub_tlvs, te_is_neigh->sub_tlvs_length);
           pos += te_is_neigh->sub_tlvs_length;
         }
+      consumed++;
     }
 
-  return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
+  if (consumed)
+    {
+      int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IS_NEIGHBOURS
+                                                       : TE_IS_NEIGHBOURS,
+                        pos - value, value, stream);
+      assert(rv == ISIS_OK);
+    }
+  return consumed;
 }
 
 int
@@ -1100,37 +1348,49 @@ tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream)
 }
 
 
-int
-tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)
+unsigned int
+tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream, void *arg)
 {
   struct listnode *node;
   struct te_ipv4_reachability *te_reach;
   u_char value[255];
   u_char *pos = value;
-  u_char prefix_size;
-  int retval;
+  uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST;
+  unsigned int consumed = 0;
+  size_t max_size = max_tlv_size(stream);
+
+  if (mtid != ISIS_MT_IPV4_UNICAST)
+    {
+      uint16_t mtid_conversion = ntohs(mtid);
+      memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
+      pos += sizeof(mtid_conversion);
+    }
 
   for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach))
     {
-      prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1);
+      unsigned char prefixlen = te_reach->control & 0x3F;
+
+      if ((size_t)(pos - value) + 5 + PSIZE(prefixlen) > max_size)
+        break;
 
-      if (pos - value + (5 + prefix_size) > 255)
-       {
-         retval =
-           add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
-         if (retval != ISIS_OK)
-           return retval;
-         pos = value;
-       }
       *(u_int32_t *) pos = te_reach->te_metric;
       pos += 4;
       *pos = te_reach->control;
       pos++;
-      memcpy (pos, &te_reach->prefix_start, prefix_size);
-      pos += prefix_size;
+      memcpy (pos, &te_reach->prefix_start, PSIZE(prefixlen));
+      pos += PSIZE(prefixlen);
+      consumed++;
+    }
+
+  if (consumed)
+    {
+      int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IPV4_REACHABILITY
+                                                       : TE_IPV4_REACHABILITY,
+                        pos - value, value, stream);
+      assert(rv == ISIS_OK);
     }
 
-  return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
+  return consumed;
 }
 
 int
@@ -1158,36 +1418,49 @@ tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
   return add_tlv (IPV6_ADDR, pos - value, value, stream);
 }
 
-int
-tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
+unsigned int
+tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream, void *arg)
 {
   struct listnode *node;
   struct ipv6_reachability *ip6reach;
   u_char value[255];
   u_char *pos = value;
-  int retval, prefix_octets;
+  uint16_t mtid = arg ? *(uint16_t*)arg : ISIS_MT_IPV4_UNICAST;
+  unsigned int consumed = 0;
+  size_t max_size = max_tlv_size(stream);
+
+  if (mtid != ISIS_MT_IPV4_UNICAST)
+    {
+      uint16_t mtid_conversion = ntohs(mtid);
+      memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
+      pos += sizeof(mtid_conversion);
+    }
 
   for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach))
     {
-      if (pos - value + IPV6_MAX_BYTELEN + 6 > 255)
-       {
-         retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
-         if (retval != ISIS_OK)
-           return retval;
-         pos = value;
-       }
-      *(uint32_t *) pos = ip6reach->metric;
+      if ((size_t)(pos - value) + 6 + PSIZE(ip6reach->prefix_len) > max_size)
+        break;
+
+      *(uint32_t *)pos = ip6reach->metric;
       pos += 4;
       *pos = ip6reach->control_info;
       pos++;
-      prefix_octets = ((ip6reach->prefix_len + 7) / 8);
       *pos = ip6reach->prefix_len;
       pos++;
-      memcpy (pos, ip6reach->prefix, prefix_octets);
-      pos += prefix_octets;
+      memcpy (pos, ip6reach->prefix, PSIZE(ip6reach->prefix_len));
+      pos += PSIZE(ip6reach->prefix_len);
+      consumed++;
+    }
+
+  if (consumed)
+    {
+      int rv = add_tlv ((mtid != ISIS_MT_IPV4_UNICAST) ? MT_IPV6_REACHABILITY
+                                                       : IPV6_REACHABILITY,
+                        pos - value, value, stream);
+      assert(rv == ISIS_OK);
     }
 
-  return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
+  return consumed;
 }
 
 int
index f899b9e9db2f96af3d8128b741e71c4e47de17c1..2135f5071fcceded2721a3c4b86ffd3b719bdf69 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef _ZEBRA_ISIS_TLV_H
 #define _ZEBRA_ISIS_TLV_H
 
+#include "isisd/isis_mt.h"
+
 /*
  * The list of TLVs we (should) support.
  * ____________________________________________________________________________
 #define TE_IPV4_REACHABILITY      135
 #define DYNAMIC_HOSTNAME          137
 #define GRACEFUL_RESTART          211
+#define MT_IS_NEIGHBOURS          222
+#define MT_ROUTER_INFORMATION     229
 #define IPV6_ADDR                 232
+#define MT_IPV4_REACHABILITY      235
 #define IPV6_REACHABILITY         236
+#define MT_IPV6_REACHABILITY      237
 #define WAY3_HELLO                240
 #define ROUTER_INFORMATION        242
 
@@ -250,6 +256,12 @@ struct ipv6_reachability
 
 #define CTRL_INFO_SUBTLVS      0x20
 
+struct mt_router_info
+{
+  ISIS_MT_INFO_FIELDS
+  bool overload;
+};
+
 /*
  * Pointer to each tlv type, filled by parse_tlvs()
  */
@@ -260,8 +272,10 @@ struct tlvs
   struct nlpids *nlpids;
   struct te_router_id *router_id;
   struct list *area_addrs;
+  struct list *mt_router_info;
   struct list *is_neighs;
   struct list *te_is_neighs;
+  struct list *mt_is_neighs;
   struct list *es_neighs;
   struct list *lsp_entries;
   struct list *prefix_neighs;
@@ -270,8 +284,10 @@ struct tlvs
   struct list *ipv4_int_reachs;
   struct list *ipv4_ext_reachs;
   struct list *te_ipv4_reachs;
+  struct list *mt_ipv4_reachs;
   struct list *ipv6_addrs;
   struct list *ipv6_reachs;
+  struct list *mt_ipv6_reachs;
   struct isis_passwd auth_info;
 };
 
@@ -301,6 +317,7 @@ struct tlvs
 #define TLVFLAG_TE_ROUTER_ID              (1<<19)
 #define TLVFLAG_CHECKSUM                  (1<<20)
 #define TLVFLAG_GRACEFUL_RESTART          (1<<21)
+#define TLVFLAG_MT_ROUTER_INFORMATION     (1<<22)
 
 void init_tlvs (struct tlvs *tlvs, uint32_t expected);
 void free_tlvs (struct tlvs *tlvs);
@@ -310,9 +327,10 @@ int parse_tlvs (char *areatag, u_char * stream, int size,
 int add_tlv (u_char, u_char, u_char *, struct stream *);
 void free_tlv (void *val);
 
+int tlv_add_mt_router_info (struct list *mt_router_info, struct stream *stream);
 int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream);
 int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream);
-int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream);
+unsigned int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream, void *arg);
 int tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream);
 int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream);
 int tlv_add_checksum (struct checksum *checksum, struct stream *stream);
@@ -325,9 +343,9 @@ int tlv_add_dynamic_hostname (struct hostname *hostname,
 int tlv_add_lsp_entries (struct list *lsps, struct stream *stream);
 int tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream);
 int tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream);
-int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream);
+unsigned int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream, void *arg);
 int tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream);
-int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream);
+unsigned int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream, void *arg);
 
 int tlv_add_padding (struct stream *stream);
 
index 721959859a0cb46b31f1d154091b6c0d500778f5..9cae5f9a5c449995669e38a897383ec582eea68b 100644 (file)
@@ -29,6 +29,7 @@
 #include "isis_circuit.h"
 #include "isis_csm.h"
 #include "isis_misc.h"
+#include "isis_mt.h"
 #include "isisd.h"
 
 static struct isis_circuit *
@@ -1271,6 +1272,62 @@ DEFUN (no_psnp_interval_l2,
   return CMD_SUCCESS;
 }
 
+DEFUN (circuit_topology,
+       circuit_topology_cmd,
+       "isis topology " ISIS_MT_NAMES,
+       "IS-IS commands\n"
+       "Configure interface IS-IS topologies\n"
+       ISIS_MT_DESCRIPTIONS)
+{
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
+  const char *arg = argv[2]->arg;
+  uint16_t mtid = isis_str2mtid(arg);
+
+  if (circuit->area && circuit->area->oldmetric)
+    {
+      vty_out (vty, "Multi topology IS-IS can only be used with wide metrics%s", VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  if (mtid == (uint16_t)-1)
+    {
+      vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  return isis_circuit_mt_enabled_set(circuit, mtid, true);
+}
+
+DEFUN (no_circuit_topology,
+       no_circuit_topology_cmd,
+       "no isis topology " ISIS_MT_NAMES,
+       NO_STR
+       "IS-IS commands\n"
+       "Configure interface IS-IS topologies\n"
+       ISIS_MT_DESCRIPTIONS)
+{
+  struct isis_circuit *circuit = isis_circuit_lookup (vty);
+  if (!circuit)
+    return CMD_ERR_NO_MATCH;
+  const char *arg = argv[3]->arg;
+  uint16_t mtid = isis_str2mtid(arg);
+
+  if (circuit->area && circuit->area->oldmetric)
+    {
+      vty_out (vty, "Multi topology IS-IS can only be used with wide metrics%s", VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  if (mtid == (uint16_t)-1)
+    {
+      vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  return isis_circuit_mt_enabled_set(circuit, mtid, false);
+}
 
 static int
 validate_metric_style_narrow (struct vty *vty, struct isis_area *area)
@@ -1328,6 +1385,12 @@ DEFUN (metric_style,
       return CMD_SUCCESS;
     }
 
+  if (area_is_mt(area))
+    {
+      vty_out (vty, "Narrow metrics cannot be used while multi topology IS-IS is active%s", VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
   ret = validate_metric_style_narrow (vty, area);
   if (ret != CMD_SUCCESS)
     return ret;
@@ -1350,6 +1413,12 @@ DEFUN (no_metric_style,
   VTY_DECLVAR_CONTEXT (isis_area, area);
   int ret;
 
+  if (area_is_mt(area))
+    {
+      vty_out (vty, "Narrow metrics cannot be used while multi topology IS-IS is active%s", VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
   ret = validate_metric_style_narrow (vty, area);
   if (ret != CMD_SUCCESS)
     return ret;
@@ -2116,6 +2185,9 @@ isis_vty_init (void)
   install_element (INTERFACE_NODE, &psnp_interval_l2_cmd);
   install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd);
 
+  install_element (INTERFACE_NODE, &circuit_topology_cmd);
+  install_element (INTERFACE_NODE, &no_circuit_topology_cmd);
+
   install_element (ISIS_NODE, &metric_style_cmd);
   install_element (ISIS_NODE, &no_metric_style_cmd);
 
index e7bd99c3e84d073f669805c6055671b398fed948..3b128a689d78e3015aff0be025108132156de7d6 100644 (file)
@@ -300,8 +300,9 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix,
          /* FIXME: can it be ? */
          if (nexthop->ip.s_addr != INADDR_ANY)
            {
-             stream_putc (stream, NEXTHOP_TYPE_IPV4);
+             stream_putc (stream, NEXTHOP_TYPE_IPV4_IFINDEX);
              stream_put_in_addr (stream, &nexthop->ip);
+             stream_putl (stream, nexthop->ifindex);
            }
          else
            {
index f226c4a1f3cdea0679c3235c24dae8f7fc7583f6..d11044377f4d534c13cc10697ed2baea04db63c6 100644 (file)
@@ -56,6 +56,7 @@
 #include "isisd/isis_zebra.h"
 #include "isisd/isis_events.h"
 #include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
 
 struct isis *isis = NULL;
 
@@ -156,6 +157,8 @@ isis_area_create (const char *area_tag)
   area->lsp_frag_threshold = 90;
   area->lsp_mtu = DEFAULT_LSP_MTU;
 
+  area_mt_init(area);
+
   area->area_tag = strdup (area_tag);
   listnode_add (isis->area_list, area);
   area->isis = isis;
@@ -296,6 +299,8 @@ isis_area_destroy (struct vty *vty, const char *area_tag)
 
   free (area->area_tag);
 
+  area_mt_finish(area);
+
   XFREE (MTYPE_ISIS_AREA, area);
 
   if (listcount (isis->area_list) == 0)
@@ -307,6 +312,33 @@ isis_area_destroy (struct vty *vty, const char *area_tag)
   return CMD_SUCCESS;
 }
 
+static void
+area_set_mt_enabled(struct isis_area *area, uint16_t mtid, bool enabled)
+{
+  struct isis_area_mt_setting *setting;
+
+  setting = area_get_mt_setting(area, mtid);
+  if (setting->enabled != enabled)
+    {
+      setting->enabled = enabled;
+      lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+    }
+}
+
+static void
+area_set_mt_overload(struct isis_area *area, uint16_t mtid, bool overload)
+{
+  struct isis_area_mt_setting *setting;
+
+  setting = area_get_mt_setting(area, mtid);
+  if (setting->overload != overload)
+    {
+      setting->overload = overload;
+      if (setting->enabled)
+        lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+    }
+}
+
 int
 area_net_title (struct vty *vty, const char *net_title)
 {
@@ -1626,6 +1658,75 @@ DEFUN (no_net,
   return area_clear_net_title (vty, argv[idx_word]->arg);
 }
 
+DEFUN (isis_topology,
+       isis_topology_cmd,
+       "topology " ISIS_MT_NAMES " [overload]",
+       "Configure IS-IS topologies\n"
+       ISIS_MT_DESCRIPTIONS
+       "Set overload bit for topology\n")
+{
+  VTY_DECLVAR_CONTEXT (isis_area, area);
+
+  const char *arg = argv[1]->arg;
+  uint16_t mtid = isis_str2mtid(arg);
+
+  if (area->oldmetric)
+    {
+      vty_out (vty, "Multi topology IS-IS can only be used with wide metrics%s", VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  if (mtid == (uint16_t)-1)
+    {
+      vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+  if (mtid == ISIS_MT_IPV4_UNICAST)
+    {
+      vty_out (vty, "Cannot configure IPv4 unicast topology%s", VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  area_set_mt_enabled(area, mtid, true);
+  area_set_mt_overload(area, mtid, (argc == 3));
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_topology,
+       no_isis_topology_cmd,
+       "no topology " ISIS_MT_NAMES " [overload]",
+       NO_STR
+       "Configure IS-IS topologies\n"
+       ISIS_MT_DESCRIPTIONS
+       "Set overload bit for topology\n")
+{
+  VTY_DECLVAR_CONTEXT (isis_area, area);
+
+  const char *arg = argv[2]->arg;
+  uint16_t mtid = isis_str2mtid(arg);
+
+  if (area->oldmetric)
+    {
+      vty_out (vty, "Multi topology IS-IS can only be used with wide metrics%s", VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  if (mtid == (uint16_t)-1)
+    {
+      vty_out (vty, "Don't know topology '%s'%s", arg, VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+  if (mtid == ISIS_MT_IPV4_UNICAST)
+    {
+      vty_out (vty, "Cannot configure IPv4 unicast topology%s", VTY_NEWLINE);
+      return CMD_ERR_AMBIGUOUS;
+    }
+
+  area_set_mt_enabled(area, mtid, false);
+  area_set_mt_overload(area, mtid, false);
+  return CMD_SUCCESS;
+}
+
 void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu)
 {
   area->lsp_mtu = lsp_mtu;
@@ -2148,6 +2249,7 @@ isis_config_write (struct vty *vty)
            write++;
          }
 
+       write += area_write_mt_settings(area, vty);
       }
     isis_mpls_te_config_write_router(vty);
     }
@@ -2254,6 +2356,9 @@ isis_init ()
   install_element (ISIS_NODE, &net_cmd);
   install_element (ISIS_NODE, &no_net_cmd);
 
+  install_element (ISIS_NODE, &isis_topology_cmd);
+  install_element (ISIS_NODE, &no_isis_topology_cmd);
+
   install_element (ISIS_NODE, &log_adj_changes_cmd);
   install_element (ISIS_NODE, &no_log_adj_changes_cmd);
 
index e1d3a69f8dcc5e4ac7bf8ab6f71b9cfdf80ccf35..a8cf3673fc54b79bf8ebab0725887e3184820054 100644 (file)
@@ -120,6 +120,8 @@ struct isis_area
   int ip_circuits;
   /* logging adjacency changes? */
   u_char log_adj_changes;
+  /* multi topology settings */
+  struct list *mt_settings;
   int ipv6_circuits;
   /* Counters */
   u_int32_t circuit_state_changes;
index 19f819ae365d00fc3559a7d6d192cfca91da2afe..b760b44573141d40331a8a428062e2a1129a8c0d 100644 (file)
@@ -16,7 +16,7 @@ EXTRA_DIST += ldp_vty.xml
 libldp_a_SOURCES = \
        accept.c address.c adjacency.c control.c hello.c init.c interface.c \
        keepalive.c l2vpn.c labelmapping.c lde.c lde_lib.c ldpd.c \
-       ldpe.c log.c neighbor.c notification.c packet.c pfkey.c \
+       ldpe.c log.c logmsg.c neighbor.c notification.c packet.c pfkey.c \
        socket.c util.c ldp_vty_cmds.c ldp_vty_conf.c ldp_vty_exec.c \
        ldp_debug.c ldp_zebra.c
 
index 8659202ee4e5c14bf7fbaec47fb7dc2b575c86f1..3ec57f158971385ed445ba788e89bbfa592bf109 100644 (file)
@@ -29,6 +29,8 @@ static __inline int adj_compare(struct adj *, struct adj *);
 static int      adj_itimer(struct thread *);
 static __inline int tnbr_compare(struct tnbr *, struct tnbr *);
 static void     tnbr_del(struct ldpd_conf *, struct tnbr *);
+static void     tnbr_start(struct tnbr *);
+static void     tnbr_stop(struct tnbr *);
 static int      tnbr_hello_timer(struct thread *);
 static void     tnbr_start_hello_timer(struct tnbr *);
 static void     tnbr_stop_hello_timer(struct tnbr *);
@@ -245,9 +247,7 @@ tnbr_new(int af, union ldpd_addr *addr)
 static void
 tnbr_del(struct ldpd_conf *xconf, struct tnbr *tnbr)
 {
-       tnbr_stop_hello_timer(tnbr);
-       if (tnbr->adj)
-               adj_del(tnbr->adj, S_SHUTDOWN);
+       tnbr_stop(tnbr);
        RB_REMOVE(tnbr_head, &xconf->tnbr_tree, tnbr);
        free(tnbr);
 }
@@ -273,6 +273,23 @@ tnbr_check(struct ldpd_conf *xconf, struct tnbr *tnbr)
        return (tnbr);
 }
 
+static void
+tnbr_start(struct tnbr *tnbr)
+{
+       send_hello(HELLO_TARGETED, NULL, tnbr);
+       tnbr_start_hello_timer(tnbr);
+       tnbr->state = TNBR_STA_ACTIVE;
+}
+
+static void
+tnbr_stop(struct tnbr *tnbr)
+{
+       tnbr_stop_hello_timer(tnbr);
+       if (tnbr->adj)
+               adj_del(tnbr->adj, S_SHUTDOWN);
+       tnbr->state = TNBR_STA_DOWN;
+}
+
 void
 tnbr_update(struct tnbr *tnbr)
 {
@@ -292,16 +309,12 @@ tnbr_update(struct tnbr *tnbr)
                if (!socket_ok || !rtr_id_ok)
                        return;
 
-               tnbr->state = TNBR_STA_ACTIVE;
-               send_hello(HELLO_TARGETED, NULL, tnbr);
-
-               tnbr_start_hello_timer(tnbr);
+               tnbr_start(tnbr);
        } else if (tnbr->state == TNBR_STA_ACTIVE) {
                if (socket_ok && rtr_id_ok)
                        return;
 
-               tnbr->state = TNBR_STA_DOWN;
-               tnbr_stop_hello_timer(tnbr);
+               tnbr_stop(tnbr);
        }
 }
 
index 5c530e1b701163736f876a63206e7deccfb1f9dd..d40e0342c13a76011e0a112fec96145e2a783feb 100644 (file)
@@ -37,7 +37,7 @@ struct ctl_conns       ctl_conns;
 static int              control_fd;
 
 int
-control_init(void)
+control_init(char *path)
 {
        struct sockaddr_un       s_un;
        int                      fd;
@@ -51,28 +51,28 @@ control_init(void)
 
        memset(&s_un, 0, sizeof(s_un));
        s_un.sun_family = AF_UNIX;
-       strlcpy(s_un.sun_path, ctl_sock_path, sizeof(s_un.sun_path));
+       strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path));
 
-       if (unlink(ctl_sock_path) == -1)
+       if (unlink(path) == -1)
                if (errno != ENOENT) {
-                       log_warn("%s: unlink %s", __func__, ctl_sock_path);
+                       log_warn("%s: unlink %s", __func__, path);
                        close(fd);
                        return (-1);
                }
 
        old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
        if (bind(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
-               log_warn("%s: bind: %s", __func__, ctl_sock_path);
+               log_warn("%s: bind: %s", __func__, path);
                close(fd);
                umask(old_umask);
                return (-1);
        }
        umask(old_umask);
 
-       if (chmod(ctl_sock_path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
+       if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
                log_warn("%s: chmod", __func__);
                close(fd);
-               (void)unlink(ctl_sock_path);
+               (void)unlink(path);
                return (-1);
        }
 
@@ -93,11 +93,11 @@ control_listen(void)
 }
 
 void
-control_cleanup(void)
+control_cleanup(char *path)
 {
        accept_del(control_fd);
        close(control_fd);
-       unlink(ctl_sock_path);
+       unlink(path);
 }
 
 /* ARGSUSED */
index 32c49fdf8760cfd7782210ea1da5bc4092a24d39..0e66a1636aa88354fd83db989b961856cf05aa4f 100644 (file)
@@ -29,9 +29,9 @@ TAILQ_HEAD(ctl_conns, ctl_conn);
 
 extern struct ctl_conns ctl_conns;
 
-int    control_init(void);
+int    control_init(char *);
 int    control_listen(void);
-void   control_cleanup(void);
+void   control_cleanup(char *);
 int    control_imsg_relay(struct imsg *);
 
 #endif /* _CONTROL_H_ */
index 7be8be755e4dca392eec913a9913a675d1564fd4..440bb2dca06244828fad0ceb4ff7811999143a8c 100644 (file)
@@ -287,8 +287,9 @@ if_start(struct iface *iface, int af)
        }
 
        send_hello(HELLO_LINK, ia, NULL);
-
        if_start_hello_timer(ia);
+       ia->state = IF_STA_ACTIVE;
+
        return (0);
 }
 
@@ -318,9 +319,11 @@ if_reset(struct iface *iface, int af)
                        if_leave_ipv6_group(iface, &global.mcast_addr_v6);
                break;
        default:
-               fatalx("if_start: unknown af");
+               fatalx("if_reset: unknown af");
        }
 
+       ia->state = IF_STA_DOWN;
+
        return (0);
 }
 
@@ -367,14 +370,12 @@ if_update_af(struct iface_af *ia)
                    !socket_ok || !rtr_id_ok)
                        return;
 
-               ia->state = IF_STA_ACTIVE;
                if_start(ia->iface, ia->af);
        } else if (ia->state == IF_STA_ACTIVE) {
                if (ia->enabled && ia->iface->operative && addr_ok &&
                    socket_ok && rtr_id_ok)
                        return;
 
-               ia->state = IF_STA_DOWN;
                if_reset(ia->iface, ia->af);
        }
 }
index d8a2924b31c9fdd4ee60c6628b01182ac59df5c1..859d47431b394c5855e72d234b9ef5c7e9fdb6db 100644 (file)
@@ -54,9 +54,9 @@ static void            lde_map_free(void *);
 static int              lde_address_add(struct lde_nbr *, struct lde_addr *);
 static int              lde_address_del(struct lde_nbr *, struct lde_addr *);
 static void             lde_address_list_free(struct lde_nbr *);
-static void             zclient_sync_init (u_short instance);
+static void             zclient_sync_init(u_short instance);
 static void             lde_label_list_init(void);
-static int              lde_get_label_chunk (void);
+static int              lde_get_label_chunk(void);
 static void             on_get_label_chunk_response(uint32_t start, uint32_t end);
 static uint32_t                 lde_get_next_label(void);
 
@@ -80,10 +80,6 @@ static zebra_capabilities_t _caps_p [] =
 
 static struct zebra_privs_t lde_privs =
 {
-#if defined(FRR_USER) && defined(FRR_GROUP)
-       .user = FRR_USER,
-       .group = FRR_GROUP,
-#endif
 #if defined(VTY_GROUP)
        .vty_group = VTY_GROUP,
 #endif
@@ -93,8 +89,11 @@ static struct zebra_privs_t lde_privs =
 };
 
 /* List of chunks of labels externally assigned by Zebra */
-struct list *label_chunk_list;
-struct listnode *current_label_chunk;
+static struct list *label_chunk_list;
+static struct listnode *current_label_chunk;
+
+/* Synchronous zclient to request labels */
+static struct zclient *zclient_sync;
 
 /* SIGINT / SIGTERM handler. */
 static void
@@ -119,60 +118,17 @@ static struct quagga_signal_t lde_signals[] =
        },
 };
 
-static void
-lde_sleep (void)
-{
-       sleep(1);
-       if (lde_signals[0].caught || lde_signals[1].caught)
-               lde_shutdown();
-}
-struct zclient *zclient_sync = NULL;
-static void
-zclient_sync_init(u_short instance)
-{
-       /* Initialize special zclient for synchronous message exchanges. */
-       log_debug("Initializing synchronous zclient for label manager");
-       zclient_sync = zclient_new(master);
-       zclient_sync->sock = -1;
-       zclient_sync->redist_default = ZEBRA_ROUTE_LDP;
-       zclient_sync->instance = instance;
-       while (zclient_socket_connect (zclient_sync) < 0) {
-               fprintf(stderr, "Error connecting synchronous zclient!\n");
-               lde_sleep();
-       }
-
-       /* Connect to label manager */
-       while (lm_label_manager_connect (zclient_sync) != 0) {
-               fprintf(stderr, "Error connecting to label manager!\n");
-               lde_sleep();
-       }
-}
-
 /* label decision engine */
 void
-lde(const char *user, const char *group, u_short instance)
+lde(void)
 {
        struct thread            thread;
-       struct timeval           now;
-
-       ldeconf = config_new_empty();
 
 #ifdef HAVE_SETPROCTITLE
        setproctitle("label decision engine");
 #endif
        ldpd_process = PROC_LDE_ENGINE;
-
-       /* drop privileges */
-       if (user)
-               lde_privs.user = user;
-       if (group)
-               lde_privs.group = group;
-       zprivs_init(&lde_privs);
-
-#ifdef HAVE_PLEDGE
-       if (pledge("stdio recvfd unix", NULL) == -1)
-               fatal("pledge");
-#endif
+       log_procname = log_procnames[PROC_LDE_ENGINE];
 
        master = thread_master_create();
 
@@ -192,27 +148,44 @@ lde(const char *user, const char *group, u_short instance)
                fatal(NULL);
        imsg_init(&iev_main_sync->ibuf, LDPD_FD_SYNC);
 
+       /* create base configuration */
+       ldeconf = config_new_empty();
+
+       /* Fetch next active thread. */
+       while (thread_fetch(master, &thread))
+               thread_call(&thread);
+}
+
+void
+lde_init(struct ldpd_init *init)
+{
+       /* drop privileges */
+       lde_privs.user = init->user;
+       lde_privs.group = init->group;
+       zprivs_init(&lde_privs);
+
+#ifdef HAVE_PLEDGE
+       if (pledge("stdio recvfd unix", NULL) == -1)
+               fatal("pledge");
+#endif
+
        /* start the LIB garbage collector */
        lde_gc_start_timer();
 
-       gettimeofday(&now, NULL);
-       global.uptime = now.tv_sec;
-
        /* Init synchronous zclient and label list */
-       zclient_sync_init(instance);
+       zclient_serv_path_set(init->zclient_serv_path);
+       zclient_sync_init(init->instance);
        lde_label_list_init();
-
-       /* Fetch next active thread. */
-       while (thread_fetch(master, &thread))
-               thread_call(&thread);
 }
 
 static void
 lde_shutdown(void)
 {
        /* close pipes */
-       msgbuf_clear(&iev_ldpe->ibuf.w);
-       close(iev_ldpe->ibuf.fd);
+       if (iev_ldpe) {
+               msgbuf_clear(&iev_ldpe->ibuf.w);
+               close(iev_ldpe->ibuf.fd);
+       }
        msgbuf_clear(&iev_main->ibuf.w);
        close(iev_main->ibuf.fd);
        msgbuf_clear(&iev_main_sync->ibuf.w);
@@ -224,7 +197,8 @@ lde_shutdown(void)
 
        config_clear(ldeconf);
 
-       free(iev_ldpe);
+       if (iev_ldpe)
+               free(iev_ldpe);
        free(iev_main);
        free(iev_main_sync);
 
@@ -239,6 +213,13 @@ lde_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen)
        return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
 }
 
+void
+lde_imsg_compose_parent_sync(int type, pid_t pid, void *data, uint16_t datalen)
+{
+       imsg_compose_event(iev_main_sync, type, 0, pid, -1, data, datalen);
+       imsg_flush(&iev_main_sync->ibuf);
+}
+
 int
 lde_imsg_compose_ldpe(int type, uint32_t peerid, pid_t pid, void *data,
     uint16_t datalen)
@@ -550,6 +531,14 @@ lde_dispatch_parent(struct thread *thread)
                        iev_ldpe->handler_write = ldp_write_handler;
                        iev_ldpe->ev_write = NULL;
                        break;
+               case IMSG_INIT:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct ldpd_init))
+                               fatalx("INIT imsg with wrong len");
+
+                       memcpy(&init, imsg.data, sizeof(init));
+                       lde_init(&init);
+                       break;
                case IMSG_RECONF_CONF:
                        if ((nconf = malloc(sizeof(struct ldpd_conf))) ==
                            NULL)
@@ -719,7 +708,7 @@ lde_update_label(struct fec_node *fn)
            fn->local_label > MPLS_LABEL_RESERVED_MAX)
                return (fn->local_label);
 
-       return lde_get_next_label ();
+       return (lde_get_next_label());
 }
 
 void
@@ -901,10 +890,23 @@ lde_map2fec(struct map *map, struct in_addr lsr_id, struct fec *fec)
 void
 lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
 {
-       struct lde_req  *lre;
-       struct lde_map  *me;
-       struct map       map;
-       struct l2vpn_pw *pw;
+       struct lde_wdraw        *lw;
+       struct lde_map          *me;
+       struct lde_req          *lre;
+       struct map               map;
+       struct l2vpn_pw         *pw;
+
+       /*
+        * We shouldn't send a new label mapping if we have a pending
+        * label release to receive. In this case, schedule to send a
+        * label mapping as soon as a label release is received.
+        */
+       lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
+       if (lw) {
+               if (!fec_find(&ln->sent_map_pending, &fn->fec))
+                       lde_map_pending_add(ln, fn);
+               return;
+       }
 
        /*
         * This function skips SL.1 - 3 and SL.9 - 14 because the label
@@ -1210,6 +1212,7 @@ lde_nbr_new(uint32_t peerid, struct lde_nbr *new)
        ln->peerid = peerid;
        fec_init(&ln->recv_map);
        fec_init(&ln->sent_map);
+       fec_init(&ln->sent_map_pending);
        fec_init(&ln->recv_req);
        fec_init(&ln->sent_req);
        fec_init(&ln->sent_wdraw);
@@ -1265,6 +1268,7 @@ lde_nbr_del(struct lde_nbr *ln)
 
        fec_clear(&ln->recv_map, lde_map_free);
        fec_clear(&ln->sent_map, lde_map_free);
+       fec_clear(&ln->sent_map_pending, free);
        fec_clear(&ln->recv_req, free);
        fec_clear(&ln->sent_req, free);
        fec_clear(&ln->sent_wdraw, free);
@@ -1415,6 +1419,30 @@ lde_map_free(void *ptr)
        free(map);
 }
 
+struct fec *
+lde_map_pending_add(struct lde_nbr *ln, struct fec_node *fn)
+{
+       struct fec      *map;
+
+       map = calloc(1, sizeof(*map));
+       if (map == NULL)
+               fatal(__func__);
+
+       *map = fn->fec;
+       if (fec_insert(&ln->sent_map_pending, map))
+               log_warnx("failed to add %s to sent map (pending)",
+                   log_fec(map));
+
+       return (map);
+}
+
+void
+lde_map_pending_del(struct lde_nbr *ln, struct fec *map)
+{
+       fec_remove(&ln->sent_map_pending, map);
+       free(map);
+}
+
 struct lde_req *
 lde_req_add(struct lde_nbr *ln, struct fec *fec, int sent)
 {
@@ -1580,21 +1608,42 @@ lde_address_list_free(struct lde_nbr *ln)
        }
 }
 
+static void
+zclient_sync_init(u_short instance)
+{
+       /* Initialize special zclient for synchronous message exchanges. */
+       log_debug("Initializing synchronous zclient for label manager");
+       zclient_sync = zclient_new(master);
+       zclient_sync->sock = -1;
+       zclient_sync->redist_default = ZEBRA_ROUTE_LDP;
+       zclient_sync->instance = instance;
+       while (zclient_socket_connect(zclient_sync) < 0) {
+               log_warnx("Error connecting synchronous zclient!");
+               sleep(1);
+       }
+
+       /* Connect to label manager */
+       while (lm_label_manager_connect(zclient_sync) != 0) {
+               log_warnx("Error connecting to label manager!");
+               sleep(1);
+       }
+}
+
 static void
 lde_del_label_chunk(void *val)
 {
        free(val);
 }
+
 static int
 lde_get_label_chunk(void)
 {
-       int ret;
-       uint32_t start, end;
+       int              ret;
+       uint32_t         start, end;
 
        log_debug("Getting label chunk");
        ret = lm_get_label_chunk(zclient_sync, 0, CHUNK_SIZE, &start, &end);
-       if (ret < 0)
-       {
+       if (ret < 0) {
                log_warnx("Error getting label chunk!");
                close(zclient_sync->sock);
                zclient_sync->sock = -1;
@@ -1603,8 +1652,9 @@ lde_get_label_chunk(void)
 
        on_get_label_chunk_response(start, end);
 
-       return 0;
+       return (0);
 }
+
 static void
 lde_label_list_init(void)
 {
@@ -1613,8 +1663,8 @@ lde_label_list_init(void)
 
        /* get first chunk */
        while (lde_get_label_chunk () != 0) {
-               fprintf(stderr, "Error getting first label chunk!\n");
-               lde_sleep();
+               log_warnx("Error getting first label chunk!");
+               sleep(1);
        }
 }
 
@@ -1645,9 +1695,9 @@ on_get_label_chunk_response(uint32_t start, uint32_t end)
 static uint32_t
 lde_get_next_label(void)
 {
-       struct label_chunk *label_chunk;
-       uint32_t i, pos, size;
-       uint32_t label = NO_LABEL;
+       struct label_chunk      *label_chunk;
+       uint32_t                 i, pos, size;
+       uint32_t                 label = NO_LABEL;
 
        while (current_label_chunk) {
                label_chunk = listgetdata(current_label_chunk);
@@ -1669,12 +1719,13 @@ lde_get_next_label(void)
 end:
        /* we moved till the last chunk, or were not able to find a label,
           so let's ask for another one */
-       if (!current_label_chunk || current_label_chunk == listtail(label_chunk_list)
-               || label == NO_LABEL) {
+       if (!current_label_chunk ||
+           current_label_chunk == listtail(label_chunk_list) ||
+           label == NO_LABEL) {
                if (lde_get_label_chunk() != 0)
                        log_warn("%s: Error getting label chunk!", __func__);
 
        }
 
-       return label;
+       return (label);
 }
index 57791cd1b0c64ea5a033e349dd188c97736ee65a..1cce483832d19283e81a1466f5d2530259faedf1 100644 (file)
@@ -95,6 +95,7 @@ struct lde_nbr {
        struct fec_tree          sent_req;
        struct fec_tree          recv_map;
        struct fec_tree          sent_map;
+       struct fec_tree          sent_map_pending;
        struct fec_tree          sent_wdraw;
        TAILQ_HEAD(, lde_addr)   addr_list;
 };
@@ -139,8 +140,10 @@ extern struct nbr_tree      lde_nbrs;
 extern struct thread   *gc_timer;
 
 /* lde.c */
-void            lde(const char *, const char *, u_short instance);
+void            lde(void);
+void            lde_init(struct ldpd_init *);
 int             lde_imsg_compose_parent(int, pid_t, void *, uint16_t);
+void            lde_imsg_compose_parent_sync(int, pid_t, void *, uint16_t);
 int             lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t);
 int             lde_acl_check(char *, int, union ldpd_addr *, uint8_t);
 uint32_t        lde_update_label(struct fec_node *);
@@ -169,6 +172,8 @@ struct lde_nbr      *lde_nbr_find_by_lsrid(struct in_addr);
 struct lde_nbr *lde_nbr_find_by_addr(int, union ldpd_addr *);
 struct lde_map *lde_map_add(struct lde_nbr *, struct fec_node *, int);
 void            lde_map_del(struct lde_nbr *, struct lde_map *, int);
+struct fec     *lde_map_pending_add(struct lde_nbr *, struct fec_node *);
+void            lde_map_pending_del(struct lde_nbr *, struct fec *);
 struct lde_req *lde_req_add(struct lde_nbr *, struct fec *, int);
 void            lde_req_del(struct lde_nbr *, struct lde_req *, int);
 struct lde_wdraw *lde_wdraw_add(struct lde_nbr *, struct fec_node *);
index db2682a173698a65c357ee0d6e37779e9965cdd3..37a670bc8ca58be4988cba4cfa7172df69b4bb5b 100644 (file)
@@ -383,20 +383,23 @@ lde_kernel_update(struct fec *fec)
        if (LIST_EMPTY(&fn->nexthops)) {
                RB_FOREACH(ln, nbr_tree, &lde_nbrs)
                        lde_send_labelwithdraw(ln, fn, NULL, NULL);
-               fn->local_label = NO_LABEL;
                fn->data = NULL;
-       } else {
-               uint32_t         previous_label;
 
-               previous_label = fn->local_label;
+               /*
+                * Do not deallocate the local label now, do that only in the
+                * LIB garbage collector. This will prevent ldpd from changing
+                * the input label of some prefixes too often when running on
+                * an unstable network. Also, restart the garbage collector
+                * timer so that labels are deallocated only when the network
+                * is stabilized.
+                */
+               lde_gc_start_timer();
+       } else {
                fn->local_label = lde_update_label(fn);
-
-               if (fn->local_label != NO_LABEL &&
-                   fn->local_label != previous_label) {
+               if (fn->local_label != NO_LABEL && RB_EMPTY(&fn->upstream))
                        /* FEC.1: perform lsr label distribution procedure */
                        RB_FOREACH(ln, nbr_tree, &lde_nbrs)
                                lde_send_labelmapping(ln, fn, 1);
-               }
        }
 
        LIST_FOREACH(fnh, &fn->nexthops, entry) {
@@ -659,6 +662,7 @@ lde_check_release(struct map *map, struct lde_nbr *ln)
        struct fec_node         *fn;
        struct lde_wdraw        *lw;
        struct lde_map          *me;
+       struct fec              *pending_map;
 
        /* wildcard label release */
        if (map->type == MAP_TYPE_WILDCARD ||
@@ -674,17 +678,24 @@ lde_check_release(struct map *map, struct lde_nbr *ln)
        if (fn == NULL)
                return;
 
+       /* LRl.6: check sent map list and remove it if available */
+       me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
+       if (me && (map->label == NO_LABEL || map->label == me->map.label))
+               lde_map_del(ln, me, 1);
+
        /* LRl.3: first check if we have a pending withdraw running */
        lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
        if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
                /* LRl.4: delete record of outstanding label withdraw */
                lde_wdraw_del(ln, lw);
-       }
 
-       /* LRl.6: check sent map list and remove it if available */
-       me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
-       if (me && (map->label == NO_LABEL || map->label == me->map.label))
-               lde_map_del(ln, me, 1);
+               /* send pending label mapping if any */
+               pending_map = fec_find(&ln->sent_map_pending, &fn->fec);
+               if (pending_map) {
+                       lde_send_labelmapping(ln, fn, 1);
+                       lde_map_pending_del(ln, pending_map);
+               }
+       }
 
        /*
         * LRl.11 - 13 are unnecessary since we remove the label from
@@ -699,6 +710,7 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln)
        struct fec_node         *fn;
        struct lde_wdraw        *lw;
        struct lde_map          *me;
+       struct fec              *pending_map;
 
        RB_FOREACH(f, fec_tree, &ft) {
                fn = (struct fec_node *)f;
@@ -708,17 +720,24 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln)
                if (lde_wildcard_apply(map, &fn->fec, me) == 0)
                        continue;
 
+               /* LRl.6: check sent map list and remove it if available */
+               if (me &&
+                   (map->label == NO_LABEL || map->label == me->map.label))
+                       lde_map_del(ln, me, 1);
+
                /* LRl.3: first check if we have a pending withdraw running */
                lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
                if (lw && (map->label == NO_LABEL || map->label == lw->label)) {
                        /* LRl.4: delete record of outstanding lbl withdraw */
                        lde_wdraw_del(ln, lw);
-               }
 
-               /* LRl.6: check sent map list and remove it if available */
-               if (me &&
-                   (map->label == NO_LABEL || map->label == me->map.label))
-                       lde_map_del(ln, me, 1);
+                       /* send pending label mapping if any */
+                       pending_map = fec_find(&ln->sent_map_pending, &fn->fec);
+                       if (pending_map) {
+                               lde_send_labelmapping(ln, fn, 1);
+                               lde_map_pending_del(ln, pending_map);
+                       }
+               }
 
                /*
                 * LRl.11 - 13 are unnecessary since we remove the label from
index e4fc7b00545fc281f34edc8651bc9bf2bcc655f2..6943e8edc6234cd14bab30ae9fa4cb2151858d9a 100644 (file)
@@ -1641,7 +1641,7 @@ iface_new_api(struct ldpd_conf *conf, const char *name)
        struct iface            *iface;
 
        if (ldp_iface_is_configured(conf, ifname))
-               return NULL;
+               return (NULL);
 
        iface = if_new(name);
        RB_INSERT(iface_head, &conf->iface_tree, iface);
index a149b7fe3522b4993dbd758cb88559dad8e291fa..ffd20abb4a73fce9000c4dcadbfde5028bb18067 100644 (file)
@@ -517,8 +517,7 @@ show_nbr_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
                    nbr_state_name(nbr->nbr_state), addr);
                if (strlen(addr) > 15)
                        vty_out(vty, "%s%48s", VTY_NEWLINE, " ");
-               vty_out(vty, " %8s%s", nbr->uptime == 0 ? "-" :
-                   log_time(nbr->uptime), VTY_NEWLINE);
+               vty_out(vty, " %8s%s", log_time(nbr->uptime), VTY_NEWLINE);
                break;
        case IMSG_CTL_END:
                return (1);
@@ -909,6 +908,7 @@ show_nbr_capabilities_msg(struct vty *vty, struct imsg *imsg, struct show_params
                vty_out(vty, "Peer LDP Identifier: %s:0%s", inet_ntoa(nbr->id),
                    VTY_NEWLINE);
                show_nbr_capabilities(vty, nbr);
+               vty_out(vty, "%s", VTY_NEWLINE);
                break;
        case IMSG_CTL_END:
                vty_out(vty, "%s", VTY_NEWLINE);
index fde6e56c64a8fb56f3d7168a20b2d88d444b4901..3320238a05c6df1add4b166b524ddb9ea462e408 100644 (file)
@@ -360,6 +360,7 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
        struct kroute            kr;
        int                      nhnum = 0, nhlen;
        size_t                   nhmark;
+       int                      add = 0;
 
        memset(&kr, 0, sizeof(kr));
        s = zclient->ibuf;
@@ -426,21 +427,14 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
        if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP))
                stream_set_getp(s, nhmark);
 
-       if (nhnum == 0) {
-               switch (command) {
-               case ZEBRA_REDISTRIBUTE_IPV4_ADD:
-               case ZEBRA_REDISTRIBUTE_IPV6_ADD:
-                       return (0);
-               case ZEBRA_REDISTRIBUTE_IPV4_DEL:
-               case ZEBRA_REDISTRIBUTE_IPV6_DEL:
-                       debug_zebra_in("route delete %s/%d (%s)",
-                           log_addr(kr.af, &kr.prefix), kr.prefixlen,
-                           zebra_route_string(type));
-                       break;
-               default:
-                       fatalx("ldp_zebra_read_route: unknown command");
-               }
-       }
+       if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD ||
+           command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
+               add = 1;
+
+       if (nhnum == 0)
+               debug_zebra_in("route %s %s/%d (%s)", (add) ? "add" : "delete",
+                   log_addr(kr.af, &kr.prefix), kr.prefixlen,
+                   zebra_route_string(type));
 
        /* loop through all the nexthops */
        for (; nhnum > 0; nhnum--) {
@@ -457,19 +451,14 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
                stream_getc(s); /* ifindex_num, unused. */
                kr.ifindex = stream_getl(s);
 
-               switch (command) {
-               case ZEBRA_REDISTRIBUTE_IPV4_ADD:
-               case ZEBRA_REDISTRIBUTE_IPV6_ADD:
-                       debug_zebra_in("route add %s/%d nexthop %s "
-                           "ifindex %u (%s)", log_addr(kr.af, &kr.prefix),
-                           kr.prefixlen, log_addr(kr.af, &kr.nexthop),
-                           kr.ifindex, zebra_route_string(type));
+               debug_zebra_in("route %s %s/%d nexthop %s ifindex %u (%s)",
+                   (add) ? "add" : "delete", log_addr(kr.af, &kr.prefix),
+                   kr.prefixlen, log_addr(kr.af, &kr.nexthop), kr.ifindex,
+                   zebra_route_string(type));
+
+               if (add)
                        main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, &kr,
                            sizeof(kr));
-                       break;
-               default:
-                       break;
-               }
        }
 
        main_imsg_compose_lde(IMSG_NETWORK_UPDATE, 0, &kr, sizeof(kr));
index def3d2e2f3fd55b259a6b8af625aa93897644640..bdf70973234559c47c333fd8c479e2d0c9219b4a 100644 (file)
@@ -44,8 +44,7 @@
 #include "libfrr.h"
 
 static void             ldpd_shutdown(void);
-static pid_t            start_child(enum ldpd_process, char *, int, int,
-                           const char *, const char *, const char *, const char *);
+static pid_t            start_child(enum ldpd_process, char *, int, int);
 static int              main_dispatch_ldpe(struct thread *);
 static int              main_dispatch_lde(struct thread *);
 static int              main_imsg_send_ipc_sockets(struct imsgbuf *,
@@ -77,6 +76,7 @@ DEFINE_QOBJ_TYPE(l2vpn)
 DEFINE_QOBJ_TYPE(ldpd_conf)
 
 struct ldpd_global      global;
+struct ldpd_init        init;
 struct ldpd_conf       *ldpd_conf, *vty_conf;
 
 static struct imsgev   *iev_ldpe, *iev_ldpe_sync;
@@ -200,14 +200,10 @@ main(int argc, char *argv[])
        int                      lflag = 0, eflag = 0;
        int                      pipe_parent2ldpe[2], pipe_parent2ldpe_sync[2];
        int                      pipe_parent2lde[2], pipe_parent2lde_sync[2];
-       char                    *ctl_sock_custom_path = NULL;
        char                    *ctl_sock_name;
-       const char              *user = NULL;
-       const char              *group = NULL;
-       u_short                  instance = 0;
-       const char              *instance_char = NULL;
 
        ldpd_process = PROC_MAIN;
+       log_procname = log_procnames[ldpd_process];
 
        saved_argv0 = argv[0];
        if (saved_argv0 == NULL)
@@ -241,17 +237,14 @@ main(int argc, char *argv[])
                                 * sensible config
                                 */
                                ctl_sock_name = (char *)LDPD_SOCKET;
-                       ctl_sock_custom_path = optarg;
-                       strlcpy(ctl_sock_path, ctl_sock_custom_path,
-                           sizeof(ctl_sock_path));
+                       strlcpy(ctl_sock_path, optarg, sizeof(ctl_sock_path));
                        strlcat(ctl_sock_path, "/", sizeof(ctl_sock_path));
                        strlcat(ctl_sock_path, ctl_sock_name,
                            sizeof(ctl_sock_path));
                        break;
                case 'n':
-                       instance = atoi(optarg);
-                       instance_char = optarg;
-                       if (instance < 1)
+                       init.instance = atoi(optarg);
+                       if (init.instance < 1)
                                exit(0);
                        break;
                case 'L':
@@ -266,8 +259,11 @@ main(int argc, char *argv[])
                }
        }
 
-       user = ldpd_privs.user;
-       group = ldpd_privs.group;
+       strlcpy(init.user, ldpd_privs.user, sizeof(init.user));
+       strlcpy(init.group, ldpd_privs.group, sizeof(init.group));
+       strlcpy(init.ctl_sock_path, ctl_sock_path, sizeof(init.ctl_sock_path));
+       strlcpy(init.zclient_serv_path, zclient_serv_path_get(),
+           sizeof(init.zclient_serv_path));
 
        argc -= optind;
        argv += optind;
@@ -281,14 +277,14 @@ main(int argc, char *argv[])
                exit(1);
        }
 
-       if (lflag)
-               lde(user, group, instance);
-       else if (eflag)
-               ldpe(user, group, ctl_sock_path);
-
        openzlog(ldpd_di.progname, "LDP", 0,
            LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
 
+       if (lflag)
+               lde();
+       else if (eflag)
+               ldpe();
+
        if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2ldpe) == -1)
                fatal("socketpair");
        if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
@@ -316,11 +312,9 @@ main(int argc, char *argv[])
 
        /* start children */
        lde_pid = start_child(PROC_LDE_ENGINE, saved_argv0,
-           pipe_parent2lde[1], pipe_parent2lde_sync[1],
-           user, group, ctl_sock_custom_path, instance_char);
+           pipe_parent2lde[1], pipe_parent2lde_sync[1]);
        ldpe_pid = start_child(PROC_LDP_ENGINE, saved_argv0,
-           pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1],
-           user, group, ctl_sock_custom_path, instance_char);
+           pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1]);
 
        /* drop privileges */
        zprivs_init(&ldpd_privs);
@@ -388,6 +382,7 @@ main(int argc, char *argv[])
 
        if (main_imsg_send_ipc_sockets(&iev_ldpe->ibuf, &iev_lde->ibuf))
                fatal("could not establish imsg links");
+       main_imsg_compose_both(IMSG_INIT, &init, sizeof(init));
        main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug,
            sizeof(ldp_debug));
        main_imsg_send_config(ldpd_conf);
@@ -452,11 +447,9 @@ ldpd_shutdown(void)
 }
 
 static pid_t
-start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync,
-    const char *user, const char *group, const char *ctl_sock_custom_path,
-    const char *instance)
+start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync)
 {
-       char    *argv[13];
+       char    *argv[3];
        int      argc = 0;
        pid_t    pid;
 
@@ -487,29 +480,6 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync,
                argv[argc++] = (char *)"-E";
                break;
        }
-       if (user) {
-               argv[argc++] = (char *)"-u";
-               argv[argc++] = (char *)user;
-       }
-       if (group) {
-               argv[argc++] = (char *)"-g";
-               argv[argc++] = (char *)group;
-       }
-       if (ctl_sock_custom_path) {
-               argv[argc++] = (char *)"--ctl_socket";
-               argv[argc++] = (char *)ctl_sock_custom_path;
-       }
-       /* zclient serv path */
-#ifdef HAVE_TCP_ZEBRA
-#else
-       argv[argc++] = (char *)"-z";
-       argv[argc++] = (char *)zclient_serv_path_get();
-#endif
-       /* instance */
-       if (instance) {
-               argv[argc++] = (char *)"-n";
-               argv[argc++] = (char *)instance;
-       }
        argv[argc++] = NULL;
 
        execvp(argv0, argv);
index 10742cf0dc2d6e4659ccab78a9a163797757f639..3acc4fbe2d8b1f97551c4e3daf02657b6658d09a 100644 (file)
@@ -146,8 +146,15 @@ enum imsg_type {
        IMSG_DEBUG_UPDATE,
        IMSG_LOG,
        IMSG_ACL_CHECK,
-       IMSG_GET_LABEL_CHUNK,
-       IMSG_RELEASE_LABEL_CHUNK
+       IMSG_INIT
+};
+
+struct ldpd_init {
+       char             user[256];
+       char             group[256];
+       char             ctl_sock_path[MAXPATHLEN];
+       char             zclient_serv_path[MAXPATHLEN];
+       u_short          instance;
 };
 
 union ldpd_addr {
@@ -439,6 +446,12 @@ enum ldpd_process {
        PROC_LDE_ENGINE
 } ldpd_process;
 
+static const char * const log_procnames[] = {
+       "parent",
+       "ldpe",
+       "lde"
+};
+
 enum socket_type {
        LDP_SOCKET_DISC,
        LDP_SOCKET_EDISC,
@@ -504,7 +517,6 @@ struct ldpd_af_global {
 struct ldpd_global {
        int                      cmd_opts;
        int                      sighup;
-       time_t                   uptime;
        struct in_addr           rtr_id;
        struct ldpd_af_global    ipv4;
        struct ldpd_af_global    ipv6;
@@ -649,6 +661,7 @@ struct ctl_pw {
 
 extern struct ldpd_conf                *ldpd_conf, *vty_conf;
 extern struct ldpd_global       global;
+extern struct ldpd_init                 init;
 
 /* parse.y */
 struct ldpd_conf       *parse_config(char *);
@@ -762,6 +775,30 @@ int                 sock_set_ipv6_mcast_hops(int, int);
 int             sock_set_ipv6_mcast(struct iface *);
 int             sock_set_ipv6_mcast_loop(int);
 
+/* logmsg.h */
+struct in6_addr;
+union ldpd_addr;
+struct hello_source;
+struct fec;
+
+const char     *log_sockaddr(void *);
+const char     *log_in6addr(const struct in6_addr *);
+const char     *log_in6addr_scope(const struct in6_addr *, unsigned int);
+const char     *log_addr(int, const union ldpd_addr *);
+char           *log_label(uint32_t);
+const char     *log_time(time_t);
+char           *log_hello_src(const struct hello_source *);
+const char     *log_map(const struct map *);
+const char     *log_fec(const struct fec *);
+const char     *af_name(int);
+const char     *socket_name(int);
+const char     *nbr_state_name(int);
+const char     *if_state_name(int);
+const char     *if_type_name(enum iface_type);
+const char     *msg_name(uint16_t);
+const char     *status_code_name(uint32_t);
+const char     *pw_type_name(uint16_t);
+
 /* quagga */
 extern struct thread_master    *master;
 extern char                     ctl_sock_path[MAXPATHLEN];
index 1bec3d2a958cd08532db799f5390d71f7263c626..017eec2502c4145cf9bdfe5bc99d233d927e8bc9 100644 (file)
@@ -66,10 +66,6 @@ static zebra_capabilities_t _caps_p [] =
 
 struct zebra_privs_t ldpe_privs =
 {
-#if defined(FRR_USER) && defined(FRR_GROUP)
-       .user = FRR_USER,
-       .group = FRR_GROUP,
-#endif
 #if defined(VTY_GROUP)
        .vty_group = VTY_GROUP,
 #endif
@@ -103,46 +99,17 @@ static struct quagga_signal_t ldpe_signals[] =
 
 /* label distribution protocol engine */
 void
-ldpe(const char *user, const char *group, const char *ctl_path)
+ldpe(void)
 {
        struct thread            thread;
 
-       leconf = config_new_empty();
-
 #ifdef HAVE_SETPROCTITLE
        setproctitle("ldp engine");
 #endif
        ldpd_process = PROC_LDP_ENGINE;
-
-       LIST_INIT(&global.addr_list);
-       RB_INIT(&global.adj_tree);
-       TAILQ_INIT(&global.pending_conns);
-       if (inet_pton(AF_INET, AllRouters_v4, &global.mcast_addr_v4) != 1)
-               fatal("inet_pton");
-       if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1)
-               fatal("inet_pton");
-#ifdef __OpenBSD__
-       global.pfkeysock = pfkey_init();
-#endif
-
-       /* drop privileges */
-       if (user)
-               ldpe_privs.user = user;
-       if (group)
-               ldpe_privs.group = group;
-       zprivs_init(&ldpe_privs);
-
-       strlcpy(ctl_sock_path, ctl_path, sizeof(ctl_sock_path));
-       if (control_init() == -1)
-               fatalx("control socket setup failed");
-
-#ifdef HAVE_PLEDGE
-       if (pledge("stdio cpath inet mcast recvfd", NULL) == -1)
-               fatal("pledge");
-#endif
+       log_procname = log_procnames[ldpd_process];
 
        master = thread_master_create();
-       accept_init();
 
        /* setup signal handler */
        signal_init(master, array_size(ldpe_signals), ldpe_signals);
@@ -160,7 +127,43 @@ ldpe(const char *user, const char *group, const char *ctl_path)
                fatal(NULL);
        imsg_init(&iev_main_sync->ibuf, LDPD_FD_SYNC);
 
+       /* create base configuration */
+       leconf = config_new_empty();
+
+       /* Fetch next active thread. */
+       while (thread_fetch(master, &thread))
+               thread_call(&thread);
+}
+
+void
+ldpe_init(struct ldpd_init *init)
+{
+       /* drop privileges */
+       ldpe_privs.user = init->user;
+       ldpe_privs.group = init->group;
+       zprivs_init(&ldpe_privs);
+
+       /* listen on ldpd control socket */
+       strlcpy(ctl_sock_path, init->ctl_sock_path, sizeof(ctl_sock_path));
+       if (control_init(ctl_sock_path) == -1)
+               fatalx("control socket setup failed");
+       TAILQ_INIT(&ctl_conns);
+       control_listen();
+
+#ifdef HAVE_PLEDGE
+       if (pledge("stdio cpath inet mcast recvfd", NULL) == -1)
+               fatal("pledge");
+#endif
+
+       LIST_INIT(&global.addr_list);
+       RB_INIT(&global.adj_tree);
+       TAILQ_INIT(&global.pending_conns);
+       if (inet_pton(AF_INET, AllRouters_v4, &global.mcast_addr_v4) != 1)
+               fatal("inet_pton");
+       if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1)
+               fatal("inet_pton");
 #ifdef __OpenBSD__
+       global.pfkeysock = pfkey_init();
        if (sysdep.no_pfkey == 0)
                pfkey_ev = thread_add_read(master, ldpe_dispatch_pfkey,
                    NULL, global.pfkeysock);
@@ -174,16 +177,10 @@ ldpe(const char *user, const char *group, const char *ctl_path)
        global.ipv6.ldp_edisc_socket = -1;
        global.ipv6.ldp_session_socket = -1;
 
-       /* listen on ldpd control socket */
-       TAILQ_INIT(&ctl_conns);
-       control_listen();
-
        if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL)
                fatal(__func__);
 
-       /* Fetch next active thread. */
-       while (thread_fetch(master, &thread))
-               thread_call(&thread);
+       accept_init();
 }
 
 static void
@@ -193,16 +190,18 @@ ldpe_shutdown(void)
        struct adj              *adj;
 
        /* close pipes */
-       msgbuf_write(&iev_lde->ibuf.w);
-       msgbuf_clear(&iev_lde->ibuf.w);
-       close(iev_lde->ibuf.fd);
+       if (iev_lde) {
+               msgbuf_write(&iev_lde->ibuf.w);
+               msgbuf_clear(&iev_lde->ibuf.w);
+               close(iev_lde->ibuf.fd);
+       }
        msgbuf_write(&iev_main->ibuf.w);
        msgbuf_clear(&iev_main->ibuf.w);
        close(iev_main->ibuf.fd);
        msgbuf_clear(&iev_main_sync->ibuf.w);
        close(iev_main_sync->ibuf.fd);
 
-       control_cleanup();
+       control_cleanup(ctl_sock_path);
        config_clear(leconf);
 
 #ifdef __OpenBSD__
@@ -223,7 +222,8 @@ ldpe_shutdown(void)
                adj_del(adj, S_SHUTDOWN);
 
        /* clean up */
-       free(iev_lde);
+       if (iev_lde)
+               free(iev_lde);
        free(iev_main);
        free(iev_main_sync);
        free(pkt_ptr);
@@ -239,6 +239,13 @@ ldpe_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen)
        return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
 }
 
+void
+ldpe_imsg_compose_parent_sync(int type, pid_t pid, void *data, uint16_t datalen)
+{
+       imsg_compose_event(iev_main_sync, type, 0, pid, -1, data, datalen);
+       imsg_flush(&iev_main_sync->ibuf);
+}
+
 int
 ldpe_imsg_compose_lde(int type, uint32_t peerid, pid_t pid, void *data,
     uint16_t datalen)
@@ -351,6 +358,14 @@ ldpe_dispatch_main(struct thread *thread)
                        iev_lde->handler_write = ldp_write_handler;
                        iev_lde->ev_write = NULL;
                        break;
+               case IMSG_INIT:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct ldpd_init))
+                               fatalx("INIT imsg with wrong len");
+
+                       memcpy(&init, imsg.data, sizeof(init));
+                       ldpe_init(&init);
+                       break;
                case IMSG_CLOSE_SOCKETS:
                        af = imsg.hdr.peerid;
 
index a3f41a8b9fa12f1914fb59e0d1eb1a8e2c10c97e..d34ca4dc246542a09be32d0696f88e78e0aea1b1 100644 (file)
@@ -195,9 +195,11 @@ int         tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *,
            uint16_t, struct map *);
 
 /* ldpe.c */
-void            ldpe(const char *, const char *, const char *);
+void            ldpe(void);
+void            ldpe_init(struct ldpd_init *);
 int             ldpe_imsg_compose_parent(int, pid_t, void *,
                    uint16_t);
+void            ldpe_imsg_compose_parent_sync(int, pid_t, void *, uint16_t);
 int             ldpe_imsg_compose_lde(int, uint32_t, pid_t, void *,
                    uint16_t);
 int             ldpe_acl_check(char *, int, union ldpd_addr *, uint8_t);
index 407668bb03763f2f7505c5dd21dbcb2887043986..b138e5754aa7762890c3e6d124c722718368024c 100644 (file)
 
 #include <lib/log.h>
 #include <lib/log_int.h>
-#include "mpls.h"
 
-static const char * const procnames[] = {
-       "parent",
-       "ldpe",
-       "lde"
-};
-
-void            vlog(int, const char *, va_list);
+const char     *log_procname;
 
 void
 logit(int pri, const char *fmt, ...)
@@ -53,11 +46,13 @@ vlog(int pri, const char *fmt, va_list ap)
        switch (ldpd_process) {
        case PROC_LDE_ENGINE:
                vsnprintf(buf, sizeof(buf), fmt, ap);
-               lde_imsg_compose_parent(IMSG_LOG, pri, buf, strlen(buf) + 1);
+               lde_imsg_compose_parent_sync(IMSG_LOG, pri, buf,
+                   strlen(buf) + 1);
                break;
        case PROC_LDP_ENGINE:
                vsnprintf(buf, sizeof(buf), fmt, ap);
-               ldpe_imsg_compose_parent(IMSG_LOG, pri, buf, strlen(buf) + 1);
+               ldpe_imsg_compose_parent_sync(IMSG_LOG, pri, buf,
+                   strlen(buf) + 1);
                break;
        case PROC_MAIN:
                vzlog(pri, fmt, ap);
@@ -73,16 +68,16 @@ log_warn(const char *emsg, ...)
 
        /* best effort to even work in out of memory situations */
        if (emsg == NULL)
-               logit(LOG_CRIT, "%s", strerror(errno));
+               logit(LOG_ERR, "%s", strerror(errno));
        else {
                va_start(ap, emsg);
 
                if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) {
                        /* we tried it... */
-                       vlog(LOG_CRIT, emsg, ap);
-                       logit(LOG_CRIT, "%s", strerror(errno));
+                       vlog(LOG_ERR, emsg, ap);
+                       logit(LOG_ERR, "%s", strerror(errno));
                } else {
-                       vlog(LOG_CRIT, nfmt, ap);
+                       vlog(LOG_ERR, nfmt, ap);
                        free(nfmt);
                }
                va_end(ap);
@@ -95,7 +90,7 @@ log_warnx(const char *emsg, ...)
        va_list  ap;
 
        va_start(ap, emsg);
-       vlog(LOG_CRIT, emsg, ap);
+       vlog(LOG_ERR, emsg, ap);
        va_end(ap);
 }
 
@@ -133,15 +128,15 @@ void
 fatal(const char *emsg)
 {
        if (emsg == NULL)
-               logit(LOG_CRIT, "fatal in %s: %s", procnames[ldpd_process],
+               logit(LOG_CRIT, "fatal in %s: %s", log_procname,
                    strerror(errno));
        else
                if (errno)
                        logit(LOG_CRIT, "fatal in %s: %s: %s",
-                           procnames[ldpd_process], emsg, strerror(errno));
+                           log_procname, emsg, strerror(errno));
                else
                        logit(LOG_CRIT, "fatal in %s: %s",
-                           procnames[ldpd_process], emsg);
+                           log_procname, emsg);
 
        exit(1);
 }
@@ -152,465 +147,3 @@ fatalx(const char *emsg)
        errno = 0;
        fatal(emsg);
 }
-
-#define NUM_LOGS       4
-const char *
-log_sockaddr(void *vp)
-{
-       static char      buf[NUM_LOGS][NI_MAXHOST];
-       static int       round = 0;
-       struct sockaddr *sa = vp;
-
-       round = (round + 1) % NUM_LOGS;
-
-       if (getnameinfo(sa, sockaddr_len(sa), buf[round], NI_MAXHOST, NULL, 0,
-           NI_NUMERICHOST))
-               return ("(unknown)");
-       else
-               return (buf[round]);
-}
-
-const char *
-log_in6addr(const struct in6_addr *addr)
-{
-       struct sockaddr_in6     sa_in6;
-
-       memset(&sa_in6, 0, sizeof(sa_in6));
-#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
-       sa_in6.sin6_len = sizeof(sa_in6);
-#endif
-       sa_in6.sin6_family = AF_INET6;
-       sa_in6.sin6_addr = *addr;
-
-       recoverscope(&sa_in6);
-
-       return (log_sockaddr(&sa_in6));
-}
-
-const char *
-log_in6addr_scope(const struct in6_addr *addr, unsigned int ifindex)
-{
-       struct sockaddr_in6     sa_in6;
-
-       memset(&sa_in6, 0, sizeof(sa_in6));
-#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
-       sa_in6.sin6_len = sizeof(sa_in6);
-#endif
-       sa_in6.sin6_family = AF_INET6;
-       sa_in6.sin6_addr = *addr;
-
-       addscope(&sa_in6, ifindex);
-
-       return (log_sockaddr(&sa_in6));
-}
-
-const char *
-log_addr(int af, const union ldpd_addr *addr)
-{
-       static char      buf[NUM_LOGS][INET6_ADDRSTRLEN];
-       static int       round = 0;
-
-       switch (af) {
-       case AF_INET:
-               round = (round + 1) % NUM_LOGS;
-               if (inet_ntop(AF_INET, &addr->v4, buf[round],
-                   sizeof(buf[round])) == NULL)
-                       return ("???");
-               return (buf[round]);
-       case AF_INET6:
-               return (log_in6addr(&addr->v6));
-       default:
-               break;
-       }
-
-       return ("???");
-}
-
-#define        TF_BUFS 4
-#define        TF_LEN  32
-
-char *
-log_label(uint32_t label)
-{
-       char            *buf;
-       static char      tfbuf[TF_BUFS][TF_LEN];        /* ring buffer */
-       static int       idx = 0;
-
-       buf = tfbuf[idx++];
-       if (idx == TF_BUFS)
-               idx = 0;
-
-       switch (label) {
-       case NO_LABEL:
-               snprintf(buf, TF_LEN, "-");
-               break;
-       case MPLS_LABEL_IMPLNULL:
-               snprintf(buf, TF_LEN, "imp-null");
-               break;
-       case MPLS_LABEL_IPV4NULL:
-       case MPLS_LABEL_IPV6NULL:
-               snprintf(buf, TF_LEN, "exp-null");
-               break;
-       default:
-               snprintf(buf, TF_LEN, "%u", label);
-               break;
-       }
-
-       return (buf);
-}
-
-const char *
-log_time(time_t t)
-{
-       char            *buf;
-       static char      tfbuf[TF_BUFS][TF_LEN];        /* ring buffer */
-       static int       idx = 0;
-       unsigned int     sec, min, hrs, day, week;
-
-       buf = tfbuf[idx++];
-       if (idx == TF_BUFS)
-               idx = 0;
-
-       week = t;
-
-       sec = week % 60;
-       week /= 60;
-       min = week % 60;
-       week /= 60;
-       hrs = week % 24;
-       week /= 24;
-       day = week % 7;
-       week /= 7;
-
-       if (week > 0)
-               snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs);
-       else if (day > 0)
-               snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
-       else
-               snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
-
-       return (buf);
-}
-
-char *
-log_hello_src(const struct hello_source *src)
-{
-       static char buf[64];
-
-       switch (src->type) {
-       case HELLO_LINK:
-               snprintf(buf, sizeof(buf), "iface %s",
-                   src->link.ia->iface->name);
-               break;
-       case HELLO_TARGETED:
-               snprintf(buf, sizeof(buf), "source %s",
-                   log_addr(src->target->af, &src->target->addr));
-               break;
-       }
-
-       return (buf);
-}
-
-const char *
-log_map(const struct map *map)
-{
-       static char     buf[128];
-
-       switch (map->type) {
-       case MAP_TYPE_WILDCARD:
-               if (snprintf(buf, sizeof(buf), "wildcard") < 0)
-                       return ("???");
-               break;
-       case MAP_TYPE_PREFIX:
-               if (snprintf(buf, sizeof(buf), "%s/%u",
-                   log_addr(map->fec.prefix.af, &map->fec.prefix.prefix),
-                   map->fec.prefix.prefixlen) == -1)
-                       return ("???");
-               break;
-       case MAP_TYPE_PWID:
-               if (snprintf(buf, sizeof(buf), "pw-id %u group-id %u (%s)",
-                   map->fec.pwid.pwid, map->fec.pwid.group_id,
-                   pw_type_name(map->fec.pwid.type)) == -1)
-                       return ("???");
-               break;
-       case MAP_TYPE_TYPED_WCARD:
-               if (snprintf(buf, sizeof(buf), "typed wildcard") < 0)
-                       return ("???");
-               switch (map->fec.twcard.type) {
-               case MAP_TYPE_PREFIX:
-                       if (snprintf(buf + strlen(buf), sizeof(buf) -
-                           strlen(buf), " (prefix, address-family %s)",
-                           af_name(map->fec.twcard.u.prefix_af)) < 0)
-                               return ("???");
-                       break;
-               case MAP_TYPE_PWID:
-                       if (snprintf(buf + strlen(buf), sizeof(buf) -
-                           strlen(buf), " (pwid, type %s)",
-                           pw_type_name(map->fec.twcard.u.pw_type)) < 0)
-                               return ("???");
-                       break;
-               default:
-                       if (snprintf(buf + strlen(buf), sizeof(buf) -
-                           strlen(buf), " (unknown type)") < 0)
-                               return ("???");
-                       break;
-               }
-               break;
-       default:
-               return ("???");
-       }
-
-       return (buf);
-}
-
-const char *
-log_fec(const struct fec *fec)
-{
-       static char     buf[64];
-       union ldpd_addr addr;
-
-       switch (fec->type) {
-       case FEC_TYPE_IPV4:
-               addr.v4 = fec->u.ipv4.prefix;
-               if (snprintf(buf, sizeof(buf), "ipv4 %s/%u",
-                   log_addr(AF_INET, &addr), fec->u.ipv4.prefixlen) == -1)
-                       return ("???");
-               break;
-       case FEC_TYPE_IPV6:
-               addr.v6 = fec->u.ipv6.prefix;
-               if (snprintf(buf, sizeof(buf), "ipv6 %s/%u",
-                   log_addr(AF_INET6, &addr), fec->u.ipv6.prefixlen) == -1)
-                       return ("???");
-               break;
-       case FEC_TYPE_PWID:
-               if (snprintf(buf, sizeof(buf),
-                   "pwid %u (%s) - %s",
-                   fec->u.pwid.pwid, pw_type_name(fec->u.pwid.type),
-                   inet_ntoa(fec->u.pwid.lsr_id)) == -1)
-                       return ("???");
-               break;
-       default:
-               return ("???");
-       }
-
-       return (buf);
-}
-
-/* names */
-const char *
-af_name(int af)
-{
-       switch (af) {
-       case AF_INET:
-               return ("ipv4");
-       case AF_INET6:
-               return ("ipv6");
-#ifdef AF_MPLS
-       case AF_MPLS:
-               return ("mpls");
-#endif
-       default:
-               return ("UNKNOWN");
-       }
-}
-
-const char *
-socket_name(int type)
-{
-       switch (type) {
-       case LDP_SOCKET_DISC:
-               return ("discovery");
-       case LDP_SOCKET_EDISC:
-               return ("extended discovery");
-       case LDP_SOCKET_SESSION:
-               return ("session");
-       default:
-               return ("UNKNOWN");
-       }
-}
-
-const char *
-nbr_state_name(int state)
-{
-       switch (state) {
-       case NBR_STA_PRESENT:
-               return ("PRESENT");
-       case NBR_STA_INITIAL:
-               return ("INITIALIZED");
-       case NBR_STA_OPENREC:
-               return ("OPENREC");
-       case NBR_STA_OPENSENT:
-               return ("OPENSENT");
-       case NBR_STA_OPER:
-               return ("OPERATIONAL");
-       default:
-               return ("UNKNOWN");
-       }
-}
-
-const char *
-if_state_name(int state)
-{
-       switch (state) {
-       case IF_STA_DOWN:
-               return ("DOWN");
-       case IF_STA_ACTIVE:
-               return ("ACTIVE");
-       default:
-               return ("UNKNOWN");
-       }
-}
-
-const char *
-if_type_name(enum iface_type type)
-{
-       switch (type) {
-       case IF_TYPE_POINTOPOINT:
-               return ("POINTOPOINT");
-       case IF_TYPE_BROADCAST:
-               return ("BROADCAST");
-       }
-       /* NOTREACHED */
-       return ("UNKNOWN");
-}
-
-const char *
-msg_name(uint16_t msg)
-{
-       static char buf[16];
-
-       switch (msg) {
-       case MSG_TYPE_NOTIFICATION:
-               return ("notification");
-       case MSG_TYPE_HELLO:
-               return ("hello");
-       case MSG_TYPE_INIT:
-               return ("initialization");
-       case MSG_TYPE_KEEPALIVE:
-               return ("keepalive");
-       case MSG_TYPE_CAPABILITY:
-               return ("capability");
-       case MSG_TYPE_ADDR:
-               return ("address");
-       case MSG_TYPE_ADDRWITHDRAW:
-               return ("address withdraw");
-       case MSG_TYPE_LABELMAPPING:
-               return ("label mapping");
-       case MSG_TYPE_LABELREQUEST:
-               return ("label request");
-       case MSG_TYPE_LABELWITHDRAW:
-               return ("label withdraw");
-       case MSG_TYPE_LABELRELEASE:
-               return ("label release");
-       case MSG_TYPE_LABELABORTREQ:
-       default:
-               snprintf(buf, sizeof(buf), "[%08x]", msg);
-               return (buf);
-       }
-}
-
-const char *
-status_code_name(uint32_t status)
-{
-       static char buf[16];
-
-       switch (status) {
-       case S_SUCCESS:
-               return ("Success");
-       case S_BAD_LDP_ID:
-               return ("Bad LDP Identifier");
-       case S_BAD_PROTO_VER:
-               return ("Bad Protocol Version");
-       case S_BAD_PDU_LEN:
-               return ("Bad PDU Length");
-       case S_UNKNOWN_MSG:
-               return ("Unknown Message Type");
-       case S_BAD_MSG_LEN:
-               return ("Bad Message Length");
-       case S_UNKNOWN_TLV:
-               return ("Unknown TLV");
-       case S_BAD_TLV_LEN:
-               return ("Bad TLV Length");
-       case S_BAD_TLV_VAL:
-               return ("Malformed TLV Value");
-       case S_HOLDTIME_EXP:
-               return ("Hold Timer Expired");
-       case S_SHUTDOWN:
-               return ("Shutdown");
-       case S_LOOP_DETECTED:
-               return ("Loop Detected");
-       case S_UNKNOWN_FEC:
-               return ("Unknown FEC");
-       case S_NO_ROUTE:
-               return ("No Route");
-       case S_NO_LABEL_RES:
-               return ("No Label Resources");
-       case S_AVAILABLE:
-               return ("Label Resources Available");
-       case S_NO_HELLO:
-               return ("Session Rejected, No Hello");
-       case S_PARM_ADV_MODE:
-               return ("Rejected Advertisement Mode Parameter");
-       case S_MAX_PDU_LEN:
-               return ("Rejected Max PDU Length Parameter");
-       case S_PARM_L_RANGE:
-               return ("Rejected Label Range Parameter");
-       case S_KEEPALIVE_TMR:
-               return ("KeepAlive Timer Expired");
-       case S_LAB_REQ_ABRT:
-               return ("Label Request Aborted");
-       case S_MISS_MSG:
-               return ("Missing Message Parameters");
-       case S_UNSUP_ADDR:
-               return ("Unsupported Address Family");
-       case S_KEEPALIVE_BAD:
-               return ("Bad KeepAlive Time");
-       case S_INTERN_ERR:
-               return ("Internal Error");
-       case S_ILLEGAL_CBIT:
-               return ("Illegal C-Bit");
-       case S_WRONG_CBIT:
-               return ("Wrong C-Bit");
-       case S_INCPT_BITRATE:
-               return ("Incompatible bit-rate");
-       case S_CEP_MISCONF:
-               return ("CEP-TDM mis-configuration");
-       case S_PW_STATUS:
-               return ("PW Status");
-       case S_UNASSIGN_TAI:
-               return ("Unassigned/Unrecognized TAI");
-       case S_MISCONF_ERR:
-               return ("Generic Misconfiguration Error");
-       case S_WITHDRAW_MTHD:
-               return ("Label Withdraw PW Status Method");
-       case S_UNSSUPORTDCAP:
-               return ("Unsupported Capability");
-       case S_ENDOFLIB:
-               return ("End-of-LIB");
-       case S_TRANS_MISMTCH:
-               return ("Transport Connection Mismatch");
-       case S_DS_NONCMPLNCE:
-               return ("Dual-Stack Noncompliance");
-       default:
-               snprintf(buf, sizeof(buf), "[%08x]", status);
-               return (buf);
-       }
-}
-
-const char *
-pw_type_name(uint16_t pw_type)
-{
-       static char buf[64];
-
-       switch (pw_type) {
-       case PW_TYPE_ETHERNET_TAGGED:
-               return ("Eth Tagged");
-       case PW_TYPE_ETHERNET:
-               return ("Ethernet");
-       case PW_TYPE_WILDCARD:
-               return ("Wildcard");
-       default:
-               snprintf(buf, sizeof(buf), "[%0x]", pw_type);
-               return (buf);
-       }
-}
index 4d6da43cac9b6c6e411cdbf142e5434f6d350ad7..8c236ff5fe3f3bd3b0e95626fdeb89fac29d1b11 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#ifndef _LOG_H_
-#define        _LOG_H_
+#ifndef LOG_H
+#define LOG_H
 
 #include <stdarg.h>
 
-struct in6_addr;
-union ldpd_addr;
-struct hello_source;
-struct fec;
+extern const char      *log_procname;
 
-void            logit(int, const char *, ...)
-                       __attribute__((__format__ (printf, 2, 3)));
-void            log_warn(const char *, ...)
-                       __attribute__((__format__ (printf, 1, 2)));
-void            log_warnx(const char *, ...)
-                       __attribute__((__format__ (printf, 1, 2)));
-void            log_info(const char *, ...)
-                       __attribute__((__format__ (printf, 1, 2)));
-void            log_notice(const char *, ...)
-                       __attribute__((__format__ (printf, 1, 2)));
-void            log_debug(const char *, ...)
-                       __attribute__((__format__ (printf, 1, 2)));
-void            fatal(const char *)
-                       __attribute__ ((noreturn))
-                       __attribute__((__format__ (printf, 1, 0)));
-void            fatalx(const char *)
-                       __attribute__ ((noreturn))
-                       __attribute__((__format__ (printf, 1, 0)));
-const char     *log_sockaddr(void *);
-const char     *log_in6addr(const struct in6_addr *);
-const char     *log_in6addr_scope(const struct in6_addr *, unsigned int);
-const char     *log_addr(int, const union ldpd_addr *);
-char           *log_label(uint32_t);
-const char     *log_time(time_t);
-char           *log_hello_src(const struct hello_source *);
-const char     *log_map(const struct map *);
-const char     *log_fec(const struct fec *);
-const char     *af_name(int);
-const char     *socket_name(int);
-const char     *nbr_state_name(int);
-const char     *if_state_name(int);
-const char     *if_type_name(enum iface_type);
-const char     *msg_name(uint16_t);
-const char     *status_code_name(uint32_t);
-const char     *pw_type_name(uint16_t);
+void    logit(int, const char *, ...)
+               __attribute__((__format__ (printf, 2, 3)));
+void    vlog(int, const char *, va_list)
+               __attribute__((__format__ (printf, 2, 0)));
+void    log_warn(const char *, ...)
+               __attribute__((__format__ (printf, 1, 2)));
+void    log_warnx(const char *, ...)
+               __attribute__((__format__ (printf, 1, 2)));
+void    log_info(const char *, ...)
+               __attribute__((__format__ (printf, 1, 2)));
+void    log_notice(const char *, ...)
+               __attribute__((__format__ (printf, 1, 2)));
+void    log_debug(const char *, ...)
+               __attribute__((__format__ (printf, 1, 2)));
+void    fatal(const char *)
+               __attribute__ ((noreturn))
+               __attribute__((__format__ (printf, 1, 0)));
+void    fatalx(const char *)
+               __attribute__ ((noreturn))
+               __attribute__((__format__ (printf, 1, 0)));
 
-#endif /* _LOG_H_ */
+#endif /* LOG_H */
diff --git a/ldpd/logmsg.c b/ldpd/logmsg.c
new file mode 100644 (file)
index 0000000..c819b33
--- /dev/null
@@ -0,0 +1,487 @@
+/*     $OpenBSD$ */
+
+/*
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <zebra.h>
+
+#include "mpls.h"
+
+#include "ldpd.h"
+#include "ldpe.h"
+#include "lde.h"
+
+#define NUM_LOGS       4
+const char *
+log_sockaddr(void *vp)
+{
+       static char      buf[NUM_LOGS][NI_MAXHOST];
+       static int       round = 0;
+       struct sockaddr *sa = vp;
+
+       round = (round + 1) % NUM_LOGS;
+
+       if (getnameinfo(sa, sockaddr_len(sa), buf[round], NI_MAXHOST, NULL, 0,
+           NI_NUMERICHOST))
+               return ("(unknown)");
+       else
+               return (buf[round]);
+}
+
+const char *
+log_in6addr(const struct in6_addr *addr)
+{
+       struct sockaddr_in6     sa_in6;
+
+       memset(&sa_in6, 0, sizeof(sa_in6));
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+       sa_in6.sin6_len = sizeof(sa_in6);
+#endif
+       sa_in6.sin6_family = AF_INET6;
+       sa_in6.sin6_addr = *addr;
+
+       recoverscope(&sa_in6);
+
+       return (log_sockaddr(&sa_in6));
+}
+
+const char *
+log_in6addr_scope(const struct in6_addr *addr, unsigned int ifindex)
+{
+       struct sockaddr_in6     sa_in6;
+
+       memset(&sa_in6, 0, sizeof(sa_in6));
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+       sa_in6.sin6_len = sizeof(sa_in6);
+#endif
+       sa_in6.sin6_family = AF_INET6;
+       sa_in6.sin6_addr = *addr;
+
+       addscope(&sa_in6, ifindex);
+
+       return (log_sockaddr(&sa_in6));
+}
+
+const char *
+log_addr(int af, const union ldpd_addr *addr)
+{
+       static char      buf[NUM_LOGS][INET6_ADDRSTRLEN];
+       static int       round = 0;
+
+       switch (af) {
+       case AF_INET:
+               round = (round + 1) % NUM_LOGS;
+               if (inet_ntop(AF_INET, &addr->v4, buf[round],
+                   sizeof(buf[round])) == NULL)
+                       return ("???");
+               return (buf[round]);
+       case AF_INET6:
+               return (log_in6addr(&addr->v6));
+       default:
+               break;
+       }
+
+       return ("???");
+}
+
+#define        TF_BUFS 4
+#define        TF_LEN  32
+
+char *
+log_label(uint32_t label)
+{
+       char            *buf;
+       static char      tfbuf[TF_BUFS][TF_LEN];        /* ring buffer */
+       static int       idx = 0;
+
+       buf = tfbuf[idx++];
+       if (idx == TF_BUFS)
+               idx = 0;
+
+       switch (label) {
+       case NO_LABEL:
+               snprintf(buf, TF_LEN, "-");
+               break;
+       case MPLS_LABEL_IMPLNULL:
+               snprintf(buf, TF_LEN, "imp-null");
+               break;
+       case MPLS_LABEL_IPV4NULL:
+       case MPLS_LABEL_IPV6NULL:
+               snprintf(buf, TF_LEN, "exp-null");
+               break;
+       default:
+               snprintf(buf, TF_LEN, "%u", label);
+               break;
+       }
+
+       return (buf);
+}
+
+const char *
+log_time(time_t t)
+{
+       char            *buf;
+       static char      tfbuf[TF_BUFS][TF_LEN];        /* ring buffer */
+       static int       idx = 0;
+       unsigned int     sec, min, hrs, day, week;
+
+       buf = tfbuf[idx++];
+       if (idx == TF_BUFS)
+               idx = 0;
+
+       week = t;
+
+       sec = week % 60;
+       week /= 60;
+       min = week % 60;
+       week /= 60;
+       hrs = week % 24;
+       week /= 24;
+       day = week % 7;
+       week /= 7;
+
+       if (week > 0)
+               snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs);
+       else if (day > 0)
+               snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
+       else
+               snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
+
+       return (buf);
+}
+
+char *
+log_hello_src(const struct hello_source *src)
+{
+       static char buf[64];
+
+       switch (src->type) {
+       case HELLO_LINK:
+               snprintf(buf, sizeof(buf), "iface %s",
+                   src->link.ia->iface->name);
+               break;
+       case HELLO_TARGETED:
+               snprintf(buf, sizeof(buf), "source %s",
+                   log_addr(src->target->af, &src->target->addr));
+               break;
+       }
+
+       return (buf);
+}
+
+const char *
+log_map(const struct map *map)
+{
+       static char     buf[128];
+
+       switch (map->type) {
+       case MAP_TYPE_WILDCARD:
+               if (snprintf(buf, sizeof(buf), "wildcard") < 0)
+                       return ("???");
+               break;
+       case MAP_TYPE_PREFIX:
+               if (snprintf(buf, sizeof(buf), "%s/%u",
+                   log_addr(map->fec.prefix.af, &map->fec.prefix.prefix),
+                   map->fec.prefix.prefixlen) == -1)
+                       return ("???");
+               break;
+       case MAP_TYPE_PWID:
+               if (snprintf(buf, sizeof(buf), "pw-id %u group-id %u (%s)",
+                   map->fec.pwid.pwid, map->fec.pwid.group_id,
+                   pw_type_name(map->fec.pwid.type)) == -1)
+                       return ("???");
+               break;
+       case MAP_TYPE_TYPED_WCARD:
+               if (snprintf(buf, sizeof(buf), "typed wildcard") < 0)
+                       return ("???");
+               switch (map->fec.twcard.type) {
+               case MAP_TYPE_PREFIX:
+                       if (snprintf(buf + strlen(buf), sizeof(buf) -
+                           strlen(buf), " (prefix, address-family %s)",
+                           af_name(map->fec.twcard.u.prefix_af)) < 0)
+                               return ("???");
+                       break;
+               case MAP_TYPE_PWID:
+                       if (snprintf(buf + strlen(buf), sizeof(buf) -
+                           strlen(buf), " (pwid, type %s)",
+                           pw_type_name(map->fec.twcard.u.pw_type)) < 0)
+                               return ("???");
+                       break;
+               default:
+                       if (snprintf(buf + strlen(buf), sizeof(buf) -
+                           strlen(buf), " (unknown type)") < 0)
+                               return ("???");
+                       break;
+               }
+               break;
+       default:
+               return ("???");
+       }
+
+       return (buf);
+}
+
+const char *
+log_fec(const struct fec *fec)
+{
+       static char     buf[64];
+       union ldpd_addr addr;
+
+       switch (fec->type) {
+       case FEC_TYPE_IPV4:
+               addr.v4 = fec->u.ipv4.prefix;
+               if (snprintf(buf, sizeof(buf), "ipv4 %s/%u",
+                   log_addr(AF_INET, &addr), fec->u.ipv4.prefixlen) == -1)
+                       return ("???");
+               break;
+       case FEC_TYPE_IPV6:
+               addr.v6 = fec->u.ipv6.prefix;
+               if (snprintf(buf, sizeof(buf), "ipv6 %s/%u",
+                   log_addr(AF_INET6, &addr), fec->u.ipv6.prefixlen) == -1)
+                       return ("???");
+               break;
+       case FEC_TYPE_PWID:
+               if (snprintf(buf, sizeof(buf),
+                   "pwid %u (%s) - %s",
+                   fec->u.pwid.pwid, pw_type_name(fec->u.pwid.type),
+                   inet_ntoa(fec->u.pwid.lsr_id)) == -1)
+                       return ("???");
+               break;
+       default:
+               return ("???");
+       }
+
+       return (buf);
+}
+
+/* names */
+const char *
+af_name(int af)
+{
+       switch (af) {
+       case AF_INET:
+               return ("ipv4");
+       case AF_INET6:
+               return ("ipv6");
+#ifdef AF_MPLS
+       case AF_MPLS:
+               return ("mpls");
+#endif
+       default:
+               return ("UNKNOWN");
+       }
+}
+
+const char *
+socket_name(int type)
+{
+       switch (type) {
+       case LDP_SOCKET_DISC:
+               return ("discovery");
+       case LDP_SOCKET_EDISC:
+               return ("extended discovery");
+       case LDP_SOCKET_SESSION:
+               return ("session");
+       default:
+               return ("UNKNOWN");
+       }
+}
+
+const char *
+nbr_state_name(int state)
+{
+       switch (state) {
+       case NBR_STA_PRESENT:
+               return ("PRESENT");
+       case NBR_STA_INITIAL:
+               return ("INITIALIZED");
+       case NBR_STA_OPENREC:
+               return ("OPENREC");
+       case NBR_STA_OPENSENT:
+               return ("OPENSENT");
+       case NBR_STA_OPER:
+               return ("OPERATIONAL");
+       default:
+               return ("UNKNOWN");
+       }
+}
+
+const char *
+if_state_name(int state)
+{
+       switch (state) {
+       case IF_STA_DOWN:
+               return ("DOWN");
+       case IF_STA_ACTIVE:
+               return ("ACTIVE");
+       default:
+               return ("UNKNOWN");
+       }
+}
+
+const char *
+if_type_name(enum iface_type type)
+{
+       switch (type) {
+       case IF_TYPE_POINTOPOINT:
+               return ("POINTOPOINT");
+       case IF_TYPE_BROADCAST:
+               return ("BROADCAST");
+       }
+       /* NOTREACHED */
+       return ("UNKNOWN");
+}
+
+const char *
+msg_name(uint16_t msg)
+{
+       static char buf[16];
+
+       switch (msg) {
+       case MSG_TYPE_NOTIFICATION:
+               return ("notification");
+       case MSG_TYPE_HELLO:
+               return ("hello");
+       case MSG_TYPE_INIT:
+               return ("initialization");
+       case MSG_TYPE_KEEPALIVE:
+               return ("keepalive");
+       case MSG_TYPE_CAPABILITY:
+               return ("capability");
+       case MSG_TYPE_ADDR:
+               return ("address");
+       case MSG_TYPE_ADDRWITHDRAW:
+               return ("address withdraw");
+       case MSG_TYPE_LABELMAPPING:
+               return ("label mapping");
+       case MSG_TYPE_LABELREQUEST:
+               return ("label request");
+       case MSG_TYPE_LABELWITHDRAW:
+               return ("label withdraw");
+       case MSG_TYPE_LABELRELEASE:
+               return ("label release");
+       case MSG_TYPE_LABELABORTREQ:
+       default:
+               snprintf(buf, sizeof(buf), "[%08x]", msg);
+               return (buf);
+       }
+}
+
+const char *
+status_code_name(uint32_t status)
+{
+       static char buf[16];
+
+       switch (status) {
+       case S_SUCCESS:
+               return ("Success");
+       case S_BAD_LDP_ID:
+               return ("Bad LDP Identifier");
+       case S_BAD_PROTO_VER:
+               return ("Bad Protocol Version");
+       case S_BAD_PDU_LEN:
+               return ("Bad PDU Length");
+       case S_UNKNOWN_MSG:
+               return ("Unknown Message Type");
+       case S_BAD_MSG_LEN:
+               return ("Bad Message Length");
+       case S_UNKNOWN_TLV:
+               return ("Unknown TLV");
+       case S_BAD_TLV_LEN:
+               return ("Bad TLV Length");
+       case S_BAD_TLV_VAL:
+               return ("Malformed TLV Value");
+       case S_HOLDTIME_EXP:
+               return ("Hold Timer Expired");
+       case S_SHUTDOWN:
+               return ("Shutdown");
+       case S_LOOP_DETECTED:
+               return ("Loop Detected");
+       case S_UNKNOWN_FEC:
+               return ("Unknown FEC");
+       case S_NO_ROUTE:
+               return ("No Route");
+       case S_NO_LABEL_RES:
+               return ("No Label Resources");
+       case S_AVAILABLE:
+               return ("Label Resources Available");
+       case S_NO_HELLO:
+               return ("Session Rejected, No Hello");
+       case S_PARM_ADV_MODE:
+               return ("Rejected Advertisement Mode Parameter");
+       case S_MAX_PDU_LEN:
+               return ("Rejected Max PDU Length Parameter");
+       case S_PARM_L_RANGE:
+               return ("Rejected Label Range Parameter");
+       case S_KEEPALIVE_TMR:
+               return ("KeepAlive Timer Expired");
+       case S_LAB_REQ_ABRT:
+               return ("Label Request Aborted");
+       case S_MISS_MSG:
+               return ("Missing Message Parameters");
+       case S_UNSUP_ADDR:
+               return ("Unsupported Address Family");
+       case S_KEEPALIVE_BAD:
+               return ("Bad KeepAlive Time");
+       case S_INTERN_ERR:
+               return ("Internal Error");
+       case S_ILLEGAL_CBIT:
+               return ("Illegal C-Bit");
+       case S_WRONG_CBIT:
+               return ("Wrong C-Bit");
+       case S_INCPT_BITRATE:
+               return ("Incompatible bit-rate");
+       case S_CEP_MISCONF:
+               return ("CEP-TDM mis-configuration");
+       case S_PW_STATUS:
+               return ("PW Status");
+       case S_UNASSIGN_TAI:
+               return ("Unassigned/Unrecognized TAI");
+       case S_MISCONF_ERR:
+               return ("Generic Misconfiguration Error");
+       case S_WITHDRAW_MTHD:
+               return ("Label Withdraw PW Status Method");
+       case S_UNSSUPORTDCAP:
+               return ("Unsupported Capability");
+       case S_ENDOFLIB:
+               return ("End-of-LIB");
+       case S_TRANS_MISMTCH:
+               return ("Transport Connection Mismatch");
+       case S_DS_NONCMPLNCE:
+               return ("Dual-Stack Noncompliance");
+       default:
+               snprintf(buf, sizeof(buf), "[%08x]", status);
+               return (buf);
+       }
+}
+
+const char *
+pw_type_name(uint16_t pw_type)
+{
+       static char buf[64];
+
+       switch (pw_type) {
+       case PW_TYPE_ETHERNET_TAGGED:
+               return ("Eth Tagged");
+       case PW_TYPE_ETHERNET:
+               return ("Ethernet");
+       case PW_TYPE_WILDCARD:
+               return ("Wildcard");
+       default:
+               snprintf(buf, sizeof(buf), "[%0x]", pw_type);
+               return (buf);
+       }
+}
index f10faa4a54b3bcf06b602388a86cabed616f09b5..4a5f3c8fa4bbc9ad2081c184b6c42d413d6837ef 100644 (file)
@@ -237,6 +237,16 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
                if (nbr->state == NBR_STA_OPENSENT)
                        nbr_start_idtimer(nbr);
 
+               /*
+                * RFC 5036 - Section 3.5.1.1:
+                * "When an LSR receives a Shutdown message during session
+                * initialization, it SHOULD transmit a Shutdown message and
+                * then close the transport connection".
+                */
+               if (nbr->state != NBR_STA_OPER && nm.status_code == S_SHUTDOWN)
+                       send_notification(nbr->tcp, S_SHUTDOWN,
+                           msg.id, msg.type);
+
                nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
                return (-1);
        }
index 46893b992bd5b2e2d0f193e47dc4c1613c4541f8..df6bd8e57a8849cc6b9654370bf624909680dd04 100644 (file)
@@ -27,7 +27,7 @@
 #include "sockopt.h"
 
 static struct iface            *disc_find_iface(unsigned int, int,
-                                   union ldpd_addr *, int);
+                                   union ldpd_addr *);
 static int                      session_read(struct thread *);
 static int                      session_write(struct thread *);
 static ssize_t                  session_get_pdu(struct ibuf_read *, char **);
@@ -134,7 +134,7 @@ disc_recv_packet(struct thread *thread)
        int                      af;
        union ldpd_addr          src;
        unsigned int             ifindex = 0;
-       struct iface            *iface;
+       struct iface            *iface = NULL;
        uint16_t                 len;
        struct ldp_hdr           ldp_hdr;
        uint16_t                 pdu_len;
@@ -212,9 +212,11 @@ disc_recv_packet(struct thread *thread)
        ifindex = getsockopt_ifindex(af, &m);
 
        /* find a matching interface */
-       iface = disc_find_iface(ifindex, af, &src, multicast);
-       if (iface == NULL)
-               return (0);
+       if (multicast) {
+               iface = disc_find_iface(ifindex, af, &src);
+               if (iface == NULL)
+                       return (0);
+       }
 
        /* check packet size */
        len = (uint16_t)r;
@@ -280,8 +282,7 @@ disc_recv_packet(struct thread *thread)
 }
 
 static struct iface *
-disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src,
-    int multicast)
+disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src)
 {
        struct iface    *iface;
        struct iface_af *ia;
@@ -299,7 +300,7 @@ disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src,
         * "Link-local IPv6 address MUST be used as the source IP address in
         * IPv6 LDP Link Hellos".
         */
-       if (multicast && af == AF_INET6 && !IN6_IS_ADDR_LINKLOCAL(&src->v6))
+       if (af == AF_INET6 && !IN6_IS_ADDR_LINKLOCAL(&src->v6))
                return (NULL);
 
        return (iface);
@@ -519,6 +520,8 @@ session_read(struct thread *thread)
                                        return (0);
                                }
                                break;
+                       case MSG_TYPE_NOTIFICATION:
+                               break;
                        default:
                                if (nbr->state != NBR_STA_OPER) {
                                        session_shutdown(nbr, S_SHUTDOWN,
@@ -661,8 +664,6 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id,
        case NBR_STA_OPENREC:
        case NBR_STA_OPENSENT:
        case NBR_STA_OPER:
-               log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
-
                send_notification(nbr->tcp, status, msg_id, msg_type);
 
                nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
index 14b7130c8a8d796ccff52eb65c256fa968ef1f09..6e3c6d680d435e5b8ca41e0fbb7a0d59ede151da 100644 (file)
@@ -32,8 +32,10 @@ libfrr_la_SOURCES = \
        libfrr.c \
        strlcpy.c \
        strlcat.c \
+       sha256.c \
        module.c \
        hook.c \
+       frr_pthread.c \
        # end
 
 BUILT_SOURCES = route_types.h gitversion.h command_parse.h command_lex.h
@@ -54,6 +56,7 @@ libfrrsnmp_la_SOURCES = \
        #end
 
 pkginclude_HEADERS = \
+       frratomic.h \
        buffer.h checksum.h filter.h getopt.h hash.h \
        if.h linklist.h log.h \
        graph.h command_match.h \
@@ -73,6 +76,8 @@ pkginclude_HEADERS = \
        module.h \
        hook.h \
        libfrr.h \
+       sha256.h \
+       frr_pthread.h \
        # end
 
 noinst_HEADERS = \
index 11d5c9385d103f51f549ed6f2f9dc53293589376..e1d8b5404317e8dd1d767523b17f16302951a380 100644 (file)
@@ -134,7 +134,8 @@ agentx_events_update(void)
 static struct cmd_node agentx_node =
 {
   SMUX_NODE,
-  ""                            /* AgentX has no interface. */
+  "",                           /* AgentX has no interface. */
+  1
 };
 
 /* Logging NetSNMP messages */
@@ -165,7 +166,7 @@ config_write_agentx (struct vty *vty)
 {
   if (agentx_enabled)
       vty_out (vty, "agentx%s", VTY_NEWLINE);
-  return 0;
+  return 1;
 }
 
 DEFUN (agentx_enable,
@@ -183,7 +184,7 @@ DEFUN (agentx_enable,
       return CMD_SUCCESS;
     }
   vty_out (vty, "SNMP AgentX already enabled%s", VTY_NEWLINE);
-  return CMD_WARNING;
+  return CMD_SUCCESS;
 }
 
 DEFUN (no_agentx,
index 43b2c478a03fafe6487c630708a4ece0ea0cb043..11c9a0968bcf9ca3181440f185c861f02427edb7 100644 (file)
@@ -1055,9 +1055,11 @@ node_parent ( enum node_type node )
     case BGP_VNC_L2_GROUP_NODE:
     case BGP_IPV4_NODE:
     case BGP_IPV4M_NODE:
+    case BGP_IPV4L_NODE:
     case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:
     case BGP_EVPN_NODE:
+    case BGP_IPV6L_NODE:
       ret = BGP_NODE;
       break;
     case KEYCHAIN_KEY_NODE:
@@ -1399,6 +1401,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:
@@ -1414,6 +1417,7 @@ cmd_exit (struct vty *vty)
       break;
     case BGP_IPV4_NODE:
     case BGP_IPV4M_NODE:
+    case BGP_IPV4L_NODE:
     case BGP_VPNV4_NODE:
     case BGP_VPNV6_NODE:
     case BGP_ENCAP_NODE:
@@ -1425,6 +1429,7 @@ cmd_exit (struct vty *vty)
     case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:
     case BGP_EVPN_NODE:
+    case BGP_IPV6L_NODE:
       vty->node = BGP_NODE;
       break;
     case LDP_IPV4_NODE:
@@ -1480,6 +1485,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:
@@ -1491,9 +1497,11 @@ DEFUN (config_end,
     case BGP_VPNV6_NODE:
     case BGP_IPV4_NODE:
     case BGP_IPV4M_NODE:
+    case BGP_IPV4L_NODE:
     case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:
     case BGP_EVPN_NODE:
+    case BGP_IPV6L_NODE:
     case RMAP_NODE:
     case OSPF_NODE:
     case OSPF6_NODE:
index d62f7655eed8cf65ee108e0e0ba51e84655a8609..8f6abc85baf519b57431111aa71e96f1356bbdb6 100644 (file)
@@ -91,13 +91,16 @@ 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. */
   BGP_IPV4_NODE,                /* BGP IPv4 unicast address family.  */
   BGP_IPV4M_NODE,               /* BGP IPv4 multicast address family.  */
+  BGP_IPV4L_NODE,               /* BGP IPv4 labeled unicast address family.  */
   BGP_IPV6_NODE,                /* BGP IPv6 address family */
   BGP_IPV6M_NODE,               /* BGP IPv6 multicast address family. */
+  BGP_IPV6L_NODE,               /* BGP IPv6 labeled unicast address family. */
   BGP_ENCAP_NODE,               /* BGP ENCAP SAFI */
   BGP_ENCAPV6_NODE,             /* BGP ENCAP SAFI */
   BGP_VRF_POLICY_NODE,          /* BGP VRF policy */
@@ -356,6 +359,7 @@ struct cmd_element
 #define REDIST_STR "Redistribute information from another routing protocol\n"
 #define CLEAR_STR "Reset functions\n"
 #define RIP_STR "RIP information\n"
+#define EIGRP_STR "EIGRP information\n"
 #define BGP_STR "BGP information\n"
 #define BGP_SOFT_STR "Soft reconfig inbound and outbound updates\n"
 #define BGP_SOFT_IN_STR "Send route-refresh unless using 'soft-reconfiguration inbound'\n"
index deec1757c28cf84049ceca2468c969f864cb0093..c020d193a12515b45671ae12c9cb6ff44ee01c84 100644 (file)
@@ -23,6 +23,9 @@
  */
 
 %{
+/* ignore harmless bug in old versions of flex */
+#pragma GCC diagnostic ignored "-Wsign-compare"
+
 #include "command_parse.h"
 
 #define YY_USER_ACTION yylloc->last_column += yyleng;
diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c
new file mode 100644 (file)
index 0000000..0408bca
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+  Utilities and interfaces for managing POSIX threads
+  Copyright (C) 2017  Cumulus Networks
+
+  This program 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 of the License, or
+  (at your option) any later version.
+
+  This program 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 this program; see the file COPYING; if not, write to the
+  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+  MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+#include <pthread.h>
+
+#include "frr_pthread.h"
+#include "memory.h"
+#include "hash.h"
+
+DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
+
+static unsigned int next_id = 0;
+
+/* Hash table of all frr_pthreads along with synchronization primitive(s) and
+ * hash table callbacks.
+ * ------------------------------------------------------------------------ */
+static struct hash *pthread_table;
+static pthread_mutex_t pthread_table_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+/* pthread_table->hash_cmp */
+static int pthread_table_hash_cmp(const void *value1, const void *value2)
+{
+        const struct frr_pthread *tq1 = value1;
+        const struct frr_pthread *tq2 = value2;
+
+        return (tq1->id == tq2->id);
+}
+
+/* pthread_table->hash_key */
+static unsigned int pthread_table_hash_key(void *value)
+{
+        return ((struct frr_pthread *)value)->id;
+}
+/* ------------------------------------------------------------------------ */
+
+void frr_pthread_init()
+{
+        pthread_mutex_lock(&pthread_table_mtx);
+        {
+                pthread_table =
+                    hash_create(pthread_table_hash_key, pthread_table_hash_cmp);
+        }
+        pthread_mutex_unlock(&pthread_table_mtx);
+}
+
+void frr_pthread_finish()
+{
+        pthread_mutex_lock(&pthread_table_mtx);
+        {
+                hash_clean(pthread_table, (void (*)(void *))frr_pthread_destroy);
+                hash_free(pthread_table);
+        }
+        pthread_mutex_unlock(&pthread_table_mtx);
+}
+
+struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
+                                    void *(*start_routine) (void *),
+                                    int (*stop_routine) (void **, struct frr_pthread *))
+{
+        static struct frr_pthread holder = { 0 };
+        struct frr_pthread *fpt = NULL;
+
+        pthread_mutex_lock(&pthread_table_mtx);
+        {
+                holder.id = id;
+
+                if (!hash_lookup(pthread_table, &holder)) {
+                        struct frr_pthread *fpt =
+                            XCALLOC(MTYPE_FRR_PTHREAD,
+                                    sizeof(struct frr_pthread));
+                        fpt->id = id;
+                        fpt->master = thread_master_create();
+                        fpt->start_routine = start_routine;
+                        fpt->stop_routine = stop_routine;
+                        fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
+
+                        hash_get(pthread_table, fpt, hash_alloc_intern);
+                }
+        }
+        pthread_mutex_unlock(&pthread_table_mtx);
+
+        return fpt;
+}
+
+void frr_pthread_destroy(struct frr_pthread *fpt)
+{
+        thread_master_free(fpt->master);
+        XFREE(MTYPE_FRR_PTHREAD, fpt->name);
+        XFREE(MTYPE_FRR_PTHREAD, fpt);
+}
+
+struct frr_pthread *frr_pthread_get(unsigned int id)
+{
+        static struct frr_pthread holder = { 0 };
+        struct frr_pthread *fpt;
+
+        pthread_mutex_lock(&pthread_table_mtx);
+        {
+                holder.id = id;
+                fpt = hash_lookup(pthread_table, &holder);
+        }
+        pthread_mutex_unlock(&pthread_table_mtx);
+
+        return fpt;
+}
+
+int frr_pthread_run(unsigned int id, const pthread_attr_t * attr, void *arg)
+{
+        struct frr_pthread *fpt = frr_pthread_get(id);
+        int ret;
+
+        if (!fpt)
+                return -1;
+
+        ret = pthread_create(&fpt->thread, attr, fpt->start_routine, arg);
+
+        /* Per pthread_create(3), the contents of fpt->thread are undefined if
+         * pthread_create() did not succeed. Reset this value to zero. */
+        if (ret < 0)
+                memset(&fpt->thread, 0x00, sizeof(fpt->thread));
+
+        return ret;
+}
+
+/**
+ * Calls the stop routine for the frr_pthread and resets any relevant fields.
+ *
+ * @param fpt - the frr_pthread to stop
+ * @param result - pointer to result pointer
+ * @return the return code from the stop routine
+ */
+static int frr_pthread_stop_actual(struct frr_pthread *fpt, void **result)
+{
+        int ret = (*fpt->stop_routine) (result, fpt);
+        memset(&fpt->thread, 0x00, sizeof(fpt->thread));
+        return ret;
+}
+
+int frr_pthread_stop(unsigned int id, void **result)
+{
+        struct frr_pthread *fpt = frr_pthread_get(id);
+        return frr_pthread_stop_actual(fpt, result);
+}
+
+/**
+ * Callback for hash_iterate to stop all frr_pthread's.
+ */
+static void frr_pthread_stop_all_iter(struct hash_backet *hb, void *arg)
+{
+        struct frr_pthread *fpt = hb->data;
+        frr_pthread_stop_actual(fpt, NULL);
+}
+
+void frr_pthread_stop_all()
+{
+        pthread_mutex_lock(&pthread_table_mtx);
+        {
+                hash_iterate(pthread_table, frr_pthread_stop_all_iter, NULL);
+        }
+        pthread_mutex_unlock(&pthread_table_mtx);
+}
+
+unsigned int frr_pthread_get_id()
+{
+        return next_id++;
+}
diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h
new file mode 100644 (file)
index 0000000..b495436
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+  Utilities and interfaces for managing POSIX threads
+  Copyright (C) 2017  Cumulus Networks
+
+  This program 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 of the License, or
+  (at your option) any later version.
+
+  This program 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 this program; see the file COPYING; if not, write to the
+  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+  MA 02110-1301 USA
+ */
+
+#ifndef _FRR_PTHREAD_H
+#define _FRR_PTHREAD_H
+
+#include <pthread.h>
+#include "thread.h"
+
+struct frr_pthread {
+
+        /* pthread id */
+        pthread_t thread;
+
+        /* frr thread identifier */
+        unsigned int id;
+
+        /* thread master for this pthread's thread.c event loop */
+        struct thread_master *master;
+
+        /* start routine */
+        void *(*start_routine) (void *);
+
+        /* stop routine */
+        int (*stop_routine) (void **, struct frr_pthread *);
+
+        /* the (hopefully descriptive) name of this thread */
+        char *name;
+};
+
+/* Initializes this module.
+ *
+ * Must be called before using any of the other functions.
+ */
+void frr_pthread_init(void);
+
+/* Uninitializes this module.
+ *
+ * Destroys all registered frr_pthread's and internal data structures.
+ *
+ * It is safe to call frr_pthread_init() after this function to reinitialize
+ * the module.
+ */
+void frr_pthread_finish(void);
+
+/* Creates a new frr_pthread.
+ *
+ * If the provided ID is already assigned to an existing frr_pthread, the
+ * return value will be NULL.
+ *
+ * @param name - the name of the thread. Doesn't have to be unique, but it
+ * probably should be. This value is copied and may be safely free'd upon
+ * return.
+ *
+ * @param id - the integral ID of the thread. MUST be unique. The caller may
+ * use this id to retrieve the thread.
+ *
+ * @param start_routine - start routine for the pthread, will be passed to
+ * pthread_create (see those docs for details)
+ *
+ * @param stop_routine - stop routine for the pthread, called to terminate the
+ * thread. This function should gracefully stop the pthread and clean up any
+ * thread-specific resources. The passed pointer is used to return a data
+ * result.
+ *
+ * @return the created frr_pthread upon success, or NULL upon failure
+ */
+struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
+                                    void *(*start_routine) (void *),
+                                    int (*stop_routine) (void **, struct frr_pthread *));
+
+/* Destroys an frr_pthread.
+ *
+ * Assumes that the associated pthread, if any, has already terminated.
+ *
+ * @param fpt - the frr_pthread to destroy
+ */
+void frr_pthread_destroy(struct frr_pthread *fpt);
+
+/* Gets an existing frr_pthread by its id.
+ *
+ * @return frr_thread associated with the provided id, or NULL on error
+ */
+struct frr_pthread *frr_pthread_get(unsigned int id);
+
+/* Creates a new pthread and binds it to a frr_pthread.
+ *
+ * This function is a wrapper for pthread_create. The first parameter is the
+ * frr_pthread to bind the created pthread to. All subsequent arguments are
+ * passed unmodified to pthread_create().
+ *
+ * This function returns the same code as pthread_create(). If the value is
+ * zero, the provided frr_pthread is bound to a running POSIX thread. If the
+ * value is less than zero, the provided frr_pthread is guaranteed to be a
+ * clean instance that may be susbsequently passed to frr_pthread_run().
+ *
+ * @param id - frr_pthread to bind the created pthread to
+ * @param attr - see pthread_create(3)
+ * @param arg - see pthread_create(3)
+ *
+ * @return see pthread_create(3)
+ */
+int frr_pthread_run(unsigned int id, const pthread_attr_t * attr, void *arg);
+
+/* Stops an frr_pthread with a result.
+ *
+ * @param id - frr_pthread to stop
+ * @param result - where to store the thread's result, if any. May be NULL if a
+ * result is not needed.
+ */
+int frr_pthread_stop(unsigned int id, void **result);
+
+/* Stops all frr_pthread's. */
+void frr_pthread_stop_all(void);
+
+/* Returns a unique identifier for use with frr_pthread_new().
+ *
+ * Internally, this is an integer that increments after each call to this
+ * function. Because the number of pthreads created should never exceed INT_MAX
+ * during the life of the program, there is no overflow protection. If by
+ * chance this function returns an ID which is already in use,
+ * frr_pthread_new() will fail when it is provided.
+ *
+ * @return unique identifier
+ */
+unsigned int frr_pthread_get_id(void);
+
+#endif /* _FRR_PTHREAD_H */
diff --git a/lib/frratomic.h b/lib/frratomic.h
new file mode 100644 (file)
index 0000000..183790a
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015-16  David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FRRATOMIC_H
+#define _FRRATOMIC_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef FRR_AUTOCONF_ATOMIC
+#error autoconf checks for atomic functions were not properly run
+#endif
+
+/* ISO C11 */
+#ifdef HAVE_STDATOMIC_H
+#include <stdatomic.h>
+
+/* gcc 4.7 and newer */
+#elif defined(HAVE___ATOMIC)
+
+#define _Atomic volatile
+
+#define memory_order_relaxed __ATOMIC_RELAXED
+#define memory_order_consume __ATOMIC_CONSUME
+#define memory_order_acquire __ATOMIC_ACQUIRE
+#define memory_order_release __ATOMIC_RELEASE
+#define memory_order_acq_rel __ATOMIC_ACQ_REL
+#define memory_order_seq_cst __ATOMIC_SEQ_CST
+
+#define atomic_load_explicit __atomic_load_n
+#define atomic_store_explicit __atomic_store_n
+#define atomic_exchange_explicit __atomic_exchange_n
+#define atomic_fetch_add_explicit __atomic_fetch_add
+#define atomic_fetch_sub_explicit __atomic_fetch_sub
+
+#define atomic_compare_exchange_weak_explicit(atom, expect, desire, mem1, mem2) \
+       __atomic_compare_exchange_n(atom, expect, desire, 1, mem1, mem2)
+
+/* gcc 4.1 and newer,
+ * clang 3.3 (possibly older)
+ *
+ * __sync_swap isn't in gcc's documentation, but clang has it
+ *
+ * note __sync_synchronize() 
+ */
+#elif defined(HAVE___SYNC)
+
+#define _Atomic volatile
+
+#define memory_order_relaxed 0
+#define memory_order_consume 0
+#define memory_order_acquire 0
+#define memory_order_release 0
+#define memory_order_acq_rel 0
+#define memory_order_seq_cst 0
+
+#define atomic_load_explicit(ptr, mem) \
+       ({ __sync_synchronize(); \
+          typeof(*ptr) rval = __sync_fetch_and_add((ptr), 0); \
+          __sync_synchronize(); rval; })
+#define atomic_store_explicit(ptr, val, mem) \
+       ({ __sync_synchronize(); \
+          *(ptr) = (val); \
+          __sync_synchronize(); (void)0; })
+#ifdef HAVE___SYNC_SWAP
+#define atomic_exchange_explicit(ptr, val, mem) \
+       ({ __sync_synchronize(); \
+          typeof(*ptr) rval = __sync_swap((ptr, val), 0); \
+          __sync_synchronize(); rval; })
+#else /* !HAVE___SYNC_SWAP */
+#define atomic_exchange_explicit(ptr, val, mem) \
+       ({ typeof(ptr) _ptr = (ptr); typeof(val) _val = (val); \
+          __sync_synchronize(); \
+          typeof(*ptr) old1, old2 = __sync_fetch_and_add(_ptr, 0); \
+          do { \
+               old1 = old2; \
+               old2 = __sync_val_compare_and_swap (_ptr, old1, _val); \
+          } while (old1 != old2); \
+          __sync_synchronize(); \
+          old2; \
+       })
+#endif /* !HAVE___SYNC_SWAP */
+#define atomic_fetch_add_explicit(ptr, val, mem) \
+       ({ __sync_synchronize(); \
+          typeof(*ptr) rval = __sync_fetch_and_add((ptr), (val)); \
+          __sync_synchronize(); rval; })
+#define atomic_fetch_sub_explicit(ptr, val, mem) \
+       ({ __sync_synchronize(); \
+          typeof(*ptr) rval = __sync_fetch_and_sub((ptr), (val)); \
+          __sync_synchronize(); rval; })
+
+#define atomic_compare_exchange_weak_explicit(atom, expect, desire, mem1, mem2) \
+       ({ typeof(atom) _atom = (atom); typeof(expect) _expect = (expect); \
+          typeof(desire) _desire = (desire); \
+          __sync_synchronize(); \
+          typeof(*atom) rval = __sync_val_compare_and_swap(_atom, *_expect, _desire); \
+          __sync_synchronize(); \
+          bool ret = (rval == *_expect); *_expect = rval; ret; })
+
+#else /* !HAVE___ATOMIC && !HAVE_STDATOMIC_H */
+#error no atomic functions...
+#endif
+
+#endif /* _FRRATOMIC_H */
index c7d4ca2d97fb201331cc6663213d267db47eb469..4460efca6e5f3548267b6c6728f232420daffb00 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -734,6 +734,17 @@ openzlog (const char *progname, const char *protoname, u_short instance,
 
   openlog (progname, syslog_flags, zl->facility);
   zlog_default = zl;
+
+#ifdef HAVE_GLIBC_BACKTRACE
+  /* work around backtrace() using lazily resolved dynamically linked
+   * symbols, which will otherwise cause funny breakage in the SEGV handler.
+   * (particularly, the dynamic linker can call malloc(), which uses locks
+   * in programs linked with -pthread, thus can deadlock.) */
+  void *bt[4];
+  backtrace (bt, array_size(bt));
+  free (backtrace_symbols (bt, 0));
+  backtrace_symbols_fd (bt, 0, 0);
+#endif
 }
 
 void
@@ -1047,6 +1058,8 @@ proto_redistnum(int afi, const char *s)
        return ZEBRA_ROUTE_STATIC;
       else if (strmatch (s, "rip"))
        return ZEBRA_ROUTE_RIP;
+      else if (strmatch (s, "eigrp"))
+        return ZEBRA_ROUTE_EIGRP;
       else if (strmatch (s, "ospf"))
        return ZEBRA_ROUTE_OSPF;
       else if (strmatch (s, "isis"))
index ad55366f64a15a040547b41666753f49222bb04f..c6207adb981f1ef32f9ab233608cb51c0caaa358 100644 (file)
@@ -27,119 +27,107 @@ struct memgroup **mg_insert = &mg_first;
 DEFINE_MGROUP(LIB, "libfrr")
 DEFINE_MTYPE(LIB, TMP, "Temporary memory")
 
-static inline void
-mt_count_alloc (struct memtype *mt, size_t size)
+static inline void mt_count_alloc(struct memtype *mt, size_t size)
 {
-  mt->n_alloc++;
+       size_t oldsize;
 
-  if (mt->size == 0)
-    mt->size = size;
-  else if (mt->size != size)
-    mt->size = SIZE_VAR;
+       atomic_fetch_add_explicit(&mt->n_alloc, 1, memory_order_relaxed);
+
+       oldsize = atomic_load_explicit(&mt->size, memory_order_relaxed);
+       if (oldsize == 0)
+               oldsize = atomic_exchange_explicit(&mt->size, size, memory_order_relaxed);
+       if (oldsize != 0 && oldsize != size && oldsize != SIZE_VAR)
+               atomic_store_explicit(&mt->size, SIZE_VAR, memory_order_relaxed);
 }
 
-static inline void
-mt_count_free (struct memtype *mt)
+static inline void mt_count_free(struct memtype *mt)
 {
-  assert(mt->n_alloc);
-  mt->n_alloc--;
+       assert(mt->n_alloc);
+       atomic_fetch_sub_explicit(&mt->n_alloc, 1, memory_order_relaxed);
 }
 
-static inline void *
-mt_checkalloc (struct memtype *mt, void *ptr, size_t size)
+static inline void *mt_checkalloc(struct memtype *mt, void *ptr, size_t size)
 {
-  if (__builtin_expect(ptr == NULL, 0))
-    {
-      memory_oom (size, mt->name);
-      return NULL;
-    }
-  mt_count_alloc (mt, size);
-  return ptr;
+       if (__builtin_expect(ptr == NULL, 0)) {
+               memory_oom(size, mt->name);
+               return NULL;
+       }
+       mt_count_alloc(mt, size);
+       return ptr;
 }
 
-void *
-qmalloc (struct memtype *mt, size_t size)
+void *qmalloc(struct memtype *mt, size_t size)
 {
-  return mt_checkalloc (mt, malloc (size), size);
+       return mt_checkalloc(mt, malloc(size), size);
 }
 
-void *
-qcalloc (struct memtype *mt, size_t size)
+void *qcalloc(struct memtype *mt, size_t size)
 {
-  return mt_checkalloc (mt, calloc (size, 1), size);
+       return mt_checkalloc(mt, calloc(size, 1), size);
 }
 
-void *
-qrealloc (struct memtype *mt, void *ptr, size_t size)
+void *qrealloc(struct memtype *mt, void *ptr, size_t size)
 {
-  if (ptr)
-    mt_count_free (mt);
-  return mt_checkalloc (mt, ptr ? realloc (ptr, size) : malloc (size), size);
+       if (ptr)
+               mt_count_free(mt);
+       return mt_checkalloc(mt, ptr ? realloc(ptr, size) : malloc(size), size);
 }
 
-void *
-qstrdup (struct memtype *mt, const char *str)
+void *qstrdup(struct memtype *mt, const char *str)
 {
-  return mt_checkalloc (mt, strdup (str), strlen (str) + 1);
+       return mt_checkalloc(mt, strdup(str), strlen(str) + 1);
 }
 
-void
-qfree (struct memtype *mt, void *ptr)
+void qfree(struct memtype *mt, void *ptr)
 {
-  if (ptr)
-    mt_count_free (mt);
-  free (ptr);
+       if (ptr)
+               mt_count_free(mt);
+       free(ptr);
 }
 
-int
-qmem_walk (qmem_walk_fn *func, void *arg)
+int qmem_walk(qmem_walk_fn *func, void *arg)
 {
-  struct memgroup *mg;
-  struct memtype *mt;
-  int rv;
-
-  for (mg = mg_first; mg; mg = mg->next)
-    {
-      if ((rv = func (arg, mg, NULL)))
-        return rv;
-      for (mt = mg->types; mt; mt = mt->next)
-        if ((rv = func (arg, mg, mt)))
-          return rv;
-    }
-  return 0;
+       struct memgroup *mg;
+       struct memtype *mt;
+       int rv;
+
+       for (mg = mg_first; mg; mg = mg->next) {
+               if ((rv = func(arg, mg, NULL)))
+                       return rv;
+               for (mt = mg->types; mt; mt = mt->next)
+                       if ((rv = func(arg, mg, mt)))
+                               return rv;
+       }
+       return 0;
 }
 
-struct exit_dump_args
-{
-  const char *prefix;
-  int error;
+struct exit_dump_args {
+       const char *prefix;
+       int error;
 };
 
-static int
-qmem_exit_walker (void *arg, struct memgroup *mg, struct memtype *mt)
+static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt)
 {
-  struct exit_dump_args *eda = arg;
-
-  if (!mt)
-    {
-      fprintf (stderr, "%s: showing active allocations in memory group %s\n",
-               eda->prefix, mg->name);
-    }
-  else if (mt->n_alloc)
-    {
-      char size[32];
-      eda->error++;
-      snprintf (size, sizeof (size), "%10zu", mt->size);
-      fprintf (stderr, "%s: memstats:  %-30s: %6zu * %s\n",
-               eda->prefix, mt->name, mt->n_alloc,
-               mt->size == SIZE_VAR ? "(variably sized)" : size);
-    }
-  return 0;
+       struct exit_dump_args *eda = arg;
+
+       if (!mt) {
+               fprintf(stderr, "%s: showing active allocations in "
+                               "memory group %s\n",
+                               eda->prefix, mg->name);
+
+       } else if (mt->n_alloc) {
+               char size[32];
+               eda->error++;
+               snprintf(size, sizeof(size), "%10zu", mt->size);
+               fprintf(stderr, "%s: memstats:  %-30s: %6zu * %s\n",
+                               eda->prefix, mt->name, mt->n_alloc,
+                               mt->size == SIZE_VAR ? "(variably sized)" : size);
+       }
+       return 0;
 }
 
-void
-log_memstats_stderr (const char *prefix)
+void log_memstats_stderr(const char *prefix)
 {
-  struct exit_dump_args eda = { .prefix = prefix, .error = 0 };
-  qmem_walk (qmem_exit_walker, &eda);
+       struct exit_dump_args eda = { .prefix = prefix, .error = 0 };
+       qmem_walk(qmem_exit_walker, &eda);
 }
index 477a6162dc45960aa0be35c66269a38227af33d6..9e8803a8b2a6dbc1881df66e050cfe83c2072c4a 100644 (file)
 #define _QUAGGA_MEMORY_H
 
 #include <stdlib.h>
+#include <frratomic.h>
 
 #define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
 
 #define SIZE_VAR ~0UL
-struct memtype
-{
-  struct memtype *next, **ref;
-  const char *name;
-  size_t n_alloc;
-  size_t size;
+struct memtype {
+       struct memtype *next, **ref;
+       const char *name;
+       _Atomic size_t n_alloc;
+       _Atomic size_t size;
 };
 
-struct memgroup
-{
-  struct memgroup *next, **ref;
-  struct memtype *types, **insert;
-  const char *name;
+struct memgroup {
+       struct memgroup *next, **ref;
+       struct memtype *types, **insert;
+       const char *name;
 };
 
 #if defined(__clang__)
@@ -82,14 +81,14 @@ struct memgroup
  *    DEFINE_MGROUP(MYDAEMON, "my daemon memory")
  *    DEFINE_MTYPE(MYDAEMON, MYDAEMON_COMMON,
  *                   "this mtype is used in multiple files in mydaemon")
- *    foo = qmalloc (MTYPE_MYDAEMON_COMMON, sizeof (*foo))
+ *    foo = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*foo))
  *
  *  mydaemon_io.c
- *    bar = qmalloc (MTYPE_MYDAEMON_COMMON, sizeof (*bar))
+ *    bar = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*bar))
  *
  *    DEFINE_MTYPE_STATIC(MYDAEMON, MYDAEMON_IO,
  *                          "this mtype is used only in this file")
- *    baz = qmalloc (MTYPE_MYDAEMON_IO, sizeof (*baz))
+ *    baz = qmalloc(MTYPE_MYDAEMON_IO, sizeof(*baz))
  *
  *  Note:  Naming conventions (MGROUP_ and MTYPE_ prefixes are enforced
  *         by not having these as part of the macro arguments)
@@ -155,15 +154,15 @@ DECLARE_MGROUP(LIB)
 DECLARE_MTYPE(TMP)
 
 
-extern void *qmalloc (struct memtype *mt, size_t size)
+extern void *qmalloc(struct memtype *mt, size_t size)
        __attribute__ ((malloc, _ALLOC_SIZE(2), nonnull (1) _RET_NONNULL));
-extern void *qcalloc (struct memtype *mt, size_t size)
+extern void *qcalloc(struct memtype *mt, size_t size)
        __attribute__ ((malloc, _ALLOC_SIZE(2), nonnull (1) _RET_NONNULL));
-extern void *qrealloc (struct memtype *mt, void *ptr, size_t size)
+extern void *qrealloc(struct memtype *mt, void *ptr, size_t size)
        __attribute__ ((_ALLOC_SIZE(3), nonnull (1) _RET_NONNULL));
 extern void *qstrdup (struct memtype *mt, const char *str)
        __attribute__ ((malloc, nonnull (1) _RET_NONNULL));
-extern void qfree (struct memtype *mt, void *ptr)
+extern void qfree(struct memtype *mt, void *ptr)
        __attribute__ ((nonnull (1)));
 
 #define XMALLOC(mtype, size)           qmalloc(mtype, size)
@@ -183,10 +182,10 @@ static inline size_t mtype_stats_alloc(struct memtype *mt)
  *
  * return value: 0: continue, !0: abort walk.  qmem_walk will return the
  * last value from qmem_walk_fn. */
-typedef int qmem_walk_fn (void *arg, struct memgroup *mg, struct memtype *mt);
-extern int qmem_walk (qmem_walk_fn *func, void *arg);
-extern void log_memstats_stderr (const char *);
+typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt);
+extern int qmem_walk(qmem_walk_fn *func, void *arg);
+extern void log_memstats_stderr(const char *);
 
-extern void memory_oom (size_t size, const char *name);
+extern void memory_oom(size_t size, const char *name);
 
 #endif /* _QUAGGA_MEMORY_H */
index 13a46e10127cacdd67002c07ec8309aede0a9ac6..f4f360c957f5d7d800ec89757d169bed04f60eaf 100644 (file)
@@ -85,7 +85,8 @@ enum lsp_types_t
 {
   ZEBRA_LSP_NONE = 0,        /* No LSP. */
   ZEBRA_LSP_STATIC = 1,      /* Static LSP. */
-  ZEBRA_LSP_LDP = 2          /* LDP LSP. */
+  ZEBRA_LSP_LDP = 2,         /* LDP LSP. */
+  ZEBRA_LSP_BGP = 3          /* BGP LSP. */
 };
 
 /* Functions for basic label operations. */
@@ -122,6 +123,11 @@ mpls_lse_decode (mpls_lse_t lse, mpls_label_t *label,
   *ttl = MPLS_LABEL_TTL(local_lse);
 }
 
+/* Invalid label index value (when used with BGP Prefix-SID). Should
+ * match the BGP definition.
+ */
+#define MPLS_INVALID_LABEL_INDEX   0xFFFFFFFF
+
 
 /* Printable string for labels (with consideration for reserved values). */
 static inline char *
index 7b8ac95e832bec6978b803e92230459df2044136..a6420fea339c1bd481cde379ccbd9e8213664dd0 100644 (file)
@@ -92,6 +92,28 @@ nexthop_type_to_str (enum nexthop_types_t nh_type)
   return desc[nh_type];
 }
 
+/*
+ * Check if the labels match for the 2 nexthops specified.
+ */
+int
+nexthop_labels_match (struct nexthop *nh1, struct nexthop *nh2)
+{
+  struct nexthop_label *nhl1, *nhl2;
+
+  nhl1 = nh1->nh_label;
+  nhl2 = nh2->nh_label;
+  if ((nhl1 && !nhl2) || (!nhl1 && nhl2))
+    return 0;
+
+  if (nhl1->num_labels != nhl2->num_labels)
+    return 0;
+
+  if (memcmp (nhl1->label, nhl2->label, nhl1->num_labels))
+    return 0;
+
+  return 1;
+}
+
 struct nexthop *
 nexthop_new (void)
 {
index e66e0eee20ef08eb0221c60238c6bc3340a616ac..83c5b850b8f90def607723447c286287aa71b302 100644 (file)
@@ -117,6 +117,7 @@ void nexthop_del_labels (struct nexthop *);
 
 extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
 extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2);
+extern int nexthop_labels_match (struct nexthop *nh1, struct nexthop *nh2);
 
 extern const char * nexthop2str (struct nexthop *nexthop, char *str, int size);
 #endif /*_LIB_NEXTHOP_H */
index 0f870564dab7a032d4a77d63b3cb1746f68e8f86..fa502b462ae4d65adb936b33511979a47be56c01 100644 (file)
@@ -188,3 +188,11 @@ pqueue_remove_at (int index, struct pqueue *queue)
       trickle_down (index, queue);
     }
 }
+
+void
+pqueue_remove (void *data, struct pqueue *queue)
+{
+  for (int i = 0; i < queue->size; i++)
+    if (queue->array[i] == data)
+      pqueue_remove_at (i, queue);
+}
index 8bb6961d8641b295561a1ac2ff7d904ec4a07e71..b39fb92ee9829918695e02d2bc49be86d74800ec 100644 (file)
@@ -39,6 +39,7 @@ extern void pqueue_delete (struct pqueue *queue);
 extern void pqueue_enqueue (void *data, struct pqueue *queue);
 extern void *pqueue_dequeue (struct pqueue *queue);
 extern void pqueue_remove_at (int index, struct pqueue *queue);
+extern void pqueue_remove (void *data, struct pqueue *queue);
 
 extern void trickle_down (int index, struct pqueue *queue);
 extern void trickle_up (int index, struct pqueue *queue);
index eb3ae3dafb618713b8f9e327ad4fb0c3e81e22bf..786c2bf7ea0b60b2f36a410079e57ecb5db002f8 100644 (file)
@@ -244,6 +244,8 @@ union prefixconstptr
 /* Count prefix size from mask length */
 #define PSIZE(a) (((a) + 7) / (8))
 
+#define BSIZE(a) ((a) * (8))
+
 /* Prefix's family member. */
 #define PREFIX_FAMILY(p)  ((p)->family)
 
index decd4bb7db94319d81d1078e745fe46d08b342b2..767ab667e78e908eb44e8492caaac299ea241388 100644 (file)
@@ -769,6 +769,7 @@ zprivs_init(struct zebra_privs_t *zprivs)
         }
     }
 
+  zprivs_state.zsuid = geteuid(); /* initial uid */
   /* add groups only if we changed uid - otherwise skip */
   if ((ngroups) && (zprivs_state.zsuid != zprivs_state.zuid))
     {
index 5cb06ffb7f4db7695565ea54b07f8bc01b09cf57..7625d1f690ac35539281568b35e5b494407b56c9 100644 (file)
@@ -52,6 +52,7 @@ ZEBRA_ROUTE_OSPF6,      ospf6,     ospf6d, 'O', 0, 1, "OSPFv3"
 ZEBRA_ROUTE_ISIS,       isis,      isisd,  'I', 1, 1, "IS-IS"
 ZEBRA_ROUTE_BGP,        bgp,       bgpd,   'B', 1, 1, "BGP"
 ZEBRA_ROUTE_PIM,       pim,       pimd,   'P', 1, 0, "PIM"
+ZEBRA_ROUTE_EIGRP,      eigrp,     eigrpd, 'E', 1, 0, "EIGRP"
 ZEBRA_ROUTE_NHRP,       nhrp,      nhrpd,  'N', 1, 1, "NHRP"
 # HSLS and OLSR both are AFI independent (so: 1, 1), however
 # we want to disable for them for general Quagga distribution.
@@ -86,6 +87,7 @@ ZEBRA_ROUTE_OSPF6,  "Open Shortest Path First (IPv6) (OSPFv3)"
 ZEBRA_ROUTE_ISIS,   "Intermediate System to Intermediate System (IS-IS)"
 ZEBRA_ROUTE_BGP,    "Border Gateway Protocol (BGP)"
 ZEBRA_ROUTE_PIM,    "Protocol Independent Multicast (PIM)"
+ZEBRA_ROUTE_EIGRP,  "Enhanced Interior Gateway Routing Protocol (EIGRP)"
 ZEBRA_ROUTE_NHRP,   "Next Hop Resolution Protocol (NHRP)"
 ZEBRA_ROUTE_HSLS,   "Hazy-Sighted Link State Protocol (HSLS)"
 ZEBRA_ROUTE_VNC,    "Virtual Network Control (VNC)"
diff --git a/lib/sha256.c b/lib/sha256.c
new file mode 100644 (file)
index 0000000..f98a758
--- /dev/null
@@ -0,0 +1,433 @@
+/*-
+ * 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"
+
+#if !HAVE_DECL_BE32DEC
+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));
+}
+#else
+#include <sys/endian.h>
+#endif
+
+#if !HAVE_DECL_BE32ENC
+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;
+}
+#else
+#include <sys/endian.h>
+#endif
+
+/*
+ * Encode a length len/4 vector of (uint32_t) into a length len vector of
+ * (unsigned char) in big-endian form.  Assumes len is a multiple of 4.
+ */
+static void
+be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
+{
+        size_t i;
+
+        for (i = 0; i < len / 4; i++)
+                be32enc(dst + i * 4, src[i]);
+}
+
+/*
+ * Decode a big-endian length len vector of (unsigned char) into a length
+ * len/4 vector of (uint32_t).  Assumes len is a multiple of 4.
+ */
+static void
+be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
+{
+        size_t i;
+
+        for (i = 0; i < len / 4; i++)
+                dst[i] = be32dec(src + i * 4);
+}
+
+/* Elementary functions used by SHA256 */
+#define Ch(x, y, z)     ((x & (y ^ z)) ^ z)
+#define Maj(x, y, z)    ((x & (y | z)) | (y & z))
+#define SHR(x, n)       (x >> n)
+#define ROTR(x, n)      ((x >> n) | (x << (32 - n)))
+#define S0(x)           (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define S1(x)           (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define s0(x)           (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
+#define s1(x)           (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
+
+/* SHA256 round function */
+#define RND(a, b, c, d, e, f, g, h, k)                  \
+        t0 = h + S1(e) + Ch(e, f, g) + k;               \
+        t1 = S0(a) + Maj(a, b, c);                      \
+        d += t0;                                        \
+        h  = t0 + t1;
+
+/* Adjusted round function for rotating state */
+#define RNDr(S, W, i, k)                        \
+        RND(S[(64 - i) % 8], S[(65 - i) % 8],   \
+            S[(66 - i) % 8], S[(67 - i) % 8],   \
+            S[(68 - i) % 8], S[(69 - i) % 8],   \
+            S[(70 - i) % 8], S[(71 - i) % 8],   \
+            W[i] + k)
+
+/*
+ * SHA256 block compression function.  The 256-bit state is transformed via
+ * the 512-bit input block to produce a new state.
+ */
+static void
+SHA256_Transform(uint32_t * state, const unsigned char block[64])
+{
+        uint32_t W[64];
+        uint32_t S[8];
+        uint32_t t0, t1;
+        int i;
+
+        /* 1. Prepare message schedule W. */
+        be32dec_vect(W, block, 64);
+        for (i = 16; i < 64; i++)
+                W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
+
+        /* 2. Initialize working variables. */
+        memcpy(S, state, 32);
+
+        /* 3. Mix. */
+        RNDr(S, W, 0, 0x428a2f98);
+        RNDr(S, W, 1, 0x71374491);
+        RNDr(S, W, 2, 0xb5c0fbcf);
+        RNDr(S, W, 3, 0xe9b5dba5);
+        RNDr(S, W, 4, 0x3956c25b);
+        RNDr(S, W, 5, 0x59f111f1);
+        RNDr(S, W, 6, 0x923f82a4);
+        RNDr(S, W, 7, 0xab1c5ed5);
+        RNDr(S, W, 8, 0xd807aa98);
+        RNDr(S, W, 9, 0x12835b01);
+        RNDr(S, W, 10, 0x243185be);
+        RNDr(S, W, 11, 0x550c7dc3);
+        RNDr(S, W, 12, 0x72be5d74);
+        RNDr(S, W, 13, 0x80deb1fe);
+        RNDr(S, W, 14, 0x9bdc06a7);
+        RNDr(S, W, 15, 0xc19bf174);
+        RNDr(S, W, 16, 0xe49b69c1);
+        RNDr(S, W, 17, 0xefbe4786);
+        RNDr(S, W, 18, 0x0fc19dc6);
+        RNDr(S, W, 19, 0x240ca1cc);
+        RNDr(S, W, 20, 0x2de92c6f);
+        RNDr(S, W, 21, 0x4a7484aa);
+        RNDr(S, W, 22, 0x5cb0a9dc);
+        RNDr(S, W, 23, 0x76f988da);
+        RNDr(S, W, 24, 0x983e5152);
+        RNDr(S, W, 25, 0xa831c66d);
+        RNDr(S, W, 26, 0xb00327c8);
+        RNDr(S, W, 27, 0xbf597fc7);
+        RNDr(S, W, 28, 0xc6e00bf3);
+        RNDr(S, W, 29, 0xd5a79147);
+        RNDr(S, W, 30, 0x06ca6351);
+        RNDr(S, W, 31, 0x14292967);
+        RNDr(S, W, 32, 0x27b70a85);
+        RNDr(S, W, 33, 0x2e1b2138);
+        RNDr(S, W, 34, 0x4d2c6dfc);
+        RNDr(S, W, 35, 0x53380d13);
+        RNDr(S, W, 36, 0x650a7354);
+        RNDr(S, W, 37, 0x766a0abb);
+        RNDr(S, W, 38, 0x81c2c92e);
+        RNDr(S, W, 39, 0x92722c85);
+        RNDr(S, W, 40, 0xa2bfe8a1);
+        RNDr(S, W, 41, 0xa81a664b);
+        RNDr(S, W, 42, 0xc24b8b70);
+        RNDr(S, W, 43, 0xc76c51a3);
+        RNDr(S, W, 44, 0xd192e819);
+        RNDr(S, W, 45, 0xd6990624);
+        RNDr(S, W, 46, 0xf40e3585);
+        RNDr(S, W, 47, 0x106aa070);
+        RNDr(S, W, 48, 0x19a4c116);
+        RNDr(S, W, 49, 0x1e376c08);
+        RNDr(S, W, 50, 0x2748774c);
+        RNDr(S, W, 51, 0x34b0bcb5);
+        RNDr(S, W, 52, 0x391c0cb3);
+        RNDr(S, W, 53, 0x4ed8aa4a);
+        RNDr(S, W, 54, 0x5b9cca4f);
+        RNDr(S, W, 55, 0x682e6ff3);
+        RNDr(S, W, 56, 0x748f82ee);
+        RNDr(S, W, 57, 0x78a5636f);
+        RNDr(S, W, 58, 0x84c87814);
+        RNDr(S, W, 59, 0x8cc70208);
+        RNDr(S, W, 60, 0x90befffa);
+        RNDr(S, W, 61, 0xa4506ceb);
+        RNDr(S, W, 62, 0xbef9a3f7);
+        RNDr(S, W, 63, 0xc67178f2);
+
+        /* 4. Mix local working variables into global state */
+        for (i = 0; i < 8; i++)
+                state[i] += S[i];
+
+        /* Clean the stack. */
+        memset(W, 0, 256);
+        memset(S, 0, 32);
+        t0 = t1 = 0;
+}
+
+static unsigned char PAD[64] = {
+        0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* Add padding and terminating bit-count. */
+static void
+SHA256_Pad(SHA256_CTX * ctx)
+{
+        unsigned char len[8];
+        uint32_t r, plen;
+
+        /*
+         * Convert length to a vector of bytes -- we do this now rather
+         * than later because the length will change after we pad.
+         */
+        be32enc_vect(len, ctx->count, 8);
+
+        /* Add 1--64 bytes so that the resulting length is 56 mod 64 */
+        r = (ctx->count[1] >> 3) & 0x3f;
+        plen = (r < 56) ? (56 - r) : (120 - r);
+        SHA256_Update(ctx, PAD, (size_t)plen);
+
+        /* Add the terminating bit-count */
+        SHA256_Update(ctx, len, 8);
+}
+
+/* SHA-256 initialization.  Begins a SHA-256 operation. */
+void
+SHA256_Init(SHA256_CTX * ctx)
+{
+
+        /* Zero bits processed so far */
+        ctx->count[0] = ctx->count[1] = 0;
+
+        /* Magic initialization constants */
+        ctx->state[0] = 0x6A09E667;
+        ctx->state[1] = 0xBB67AE85;
+        ctx->state[2] = 0x3C6EF372;
+        ctx->state[3] = 0xA54FF53A;
+        ctx->state[4] = 0x510E527F;
+        ctx->state[5] = 0x9B05688C;
+        ctx->state[6] = 0x1F83D9AB;
+        ctx->state[7] = 0x5BE0CD19;
+}
+
+/* Add bytes into the hash */
+void
+SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len)
+{
+        uint32_t bitlen[2];
+        uint32_t r;
+        const unsigned char *src = in;
+
+        /* Number of bytes left in the buffer from previous updates */
+        r = (ctx->count[1] >> 3) & 0x3f;
+
+        /* Convert the length into a number of bits */
+        bitlen[1] = ((uint32_t)len) << 3;
+        bitlen[0] = (uint32_t)(len >> 29);
+
+        /* Update number of bits */
+        if ((ctx->count[1] += bitlen[1]) < bitlen[1])
+                ctx->count[0]++;
+        ctx->count[0] += bitlen[0];
+
+        /* Handle the case where we don't need to perform any transforms */
+        if (len < 64 - r) {
+                memcpy(&ctx->buf[r], src, len);
+                return;
+        }
+
+        /* Finish the current block */
+        memcpy(&ctx->buf[r], src, 64 - r);
+        SHA256_Transform(ctx->state, ctx->buf);
+        src += 64 - r;
+        len -= 64 - r;
+
+        /* Perform complete blocks */
+        while (len >= 64) {
+                SHA256_Transform(ctx->state, src);
+                src += 64;
+                len -= 64;
+        }
+
+        /* Copy left over data into buffer */
+        memcpy(ctx->buf, src, len);
+}
+
+/*
+ * SHA-256 finalization.  Pads the input data, exports the hash value,
+ * and clears the context state.
+ */
+void
+SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx)
+{
+
+        /* Add padding */
+        SHA256_Pad(ctx);
+
+        /* Write the hash */
+        be32enc_vect(digest, ctx->state, 32);
+
+        /* Clear the context state */
+        memset((void *)ctx, 0, sizeof(*ctx));
+}
+
+/* Initialize an HMAC-SHA256 operation with the given key. */
+void
+HMAC__SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen)
+{
+        unsigned char pad[64];
+        unsigned char khash[32];
+        const unsigned char * K = _K;
+        size_t i;
+
+        /* If Klen > 64, the key is really SHA256(K). */
+        if (Klen > 64) {
+                SHA256_Init(&ctx->ictx);
+                SHA256_Update(&ctx->ictx, K, Klen);
+                SHA256_Final(khash, &ctx->ictx);
+                K = khash;
+                Klen = 32;
+        }
+
+        /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
+        SHA256_Init(&ctx->ictx);
+        memset(pad, 0x36, 64);
+        for (i = 0; i < Klen; i++)
+                pad[i] ^= K[i];
+        SHA256_Update(&ctx->ictx, pad, 64);
+
+        /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
+        SHA256_Init(&ctx->octx);
+        memset(pad, 0x5c, 64);
+        for (i = 0; i < Klen; i++)
+                pad[i] ^= K[i];
+        SHA256_Update(&ctx->octx, pad, 64);
+
+        /* Clean the stack. */
+        memset(khash, 0, 32);
+}
+
+/* Add bytes to the HMAC-SHA256 operation. */
+void
+HMAC__SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len)
+{
+
+        /* Feed data to the inner SHA256 operation. */
+        SHA256_Update(&ctx->ictx, in, len);
+}
+
+/* Finish an HMAC-SHA256 operation. */
+void
+HMAC__SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx)
+{
+        unsigned char ihash[32];
+
+        /* Finish the inner SHA256 operation. */
+        SHA256_Final(ihash, &ctx->ictx);
+
+        /* Feed the inner hash to the outer SHA256 operation. */
+        SHA256_Update(&ctx->octx, ihash, 32);
+
+        /* Finish the outer SHA256 operation. */
+        SHA256_Final(digest, &ctx->octx);
+
+        /* Clean the stack. */
+        memset(ihash, 0, 32);
+}
+
+/**
+ * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
+ * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
+ * write the output to buf.  The value dkLen must be at most 32 * (2^32 - 1).
+ */
+void
+PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,
+    size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)
+{
+        HMAC_SHA256_CTX PShctx, hctx;
+        size_t i;
+        uint8_t ivec[4];
+        uint8_t U[32];
+        uint8_t T[32];
+        uint64_t j;
+        int k;
+        size_t clen;
+
+        /* Compute HMAC state after processing P and S. */
+        HMAC__SHA256_Init(&PShctx, passwd, passwdlen);
+        HMAC__SHA256_Update(&PShctx, salt, saltlen);
+
+        /* Iterate through the blocks. */
+        for (i = 0; i * 32 < dkLen; i++) {
+                /* Generate INT(i + 1). */
+                be32enc(ivec, (uint32_t)(i + 1));
+
+                /* Compute U_1 = PRF(P, S || INT(i)). */
+                memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));
+                HMAC__SHA256_Update(&hctx, ivec, 4);
+                HMAC__SHA256_Final(U, &hctx);
+
+                /* T_i = U_1 ... */
+                memcpy(T, U, 32);
+
+                for (j = 2; j <= c; j++) {
+                        /* Compute U_j. */
+                        HMAC__SHA256_Init(&hctx, passwd, passwdlen);
+                        HMAC__SHA256_Update(&hctx, U, 32);
+                        HMAC__SHA256_Final(U, &hctx);
+
+                        /* ... xor U_j ... */
+                        for (k = 0; k < 32; k++)
+                                T[k] ^= U[k];
+                }
+
+                /* Copy as many bytes as necessary into buf. */
+                clen = dkLen - i * 32;
+                if (clen > 32)
+                        clen = 32;
+                memcpy(&buf[i * 32], T, clen);
+        }
+
+        /* Clean PShctx, since we never called _Final on it. */
+        memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX));
+}
diff --git a/lib/sha256.h b/lib/sha256.h
new file mode 100644 (file)
index 0000000..502f3fc
--- /dev/null
@@ -0,0 +1,58 @@
+/*-
+ * Copyright 2005,2007,2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libmd/sha256.h,v 1.2 2006/01/17 15:35:56 phk Exp $
+ */
+
+#ifndef _SHA256_H_
+#define _SHA256_H_
+
+typedef struct SHA256Context {
+        uint32_t state[8];
+        uint32_t count[2];
+        unsigned char buf[64];
+} SHA256_CTX;
+
+typedef struct HMAC_SHA256Context {
+        SHA256_CTX ictx;
+        SHA256_CTX octx;
+} HMAC_SHA256_CTX;
+
+void    SHA256_Init(SHA256_CTX *);
+void    SHA256_Update(SHA256_CTX *, const void *, size_t);
+void    SHA256_Final(unsigned char [32], SHA256_CTX *);
+void    HMAC__SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t);
+void    HMAC__SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t);
+void    HMAC__SHA256_Final(unsigned char [32], HMAC_SHA256_CTX *);
+
+/**
+ * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
+ * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
+ * write the output to buf.  The value dkLen must be at most 32 * (2^32 - 1).
+ */
+void    PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t,
+    uint64_t, uint8_t *, size_t);
+
+#endif /* !_SHA256_H_ */
index 09f07180cec884d406196ccdfd8959dd1335e6c9..b2059a17bf6104de35a54a847fa1f04c41fbbac7 100644 (file)
@@ -233,6 +233,18 @@ core_handler(int signo
 #endif
            )
 {
+  /* make sure we don't hang in here.  default for SIGALRM is terminate.
+   * - if we're in backtrace for more than a second, abort. */
+  struct sigaction sa_default = { .sa_handler = SIG_DFL };
+  sigaction (SIGALRM, &sa_default, NULL);
+
+  sigset_t sigset;
+  sigemptyset (&sigset);
+  sigaddset (&sigset, SIGALRM);
+  sigprocmask (SIG_UNBLOCK, &sigset, NULL);
+
+  alarm (1);
+
   zlog_signal(signo, "aborting..."
 #ifdef SA_SIGINFO
              , siginfo, program_counter(context)
@@ -326,6 +338,11 @@ trap_default_signals(void)
 #else
                  act.sa_handler = sigmap[i].handler;
                  act.sa_flags = 0;
+#endif
+#ifdef SA_RESETHAND
+                  /* don't try to print backtraces recursively */
+                  if (sigmap[i].handler == core_handler)
+                    act.sa_flags |= SA_RESETHAND;
 #endif
                }
              if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0)
index 301ebc627527611977326b0005de950f94514d89..32dde1ca0c0d4bb42faffa371b04c7d98073cabc 100644 (file)
@@ -919,6 +919,31 @@ stream_put_prefix (struct stream *s, struct prefix *p)
   return stream_put_prefix_addpath (s, p, 0, 0);
 }
 
+/* Put NLRI with label */
+int
+stream_put_labeled_prefix (struct stream *s, struct prefix *p, u_char *label)
+{
+  size_t psize;
+
+  STREAM_VERIFY_SANE(s);
+
+  psize = PSIZE (p->prefixlen);
+
+  if (STREAM_WRITEABLE (s) < (psize + 3))
+    {
+      STREAM_BOUND_WARN (s, "put");
+      return 0;
+    }
+
+  stream_putc (s, (p->prefixlen + 24));
+  stream_putc(s, label[0]);
+  stream_putc(s, label[1]);
+  stream_putc(s, label[2]);
+  memcpy (s->data + s->endp, &p->u.prefix, psize);
+  s->endp += psize;
+
+  return (psize + 3);
+}
 
 /* Read size from fd. */
 int
index 1e2bc89b32d63a26f74217d0dce4d325265e5928..b7bf31bf7f45af225741ae16d854535a1ffd6d34 100644 (file)
@@ -181,7 +181,8 @@ extern int stream_put_prefix_addpath (struct stream *, struct prefix *,
                                       int addpath_encode,
                                       u_int32_t addpath_tx_id);
 extern int stream_put_prefix (struct stream *, struct prefix *);
-
+extern int stream_put_labeled_prefix (struct stream *, struct prefix *,
+                                      u_char *);
 extern void stream_get (void *, struct stream *, size_t);
 extern void stream_get_from (void *, struct stream *, size_t, size_t);
 extern u_char stream_getc (struct stream *);
index 34802fcedd2477c11b7e47c2505ede8b3e675d72..3fb28bce26f0e0961a530f3025619d6c77eeed46 100644 (file)
@@ -41,7 +41,7 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS,  "Thread stats")
 #include <mach/mach_time.h>
 #endif
 
-/* Relative time, since startup */
+static pthread_mutex_t cpu_record_mtx = PTHREAD_MUTEX_INITIALIZER;
 static struct hash *cpu_record = NULL;
 
 static unsigned long
@@ -137,9 +137,14 @@ cpu_record_print(struct vty *vty, thread_type filter)
   vty_out(vty, "Active   Runtime(ms)   Invoked Avg uSec Max uSecs");
   vty_out(vty, " Avg uSec Max uSecs");
   vty_out(vty, "  Type  Thread%s", VTY_NEWLINE);
-  hash_iterate(cpu_record,
-              (void(*)(struct hash_backet*,void*))cpu_record_hash_print,
-              args);
+
+  pthread_mutex_lock (&cpu_record_mtx);
+  {
+    hash_iterate(cpu_record,
+                 (void(*)(struct hash_backet*,void*))cpu_record_hash_print,
+                 args);
+  }
+  pthread_mutex_unlock (&cpu_record_mtx);
 
   if (tmp.total_calls > 0)
     vty_out_cpu_thread_history(vty, &tmp);
@@ -216,16 +221,25 @@ cpu_record_hash_clear (struct hash_backet *bucket,
   if ( !(a->types & *filter) )
        return;
   
-  hash_release (cpu_record, bucket->data);
+  pthread_mutex_lock (&cpu_record_mtx);
+  {
+    hash_release (cpu_record, bucket->data);
+  }
+  pthread_mutex_unlock (&cpu_record_mtx);
 }
 
 static void
 cpu_record_clear (thread_type filter)
 {
   thread_type *tmp = &filter;
-  hash_iterate (cpu_record,
-               (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
-               tmp);
+
+  pthread_mutex_lock (&cpu_record_mtx);
+  {
+    hash_iterate (cpu_record,
+                  (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
+                  tmp);
+  }
+  pthread_mutex_unlock (&cpu_record_mtx);
 }
 
 DEFUN (clear_thread_cpu,
@@ -326,16 +340,20 @@ thread_master_create (void)
 
   getrlimit(RLIMIT_NOFILE, &limit);
 
-  if (cpu_record == NULL) 
-    cpu_record 
-      = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
-                    (int (*) (const void *, const void *))cpu_record_hash_cmp);
+  pthread_mutex_lock (&cpu_record_mtx);
+  {
+    if (cpu_record == NULL)
+      cpu_record = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
+                                (int (*) (const void *, const void *))
+                                cpu_record_hash_cmp);
+  }
+  pthread_mutex_unlock (&cpu_record_mtx);
 
   rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master));
   if (rv == NULL)
-    {
-      return NULL;
-    }
+    return NULL;
+
+  pthread_mutex_init (&rv->mtx, NULL);
 
   rv->fd_limit = (int)limit.rlim_cur;
   rv->read = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit);
@@ -358,6 +376,8 @@ thread_master_create (void)
   rv->background = pqueue_create();
   rv->timer->cmp = rv->background->cmp = thread_timer_cmp;
   rv->timer->update = rv->background->update = thread_timer_update;
+  rv->spin = true;
+  rv->handle_signals = true;
 
 #if defined(HAVE_POLL_CALL)
   rv->handler.pfdsize = rv->fd_limit;
@@ -498,11 +518,16 @@ thread_queue_free (struct thread_master *m, struct pqueue *queue)
 void
 thread_master_free_unused (struct thread_master *m)
 {
-  struct thread *t;
-  while ((t = thread_trim_head(&m->unuse)) != NULL)
-    {
-      XFREE(MTYPE_THREAD, t);
-    }
+  pthread_mutex_lock (&m->mtx);
+  {
+    struct thread *t;
+    while ((t = thread_trim_head(&m->unuse)) != NULL)
+      {
+        pthread_mutex_destroy (&t->mtx);
+        XFREE(MTYPE_THREAD, t);
+      }
+  }
+  pthread_mutex_unlock (&m->mtx);
 }
 
 /* Stop thread scheduler. */
@@ -516,25 +541,37 @@ thread_master_free (struct thread_master *m)
   thread_list_free (m, &m->ready);
   thread_list_free (m, &m->unuse);
   thread_queue_free (m, m->background);
+  pthread_mutex_destroy (&m->mtx);
 
 #if defined(HAVE_POLL_CALL)
   XFREE (MTYPE_THREAD_MASTER, m->handler.pfds);
 #endif
   XFREE (MTYPE_THREAD_MASTER, m);
 
-  if (cpu_record)
-    {
-      hash_clean (cpu_record, cpu_record_hash_free);
-      hash_free (cpu_record);
-      cpu_record = NULL;
-    }
+  pthread_mutex_lock (&cpu_record_mtx);
+  {
+    if (cpu_record)
+      {
+        hash_clean (cpu_record, cpu_record_hash_free);
+        hash_free (cpu_record);
+        cpu_record = NULL;
+      }
+  }
+  pthread_mutex_unlock (&cpu_record_mtx);
 }
 
 /* Return remain time in second. */
 unsigned long
 thread_timer_remain_second (struct thread *thread)
 {
-  int64_t remain = monotime_until(&thread->u.sands, NULL) / 1000000LL;
+  int64_t remain;
+
+  pthread_mutex_lock (&thread->mtx);
+  {
+    remain = monotime_until(&thread->u.sands, NULL) / 1000000LL;
+  }
+  pthread_mutex_unlock (&thread->mtx);
+
   return remain < 0 ? 0 : remain;
 }
 
@@ -545,7 +582,11 @@ struct timeval
 thread_timer_remain(struct thread *thread)
 {
   struct timeval remain;
-  monotime_until(&thread->u.sands, &remain);
+  pthread_mutex_lock (&thread->mtx);
+  {
+    monotime_until(&thread->u.sands, &remain);
+  }
+  pthread_mutex_unlock (&thread->mtx);
   return remain;
 }
 
@@ -560,8 +601,11 @@ thread_get (struct thread_master *m, u_char type,
   if (! thread)
     {
       thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
+      /* mutex only needs to be initialized at struct creation. */
+      pthread_mutex_init (&thread->mtx, NULL);
       m->alloc++;
     }
+
   thread->type = type;
   thread->add_type = type;
   thread->master = m;
@@ -584,8 +628,12 @@ thread_get (struct thread_master *m, u_char type,
     {
       tmp.func = func;
       tmp.funcname = funcname;
-      thread->hist = hash_get (cpu_record, &tmp,
-                              (void * (*) (void *))cpu_record_hash_alloc);
+      pthread_mutex_lock (&cpu_record_mtx);
+      {
+        thread->hist = hash_get (cpu_record, &tmp,
+                                 (void * (*) (void *))cpu_record_hash_alloc);
+      }
+      pthread_mutex_unlock (&cpu_record_mtx);
     }
   thread->hist->total_active++;
   thread->func = func;
@@ -650,15 +698,45 @@ static int
 fd_select (struct thread_master *m, int size, thread_fd_set *read, thread_fd_set *write, thread_fd_set *except, struct timeval *timer_wait)
 {
   int num;
+
+  /* If timer_wait is null here, that means either select() or poll() should
+   * block indefinitely, unless the thread_master has overriden it. select()
+   * and poll() differ in the timeout values they interpret as an indefinite
+   * block; select() requires a null pointer, while poll takes a millisecond
+   * value of -1.
+   *
+   * The thread_master owner has the option of overriding the default behavior
+   * by setting ->selectpoll_timeout. If the value is positive, it specifies
+   * the maximum number of milliseconds to wait. If the timeout is -1, it
+   * specifies that we should never wait and always return immediately even if
+   * no event is detected. If the value is zero, the behavior is default.
+   */
+
 #if defined(HAVE_POLL_CALL)
-  /* recalc timeout for poll. Attention NULL pointer is no timeout with
-  select, where with poll no timeount is -1 */
   int timeout = -1;
-  if (timer_wait != NULL)
+
+  if (timer_wait != NULL && m->selectpoll_timeout == 0) // use the default value
     timeout = (timer_wait->tv_sec*1000) + (timer_wait->tv_usec/1000);
+  else if (m->selectpoll_timeout > 0) // use the user's timeout
+    timeout = m->selectpoll_timeout;
+  else if (m->selectpoll_timeout < 0) // effect a poll (return immediately)
+    timeout = 0;
 
   num = poll (m->handler.pfds, m->handler.pfdcount + m->handler.pfdcountsnmp, timeout);
 #else
+  struct timeval timeout;
+  if (m->selectpoll_timeout > 0) // use the user's timeout
+  {
+    timeout.tv_sec = m->selectpoll_timeout / 1000;
+    timeout.tv_usec = (m->selectpoll_timeout % 1000) * 1000;
+    timer_wait = &timeout;
+  }
+  else if (m->selectpoll_timeout < 0) // effect a poll (return immediately)
+  {
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+    timer_wait = &timeout;
+  }
   num = select (size, read, write, except, timer_wait);
 #endif
 
@@ -703,36 +781,49 @@ funcname_thread_add_read_write (int dir, struct thread_master *m,
 {
   struct thread *thread = NULL;
 
-#if !defined(HAVE_POLL_CALL)
-  thread_fd_set *fdset = NULL;
-  if (dir == THREAD_READ)
-    fdset = &m->handler.readfd;
-  else
-    fdset = &m->handler.writefd;
-#endif
-
+  pthread_mutex_lock (&m->mtx);
+  {
 #if defined (HAVE_POLL_CALL)
-  thread = generic_thread_add(m, func, arg, fd, dir, debugargpass);
-
-  if (thread == NULL)
-    return NULL;
+    thread = generic_thread_add(m, func, arg, fd, dir, debugargpass);
 #else
-  if (FD_ISSET (fd, fdset))
-    {
-      zlog_warn ("There is already %s fd [%d]",
-                 (dir == THREAD_READ) ? "read" : "write", fd);
-      return NULL;
-    }
+    if (fd >= FD_SETSIZE)
+      {
+        zlog_err ("File descriptor %d is >= FD_SETSIZE (%d). Please recompile"
+                  "with --enable-poll=yes", fd, FD_SETSIZE);
+        assert (fd < FD_SETSIZE && !"fd >= FD_SETSIZE");
+      }
+    thread_fd_set *fdset = NULL;
+    if (dir == THREAD_READ)
+      fdset = &m->handler.readfd;
+    else
+      fdset = &m->handler.writefd;
 
-  FD_SET (fd, fdset);
-  thread = thread_get (m, dir, func, arg, debugargpass);
+    if (FD_ISSET (fd, fdset))
+      {
+        zlog_warn ("There is already %s fd [%d]",
+                   (dir == THREAD_READ) ? "read" : "write", fd);
+      }
+    else
+      {
+        FD_SET (fd, fdset);
+        thread = thread_get (m, dir, func, arg, debugargpass);
+      }
 #endif
 
-  thread->u.fd = fd;
-  if (dir == THREAD_READ)
-    thread_add_fd (m->read, thread);
-  else
-    thread_add_fd (m->write, thread);
+    if (thread)
+      {
+        pthread_mutex_lock (&thread->mtx);
+        {
+          thread->u.fd = fd;
+          if (dir == THREAD_READ)
+            thread_add_fd (m->read, thread);
+          else
+            thread_add_fd (m->write, thread);
+        }
+        pthread_mutex_unlock (&thread->mtx);
+      }
+  }
+  pthread_mutex_unlock (&m->mtx);
 
   return thread;
 }
@@ -753,13 +844,21 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
   assert (type == THREAD_TIMER || type == THREAD_BACKGROUND);
   assert (time_relative);
   
-  queue = ((type == THREAD_TIMER) ? m->timer : m->background);
-  thread = thread_get (m, type, func, arg, debugargpass);
+  pthread_mutex_lock (&m->mtx);
+  {
+    queue = ((type == THREAD_TIMER) ? m->timer : m->background);
+    thread = thread_get (m, type, func, arg, debugargpass);
 
-  monotime(&thread->u.sands);
-  timeradd(&thread->u.sands, time_relative, &thread->u.sands);
+    pthread_mutex_lock (&thread->mtx);
+    {
+      monotime(&thread->u.sands);
+      timeradd(&thread->u.sands, time_relative, &thread->u.sands);
+      pqueue_enqueue(thread, queue);
+    }
+    pthread_mutex_unlock (&thread->mtx);
+  }
+  pthread_mutex_unlock (&m->mtx);
 
-  pqueue_enqueue(thread, queue);
   return thread;
 }
 
@@ -847,9 +946,17 @@ funcname_thread_add_event (struct thread_master *m,
 
   assert (m != NULL);
 
-  thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass);
-  thread->u.val = val;
-  thread_list_add (&m->event, thread);
+  pthread_mutex_lock (&m->mtx);
+  {
+    thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass);
+    pthread_mutex_lock (&thread->mtx);
+    {
+      thread->u.val = val;
+      thread_list_add (&m->event, thread);
+    }
+    pthread_mutex_unlock (&thread->mtx);
+  }
+  pthread_mutex_unlock (&m->mtx);
 
   return thread;
 }
@@ -880,14 +987,22 @@ thread_cancel_read_or_write (struct thread *thread, short int state)
   fd_clear_read_write (thread);
 }
 
-/* Cancel thread from scheduler. */
+/**
+ * Cancel thread from scheduler.
+ *
+ * This function is *NOT* MT-safe. DO NOT call it from any other pthread except
+ * the one which owns thread->master.
+ */
 void
 thread_cancel (struct thread *thread)
 {
   struct thread_list *list = NULL;
   struct pqueue *queue = NULL;
   struct thread **thread_array = NULL;
-  
+
+  pthread_mutex_lock (&thread->master->mtx);
+  pthread_mutex_lock (&thread->mtx);
+
   switch (thread->type)
     {
     case THREAD_READ:
@@ -919,15 +1034,14 @@ thread_cancel (struct thread *thread)
       queue = thread->master->background;
       break;
     default:
-      return;
+      goto done;
       break;
     }
 
   if (queue)
     {
       assert(thread->index >= 0);
-      assert(thread == queue->array[thread->index]);
-      pqueue_remove_at(thread->index, queue);
+      pqueue_remove (thread, queue);
     }
   else if (list)
     {
@@ -943,6 +1057,10 @@ thread_cancel (struct thread *thread)
     }
 
   thread_add_unuse (thread->master, thread);
+
+done:
+  pthread_mutex_unlock (&thread->mtx);
+  pthread_mutex_unlock (&thread->master->mtx);
 }
 
 /* Delete all events which has argument value arg. */
@@ -951,39 +1069,48 @@ thread_cancel_event (struct thread_master *m, void *arg)
 {
   unsigned int ret = 0;
   struct thread *thread;
+  struct thread *t;
 
-  thread = m->event.head;
-  while (thread)
-    {
-      struct thread *t;
-
-      t = thread;
-      thread = t->next;
-
-      if (t->arg == arg)
+  pthread_mutex_lock (&m->mtx);
+  {
+    thread = m->event.head;
+    while (thread)
+      {
+        t = thread;
+        pthread_mutex_lock (&t->mtx);
         {
-          ret++;
-          thread_list_delete (&m->event, t);
-          thread_add_unuse (m, t);
+          thread = t->next;
+
+          if (t->arg == arg)
+            {
+              ret++;
+              thread_list_delete (&m->event, t);
+              thread_add_unuse (m, t);
+            }
         }
-    }
-
-  /* thread can be on the ready list too */
-  thread = m->ready.head;
-  while (thread)
-    {
-      struct thread *t;
-
-      t = thread;
-      thread = t->next;
+        pthread_mutex_unlock (&t->mtx);
+      }
 
-      if (t->arg == arg)
+    /* thread can be on the ready list too */
+    thread = m->ready.head;
+    while (thread)
+      {
+        t = thread;
+        pthread_mutex_lock (&t->mtx);
         {
-          ret++;
-          thread_list_delete (&m->ready, t);
-          thread_add_unuse (m, t);
+          thread = t->next;
+
+          if (t->arg == arg)
+            {
+              ret++;
+              thread_list_delete (&m->ready, t);
+              thread_add_unuse (m, t);
+            }
         }
-    }
+        pthread_mutex_unlock (&t->mtx);
+      }
+  }
+  pthread_mutex_unlock (&m->mtx);
   return ret;
 }
 
@@ -1143,18 +1270,24 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
   struct timeval *timer_wait = &timer_val;
   struct timeval *timer_wait_bg;
 
-  while (1)
+  do
     {
       int num = 0;
 
       /* Signals pre-empt everything */
-      quagga_sigevent_process ();
+      if (m->handle_signals)
+        quagga_sigevent_process ();
        
+      pthread_mutex_lock (&m->mtx);
       /* Drain the ready queue of already scheduled jobs, before scheduling
        * more.
        */
       if ((thread = thread_trim_head (&m->ready)) != NULL)
-        return thread_run (m, thread, fetch);
+        {
+          fetch = thread_run (m, thread, fetch);
+          pthread_mutex_unlock (&m->mtx);
+          return fetch;
+        }
       
       /* To be fair to all kinds of threads, and avoid starvation, we
        * need to be careful to consider all thread types for scheduling
@@ -1194,8 +1327,12 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
       if (num < 0)
         {
           if (errno == EINTR)
-            continue; /* signal received - process it */
+            {
+              pthread_mutex_unlock (&m->mtx);
+              continue; /* signal received - process it */
+            }
           zlog_warn ("select() error: %s", safe_strerror (errno));
+          pthread_mutex_unlock (&m->mtx);
           return NULL;
         }
 
@@ -1215,15 +1352,28 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
         list at this time.  If this is code is uncommented, then background
         timer threads will not run unless there is nothing else to do. */
       if ((thread = thread_trim_head (&m->ready)) != NULL)
-        return thread_run (m, thread, fetch);
+        {
+          fetch = thread_run (m, thread, fetch);
+          pthread_mutex_unlock (&m->mtx);
+          return fetch;
+        }
 #endif
 
       /* Background timer/events, lowest priority */
       thread_timer_process (m->background, &now);
       
       if ((thread = thread_trim_head (&m->ready)) != NULL)
-        return thread_run (m, thread, fetch);
-    }
+        {
+          fetch = thread_run (m, thread, fetch);
+          pthread_mutex_unlock (&m->mtx);
+          return fetch;
+        }
+
+      pthread_mutex_unlock (&m->mtx);
+
+    } while (m->spin);
+
+  return NULL;
 }
 
 unsigned long
@@ -1248,13 +1398,23 @@ thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
 int
 thread_should_yield (struct thread *thread)
 {
-  return monotime_since(&thread->real, NULL) > (int64_t)thread->yield;
+  int result;
+  pthread_mutex_lock (&thread->mtx);
+  {
+    result = monotime_since(&thread->real, NULL) > (int64_t)thread->yield;
+  }
+  pthread_mutex_unlock (&thread->mtx);
+  return result;
 }
 
 void
 thread_set_yield_time (struct thread *thread, unsigned long yield_time)
 {
-  thread->yield = yield_time;
+  pthread_mutex_lock (&thread->mtx);
+  {
+    thread->yield = yield_time;
+  }
+  pthread_mutex_unlock (&thread->mtx);
 }
 
 void
@@ -1324,6 +1484,7 @@ funcname_thread_execute (struct thread_master *m,
 
   memset (&dummy, 0, sizeof (struct thread));
 
+  pthread_mutex_init (&dummy.mtx, NULL);
   dummy.type = THREAD_EVENT;
   dummy.add_type = THREAD_EXECUTE;
   dummy.master = NULL;
@@ -1332,8 +1493,12 @@ funcname_thread_execute (struct thread_master *m,
 
   tmp.func = dummy.func = func;
   tmp.funcname = dummy.funcname = funcname;
-  dummy.hist = hash_get (cpu_record, &tmp,
-                        (void * (*) (void *))cpu_record_hash_alloc);
+  pthread_mutex_lock (&cpu_record_mtx);
+  {
+    dummy.hist = hash_get (cpu_record, &tmp,
+                           (void * (*) (void *))cpu_record_hash_alloc);
+  }
+  pthread_mutex_unlock (&cpu_record_mtx);
 
   dummy.schedfrom = schedfrom;
   dummy.schedfrom_line = fromln;
index 6cb7896e7d1c89f7b59410b16d0c609705e3043f..6fb6ad7c9d9eae0e7df3b390f6f410c80cc3f423 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <zebra.h>
 #include "monotime.h"
+#include <pthread.h>
 
 struct rusage_t
 {
@@ -84,6 +85,10 @@ struct thread_master
   int fd_limit;
   struct fd_handler handler;
   unsigned long alloc;
+  long selectpoll_timeout;
+  bool spin;
+  bool handle_signals;
+  pthread_mutex_t mtx;
 };
 
 typedef unsigned char thread_type;
@@ -110,6 +115,7 @@ struct thread
   const char *funcname;
   const char *schedfrom;
   int schedfrom_line;
+  pthread_mutex_t mtx;
 };
 
 struct cpu_thread_history 
index 36755b1d9526cf9f8f356858c66cf5b805edb17c..225a82c2dbf22a912fe482c9244d9ddfbfc81f7e 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -734,6 +734,7 @@ vty_end_config (struct vty *vty)
     case ZEBRA_NODE:
     case RIP_NODE:
     case RIPNG_NODE:
+    case EIGRP_NODE:
     case BGP_NODE:
     case BGP_VPNV4_NODE:
     case BGP_VPNV6_NODE:
@@ -745,9 +746,11 @@ vty_end_config (struct vty *vty)
     case BGP_VNC_L2_GROUP_NODE:
     case BGP_IPV4_NODE:
     case BGP_IPV4M_NODE:
+    case BGP_IPV4L_NODE:
     case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:
     case BGP_EVPN_NODE:
+    case BGP_IPV6L_NODE:
     case RMAP_NODE:
     case OSPF_NODE:
     case OSPF6_NODE:
@@ -1161,6 +1164,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:
index d2a518631518a14cc921e2ab72d64817098b9c4b..e3eadf22a47ffd2b6ef65854d257c999bd6677d8 100644 (file)
@@ -733,6 +733,18 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
   s = zclient->obuf;
   stream_reset (s);
 
+  /* Some checks for labeled-unicast. The current expectation is that each
+   * nexthop is accompanied by a label in the case of labeled-unicast.
+   */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) &&
+      CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      /* We expect prefixes installed with labels and the number to match
+       * the number of nexthops.
+       */
+      assert (api->label_num == api->nexthop_num);
+    }
+
   zclient_create_header (s, cmd, api->vrf_id);
   
   /* Put type and nexthop. */
@@ -749,7 +761,7 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
 
   /* Nexthop, ifindex, distance and metric information. */
   if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
-     {
+    {
       /* traditional 32-bit data units */
       if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
         {
@@ -765,6 +777,9 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
         {
           stream_putc (s, NEXTHOP_TYPE_IPV4);
           stream_put_in_addr (s, api->nexthop[i]);
+          /* For labeled-unicast, each nexthop is followed by label. */
+          if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL))
+            stream_putl (s, api->label[i]);
         }
       for (i = 0; i < api->ifindex_num; i++)
         {
@@ -800,6 +815,18 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
   s = zclient->obuf;
   stream_reset (s);
 
+  /* Some checks for labeled-unicast. The current expectation is that each
+   * nexthop is accompanied by a label in the case of labeled-unicast.
+   */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) &&
+      CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      /* We expect prefixes installed with labels and the number to match
+       * the number of nexthops.
+       */
+      assert (api->label_num == api->nexthop_num);
+    }
+
   zclient_create_header (s, cmd, api->vrf_id);
 
   /* Put type and nexthop. */
@@ -831,6 +858,9 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
        {
          stream_putc (s, NEXTHOP_TYPE_IPV6);
          stream_write (s, (u_char *)api->nexthop[i], 16);
+          /* For labeled-unicast, each nexthop is followed by label. */
+          if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL))
+            stream_putl (s, api->label[i]);
        }
       for (i = 0; i < api->ifindex_num; i++)
        {
@@ -869,6 +899,18 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
   s = zclient->obuf;
   stream_reset (s);
 
+  /* Some checks for labeled-unicast. The current expectation is that each
+   * nexthop is accompanied by a label in the case of labeled-unicast.
+   */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) &&
+      CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      /* We expect prefixes installed with labels and the number to match
+       * the number of nexthops.
+       */
+      assert (api->label_num == api->nexthop_num);
+    }
+
   zclient_create_header (s, cmd, api->vrf_id);
 
   /* Put type and nexthop. */
@@ -907,6 +949,9 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
        {
          stream_putc (s, NEXTHOP_TYPE_IPV6);
          stream_write (s, (u_char *)api->nexthop[i], 16);
+          /* For labeled-unicast, each nexthop is followed by label. */
+          if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL))
+            stream_putl (s, api->label[i]);
        }
       for (i = 0; i < api->ifindex_num; i++)
        {
@@ -1879,6 +1924,12 @@ zclient_read (struct thread *thread)
       if (zclient->interface_link_params)
         (*zclient->interface_link_params) (command, zclient, length);
       break;
+    case ZEBRA_FEC_UPDATE:
+      if (zclient_debug)
+        zlog_debug("zclient rcvd fec update\n");
+      if (zclient->fec_update)
+        (*zclient->fec_update) (command, zclient, length);
+      break;
     default:
       break;
     }
index d3d0a202c5caf379bcaf3d56324fb9bd6db33b87..a54bf420d37feb53d3fd15fab61e927be056e38a 100644 (file)
@@ -94,6 +94,9 @@ typedef enum {
   ZEBRA_LABEL_MANAGER_CONNECT,
   ZEBRA_GET_LABEL_CHUNK,
   ZEBRA_RELEASE_LABEL_CHUNK,
+  ZEBRA_FEC_REGISTER,
+  ZEBRA_FEC_UNREGISTER,
+  ZEBRA_FEC_UPDATE,
 } zebra_message_types_t;
 
 struct redist_proto
@@ -164,6 +167,7 @@ struct zclient
   int (*redistribute_route_ipv4_del) (int, struct zclient *, uint16_t, vrf_id_t);
   int (*redistribute_route_ipv6_add) (int, struct zclient *, uint16_t, vrf_id_t);
   int (*redistribute_route_ipv6_del) (int, struct zclient *, uint16_t, vrf_id_t);
+  int (*fec_update) (int, struct zclient *, uint16_t);
 };
 
 /* Zebra API message flag. */
@@ -174,6 +178,7 @@ struct zclient
 #define ZAPI_MESSAGE_TAG      0x10
 #define ZAPI_MESSAGE_MTU      0x20
 #define ZAPI_MESSAGE_SRCPFX   0x40
+#define ZAPI_MESSAGE_LABEL    0x80
 
 /* Zserv protocol message header */
 struct zserv_header
@@ -206,6 +211,9 @@ struct zapi_ipv4
   u_char ifindex_num;
   ifindex_t *ifindex;
 
+  u_char label_num;
+  unsigned int *label;
+
   u_char distance;
 
   u_int32_t metric;
@@ -297,6 +305,9 @@ struct zapi_ipv6
   u_char ifindex_num;
   ifindex_t *ifindex;
 
+  u_char label_num;
+  unsigned int *label;
+
   u_char distance;
 
   u_int32_t metric;
index 760264d752fe72ad60616ad21df0416f67dcf43c..cd72dc67f82feba622212ef9ef8aed4d9068aa79 100644 (file)
@@ -393,6 +393,9 @@ extern const char *zserv_command_string (unsigned int command);
 #define ZEBRA_FLAG_SCOPE_LINK         0x100
 #define ZEBRA_FLAG_FIB_OVERRIDE       0x200
 
+/* Zebra FEC flags. */
+#define ZEBRA_FEC_REGISTER_LABEL_INDEX        0x1
+
 #ifndef INADDR_LOOPBACK
 #define        INADDR_LOOPBACK 0x7f000001      /* Internet address 127.0.0.1.  */
 #endif
@@ -413,11 +416,13 @@ typedef enum {
 #define SAFI_ENCAP               5
 #define SAFI_RESERVED_5           5
 #define SAFI_EVPN                 6
-#define SAFI_MAX                  7
+#define SAFI_LABELED_UNICAST      7
+#define SAFI_MAX                  8
 
 #define IANA_SAFI_RESERVED            0
 #define IANA_SAFI_UNICAST             1
 #define IANA_SAFI_MULTICAST           2
+#define IANA_SAFI_LABELED_UNICAST     4
 #define IANA_SAFI_ENCAP               7
 #define IANA_SAFI_MPLS_VPN            128
 
@@ -512,6 +517,8 @@ static inline safi_t safi_iana2int (safi_t safi)
     return SAFI_ENCAP;
   if (safi == IANA_SAFI_EVPN)
     return SAFI_EVPN;
+  if (safi == IANA_SAFI_LABELED_UNICAST)
+    return SAFI_LABELED_UNICAST;
   return SAFI_MAX;
 }
 
@@ -527,6 +534,8 @@ static inline safi_t safi_int2iana (safi_t safi)
     return IANA_SAFI_ENCAP;
   if (safi == SAFI_EVPN)
     return IANA_SAFI_EVPN;
+  if (safi == SAFI_LABELED_UNICAST)
+    return IANA_SAFI_LABELED_UNICAST;
   return IANA_SAFI_RESERVED;
 }
 
index 3f3bd0a73574620a2ba5b3b7dc04cb74a2369aaf..798188b0b93d284c066bf7845fd74f23040fde0d 100644 (file)
@@ -4,4 +4,5 @@ Makefile.in
 .arch-ids
 *~
 *.loT
-
+!ax_pthread.m4
+!ax_sys_weak_alias.m4
diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4
new file mode 100644 (file)
index 0000000..d383ad5
--- /dev/null
@@ -0,0 +1,332 @@
+# ===========================================================================
+#        http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+#
+# DESCRIPTION
+#
+#   This macro figures out how to build C programs using POSIX threads. It
+#   sets the PTHREAD_LIBS output variable to the threads library and linker
+#   flags, and the PTHREAD_CFLAGS output variable to any special C compiler
+#   flags that are needed. (The user can also force certain compiler
+#   flags/libs to be tested by setting these environment variables.)
+#
+#   Also sets PTHREAD_CC to any special C compiler that is needed for
+#   multi-threaded programs (defaults to the value of CC otherwise). (This
+#   is necessary on AIX to use the special cc_r compiler alias.)
+#
+#   NOTE: You are assumed to not only compile your program with these flags,
+#   but also link it with them as well. e.g. you should link with
+#   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+#
+#   If you are only building threads programs, you may wish to use these
+#   variables in your default LIBS, CFLAGS, and CC:
+#
+#     LIBS="$PTHREAD_LIBS $LIBS"
+#     CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+#     CC="$PTHREAD_CC"
+#
+#   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
+#   has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
+#   (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#
+#   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
+#   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
+#   PTHREAD_CFLAGS.
+#
+#   ACTION-IF-FOUND is a list of shell commands to run if a threads library
+#   is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
+#   is not found. If ACTION-IF-FOUND is not specified, the default action
+#   will define HAVE_PTHREAD.
+#
+#   Please let the authors know if this macro fails on any platform, or if
+#   you have any other suggestions or comments. This macro was based on work
+#   by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
+#   from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
+#   Alejandro Forero Cuervo to the autoconf macro repository. We are also
+#   grateful for the helpful feedback of numerous users.
+#
+#   Updated for Autoconf 2.68 by Daniel Richard G.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+#   Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
+#
+#   This program 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 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 21
+
+AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
+AC_DEFUN([AX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_PUSH([C])
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
+        AC_MSG_RESULT([$ax_pthread_ok])
+        if test x"$ax_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+#      ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case ${host_os} in
+        solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
+        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+        # a function called by this macro, so we could check for that, but
+        # who knows whether they'll stub that too in a future libc.)  So,
+        # we'll just look for -pthreads and -lpthread first:
+
+        ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
+        ;;
+
+        darwin*)
+        ax_pthread_flags="-pthread $ax_pthread_flags"
+        ;;
+esac
+
+# Clang doesn't consider unrecognized options an error unless we specify
+# -Werror. We throw in some extra Clang-specific options to ensure that
+# this doesn't happen for GCC, which also accepts -Werror.
+
+AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
+save_CFLAGS="$CFLAGS"
+ax_pthread_extra_flags="-Werror"
+CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
+                  [AC_MSG_RESULT([yes])],
+                  [ax_pthread_extra_flags=
+                   AC_MSG_RESULT([no])])
+CFLAGS="$save_CFLAGS"
+
+if test x"$ax_pthread_ok" = xno; then
+for flag in $ax_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+                pthread-config)
+                AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
+                if test x"$ax_pthread_config" = xno; then continue; fi
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                ;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+                        static void routine(void *a) { a = 0; }
+                        static void *start_routine(void *a) { return a; }],
+                       [pthread_t th; pthread_attr_t attr;
+                        pthread_create(&th, 0, start_routine, 0);
+                        pthread_join(th, 0);
+                        pthread_attr_init(&attr);
+                        pthread_cleanup_push(routine, 0);
+                        pthread_cleanup_pop(0) /* ; */])],
+                [ax_pthread_ok=yes],
+                [])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT([$ax_pthread_ok])
+        if test "x$ax_pthread_ok" = xyes; then
+                break;
+        fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$ax_pthread_ok" = xyes; then
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+        AC_MSG_CHECKING([for joinable pthread attribute])
+        attr_name=unknown
+        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+            AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+                           [int attr = $attr; return attr /* ; */])],
+                [attr_name=$attr; break],
+                [])
+        done
+        AC_MSG_RESULT([$attr_name])
+        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+            AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
+                               [Define to necessary symbol if this constant
+                                uses a non-standard name on your system.])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case ${host_os} in
+            aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
+            osf* | hpux*) flag="-D_REENTRANT";;
+            solaris*)
+            if test "$GCC" = "yes"; then
+                flag="-D_REENTRANT"
+            else
+                # TODO: What about Clang on Solaris?
+                flag="-mt -D_REENTRANT"
+            fi
+            ;;
+        esac
+        AC_MSG_RESULT([$flag])
+        if test "x$flag" != xno; then
+            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
+            [ax_cv_PTHREAD_PRIO_INHERIT], [
+                AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
+                                                [[int i = PTHREAD_PRIO_INHERIT;]])],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=no])
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
+            [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: compile with *_r variant
+        if test "x$GCC" != xyes; then
+            case $host_os in
+                aix*)
+                AS_CASE(["x/$CC"],
+                  [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
+                  [#handle absolute path differently from PATH based program lookup
+                   AS_CASE(["x$CC"],
+                     [x/*],
+                     [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
+                     [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
+                ;;
+            esac
+        fi
+fi
+
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+
+AC_SUBST([PTHREAD_LIBS])
+AC_SUBST([PTHREAD_CFLAGS])
+AC_SUBST([PTHREAD_CC])
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$ax_pthread_ok" = xyes; then
+        ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
+        :
+else
+        ax_pthread_ok=no
+        $2
+fi
+AC_LANG_POP
+])dnl AX_PTHREAD
index aac8ef4b8b529974aa192fcf4cb44b4ecc5a61c1..620dacb1576d41feed7fe11baf7e24c63163946f 100644 (file)
@@ -2459,7 +2459,7 @@ ospf_apiserver_clients_notify_nsm_change (struct ospf_neighbor *nbr)
 {
   struct msg *msg;
   struct in_addr ifaddr = { .s_addr = 0L };
-  struct in_addr nbraddr = { .s_addr = 0L };
+  struct in_addr nbraddr;
 
   assert (nbr);
 
index f5880ca9e35f6b51a23244c50003b4b163eb7e11..4a7dbb9541908b042ea927ce4666d40d100c6260 100644 (file)
@@ -6333,7 +6333,7 @@ DEFUN (no_ip_ospf_dead_interval,
 {
   VTY_DECLVAR_CONTEXT(interface, ifp);
   int idx_ipv4 = argc - 1;
-  struct in_addr addr;
+  struct in_addr addr = { .s_addr = 0L};
   int ret;
   struct ospf_if_params *params;
   struct ospf_interface *oi;
@@ -6465,6 +6465,7 @@ DEFUN (no_ip_ospf_hello_interval,
   int idx = 0;
   struct in_addr addr;
   struct ospf_if_params *params;
+
   params = IF_DEF_PARAMS (ifp);
 
   if (argv_find (argv, argc, "A.B.C.D", &idx))
index f2bfb846dda46ee402e5e6cb8b30f65e65788892..17f5fcfe0f9a321b872ea3940e1abf970b9d4611 100644 (file)
@@ -230,6 +230,7 @@ int pim_assert_recv(struct interface *ifp,
   int offset;
   uint8_t *curr;
   int curr_size;
+  struct pim_interface *pim_ifp = NULL;
 
   on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
 
@@ -311,6 +312,10 @@ int pim_assert_recv(struct interface *ifp,
 
   msg_metric.ip_address = src_addr;
 
+  pim_ifp = ifp->info;
+  zassert(pim_ifp);
+  ++pim_ifp->pim_ifstat_assert_recv;
+
   return dispatch_assert(ifp,
                         msg_source_addr.u.prefix4,
                         sg.grp,
@@ -473,6 +478,7 @@ static int pim_assert_do(struct pim_ifchannel *ch,
               metric.route_metric,
               PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
   }
+  ++pim_ifp->pim_ifstat_assert_send;
 
   if (pim_msg_send(pim_ifp->pim_sock_fd,
                   pim_ifp->primary_address,
index 1224bc5fc80223b9da14d172784a79d6de848915..c6e9ae0c376811daed2629d85489b72cba872803 100644 (file)
@@ -820,6 +820,7 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch
     mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
 
     if (uj) {
+      char pbuf[PREFIX2STR_BUFFER];
       json_row = json_object_new_object();
       json_object_pim_ifp_add(json_row, ifp);
 
@@ -831,7 +832,10 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch
 
         sec_list = json_object_new_array();
         for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) {
-          json_object_array_add(sec_list, json_object_new_string(inet_ntoa(sec_addr->addr)));
+          json_object_array_add(sec_list,
+                                json_object_new_string(prefix2str(&sec_addr->addr,
+                                                                 pbuf,
+                                                                 sizeof(pbuf))));
         }
         json_object_object_add(json_row, "secondaryAddressList", sec_list);
       }
@@ -922,11 +926,14 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch
         vty_out(vty, "Use Source : %s%s", inet_ntoa(pim_ifp->update_source), VTY_NEWLINE);
       }
       if (pim_ifp->sec_addr_list) {
+        char pbuf[PREFIX2STR_BUFFER];
         vty_out(vty, "Address    : %s (primary)%s",
-                                    inet_ntoa(ifaddr), VTY_NEWLINE);
+                inet_ntoa(ifaddr), VTY_NEWLINE);
         for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) {
           vty_out(vty, "             %s%s",
-                                    inet_ntoa(sec_addr->addr), VTY_NEWLINE);
+                  prefix2str(&sec_addr->addr,
+                            pbuf,
+                            sizeof(pbuf)), VTY_NEWLINE);
         }
       } else {
         vty_out(vty, "Address    : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE);
@@ -1116,6 +1123,163 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
   json_object_free(json);
 }
 
+static void pim_show_interface_traffic (struct vty *vty, u_char uj)
+{
+  struct interface *ifp = NULL;
+  struct pim_interface *pim_ifp = NULL;
+  struct listnode *node = NULL;
+  json_object *json = NULL;
+  json_object *json_row = NULL;
+
+  if (uj)
+    json = json_object_new_object ();
+  else
+    {
+      vty_out (vty, "%s", VTY_NEWLINE);
+      vty_out (vty, "%-12s%-17s%-17s%-17s%-17s%-17s%-17s%s", "Interface",
+               "    HELLO", "    JOIN", "   PRUNE", "   REGISTER",
+               "  REGISTER-STOP", "  ASSERT", VTY_NEWLINE);
+      vty_out (vty,
+               "%-10s%-18s%-17s%-17s%-17s%-17s%-17s%s",
+               "", "      Rx/Tx", "     Rx/Tx", "    Rx/Tx", "    Rx/Tx",
+               "     Rx/Tx", "    Rx/Tx", VTY_NEWLINE);
+      vty_out (vty,
+           "---------------------------------------------------------------------------------------------------------------%s",
+           VTY_NEWLINE);
+    }
+
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
+    {
+      pim_ifp = ifp->info;
+
+      if (!pim_ifp)
+        continue;
+
+      if (pim_ifp->pim_sock_fd < 0)
+        continue;
+      if (uj)
+        {
+          json_row = json_object_new_object ();
+          json_object_pim_ifp_add (json_row, ifp);
+          json_object_int_add (json_row, "helloRx", pim_ifp->pim_ifstat_hello_recv);
+          json_object_int_add (json_row, "helloTx", pim_ifp->pim_ifstat_hello_sent);
+          json_object_int_add (json_row, "joinRx", pim_ifp->pim_ifstat_join_recv);
+          json_object_int_add (json_row, "joinTx", pim_ifp->pim_ifstat_join_send);
+          json_object_int_add (json_row, "registerRx", pim_ifp->pim_ifstat_reg_recv);
+          json_object_int_add (json_row, "registerTx", pim_ifp->pim_ifstat_reg_recv);
+          json_object_int_add (json_row, "registerStopRx", pim_ifp->pim_ifstat_reg_stop_recv);
+          json_object_int_add (json_row, "registerStopTx", pim_ifp->pim_ifstat_reg_stop_send);
+          json_object_int_add (json_row, "assertRx", pim_ifp->pim_ifstat_assert_recv);
+          json_object_int_add (json_row, "assertTx", pim_ifp->pim_ifstat_assert_send);
+
+          json_object_object_add (json, ifp->name, json_row);
+        }
+      else
+        {
+          vty_out (vty,
+               "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %s",
+               ifp->name, pim_ifp->pim_ifstat_hello_recv,
+               pim_ifp->pim_ifstat_hello_sent, pim_ifp->pim_ifstat_join_recv,
+               pim_ifp->pim_ifstat_join_send, pim_ifp->pim_ifstat_prune_recv,
+               pim_ifp->pim_ifstat_prune_send, pim_ifp->pim_ifstat_reg_recv,
+               pim_ifp->pim_ifstat_reg_send,
+               pim_ifp->pim_ifstat_reg_stop_recv,
+               pim_ifp->pim_ifstat_reg_stop_send,
+               pim_ifp->pim_ifstat_assert_recv,
+               pim_ifp->pim_ifstat_assert_send, VTY_NEWLINE);
+        }
+    }
+  if (uj)
+    {
+      vty_out (vty, "%s%s", json_object_to_json_string_ext (json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+      json_object_free (json);
+    }
+}
+
+static void pim_show_interface_traffic_single (struct vty *vty, const char *ifname, u_char uj)
+{
+  struct interface *ifp = NULL;
+  struct pim_interface *pim_ifp = NULL;
+  struct listnode *node = NULL;
+  json_object *json = NULL;
+  json_object *json_row = NULL;
+  uint8_t found_ifname = 0;
+
+  if (uj)
+    json = json_object_new_object ();
+  else
+    {
+      vty_out (vty, "%s", VTY_NEWLINE);
+      vty_out (vty, "%-12s%-17s%-17s%-17s%-17s%-17s%-17s%s", "Interface",
+               "    HELLO", "    JOIN", "   PRUNE", "   REGISTER",
+               "  REGISTER-STOP", "  ASSERT", VTY_NEWLINE);
+      vty_out (vty,
+               "%-10s%-18s%-17s%-17s%-17s%-17s%-17s%s",
+               "", "      Rx/Tx", "     Rx/Tx", "    Rx/Tx", "    Rx/Tx",
+               "     Rx/Tx", "    Rx/Tx", VTY_NEWLINE);
+      vty_out (vty,
+           "---------------------------------------------------------------------------------------------------------------%s",
+           VTY_NEWLINE);
+    }
+
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
+    {
+      if (strcmp (ifname, ifp->name))
+        continue;
+
+      pim_ifp = ifp->info;
+
+      if (!pim_ifp)
+        continue;
+
+      if (pim_ifp->pim_sock_fd < 0)
+        continue;
+
+      found_ifname = 1;
+      if (uj)
+        {
+          json_row = json_object_new_object ();
+          json_object_pim_ifp_add (json_row, ifp);
+          json_object_int_add (json_row, "helloRx", pim_ifp->pim_ifstat_hello_recv);
+          json_object_int_add (json_row, "helloTx", pim_ifp->pim_ifstat_hello_sent);
+          json_object_int_add (json_row, "joinRx", pim_ifp->pim_ifstat_join_recv);
+          json_object_int_add (json_row, "joinTx", pim_ifp->pim_ifstat_join_send);
+          json_object_int_add (json_row, "registerRx", pim_ifp->pim_ifstat_reg_recv);
+          json_object_int_add (json_row, "registerTx", pim_ifp->pim_ifstat_reg_recv);
+          json_object_int_add (json_row, "registerStopRx", pim_ifp->pim_ifstat_reg_stop_recv);
+          json_object_int_add (json_row, "registerStopTx", pim_ifp->pim_ifstat_reg_stop_send);
+          json_object_int_add (json_row, "assertRx", pim_ifp->pim_ifstat_assert_recv);
+          json_object_int_add (json_row, "assertTx", pim_ifp->pim_ifstat_assert_send);
+
+          json_object_object_add (json, ifp->name, json_row);
+        }
+      else
+        {
+          vty_out (vty,
+               "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %s",
+               ifp->name, pim_ifp->pim_ifstat_hello_recv,
+               pim_ifp->pim_ifstat_hello_sent, pim_ifp->pim_ifstat_join_recv,
+               pim_ifp->pim_ifstat_join_send, pim_ifp->pim_ifstat_prune_recv,
+               pim_ifp->pim_ifstat_prune_send, pim_ifp->pim_ifstat_reg_recv,
+               pim_ifp->pim_ifstat_reg_send,
+               pim_ifp->pim_ifstat_reg_stop_recv,
+               pim_ifp->pim_ifstat_reg_stop_send,
+               pim_ifp->pim_ifstat_assert_recv,
+               pim_ifp->pim_ifstat_assert_send, VTY_NEWLINE);
+        }
+    }
+  if (uj)
+    {
+      vty_out (vty, "%s%s", json_object_to_json_string_ext (json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+      json_object_free (json);
+    }
+  else
+    {
+      if (!found_ifname)
+        vty_out (vty, "%% No such interface%s", VTY_NEWLINE);
+    }
+}
+
 static void pim_show_join(struct vty *vty, u_char uj)
 {
   struct pim_interface *pim_ifp;
@@ -1617,13 +1781,9 @@ static void pim_show_neighbors_secondary(struct vty *vty)
                     neigh_src_str, sizeof(neigh_src_str));
 
       for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, prefix_node, p)) {
-       char neigh_sec_str[INET_ADDRSTRLEN];
+       char neigh_sec_str[PREFIX2STR_BUFFER];
 
-       if (p->family != AF_INET)
-         continue;
-
-       pim_inet4_dump("<src?>", p->u.prefix4,
-                      neigh_sec_str, sizeof(neigh_sec_str));
+       prefix2str(p, neigh_sec_str, sizeof(neigh_sec_str));
 
        vty_out(vty, "%-9s %-15s %-15s %-15s%s",
                ifp->name,
@@ -2494,6 +2654,45 @@ DEFUN (clear_ip_pim_interfaces,
   return CMD_SUCCESS;
 }
 
+DEFUN (clear_ip_pim_interface_traffic,
+       clear_ip_pim_interface_traffic_cmd,
+       "clear ip pim interface traffic",
+       "Reset functions\n"
+       "IP information\n"
+       "PIM clear commands\n"
+       "Reset PIM interfaces\n"
+       "Reset Protocol Packet counters\n")
+{
+  struct listnode  *ifnode = NULL;
+  struct listnode  *ifnextnode = NULL;
+  struct interface *ifp = NULL;
+  struct pim_interface *pim_ifp = NULL;
+
+  for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp))
+    {
+      pim_ifp = ifp->info;
+
+      if (!pim_ifp)
+        continue;
+
+      pim_ifp->pim_ifstat_hello_recv = 0;
+      pim_ifp->pim_ifstat_hello_sent = 0;
+      pim_ifp->pim_ifstat_join_recv = 0;
+      pim_ifp->pim_ifstat_join_send = 0;
+      pim_ifp->pim_ifstat_prune_recv = 0;
+      pim_ifp->pim_ifstat_prune_send = 0;
+      pim_ifp->pim_ifstat_reg_recv = 0;
+      pim_ifp->pim_ifstat_reg_send = 0;
+      pim_ifp->pim_ifstat_reg_stop_recv = 0;
+      pim_ifp->pim_ifstat_reg_stop_send = 0;
+      pim_ifp->pim_ifstat_assert_recv = 0;
+      pim_ifp->pim_ifstat_assert_send = 0;
+
+    }
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (clear_ip_pim_oil,
        clear_ip_pim_oil_cmd,
        "clear ip pim oil",
@@ -2880,7 +3079,7 @@ DEFUN (show_ip_pim_nexthop_lookup,
   char nexthop_addr_str[PREFIX_STRLEN];
   char grp_str[PREFIX_STRLEN];
 
-  addr_str = (const char *)argv[0];
+  addr_str = argv[4]->arg;
   result = inet_pton (AF_INET, addr_str, &src_addr);
   if (result <= 0)
     {
@@ -2895,7 +3094,7 @@ DEFUN (show_ip_pim_nexthop_lookup,
       return CMD_WARNING;
     }
 
-  addr_str1 = (const char *)argv[1];
+  addr_str1 = argv[5]->arg;
   result = inet_pton (AF_INET, addr_str1, &grp_addr);
   if (result <= 0)
     {
@@ -2939,6 +3138,28 @@ DEFUN (show_ip_pim_nexthop_lookup,
   return CMD_SUCCESS;
 }
 
+DEFUN (show_ip_pim_interface_traffic,
+       show_ip_pim_interface_traffic_cmd,
+       "show ip pim interface traffic [WORD] [json]",
+       SHOW_STR
+       IP_STR
+       PIM_STR
+       "PIM interface information\n"
+       "Protocol Packet counters\n"
+       "Interface name\n"
+       "JavaScript Object Notation\n")
+{
+  u_char uj = use_json (argc, argv);
+  int idx = 0;
+
+  if (argv_find(argv, argc, "WORD", &idx))
+    pim_show_interface_traffic_single (vty, argv[idx]->arg, uj);
+  else
+    pim_show_interface_traffic (vty, uj);
+
+  return CMD_SUCCESS;
+}
+
 static void show_multicast_interfaces(struct vty *vty)
 {
   struct listnode  *node;
@@ -3735,6 +3956,31 @@ DEFUN (no_ip_pim_packets,
   return CMD_SUCCESS;
 }
 
+DEFUN (ip_pim_v6_secondary,
+       ip_pim_v6_secondary_cmd,
+       "ip pim send-v6-secondary",
+       IP_STR
+       "pim multicast routing\n"
+       "Send v6 secondary addresses\n")
+{
+  pimg->send_v6_secondary = 1;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_v6_secondary,
+       no_ip_pim_v6_secondary_cmd,
+       "no ip pim send-v6-secondary",
+       NO_STR
+       IP_STR
+       "pim multicast routing\n"
+       "Send v6 secondary addresses\n")
+{
+  pimg->send_v6_secondary = 0;
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (ip_pim_rp,
        ip_pim_rp_cmd,
        "ip pim rp A.B.C.D [A.B.C.D/M]",
@@ -3803,12 +4049,12 @@ DEFUN (no_ip_pim_rp,
        "ip address of RP\n"
        "Group Address range to cover\n")
 {
-  int idx_ipv4 = 4;
+  int idx_ipv4 = 4, idx_group = 0;
 
-  if (argc == (idx_ipv4 + 1))
-    return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, NULL, NULL);
+  if (argv_find (argv, argc, "A.B.C.D/M", &idx_group))
+    return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_group]->arg, NULL);
   else
-    return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_ipv4 + 1]->arg, NULL);
+    return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, NULL, NULL);
 }
 
 DEFUN (no_ip_pim_rp_prefix_list,
@@ -6457,13 +6703,16 @@ DEFUN (show_ip_msdp_sa_sg,
        "JavaScript Object Notation\n")
 {
   u_char uj = use_json(argc, argv);
-  if (uj)
-    argc--;
 
-  if (argc == 6)
-    ip_msdp_show_sa_sg(vty, argv[4]->arg, argv[5]->arg, uj);
-  else if (argc == 5)
-    ip_msdp_show_sa_addr(vty, argv[4]->arg, uj);
+  int idx = 0;
+  char *src_ip = argv_find (argv, argc, "A.B.C.D", &idx) ? argv[idx++]->arg : NULL;
+  char *grp_ip = idx < argc && argv_find (argv, argc, "A.B.C.D", &idx) ?
+                 argv[idx]->arg : NULL;
+
+  if (src_ip && grp_ip)
+    ip_msdp_show_sa_sg(vty, src_ip, grp_ip, uj);
+  else if (src_ip)
+    ip_msdp_show_sa_addr(vty, src_ip, uj);
   else
     ip_msdp_show_sa(vty, uj);
 
@@ -6499,6 +6748,8 @@ void pim_cmd_init()
   install_element (CONFIG_NODE, &no_ip_pim_keep_alive_cmd);
   install_element (CONFIG_NODE, &ip_pim_packets_cmd);
   install_element (CONFIG_NODE, &no_ip_pim_packets_cmd);
+  install_element (CONFIG_NODE, &ip_pim_v6_secondary_cmd);
+  install_element (CONFIG_NODE, &no_ip_pim_v6_secondary_cmd);
   install_element (CONFIG_NODE, &ip_ssmpingd_cmd);
   install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd); 
   install_element (CONFIG_NODE, &ip_msdp_peer_cmd);
@@ -6545,6 +6796,7 @@ void pim_cmd_init()
   install_element (VIEW_NODE, &show_ip_pim_assert_internal_cmd);
   install_element (VIEW_NODE, &show_ip_pim_assert_metric_cmd);
   install_element (VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd);
+  install_element (VIEW_NODE, &show_ip_pim_interface_traffic_cmd);
   install_element (VIEW_NODE, &show_ip_pim_interface_cmd);
   install_element (VIEW_NODE, &show_ip_pim_join_cmd);
   install_element (VIEW_NODE, &show_ip_pim_local_membership_cmd);
@@ -6569,6 +6821,7 @@ void pim_cmd_init()
   install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
   install_element (ENABLE_NODE, &clear_ip_mroute_cmd);
   install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd);
+  install_element (ENABLE_NODE, &clear_ip_pim_interface_traffic_cmd);
   install_element (ENABLE_NODE, &clear_ip_pim_oil_cmd);
 
   install_element (ENABLE_NODE, &debug_igmp_cmd);
index 3d7ae4ad22bdc977bdd2b45848aab3157341b1a3..ee9433d7973b63e1be15d869f18397a6540dc04e 100644 (file)
@@ -428,15 +428,14 @@ int pim_hello_recv(struct interface *ifp,
   return 0;
 }
 
-int pim_hello_build_tlv(const char *ifname,
+int pim_hello_build_tlv(struct interface *ifp,
                        uint8_t *tlv_buf, int tlv_buf_size,
                        uint16_t holdtime,
                        uint32_t dr_priority,
                        uint32_t generation_id,
                        uint16_t propagation_delay,
                        uint16_t override_interval,
-                       int can_disable_join_suppression,
-                       struct list *ifconnected)
+                       int can_disable_join_suppression)
 {
   uint8_t *curr = tlv_buf;
   uint8_t *pastend = tlv_buf + tlv_buf_size;
@@ -454,7 +453,7 @@ int pim_hello_build_tlv(const char *ifname,
   if (!curr) {
     if (PIM_DEBUG_PIM_HELLO) {
       zlog_debug("%s: could not set PIM hello Holdtime option for interface %s",
-                __PRETTY_FUNCTION__, ifname);
+                __PRETTY_FUNCTION__, ifp->name);
     }
     return -1;
   }
@@ -468,7 +467,7 @@ int pim_hello_build_tlv(const char *ifname,
   if (!tmp) {
     if (PIM_DEBUG_PIM_HELLO) {
       zlog_debug("%s: could not set PIM LAN Prune Delay option for interface %s",
-                __PRETTY_FUNCTION__, ifname);
+                __PRETTY_FUNCTION__, ifp->name);
     }
     return -1;
   }
@@ -485,7 +484,7 @@ int pim_hello_build_tlv(const char *ifname,
   if (!curr) {
     if (PIM_DEBUG_PIM_HELLO) {
       zlog_debug("%s: could not set PIM hello DR Priority option for interface %s",
-                __PRETTY_FUNCTION__, ifname);
+                __PRETTY_FUNCTION__, ifp->name);
     }
     return -2;
   }
@@ -498,23 +497,38 @@ int pim_hello_build_tlv(const char *ifname,
   if (!curr) {
     if (PIM_DEBUG_PIM_HELLO) {
       zlog_debug("%s: could not set PIM hello Generation ID option for interface %s",
-                __PRETTY_FUNCTION__, ifname);
+                __PRETTY_FUNCTION__, ifp->name);
     }
     return -3;
   }
 
   /* Secondary Address List */
-  if (ifconnected) {
+  if (ifp->connected->count) {
     curr = pim_tlv_append_addrlist_ucast(curr,
                                         pastend,
-                                        ifconnected);
+                                        ifp->connected,
+                                         AF_INET);
     if (!curr) {
       if (PIM_DEBUG_PIM_HELLO) {
-       zlog_debug("%s: could not set PIM hello Secondary Address List option for interface %s",
-                 __PRETTY_FUNCTION__, ifname);
+       zlog_debug("%s: could not set PIM hello v4 Secondary Address List option for interface %s",
+                 __PRETTY_FUNCTION__, ifp->name);
       }
       return -4;
     }
+    if (pimg->send_v6_secondary)
+      {
+        curr = pim_tlv_append_addrlist_ucast(curr,
+                                             pastend,
+                                             ifp->connected,
+                                             AF_INET6);
+        if (!curr) {
+          if (PIM_DEBUG_PIM_HELLO) {
+            zlog_debug("%s: could not sent PIM hello v6 secondary Address List option for interface %s",
+                       __PRETTY_FUNCTION__, ifp->name);
+          }
+          return -4;
+        }
+      }
   }
 
   return curr - tlv_buf;
index 3a6d3361ba3b877de661a33744aa199feed9e88c..1f8b348bd77665a7d6b5c65251e6ef481d37ebdc 100644 (file)
@@ -29,15 +29,14 @@ int pim_hello_recv(struct interface *ifp,
                   struct in_addr src_addr,
                   uint8_t *tlv_buf, int tlv_buf_size);
 
-int pim_hello_build_tlv(const char *ifname,
+int pim_hello_build_tlv(struct interface *ifp,
                        uint8_t *tlv_buf, int tlv_buf_size,
                        uint16_t holdtime,
                        uint32_t dr_priority,
                        uint32_t generation_id,
                        uint16_t propagation_delay,
                        uint16_t override_interval,
-                       int can_disable_join_suppression,
-                       struct list *ifconnected);
+                       int can_disable_join_suppression);
 
 void pim_hello_require(struct interface *ifp);
 
index cce87ae5fd49b467e2653812e22bd36ad0f7bbb2..48a59344eb6f679d40c0800947d81972ad760973 100644 (file)
@@ -328,12 +328,29 @@ static int pim_sec_addr_comp(const void *p1, const void *p2)
   const struct pim_secondary_addr *sec1 = p1;
   const struct pim_secondary_addr *sec2 = p2;
 
-  if (ntohl(sec1->addr.s_addr) < ntohl(sec2->addr.s_addr))
+  if (sec1->addr.family == AF_INET &&
+      sec2->addr.family == AF_INET6)
     return -1;
 
-  if (ntohl(sec1->addr.s_addr) > ntohl(sec2->addr.s_addr))
+  if (sec1->addr.family == AF_INET6 &&
+      sec2->addr.family == AF_INET)
     return 1;
 
+  if (sec1->addr.family == AF_INET)
+    {
+      if (ntohl(sec1->addr.u.prefix4.s_addr) < ntohl(sec2->addr.u.prefix4.s_addr))
+        return -1;
+
+      if (ntohl(sec1->addr.u.prefix4.s_addr) > ntohl(sec2->addr.u.prefix4.s_addr))
+        return 1;
+    }
+  else
+    {
+      return memcmp (&sec1->addr.u.prefix6,
+                     &sec2->addr.u.prefix6,
+                     sizeof (struct in6_addr));
+    }
+
   return 0;
 }
 
@@ -343,7 +360,7 @@ static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
 }
 
 static struct pim_secondary_addr *
-pim_sec_addr_find(struct pim_interface *pim_ifp, struct in_addr addr)
+pim_sec_addr_find(struct pim_interface *pim_ifp, struct prefix *addr)
 {
   struct pim_secondary_addr *sec_addr;
   struct listnode *node;
@@ -353,7 +370,7 @@ pim_sec_addr_find(struct pim_interface *pim_ifp, struct in_addr addr)
   }
 
   for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
-    if (sec_addr->addr.s_addr == addr.s_addr) {
+    if (prefix_cmp(&sec_addr->addr, addr)) {
       return sec_addr;
     }
   }
@@ -368,7 +385,7 @@ static void pim_sec_addr_del(struct pim_interface *pim_ifp,
   pim_sec_addr_free(sec_addr);
 }
 
-static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr)
+static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct prefix *addr)
 {
   int changed = 0;
   struct pim_secondary_addr *sec_addr;
@@ -395,7 +412,7 @@ static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr)
   }
 
   changed = 1;
-  sec_addr->addr = addr;
+  sec_addr->addr = *addr;
   listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
 
   return changed;
@@ -437,10 +454,6 @@ static int pim_sec_addr_update(struct interface *ifp)
   for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
     struct prefix *p = ifc->address;
 
-    if (p->family != AF_INET) {
-      continue;
-    }
-
     if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
       continue;
     }
@@ -450,7 +463,7 @@ static int pim_sec_addr_update(struct interface *ifp)
       continue;
     }
 
-    if (pim_sec_addr_add(pim_ifp, p->u.prefix4)) {
+    if (pim_sec_addr_add(pim_ifp, p)) {
       changed = 1;
     }
   }
@@ -575,12 +588,15 @@ void pim_if_addr_add(struct connected *ifc)
 
   detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
 
+  if (ifc->address->family != AF_INET)
+    return;
+
   if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
     struct igmp_sock *igmp;
 
     /* lookup IGMP socket */
     igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
-                                      ifaddr);
+                                       ifaddr);
     if (!igmp) {
       /* if addr new, add IGMP socket */
       pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
@@ -727,14 +743,17 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
   ifp = ifc->ifp;
   zassert(ifp);
 
+  if (ifc->address->family != AF_INET)
+    return;
+
   if (PIM_DEBUG_ZEBRA) {
     char buf[BUFSIZ];
     prefix2str(ifc->address, buf, BUFSIZ);
     zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
-              __PRETTY_FUNCTION__,
-              ifp->name, ifp->ifindex, buf,
-              CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
-              "secondary" : "primary");
+               __PRETTY_FUNCTION__,
+               ifp->name, ifp->ifindex, buf,
+               CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
+               "secondary" : "primary");
   }
 
   detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__);
@@ -761,12 +780,9 @@ void pim_if_addr_add_all(struct interface *ifp)
     struct prefix *p = ifc->address;
     
     if (p->family != AF_INET)
-      {
-        v6_addrs++;
-        continue;
-      }
-
-    v4_addrs++;
+      v6_addrs++;
+    else
+      v4_addrs++;
     pim_if_addr_add(ifc);
   }
 
@@ -1157,6 +1173,7 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
   struct listnode *neighnode;
   struct pim_neighbor *neigh;
   struct pim_interface *pim_ifp;
+  struct prefix p;
 
   zassert(ifp);
 
@@ -1168,6 +1185,10 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
     return 0;
   }
 
+  p.family = AF_INET;
+  p.u.prefix4 = addr;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+
   for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
 
     /* primary address ? */
@@ -1175,7 +1196,7 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
       return neigh;
 
     /* secondary address ? */
-    if (pim_neighbor_find_secondary(neigh, addr))
+    if (pim_neighbor_find_secondary(neigh, &p))
        return neigh;
   }
 
index e98c17fed287fc0e902400d60ed256425fce072a..3c353b04975e9a9158b0295095936babf8c11b6b 100644 (file)
@@ -64,7 +64,7 @@ enum pim_secondary_addr_flags {
 };
 
 struct pim_secondary_addr {
-  struct in_addr addr;
+  struct prefix addr;
   enum pim_secondary_addr_flags flags;
 };
 
@@ -118,6 +118,16 @@ struct pim_interface {
   uint32_t       pim_ifstat_hello_sendfail;
   uint32_t       pim_ifstat_hello_recv;
   uint32_t       pim_ifstat_hello_recvfail;
+  uint32_t       pim_ifstat_join_recv;
+  uint32_t       pim_ifstat_join_send;
+  uint32_t       pim_ifstat_prune_recv;
+  uint32_t       pim_ifstat_prune_send;
+  uint32_t       pim_ifstat_reg_recv;
+  uint32_t       pim_ifstat_reg_send;
+  uint32_t       pim_ifstat_reg_stop_recv;
+  uint32_t       pim_ifstat_reg_stop_send;
+  uint32_t       pim_ifstat_assert_recv;
+  uint32_t       pim_ifstat_assert_send;
 };
 
 extern struct interface *pim_regiface;
index 828781a4670b511376491009154f30db7b00680d..ae7fedc62bef5257f5d84f8b3d9641bd93967ac2 100644 (file)
@@ -59,6 +59,8 @@ static void recv_join(struct interface *ifp,
                      struct prefix_sg *sg,
                      uint8_t source_flags)
 {
+  struct pim_interface *pim_ifp = NULL;
+
   if (PIM_DEBUG_PIM_TRACE) {
     char up_str[INET_ADDRSTRLEN];
     char neigh_str[INET_ADDRSTRLEN];
@@ -72,6 +74,11 @@ static void recv_join(struct interface *ifp,
              up_str, holdtime, neigh_str, ifp->name);
   }
 
+  pim_ifp = ifp->info;
+  zassert(pim_ifp);
+
+  ++pim_ifp->pim_ifstat_join_recv;
+
   /*
    * If the RPT and WC are set it's a (*,G)
    * and the source is the RP
@@ -104,6 +111,8 @@ static void recv_prune(struct interface *ifp,
                       struct prefix_sg *sg,
                       uint8_t source_flags)
 {
+  struct pim_interface *pim_ifp = NULL;
+
   if (PIM_DEBUG_PIM_TRACE) {
     char up_str[INET_ADDRSTRLEN];
     char neigh_str[INET_ADDRSTRLEN];
@@ -117,6 +126,11 @@ static void recv_prune(struct interface *ifp,
              up_str, holdtime, neigh_str, ifp->name);
   }
 
+  pim_ifp = ifp->info;
+  zassert(pim_ifp);
+
+  ++pim_ifp->pim_ifstat_prune_recv;
+
   if ((source_flags & PIM_RPT_BIT_MASK) &&
       (source_flags & PIM_WILDCARD_BIT_MASK))
     {
@@ -502,6 +516,9 @@ int pim_joinprune_send(struct pim_rpf *rpf,
       packet_size += group_size;
       pim_msg_build_jp_groups (grp, group, group_size);
 
+      pim_ifp->pim_ifstat_join_send += ntohs(grp->joins);
+      pim_ifp->pim_ifstat_prune_send += ntohs(grp->prunes);
+
       grp = (struct pim_jp_groups *)curr_ptr;
       if (packet_left < sizeof (struct pim_jp_groups) || msg->num_groups == 255)
         {
index de663aa3b52007d2e0c7823bda21e3a5ce908a6c..e5676289b73f458d5e74fc02015c654b180cfa4e 100644 (file)
   From:
   http://www.iana.org/assignments/address-family-numbers
 */
-#define PIM_MSG_ADDRESS_FAMILY_IPV4 (1)
+enum pim_msg_address_family {
+  PIM_MSG_ADDRESS_FAMILY_RESERVED,
+  PIM_MSG_ADDRESS_FAMILY_IPV4,
+  PIM_MSG_ADDRESS_FAMILY_IPV6,
+};
 
 /*
  * Network Order pim_msg_hdr
index 181a71210c676f2de6281cf9d29ff7983f1a5ff2..de0f75e38072f96057a32d5f68def74cc06eab99 100644 (file)
@@ -423,6 +423,31 @@ void pim_neighbor_free(struct pim_neighbor *neigh)
   XFREE(MTYPE_PIM_NEIGHBOR, neigh);
 }
 
+struct pim_neighbor *
+pim_neighbor_find_by_secondary (struct interface *ifp,
+                                struct prefix *src)
+{
+  struct pim_interface *pim_ifp;
+  struct listnode *node, *pnode;
+  struct pim_neighbor *neigh;
+  struct prefix *p;
+
+  pim_ifp = ifp->info;
+  if (!pim_ifp)
+    return NULL;
+
+  for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh))
+    {
+      for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, pnode, p))
+        {
+          if (prefix_same (p, src))
+            return neigh;
+        }
+    }
+
+  return NULL;
+}
+
 struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
                                       struct in_addr source_addr)
 {
@@ -686,7 +711,7 @@ void pim_neighbor_delete_all(struct interface *ifp,
 }
 
 struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
-                                          struct in_addr addr)
+                                          struct prefix *addr)
 {
   struct listnode *node;
   struct prefix   *p;
@@ -695,14 +720,11 @@ struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
     return 0;
 
   for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
-    if (p->family == AF_INET) {
-      if (addr.s_addr == p->u.prefix4.s_addr) {
-       return p;
-      }
-    }
+    if (prefix_same (p, addr))
+      return p;
   }
 
-  return 0;
+  return NULL;
 }
 
 /*
@@ -746,7 +768,7 @@ static void delete_from_neigh_addr(struct interface *ifp,
     for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
                              neigh)) {
       {
-       struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4);
+       struct prefix *p = pim_neighbor_find_secondary(neigh, addr);
        if (p) {
          char addr_str[INET_ADDRSTRLEN];
          char this_neigh_str[INET_ADDRSTRLEN];
index 986721666eaaa63fe5b2d9f58288257260bb755a..e27920fdd8bf979e3e1e39a0b2a0826d899e3142 100644 (file)
@@ -50,7 +50,8 @@ void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime);
 void pim_neighbor_free(struct pim_neighbor *neigh);
 struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
                                       struct in_addr source_addr);
-
+struct pim_neighbor *pim_neighbor_find_by_secondary (struct interface *ifp,
+                                                     struct prefix *src);
 struct pim_neighbor *pim_neighbor_find_if (struct interface *ifp);
 
 
@@ -77,7 +78,7 @@ void pim_neighbor_update(struct pim_neighbor *neigh,
                         uint32_t dr_priority,
                         struct list *addr_list);
 struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
-                                          struct in_addr addr);
+                                          struct prefix *addr);
 int pim_if_dr_election(struct interface *ifp);
 
 #endif /* PIM_NEIGHBOR_H */
index b2f858b7d96c87c758cfcf567d4c68e2623021ea..9886cd6ad29ab23fc59f986b0f59047efa0b217b 100644 (file)
@@ -627,7 +627,7 @@ static int hello_send(struct interface *ifp,
               listcount(ifp->connected));
   }
 
-  pim_tlv_size = pim_hello_build_tlv(ifp->name,
+  pim_tlv_size = pim_hello_build_tlv(ifp,
                                     pim_msg + PIM_PIM_MIN_LEN,
                                     sizeof(pim_msg) - PIM_PIM_MIN_LEN,
                                     holdtime,
@@ -635,8 +635,7 @@ static int hello_send(struct interface *ifp,
                                     pim_ifp->pim_generation_id,
                                     pim_ifp->pim_propagation_delay_msec,
                                     pim_ifp->pim_override_interval_msec,
-                                    PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options),
-                                    ifp->connected);
+                                    PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options));
   if (pim_tlv_size < 0) {
     return -1;
   }
index 8dc179c1444ccec91166b93a72e5ee3a35c5de33..f23993625d7e3faf3bd24dc007aeb1c1f568158a 100644 (file)
@@ -110,6 +110,7 @@ pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg,
                      __PRETTY_FUNCTION__, ifp->name);
        }
     }
+  ++pinfo->pim_ifstat_reg_stop_send;
 }
 
 int
@@ -205,6 +206,8 @@ pim_register_send (const uint8_t *buf, int buf_size, struct in_addr src, struct
 
   pim_msg_build_header(buffer, buf_size + PIM_MSG_REGISTER_LEN, PIM_MSG_TYPE_REGISTER);
 
+  ++pinfo->pim_ifstat_reg_send;
+
   if (pim_msg_send(pinfo->pim_sock_fd,
                   src,
                   rpg->rpf_addr.u.prefix4,
@@ -274,6 +277,7 @@ pim_register_recv (struct interface *ifp,
   struct prefix_sg sg;
   uint32_t *bits;
   int i_am_rp = 0;
+  struct pim_interface *pim_ifp = NULL;
 
 #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
   ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
@@ -289,6 +293,10 @@ pim_register_recv (struct interface *ifp,
     return 0;
   }
 
+  pim_ifp = ifp->info;
+  zassert(pim_ifp);
+  ++pim_ifp->pim_ifstat_reg_recv;
+
   /*
    * Please note this is not drawn to get the correct bit/data size
    *
index 6c4504d9b0be236b2a3ed2cbbf0da8eb4e6e35a0..cdc760e92df31dc7ab5174d8e27377308b9075fe 100644 (file)
@@ -250,7 +250,7 @@ pim_rp_check_interface_addrs(struct rp_info *rp_info,
   }
 
   for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
-    if (sec_addr->addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr) {
+    if (prefix_same(&sec_addr->addr, &rp_info->rp.rpf_addr)) {
       return 1;
     }
   }
index 5223f60e1b223aa6be5769ce42e1b22e7ca8d05d..259ed44c714de11767994c9d148b912822eca4b0 100644 (file)
@@ -94,6 +94,7 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf,
 }
 
 #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
+#define ucast_ipv6_encoding_len (2 + sizeof(struct in6_addr))
 
 /*
  * An Encoded-Unicast address takes the following format:
@@ -135,6 +136,14 @@ pim_encode_addr_ucast (uint8_t *buf, struct prefix *p)
       memcpy (buf, &p->u.prefix4, sizeof (struct in_addr));
       return ucast_ipv4_encoding_len;
       break;
+    case AF_INET6:
+      *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV6;
+      ++buf;
+      *(uint8_t *)buf = 0;
+      ++buf;
+      memcpy (buf, &p->u.prefix6, sizeof (struct in6_addr));
+      return ucast_ipv6_encoding_len;
+      break;
     default:
       return 0;
       break;
@@ -216,12 +225,13 @@ pim_encode_addr_group (uint8_t *buf, afi_t afi, int bidir, int scope, struct in_
 
 uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
                                       const uint8_t *buf_pastend,
-                                      struct list *ifconnected)
+                                      struct list *ifconnected,
+                                       int family)
 {
   struct listnode *node;
   uint16_t option_len = 0;
-
   uint8_t *curr;
+  size_t uel;
 
   node = listhead(ifconnected);
 
@@ -230,8 +240,10 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
     return buf;
   }
 
-  /* Skip first address (primary) */
-  node = listnextnode(node);
+  if (family == AF_INET)
+    uel = ucast_ipv4_encoding_len;
+  else
+    uel = ucast_ipv6_encoding_len;
 
   /* Scan secondary address list */
   curr = buf + 4; /* skip T and L */
@@ -240,8 +252,14 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
     struct prefix *p = ifc->address;
     int l_encode;
 
-    if ((curr + ucast_ipv4_encoding_len) > buf_pastend)
-      return 0;
+    if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
+      continue;
+
+    if ((curr + uel) > buf_pastend)
+          return 0;
+
+    if (p->family != family)
+      continue;
 
     l_encode = pim_encode_addr_ucast (curr, p);
     curr += l_encode;
@@ -251,7 +269,7 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
   if (PIM_DEBUG_PIM_TRACE_DETAIL) {
     zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
               __PRETTY_FUNCTION__,
-              option_len / ucast_ipv4_encoding_len);
+              option_len / uel);
   }
 
   if (option_len < 1) {
@@ -491,9 +509,23 @@ pim_parse_addr_ucast (struct prefix *p,
 
     p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
     memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
-
+    p->prefixlen = IPV4_MAX_PREFIXLEN;
     addr += sizeof(struct in_addr);
 
+    break;
+  case PIM_MSG_ADDRESS_FAMILY_IPV6:
+    if ((addr + sizeof(struct in6_addr)) > pastend) {
+      zlog_warn ("%s: IPv6 unicast address overflow: left=%zd needed %zu",
+                 __PRETTY_FUNCTION__,
+                 pastend - addr, sizeof(struct in6_addr));
+      return -3;
+    }
+
+    p->family = AF_INET6;
+    p->prefixlen = IPV6_MAX_PREFIXLEN;
+    memcpy(&p->u.prefix6, addr, sizeof(struct in6_addr));
+    addr += sizeof(struct in6_addr);
+
     break;
   default:
     {
@@ -706,6 +738,8 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
                     addr_str, src_str, ifname);
        }
        break;
+      case AF_INET6:
+        break;
       default:
        {
          char src_str[INET_ADDRSTRLEN];
@@ -759,8 +793,7 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
        FREE_ADDR_LIST(*hello_option_addr_list);
        return -3;
       }
-      p->family = tmp.family;
-      p->u.prefix4 = tmp.u.prefix4;
+      prefix_copy(p, &tmp);
       listnode_add(*hello_option_addr_list, p);
     }
 
index 9c4ebc9f0f86d5468e31d4cf5341096ce6bc43e2..7e0a8a147f9e9ea8f0ea293ab60af23b1f4a0e0e 100644 (file)
@@ -80,7 +80,8 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf,
                               uint32_t option_value);
 uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
                                       const uint8_t *buf_pastend,
-                                      struct list *ifconnected);
+                                      struct list *ifconnected,
+                                       int family);
 
 int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
                           pim_hello_options *hello_options,
index 754cf8468b415569b7cd079fd0a02ff147a4c343..2d502d9aa901b8c9317e856a8fb0316008897e2d 100644 (file)
@@ -150,6 +150,12 @@ int pim_global_config_write(struct vty *vty)
 
   writes += pim_msdp_config_write (vty);
 
+  if (!pimg->send_v6_secondary)
+    {
+      vty_out (vty, "no ip pim send-v6-secondary%s", VTY_NEWLINE);
+      ++writes;
+    }
+
   writes += pim_rp_config_write (vty);
 
   if (qpim_register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT)
index baf296623fd92cf24adde2cba2881f8729c67124..b2a7319bf1740bc856ecd99d307f7d7be3db2965 100644 (file)
@@ -257,31 +257,11 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
 #endif
   }
 
-  if (p->family != AF_INET)
-    {
-      struct listnode *cnode;
-      struct connected *conn;
-      int v4addrs = 0;
-
-      for (ALL_LIST_ELEMENTS_RO (c->ifp->connected, cnode, conn))
-        {
-          if (conn->address->family == AF_INET)
-           v4addrs++;
-        }
-      if (!v4addrs && pim_ifp) 
-       {
-         pim_ifp->primary_address = pim_find_primary_addr (c->ifp);
-         pim_if_addr_add_all (c->ifp);
-          pim_if_add_vif (c->ifp);
-       }
-      return 0;
-    }
-
   if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
     /* trying to add primary address */
 
     struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
-    if (primary_addr.s_addr != p->u.prefix4.s_addr) {
+    if (p->family != AF_INET || primary_addr.s_addr != p->u.prefix4.s_addr) {
       if (PIM_DEBUG_ZEBRA) {
        /* but we had a primary address already */
 
index f77990ab5ab81faa3b7e05ec34f850ce65e330aa..27bd1370438a5593ca67cb36d67f1cea2fd93749 100644 (file)
@@ -222,6 +222,7 @@ static int zclient_read_nexthop(struct zclient *zlookup,
   for (i = 0; i < nexthop_num; ++i) {
     enum nexthop_types_t nexthop_type;
     struct pim_neighbor *nbr;
+    struct prefix p;
 
     nexthop_type = stream_getc(s);
     if (num_ifindex >= tab_size) {
@@ -251,9 +252,24 @@ static int zclient_read_nexthop(struct zclient *zlookup,
       break;
     case NEXTHOP_TYPE_IPV6_IFINDEX:
       nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET6;
-      stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, s, 16);
+      stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6,
+                 s,
+                 sizeof(struct in6_addr));
       nexthop_tab[num_ifindex].ifindex = stream_getl (s);
-      nbr = pim_neighbor_find_if (if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT));
+
+      p.family = AF_INET6;
+      p.prefixlen = IPV6_MAX_PREFIXLEN;
+      memcpy (&p.u.prefix6,
+             &nexthop_tab[num_ifindex].nexthop_addr.u.prefix6,
+             sizeof(struct in6_addr));
+
+      /*
+       * If we are sending v6 secondary assume we receive v6 secondary
+       */
+      if (pimg->send_v6_secondary)
+        nbr = pim_neighbor_find_by_secondary(if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT), &p);
+      else
+        nbr = pim_neighbor_find_if (if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT));
       if (nbr)
         {
           nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
index 749f1e2b0d9fd5f0c2e80225faaa75917ef74830..fc6663776b9e861620e6b5f3d51ab23f1b4fc35c 100644 (file)
@@ -117,7 +117,10 @@ pim_vrf_enable (struct vrf *vrf)
            * We will crash and burn otherwise
            */
           exit(1);
-        }
+      }
+
+    pimg->send_v6_secondary = 1;
+
     }
   return 0;
 }
index 693cce7e9f2c05644ffc9a78827bc6eed6d7cf25..e10155c209b3c35451de3e22ff2ac688c90712c8 100644 (file)
@@ -257,7 +257,10 @@ struct pim_instance
   } spt;
 
   struct hash *rpf_hash;
+
   void *ssm_info; /* per-vrf SSM configuration */
+  
+  int send_v6_secondary;
 };
 
 extern struct pim_instance *pimg; //Pim Global Instance
diff --git a/pkgsrc/eigrpd.sh.in b/pkgsrc/eigrpd.sh.in
new file mode 100644 (file)
index 0000000..b28b81e
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+#
+# eigrpd is part of the quagga routing beast
+#
+# PROVIDE: eigrpd
+# REQUIRE: zebra
+##
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin
+export PATH
+
+if [ -f /etc/rc.subr ]
+then
+       . /etc/rc.subr
+fi
+
+name="eigrpd"
+rcvar=$name
+required_files="@sysconfdir@/${name}.conf"
+command="@prefix@/sbin/${name}"
+command_args="-d"
+
+start_precmd="zebra_precmd"
+socket_dir=@localstatedir@
+pidfile="${socket_dir}/${name}.pid"
+
+zebra_precmd()
+{
+    rc_flags="$(
+       set -- $rc_flags
+       while [ $# -ne 0 ]; do
+           if [ X"$1" = X-P -o X"$1" = X-A ]; then
+               break
+           fi
+           shift
+       done
+       if [ $# -eq 0 ]; then
+           echo "-P 0"
+       fi
+       ) $rc_flags"
+}
+
+load_rc_config $name
+run_rc_command "$1"
index c32e3e3af8138d41e87b58c9f038376c849249d7..aef7a7cd2a5cca067151445fd38e204968d62573 100644 (file)
@@ -34,7 +34,7 @@
 %define                zeb_rh_src      %{zeb_src}/redhat
 %define                zeb_docs        %{zeb_src}/doc
 %define         frr_tools    %{zeb_src}/tools
-%define         cumulus_dir     %{zeb_src}/cumulus/etc
+%define         frr_tools_etc   %{frr_tools}/etc
 
 # defines for configure
 %define                _localstatedir  /var/run/frr
@@ -291,9 +291,9 @@ for daemon in %{all_daemons} ; do
 done
 %endif
 
-install %{cumulus_dir}/frr/debian.conf %{buildroot}/etc/frr
-install %{cumulus_dir}/frr/daemons %{buildroot}/etc/frr
-install -m644 %{cumulus_dir}/default/frr %{buildroot}/etc/default
+install %{frr_tools_dir}/frr/daemons.conf %{buildroot}/etc/frr
+install %{frr_tools_dir}/frr/daemons %{buildroot}/etc/frr
+install -m644 %{frr_tools_dir}/default/frr %{buildroot}/etc/default
 install -m644 %{zeb_rh_src}/frr.pam \
        %{buildroot}/etc/pam.d/frr
 install -m644 %{zeb_rh_src}/frr.logrotate \
index a7ef1c56b7d2d8c30ba70d62877fd755eae1bad6..da9e447fc0a78929d6672f5cce701ddf2172bd16 100644 (file)
@@ -87,7 +87,8 @@ class _TestMultiOut(object):
     def _add_test(cls, method, *args, **kwargs):
         if 'tests' not in dir(cls):
             setattr(cls,'tests',[])
-            cls._add_test(cls._exit_cleanly)
+            if method is not cls._exit_cleanly:
+                cls._add_test(cls._exit_cleanly)
 
         def matchfunction(self):
             method(self, *args, **kwargs)
index b2d56170c14466df1a530718dc15a33f85b49521..de81919cdd2f87e2b2257a0d9514779130513fba 100644 (file)
@@ -4,6 +4,8 @@ AM_CFLAGS = $(WERROR)
 EXTRA_DIST =
 
 bin_PROGRAMS = permutations
+sbin_PROGRAMS = ssd
+
 permutations_SOURCES = permutations.c
 permutations_LDADD = ../lib/libfrr.la
 
@@ -12,3 +14,5 @@ sbin_SCRIPTS = frr-reload.py frr
 EXTRA_DIST += frr.service frr-reload.py frr
 
 EXTRA_DIST += xml2cli.pl
+
+ssd_SOURCES = start-stop-daemon.c
diff --git a/tools/etc/default/frr b/tools/etc/default/frr
new file mode 100644 (file)
index 0000000..693fa63
--- /dev/null
@@ -0,0 +1,10 @@
+MAX_INSTANCES=5
+MAX_FDS=1024
+ZEBRA_OPTIONS="-s 16777216 -A 127.0.0.1"
+BGPD_OPTIONS="-A 127.0.0.1"
+OSPFD_OPTIONS="-A 127.0.0.1"
+OSPF6D_OPTIONS="-A ::1"
+RIPD_OPTIONS="-A 127.0.0.1"
+RIPNGD_OPTIONS="-A ::1"
+ISISD_OPTIONS="-A 127.0.0.1"
+EIGRP_OPTIONS="-A 127.0.0.1"
diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons
new file mode 100644 (file)
index 0000000..eb7a5c9
--- /dev/null
@@ -0,0 +1,34 @@
+# This file tells the frr package which daemons to start.
+#
+# Entries are in the format: <daemon>=(yes|no|priority)
+#   0, "no"  = disabled
+#   1, "yes" = highest priority
+#   2 .. 10  = lower priorities
+# Read /usr/share/doc/frr/README.Debian for details.
+#
+# Sample configurations for these daemons can be found in
+# /usr/share/doc/frr/examples/.
+#
+# ATTENTION:
+#
+# When activation a daemon at the first time, a config file, even if it is
+# empty, has to be present *and* be owned by the user and group "frr", else
+# the daemon will not be started by /etc/init.d/frr. The permissions should
+# be u=rw,g=r,o=.
+# When using "vtysh" such a config file is also needed. It should be owned by
+# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
+#
+# The watchfrr daemon is always started. Per default in monitoring-only but
+# that can be changed via /etc/frr/daemons.conf.
+#
+zebra=no
+bgpd=no
+ospfd=no
+ospf6d=no
+ripd=no
+ripngd=no
+isisd=no
+pimd=no
+ldpd=no
+nhrpd=no
+eigrpd=no
diff --git a/tools/etc/frr/daemons.conf b/tools/etc/frr/daemons.conf
new file mode 100644 (file)
index 0000000..21ae29d
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# If this option is set the /etc/init.d/frr script automatically loads
+# the config via "vtysh -b" when the servers are started.
+# Check /etc/pam.d/frr if you intend to use "vtysh"!
+#
+vtysh_enable=yes
+zebra_options="  -s 90000000 --daemon -A 127.0.0.1"
+bgpd_options="   --daemon -A 127.0.0.1"
+ospfd_options="  --daemon -A 127.0.0.1"
+ospf6d_options=" --daemon -A ::1"
+ripd_options="   --daemon -A 127.0.0.1"
+ripngd_options=" --daemon -A ::1"
+isisd_options="  --daemon -A 127.0.0.1"
+pimd_options="  --daemon -A 127.0.0.1"
+ldpd_options="  --daemon -A 127.0.0.1"
+nhrpd_options="  --daemon -A 127.0.0.1"
+eigrpd_options="  --daemon -A 127.0.0.1"
+
+# The list of daemons to watch is automatically generated by the init script.
+watchfrr_enable=yes
+watchfrr_options=(-adz -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB -t 30)
+
+# If valgrind_enable is 'yes' the frr daemons will be started via valgrind.
+# The use case for doing so is tracking down memory leaks, etc in frr.
+valgrind_enable=no
+valgrind=/usr/bin/valgrind
diff --git a/tools/etc/frr/frr.conf b/tools/etc/frr/frr.conf
new file mode 100644 (file)
index 0000000..2cd05bf
--- /dev/null
@@ -0,0 +1,2 @@
+log file /var/log/frr/frr.log
+log timestamp precision 6
diff --git a/tools/etc/frr/vtysh.conf b/tools/etc/frr/vtysh.conf
new file mode 100644 (file)
index 0000000..80ceb00
--- /dev/null
@@ -0,0 +1,2 @@
+service integrated-vtysh-config
+username cumulus nopassword
diff --git a/tools/etc/iproute2/rt_protos.d/frr.conf b/tools/etc/iproute2/rt_protos.d/frr.conf
new file mode 100644 (file)
index 0000000..3f55b11
--- /dev/null
@@ -0,0 +1,8 @@
+# Additional protocol strings defined by frr for each of its daemons
+
+186  bgp
+187  isis
+188  ospf
+189  rip
+190  ripng
+191  static
index 80dd9e8747fbb32a4a12663c36a54776d855b85b..6f00700e4073d8cdf749287d4941a13d13fbf539 100755 (executable)
--- a/tools/frr
+++ b/tools/frr
@@ -21,7 +21,7 @@ V_PATH=/var/run/frr
 # Local Daemon selection may be done by using /etc/frr/daemons.
 # See /usr/share/doc/frr/README.Debian.gz for further information.
 # Keep zebra first and do not list watchfrr!
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd"
+DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd"
 MAX_INSTANCES=5
 RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py
 
@@ -150,12 +150,21 @@ start()
                return;
            fi
 
-           ${SSD} \
+           if [ $valgrind_enable = "yes" ]; then
+              ${SSD} \
+               --start \
+               --pidfile=`pidfile $1` \
+               --exec $valgrind \
+               -- --trace-children=no --leak-check=full --log-file=/var/log/frr/$1-valgrind.log $D_PATH/$1 \
+               `eval echo "$""$1""_options"`
+           else
+              ${SSD} \
                --start \
                --pidfile=`pidfile $1` \
                --exec "$D_PATH/$1" \
                -- \
                `eval echo "$""$1""_options"`
+           fi
         fi
 }
 
@@ -476,7 +485,7 @@ check_status()
 
 # Load configuration
 . "$C_PATH/daemons"
-. "$C_PATH/debian.conf"
+. "$C_PATH/daemons.conf"
 
 # Read configuration variable file if it is present
 [ -r /etc/default/frr ] && . /etc/default/frr
@@ -532,8 +541,15 @@ case "$1" in
         fi
 
         if [ -z "$dmn" -o "$dmn" = "zebra" ]; then
-          echo "Removing all routes made by zebra."
+          echo "Removing all routes made by FRR."
+          ip route flush proto bgp
+          ip route flush proto ospf
+          ip route flush proto static
+          ip route flush proto rip
+          ip route flush proto ripng
           ip route flush proto zebra
+          ip route flush proto isis
+
        else
          [ -n "$dmn" ] && eval "${dmn/-/_}=0"
          start_watchfrr
diff --git a/tools/start-stop-daemon.c b/tools/start-stop-daemon.c
new file mode 100644 (file)
index 0000000..f1a252a
--- /dev/null
@@ -0,0 +1,1064 @@
+/*
+ * A rewrite of the original Debian's start-stop-daemon Perl script
+ * in C (faster - it is executed many times during system startup).
+ *
+ * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
+ * public domain.  Based conceptually on start-stop-daemon.pl, by Ian
+ * Jackson <ijackson@gnu.ai.mit.edu>.  May be used and distributed
+ * freely for any purpose.  Changes by Christian Schwarz
+ * <schwarz@monet.m.isar.de>, to make output conform to the Debian
+ * Console Message Standard, also placed in public domain.  Minor
+ * changes by Klee Dienes <klee@debian.org>, also placed in the Public
+ * Domain.
+ *
+ * Changes by Ben Collins <bcollins@debian.org>, added --chuid, --background
+ * and --make-pidfile options, placed in public domain aswell.
+ *
+ * Port to OpenBSD by Sontri Tomo Huynh <huynh.29@osu.edu>
+ *                 and Andreas Schuldei <andreas@schuldei.org>
+ *
+ * Changes by Ian Jackson: added --retry (and associated rearrangements).
+ *
+ * Modified for Gentoo rc-scripts by Donny Davies <woodchip@gentoo.org>:
+ *   I removed the BSD/Hurd/OtherOS stuff, added #include <stddef.h>
+ *   and stuck in a #define VERSION "1.9.18".  Now it compiles without
+ *   the whole automake/config.h dance.
+ */
+
+#ifdef HAVE_LXC
+#define _GNU_SOURCE
+#include <sched.h>
+#endif /* HAVE_LXC */
+
+#include <stddef.h>
+#define VERSION "1.9.18"
+
+#define MIN_POLL_INTERVAL 20000 /*us*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <assert.h>
+#include <ctype.h>
+#ifdef linux
+#include <linux/sched.h>
+#endif
+
+static int testmode = 0;
+static int quietmode = 0;
+static int exitnodo = 1;
+static int start = 0;
+static int stop = 0;
+static int background = 0;
+static int mpidfile = 0;
+static int signal_nr = 15;
+static const char *signal_str = NULL;
+static int user_id = -1;
+static int runas_uid = -1;
+static int runas_gid = -1;
+static const char *userspec = NULL;
+static char *changeuser = NULL;
+static const char *changegroup = NULL;
+static char *changeroot = NULL;
+static const char *cmdname = NULL;
+static char *execname = NULL;
+static char *startas = NULL;
+static const char *pidfile = NULL;
+static char what_stop[1024];
+static const char *schedule_str = NULL;
+static const char *progname = "";
+static int nicelevel = 0;
+
+static struct stat exec_stat;
+
+struct pid_list {
+       struct pid_list *next;
+       pid_t pid;
+};
+
+static struct pid_list *found = NULL;
+static struct pid_list *killed = NULL;
+
+struct schedule_item {
+       enum { sched_timeout, sched_signal, sched_goto, sched_forever } type;
+       int value; /* seconds, signal no., or index into array */
+       /* sched_forever is only seen within parse_schedule and callees */
+};
+
+static int schedule_length;
+static struct schedule_item *schedule = NULL;
+
+LIST_HEAD(namespace_head, namespace);
+
+struct namespace {
+       LIST_ENTRY(namespace) list;
+       const char *path;
+       int nstype;
+};
+
+static struct namespace_head namespace_head;
+
+static void *xmalloc(int size);
+static void push(struct pid_list **list, pid_t pid);
+static void do_help(void);
+static void parse_options(int argc, char * const *argv);
+static int pid_is_user(pid_t pid, uid_t uid);
+static int pid_is_cmd(pid_t pid, const char *name);
+static void check(pid_t pid);
+static void do_pidfile(const char *name);
+static void do_stop(int signal_nr, int quietmode,
+                   int *n_killed, int *n_notkilled, int retry_nr);
+static int pid_is_exec(pid_t pid, const struct stat *esb);
+
+#ifdef __GNUC__
+static void fatal(const char *format, ...)
+       __attribute__((noreturn, format(printf, 1, 2)));
+static void badusage(const char *msg)
+       __attribute__((noreturn));
+#else
+static void fatal(const char *format, ...);
+static void badusage(const char *msg);
+#endif
+
+/* This next part serves only to construct the TVCALC macro, which
+ * is used for doing arithmetic on struct timeval's.  It works like this:
+ *   TVCALC(result, expression);
+ * where result is a struct timeval (and must be an lvalue) and
+ * expression is the single expression for both components.  In this
+ * expression you can use the special values TVELEM, which when fed a
+ * const struct timeval* gives you the relevant component, and
+ * TVADJUST.  TVADJUST is necessary when subtracting timevals, to make
+ * it easier to renormalise.  Whenver you subtract timeval elements,
+ * you must make sure that TVADJUST is added to the result of the
+ * subtraction (before any resulting multiplication or what have you).
+ * TVELEM must be linear in TVADJUST.
+ */
+typedef long tvselector(const struct timeval*);
+static long tvselector_sec(const struct timeval *tv) { return tv->tv_sec; }
+static long tvselector_usec(const struct timeval *tv) { return tv->tv_usec; }
+#define TVCALC_ELEM(result, expr, sec, adj)                           \
+{                                                                    \
+  const long TVADJUST = adj;                                         \
+  long (*const TVELEM)(const struct timeval*) = tvselector_##sec;     \
+  (result).tv_##sec = (expr);                                        \
+}
+#define TVCALC(result,expr)                                          \
+do {                                                                 \
+  TVCALC_ELEM(result, expr, sec, (-1));                                      \
+  TVCALC_ELEM(result, expr, usec, (+1000000));                       \
+  (result).tv_sec += (result).tv_usec / 1000000;                     \
+  (result).tv_usec %= 1000000;                                       \
+} while(0)
+
+
+static void
+fatal(const char *format, ...)
+{
+       va_list arglist;
+
+       fprintf(stderr, "%s: ", progname);
+       va_start(arglist, format);
+       vfprintf(stderr, format, arglist);
+       va_end(arglist);
+       putc('\n', stderr);
+       exit(2);
+}
+
+
+static void *
+xmalloc(int size)
+{
+       void *ptr;
+
+       ptr = malloc(size);
+       if (ptr)
+               return ptr;
+       fatal("malloc(%d) failed", size);
+}
+
+static void
+xgettimeofday(struct timeval *tv)
+{
+       if (gettimeofday(tv,0) != 0)
+               fatal("gettimeofday failed: %s", strerror(errno));
+}
+
+static void
+push(struct pid_list **list, pid_t pid)
+{
+       struct pid_list *p;
+
+       p = xmalloc(sizeof(*p));
+       p->next = *list;
+       p->pid = pid;
+       *list = p;
+}
+
+static void
+clear(struct pid_list **list)
+{
+       struct pid_list *here, *next;
+
+       for (here = *list; here != NULL; here = next) {
+               next = here->next;
+               free(here);
+       }
+
+       *list = NULL;
+}
+
+#ifdef linux
+static const char *
+next_dirname(const char *s)
+{
+       const char *cur;
+
+       cur = (const char *)s;
+
+       if (*cur != '\0') {
+               for (; *cur != '/'; ++cur)
+                       if (*cur == '\0')
+                               return cur;
+
+               for (; *cur == '/'; ++cur)
+                       ;
+       }
+
+       return cur;
+}
+
+static void
+add_namespace(const char *path)
+{
+       int nstype;
+       const char *nsdirname, *nsname, *cur;
+       struct namespace *namespace;
+
+       cur = (const char *)path;
+       nsdirname = nsname = "";
+
+       while ((cur = next_dirname(cur))[0] != '\0') {
+               nsdirname = nsname;
+               nsname = cur;
+       }
+
+       if      (!memcmp(nsdirname, "ipcns/", strlen("ipcns/")))
+               nstype = CLONE_NEWIPC;
+       else if (!memcmp(nsdirname, "netns/", strlen("netns/")))
+               nstype = CLONE_NEWNET;
+       else if (!memcmp(nsdirname, "utcns/", strlen("utcns/")))
+               nstype = CLONE_NEWUTS;
+       else
+               badusage("invalid namepspace path");
+
+       namespace = xmalloc(sizeof(*namespace));
+       namespace->path = (const char *)path;
+       namespace->nstype = nstype;
+       LIST_INSERT_HEAD(&namespace_head, namespace, list);
+}
+#endif
+
+#ifdef HAVE_LXC
+static void
+set_namespaces()
+{
+       struct namespace *namespace;
+       int fd;
+
+       LIST_FOREACH(namespace, &namespace_head, list) {
+               if ((fd = open(namespace->path, O_RDONLY)) == -1)
+                       fatal("open namespace %s: %s", namespace->path, strerror(errno));
+               if (setns(fd, namespace->nstype) == -1)
+                       fatal("setns %s: %s", namespace->path, strerror(errno));
+       }
+}
+#else
+static void
+set_namespaces()
+{
+       if (!LIST_EMPTY(&namespace_head))
+               fatal("LCX namespaces not supported");
+}
+#endif
+
+static void
+do_help(void)
+{
+       printf(
+"start-stop-daemon " VERSION " for Debian - small and fast C version written by\n"
+"Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
+"\n"
+"Usage:\n"
+"  start-stop-daemon -S|--start options ... -- arguments ...\n"
+"  start-stop-daemon -K|--stop options ...\n"
+"  start-stop-daemon -H|--help\n"
+"  start-stop-daemon -V|--version\n"
+"\n"
+"Options (at least one of --exec|--pidfile|--user is required):\n"
+"  -x|--exec <executable>        program to start/check if it is running\n"
+"  -p|--pidfile <pid-file>       pid file to check\n"
+"  -c|--chuid <name|uid[:group|gid]>\n"
+"              change to this user/group before starting process\n"
+"  -u|--user <username>|<uid>    stop processes owned by this user\n"
+"  -n|--name <process-name>      stop processes with this name\n"
+"  -s|--signal <signal>          signal to send (default TERM)\n"
+"  -a|--startas <pathname>       program to start (default is <executable>)\n"
+"  -N|--nicelevel <incr>         add incr to the process's nice level\n"
+"  -b|--background               force the process to detach\n"
+"  -m|--make-pidfile             create the pidfile before starting\n"
+"  -R|--retry <schedule>         check whether processes die, and retry\n"
+"  -t|--test                     test mode, don't do anything\n"
+"  -o|--oknodo                   exit status 0 (not 1) if nothing done\n"
+"  -q|--quiet                    be more quiet\n"
+"  -v|--verbose                  be more verbose\n"
+"Retry <schedule> is <item>|/<item>/... where <item> is one of\n"
+" -<signal-num>|[-]<signal-name>  send that signal\n"
+" <timeout>                       wait that many seconds\n"
+" forever                         repeat remainder forever\n"
+"or <schedule> may be just <timeout>, meaning <signal>/<timeout>/KILL/<timeout>\n"
+"\n"
+"Exit status:  0 = done      1 = nothing done (=> 0 if --oknodo)\n"
+"              3 = trouble   2 = with --retry, processes wouldn't die\n");
+}
+
+
+static void
+badusage(const char *msg)
+{
+       if (msg)
+               fprintf(stderr, "%s: %s\n", progname, msg);
+       fprintf(stderr, "Try `%s --help' for more information.\n", progname);
+       exit(3);
+}
+
+struct sigpair {
+       const char *name;
+       int signal;
+};
+
+const struct sigpair siglist[] = {
+       { "ABRT",       SIGABRT },
+       { "ALRM",       SIGALRM },
+       { "FPE",        SIGFPE  },
+       { "HUP",        SIGHUP  },
+       { "ILL",        SIGILL  },
+       { "INT",        SIGINT  },
+       { "KILL",       SIGKILL },
+       { "PIPE",       SIGPIPE },
+       { "QUIT",       SIGQUIT },
+       { "SEGV",       SIGSEGV },
+       { "TERM",       SIGTERM },
+       { "USR1",       SIGUSR1 },
+       { "USR2",       SIGUSR2 },
+       { "CHLD",       SIGCHLD },
+       { "CONT",       SIGCONT },
+       { "STOP",       SIGSTOP },
+       { "TSTP",       SIGTSTP },
+       { "TTIN",       SIGTTIN },
+       { "TTOU",       SIGTTOU }
+};
+
+static int parse_integer (const char *string, int *value_r) {
+       unsigned long ul;
+       char *ep;
+
+       if (!string[0])
+               return -1;
+
+       ul= strtoul(string,&ep,10);
+       if (ul > INT_MAX || *ep != '\0')
+               return -1;
+
+       *value_r= ul;
+       return 0;
+}
+
+static int parse_signal (const char *signal_str, int *signal_nr)
+{
+       unsigned int i;
+
+       if (parse_integer(signal_str, signal_nr) == 0)
+               return 0;
+
+       for (i = 0; i < sizeof (siglist) / sizeof (siglist[0]); i++) {
+               if (strcmp (signal_str, siglist[i].name) == 0) {
+                       *signal_nr = siglist[i].signal;
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+static void
+parse_schedule_item(const char *string, struct schedule_item *item) {
+       const char *after_hyph;
+
+       if (!strcmp(string,"forever")) {
+               item->type = sched_forever;
+       } else if (isdigit(string[0])) {
+               item->type = sched_timeout;
+               if (parse_integer(string, &item->value) != 0)
+                       badusage("invalid timeout value in schedule");
+       } else if ((after_hyph = string + (string[0] == '-')) &&
+                  parse_signal(after_hyph, &item->value) == 0) {
+               item->type = sched_signal;
+       } else {
+               badusage("invalid schedule item (must be [-]<signal-name>, "
+                        "-<signal-number>, <timeout> or `forever'");
+       }
+}
+
+static void
+parse_schedule(const char *schedule_str) {
+       char item_buf[20];
+       const char *slash;
+       int count, repeatat;
+       ptrdiff_t str_len;
+
+       count = 0;
+       for (slash = schedule_str; *slash; slash++)
+               if (*slash == '/')
+                       count++;
+
+       schedule_length = (count == 0) ? 4 : count+1;
+       schedule = xmalloc(sizeof(*schedule) * schedule_length);
+
+       if (count == 0) {
+               schedule[0].type = sched_signal;
+               schedule[0].value = signal_nr;
+               parse_schedule_item(schedule_str, &schedule[1]);
+               if (schedule[1].type != sched_timeout) {
+                       badusage ("--retry takes timeout, or schedule list"
+                                 " of at least two items");
+               }
+               schedule[2].type = sched_signal;
+               schedule[2].value = SIGKILL;
+               schedule[3]= schedule[1];
+       } else {
+               count = 0;
+               repeatat = -1;
+               while (schedule_str != NULL) {
+                       slash = strchr(schedule_str,'/');
+                       str_len = slash ? slash - schedule_str : (ptrdiff_t)strlen(schedule_str);
+                       if (str_len >= (ptrdiff_t)sizeof(item_buf))
+                               badusage("invalid schedule item: far too long"
+                                        " (you must delimit items with slashes)");
+                       memcpy(item_buf, schedule_str, str_len);
+                       item_buf[str_len] = 0;
+                       schedule_str = slash ? slash+1 : NULL;
+
+                       parse_schedule_item(item_buf, &schedule[count]);
+                       if (schedule[count].type == sched_forever) {
+                               if (repeatat >= 0)
+                                       badusage("invalid schedule: `forever'"
+                                                " appears more than once");
+                               repeatat = count;
+                               continue;
+                       }
+                       count++;
+               }
+               if (repeatat >= 0) {
+                       schedule[count].type = sched_goto;
+                       schedule[count].value = repeatat;
+                       count++;
+               }
+               assert(count == schedule_length);
+       }
+}
+
+static void
+parse_options(int argc, char * const *argv)
+{
+       static struct option longopts[] = {
+               { "help",         0, NULL, 'H'},
+               { "stop",         0, NULL, 'K'},
+               { "start",        0, NULL, 'S'},
+               { "version",      0, NULL, 'V'},
+               { "startas",      1, NULL, 'a'},
+               { "name",         1, NULL, 'n'},
+               { "oknodo",       0, NULL, 'o'},
+               { "pidfile",      1, NULL, 'p'},
+               { "quiet",        0, NULL, 'q'},
+               { "signal",       1, NULL, 's'},
+               { "test",         0, NULL, 't'},
+               { "user",         1, NULL, 'u'},
+               { "chroot",       1, NULL, 'r'},
+               { "namespace",    1, NULL, 'd'},
+               { "verbose",      0, NULL, 'v'},
+               { "exec",         1, NULL, 'x'},
+               { "chuid",        1, NULL, 'c'},
+               { "nicelevel",    1, NULL, 'N'},
+               { "background",   0, NULL, 'b'},
+               { "make-pidfile", 0, NULL, 'm'},
+               { "retry",        1, NULL, 'R'},
+               { NULL,         0, NULL, 0}
+       };
+       int c;
+
+       for (;;) {
+               c = getopt_long(argc, argv, "HKSVa:n:op:qr:d:s:tu:vx:c:N:bmR:",
+                               longopts, (int *) 0);
+               if (c == -1)
+                       break;
+               switch (c) {
+               case 'H':  /* --help */
+                       do_help();
+                       exit(0);
+               case 'K':  /* --stop */
+                       stop = 1;
+                       break;
+               case 'S':  /* --start */
+                       start = 1;
+                       break;
+               case 'V':  /* --version */
+                       printf("start-stop-daemon " VERSION "\n");
+                       exit(0);
+               case 'a':  /* --startas <pathname> */
+                       startas = optarg;
+                       break;
+               case 'n':  /* --name <process-name> */
+                       cmdname = optarg;
+                       break;
+               case 'o':  /* --oknodo */
+                       exitnodo = 0;
+                       break;
+               case 'p':  /* --pidfile <pid-file> */
+                       pidfile = optarg;
+                       break;
+               case 'q':  /* --quiet */
+                       quietmode = 1;
+                       break;
+               case 's':  /* --signal <signal> */
+                       signal_str = optarg;
+                       break;
+               case 't':  /* --test */
+                       testmode = 1;
+                       break;
+               case 'u':  /* --user <username>|<uid> */
+                       userspec = optarg;
+                       break;
+               case 'v':  /* --verbose */
+                       quietmode = -1;
+                       break;
+               case 'x':  /* --exec <executable> */
+                       execname = optarg;
+                       break;
+               case 'c':  /* --chuid <username>|<uid> */
+                       /* we copy the string just in case we need the
+                        * argument later. */
+                       changeuser = strdup(optarg);
+                       changeuser = strtok(changeuser, ":");
+                       changegroup = strtok(NULL, ":");
+                       break;
+               case 'r':  /* --chroot /new/root */
+                       changeroot = optarg;
+                       break;
+               case 'd': /* --namespace /.../<ipcns>|<netns>|<utsns>/name */
+#ifdef linux
+                       add_namespace(optarg);
+#endif
+                       break;
+               case 'N':  /* --nice */
+                       nicelevel = atoi(optarg);
+                       break;
+               case 'b':  /* --background */
+                       background = 1;
+                       break;
+               case 'm':  /* --make-pidfile */
+                       mpidfile = 1;
+                       break;
+               case 'R':  /* --retry <schedule>|<timeout> */
+                       schedule_str = optarg;
+                       break;
+               default:
+                       badusage(NULL);  /* message printed by getopt */
+               }
+       }
+
+       if (signal_str != NULL) {
+               if (parse_signal (signal_str, &signal_nr) != 0)
+                       badusage("signal value must be numeric or name"
+                                " of signal (KILL, INTR, ...)");
+       }
+
+       if (schedule_str != NULL) {
+               parse_schedule(schedule_str);
+       }
+
+       if (start == stop)
+               badusage("need one of --start or --stop");
+
+       if (!execname && !pidfile && !userspec && !cmdname)
+               badusage("need at least one of --exec, --pidfile, --user or --name");
+
+       if (!startas)
+               startas = execname;
+
+       if (start && !startas)
+               badusage("--start needs --exec or --startas");
+
+       if (mpidfile && pidfile == NULL)
+               badusage("--make-pidfile is only relevant with --pidfile");
+
+       if (background && !start)
+               badusage("--background is only relevant with --start");
+
+}
+
+static int
+pid_is_exec(pid_t pid, const struct stat *esb)
+{
+       struct stat sb;
+       char buf[32];
+
+       sprintf(buf, "/proc/%d/exe", pid);
+       if (stat(buf, &sb) != 0)
+               return 0;
+       return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
+}
+
+
+static int
+pid_is_user(pid_t pid, uid_t uid)
+{
+       struct stat sb;
+       char buf[32];
+
+       sprintf(buf, "/proc/%d", pid);
+       if (stat(buf, &sb) != 0)
+               return 0;
+       return (sb.st_uid == uid);
+}
+
+
+static int
+pid_is_cmd(pid_t pid, const char *name)
+{
+       char buf[32];
+       FILE *f;
+       int c;
+
+       sprintf(buf, "/proc/%d/stat", pid);
+       f = fopen(buf, "r");
+       if (!f)
+               return 0;
+       while ((c = getc(f)) != EOF && c != '(')
+               ;
+       if (c != '(') {
+               fclose(f);
+               return 0;
+       }
+       /* this hopefully handles command names containing ')' */
+       while ((c = getc(f)) != EOF && c == *name)
+               name++;
+       fclose(f);
+       return (c == ')' && *name == '\0');
+}
+
+
+static void
+check(pid_t pid)
+{
+       if (execname && !pid_is_exec(pid, &exec_stat))
+               return;
+       if (userspec && !pid_is_user(pid, user_id))
+               return;
+       if (cmdname && !pid_is_cmd(pid, cmdname))
+               return;
+       push(&found, pid);
+}
+
+static void
+do_pidfile(const char *name)
+{
+       FILE *f;
+       pid_t pid;
+
+       f = fopen(name, "r");
+       if (f) {
+               if (fscanf(f, "%d", &pid) == 1)
+                       check(pid);
+               fclose(f);
+       } else if (errno != ENOENT)
+               fatal("open pidfile %s: %s", name, strerror(errno));
+
+}
+
+/* WTA: this  needs to be an autoconf check for /proc/pid existance.
+ */
+static void
+do_procinit(void)
+{
+       DIR *procdir;
+       struct dirent *entry;
+       int foundany;
+       pid_t pid;
+
+       procdir = opendir("/proc");
+       if (!procdir)
+               fatal("opendir /proc: %s", strerror(errno));
+
+       foundany = 0;
+       while ((entry = readdir(procdir)) != NULL) {
+               if (sscanf(entry->d_name, "%d", &pid) != 1)
+                       continue;
+               foundany++;
+               check(pid);
+       }
+       closedir(procdir);
+       if (!foundany)
+               fatal("nothing in /proc - not mounted?");
+}
+
+static void
+do_findprocs(void)
+{
+       clear(&found);
+       
+       if (pidfile)
+               do_pidfile(pidfile);
+       else
+               do_procinit();
+}
+
+/* return 1 on failure */
+static void
+do_stop(int signal_nr, int quietmode, int *n_killed, int *n_notkilled, int retry_nr)
+{
+       struct pid_list *p;
+
+       do_findprocs();
+       *n_killed = 0;
+       *n_notkilled = 0;
+       if (!found)
+               return;
+       clear(&killed);
+
+       for (p = found; p; p = p->next) {
+               if (testmode)
+                       printf("Would send signal %d to %d.\n",
+                              signal_nr, p->pid);
+               else if (kill(p->pid, signal_nr) == 0) {
+                       push(&killed, p->pid);
+                       (*n_killed)++;
+               } else {
+                       printf("%s: warning: failed to kill %d: %s\n",
+                              progname, p->pid, strerror(errno));
+                       (*n_notkilled)++;
+               }
+       }
+       if (quietmode < 0 && killed) {
+               printf("Stopped %s (pid", what_stop);
+               for (p = killed; p; p = p->next)
+                       printf(" %d", p->pid);
+               putchar(')');
+               if (retry_nr > 0)
+                       printf(", retry #%d", retry_nr);
+               printf(".\n");
+       }
+}
+
+
+static void
+set_what_stop(const char *str)
+{
+       strncpy(what_stop, str, sizeof(what_stop));
+       what_stop[sizeof(what_stop)-1] = '\0';
+}
+
+static int
+run_stop_schedule(void)
+{
+       int r, position, n_killed, n_notkilled, value, ratio, anykilled, retry_nr;
+       struct timeval stopat, before, after, interval, maxinterval;
+
+       if (testmode) {
+               if (schedule != NULL) {
+                       printf("Ignoring --retry in test mode\n");
+                       schedule = NULL;
+               }
+       }
+
+       if (cmdname)
+               set_what_stop(cmdname);
+       else if (execname)
+               set_what_stop(execname);
+       else if (pidfile)
+               sprintf(what_stop, "process in pidfile `%.200s'", pidfile);
+       else if (userspec)
+               sprintf(what_stop, "process(es) owned by `%.200s'", userspec);
+       else
+               fatal("internal error, please report");
+
+       anykilled = 0;
+       retry_nr = 0;
+       n_killed = 0;
+
+       if (schedule == NULL) {
+               do_stop(signal_nr, quietmode, &n_killed, &n_notkilled, 0);
+               if (n_notkilled > 0 && quietmode <= 0)
+                       printf("%d pids were not killed\n", n_notkilled);
+               if (n_killed)
+                       anykilled = 1;
+               goto x_finished;
+       }
+
+       for (position = 0; position < schedule_length; ) {
+               value= schedule[position].value;
+               n_notkilled = 0;
+
+               switch (schedule[position].type) {
+
+               case sched_goto:
+                       position = value;
+                       continue;
+
+               case sched_signal:
+                       do_stop(value, quietmode, &n_killed, &n_notkilled, retry_nr++);
+                       if (!n_killed)
+                               goto x_finished;
+                       else
+                               anykilled = 1;
+                       goto next_item;
+
+               case sched_timeout:
+ /* We want to keep polling for the processes, to see if they've exited,
+  * or until the timeout expires.
+  *
+  * This is a somewhat complicated algorithm to try to ensure that we
+  * notice reasonably quickly when all the processes have exited, but
+  * don't spend too much CPU time polling.  In particular, on a fast
+  * machine with quick-exiting daemons we don't want to delay system
+  * shutdown too much, whereas on a slow one, or where processes are
+  * taking some time to exit, we want to increase the polling
+  * interval.
+  *
+  * The algorithm is as follows: we measure the elapsed time it takes
+  * to do one poll(), and wait a multiple of this time for the next
+  * poll.  However, if that would put us past the end of the timeout
+  * period we wait only as long as the timeout period, but in any case
+  * we always wait at least MIN_POLL_INTERVAL (20ms).  The multiple
+  * (`ratio') starts out as 2, and increases by 1 for each poll to a
+  * maximum of 10; so we use up to between 30% and 10% of the
+  * machine's resources (assuming a few reasonable things about system
+  * performance).
+  */
+                       xgettimeofday(&stopat);
+                       stopat.tv_sec += value;
+                       ratio = 1;
+                       for (;;) {
+                               xgettimeofday(&before);
+                               if (timercmp(&before,&stopat,>))
+                                       goto next_item;
+
+                               do_stop(0, 1, &n_killed, &n_notkilled, 0);
+                               if (!n_killed)
+                                       goto x_finished;
+
+                               xgettimeofday(&after);
+
+                               if (!timercmp(&after,&stopat,<))
+                                       goto next_item;
+
+                               if (ratio < 10)
+                                       ratio++;
+
+ TVCALC(interval,    ratio * (TVELEM(&after) - TVELEM(&before) + TVADJUST));
+ TVCALC(maxinterval,          TVELEM(&stopat) - TVELEM(&after) + TVADJUST);
+
+                               if (timercmp(&interval,&maxinterval,>))
+                                       interval = maxinterval;
+
+                               if (interval.tv_sec == 0 &&
+                                   interval.tv_usec <= MIN_POLL_INTERVAL)
+                                       interval.tv_usec = MIN_POLL_INTERVAL;
+
+                               r = select(0,0,0,0,&interval);
+                               if (r < 0 && errno != EINTR)
+                                       fatal("select() failed for pause: %s",
+                                             strerror(errno));
+                       }
+
+               default:
+                       assert(!"schedule[].type value must be valid");
+
+               }
+
+       next_item:
+               position++;
+       }
+
+       if (quietmode <= 0)
+               printf("Program %s, %d process(es), refused to die.\n",
+                      what_stop, n_killed);
+
+       return 2;
+
+x_finished:
+       if (!anykilled) {
+               if (quietmode <= 0)
+                       printf("No %s found running; none killed.\n", what_stop);
+               return exitnodo;
+       } else {
+               return 0;
+       }
+}
+
+/*
+int main(int argc, char **argv) NONRETURNING;
+*/
+
+int
+main(int argc, char **argv)
+{
+       progname = argv[0];
+
+       LIST_INIT(&namespace_head);
+
+       parse_options(argc, argv);
+       argc -= optind;
+       argv += optind;
+
+       if (execname && stat(execname, &exec_stat))
+               fatal("stat %s: %s", execname, strerror(errno));
+
+       if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
+               struct passwd *pw;
+
+               pw = getpwnam(userspec);
+               if (!pw)
+                       fatal("user `%s' not found\n", userspec);
+
+               user_id = pw->pw_uid;
+       }
+
+       if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) {
+               struct group *gr = getgrnam(changegroup);
+               if (!gr)
+                       fatal("group `%s' not found\n", changegroup);
+               runas_gid = gr->gr_gid;
+       }
+       if (changeuser && sscanf(changeuser, "%d", &runas_uid) != 1) {
+               struct passwd *pw = getpwnam(changeuser);
+               if (!pw)
+                       fatal("user `%s' not found\n", changeuser);
+               runas_uid = pw->pw_uid;
+               if (changegroup == NULL) { /* pass the default group of this user */
+                       changegroup = ""; /* just empty */
+                       runas_gid = pw->pw_gid;
+               }
+       }
+
+       if (stop) {
+               int i = run_stop_schedule();
+               exit(i);
+       }
+
+       do_findprocs();
+
+       if (found) {
+               if (quietmode <= 0)
+                       printf("%s already running.\n", execname);
+               exit(exitnodo);
+       }
+       if (testmode) {
+               printf("Would start %s ", startas);
+               while (argc-- > 0)
+                       printf("%s ", *argv++);
+               if (changeuser != NULL) {
+                       printf(" (as user %s[%d]", changeuser, runas_uid);
+                       if (changegroup != NULL)
+                               printf(", and group %s[%d])", changegroup, runas_gid);
+                       else
+                               printf(")");
+               }
+               if (changeroot != NULL)
+                       printf(" in directory %s", changeroot);
+               if (nicelevel)
+                       printf(", and add %i to the priority", nicelevel);
+               printf(".\n");
+               exit(0);
+       }
+       if (quietmode < 0)
+               printf("Starting %s...\n", startas);
+       *--argv = startas;
+       if (changeroot != NULL) {
+               if (chdir(changeroot) < 0)
+                       fatal("Unable to chdir() to %s", changeroot);
+               if (chroot(changeroot) < 0)
+                       fatal("Unable to chroot() to %s", changeroot);
+       }
+       if (changeuser != NULL) {
+               if (setgid(runas_gid))
+                       fatal("Unable to set gid to %d", runas_gid);
+               if (initgroups(changeuser, runas_gid))
+                       fatal("Unable to set initgroups() with gid %d", runas_gid);
+               if (setuid(runas_uid))
+                       fatal("Unable to set uid to %s", changeuser);
+       }
+
+       if (background) { /* ok, we need to detach this process */
+               int i, fd;
+               if (quietmode < 0)
+                       printf("Detatching to start %s...", startas);
+               i = fork();
+               if (i<0) {
+                       fatal("Unable to fork.\n");
+               }
+               if (i) { /* parent */
+                       if (quietmode < 0)
+                               printf("done.\n");
+                       exit(0);
+               }
+                /* child continues here */
+                /* now close all extra fds */
+               for (i=getdtablesize()-1; i>=0; --i) close(i);
+                /* change tty */
+               fd = open("/dev/tty", O_RDWR);
+               ioctl(fd, TIOCNOTTY, 0);
+               close(fd);
+               chdir("/");
+               umask(022); /* set a default for dumb programs */
+               setpgid(0,0);  /* set the process group */
+               fd=open("/dev/null", O_RDWR); /* stdin */
+               dup(fd); /* stdout */
+               dup(fd); /* stderr */
+       }
+       if (nicelevel) {
+               errno = 0;
+               if (nice(nicelevel) < 0 && errno)
+                       fatal("Unable to alter nice level by %i: %s", nicelevel,
+                               strerror(errno));
+       }
+       if (mpidfile && pidfile != NULL) { /* user wants _us_ to make the pidfile :) */
+               FILE *pidf = fopen(pidfile, "w");
+               pid_t pidt = getpid();
+               if (pidf == NULL)
+                       fatal("Unable to open pidfile `%s' for writing: %s", pidfile,
+                               strerror(errno));
+               fprintf(pidf, "%d\n", pidt);
+               fclose(pidf);
+       }
+       set_namespaces();
+       execv(startas, argv);
+       fatal("Unable to start %s: %s", startas, strerror(errno));
+}
index 9b81f99607f59e5cb7d639d525abb9614a4f1b66..bb6bbbe87e50ebadd87584fab591ad61b42ef38f 100644 (file)
@@ -112,6 +112,16 @@ 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
+
+if SNMP
+vtysh_scan += $(top_srcdir)/lib/agentx.c
+endif
+
 vtysh_cmd_FILES = $(vtysh_scan) \
                  $(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \
                  $(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \
index 551048248520d2b34bf408cb810f1c884bcd224e..0ca1451ff536da3efa3138fdcfa4fe4c3dea7eb2 100755 (executable)
@@ -82,14 +82,17 @@ foreach (@ARGV) {
             $protocol = "VTYSH_RIPD";
         }
         elsif ($file =~ /lib\/routemap\.c$/) {
-            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD";
+            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD";
         }
         elsif ($file =~ /lib\/vrf\.c$/) {
-            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
+            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_EIGRPD";
         }
         elsif ($file =~ /lib\/filter\.c$/) {
             $protocol = "VTYSH_ALL";
         }
+       elsif ($file =~ /lib\/agentx\.c$/) {
+           $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
+       }
         elsif ($file =~ /lib\/ns\.c$/) {
             $protocol = "VTYSH_ZEBRA";
         }
@@ -97,7 +100,7 @@ foreach (@ARGV) {
             if ($defun_array[1] =~ m/ipv6/) {
                 $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
             } else {
-                $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD";
+                $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD";
             }
         }
         elsif ($file =~ /lib\/distribute\.c$/) {
index 682cd99c238719099b5c405ad54c7e7bd3798cc7..b029db2337a488d1a51285958c3a85fa77c49230 100644 (file)
@@ -75,6 +75,7 @@ struct vtysh_client vtysh_client[] =
   { .fd = -1, .name = "isisd",    .flag = VTYSH_ISISD,    .next = NULL},
   { .fd = -1, .name = "pimd",     .flag = VTYSH_PIMD,     .next = NULL},
   { .fd = -1, .name = "nhrpd",    .flag = VTYSH_NHRPD,    .next = NULL},
+  { .fd = -1, .name = "eigrpd",   .flag = VTYSH_EIGRPD,   .next = NULL},
   { .fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL},
 };
 
@@ -309,7 +310,8 @@ vtysh_execute_func (const char *line, int pager)
           || saved_node == BGP_ENCAP_NODE || saved_node == BGP_ENCAPV6_NODE
            || saved_node == BGP_IPV4_NODE
           || saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE
-          || saved_node == BGP_IPV6M_NODE || saved_node == BGP_EVPN_NODE)
+          || saved_node == BGP_IPV4L_NODE || saved_node == BGP_IPV6L_NODE
+           || saved_node == BGP_IPV6M_NODE || saved_node == BGP_EVPN_NODE)
          && (tried == 1))
        {
          vtysh_execute("exit-address-family");
@@ -947,6 +949,12 @@ static struct cmd_node bgp_ipv4m_node =
   "%s(config-router-af)# "
 };
 
+static struct cmd_node bgp_ipv4l_node =
+{
+  BGP_IPV4L_NODE,
+  "%s(config-router-af)# "
+};
+
 static struct cmd_node bgp_ipv6_node =
 {
   BGP_IPV6_NODE,
@@ -965,6 +973,12 @@ static struct cmd_node bgp_evpn_node =
   "%s(config-router-af)# "
 };
 
+static struct cmd_node bgp_ipv6l_node =
+{
+  BGP_IPV6L_NODE,
+  "%s(config-router-af)# "
+};
+
 static struct cmd_node bgp_vnc_defaults_node =
 {
   BGP_VNC_DEFAULTS_NODE,
@@ -994,6 +1008,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,
@@ -1115,7 +1135,7 @@ DEFUNSH (VTYSH_BGPD,
         "address-family vpnv4 [unicast]",
         "Enter Address Family command mode\n"
         "Address Family\n"
-        "Address Family Modifier\n")
+        "Address Family modifier\n")
 {
   vty->node = BGP_VPNV4_NODE;
   return CMD_SUCCESS;
@@ -1127,7 +1147,7 @@ DEFUNSH (VTYSH_BGPD,
         "address-family vpnv6 [unicast]",
         "Enter Address Family command mode\n"
         "Address Family\n"
-        "Address Family Modifier\n")
+        "Address Family modifier\n")
 {
   vty->node = BGP_VPNV6_NODE;
   return CMD_SUCCESS;
@@ -1194,6 +1214,18 @@ DEFUNSH (VTYSH_BGPD,
   return CMD_SUCCESS;
 }
 
+DEFUNSH (VTYSH_BGPD,
+         address_family_ipv4_labeled_unicast,
+         address_family_ipv4_labeled_unicast_cmd,
+         "address-family ipv4 labeled-unicast",
+         "Enter Address Family command mode\n"
+         "Address Family\n"
+         "Address Family modifier\n")
+{
+  vty->node = BGP_IPV4L_NODE;
+  return CMD_SUCCESS;
+}
+
 DEFUNSH (VTYSH_BGPD,
          address_family_ipv6,
          address_family_ipv6_cmd,
@@ -1230,6 +1262,18 @@ DEFUNSH (VTYSH_BGPD,
   return CMD_SUCCESS;
 }
 
+DEFUNSH (VTYSH_BGPD,
+         address_family_ipv6_labeled_unicast,
+         address_family_ipv6_labeled_unicast_cmd,
+         "address-family ipv6 labeled-unicast",
+         "Enter Address Family command mode\n"
+         "Address Family\n"
+         "Address Family modifier\n")
+{
+  vty->node = BGP_IPV6L_NODE;
+  return CMD_SUCCESS;
+}
+
 DEFUNSH (VTYSH_BGPD,
         address_family_evpn,
         address_family_evpn_cmd,
@@ -1348,6 +1392,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,
@@ -1531,6 +1587,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:
@@ -1548,8 +1605,10 @@ vtysh_exit (struct vty *vty)
     case BGP_ENCAPV6_NODE:
     case BGP_IPV4_NODE:
     case BGP_IPV4M_NODE:
+    case BGP_IPV4L_NODE:
     case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:
+    case BGP_IPV6L_NODE:
     case BGP_VRF_POLICY_NODE:
     case BGP_EVPN_NODE:
     case BGP_VNC_DEFAULTS_NODE:
@@ -1608,11 +1667,13 @@ DEFUNSH (VTYSH_BGPD,
 {
   if (vty->node == BGP_IPV4_NODE
       || vty->node == BGP_IPV4M_NODE
+      || vty->node == BGP_IPV4L_NODE
       || vty->node == BGP_VPNV4_NODE
       || vty->node == BGP_VPNV6_NODE
       || vty->node == BGP_ENCAP_NODE
       || vty->node == BGP_ENCAPV6_NODE
       || vty->node == BGP_IPV6_NODE
+      || vty->node == BGP_IPV6L_NODE
       || vty->node == BGP_IPV6M_NODE)
     vty->node = BGP_NODE;
   return CMD_SUCCESS;
@@ -1732,6 +1793,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,
@@ -1815,7 +1894,7 @@ DEFUNSH (VTYSH_INTERFACE,
 }
 
 /* TODO Implement "no interface command in isisd. */
-DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D,
+DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_EIGRPD,
        vtysh_no_interface_cmd,
        "no interface IFNAME",
        NO_STR
@@ -1899,13 +1978,13 @@ DEFUNSH (VTYSH_VRF,
 
 /* TODO Implement interface description commands in ripngd, ospf6d
  * and isisd. */
-DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD,
-       vtysh_interface_desc_cmd,
+DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_EIGRPD,
+      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
@@ -3140,14 +3219,17 @@ vtysh_init_vty (void)
   install_node (&bgp_encapv6_node, NULL);
   install_node (&bgp_ipv4_node, NULL);
   install_node (&bgp_ipv4m_node, NULL);
+  install_node (&bgp_ipv4l_node, NULL);
   install_node (&bgp_ipv6_node, NULL);
   install_node (&bgp_ipv6m_node, NULL);
+  install_node (&bgp_ipv6l_node, NULL);
   install_node (&bgp_vrf_policy_node, NULL);
   install_node (&bgp_evpn_node, NULL);
   install_node (&bgp_vnc_defaults_node, NULL);
   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);
@@ -3178,9 +3260,11 @@ vtysh_init_vty (void)
   vtysh_install_default (BGP_ENCAPV6_NODE);
   vtysh_install_default (BGP_IPV4_NODE);
   vtysh_install_default (BGP_IPV4M_NODE);
+  vtysh_install_default (BGP_IPV4L_NODE);
   vtysh_install_default (BGP_IPV6_NODE);
   vtysh_install_default (BGP_IPV6M_NODE);
   vtysh_install_default (BGP_EVPN_NODE);
+  vtysh_install_default (BGP_IPV6L_NODE);
 #if ENABLE_BGP_VNC
   vtysh_install_default (BGP_VRF_POLICY_NODE);
   vtysh_install_default (BGP_VNC_DEFAULTS_NODE);
@@ -3188,6 +3272,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);
@@ -3217,6 +3302,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)
@@ -3249,11 +3336,15 @@ vtysh_init_vty (void)
   install_element (BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd);
   install_element (BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd);
   install_element (BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd);
+  install_element (BGP_IPV4L_NODE, &vtysh_exit_bgpd_cmd);
+  install_element (BGP_IPV4L_NODE, &vtysh_quit_bgpd_cmd);
   install_element (BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd);
   install_element (BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd);
   install_element (BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd);
   install_element (BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd);
   install_element (BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd);
+  install_element (BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd);
+  install_element (BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd);
 #if defined (ENABLE_BGP_VNC)
   install_element (BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
   install_element (BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
@@ -3281,6 +3372,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);
@@ -3292,12 +3384,14 @@ vtysh_init_vty (void)
   install_element (BGP_NODE, &vtysh_end_all_cmd);
   install_element (BGP_IPV4_NODE, &vtysh_end_all_cmd);
   install_element (BGP_IPV4M_NODE, &vtysh_end_all_cmd);
+  install_element (BGP_IPV4L_NODE, &vtysh_end_all_cmd);
   install_element (BGP_VPNV4_NODE, &vtysh_end_all_cmd);
   install_element (BGP_VPNV6_NODE, &vtysh_end_all_cmd);
   install_element (BGP_ENCAP_NODE, &vtysh_end_all_cmd);
   install_element (BGP_ENCAPV6_NODE, &vtysh_end_all_cmd);
   install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd);
   install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd);
+  install_element (BGP_IPV6L_NODE, &vtysh_end_all_cmd);
   install_element (BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd);
   install_element (BGP_EVPN_NODE, &vtysh_end_all_cmd);
   install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
@@ -3328,6 +3422,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);
@@ -3356,9 +3451,11 @@ vtysh_init_vty (void)
   install_element (BGP_NODE, &address_family_ipv4_cmd);
   install_element (BGP_NODE, &address_family_ipv4_multicast_cmd);
   install_element (BGP_NODE, &address_family_ipv4_vpn_cmd);
+  install_element (BGP_NODE, &address_family_ipv4_labeled_unicast_cmd);
   install_element (BGP_NODE, &address_family_ipv6_cmd);
   install_element (BGP_NODE, &address_family_ipv6_multicast_cmd);
   install_element (BGP_NODE, &address_family_ipv6_vpn_cmd);
+  install_element (BGP_NODE, &address_family_ipv6_labeled_unicast_cmd);
   install_element (BGP_NODE, &address_family_evpn_cmd);
   install_element (BGP_VPNV4_NODE, &exit_address_family_cmd);
   install_element (BGP_VPNV6_NODE, &exit_address_family_cmd);
@@ -3366,9 +3463,11 @@ vtysh_init_vty (void)
   install_element (BGP_ENCAPV6_NODE, &exit_address_family_cmd);
   install_element (BGP_IPV4_NODE, &exit_address_family_cmd);
   install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
+  install_element (BGP_IPV4L_NODE, &exit_address_family_cmd);
   install_element (BGP_IPV6_NODE, &exit_address_family_cmd);
   install_element (BGP_IPV6M_NODE, &exit_address_family_cmd);
   install_element (BGP_EVPN_NODE, &exit_address_family_cmd);
+  install_element (BGP_IPV6L_NODE, &exit_address_family_cmd);
 
   install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
   install_element (BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd);
index 6d9e21d8a0cdd0ed3a29a5a84d5224d221158771..ad45abcdf33185b7eee6bdbe50453cde0feef6a3 100644 (file)
@@ -36,15 +36,16 @@ 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
 /* watchfrr is not in ALL since library CLI functions should not be
  * run on it (logging & co. should stay in a fixed/frozen config, and
  * things like prefix lists are not even initialised) */
-#define VTYSH_ALL        VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD
+#define VTYSH_ALL        VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD
 #define VTYSH_RMAP       VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_PIMD
-#define VTYSH_INTERFACE          VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD
+#define VTYSH_INTERFACE          VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD
 #define VTYSH_NS          VTYSH_ZEBRA
 #define VTYSH_VRF        VTYSH_ZEBRA
 
index 94c4042dd4b8e79914b219aca88a694575516145..2a84847aaa798d56f3fe2231f590023a21f5bee5 100644 (file)
@@ -206,6 +206,8 @@ vtysh_config_parse_line (const char *line)
        config = config_get (RIP_NODE, line);
       else if (strncmp (line, "router ripng", strlen ("router ripng")) == 0)
        config = config_get (RIPNG_NODE, line);
+      else if (strncmp (line, "router eigrp", strlen ("router eigrp")) == 0)
+        config = config_get (EIGRP_NODE, line);
       else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0)
        config = config_get (OSPF_NODE, line);
       else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0)
@@ -275,6 +277,7 @@ vtysh_config_parse_line (const char *line)
          if (strncmp (line, "log", strlen ("log")) == 0
              || strncmp (line, "hostname", strlen ("hostname")) == 0
              || strncmp (line, "frr", strlen ("frr")) == 0
+             || strncmp (line, "agentx", strlen ("agentx")) == 0
             )
            config_add_line_uniq (config_top, line);
          else
index 3e0de3b4631c7b913b111f7f46760e0d999a7ffa..6c5e069064666d4445034d1265ca585e37cf7140 100644 (file)
@@ -31,7 +31,7 @@ zebra_SOURCES = \
        redistribute.c debug.c rtadv.c zebra_vty.c \
        irdp_main.c irdp_interface.c irdp_packet.c router-id.c \
        zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \
-       zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \
+       zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls_vty.c \
        zebra_mroute.c \
        label_manager.c \
        # end
@@ -40,7 +40,7 @@ testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
        zebra_vty.c zebra_ptm.c zebra_routemap.c zebra_ns.c zebra_vrf.c \
        kernel_null.c  redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c \
        zebra_ptm_null.c rtadv_null.c if_null.c zserv_null.c zebra_static.c \
-       zebra_memory.c zebra_mpls.c zebra_mpls_vty.c zebra_mpls_null.c
+       zebra_memory.c zebra_mpls_vty.c zebra_mpls_null.c
 
 noinst_HEADERS = \
        zebra_memory.h \
@@ -88,7 +88,7 @@ EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c \
        rt_socket.c rtread_netlink.c rtread_sysctl.c \
        rtread_getmsg.c kernel_socket.c kernel_netlink.c \
        ioctl.c ioctl_solaris.c \
-       zebra_mpls_netlink.c zebra_mpls_openbsd.c \
+       zebra_mpls_netlink.c zebra_mpls_openbsd.c zebra_mpls.c \
        GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB
 
 client : client_main.o ../lib/libfrr.la
index 78ac0258caf7ac4f2b46edf86aaba3f6de2bf259..42e7c7bb1871bbf4bb8d706fbb65b11def946751 100644 (file)
@@ -709,6 +709,7 @@ if_delete_update (struct interface *ifp)
      for setting ifindex to IFINDEX_INTERNAL after processing the
      interface deletion message. */
   ifp->ifindex = IFINDEX_INTERNAL;
+  ifp->node = NULL;
 }
 
 /* VRF change for an interface */
index 49394bd6f81cf08548f8c6ef166f38a6af3ca27f..e97420321990e62f0733f254db2c33feda824cef 100644 (file)
@@ -100,6 +100,11 @@ static const struct message rtproto_str[] = {
   {RTPROT_BIRD,     "BIRD"},
 #endif /* RTPROT_BIRD */
   {RTPROT_MROUTED,  "mroute"},
+  {RTPROT_BGP,      "BGP"},
+  {RTPROT_OSPF,     "OSPF"},
+  {RTPROT_ISIS,     "IS-IS"},
+  {RTPROT_RIP,      "RIP"},
+  {RTPROT_RIPNG,    "RIPNG"},
   {0,               NULL}
 };
 
index c7ed209d3c862b0cb61dd7a67cfccfdf122c5683..23cce0a1b737a78b78d250fca75f596e7d34e4b8 100644 (file)
@@ -498,6 +498,7 @@ int
 zebra_add_import_table_entry (struct route_node *rn, struct rib *rib, const char *rmap_name)
 {
   struct rib *newrib;
+  struct rib *same;
   struct prefix p;
   struct nexthop *nhop;
   union g_addr *gate;
@@ -515,6 +516,21 @@ zebra_add_import_table_entry (struct route_node *rn, struct rib *rib, const char
           p.prefixlen = rn->p.prefixlen;
           p.u.prefix4 = rn->p.u.prefix4;
 
+          RNODE_FOREACH_RIB (rn, same)
+            {
+              if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED))
+                continue;
+
+              if (same->type == rib->type && same->instance == rib->instance
+                  && same->table == rib->table
+                  && same->type != ZEBRA_ROUTE_CONNECT)
+                break;
+            }
+
+          if (same)
+            zebra_del_import_table_entry (rn, same);
+
+
           if (rib->nexthop_num == 1)
            {
              nhop = rib->nexthop;
index 5381d76b9874688cf88007093979a669d0b160c5..8f6cff0d8a101026be7d4ac9da100f62660ebd87 100644 (file)
@@ -372,7 +372,7 @@ extern void rib_init (void);
 extern unsigned long rib_score_proto (u_char proto, u_short instance);
 extern void rib_queue_add (struct route_node *rn);
 extern void meta_queue_free (struct meta_queue *mq);
-
+extern int zebra_rib_labeled_unicast (struct rib *rib);
 extern struct route_table *rib_table_ipv6;
 
 extern void rib_unlink (struct route_node *, struct rib *);
index a544593dd65afad9edf4bcd59477d37df560a6a2..77f03a2c67fbe3901c556e1eddae91e13cfd214b 100644 (file)
@@ -103,6 +103,47 @@ struct gw_family_t
   union g_addr  gate;
 };
 
+static inline int is_selfroute(int proto)
+{
+  if ((proto == RTPROT_BGP) || (proto == RTPROT_OSPF) ||
+      (proto == RTPROT_STATIC) || (proto == RTPROT_ZEBRA) ||
+      (proto == RTPROT_ISIS) || (proto == RTPROT_RIPNG)) {
+    return 1;
+  }
+
+  return 0;
+}
+
+static inline int get_rt_proto(int proto)
+{
+  switch (proto) {
+  case ZEBRA_ROUTE_BGP:
+    proto = RTPROT_BGP;
+    break;
+  case ZEBRA_ROUTE_OSPF:
+  case ZEBRA_ROUTE_OSPF6:
+    proto = RTPROT_OSPF;
+    break;
+  case ZEBRA_ROUTE_STATIC:
+    proto = RTPROT_STATIC;
+    break;
+  case ZEBRA_ROUTE_ISIS:
+    proto = RTPROT_ISIS;
+    break;
+  case ZEBRA_ROUTE_RIP:
+    proto = RTPROT_RIP;
+    break;
+  case ZEBRA_ROUTE_RIPNG:
+    proto = RTPROT_RIPNG;
+    break;
+  default:
+    proto = RTPROT_ZEBRA;
+    break;
+  }
+
+  return proto;
+}
+
 /*
 Pending: create an efficient table_id (in a tree/hash) based lookup)
  */
@@ -171,7 +212,7 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
     return 0;
 
   if (!startup &&
-      rtm->rtm_protocol == RTPROT_ZEBRA &&
+      is_selfroute (rtm->rtm_protocol) &&
       h->nlmsg_type == RTM_NEWROUTE)
     return 0;
 
@@ -196,7 +237,7 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
     }
 
   /* Route which inserted by Zebra. */
-  if (rtm->rtm_protocol == RTPROT_ZEBRA)
+  if (is_selfroute(rtm->rtm_protocol))
     flags |= ZEBRA_FLAG_SELFROUTE;
 
   if (tb[RTA_OIF])
@@ -1137,7 +1178,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct prefix *src_p,
   req.r.rtm_family = family;
   req.r.rtm_dst_len = p->prefixlen;
   req.r.rtm_src_len = src_p ? src_p->prefixlen : 0;
-  req.r.rtm_protocol = RTPROT_ZEBRA;
+  req.r.rtm_protocol = get_rt_proto(rib->type);
   req.r.rtm_scope = RT_SCOPE_UNIVERSE;
 
   if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
index 93ee622e3530bcdc446f1f959eca7aad24801e13..af58a0f0d4bfd6915a4557cd393c5368565b4d36 100644 (file)
 
 #define NL_DEFAULT_ROUTE_METRIC 20
 
+/* Additional protocol strings to push into routes */
+#define RTPROT_BGP         186
+#define RTPROT_ISIS        187
+#define RTPROT_OSPF        188
+#define RTPROT_RIP         189
+#define RTPROT_RIPNG       190
+
+
 extern void
 clear_nhlfe_installed (zebra_lsp_t *lsp);
 extern int
index 5a3ed7545d294f5f4f29747428f3458d540f58ca..76263024c5416b789e94d1edc0fddca8851efe8a 100644 (file)
@@ -47,6 +47,7 @@
 #include "zebra/zebra_mpls.h"
 
 DEFINE_MTYPE_STATIC(ZEBRA, LSP,                        "MPLS LSP object")
+DEFINE_MTYPE_STATIC(ZEBRA, FEC,                        "MPLS FEC object")
 DEFINE_MTYPE_STATIC(ZEBRA, SLSP,               "MPLS static LSP config")
 DEFINE_MTYPE_STATIC(ZEBRA, NHLFE,              "MPLS nexthop object")
 DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE,             "MPLS static nexthop object")
@@ -58,6 +59,32 @@ int mpls_enabled;
 extern struct zebra_t zebrad;
 
 /* static function declarations */
+
+static void
+fec_evaluate (struct zebra_vrf *zvrf, int add);
+static u_int32_t
+fec_derive_label_from_index (struct zebra_vrf *vrf, zebra_fec_t *fec);
+static int
+lsp_install (struct zebra_vrf *zvrf, mpls_label_t label,
+             struct route_node *rn, struct rib *rib);
+static int
+lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label);
+static int
+fec_change_update_lsp (struct zebra_vrf *zvrf, zebra_fec_t *fec, mpls_label_t old_label);
+static int
+fec_send (zebra_fec_t *fec, struct zserv *client);
+static void
+fec_update_clients (zebra_fec_t *fec);
+static void
+fec_print (zebra_fec_t *fec, struct vty *vty);
+static zebra_fec_t *
+fec_find (struct route_table *table, struct prefix *p);
+static zebra_fec_t *
+fec_add (struct route_table *table, struct prefix *p, mpls_label_t label,
+         u_int32_t flags, u_int32_t label_index);
+static int
+fec_del (zebra_fec_t *fec);
+
 static unsigned int
 label_hash (void *p);
 static int
@@ -68,6 +95,7 @@ static int
 nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop);
 static int
 nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe);
+
 static void
 lsp_select_best_nhlfe (zebra_lsp_t *lsp);
 static void
@@ -84,21 +112,24 @@ static int
 lsp_processq_add (zebra_lsp_t *lsp);
 static void *
 lsp_alloc (void *p);
+
 static char *
 nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size);
 static int
 nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
-                  union g_addr *gate, char *ifname, ifindex_t ifindex);
+                  union g_addr *gate, ifindex_t ifindex);
 static zebra_nhlfe_t *
 nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
             enum nexthop_types_t gtype, union g_addr *gate,
-            char *ifname, ifindex_t ifindex);
+            ifindex_t ifindex);
 static zebra_nhlfe_t *
 nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
            enum nexthop_types_t gtype, union g_addr *gate,
-           char *ifname, ifindex_t ifindex, mpls_label_t out_label);
+           ifindex_t ifindex, mpls_label_t out_label);
 static int
 nhlfe_del (zebra_nhlfe_t *snhlfe);
+static void
+nhlfe_out_label_update (zebra_nhlfe_t *nhlfe, struct nexthop_label *nh_label);
 static int
 mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp,
                        enum lsp_types_t type);
@@ -112,14 +143,13 @@ static void *
 slsp_alloc (void *p);
 static int
 snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
-              union g_addr *gate, char *ifname, ifindex_t ifindex);
+              union g_addr *gate, ifindex_t ifindex);
 static zebra_snhlfe_t *
 snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
-             union g_addr *gate, char *ifname, ifindex_t ifindex);
+             union g_addr *gate, ifindex_t ifindex);
 static zebra_snhlfe_t *
 snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
-            union g_addr *gate, char *ifname, ifindex_t ifindex,
-            mpls_label_t out_label);
+            union g_addr *gate, ifindex_t ifindex, mpls_label_t out_label);
 static int
 snhlfe_del (zebra_snhlfe_t *snhlfe);
 static int
@@ -135,153 +165,616 @@ mpls_processq_init (struct zebra_t *zebra);
 /* Static functions */
 
 /*
- * Hash function for label.
+ * Install label forwarding entry based on labeled-route entry.
  */
-static unsigned int
-label_hash (void *p)
+static int
+lsp_install (struct zebra_vrf *zvrf, mpls_label_t label,
+             struct route_node *rn, struct rib *rib)
 {
-  const zebra_ile_t *ile = p;
+  struct hash *lsp_table;
+  zebra_ile_t tmp_ile;
+  zebra_lsp_t *lsp;
+  zebra_nhlfe_t *nhlfe;
+  struct nexthop *nexthop;
+  enum lsp_types_t  lsp_type;
+  char buf[BUFSIZ];
+  int added, changed;
 
-  return (jhash_1word(ile->in_label, 0));
+  /* Lookup table. */
+  lsp_table = zvrf->lsp_table;
+  if (!lsp_table)
+    return -1;
+
+  /* See if route entry is selected; we really expect only 1 entry here. */
+  if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+    return 0;
+
+  lsp_type = lsp_type_from_rib_type (rib->type);
+  added = changed = 0;
+
+  /* Locate or allocate LSP entry. */
+  tmp_ile.in_label = label;
+  lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc);
+  if (!lsp)
+    return -1;
+
+  /* For each active nexthop, create NHLFE. Note that we deliberately skip
+   * recursive nexthops right now, because intermediate hops won't understand
+   * the label advertised by the recursive nexthop (plus we don't have the
+   * logic yet to push multiple labels).
+   */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      /* Skip inactive and recursive entries. */
+      if (!CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+        continue;
+      if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+        continue;
+
+      nhlfe = nhlfe_find (lsp, lsp_type, nexthop->type, &nexthop->gate,
+                          nexthop->ifindex);
+      if (nhlfe)
+        {
+          /* Clear deleted flag (in case it was set) */
+          UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
+          if (nexthop_labels_match (nhlfe->nexthop, nexthop))
+            /* No change */
+            continue;
+
+
+          if (IS_ZEBRA_DEBUG_MPLS)
+            {
+              nhlfe2str (nhlfe, buf, BUFSIZ);
+              zlog_debug ("LSP in-label %u type %d nexthop %s "
+                          "out-label changed",
+                          lsp->ile.in_label, lsp_type, buf);
+            }
+
+          /* Update out label, trigger processing. */
+          nhlfe_out_label_update (nhlfe, nexthop->nh_label);
+          SET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
+          changed++;
+        }
+      else
+        {
+          /* Add LSP entry to this nexthop */
+          nhlfe = nhlfe_add (lsp, lsp_type, nexthop->type,
+                             &nexthop->gate, nexthop->ifindex,
+                             nexthop->nh_label->label[0]);
+          if (!nhlfe)
+            return -1;
+
+          if (IS_ZEBRA_DEBUG_MPLS)
+            {
+              nhlfe2str (nhlfe, buf, BUFSIZ);
+              zlog_debug ("Add LSP in-label %u type %d nexthop %s "
+                          "out-label %u",
+                          lsp->ile.in_label, lsp_type, buf,
+                          nexthop->nh_label->label[0]);
+            }
+
+          lsp->addr_family = NHLFE_FAMILY (nhlfe);
+
+          /* Mark NHLFE as changed. */
+          SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
+          added++;
+        }
+    }
+
+  /* Queue LSP for processing if necessary. If no NHLFE got added (special
+   * case), delete the LSP entry; this case results in somewhat ugly logging.
+   */
+  if (added || changed)
+    {
+      if (lsp_processq_add (lsp))
+        return -1;
+    }
+  else if (!lsp->nhlfe_list &&
+           !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
+    {
+      if (IS_ZEBRA_DEBUG_MPLS)
+        zlog_debug ("Free LSP in-label %u flags 0x%x",
+                    lsp->ile.in_label, lsp->flags);
+
+      lsp = hash_release(lsp_table, &lsp->ile);
+      if (lsp)
+        XFREE(MTYPE_LSP, lsp);
+    }
+
+  return 0;
 }
 
 /*
- * Compare 2 LSP hash entries based on in-label.
+ * Uninstall all non-static NHLFEs of a label forwarding entry. If all
+ * NHLFEs are removed, the entire entry is deleted.
  */
 static int
-label_cmp (const void *p1, const void *p2)
+lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label)
 {
-  const zebra_ile_t *ile1 = p1;
-  const zebra_ile_t *ile2 = p2;
+  struct hash *lsp_table;
+  zebra_ile_t tmp_ile;
+  zebra_lsp_t *lsp;
+  zebra_nhlfe_t *nhlfe, *nhlfe_next;
+  char buf[BUFSIZ];
 
-  return (ile1->in_label == ile2->in_label);
+  /* Lookup table. */
+  lsp_table = zvrf->lsp_table;
+  if (!lsp_table)
+    return -1;
+
+  /* If entry is not present, exit. */
+  tmp_ile.in_label = label;
+  lsp = hash_lookup (lsp_table, &tmp_ile);
+  if (!lsp || !lsp->nhlfe_list)
+    return 0;
+
+  /* Mark NHLFEs for delete or directly delete, as appropriate. */
+  for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next)
+    {
+      nhlfe_next = nhlfe->next;
+
+      /* Skip static NHLFEs */
+      if (nhlfe->type == ZEBRA_LSP_STATIC)
+        continue;
+
+      if (IS_ZEBRA_DEBUG_MPLS)
+        {
+          nhlfe2str (nhlfe, buf, BUFSIZ);
+          zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
+                      label, nhlfe->type, buf, nhlfe->flags);
+        }
+
+      if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED))
+        {
+          UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
+          SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
+        }
+      else
+        {
+          nhlfe_del (nhlfe);
+        }
+    }
+
+  /* Queue LSP for processing, if needed, else delete. */
+  if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
+    {
+      if (lsp_processq_add (lsp))
+        return -1;
+    }
+  else if (!lsp->nhlfe_list &&
+           !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
+    {
+      if (IS_ZEBRA_DEBUG_MPLS)
+        zlog_debug ("Del LSP in-label %u flags 0x%x",
+                    lsp->ile.in_label, lsp->flags);
+
+      lsp = hash_release(lsp_table, &lsp->ile);
+      if (lsp)
+        XFREE(MTYPE_LSP, lsp);
+    }
+
+  return 0;
 }
 
 /*
- * Check if an IPv4 nexthop for a NHLFE is active. Update nexthop based on
- * the passed flag.
- * NOTE: Looking only for connected routes right now.
+ * This function is invoked upon change to label block configuration; it
+ * will walk all registered FECs with label-index and appropriately update
+ * their local labels and trigger client updates.
  */
-static int
-nhlfe_nexthop_active_ipv4 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop)
+static void
+fec_evaluate (struct zebra_vrf *zvrf, int add)
 {
-  struct route_table *table;
-  struct prefix_ipv4 p;
   struct route_node *rn;
-  struct rib *match;
-  struct nexthop *match_nh;
+  zebra_fec_t *fec;
+  u_int32_t old_label, new_label;
+  int af;
+  char buf[BUFSIZ];
 
-  table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
-  if (!table)
-    return 0;
+  for (af = AFI_IP; af < AFI_MAX; af++)
+    {
+      if (zvrf->fec_table[af] == NULL)
+        continue;
 
-  /* Lookup nexthop in IPv4 routing table. */
-  memset (&p, 0, sizeof (struct prefix_ipv4));
-  p.family = AF_INET;
-  p.prefixlen = IPV4_MAX_PREFIXLEN;
-  p.prefix = nexthop->gate.ipv4;
+      for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+        {
+          if ((fec = rn->info) == NULL)
+            continue;
 
-  rn = route_node_match (table, (struct prefix *) &p);
-  if (!rn)
-    return 0;
+          /* Skip configured FECs and those without a label index. */
+          if (fec->flags & FEC_FLAG_CONFIGURED ||
+              fec->label_index == MPLS_INVALID_LABEL_INDEX)
+            continue;
 
-  route_unlock_node (rn);
+          if (IS_ZEBRA_DEBUG_MPLS)
+            prefix2str(&rn->p, buf, BUFSIZ);
 
-  /* Locate a valid connected route. */
-  RNODE_FOREACH_RIB (rn, match)
-    {
-      if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED) ||
-         !CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
-       continue;
+          /* Save old label, determine new label. */
+          old_label = fec->label;
+          if (add)
+            {
+              new_label = zvrf->mpls_srgb.start_label + fec->label_index;
+              if (new_label >= zvrf->mpls_srgb.end_label)
+                new_label = MPLS_INVALID_LABEL;
+            }
+          else
+            new_label = MPLS_INVALID_LABEL;
 
-      for (match_nh = match->nexthop; match_nh; match_nh = match_nh->next)
-       {
-         if (match->type == ZEBRA_ROUTE_CONNECT ||
-             nexthop->ifindex == match_nh->ifindex)
-           {
-             nexthop->ifindex = match_nh->ifindex;
-             return 1;
-           }
-       }
-    }
+          /* If label has changed, update FEC and clients. */
+          if (new_label == old_label)
+            continue;
 
-  return 0;
+          if (IS_ZEBRA_DEBUG_MPLS)
+            zlog_debug ("Update fec %s new label %u upon label block %s",
+                         buf, new_label, add ? "ADD" : "DEL");
+
+          fec->label = new_label;
+          fec_update_clients (fec);
+
+          /* Update label forwarding entries appropriately */
+          fec_change_update_lsp (zvrf, fec, old_label);
+        }
+    }
 }
 
+/*
+ * Derive (if possible) and update the local label for the FEC based on
+ * its label index. The index is "acceptable" if it falls within the
+ * globally configured label block (SRGB).
+ */
+static u_int32_t
+fec_derive_label_from_index (struct zebra_vrf *zvrf, zebra_fec_t *fec)
+{
+  u_int32_t label;
+
+  if (fec->label_index != MPLS_INVALID_LABEL_INDEX &&
+      zvrf->mpls_srgb.start_label &&
+      ((label = zvrf->mpls_srgb.start_label + fec->label_index) <
+       zvrf->mpls_srgb.end_label))
+    fec->label = label;
+  else
+    fec->label = MPLS_INVALID_LABEL;
+
+  return fec->label;
+}
 
 /*
- * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
- * the passed flag.
- * NOTE: Looking only for connected routes right now.
+ * There is a change for this FEC. Install or uninstall label forwarding
+ * entries, as appropriate.
  */
 static int
-nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop)
+fec_change_update_lsp (struct zebra_vrf *zvrf, zebra_fec_t *fec, mpls_label_t old_label)
 {
   struct route_table *table;
-  struct prefix_ipv6 p;
   struct route_node *rn;
-  struct rib *match;
+  struct rib *rib;
+  afi_t afi;
 
-  table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT);
-  if (!table)
+  /* Uninstall label forwarding entry, if previously installed. */
+  if (old_label != MPLS_INVALID_LABEL &&
+      old_label != MPLS_IMP_NULL_LABEL)
+    lsp_uninstall (zvrf, old_label);
+
+  /* Install label forwarding entry corr. to new label, if needed. */
+  if (fec->label == MPLS_INVALID_LABEL ||
+      fec->label == MPLS_IMP_NULL_LABEL)
     return 0;
 
-  /* Lookup nexthop in IPv6 routing table. */
-  memset (&p, 0, sizeof (struct prefix_ipv6));
-  p.family = AF_INET6;
-  p.prefixlen = IPV6_MAX_PREFIXLEN;
-  p.prefix = nexthop->gate.ipv6;
+  afi = family2afi(PREFIX_FAMILY(&fec->rn->p));
+  table = zebra_vrf_table (afi, SAFI_UNICAST, zvrf_id (zvrf));
+  if (!table)
+    return 0;
 
-  rn = route_node_match (table, (struct prefix *) &p);
+  /* See if labeled route exists. */
+  rn = route_node_lookup (table, &fec->rn->p);
   if (!rn)
     return 0;
 
-  route_unlock_node (rn);
-
-  /* Locate a valid connected route. */
-  RNODE_FOREACH_RIB (rn, match)
+  RNODE_FOREACH_RIB (rn, rib)
     {
-      if ((match->type == ZEBRA_ROUTE_CONNECT) &&
-          !CHECK_FLAG (match->status, RIB_ENTRY_REMOVED) &&
-          CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
         break;
     }
 
-  if (!match || !match->nexthop)
+  if (!rib || !zebra_rib_labeled_unicast (rib))
     return 0;
 
-  nexthop->ifindex = match->nexthop->ifindex;
-  return 1;
-}
+  if (lsp_install (zvrf, fec->label, rn, rib))
+    return -1;
 
+  return 0;
+}
 
 /*
- * Check the nexthop reachability for a NHLFE and return if valid (reachable)
- * or not.
- * NOTE: Each NHLFE points to only 1 nexthop.
+ * Inform about FEC to a registered client.
  */
 static int
-nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe)
+fec_send (zebra_fec_t *fec, struct zserv *client)
 {
-  struct nexthop *nexthop;
-  struct interface *ifp;
+  struct stream *s;
+  struct route_node *rn;
 
-  nexthop = nhlfe->nexthop;
-  if (!nexthop) // unexpected
-    return 0;
+  rn = fec->rn;
 
-  /* Check on nexthop based on type. */
-  switch (nexthop->type)
-    {
-      case NEXTHOP_TYPE_IPV4:
-      case NEXTHOP_TYPE_IPV4_IFINDEX:
-        if (nhlfe_nexthop_active_ipv4 (nhlfe, nexthop))
-          SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-        else
-          UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-        break;
+  /* Get output stream. */
+  s = client->obuf;
+  stream_reset (s);
 
-      case NEXTHOP_TYPE_IPV6:
+  zserv_create_header (s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
+
+  stream_putw(s, rn->p.family);
+  stream_put_prefix (s, &rn->p);
+  stream_putl(s, fec->label);
+  stream_putw_at(s, 0, stream_get_endp(s));
+  return zebra_server_send_message(client);
+}
+
+/*
+ * Update all registered clients about this FEC. Caller should've updated
+ * FEC and ensure no duplicate updates.
+ */
+static void
+fec_update_clients (zebra_fec_t *fec)
+{
+  struct listnode *node;
+  struct zserv *client;
+
+  for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
+    {
+      if (IS_ZEBRA_DEBUG_MPLS)
+        zlog_debug ("Update client %s", zebra_route_string(client->proto));
+      fec_send(fec, client);
+    }
+}
+
+
+/*
+ * Print a FEC-label binding entry.
+ */
+static void
+fec_print (zebra_fec_t *fec, struct vty *vty)
+{
+  struct route_node *rn;
+  struct listnode *node;
+  struct zserv *client;
+  char buf[BUFSIZ];
+
+  rn = fec->rn;
+  prefix2str(&rn->p, buf, BUFSIZ);
+  vty_out(vty, "%s%s", buf, VTY_NEWLINE);
+  vty_out(vty, "  Label: %s", label2str(fec->label, buf, BUFSIZ));
+  if (fec->label_index != MPLS_INVALID_LABEL_INDEX)
+    vty_out(vty, ", Label Index: %u", fec->label_index);
+  vty_out(vty, "%s", VTY_NEWLINE);
+  if (!list_isempty(fec->client_list))
+    {
+      vty_out(vty, "  Client list:");
+      for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
+        vty_out(vty, " %s(fd %d)",
+                zebra_route_string(client->proto), client->sock);
+      vty_out(vty, "%s", VTY_NEWLINE);
+    }
+}
+
+/*
+ * Locate FEC-label binding that matches with passed info.
+ */
+static zebra_fec_t *
+fec_find (struct route_table *table, struct prefix *p)
+{
+  struct route_node *rn;
+
+  apply_mask (p);
+  rn = route_node_lookup(table, p);
+  if (!rn)
+    return NULL;
+
+  route_unlock_node(rn);
+  return (rn->info);
+}
+
+/*
+ * Add a FEC. This may be upon a client registering for a binding
+ * or when a binding is configured.
+ */
+static zebra_fec_t *
+fec_add (struct route_table *table, struct prefix *p,
+         mpls_label_t label, u_int32_t flags, u_int32_t label_index)
+{
+  struct route_node *rn;
+  zebra_fec_t *fec;
+
+  apply_mask (p);
+
+  /* Lookup (or add) route node.*/
+  rn = route_node_get (table, p);
+  if (!rn)
+    return NULL;
+
+  fec = rn->info;
+
+  if (!fec)
+    {
+      fec = XCALLOC (MTYPE_FEC, sizeof(zebra_fec_t));
+      if (!fec)
+        return NULL;
+
+      rn->info = fec;
+      fec->rn = rn;
+      fec->label = label;
+      fec->client_list = list_new();
+    }
+  else
+    route_unlock_node (rn); /* for the route_node_get */
+
+  fec->label_index = label_index;
+  fec->flags = flags;
+
+  return fec;
+}
+
+/*
+ * Delete a FEC. This may be upon the last client deregistering for
+ * a FEC and no binding exists or when the binding is deleted and there
+ * are no registered clients.
+ */
+static int
+fec_del (zebra_fec_t *fec)
+{
+  list_free (fec->client_list);
+  fec->rn->info = NULL;
+  route_unlock_node (fec->rn);
+  XFREE (MTYPE_FEC, fec);
+  return 0;
+}
+
+/*
+ * Hash function for label.
+ */
+static unsigned int
+label_hash (void *p)
+{
+  const zebra_ile_t *ile = p;
+
+  return (jhash_1word(ile->in_label, 0));
+}
+
+/*
+ * Compare 2 LSP hash entries based on in-label.
+ */
+static int
+label_cmp (const void *p1, const void *p2)
+{
+  const zebra_ile_t *ile1 = p1;
+  const zebra_ile_t *ile2 = p2;
+
+  return (ile1->in_label == ile2->in_label);
+}
+
+/*
+ * Check if an IPv4 nexthop for a NHLFE is active. Update nexthop based on
+ * the passed flag.
+ * NOTE: Looking only for connected routes right now.
+ */
+static int
+nhlfe_nexthop_active_ipv4 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop)
+{
+  struct route_table *table;
+  struct prefix_ipv4 p;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *match_nh;
+
+  table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
+  if (!table)
+    return 0;
+
+  /* Lookup nexthop in IPv4 routing table. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = nexthop->gate.ipv4;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  if (!rn)
+    return 0;
+
+  route_unlock_node (rn);
+
+  /* Locate a valid connected route. */
+  RNODE_FOREACH_RIB (rn, match)
+    {
+      if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED) ||
+         !CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+       continue;
+
+      for (match_nh = match->nexthop; match_nh; match_nh = match_nh->next)
+       {
+         if (match->type == ZEBRA_ROUTE_CONNECT ||
+             nexthop->ifindex == match_nh->ifindex)
+           {
+             nexthop->ifindex = match_nh->ifindex;
+             return 1;
+           }
+       }
+    }
+
+  return 0;
+}
+
+
+/*
+ * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
+ * the passed flag.
+ * NOTE: Looking only for connected routes right now.
+ */
+static int
+nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop)
+{
+  struct route_table *table;
+  struct prefix_ipv6 p;
+  struct route_node *rn;
+  struct rib *match;
+
+  table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT);
+  if (!table)
+    return 0;
+
+  /* Lookup nexthop in IPv6 routing table. */
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = IPV6_MAX_PREFIXLEN;
+  p.prefix = nexthop->gate.ipv6;
+
+  rn = route_node_match (table, (struct prefix *) &p);
+  if (!rn)
+    return 0;
+
+  route_unlock_node (rn);
+
+  /* Locate a valid connected route. */
+  RNODE_FOREACH_RIB (rn, match)
+    {
+      if ((match->type == ZEBRA_ROUTE_CONNECT) &&
+          !CHECK_FLAG (match->status, RIB_ENTRY_REMOVED) &&
+          CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+        break;
+    }
+
+  if (!match || !match->nexthop)
+    return 0;
+
+  nexthop->ifindex = match->nexthop->ifindex;
+  return 1;
+}
+
+
+/*
+ * Check the nexthop reachability for a NHLFE and return if valid (reachable)
+ * or not.
+ * NOTE: Each NHLFE points to only 1 nexthop.
+ */
+static int
+nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe)
+{
+  struct nexthop *nexthop;
+  struct interface *ifp;
+
+  nexthop = nhlfe->nexthop;
+  if (!nexthop) // unexpected
+    return 0;
+
+  /* Check on nexthop based on type. */
+  switch (nexthop->type)
+    {
+      case NEXTHOP_TYPE_IPV4:
+      case NEXTHOP_TYPE_IPV4_IFINDEX:
+        if (nhlfe_nexthop_active_ipv4 (nhlfe, nexthop))
+          SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+        else
+          UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+        break;
+
+      case NEXTHOP_TYPE_IPV6:
         if (nhlfe_nexthop_active_ipv6 (nhlfe, nexthop))
           SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
         else
@@ -602,7 +1095,7 @@ nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size)
  */
 static int
 nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
-                  union g_addr *gate, char *ifname, ifindex_t ifindex)
+                  union g_addr *gate, ifindex_t ifindex)
 {
   struct nexthop *nhop;
   int cmp = 1;
@@ -644,7 +1137,7 @@ nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
 static zebra_nhlfe_t *
 nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
             enum nexthop_types_t gtype, union g_addr *gate,
-            char *ifname, ifindex_t ifindex)
+            ifindex_t ifindex)
 {
   zebra_nhlfe_t *nhlfe;
 
@@ -655,7 +1148,7 @@ nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
     {
       if (nhlfe->type != lsp_type)
         continue;
-      if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifname, ifindex))
+      if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifindex))
         break;
     }
 
@@ -669,7 +1162,7 @@ nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
 static zebra_nhlfe_t *
 nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
            enum nexthop_types_t gtype, union g_addr *gate,
-           char *ifname, ifindex_t ifindex, mpls_label_t out_label)
+           ifindex_t ifindex, mpls_label_t out_label)
 {
   zebra_nhlfe_t *nhlfe;
   struct nexthop *nexthop;
@@ -759,6 +1252,15 @@ nhlfe_del (zebra_nhlfe_t *nhlfe)
   return 0;
 }
 
+/*
+ * Update label for NHLFE entry.
+ */
+static void
+nhlfe_out_label_update (zebra_nhlfe_t *nhlfe, struct nexthop_label *nh_label)
+{
+  nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
+}
+
 static int
 mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp,
                        enum lsp_types_t type)
@@ -1026,7 +1528,7 @@ slsp_cmp (zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
  */
 static int
 snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
-              union g_addr *gate, char *ifname, ifindex_t ifindex)
+              union g_addr *gate, ifindex_t ifindex)
 {
   int cmp = 1;
 
@@ -1050,228 +1552,708 @@ snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
       break;
     }
 
-  return cmp;
+  return cmp;
+}
+
+/*
+ * Locate static NHLFE that matches with passed info.
+ */
+static zebra_snhlfe_t *
+snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
+             union g_addr *gate, ifindex_t ifindex)
+{
+  zebra_snhlfe_t *snhlfe;
+
+  if (!slsp)
+    return NULL;
+
+  for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next)
+    {
+      if (!snhlfe_match (snhlfe, gtype, gate, ifindex))
+        break;
+    }
+
+  return snhlfe;
+}
+
+
+/*
+ * Add static NHLFE. Base LSP config entry must have been created
+ * and duplicate check done.
+ */
+static zebra_snhlfe_t *
+snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
+            union g_addr *gate, ifindex_t ifindex,
+            mpls_label_t out_label)
+{
+  zebra_snhlfe_t *snhlfe;
+
+  if (!slsp)
+    return NULL;
+
+  snhlfe = XCALLOC(MTYPE_SNHLFE, sizeof(zebra_snhlfe_t));
+  snhlfe->slsp = slsp;
+  snhlfe->out_label = out_label;
+  snhlfe->gtype = gtype;
+  switch (gtype)
+    {
+    case NEXTHOP_TYPE_IPV4:
+      snhlfe->gate.ipv4 = gate->ipv4;
+      break;
+    case NEXTHOP_TYPE_IPV6:
+    case NEXTHOP_TYPE_IPV6_IFINDEX:
+      snhlfe->gate.ipv6 = gate->ipv6;
+      if (ifindex)
+        snhlfe->ifindex = ifindex;
+      break;
+    default:
+      XFREE (MTYPE_SNHLFE, snhlfe);
+      return NULL;
+    }
+
+  if (slsp->snhlfe_list)
+    slsp->snhlfe_list->prev = snhlfe;
+  snhlfe->next = slsp->snhlfe_list;
+  slsp->snhlfe_list = snhlfe;
+
+  return snhlfe;
+}
+
+/*
+ * Delete static NHLFE. Entry must be present on list.
+ */
+static int
+snhlfe_del (zebra_snhlfe_t *snhlfe)
+{
+  zebra_slsp_t *slsp;
+
+  if (!snhlfe)
+    return -1;
+
+  slsp = snhlfe->slsp;
+  if (!slsp)
+    return -1;
+
+  if (snhlfe->next)
+    snhlfe->next->prev = snhlfe->prev;
+  if (snhlfe->prev)
+    snhlfe->prev->next = snhlfe->next;
+  else
+    slsp->snhlfe_list = snhlfe->next;
+
+  snhlfe->prev = snhlfe->next = NULL;
+  if (snhlfe->ifname)
+    XFREE (MTYPE_SNHLFE_IFNAME, snhlfe->ifname);
+  XFREE (MTYPE_SNHLFE, snhlfe);
+
+  return 0;
+}
+
+/*
+ * Delete all static NHLFE entries for this LSP (in label).
+ */
+static int
+snhlfe_del_all (zebra_slsp_t *slsp)
+{
+  zebra_snhlfe_t *snhlfe, *snhlfe_next;
+
+  if (!slsp)
+    return -1;
+
+  for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe_next)
+    {
+      snhlfe_next = snhlfe->next;
+      snhlfe_del (snhlfe);
+    }
+
+  return 0;
+}
+
+/*
+ * Create printable string for NHLFE configuration.
+ */
+static char *
+snhlfe2str (zebra_snhlfe_t *snhlfe, char *buf, int size)
+{
+  buf[0] = '\0';
+  switch (snhlfe->gtype)
+    {
+      case NEXTHOP_TYPE_IPV4:
+        inet_ntop (AF_INET, &snhlfe->gate.ipv4, buf, size);
+        break;
+      case NEXTHOP_TYPE_IPV6:
+      case NEXTHOP_TYPE_IPV6_IFINDEX:
+        inet_ntop (AF_INET6, &snhlfe->gate.ipv6, buf, size);
+        if (snhlfe->ifindex)
+          strcat (buf, ifindex2ifname (snhlfe->ifindex, VRF_DEFAULT));
+        break;
+      default:
+        break;
+    }
+
+  return buf;
+}
+
+/*
+ * Initialize work queue for processing changed LSPs.
+ */
+static void
+mpls_processq_init (struct zebra_t *zebra)
+{
+  zebra->lsp_process_q = work_queue_new (zebra->master, "LSP processing");
+  if (!zebra->lsp_process_q)
+    {
+      zlog_err ("%s: could not initialise work queue!", __func__);
+      return;
+    }
+
+  zebra->lsp_process_q->spec.workfunc = &lsp_process;
+  zebra->lsp_process_q->spec.del_item_data = &lsp_processq_del;
+  zebra->lsp_process_q->spec.errorfunc = NULL;
+  zebra->lsp_process_q->spec.completion_func = &lsp_processq_complete;
+  zebra->lsp_process_q->spec.max_retries = 0;
+  zebra->lsp_process_q->spec.hold = 10;
+}
+
+
+
+/* Public functions */
+
+/*
+ * String to label conversion, labels separated by '/'.
+ */
+int
+mpls_str2label (const char *label_str, u_int8_t *num_labels,
+                mpls_label_t *labels)
+{
+  char *endp;
+  int i;
+
+  *num_labels = 0;
+  for (i = 0; i < MPLS_MAX_LABELS; i++)
+    {
+      mpls_label_t label;
+
+      label = strtoul(label_str, &endp, 0);
+
+      /* validity checks */
+      if (endp == label_str)
+        return -1;
+
+      if (!IS_MPLS_UNRESERVED_LABEL(label))
+        return -1;
+
+      labels[i] = label;
+      if (*endp == '\0')
+        {
+          *num_labels = i + 1;
+          return 0;
+        }
+
+      /* Check separator. */
+      if (*endp != '/')
+        return -1;
+
+      label_str = endp + 1;
+    }
+
+  /* Too many labels. */
+  return -1;
+}
+
+/*
+ * Label to string conversion, labels in string separated by '/'.
+ */
+char *
+mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
+                char *buf, int len)
+{
+  buf[0] = '\0';
+  if (num_labels == 1)
+    snprintf (buf, len, "%u", labels[0]);
+  else if (num_labels == 2)
+    snprintf (buf, len, "%u/%u", labels[0], labels[1]);
+  return buf;
+}
+
+/*
+ * Install dynamic LSP entry.
+ */
+int
+zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
+{
+  struct route_table *table;
+  zebra_fec_t *fec;
+
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
+  if (!table)
+    return -1;
+
+  /* See if there is a configured label binding for this FEC. */
+  fec = fec_find (table, &rn->p);
+  if (!fec || fec->label == MPLS_INVALID_LABEL)
+    return 0;
+
+  /* We cannot install a label forwarding entry if local label is the
+   * implicit-null label.
+   */
+  if (fec->label == MPLS_IMP_NULL_LABEL)
+    return 0;
+
+  if (lsp_install (zvrf, fec->label, rn, rib))
+    return -1;
+
+  return 0;
+}
+
+/*
+ * Uninstall dynamic LSP entry, if any.
+ */
+int
+zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
+{
+  struct route_table *table;
+  zebra_fec_t *fec;
+
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
+  if (!table)
+    return -1;
+
+  /* See if there is a configured label binding for this FEC. */
+  fec = fec_find (table, &rn->p);
+  if (!fec || fec->label == MPLS_INVALID_LABEL)
+    return 0;
+
+  /* Uninstall always removes all dynamic NHLFEs. */
+  return lsp_uninstall (zvrf, fec->label);
+}
+
+/*
+ * Registration from a client for the label binding for a FEC. If a binding
+ * already exists, it is informed to the client.
+ * NOTE: If there is a manually configured label binding, that is used.
+ * Otherwise, if aa label index is specified, it means we have to allocate the
+ * label from a locally configured label block (SRGB), if one exists and index
+ * is acceptable.
+ */
+int
+zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
+                         u_int32_t label_index, struct zserv *client)
+{
+  struct route_table *table;
+  zebra_fec_t *fec;
+  char buf[BUFSIZ];
+  int new_client;
+  int label_change = 0;
+  u_int32_t old_label;
+
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+  if (!table)
+    return -1;
+
+  if (IS_ZEBRA_DEBUG_MPLS)
+    prefix2str(p, buf, BUFSIZ);
+
+  /* Locate FEC */
+  fec = fec_find (table, p);
+  if (!fec)
+    {
+      fec = fec_add (table, p, MPLS_INVALID_LABEL, 0, label_index);
+      if (!fec)
+        {
+          prefix2str(p, buf, BUFSIZ);
+          zlog_err("Failed to add FEC %s upon register, client %s",
+                   buf, zebra_route_string(client->proto));
+          return -1;
+        }
+
+      old_label = MPLS_INVALID_LABEL;
+      new_client = 1;
+    }
+  else
+    {
+      /* Client may register same FEC with different label index. */
+      new_client = (listnode_lookup(fec->client_list, client) == NULL);
+      if (!new_client && fec->label_index == label_index)
+        /* Duplicate register */
+        return 0;
+
+      /* Save current label, update label index */
+      old_label = fec->label;
+      fec->label_index = label_index;
+    }
+
+  if (new_client)
+    listnode_add (fec->client_list, client);
+
+  if (IS_ZEBRA_DEBUG_MPLS)
+    zlog_debug("FEC %s Label Index %u %s by client %s",
+                buf, label_index, new_client ? "registered" : "updated",
+                zebra_route_string(client->proto));
+
+  /* If not a configured FEC, derive the local label (from label index)
+   * or reset it.
+   */
+  if (!(fec->flags & FEC_FLAG_CONFIGURED))
+    {
+      fec_derive_label_from_index (zvrf, fec);
+
+      /* If no label change, exit. */
+      if (fec->label == old_label)
+        return 0;
+
+      label_change = 1;
+    }
+
+  /* If new client or label change, update client and install or uninstall
+   * label forwarding entry as needed.
+   */
+  /* Inform client of label, if needed. */
+  if ((new_client && fec->label != MPLS_INVALID_LABEL) ||
+      label_change)
+    {
+      if (IS_ZEBRA_DEBUG_MPLS)
+        zlog_debug ("Update client label %u", fec->label);
+      fec_send (fec, client);
+    }
+
+  if (new_client || label_change)
+    return fec_change_update_lsp (zvrf, fec, old_label);
+
+  return 0;
+}
+
+/*
+ * Deregistration from a client for the label binding for a FEC. The FEC
+ * itself is deleted if no other registered clients exist and there is no
+ * label bound to the FEC.
+ */
+int
+zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
+                           struct zserv *client)
+{
+  struct route_table *table;
+  zebra_fec_t *fec;
+  char buf[BUFSIZ];
+
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+  if (!table)
+    return -1;
+
+  if (IS_ZEBRA_DEBUG_MPLS)
+    prefix2str(p, buf, BUFSIZ);
+
+  fec = fec_find (table, p);
+  if (!fec)
+    {
+      prefix2str(p, buf, BUFSIZ);
+      zlog_err("Failed to find FEC %s upon unregister, client %s",
+               buf, zebra_route_string(client->proto));
+      return -1;
+    }
+
+  listnode_delete(fec->client_list, client);
+
+  if (IS_ZEBRA_DEBUG_MPLS)
+    zlog_debug("FEC %s unregistered by client %s",
+                buf, zebra_route_string(client->proto));
+
+  /* If not a configured entry, delete the FEC if no other clients. Before
+   * deleting, see if any LSP needs to be uninstalled.
+   */
+  if (!(fec->flags & FEC_FLAG_CONFIGURED) &&
+      list_isempty(fec->client_list))
+    {
+      mpls_label_t old_label = fec->label;
+      fec->label = MPLS_INVALID_LABEL; /* reset */
+      fec_change_update_lsp (zvrf, fec, old_label);
+      fec_del (fec);
+    }
+
+  return 0;
 }
 
 /*
- * Locate static NHLFE that matches with passed info.
+ * Cleanup any FECs registered by this client.
  */
-static zebra_snhlfe_t *
-snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
-             union g_addr *gate, char *ifname, ifindex_t ifindex)
+int
+zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client)
 {
-  zebra_snhlfe_t *snhlfe;
-
-  if (!slsp)
-    return NULL;
+  struct route_node *rn;
+  zebra_fec_t *fec;
+  struct listnode *node;
+  struct zserv *fec_client;
+  int af;
 
-  for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next)
+  for (af = AFI_IP; af < AFI_MAX; af++)
     {
-      if (!snhlfe_match (snhlfe, gtype, gate, ifname, ifindex))
-        break;
+      if (zvrf->fec_table[af] == NULL)
+        continue;
+
+      for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+        {
+          fec = rn->info;
+          if (!fec || list_isempty(fec->client_list))
+            continue;
+
+          for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, fec_client))
+            {
+              if (fec_client == client)
+                {
+                  listnode_delete(fec->client_list, fec_client);
+                  if (!(fec->flags & FEC_FLAG_CONFIGURED) &&
+                      list_isempty(fec->client_list))
+                    fec_del (fec);
+                  break;
+                }
+            }
+        }
     }
 
-  return snhlfe;
+  return 0;
 }
 
-
 /*
- * Add static NHLFE. Base LSP config entry must have been created
- * and duplicate check done.
+ * Return FEC (if any) to which this label is bound.
+ * Note: Only works for per-prefix binding and when the label is not
+ * implicit-null.
+ * TODO: Currently walks entire table, can optimize later with another
+ * hash..
  */
-static zebra_snhlfe_t *
-snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
-            union g_addr *gate, char *ifname, ifindex_t ifindex,
-            mpls_label_t out_label)
+zebra_fec_t *
+zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label)
 {
-  zebra_snhlfe_t *snhlfe;
-
-  if (!slsp)
-    return NULL;
+  struct route_node *rn;
+  zebra_fec_t *fec;
+  int af;
 
-  snhlfe = XCALLOC(MTYPE_SNHLFE, sizeof(zebra_snhlfe_t));
-  snhlfe->slsp = slsp;
-  snhlfe->out_label = out_label;
-  snhlfe->gtype = gtype;
-  switch (gtype)
+  for (af = AFI_IP; af < AFI_MAX; af++)
     {
-    case NEXTHOP_TYPE_IPV4:
-      snhlfe->gate.ipv4 = gate->ipv4;
-      break;
-    case NEXTHOP_TYPE_IPV6:
-    case NEXTHOP_TYPE_IPV6_IFINDEX:
-      snhlfe->gate.ipv6 = gate->ipv6;
-      if (ifindex)
-        snhlfe->ifindex = ifindex;
-      break;
-    default:
-      XFREE (MTYPE_SNHLFE, snhlfe);
-      return NULL;
-    }
+      if (zvrf->fec_table[af] == NULL)
+        continue;
 
-  if (slsp->snhlfe_list)
-    slsp->snhlfe_list->prev = snhlfe;
-  snhlfe->next = slsp->snhlfe_list;
-  slsp->snhlfe_list = snhlfe;
+      for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+        {
+          if (!rn->info)
+            continue;
+          fec = rn->info;
+          if (fec->label == label)
+            return fec;
+        }
+    }
 
-  return snhlfe;
+  return NULL;
 }
 
 /*
- * Delete static NHLFE. Entry must be present on list.
+ * Inform if specified label is currently bound to a FEC or not.
  */
-static int
-snhlfe_del (zebra_snhlfe_t *snhlfe)
+int
+zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label)
 {
-  zebra_slsp_t *slsp;
+  return (zebra_mpls_fec_for_label (zvrf, label) ? 1 : 0);
+}
 
-  if (!snhlfe)
-    return -1;
+/*
+ * Add static FEC to label binding. If there are clients registered for this
+ * FEC, notify them. If there are labeled routes for this FEC, install the
+ * label forwarding entry.
+*/
+int
+zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
+                           mpls_label_t in_label)
+{
+  struct route_table *table;
+  zebra_fec_t *fec;
+  char buf[BUFSIZ];
+  mpls_label_t old_label;
+  int ret = 0;
 
-  slsp = snhlfe->slsp;
-  if (!slsp)
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+  if (!table)
     return -1;
 
-  if (snhlfe->next)
-    snhlfe->next->prev = snhlfe->prev;
-  if (snhlfe->prev)
-    snhlfe->prev->next = snhlfe->next;
+  if (IS_ZEBRA_DEBUG_MPLS)
+    prefix2str(p, buf, BUFSIZ);
+
+  /* Update existing FEC or create a new one. */
+  fec = fec_find (table, p);
+  if (!fec)
+    {
+      fec = fec_add (table, p, in_label, FEC_FLAG_CONFIGURED,
+                     MPLS_INVALID_LABEL_INDEX);
+      if (!fec)
+        {
+          prefix2str(p, buf, BUFSIZ);
+          zlog_err ("Failed to add FEC %s upon config", buf);
+          return -1;
+        }
+
+      if (IS_ZEBRA_DEBUG_MPLS)
+        zlog_debug ("Add fec %s label %u", buf, in_label);
+    }
   else
-    slsp->snhlfe_list = snhlfe->next;
+    {
+      fec->flags |= FEC_FLAG_CONFIGURED;
+      if (fec->label == in_label)
+        /* Duplicate config */
+        return 0;
 
-  snhlfe->prev = snhlfe->next = NULL;
-  if (snhlfe->ifname)
-    XFREE (MTYPE_SNHLFE_IFNAME, snhlfe->ifname);
-  XFREE (MTYPE_SNHLFE, snhlfe);
+      /* Label change, update clients. */
+      old_label = fec->label;
+      if (IS_ZEBRA_DEBUG_MPLS)
+        zlog_debug ("Update fec %s new label %u", buf, in_label);
 
-  return 0;
+      fec->label = in_label;
+      fec_update_clients (fec);
+
+      /* Update label forwarding entries appropriately */
+      ret = fec_change_update_lsp (zvrf, fec, old_label);
+    }
+
+  return ret;
 }
 
 /*
- * Delete all static NHLFE entries for this LSP (in label).
+ * Remove static FEC to label binding. If there are no clients registered
+ * for this FEC, delete the FEC; else notify clients
+ * Note: Upon delete of static binding, if label index exists for this FEC,
+ * client may need to be updated with derived label.
  */
-static int
-snhlfe_del_all (zebra_slsp_t *slsp)
+int
+zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
 {
-  zebra_snhlfe_t *snhlfe, *snhlfe_next;
+  struct route_table *table;
+  zebra_fec_t *fec;
+  mpls_label_t old_label;
+  char buf[BUFSIZ];
 
-  if (!slsp)
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+  if (!table)
     return -1;
 
-  for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe_next)
+  fec = fec_find (table, p);
+  if (!fec)
     {
-      snhlfe_next = snhlfe->next;
-      snhlfe_del (snhlfe);
+      prefix2str(p, buf, BUFSIZ);
+      zlog_err("Failed to find FEC %s upon delete", buf);
+      return -1;
     }
 
-  return 0;
-}
+  if (IS_ZEBRA_DEBUG_MPLS)
+    {
+      prefix2str(p, buf, BUFSIZ);
+      zlog_debug ("Delete fec %s label index %u",
+                  buf, fec->label_index);
+    }
 
-/*
- * Create printable string for NHLFE configuration.
- */
-static char *
-snhlfe2str (zebra_snhlfe_t *snhlfe, char *buf, int size)
-{
-  buf[0] = '\0';
-  switch (snhlfe->gtype)
+  old_label = fec->label;
+  fec->flags &= ~FEC_FLAG_CONFIGURED;
+  fec->label = MPLS_INVALID_LABEL;
+
+  /* If no client exists, just delete the FEC. */
+  if (list_isempty(fec->client_list))
     {
-      case NEXTHOP_TYPE_IPV4:
-        inet_ntop (AF_INET, &snhlfe->gate.ipv4, buf, size);
-        break;
-      case NEXTHOP_TYPE_IPV6:
-      case NEXTHOP_TYPE_IPV6_IFINDEX:
-        inet_ntop (AF_INET6, &snhlfe->gate.ipv6, buf, size);
-        if (snhlfe->ifindex)
-          strcat (buf, ifindex2ifname (snhlfe->ifindex, VRF_DEFAULT));
-        break;
-      default:
-        break;
+      fec_del (fec);
+      return 0;
     }
 
-  return buf;
+  /* Derive the local label (from label index) or reset it. */
+  fec_derive_label_from_index (zvrf, fec);
+  /* If there is a label change, update clients. */
+  if (fec->label == old_label)
+    return 0;
+  fec_update_clients (fec);
+
+  /* Update label forwarding entries appropriately */
+  return fec_change_update_lsp (zvrf, fec, old_label);
 }
 
 /*
- * Initialize work queue for processing changed LSPs.
+ * Display MPLS FEC to label binding configuration (VTY command handler).
  */
-static void
-mpls_processq_init (struct zebra_t *zebra)
+int
+zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf)
 {
-  zebra->lsp_process_q = work_queue_new (zebra->master, "LSP processing");
-  if (!zebra->lsp_process_q)
+  struct route_node *rn;
+  int af;
+  zebra_fec_t *fec;
+  char buf[BUFSIZ];
+  int write = 0;
+
+  for (af = AFI_IP; af < AFI_MAX; af++)
     {
-      zlog_err ("%s: could not initialise work queue!", __func__);
-      return;
-    }
+      if (zvrf->fec_table[af] == NULL)
+        continue;
 
-  zebra->lsp_process_q->spec.workfunc = &lsp_process;
-  zebra->lsp_process_q->spec.del_item_data = &lsp_processq_del;
-  zebra->lsp_process_q->spec.errorfunc = NULL;
-  zebra->lsp_process_q->spec.completion_func = &lsp_processq_complete;
-  zebra->lsp_process_q->spec.max_retries = 0;
-  zebra->lsp_process_q->spec.hold = 10;
-}
+      for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+        {
+          if (!rn->info)
+            continue;
 
+          char lstr[BUFSIZ];
+          fec = rn->info;
 
+          if (!(fec->flags & FEC_FLAG_CONFIGURED))
+            continue;
 
-/* Public functions */
+          write = 1;
+          prefix2str(&rn->p, buf, BUFSIZ);
+          vty_out(vty, "mpls label bind %s %s%s", buf,
+                  label2str(fec->label, lstr, BUFSIZ), VTY_NEWLINE);
+        }
+    }
+
+  return write;
+}
 
 /*
- * String to label conversion, labels separated by '/'.
+ * Display MPLS FEC to label binding (VTY command handler).
  */
-int
-mpls_str2label (const char *label_str, u_int8_t *num_labels,
-                mpls_label_t *labels)
+void
+zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf)
 {
-  char *endp;
-  int i;
+  struct route_node *rn;
+  int af;
 
-  *num_labels = 0;
-  for (i = 0; i < MPLS_MAX_LABELS; i++)
+  for (af = AFI_IP; af < AFI_MAX; af++)
     {
-      u_int32_t label;
-
-      label = strtoul(label_str, &endp, 0);
-
-      /* validity checks */
-      if (endp == label_str)
-        return -1;
-
-      if (!IS_MPLS_UNRESERVED_LABEL(label))
-        return -1;
+      if (zvrf->fec_table[af] == NULL)
+        continue;
 
-      labels[i] = label;
-      if (*endp == '\0')
+      for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
         {
-          *num_labels = i + 1;
-          return 0;
+          if (!rn->info)
+            continue;
+          fec_print (rn->info, vty);
         }
-
-      /* Check separator. */
-      if (*endp != '/')
-        return -1;
-
-      label_str = endp + 1;
     }
-
-  /* Too many labels. */
-  return -1;
 }
 
 /*
- * Label to string conversion, labels in string separated by '/'.
+ * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
  */
-char *
-mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
-                char *buf, int len)
+void
+zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p)
 {
-  buf[0] = '\0';
-  if (num_labels == 1)
-    snprintf (buf, len, "%u", labels[0]);
-  else if (num_labels == 2)
-    snprintf (buf, len, "%u/%u", labels[0], labels[1]);
-  return buf;
+  struct route_table *table;
+  struct route_node *rn;
+
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+  if (!table)
+    return;
+
+  apply_mask (p);
+  rn = route_node_lookup(table, p);
+  if (!rn)
+    return;
+
+  route_unlock_node(rn);
+  if (!rn->info)
+    return;
+
+  fec_print (rn->info, vty);
 }
 
 /*
@@ -1361,7 +2343,7 @@ int
 mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
                  mpls_label_t in_label, mpls_label_t out_label,
                  enum nexthop_types_t gtype, union g_addr *gate,
-                 char *ifname, ifindex_t ifindex)
+                 ifindex_t ifindex)
 {
   struct hash *lsp_table;
   zebra_ile_t tmp_ile;
@@ -1379,7 +2361,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
   lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc);
   if (!lsp)
     return -1;
-  nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex);
+  nhlfe = nhlfe_find (lsp, type, gtype, gate, ifindex);
   if (nhlfe)
     {
       struct nexthop *nh = nhlfe->nexthop;
@@ -1408,8 +2390,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
   else
     {
       /* Add LSP entry to this nexthop */
-      nhlfe = nhlfe_add (lsp, type, gtype, gate,
-                         ifname, ifindex, out_label);
+      nhlfe = nhlfe_add (lsp, type, gtype, gate, ifindex, out_label);
       if (!nhlfe)
         return -1;
 
@@ -1438,7 +2419,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
 int
 mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
                    mpls_label_t in_label, enum nexthop_types_t gtype,
-                   union g_addr *gate, char *ifname, ifindex_t ifindex)
+                   union g_addr *gate, ifindex_t ifindex)
 {
   struct hash *lsp_table;
   zebra_ile_t tmp_ile;
@@ -1456,7 +2437,7 @@ mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
   lsp = hash_lookup (lsp_table, &tmp_ile);
   if (!lsp)
     return 0;
-  nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex);
+  nhlfe = nhlfe_find (lsp, type, gtype, gate, ifindex);
   if (!nhlfe)
     return 0;
 
@@ -1561,7 +2542,7 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi)
 int
 zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
                      mpls_label_t out_label, enum nexthop_types_t gtype,
-                     union g_addr *gate, char *ifname, ifindex_t ifindex)
+                     union g_addr *gate, ifindex_t ifindex)
 {
   struct hash *slsp_table;
   zebra_ile_t tmp_ile;
@@ -1579,7 +2560,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
   if (!slsp)
     return 1;
 
-  snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
+  snhlfe = snhlfe_find (slsp, gtype, gate, ifindex);
   if (snhlfe)
     {
       if (snhlfe->out_label == out_label)
@@ -1619,7 +2600,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
 int
 zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
                      mpls_label_t out_label, enum nexthop_types_t gtype,
-                     union g_addr *gate, char *ifname, ifindex_t ifindex)
+                     union g_addr *gate, ifindex_t ifindex)
 {
   struct hash *slsp_table;
   zebra_ile_t tmp_ile;
@@ -1637,7 +2618,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
   slsp = hash_get (slsp_table, &tmp_ile, slsp_alloc);
   if (!slsp)
     return -1;
-  snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
+  snhlfe = snhlfe_find (slsp, gtype, gate, ifindex);
   if (snhlfe)
     {
       if (snhlfe->out_label == out_label)
@@ -1656,7 +2637,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
   else
     {
       /* Add static LSP entry to this nexthop */
-      snhlfe = snhlfe_add (slsp, gtype, gate, ifname, ifindex, out_label);
+      snhlfe = snhlfe_add (slsp, gtype, gate, ifindex, out_label);
       if (!snhlfe)
         return -1;
 
@@ -1670,7 +2651,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
 
   /* (Re)Install LSP in the main table. */
   if (mpls_lsp_install (zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype,
-      gate, ifname, ifindex))
+      gate, ifindex))
     return -1;
 
   return 0;
@@ -1686,7 +2667,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
 int
 zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
                            enum nexthop_types_t gtype, union g_addr *gate,
-                           char *ifname, ifindex_t ifindex)
+                           ifindex_t ifindex)
 {
   struct hash *slsp_table;
   zebra_ile_t tmp_ile;
@@ -1719,7 +2700,7 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
   else
     {
       /* Find specific NHLFE, exit if not found. */
-      snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
+      snhlfe = snhlfe_find (slsp, gtype, gate, ifindex);
       if (!snhlfe)
         return 0;
 
@@ -1733,7 +2714,7 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
 
       /* Uninstall LSP from the main table. */
       mpls_lsp_uninstall (zvrf, ZEBRA_LSP_STATIC, in_label, gtype, gate,
-                         ifname, ifindex);
+                         ifindex);
 
       /* Delete static LSP NHLFE */
       snhlfe_del (snhlfe);
@@ -1901,6 +2882,51 @@ zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
   return (zvrf->slsp_table->count ? 1 : 0);
 }
 
+/*
+ * Add/update global label block.
+ */
+int
+zebra_mpls_label_block_add (struct zebra_vrf *zvrf, u_int32_t start_label,
+                            u_int32_t end_label)
+{
+  zvrf->mpls_srgb.start_label = start_label;
+  zvrf->mpls_srgb.end_label = end_label;
+
+  /* Evaluate registered FECs to see if any get a label or not. */
+  fec_evaluate (zvrf, 1);
+  return 0;
+}
+
+/*
+ * Delete global label block.
+ */
+int
+zebra_mpls_label_block_del (struct zebra_vrf *zvrf)
+{
+  zvrf->mpls_srgb.start_label = 0;
+  zvrf->mpls_srgb.end_label = 0;
+
+  /* Process registered FECs to clear their local label, if needed. */
+  fec_evaluate (zvrf, 0);
+  return 0;
+}
+
+/*
+ * Display MPLS global label block configuration (VTY command handler).
+ */
+int
+zebra_mpls_write_label_block_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+  if (zvrf->mpls_srgb.start_label == 0)
+    return 0;
+
+  vty_out(vty, "mpls label global-block %u %u%s",
+          zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label,
+          VTY_NEWLINE);
+
+  return 1;
+}
+
 /*
  * Called upon process exiting, need to delete LSP forwarding
  * entries from the kernel.
@@ -1927,7 +2953,11 @@ zebra_mpls_init_tables (struct zebra_vrf *zvrf)
     return;
   zvrf->slsp_table = hash_create(label_hash, label_cmp);
   zvrf->lsp_table = hash_create(label_hash, label_cmp);
+  zvrf->fec_table[AFI_IP] = route_table_init();
+  zvrf->fec_table[AFI_IP6] = route_table_init();
   zvrf->mpls_flags = 0;
+  zvrf->mpls_srgb.start_label = 0;
+  zvrf->mpls_srgb.end_label = 0;
 }
 
 /*
index a871fac6519b08bb6ca28ba1c194d3fc97c250f2..e271edd2eb4c78f5a89febb47740b73b7b30bba9 100644 (file)
@@ -52,6 +52,7 @@ typedef struct zebra_snhlfe_t_ zebra_snhlfe_t;
 typedef struct zebra_slsp_t_ zebra_slsp_t;
 typedef struct zebra_nhlfe_t_ zebra_nhlfe_t;
 typedef struct zebra_lsp_t_ zebra_lsp_t;
+typedef struct zebra_fec_t_ zebra_fec_t;
 
 /*
  * (Outgoing) nexthop label forwarding entry configuration
@@ -147,6 +148,27 @@ struct zebra_lsp_t_
   u_char addr_family;
 };
 
+/*
+ * FEC to label binding.
+ */
+struct zebra_fec_t_
+{
+  /* FEC (prefix) */
+  struct route_node *rn;
+
+  /* In-label - either statically bound or derived from label block. */
+  mpls_label_t label;
+
+  /* Label index (into global label block), if valid */
+  u_int32_t label_index;
+
+  /* Flags. */
+  u_int32_t flags;
+#define FEC_FLAG_CONFIGURED       (1 << 0)
+
+  /* Clients interested in this FEC. */
+  struct list *client_list;
+};
 
 /* Function declarations. */
 
@@ -164,6 +186,116 @@ char *
 mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
                 char *buf, int len);
 
+/*
+ * Add/update global label block.
+ */
+int
+zebra_mpls_label_block_add (struct zebra_vrf *zvrf, u_int32_t start_label,
+                            u_int32_t end_label);
+
+/*
+ * Delete global label block.
+ */
+int
+zebra_mpls_label_block_del (struct zebra_vrf *vrf);
+
+/*
+ * Display MPLS global label block configuration (VTY command handler).
+ */
+int
+zebra_mpls_write_label_block_config (struct vty *vty, struct zebra_vrf *vrf);
+
+/*
+ * Install dynamic LSP entry.
+ */
+int
+zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib);
+
+/*
+ * Uninstall dynamic LSP entry, if any. 
+ */
+int
+zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib);
+
+/*
+ * Registration from a client for the label binding for a FEC. If a binding
+ * already exists, it is informed to the client.
+ * NOTE: If there is a manually configured label binding, that is used.
+ * Otherwise, if aa label index is specified, it means we have to allocate the
+ * label from a locally configured label block (SRGB), if one exists and index
+ * is acceptable.
+ */
+int
+zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
+                         u_int32_t label_index, struct zserv *client);
+
+/*
+ * Deregistration from a client for the label binding for a FEC. The FEC
+ * itself is deleted if no other registered clients exist and there is no
+ * label bound to the FEC.
+ */
+int
+zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
+                           struct zserv *client);
+
+/*
+ * Cleanup any FECs registered by this client.
+ */
+int
+zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client);
+
+/*
+ * Return FEC (if any) to which this label is bound.
+ * Note: Only works for per-prefix binding and when the label is not
+ * implicit-null.
+ * TODO: Currently walks entire table, can optimize later with another
+ * hash..
+ */
+zebra_fec_t *
+zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label);
+
+/*
+ * Inform if specified label is currently bound to a FEC or not.
+ */
+int
+zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label);
+
+/*
+ * Add static FEC to label binding. If there are clients registered for this
+ * FEC, notify them. If there are labeled routes for this FEC, install the
+ * label forwarding entry.
+ */
+int
+zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
+                           mpls_label_t in_label);
+
+/*
+ * Remove static FEC to label binding. If there are no clients registered
+ * for this FEC, delete the FEC; else notify clients.
+ * Note: Upon delete of static binding, if label index exists for this FEC,
+ * client may need to be updated with derived label.
+ */
+int
+zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p);
+
+/*
+ * Display MPLS FEC to label binding configuration (VTY command handler).
+ */
+int
+zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf);
+
+/*
+ * Display MPLS FEC to label binding (VTY command handler).
+ */
+void
+zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf);
+
+/*
+ * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
+ */
+void
+zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p);
+
 /*
  * Install/uninstall a FEC-To-NHLFE (FTN) binding.
  */
@@ -182,7 +314,7 @@ int
 mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
                  mpls_label_t in_label, mpls_label_t out_label,
                  enum nexthop_types_t gtype, union g_addr *gate,
-                 char *ifname, ifindex_t ifindex);
+                 ifindex_t ifindex);
 
 /*
  * Uninstall a particular NHLFE in the forwarding table. If this is
@@ -191,7 +323,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
 int
 mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
                    mpls_label_t in_label, enum nexthop_types_t gtype,
-                   union g_addr *gate, char *ifname, ifindex_t ifindex);
+                   union g_addr *gate, ifindex_t ifindex);
 
 /*
  * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
@@ -216,7 +348,7 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi);
 int
 zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
                      mpls_label_t out_label, enum nexthop_types_t gtype,
-                     union g_addr *gate, char *ifname, ifindex_t ifindex);
+                     union g_addr *gate, ifindex_t ifindex);
 #endif /* HAVE_CUMULUS */
 
 /*
@@ -229,7 +361,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
 int
 zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
                      mpls_label_t out_label, enum nexthop_types_t gtype,
-                     union g_addr *gate, char *ifname, ifindex_t ifindex);
+                     union g_addr *gate, ifindex_t ifindex);
 
 /*
  * Delete static LSP entry. This may be the delete of one particular
@@ -241,7 +373,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
 int
 zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
                            enum nexthop_types_t gtype, union g_addr *gate,
-                           char *ifname, ifindex_t ifindex);
+                           ifindex_t ifindex);
 
 /*
  * Schedule all MPLS label forwarding entries for processing.
@@ -324,6 +456,8 @@ lsp_type_from_rib_type (int rib_type)
     {
       case ZEBRA_ROUTE_STATIC:
         return ZEBRA_LSP_STATIC;
+      case ZEBRA_ROUTE_BGP:
+        return ZEBRA_LSP_BGP;
       default:
         return ZEBRA_LSP_NONE;
     }
@@ -339,6 +473,8 @@ nhlfe_type2str(enum lsp_types_t lsp_type)
         return "Static";
       case ZEBRA_LSP_LDP:
         return "LDP";
+      case ZEBRA_LSP_BGP:
+        return "BGP";
       default:
         return "Unknown";
     }
index 23f5e72956415a345ef48aa2a6810ffb7fe38162..168c8d003c28572780e39128c2ecc8df47e0f803 100644 (file)
@@ -27,3 +27,209 @@ int kernel_add_lsp (zebra_lsp_t *lsp) { return 0; }
 int kernel_upd_lsp (zebra_lsp_t *lsp) { return 0; }
 int kernel_del_lsp (zebra_lsp_t *lsp) { return 0; }
 int mpls_kernel_init (void) { return -1; };
+
+int mpls_enabled;
+
+char *
+mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
+                char *buf, int len)
+{
+  return NULL;
+}
+
+int
+mpls_str2label (const char *label_str, u_int8_t *num_labels,
+                mpls_label_t *labels)
+{
+  return 0;
+}
+
+int
+zebra_mpls_label_block_add (struct zebra_vrf *vrf, u_int32_t start_label,
+                            u_int32_t end_label)
+{
+  return 0;
+}
+
+int
+zebra_mpls_label_block_del (struct zebra_vrf *zvrf)
+{
+  return 0;
+}
+
+int
+zebra_mpls_write_label_block_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+  return 0;
+}
+
+int
+zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
+{
+  return 0;
+}
+
+int
+zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
+{
+  return 0;
+}
+
+void
+zebra_mpls_init_tables (struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_print_lsp (struct vty *vty, struct zebra_vrf *zvrf, mpls_label_t label,
+                      u_char use_json)
+{
+}
+
+void
+zebra_mpls_print_lsp_table (struct vty *vty, struct zebra_vrf *zvrf,
+                            u_char use_json)
+{
+}
+
+int
+zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+  return 0;
+}
+
+#ifdef HAVE_CUMULUS
+int
+zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
+                                 mpls_label_t out_label, enum nexthop_types_t gtype,
+                                 union g_addr *gate, ifindex_t ifindex)
+{
+  return 0;
+}
+#endif
+
+int
+zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
+                           mpls_label_t out_label, enum nexthop_types_t gtype,
+                           union g_addr *gate, ifindex_t ifindex)
+{
+  return 0;
+}
+
+int
+zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
+                           enum nexthop_types_t gtype, union g_addr *gate,
+                           ifindex_t ifindex)
+{
+  return 0;
+}
+
+void
+zebra_mpls_lsp_schedule (struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_close_tables (struct zebra_vrf *zvrf)
+{
+}
+
+zebra_fec_t *
+zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+  return NULL;
+}
+
+int
+zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+  return 0;
+}
+
+int
+zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
+                           mpls_label_t in_label)
+{
+  return 0;
+}
+
+int
+zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
+{
+  return 0;
+}
+
+int
+zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+  return 0;
+}
+
+void
+zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p)
+{
+}
+
+int
+zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
+                         u_int32_t label_index, struct zserv *client)
+{
+  return 0;
+}
+
+int
+zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
+                           struct zserv *client)
+{
+  return 0;
+}
+
+int
+zebra_mpls_cleanup_fecs_for_client (struct zebra_vrf *zvrf, struct zserv *client)
+{
+  return 0;
+}
+
+void mpls_ldp_lsp_uninstall_all (struct hash_backet *backet, void *ctxt)
+{
+  return;
+}
+
+void mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi)
+{
+  return;
+}
+
+void zebra_mpls_init (void)
+{
+  return;
+}
+
+int mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
+              mpls_label_t in_label, mpls_label_t out_label,
+              enum nexthop_types_t gtype, union g_addr *gate,
+              ifindex_t ifindex)
+{
+  return 0;
+}
+
+int mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
+                 mpls_label_t in_label, enum nexthop_types_t gtype,
+                 union g_addr *gate, ifindex_t ifindex)
+{
+  return 0;
+}
+
+int mpls_ftn_update (int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
+              struct prefix *prefix, enum nexthop_types_t gtype,
+              union g_addr *gate, ifindex_t ifindex, u_int8_t distance,
+              mpls_label_t out_label)
+{
+  return 0;
+}
+
index dd381723c53c3ee433aae3639e6acc7eb15a8ca8..7662cf41634d9c363913f38e3c9f45cfe371e4b9 100644 (file)
@@ -133,7 +133,7 @@ zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str,
 #if defined(HAVE_CUMULUS)
       /* Check that label value is consistent. */
       if (!zebra_mpls_lsp_label_consistent (zvrf, in_label, out_label, gtype,
-                                            &gate, NULL, 0))
+                                            &gate, 0))
         {
           vty_out (vty, "%% Label value not consistent%s",
                    VTY_NEWLINE);
@@ -142,10 +142,10 @@ zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str,
 #endif /* HAVE_CUMULUS */
 
       ret = zebra_mpls_static_lsp_add (zvrf, in_label, out_label, gtype,
-                                       &gate, NULL, 0);
+                                       &gate, 0);
     }
   else
-    ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, NULL, 0);
+    ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, 0);
 
   if (ret)
     {
@@ -209,6 +209,109 @@ DEFUN (no_mpls_transit_lsp_all,
   return zebra_mpls_transit_lsp (vty, 0, argv[3]->arg, NULL, NULL, NULL);
 }
 
+static int
+zebra_mpls_bind (struct vty *vty, int add_cmd, const char *prefix,
+                const char *label_str)
+{
+  struct zebra_vrf *zvrf;
+  struct prefix p;
+  u_int32_t label;
+  int ret;
+
+  zvrf = vrf_info_lookup(VRF_DEFAULT);
+  if (!zvrf)
+    {
+      vty_out (vty, "%% Default VRF does not exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  memset(&p, 0, sizeof(struct prefix));
+  ret = str2prefix(prefix, &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (add_cmd)
+    {
+      if (!label_str)
+        {
+          vty_out (vty, "%% No label binding specified%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+
+      if (!strcmp(label_str, "implicit-null"))
+        label = MPLS_IMP_NULL_LABEL;
+      else if (!strcmp(label_str, "explicit-null"))
+        {
+          if (p.family == AF_INET)
+            label = MPLS_V4_EXP_NULL_LABEL;
+          else
+            label = MPLS_V6_EXP_NULL_LABEL;
+        }
+      else
+        {
+          label = atoi(label_str);
+          if (!IS_MPLS_UNRESERVED_LABEL(label))
+            {
+              vty_out (vty, "%% Invalid label%s", VTY_NEWLINE);
+              return CMD_WARNING;
+            }
+          if (zebra_mpls_label_already_bound (zvrf, label))
+            {
+              vty_out (vty, "%% Label already bound to a FEC%s",
+                       VTY_NEWLINE);
+              return CMD_WARNING;
+            }
+        }
+
+      ret = zebra_mpls_static_fec_add (zvrf, &p, label);
+    }
+  else
+    ret = zebra_mpls_static_fec_del (zvrf, &p);
+
+  if (ret)
+    {
+      vty_out (vty, "%% FEC to label binding cannot be %s%s",
+               add_cmd ? "added" : "deleted", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (mpls_label_bind,
+       mpls_label_bind_cmd,
+       "mpls label bind <A.B.C.D/M|X:X::X:X/M> <(16-1048575)|implicit-null|explicit-null>",
+       MPLS_STR
+       "Label configuration\n"
+       "Establish FEC to label binding\n"
+       "IPv4 prefix\n"
+       "IPv6 prefix\n"
+       "MPLS Label to bind\n"
+       "Use Implicit-Null Label\n"
+       "Use Explicit-Null Label\n")
+{
+  return zebra_mpls_bind (vty, 1, argv[3]->arg, argv[4]->arg);
+}
+
+DEFUN (no_mpls_label_bind,
+       no_mpls_label_bind_cmd,
+       "no mpls label bind <A.B.C.D/M|X:X::X:X/M> [<(16-1048575)|implicit-null>]",
+       NO_STR
+       MPLS_STR
+       "Label configuration\n"
+       "Establish FEC to label binding\n"
+       "IPv4 prefix\n"
+       "IPv6 prefix\n"
+       "MPLS Label to bind\n"
+       "Use Implicit-Null Label\n")
+
+{
+  return zebra_mpls_bind (vty, 0, argv[4]->arg, NULL);
+}
+
 /* Static route configuration.  */
 DEFUN (ip_route_label,
        ip_route_label_cmd,
@@ -777,9 +880,45 @@ zebra_mpls_config (struct vty *vty)
     return 0;
 
   write += zebra_mpls_write_lsp_config(vty, zvrf);
+  write += zebra_mpls_write_fec_config(vty, zvrf);
+  write += zebra_mpls_write_label_block_config (vty, zvrf);
   return write;
 }
 
+DEFUN (show_mpls_fec,
+       show_mpls_fec_cmd,
+       "show mpls fec [<A.B.C.D/M|X:X::X:X/M>]",
+       SHOW_STR
+       MPLS_STR
+       "MPLS FEC table\n"
+       "FEC to display information about\n"
+       "FEC to display information about\n")
+{
+  struct zebra_vrf *zvrf;
+  struct prefix p;
+  int ret;
+
+  zvrf = vrf_info_lookup(VRF_DEFAULT);
+  if (!zvrf)
+    return 0;
+
+  if (argc == 3)
+    zebra_mpls_print_fec_table(vty, zvrf);
+  else
+    {
+      memset(&p, 0, sizeof(struct prefix));
+      ret = str2prefix(argv[3]->arg, &p);
+      if (ret <= 0)
+        {
+          vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      zebra_mpls_print_fec (vty, zvrf, &p);
+    }
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (show_mpls_table,
        show_mpls_table_cmd,
        "show mpls table [json]",
@@ -827,6 +966,85 @@ DEFUN (show_mpls_status,
   return CMD_SUCCESS;
 }
 
+static int
+zebra_mpls_global_block (struct vty *vty, int add_cmd,
+                     const char *start_label_str, const char *end_label_str)
+{
+  int ret;
+  u_int32_t start_label;
+  u_int32_t end_label;
+  struct zebra_vrf *zvrf;
+
+  zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
+  if (!zvrf)
+    {
+      vty_out (vty, "%% Default VRF does not exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (add_cmd)
+    {
+      if (!start_label_str || !end_label_str)
+        {
+          vty_out (vty, "%% Labels not specified%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+
+      start_label = atoi(start_label_str);
+      end_label = atoi(end_label_str);
+      if (!IS_MPLS_UNRESERVED_LABEL(start_label) ||
+          !IS_MPLS_UNRESERVED_LABEL(end_label))
+        {
+          vty_out (vty, "%% Invalid label%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      if (end_label < start_label)
+        {
+          vty_out (vty, "%% End label is less than Start label%s",
+                   VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+
+      ret = zebra_mpls_label_block_add (zvrf, start_label, end_label);
+    }
+  else
+    ret = zebra_mpls_label_block_del (zvrf);
+
+  if (ret)
+    {
+      vty_out (vty, "%% Global label block could not be %s%s",
+               add_cmd ? "added" : "deleted", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (mpls_label_global_block,
+       mpls_label_global_block_cmd,
+       "mpls label global-block (16-1048575) (16-1048575)",
+       MPLS_STR
+       "Label configuration\n"
+       "Configure global label block\n"
+       "Start label\n"
+       "End label\n")
+{
+  return zebra_mpls_global_block (vty, 1, argv[3]->arg, argv[4]->arg);
+}
+
+DEFUN (no_mpls_label_global_block,
+       no_mpls_label_global_block_cmd,
+       "no mpls label global-block [(16-1048575) (16-1048575)]",
+       NO_STR
+       MPLS_STR
+       "Label configuration\n"
+       "Configure global label block\n"
+       "Start label\n"
+       "End label\n")
+{
+  return zebra_mpls_global_block (vty, 0, NULL, NULL);
+}
+
 /* MPLS node for MPLS LSP. */
 static struct cmd_node mpls_node = { MPLS_NODE,  "",  1 };
 
@@ -876,7 +1094,13 @@ zebra_mpls_vty_init (void)
   install_element (CONFIG_NODE, &no_mpls_transit_lsp_cmd);
   install_element (CONFIG_NODE, &no_mpls_transit_lsp_out_label_cmd);
   install_element (CONFIG_NODE, &no_mpls_transit_lsp_all_cmd);
+  install_element (CONFIG_NODE, &mpls_label_bind_cmd);
+  install_element (CONFIG_NODE, &no_mpls_label_bind_cmd);
+
+  install_element (CONFIG_NODE, &mpls_label_global_block_cmd);
+  install_element (CONFIG_NODE, &no_mpls_label_global_block_cmd);
 
   install_element (VIEW_NODE, &show_mpls_table_cmd);
   install_element (VIEW_NODE, &show_mpls_table_lsp_cmd);
+  install_element (VIEW_NODE, &show_mpls_fec_cmd);
 }
index b3e70e46fa9eaa558a6d6e4d4c59d85e85a0835b..e4d583d5f2ae7f8eb017c0f531c37157ed439e49 100644 (file)
@@ -1084,7 +1084,25 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
   return rib->nexthop_active_num;
 }
 
+/*
+ * Is this RIB labeled-unicast? It must be of type BGP and all paths
+ * (nexthops) must have a label.
+ */
+int
+zebra_rib_labeled_unicast (struct rib *rib)
+{
+  struct nexthop *nexthop = NULL, *tnexthop;
+  int recursing;
+
+  if (rib->type != ZEBRA_ROUTE_BGP)
+    return 0;
+
+  for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
+    if (!nexthop->nh_label || !nexthop->nh_label->num_labels)
+      return 0;
 
+  return 1;
+}
 
 /* Update flag indicates whether this is a "replace" or not. Currently, this
  * is only used for IPv4.
@@ -1177,7 +1195,12 @@ rib_uninstall (struct route_node *rn, struct rib *rib)
 
       if (! RIB_SYSTEM_ROUTE (rib))
        rib_uninstall_kernel (rn, rib);
-      UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB);
+
+      /* If labeled-unicast route, uninstall transit LSP. */
+      if (zebra_rib_labeled_unicast (rib))
+        zebra_mpls_lsp_uninstall (info->zvrf, rn, rib);
+
+       UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB);
     }
 
   if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
@@ -1272,6 +1295,10 @@ rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                    zvrf_id (zvrf), buf, rn, new, new->type);
     }
 
+  /* If labeled-unicast route, install transit LSP. */
+  if (zebra_rib_labeled_unicast (new))
+    zebra_mpls_lsp_install (zvrf, rn, new);
+
   if (!RIB_SYSTEM_ROUTE (new))
     {
       if (rib_install_kernel (rn, new, NULL))
@@ -1301,6 +1328,10 @@ rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                   zvrf_id (zvrf), buf, rn, old, old->type);
     }
 
+  /* If labeled-unicast route, uninstall transit LSP. */
+  if (zebra_rib_labeled_unicast (old))
+    zebra_mpls_lsp_uninstall (zvrf, rn, old);
+
   if (!RIB_SYSTEM_ROUTE (old))
     rib_uninstall_kernel (rn, old);
 
@@ -1354,6 +1385,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
           /* Non-system route should be installed. */
           if (!RIB_SYSTEM_ROUTE (new))
             {
+              /* If labeled-unicast route, install transit LSP. */
+              if (zebra_rib_labeled_unicast (new))
+                zebra_mpls_lsp_install (zvrf, rn, new);
+
               if (rib_install_kernel (rn, new, old))
                 {
                   char buf[SRCDEST2STR_BUFFER];
@@ -1368,6 +1403,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
             {
               if (RIB_SYSTEM_ROUTE(new))
                 {
+                  /* If labeled-unicast route, uninstall transit LSP. */
+                  if (zebra_rib_labeled_unicast (old))
+                    zebra_mpls_lsp_uninstall (zvrf, rn, old);
+
                   if (!RIB_SYSTEM_ROUTE (old))
                     rib_uninstall_kernel (rn, old);
                 }
@@ -1404,6 +1443,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
                             nh_active ? "install failed" : "nexthop inactive");
             }
 
+          /* If labeled-unicast route, uninstall transit LSP. */
+          if (zebra_rib_labeled_unicast (old))
+            zebra_mpls_lsp_uninstall (zvrf, rn, old);
+
           if (!RIB_SYSTEM_ROUTE (old))
             rib_uninstall_kernel (rn, old);
           UNSET_FLAG (new->status, RIB_ENTRY_SELECTED_FIB);
@@ -2934,8 +2977,10 @@ rib_tables_iter_next (rib_tables_iter_t *iter)
   } afi_safis[] = {
     { AFI_IP, SAFI_UNICAST },
     { AFI_IP, SAFI_MULTICAST },
+    { AFI_IP, SAFI_LABELED_UNICAST },
     { AFI_IP6, SAFI_UNICAST },
     { AFI_IP6, SAFI_MULTICAST },
+    { AFI_IP6, SAFI_LABELED_UNICAST },
   };
 
   table = NULL;
index 96d631d646e7d91ace47903c59fc660fc13f8754..74c2a52171c54c8c470d91b34fce404322fdc545 100644 (file)
 
 #include <zebra/zebra_ns.h>
 
+/* MPLS (Segment Routing) global block */
+typedef struct mpls_srgb_t_
+{
+  u_int32_t start_label;
+  u_int32_t end_label;
+} mpls_srgb_t;
+
 /* Routing table instance.  */
 struct zebra_vrf
 {
@@ -79,6 +86,12 @@ struct zebra_vrf
   /* MPLS label forwarding table */
   struct hash *lsp_table;
 
+  /* MPLS FEC binding table */
+  struct route_table *fec_table[AFI_MAX];
+
+  /* MPLS Segment Routing Global block */
+  mpls_srgb_t mpls_srgb;
+
   /* MPLS processing flags */
   u_int16_t mpls_flags;
 #define MPLS_FLAG_SCHEDULE_LSPS    (1 << 0)
index 3477dc36d2ccb355295d1a099fa559e9e9502281..416e5444ea5b912d3085f6e9ca4fe3b3db44b795 100644 (file)
@@ -934,6 +934,109 @@ zserv_rnh_unregister (struct zserv *client, int sock, u_short length,
   return 0;
 }
 
+#define ZEBRA_MIN_FEC_LENGTH 9
+
+/* FEC register */
+static int
+zserv_fec_register (struct zserv *client, int sock, u_short length)
+{
+  struct stream *s;
+  struct zebra_vrf *zvrf;
+  u_short l = 0;
+  struct prefix p;
+  u_int16_t flags;
+  u_int32_t label_index = MPLS_INVALID_LABEL_INDEX;
+
+  s = client->ibuf;
+  zvrf = vrf_info_lookup(VRF_DEFAULT);
+  if (!zvrf)
+    return 0; // unexpected
+
+  /*
+   * The minimum amount of data that can be sent for one fec
+   * registration
+   */
+  if (length < ZEBRA_MIN_FEC_LENGTH)
+    {
+      zlog_err ("fec_register: Received a fec register of length %d, it is of insufficient size to properly decode",
+                length);
+      return -1;
+    }
+
+  while (l < length)
+    {
+      flags = stream_getw(s);
+      p.family = stream_getw(s);
+      if (p.family != AF_INET &&
+          p.family != AF_INET6)
+        {
+          zlog_err ("fec_register: Received unknown family type %d\n",
+                    p.family);
+          return -1;
+        }
+      p.prefixlen = stream_getc(s);
+      l += 5;
+      stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+      l += PSIZE(p.prefixlen);
+      if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX)
+        {
+          label_index = stream_getl(s);
+          l += 4;
+        }
+      zebra_mpls_fec_register (zvrf, &p, label_index, client);
+    }
+
+  return 0;
+}
+
+/* FEC unregister */
+static int
+zserv_fec_unregister (struct zserv *client, int sock, u_short length)
+{
+  struct stream *s;
+  struct zebra_vrf *zvrf;
+  u_short l = 0;
+  struct prefix p;
+  //u_int16_t flags;
+
+  s = client->ibuf;
+  zvrf = vrf_info_lookup(VRF_DEFAULT);
+  if (!zvrf)
+    return 0;  // unexpected
+
+  /*
+   * The minimum amount of data that can be sent for one
+   * fec unregistration
+   */
+  if (length < ZEBRA_MIN_FEC_LENGTH)
+    {
+      zlog_err ("fec_unregister: Received a fec unregister of length %d, it is of insufficient size to properly decode",
+                length);
+      return -1;
+    }
+
+  while (l < length)
+    {
+      //flags = stream_getw(s);
+      (void)stream_getw(s);
+      p.family = stream_getw(s);
+      if (p.family != AF_INET &&
+          p.family != AF_INET6)
+        {
+          zlog_err ("fec_unregister: Received unknown family type %d\n",
+                    p.family);
+          return -1;
+        }
+      p.prefixlen = stream_getc(s);
+      l += 5;
+      stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+      l += PSIZE(p.prefixlen);
+      zebra_mpls_fec_unregister (zvrf, &p, client);
+    }
+
+  return 0;
+}
+
 /*
   Modified version of zsend_ipv4_nexthop_lookup():
   Query unicast rib if nexthop is not found on mrib.
@@ -1075,13 +1178,15 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
   struct rib *rib;
   struct prefix p;
   u_char message;
-  struct in_addr nexthop;
+  struct in_addr nhop_addr;
   u_char nexthop_num;
   u_char nexthop_type;
   struct stream *s;
   ifindex_t ifindex;
   safi_t safi;
   int ret;
+  mpls_label_t label;
+  struct nexthop *nexthop;
 
   /* Get input stream.  */
   s = client->ibuf;
@@ -1123,13 +1228,19 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
              rib_nexthop_ifindex_add (rib, ifindex);
              break;
            case NEXTHOP_TYPE_IPV4:
-             nexthop.s_addr = stream_get_ipv4 (s);
-             rib_nexthop_ipv4_add (rib, &nexthop, NULL);
+              nhop_addr.s_addr = stream_get_ipv4 (s);
+              nexthop = rib_nexthop_ipv4_add (rib, &nhop_addr, NULL);
+              /* For labeled-unicast, each nexthop is followed by label. */
+              if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
+                {
+                  label = (mpls_label_t)stream_getl (s);
+                  nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &label);
+                }
              break;
            case NEXTHOP_TYPE_IPV4_IFINDEX:
-             nexthop.s_addr = stream_get_ipv4 (s);
+             nhop_addr.s_addr = stream_get_ipv4 (s);
              ifindex = stream_getl (s);
-             rib_nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex);
+             rib_nexthop_ipv4_ifindex_add (rib, &nhop_addr, NULL, ifindex);
              break;
            case NEXTHOP_TYPE_IPV6:
              stream_forward_getp (s, IPV6_MAX_BYTELEN);
@@ -1222,6 +1333,11 @@ zread_ipv4_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
              break;
            case NEXTHOP_TYPE_IPV4:
              nexthop.s_addr = stream_get_ipv4 (s);
+              /* For labeled-unicast, each nexthop is followed by label, but
+               * we don't care for delete.
+               */
+              if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL))
+                stream_forward_getp (s, sizeof(u_int32_t));
              nexthop_p = (union g_addr *)&nexthop;
              break;
            case NEXTHOP_TYPE_IPV4_IFINDEX:
@@ -1407,7 +1523,7 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
 {
   unsigned int i;
   struct stream *s;
-  struct in6_addr nexthop;
+  struct in6_addr nhop_addr;
   struct rib *rib;
   u_char message;
   u_char nexthop_num;
@@ -1418,11 +1534,14 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
   static struct in6_addr nexthops[MULTIPATH_NUM];
   static unsigned int ifindices[MULTIPATH_NUM];
   int ret;
+  static mpls_label_t labels[MULTIPATH_NUM];
+  mpls_label_t label;
+  struct nexthop *nexthop;
 
   /* Get input stream.  */
   s = client->ibuf;
 
-  memset (&nexthop, 0, sizeof (struct in6_addr));
+  memset (&nhop_addr, 0, sizeof (struct in6_addr));
 
   /* Allocate new rib. */
   rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
@@ -1471,10 +1590,17 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
          switch (nexthop_type)
            {
            case NEXTHOP_TYPE_IPV6:
-             stream_get (&nexthop, s, 16);
-              if (nh_count < multipath_num) {
-               nexthops[nh_count++] = nexthop;
-              }
+              stream_get (&nhop_addr, s, 16);
+              if (nh_count < MULTIPATH_NUM)
+                {
+                  /* For labeled-unicast, each nexthop is followed by label. */
+                  if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
+                    {
+                      label = (mpls_label_t)stream_getl (s);
+                     labels[nh_count++] = label;
+                    }
+                 nexthops[nh_count++] = nhop_addr;
+                }
              break;
            case NEXTHOP_TYPE_IFINDEX:
               if (if_count < multipath_num) {
@@ -1492,9 +1618,11 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
         {
          if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) {
             if ((i < if_count) && ifindices[i])
-              rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
+              nexthop = rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
             else
-             rib_nexthop_ipv6_add (rib, &nexthops[i]);
+             nexthop = rib_nexthop_ipv6_add (rib, &nexthops[i]);
+            if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
+              nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &labels[i]);
           }
           else {
             if ((i < if_count) && ifindices[i])
@@ -1591,6 +1719,11 @@ zread_ipv6_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
            {
            case NEXTHOP_TYPE_IPV6:
              stream_get (&nexthop, s, 16);
+              /* For labeled-unicast, each nexthop is followed by label, but
+               * we don't care for delete.
+               */
+              if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL))
+                stream_forward_getp (s, sizeof(u_int32_t));
              pnexthop = (union g_addr *)&nexthop;
              break;
            case NEXTHOP_TYPE_IFINDEX:
@@ -1761,14 +1894,14 @@ zread_mpls_labels (int command, struct zserv *client, u_short length,
   if (command == ZEBRA_MPLS_LABELS_ADD)
     {
       mpls_lsp_install (zvrf, type, in_label, out_label, gtype, &gate,
-                       NULL, ifindex);
+                       ifindex);
       if (out_label != MPLS_IMP_NULL_LABEL)
        mpls_ftn_update (1, zvrf, type, &prefix, gtype, &gate, ifindex,
                         distance, out_label);
     }
   else if (command == ZEBRA_MPLS_LABELS_DELETE)
     {
-      mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, NULL, ifindex);
+      mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, ifindex);
       if (out_label != MPLS_IMP_NULL_LABEL)
        mpls_ftn_update (0, zvrf, type, &prefix, gtype, &gate, ifindex,
                         distance, out_label);
@@ -1975,6 +2108,9 @@ zebra_client_close (struct zserv *client)
   /* Release Label Manager chunks */
   release_daemon_chunks (client->proto, client->instance);
 
+ /* Cleanup any FECs registered by this client. */
+  zebra_mpls_cleanup_fecs_for_client (vrf_info_lookup(VRF_DEFAULT), client);
+
   /* Close file descriptor. */
   if (client->sock)
     {
@@ -2263,6 +2399,12 @@ zebra_client_read (struct thread *thread)
     case ZEBRA_RELEASE_LABEL_CHUNK:
       zread_label_manager_request (command, client, vrf_id);
       break;
+    case ZEBRA_FEC_REGISTER:
+      zserv_fec_register (client, sock, length);
+      break;
+    case ZEBRA_FEC_UNREGISTER:
+      zserv_fec_unregister (client, sock, length);
+      break;
     default:
       zlog_info ("Zebra received unknown command %d", command);
       break;