GSYMS
GRTAGS
GPATH
-
+*.la
+*.lo
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 \
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 \
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@
#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);
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
MIX(extra->mp_nexthop_global_in.s_addr);
MIX(extra->originator_id.s_addr);
MIX(extra->tag);
+ MIX(extra->label_index);
}
if (attr->aspath)
&& 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)
[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;
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)
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;
if (nh_afi == AFI_MAX)
nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->extra->mp_nexthop_len);
+
/* Nexthop */
switch (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);
{
case SAFI_UNICAST:
case SAFI_MULTICAST:
+ case SAFI_LABELED_UNICAST:
{
struct attr_extra *attre = attr->extra;
{
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);
}
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
}
}
+ /* 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 */
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);
}
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);
#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 */
/* 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 */
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;
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)) ? \
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
/* 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) &&
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 */
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)
{
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)
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))
{
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.
{
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);
}
}
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))
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;
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;
{
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])
#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
{
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
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:
/* 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);
#include "thread.h"
#include "workqueue.h"
#include "queue.h"
+#include "mpls.h"
#include "memory.h"
#include "lib/json.h"
#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"
}
}
+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.
}
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;
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)
{
/* 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);
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) &&
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;
}
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))
{
&& 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. */
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
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. */
/* 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)))
{
&& 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)
{
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. */
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))
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
}
}
- /* 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)
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 */
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)
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)
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;
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)
{
#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
{
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)
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;
/* 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;
bgp_static->valid = 0;
bgp_static->igpmetric = 0;
bgp_static->igpnexthop.s_addr = 0;
+ bgp_static->label_index = label_index;
if (rmap)
{
{
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,
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,
{
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,
}
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,
}
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,
}
return bgp_static_set (vty, prefix_str, AFI_IP, SAFI_UNICAST,
- NULL, 1);
+ NULL, 1,
+ BGP_INVALID_LABEL_INDEX);
}
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,
}
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,
}
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,
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",
{
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,
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,
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
}
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. */
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;
{
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;
{
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);
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)
{
((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)
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
"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"
}
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
"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)
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
"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"
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
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);
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);
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);
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);
} 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 */
#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;
/* 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;
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);
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);
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)
};
/*
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);
#include "workqueue.h"
#include "hash.h"
#include "queue.h"
+#include "mpls.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_label.h"
/********************
* PRIVATE FUNCTIONS
int addpath_encode = 0;
u_int32_t addpath_tx_id = 0;
struct prefix_rd *prd = NULL;
+ char label_buf[20];
if (!subgrp)
return NULL;
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);
stream_reset (s);
snlri = subgrp->scratch;
stream_reset (snlri);
+ label_buf[0] = '\0';
bpacket_attr_vec_arr_reset (&vecarr);
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,
{
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. */
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);
/* 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,
}
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);
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
{
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
+ case BGP_IPV6L_NODE:
case BGP_VPNV6_NODE:
case BGP_ENCAPV6_NODE:
afi = AFI_IP6;
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;
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)
{
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;
}
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;
* 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
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)",
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",
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)]",
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]]",
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)
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",
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",
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",
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)
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>",
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,
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,
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",
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",
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,
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",
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,
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",
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",
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",
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",
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",
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",
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",
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,
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",
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,
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>",
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,
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",
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",
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",
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,
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",
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",
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\
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
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",
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]",
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
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)]",
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,
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>",
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,
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>",
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,
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>",
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,
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>",
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,
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",
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,
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)",
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",
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",
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)",
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)",
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]]",
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,
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>]",
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)",
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",
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",
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",
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;
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;
{
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
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);
{
if (bgp_show_summary_afi_safi_peer_exists (bgp, afi, safi))
{
+ json_output = true;
if (is_wildcard)
{
/*
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
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)
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)
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)
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)
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",
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)",
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)",
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",
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)",
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",
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)",
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)",
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",
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]",
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]",
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,
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,
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,
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
/* "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);
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);
#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" \
#include "lib/json.h"
#include "lib/bfd.h"
#include "filter.h"
+#include "mpls.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_route.h"
#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"
/* 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
}
}
+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)
{
}
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;
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.
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)
{
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;
{
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;
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++;
}
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
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;
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,
}
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;
}
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++;
}
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++;
}
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
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;
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)
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 ?
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
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;
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;
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
#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);
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);
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],
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],
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;
{
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;
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))
{
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;
}
{
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)
{
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)
/* 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);
/* 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);
! 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
!
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
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
};
#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
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;
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:
{
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;
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;
#define RFAPI_MON_FLAG_NEEDCALLBACK 0x00000001 /* deferred callback */
//int dcount; /* debugging counter */
- void *timer;
+ struct thread *timer;
};
struct rfapi_monitor_encap
struct rfapi_descriptor *rfd; /* which NVE requested the route */
struct ethaddr macaddr;
uint32_t logical_net_id;
- void *timer;
+ struct thread *timer;
};
/*
struct bgp_tea_options *tea_options;
struct rfapi_un_option *un_options;
struct rfapi_vn_option *vn_options;
- void *timer;
+ struct thread *timer;
};
/*
##
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)
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 --------------------
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
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"
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])
])
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 --------------
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,
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],
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)
;;
*)
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)
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
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
AC_SUBST(OSPF6D)
AC_SUBST(LDPD)
AC_SUBST(NHRPD)
+AC_SUBST(EIGRPD)
AC_SUBST(WATCHFRR)
AC_SUBST(ISISD)
AC_SUBST(PIMD)
])
+AM_CONDITIONAL(SNMP, test "x$SNMP_METHOD" = "xagentx")
+
dnl ---------------------------
dnl sockaddr and netinet checks
dnl ---------------------------
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 --------------------------------------
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
doc/ospfd.8
doc/ldpd.8
doc/ripd.8
+ doc/eigrpd.8
doc/ripngd.8
doc/pimd.8
doc/nhrpd.8
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
+++ /dev/null
-
-sbin_PROGRAMS = ssd
-EXTRA_DIST = etc/frr/debian.conf etc/frr/daemons etc/default/frr
-
-ssd_SOURCES = start-stop-daemon.c
+++ /dev/null
-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"
+++ /dev/null
-log file /var/log/frr/frr.log
-log timestamp precision 6
+++ /dev/null
-# 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
+++ /dev/null
-#
-# 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)
+++ /dev/null
-service integrated-vtysh-config
-username cumulus nopassword
+++ /dev/null
-/*
- * 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));
-}
=====================================================================
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.
/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/
+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
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
etc/logrotate.d/
etc/frr/
+etc/iproute2/rt_protos.d/
usr/share/doc/frr/
usr/share/doc/frr/examples/
usr/share/lintian/overrides/
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
#include "config.h"
-#ifdef HAVE_CUMULUS
+#ifdef HAVE_DATACENTER
#define DFLT_BGP_IMPORT_CHECK 1
#define DFLT_BGP_TIMERS_CONNECT 10
#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
#define DFLT_OSPF_LOG_ADJACENCY_CHANGES 0
#define DFLT_OSPF6_LOG_ADJACENCY_CHANGES 0
-#endif /* !HAVE_CUMULUS */
+#endif /* !HAVE_DATACENTER */
#endif /* _FRR_DEFAULTS_H */
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
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
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
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) \
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 \
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 \
@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
@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
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
!
@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
!
@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
@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
!
!
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
!
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
@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
@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
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
!
--- /dev/null
+.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.
--- /dev/null
+@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.
@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
@example
@group
router bgp 65555
+ address-family ipv4 unicast
network 172.16.0.0/16
redistribute nhrp
+ exit-address-family
@end group
@end example
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
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
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
--- /dev/null
+Makefile
+Makefile.in
+*.o
+*.a
+eigrpd
+eigrpd.conf
+tags
+TAGS
+.deps
+.nfs*
+*.lo
+*.la
+*.libs
+.arch-inventory
+.arch-ids
+*~
+*.loT
+
--- /dev/null
+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
--- /dev/null
+## 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
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+}
+
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+
+}
--- /dev/null
+/* 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")
--- /dev/null
+/* 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 */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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)
+{
+
+}
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+/*
+ * 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);*/
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
+
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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 ();
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+! -*- 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
--- /dev/null
+/*
+ * 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 */
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 = \
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) \
#include "isisd/isis_lsp.h"
#include "isisd/isis_spf.h"
#include "isisd/isis_events.h"
+#include "isisd/isis_mt.h"
extern struct isis *isis;
if (adj->ipv6_addrs)
list_delete (adj->ipv6_addrs);
+ adj_mt_finish(adj);
+
XFREE (MTYPE_ISIS_ADJACENCY, adj);
return;
}
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))
{
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;
+}
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);
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 */
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");
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)
{
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
return ISIS_OK;
}
-int
-isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
-{
- return ISIS_OK;
-}
-
#endif /* ISIS_METHOD == ISIS_METHOD_BPF */
#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)
circuit->mtc = mpls_te_circuit_new();
+ circuit_mt_init(circuit);
+
QOBJ_REG (circuit, isis_circuit);
return circuit;
isis_circuit_if_unbind (circuit, circuit->interface);
+ circuit_mt_finish(circuit);
+
/* and lastly the circuit itself */
XFREE (MTYPE_ISIS_CIRCUIT, circuit);
VTY_NEWLINE);
write++;
}
+ write += circuit_write_mt_settings(circuit, vty);
}
vty_out (vty, "!%s", VTY_NEWLINE);
}
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)
{
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 */
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 */
#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 */
#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 ? */
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;
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)
{
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];
}
}
+ 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)
{
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;
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)
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)
{
}
}
+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)
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)
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);
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);
}
}
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;
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)
{
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 =
memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr,
sizeof (ip6reach->prefix));
- listnode_add (tlv_data.ipv6_reachs, ip6reach);
+ listnode_add (ipv6_reachs, ip6reach);
}
}
/* 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);
}
}
}
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
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)
{
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);
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);
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);
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
#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
*/
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
*/
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,
}
/*
- * 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? */
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,
/* 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 */
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,
}
/*
- * 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? */
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,
"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)
{
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)
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 */
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)
* 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
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 *
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!");
}
return;
}
-void
+static void
isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj)
{
struct listnode *node;
* 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
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;
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)
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;
}
}
- 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;
(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;
}
*/
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;
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:
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))
{
/* 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);
}
}
}
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;
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))
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))
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)
* 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:
/*
* 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);
{
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:
* 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];
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)),
}
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;
}
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);
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));
/* 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:;
}
}
}
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",
}
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
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;
}
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",
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;
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);
}
}
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);
}
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)}>
*/
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,
#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)
{
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)
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.
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));
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:
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
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
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);
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)
{
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);
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
}
-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
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
#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
#define CTRL_INFO_SUBTLVS 0x20
+struct mt_router_info
+{
+ ISIS_MT_INFO_FIELDS
+ bool overload;
+};
+
/*
* Pointer to each tlv type, filled by parse_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;
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;
};
#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);
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);
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);
#include "isis_circuit.h"
#include "isis_csm.h"
#include "isis_misc.h"
+#include "isis_mt.h"
#include "isisd.h"
static struct isis_circuit *
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)
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;
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;
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);
/* 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
{
#include "isisd/isis_zebra.h"
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
struct isis *isis = NULL;
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;
free (area->area_tag);
+ area_mt_finish(area);
+
XFREE (MTYPE_ISIS_AREA, area);
if (listcount (isis->area_list) == 0)
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)
{
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;
write++;
}
+ write += area_write_mt_settings(area, vty);
}
isis_mpls_te_config_write_router(vty);
}
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);
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;
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
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 *);
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);
}
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)
{
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);
}
}
static int control_fd;
int
-control_init(void)
+control_init(char *path)
{
struct sockaddr_un s_un;
int fd;
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);
}
}
void
-control_cleanup(void)
+control_cleanup(char *path)
{
accept_del(control_fd);
close(control_fd);
- unlink(ctl_sock_path);
+ unlink(path);
}
/* ARGSUSED */
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_ */
}
send_hello(HELLO_LINK, ia, NULL);
-
if_start_hello_timer(ia);
+ ia->state = IF_STA_ACTIVE;
+
return (0);
}
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);
}
!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);
}
}
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);
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
};
/* 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
},
};
-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();
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);
config_clear(ldeconf);
- free(iev_ldpe);
+ if (iev_ldpe)
+ free(iev_ldpe);
free(iev_main);
free(iev_main_sync);
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)
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)
fn->local_label > MPLS_LABEL_RESERVED_MAX)
return (fn->local_label);
- return lde_get_next_label ();
+ return (lde_get_next_label());
}
void
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
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);
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);
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)
{
}
}
+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;
on_get_label_chunk_response(start, end);
- return 0;
+ return (0);
}
+
static void
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);
}
}
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);
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);
}
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;
};
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 *);
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 *);
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) {
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 ||
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
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;
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
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);
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);
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);
struct kroute kr;
int nhnum = 0, nhlen;
size_t nhmark;
+ int add = 0;
memset(&kr, 0, sizeof(kr));
s = zclient->ibuf;
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--) {
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));
#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 *,
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;
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)
* 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':
}
}
- 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;
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,
/* 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);
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);
}
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;
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);
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 {
PROC_LDE_ENGINE
} ldpd_process;
+static const char * const log_procnames[] = {
+ "parent",
+ "ldpe",
+ "lde"
+};
+
enum socket_type {
LDP_SOCKET_DISC,
LDP_SOCKET_EDISC,
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;
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 *);
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];
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
/* 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);
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);
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
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__
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);
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)
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;
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);
#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, ...)
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);
/* 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);
va_list ap;
va_start(ap, emsg);
- vlog(LOG_CRIT, emsg, ap);
+ vlog(LOG_ERR, emsg, ap);
va_end(ap);
}
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);
}
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);
- }
-}
* 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 */
--- /dev/null
+/* $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);
+ }
+}
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);
}
#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 **);
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;
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;
}
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;
* "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);
return (0);
}
break;
+ case MSG_TYPE_NOTIFICATION:
+ break;
default:
if (nbr->state != NBR_STA_OPER) {
session_shutdown(nbr, S_SHUTDOWN,
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);
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
#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 \
module.h \
hook.h \
libfrr.h \
+ sha256.h \
+ frr_pthread.h \
# end
noinst_HEADERS = \
static struct cmd_node agentx_node =
{
SMUX_NODE,
- "" /* AgentX has no interface. */
+ "", /* AgentX has no interface. */
+ 1
};
/* Logging NetSNMP messages */
{
if (agentx_enabled)
vty_out (vty, "agentx%s", VTY_NEWLINE);
- return 0;
+ return 1;
}
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,
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:
case ZEBRA_NODE:
case BGP_NODE:
case RIP_NODE:
+ case EIGRP_NODE:
case RIPNG_NODE:
case OSPF_NODE:
case OSPF6_NODE:
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:
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:
case ZEBRA_NODE:
case RIP_NODE:
case RIPNG_NODE:
+ case EIGRP_NODE:
case BGP_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
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:
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 */
#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"
*/
%{
+/* 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;
--- /dev/null
+/*
+ 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++;
+}
--- /dev/null
+/*
+ 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 */
--- /dev/null
+/*
+ * 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 */
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
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"))
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);
}
#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__)
* 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)
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)
*
* 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 */
{
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. */
*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 *
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)
{
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 */
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);
+}
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);
/* 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)
}
}
+ zprivs_state.zsuid = geteuid(); /* initial uid */
/* add groups only if we changed uid - otherwise skip */
if ((ngroups) && (zprivs_state.zsuid != zprivs_state.zuid))
{
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.
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)"
--- /dev/null
+/*-
+ * 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));
+}
--- /dev/null
+/*-
+ * 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_ */
#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)
#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)
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
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 *);
#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
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);
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,
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);
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;
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. */
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;
}
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;
}
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;
{
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;
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
{
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;
}
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;
}
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;
}
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:
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)
{
}
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. */
{
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;
}
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
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;
}
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
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
memset (&dummy, 0, sizeof (struct thread));
+ pthread_mutex_init (&dummy.mtx, NULL);
dummy.type = THREAD_EVENT;
dummy.add_type = THREAD_EXECUTE;
dummy.master = NULL;
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;
#include <zebra.h>
#include "monotime.h"
+#include <pthread.h>
struct rusage_t
{
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;
const char *funcname;
const char *schedfrom;
int schedfrom_line;
+ pthread_mutex_t mtx;
};
struct cpu_thread_history
case ZEBRA_NODE:
case RIP_NODE:
case RIPNG_NODE:
+ case EIGRP_NODE:
case BGP_NODE:
case BGP_VPNV4_NODE:
case BGP_VPNV6_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:
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:
case ZEBRA_NODE:
case RIP_NODE:
case RIPNG_NODE:
+ case EIGRP_NODE:
case BGP_NODE:
case RMAP_NODE:
case OSPF_NODE:
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. */
/* 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))
{
{
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++)
{
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. */
{
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++)
{
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. */
{
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++)
{
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;
}
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
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. */
#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
u_char ifindex_num;
ifindex_t *ifindex;
+ u_char label_num;
+ unsigned int *label;
+
u_char distance;
u_int32_t metric;
u_char ifindex_num;
ifindex_t *ifindex;
+ u_char label_num;
+ unsigned int *label;
+
u_char distance;
u_int32_t metric;
#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
#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
return SAFI_ENCAP;
if (safi == IANA_SAFI_EVPN)
return SAFI_EVPN;
+ if (safi == IANA_SAFI_LABELED_UNICAST)
+ return SAFI_LABELED_UNICAST;
return SAFI_MAX;
}
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;
}
.arch-ids
*~
*.loT
-
+!ax_pthread.m4
+!ax_sys_weak_alias.m4
--- /dev/null
+# ===========================================================================
+# 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
{
struct msg *msg;
struct in_addr ifaddr = { .s_addr = 0L };
- struct in_addr nbraddr = { .s_addr = 0L };
+ struct in_addr nbraddr;
assert (nbr);
{
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;
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))
int offset;
uint8_t *curr;
int curr_size;
+ struct pim_interface *pim_ifp = NULL;
on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
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,
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,
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);
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);
}
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);
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;
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,
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",
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)
{
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)
{
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;
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]",
"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,
"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);
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);
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);
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);
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;
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;
}
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;
}
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;
}
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;
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);
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;
}
}
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;
}
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;
}
}
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;
}
changed = 1;
- sec_addr->addr = addr;
+ sec_addr->addr = *addr;
listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
return changed;
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;
}
continue;
}
- if (pim_sec_addr_add(pim_ifp, p->u.prefix4)) {
+ if (pim_sec_addr_add(pim_ifp, p)) {
changed = 1;
}
}
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);
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__);
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);
}
struct listnode *neighnode;
struct pim_neighbor *neigh;
struct pim_interface *pim_ifp;
+ struct prefix p;
zassert(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 ? */
return neigh;
/* secondary address ? */
- if (pim_neighbor_find_secondary(neigh, addr))
+ if (pim_neighbor_find_secondary(neigh, &p))
return neigh;
}
};
struct pim_secondary_addr {
- struct in_addr addr;
+ struct prefix addr;
enum pim_secondary_addr_flags flags;
};
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;
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];
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
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];
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))
{
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)
{
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
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)
{
}
struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
- struct in_addr addr)
+ struct prefix *addr)
{
struct listnode *node;
struct prefix *p;
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;
}
/*
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];
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);
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 */
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,
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;
}
__PRETTY_FUNCTION__, ifp->name);
}
}
+ ++pinfo->pim_ifstat_reg_stop_send;
}
int
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,
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);
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
*
}
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;
}
}
}
#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:
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;
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);
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 */
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;
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) {
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:
{
addr_str, src_str, ifname);
}
break;
+ case AF_INET6:
+ break;
default:
{
char src_str[INET_ADDRSTRLEN];
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);
}
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,
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)
#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 */
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) {
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;
* We will crash and burn otherwise
*/
exit(1);
- }
+ }
+
+ pimg->send_v6_secondary = 1;
+
}
return 0;
}
} spt;
struct hash *rpf_hash;
+
void *ssm_info; /* per-vrf SSM configuration */
+
+ int send_v6_secondary;
};
extern struct pim_instance *pimg; //Pim Global Instance
--- /dev/null
+#!/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"
%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
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 \
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)
EXTRA_DIST =
bin_PROGRAMS = permutations
+sbin_PROGRAMS = ssd
+
permutations_SOURCES = permutations.c
permutations_LDADD = ../lib/libfrr.la
EXTRA_DIST += frr.service frr-reload.py frr
EXTRA_DIST += xml2cli.pl
+
+ssd_SOURCES = start-stop-daemon.c
--- /dev/null
+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"
--- /dev/null
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+log file /var/log/frr/frr.log
+log timestamp precision 6
--- /dev/null
+service integrated-vtysh-config
+username cumulus nopassword
--- /dev/null
+# Additional protocol strings defined by frr for each of its daemons
+
+186 bgp
+187 isis
+188 ospf
+189 rip
+190 ripng
+191 static
# 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
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
}
# 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
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
--- /dev/null
+/*
+ * 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));
+}
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 \
$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";
}
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$/) {
{ .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},
};
|| 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");
"%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,
"%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,
"%s(config-router)# "
};
+static struct cmd_node eigrp_node =
+{
+ EIGRP_NODE,
+ "%s(config-router)# "
+};
+
static struct cmd_node ripng_node =
{
RIPNG_NODE,
"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;
"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;
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,
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,
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,
case RIPNG_NODE:
case OSPF_NODE:
case OSPF6_NODE:
+ case EIGRP_NODE:
case LDP_NODE:
case LDP_L2VPN_NODE:
case ISIS_NODE:
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:
{
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;
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,
}
/* 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
/* 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
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);
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);
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);
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)
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);
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);
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);
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);
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);
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);
#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
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)
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
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
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 \
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
for setting ifindex to IFINDEX_INTERNAL after processing the
interface deletion message. */
ifp->ifindex = IFINDEX_INTERNAL;
+ ifp->node = NULL;
}
/* VRF change for an interface */
{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}
};
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;
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;
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 *);
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)
*/
return 0;
if (!startup &&
- rtm->rtm_protocol == RTPROT_ZEBRA &&
+ is_selfroute (rtm->rtm_protocol) &&
h->nlmsg_type == RTM_NEWROUTE)
return 0;
}
/* 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])
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))
#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
#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")
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
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
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);
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
/* 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
*/
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;
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;
{
if (nhlfe->type != lsp_type)
continue;
- if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifname, ifindex))
+ if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifindex))
break;
}
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;
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)
*/
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;
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);
}
/*
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;
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;
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;
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;
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;
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;
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)
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;
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)
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;
/* (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;
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;
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;
/* 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);
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.
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;
}
/*
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
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. */
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.
*/
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
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.
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 */
/*
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
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.
{
case ZEBRA_ROUTE_STATIC:
return ZEBRA_LSP_STATIC;
+ case ZEBRA_ROUTE_BGP:
+ return ZEBRA_LSP_BGP;
default:
return ZEBRA_LSP_NONE;
}
return "Static";
case ZEBRA_LSP_LDP:
return "LDP";
+ case ZEBRA_LSP_BGP:
+ return "BGP";
default:
return "Unknown";
}
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;
+}
+
#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);
#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)
{
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,
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]",
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 };
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);
}
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.
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))
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))
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);
/* 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];
{
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);
}
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);
} 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;
#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
{
/* 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)
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.
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;
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);
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:
{
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;
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));
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) {
{
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])
{
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:
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);
/* 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)
{
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;