summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2016-03-30 13:44:03 +0300
committerTimo Teräs <timo.teras@iki.fi>2016-03-30 14:29:40 +0300
commit8cb40c91cdfb00ddf04e88d3ecd40403890d90f7 (patch)
tree6d6a3de27525820abb740f1fa8347b6f03986bad
parent86c5d2ee68f7b9c00ae4aeb5c8b3c5d82c5ebffc (diff)
downloadquagga-8cb40c91cdfb00ddf04e88d3ecd40403890d90f7.tar.bz2
quagga-8cb40c91cdfb00ddf04e88d3ecd40403890d90f7.tar.xz
cumulus take-3cumulus-take-3
-rw-r--r--bgpd/Makefile.am4
-rw-r--r--bgpd/bgp_advertise.c55
-rw-r--r--bgpd/bgp_advertise.h29
-rw-r--r--bgpd/bgp_aspath.c176
-rw-r--r--bgpd/bgp_aspath.h14
-rw-r--r--bgpd/bgp_attr.c245
-rw-r--r--bgpd/bgp_attr.h12
-rw-r--r--bgpd/bgp_btoa.c1
-rw-r--r--bgpd/bgp_clist.c15
-rw-r--r--bgpd/bgp_damp.c1
-rw-r--r--bgpd/bgp_debug.c1121
-rw-r--r--bgpd/bgp_debug.h39
-rw-r--r--bgpd/bgp_ecommunity.c1
-rw-r--r--bgpd/bgp_filter.c31
-rw-r--r--bgpd/bgp_filter.h4
-rw-r--r--bgpd/bgp_fsm.c828
-rw-r--r--bgpd/bgp_fsm.h24
-rw-r--r--bgpd/bgp_main.c33
-rw-r--r--bgpd/bgp_mpath.c58
-rw-r--r--bgpd/bgp_mpath.h6
-rw-r--r--bgpd/bgp_mplsvpn.c18
-rw-r--r--bgpd/bgp_network.c139
-rw-r--r--bgpd/bgp_network.h2
-rw-r--r--bgpd/bgp_nexthop.c1143
-rw-r--r--bgpd/bgp_nexthop.h42
-rw-r--r--bgpd/bgp_nht.c518
-rw-r--r--bgpd/bgp_nht.h58
-rw-r--r--bgpd/bgp_open.c25
-rw-r--r--bgpd/bgp_packet.c796
-rw-r--r--bgpd/bgp_packet.h13
-rw-r--r--bgpd/bgp_regex.c2
-rw-r--r--bgpd/bgp_route.c2528
-rw-r--r--bgpd/bgp_route.h38
-rw-r--r--bgpd/bgp_routemap.c1038
-rw-r--r--bgpd/bgp_table.c1
-rw-r--r--bgpd/bgp_table.h1
-rw-r--r--bgpd/bgp_vty.c1921
-rw-r--r--bgpd/bgp_vty.h4
-rw-r--r--bgpd/bgp_zebra.c729
-rw-r--r--bgpd/bgp_zebra.h9
-rw-r--r--bgpd/bgpd.c749
-rw-r--r--bgpd/bgpd.h139
-rw-r--r--doc/bgpd.texi41
-rw-r--r--doc/next-hop-tracking.txt326
-rw-r--r--doc/routemap.texi4
-rw-r--r--isisd/isisd.c5
-rw-r--r--lib/Makefile.am4
-rw-r--r--lib/bitfield.h102
-rw-r--r--lib/command.c2
-rw-r--r--lib/command.h9
-rw-r--r--lib/fifo.h1
-rw-r--r--lib/filter.c6
-rw-r--r--lib/if.c61
-rw-r--r--lib/if.h17
-rw-r--r--lib/libospf.h6
-rw-r--r--lib/log.c27
-rw-r--r--lib/log.h12
-rw-r--r--lib/memtypes.c6
-rw-r--r--lib/nexthop.c168
-rw-r--r--lib/nexthop.h93
-rw-r--r--lib/plist.c14
-rw-r--r--lib/prefix.h15
-rw-r--r--[-rwxr-xr-x]lib/route_types.pl23
-rw-r--r--lib/routemap.c531
-rw-r--r--lib/routemap.h33
-rw-r--r--lib/thread.c14
-rw-r--r--lib/thread.h6
-rw-r--r--lib/workqueue.c37
-rw-r--r--lib/workqueue.h3
-rw-r--r--lib/zclient.c105
-rw-r--r--lib/zclient.h9
-rw-r--r--lib/zebra.h8
-rw-r--r--ospf6d/ospf6_abr.c553
-rw-r--r--ospf6d/ospf6_abr.h7
-rw-r--r--ospf6d/ospf6_area.c323
-rw-r--r--ospf6d/ospf6_area.h7
-rw-r--r--ospf6d/ospf6_asbr.c92
-rw-r--r--ospf6d/ospf6_asbr.h1
-rw-r--r--ospf6d/ospf6_flood.c5
-rw-r--r--ospf6d/ospf6_flood.h2
-rw-r--r--ospf6d/ospf6_interface.c78
-rw-r--r--ospf6d/ospf6_interface.h8
-rw-r--r--ospf6d/ospf6_intra.c142
-rw-r--r--ospf6d/ospf6_lsa.h1
-rw-r--r--ospf6d/ospf6_lsdb.c35
-rw-r--r--ospf6d/ospf6_lsdb.h4
-rw-r--r--ospf6d/ospf6_main.c4
-rw-r--r--ospf6d/ospf6_message.c14
-rw-r--r--ospf6d/ospf6_network.c10
-rw-r--r--ospf6d/ospf6_network.h2
-rw-r--r--ospf6d/ospf6_route.c291
-rw-r--r--ospf6d/ospf6_route.h56
-rw-r--r--ospf6d/ospf6_spf.c154
-rw-r--r--ospf6d/ospf6_spf.h6
-rw-r--r--ospf6d/ospf6_top.c10
-rw-r--r--ospf6d/ospf6_zebra.c109
-rw-r--r--ospf6d/ospf6_zebra.h2
-rw-r--r--ospf6d/ospf6d.c8
-rw-r--r--ospfd/ospf_abr.h1
-rw-r--r--ospfd/ospf_asbr.c5
-rw-r--r--ospfd/ospf_asbr.h3
-rw-r--r--ospfd/ospf_dump.c2
-rw-r--r--ospfd/ospf_interface.c18
-rw-r--r--ospfd/ospf_lsa.c45
-rw-r--r--ospfd/ospf_main.c1
-rw-r--r--ospfd/ospf_network.c36
-rw-r--r--ospfd/ospf_nsm.c3
-rw-r--r--ospfd/ospf_packet.c267
-rw-r--r--ospfd/ospf_route.c2
-rw-r--r--ospfd/ospf_routemap.c223
-rw-r--r--ospfd/ospf_spf.c7
-rw-r--r--ospfd/ospf_vty.c199
-rw-r--r--ospfd/ospf_vty.h1
-rw-r--r--ospfd/ospf_zebra.c28
-rw-r--r--ospfd/ospfd.c2
-rw-r--r--ospfd/ospfd.h9
-rw-r--r--ripd/rip_routemap.c51
-rw-r--r--ripngd/ripng_routemap.c24
-rw-r--r--tests/aspath_test.c1
-rw-r--r--tests/bgp_capability_test.c9
-rw-r--r--tests/bgp_mp_attr_test.c9
-rw-r--r--tests/bgp_mpath_test.c4
-rw-r--r--tests/ecommunity_test.c1
-rwxr-xr-xvtysh/extract.pl.in6
-rw-r--r--vtysh/vtysh.c160
-rw-r--r--vtysh/vtysh.h4
-rw-r--r--vtysh/vtysh_config.c2
-rw-r--r--vtysh/vtysh_main.c42
-rw-r--r--zebra/Makefile.am8
-rw-r--r--zebra/connected.c33
-rw-r--r--zebra/connected.h1
-rw-r--r--zebra/debug.c30
-rw-r--r--zebra/debug.h3
-rw-r--r--zebra/if_ioctl.c1
-rw-r--r--zebra/if_ioctl_solaris.c1
-rw-r--r--zebra/if_netlink.c1
-rw-r--r--zebra/if_sysctl.c1
-rw-r--r--zebra/interface.c35
-rw-r--r--zebra/ioctl.c1
-rw-r--r--zebra/ioctl_solaris.c1
-rw-r--r--zebra/kernel_null.c1
-rw-r--r--zebra/kernel_socket.c1
-rw-r--r--zebra/redistribute.c50
-rw-r--r--zebra/redistribute_null.c1
-rw-r--r--zebra/rib.h122
-rw-r--r--zebra/rt_netlink.c109
-rw-r--r--zebra/rtadv.c83
-rw-r--r--zebra/rtread_getmsg.c1
-rw-r--r--zebra/rtread_netlink.c1
-rw-r--r--zebra/rtread_sysctl.c1
-rw-r--r--zebra/zebra_fpm_netlink.c1
-rw-r--r--zebra/zebra_rib.c669
-rw-r--r--zebra/zebra_rnh.c761
-rw-r--r--zebra/zebra_rnh.h54
-rw-r--r--zebra/zebra_rnh_null.c21
-rw-r--r--zebra/zebra_routemap.c953
-rw-r--r--zebra/zebra_vty.c1884
-rw-r--r--zebra/zserv.c562
-rw-r--r--zebra/zserv.h51
159 files changed, 17752 insertions, 5077 deletions
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
index d2775f39..fe1be32e 100644
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -16,7 +16,7 @@ libbgp_a_SOURCES = \
bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
- bgp_encap.c bgp_encap_tlv.c
+ bgp_encap.c bgp_encap_tlv.c bgp_nht.c
noinst_HEADERS = \
bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
@@ -24,7 +24,7 @@ noinst_HEADERS = \
bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h \
- bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h
+ bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h bgp_nht.h
bgpd_SOURCES = bgp_main.c
bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index ecf531f7..43573b59 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -26,12 +26,14 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "hash.h"
#include "thread.h"
#include "filter.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_fsm.h"
@@ -186,10 +188,12 @@ bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj,
struct bgp_advertise *adv;
struct bgp_advertise_attr *baa;
struct bgp_advertise *next;
+ struct bgp_advertise_fifo *fhead;
adv = adj->adv;
baa = adv->baa;
next = NULL;
+ fhead = (struct bgp_advertise_fifo *)&peer->sync[afi][safi]->withdraw;
if (baa)
{
@@ -201,10 +205,12 @@ bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj,
/* Unintern BGP advertise attribute. */
bgp_advertise_unintern (peer->hash[afi][safi], baa);
+
+ fhead = (struct bgp_advertise_fifo *)&peer->sync[afi][safi]->update;
}
/* Unlink myself from advertisement FIFO. */
- FIFO_DEL (adv);
+ BGP_ADV_FIFO_DEL (fhead, adv);
/* Free memory. */
bgp_advertise_free (adj->adv);
@@ -264,7 +270,24 @@ bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p,
/* Add new advertisement to advertisement attribute list. */
bgp_advertise_add (adv->baa, adv);
- FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo);
+ BGP_ADV_FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo);
+
+ /*
+ * Schedule write thread (by triggering adjustment of MRAI timer) only if
+ * update FIFO has grown. Otherwise, it will be done upon the work queue
+ * being fully processed. Only adjust timer if needed.
+ */
+ if (!BGP_ROUTE_ADV_HOLD(peer->bgp) &&
+ (BGP_ADV_FIFO_COUNT(&peer->sync[afi][safi]->update) >=
+ peer->bgp->adv_quanta))
+ {
+ if (!peer->radv_adjusted)
+ {
+ if (bgp_debug_update(peer, NULL, 0))
+ zlog_debug("%s scheduling MRAI timer after adj_out_set", peer->host);
+ bgp_adjust_routeadv(peer);
+ }
+ }
}
void
@@ -298,10 +321,24 @@ bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p,
adv->adj = adj;
/* Add to synchronization entry for withdraw announcement. */
- FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo);
-
- /* Schedule packet write. */
- BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+ BGP_ADV_FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo);
+
+ /*
+ * Schedule write thread only if withdraw FIFO has grown. Otherwise,
+ * it will be done upon the work queue being fully processed.
+ */
+ if (!BGP_ROUTE_ADV_HOLD(peer->bgp) &&
+ (BGP_ADV_FIFO_COUNT(&peer->sync[afi][safi]->withdraw) >=
+ peer->bgp->wd_quanta))
+ {
+ if (!peer->t_write)
+ {
+ if (bgp_debug_update(peer, NULL, 0))
+ zlog_debug("%s scheduling write thread after adj_out_unset",
+ peer->host);
+ BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+ }
+ }
}
else
{
@@ -391,9 +428,9 @@ bgp_sync_init (struct peer *peer)
{
sync = XCALLOC (MTYPE_BGP_SYNCHRONISE,
sizeof (struct bgp_synchronize));
- FIFO_INIT (&sync->update);
- FIFO_INIT (&sync->withdraw);
- FIFO_INIT (&sync->withdraw_low);
+ BGP_ADV_FIFO_INIT (&sync->update);
+ BGP_ADV_FIFO_INIT (&sync->withdraw);
+ BGP_ADV_FIFO_INIT (&sync->withdraw_low);
peer->sync[afi][safi] = sync;
peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp);
}
diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h
index 51ba6267..6babc16c 100644
--- a/bgpd/bgp_advertise.h
+++ b/bgpd/bgp_advertise.h
@@ -23,6 +23,14 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include <lib/fifo.h>
+/* BGP advertise FIFO. */
+struct bgp_advertise_fifo
+{
+ struct bgp_advertise *next;
+ struct bgp_advertise *prev;
+ u_int32_t count;
+};
+
/* BGP advertise attribute. */
struct bgp_advertise_attr
{
@@ -124,6 +132,27 @@ struct bgp_synchronize
#define BGP_ADJ_OUT_ADD(N,A) BGP_INFO_ADD(N,A,adj_out)
#define BGP_ADJ_OUT_DEL(N,A) BGP_INFO_DEL(N,A,adj_out)
+#define BGP_ADV_FIFO_ADD(F, N) \
+ do { \
+ FIFO_ADD((F), (N)); \
+ (F)->count++; \
+ } while (0)
+
+#define BGP_ADV_FIFO_DEL(F, N) \
+ do { \
+ FIFO_DEL((N)); \
+ (F)->count--; \
+ } while (0)
+
+#define BGP_ADV_FIFO_INIT(F) \
+ do { \
+ FIFO_INIT((F)); \
+ (F)->count = 0; \
+ } while (0)
+
+#define BGP_ADV_FIFO_COUNT(F) \
+ (F)->count
+
/* Prototypes. */
extern void bgp_adj_out_set (struct bgp_node *, struct peer *, struct prefix *,
struct attr *, afi_t, safi_t, struct bgp_info *);
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 6ab29376..71d510ec 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "stream.h"
#include "jhash.h"
#include "filter.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h"
@@ -427,7 +428,7 @@ aspath_count_confeds (struct aspath *aspath)
}
unsigned int
-aspath_count_hops (struct aspath *aspath)
+aspath_count_hops (const struct aspath *aspath)
{
int count = 0;
struct assegment *seg = aspath->segments;
@@ -471,13 +472,11 @@ aspath_highest (struct aspath *aspath)
struct assegment *seg = aspath->segments;
as_t highest = 0;
unsigned int i;
-
+
while (seg)
{
for (i = 0; i < seg->length; i++)
- if (seg->as[i] > highest
- && (seg->as[i] < BGP_PRIVATE_AS_MIN
- || seg->as[i] > BGP_PRIVATE_AS_MAX))
+ if (seg->as[i] > highest && !BGP_AS_IS_PRIVATE(seg->as[i]))
highest = seg->as[i];
seg = seg->next;
}
@@ -1065,6 +1064,9 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2)
if (match != minlen || match != seg1->length
|| seg1->length != seg2->length)
break;
+ /* We are moving on to the next segment to reset match */
+ else
+ match = 0;
seg1 = seg1->next;
seg2 = seg2->next;
@@ -1146,20 +1148,44 @@ int
aspath_private_as_check (struct aspath *aspath)
{
struct assegment *seg;
-
+
if ( !(aspath && aspath->segments) )
return 0;
-
+
seg = aspath->segments;
while (seg)
{
int i;
-
+
+ for (i = 0; i < seg->length; i++)
+ {
+ if (!BGP_AS_IS_PRIVATE(seg->as[i]))
+ return 0;
+ }
+ seg = seg->next;
+ }
+ return 1;
+}
+
+/* Return True if the entire ASPATH consist of the specified ASN */
+int
+aspath_single_asn_check (struct aspath *aspath, as_t asn)
+{
+ struct assegment *seg;
+
+ if ( !(aspath && aspath->segments) )
+ return 0;
+
+ seg = aspath->segments;
+
+ while (seg)
+ {
+ int i;
+
for (i = 0; i < seg->length; i++)
{
- if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
- || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
+ if (seg->as[i] != asn)
return 0;
}
seg = seg->next;
@@ -1167,6 +1193,132 @@ aspath_private_as_check (struct aspath *aspath)
return 1;
}
+/* Replace all instances of the target ASN with our own ASN */
+struct aspath *
+aspath_replace_specific_asn (struct aspath *aspath, as_t target_asn,
+ as_t our_asn)
+{
+ struct aspath *new;
+ struct assegment *seg;
+
+ new = aspath_dup(aspath);
+ seg = new->segments;
+
+ while (seg)
+ {
+ int i;
+
+ for (i = 0; i < seg->length; i++)
+ {
+ if (seg->as[i] == target_asn)
+ seg->as[i] = our_asn;
+ }
+ seg = seg->next;
+ }
+
+ aspath_str_update(new);
+ return new;
+}
+
+/* Replace all private ASNs with our own ASN */
+struct aspath *
+aspath_replace_private_asns (struct aspath *aspath, as_t asn)
+{
+ struct aspath *new;
+ struct assegment *seg;
+
+ new = aspath_dup(aspath);
+ seg = new->segments;
+
+ while (seg)
+ {
+ int i;
+
+ for (i = 0; i < seg->length; i++)
+ {
+ if (BGP_AS_IS_PRIVATE(seg->as[i]))
+ seg->as[i] = asn;
+ }
+ seg = seg->next;
+ }
+
+ aspath_str_update(new);
+ return new;
+}
+
+/* Remove all private ASNs */
+struct aspath *
+aspath_remove_private_asns (struct aspath *aspath)
+{
+ struct aspath *new;
+ struct assegment *seg;
+ struct assegment *new_seg;
+ struct assegment *last_new_seg;
+ int i;
+ int j;
+ int public = 0;
+
+ new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
+
+ new_seg = NULL;
+ last_new_seg = NULL;
+ seg = aspath->segments;
+ while (seg)
+ {
+ public = 0;
+ for (i = 0; i < seg->length; i++)
+ {
+ // ASN is public
+ if (!BGP_AS_IS_PRIVATE(seg->as[i]))
+ {
+ public++;
+ }
+ }
+
+ // The entire segment is private so skip it
+ if (!public)
+ {
+ seg = seg->next;
+ continue;
+ }
+
+ // The entire segment is public so copy it
+ else if (public == seg->length)
+ {
+ new_seg = assegment_dup (seg);
+ }
+
+ // The segment is a mix of public and private ASNs. Copy as many spots as
+ // there are public ASNs then come back and fill in only the public ASNs.
+ else
+ {
+ new_seg = assegment_new (seg->type, public);
+ j = 0;
+ for (i = 0; i < seg->length; i++)
+ {
+ // ASN is public
+ if (!BGP_AS_IS_PRIVATE(seg->as[i]))
+ {
+ new_seg->as[j] = seg->as[i];
+ j++;
+ }
+ }
+ }
+
+ // This is the first segment so set the aspath segments pointer to this one
+ if (!last_new_seg)
+ new->segments = new_seg;
+ else
+ last_new_seg->next = new_seg;
+
+ last_new_seg = new_seg;
+ seg = seg->next;
+ }
+
+ aspath_str_update(new);
+ return new;
+}
+
/* AS path confed check. If aspath contains confed set or sequence then return 1. */
int
aspath_confed_check (struct aspath *aspath)
@@ -1443,6 +1595,10 @@ aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
seg1 = aspath1->segments;
seg2 = aspath2->segments;
+ /* If both paths are originated in this AS then we do want to compare MED */
+ if (!seg1 && !seg2)
+ return 1;
+
/* find first non-confed segments for each */
while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
|| (seg1->type == AS_CONFED_SET)))
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index 1311f8a5..134f1f66 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -31,12 +31,20 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define BGP_PRIVATE_AS_MIN 64512U
#define BGP_PRIVATE_AS_MAX 65535U
+/* Private 4 byte AS range defined in RFC6996. */
+#define BGP_PRIVATE_AS4_MIN 4200000000U
+#define BGP_PRIVATE_AS4_MAX 4294967294U
+
/* we leave BGP_AS_MAX as the 16bit AS MAX number. */
#define BGP_AS_MAX 65535U
#define BGP_AS4_MAX 4294967295U
/* Transition 16Bit AS as defined by IANA */
#define BGP_AS_TRANS 23456U
+#define BGP_AS_IS_PRIVATE(ASN) \
+ (((ASN) >= BGP_PRIVATE_AS_MIN && (ASN) <= BGP_PRIVATE_AS_MAX) || \
+ ((ASN) >= BGP_PRIVATE_AS4_MIN && (ASN) <= BGP_PRIVATE_AS4_MAX))
+
/* AS_PATH segment data in abstracted form, no limit is placed on length */
struct assegment
{
@@ -90,11 +98,15 @@ extern void aspath_print_all_vty (struct vty *);
extern unsigned int aspath_key_make (void *);
extern int aspath_loop_check (struct aspath *, as_t);
extern int aspath_private_as_check (struct aspath *);
+extern int aspath_single_asn_check (struct aspath *, as_t asn);
+extern struct aspath *aspath_replace_specific_asn (struct aspath *aspath, as_t target_asn, as_t our_asn);
+extern struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn);
+extern struct aspath *aspath_remove_private_asns (struct aspath *aspath);
extern int aspath_firstas_check (struct aspath *, as_t);
extern int aspath_confed_check (struct aspath *);
extern int aspath_left_confed_check (struct aspath *);
extern unsigned long aspath_count (void);
-extern unsigned int aspath_count_hops (struct aspath *);
+extern unsigned int aspath_count_hops (const struct aspath *);
extern unsigned int aspath_count_confeds (struct aspath *);
extern unsigned int aspath_size (struct aspath *);
extern as_t aspath_highest (struct aspath *);
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index f34e6493..bc39f3b8 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -153,7 +153,6 @@ cluster_free (struct cluster_list *cluster)
XFREE (MTYPE_CLUSTER, cluster);
}
-#if 0
static struct cluster_list *
cluster_dup (struct cluster_list *cluster)
{
@@ -172,7 +171,6 @@ cluster_dup (struct cluster_list *cluster)
return new;
}
-#endif
static struct cluster_list *
cluster_intern (struct cluster_list *cluster)
@@ -322,6 +320,23 @@ transit_free (struct transit *transit)
XFREE (MTYPE_TRANSIT, transit);
}
+static struct transit *
+transit_dup (struct transit *transit)
+{
+ struct transit *new;
+
+ new = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
+ new->length = transit->length;
+ if (new->length)
+ {
+ new->val = XMALLOC (MTYPE_TRANSIT_VAL, transit->length);
+ memcpy (new->val, transit->val, transit->length);
+ }
+ else
+ new->val = NULL;
+
+ return new;
+}
static void *
transit_hash_alloc (void *p)
@@ -458,6 +473,46 @@ bgp_attr_dup (struct attr *new, struct attr *orig)
}
}
+void
+bgp_attr_deep_dup (struct attr *new, struct attr *orig)
+{
+ if (orig->aspath)
+ new->aspath = aspath_dup(orig->aspath);
+
+ if (orig->community)
+ new->community = community_dup(orig->community);
+
+ if (orig->extra)
+ {
+ if (orig->extra->ecommunity)
+ new->extra->ecommunity = ecommunity_dup(orig->extra->ecommunity);
+ if (orig->extra->cluster)
+ new->extra->cluster = cluster_dup(orig->extra->cluster);
+ if (orig->extra->transit)
+ new->extra->transit = transit_dup(orig->extra->transit);
+ }
+}
+
+void
+bgp_attr_deep_free (struct attr *attr)
+{
+ if (attr->aspath)
+ aspath_free(attr->aspath);
+
+ if (attr->community)
+ community_free(attr->community);
+
+ if (attr->extra)
+ {
+ if (attr->extra->ecommunity)
+ ecommunity_free(&attr->extra->ecommunity);
+ if (attr->extra->cluster)
+ cluster_free(attr->extra->cluster);
+ if (attr->extra->transit)
+ transit_free(attr->extra->transit);
+ }
+}
+
unsigned long int
attr_count (void)
{
@@ -495,6 +550,7 @@ attrhash_key_make (void *p)
MIX(extra->weight);
MIX(extra->mp_nexthop_global_in.s_addr);
MIX(extra->originator_id.s_addr);
+ MIX(extra->tag);
}
if (attr->aspath)
@@ -540,6 +596,7 @@ attrhash_cmp (const void *p1, const void *p2)
&& ae1->aggregator_as == ae2->aggregator_as
&& ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
&& ae1->weight == ae2->weight
+ && ae1->tag == ae2->tag
&& 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)
@@ -691,6 +748,7 @@ bgp_attr_default_set (struct attr *attr, u_char origin)
attr->aspath = aspath_empty ();
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
+ attr->extra->tag = 0;
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
@@ -717,10 +775,12 @@ bgp_attr_default_intern (u_char origin)
return new;
}
+/* Create the attributes for an aggregate */
struct attr *
bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
struct aspath *aspath,
- struct community *community, int as_set)
+ struct community *community, int as_set,
+ u_char atomic_aggregate)
{
struct attr attr;
struct attr *new;
@@ -753,7 +813,7 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
- if (! as_set)
+ if (! as_set || atomic_aggregate)
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
@@ -962,19 +1022,18 @@ bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
CHECK_FLAG (real_flags, attr_flag_str[i].key)
)
{
- zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
- LOOKUP (attr_str, attr_code),
- CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
- attr_flag_str[i].str);
+ zlog_err ("%s attribute must%s be flagged as \"%s\"",
+ LOOKUP (attr_str, attr_code),
+ CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
+ attr_flag_str[i].str);
seen = 1;
}
if (!seen)
{
- zlog (args->peer->log, LOG_DEBUG,
- "Strange, %s called for attr %s, but no problem found with flags"
- " (real flags 0x%x, desired 0x%x)",
- __func__, LOOKUP (attr_str, attr_code),
- real_flags, desired_flags);
+ zlog_debug ("Strange, %s called for attr %s, but no problem found with flags"
+ " (real flags 0x%x, desired 0x%x)",
+ __func__, LOOKUP (attr_str, attr_code),
+ real_flags, desired_flags);
}
}
@@ -1007,7 +1066,6 @@ bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
const u_int8_t flags = args->flags;
const u_int8_t attr_code = args->type;
- struct peer *const peer = args->peer;
/* there may be attributes we don't know about */
if (attr_code > attr_flags_values_max)
@@ -1021,9 +1079,8 @@ bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
&& !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
{
- zlog (peer->log, LOG_ERR,
- "%s well-known attributes must have transitive flag set (%x)",
- LOOKUP (attr_str, attr_code), flags);
+ zlog_err ("%s well-known attributes must have transitive flag set (%x)",
+ LOOKUP (attr_str, attr_code), flags);
return 1;
}
@@ -1034,19 +1091,17 @@ bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
{
if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
{
- zlog (peer->log, LOG_ERR,
- "%s well-known attribute "
- "must NOT have the partial flag set (%x)",
- LOOKUP (attr_str, attr_code), flags);
+ zlog_err ("%s well-known attribute "
+ "must NOT have the partial flag set (%x)",
+ LOOKUP (attr_str, attr_code), flags);
return 1;
}
if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
&& !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
{
- zlog (peer->log, LOG_ERR,
- "%s optional + transitive attribute "
- "must NOT have the partial flag set (%x)",
- LOOKUP (attr_str, attr_code), flags);
+ zlog_err ("%s optional + transitive attribute "
+ "must NOT have the partial flag set (%x)",
+ LOOKUP (attr_str, attr_code), flags);
return 1;
}
}
@@ -1081,8 +1136,7 @@ bgp_attr_origin (struct bgp_attr_parser_args *args)
value). */
if (length != 1)
{
- zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
- length);
+ zlog_err ("Origin attribute length is not one %d", length);
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -1098,8 +1152,7 @@ bgp_attr_origin (struct bgp_attr_parser_args *args)
&& (attr->origin != BGP_ORIGIN_EGP)
&& (attr->origin != BGP_ORIGIN_INCOMPLETE))
{
- zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
- attr->origin);
+ zlog_err ("Origin attribute value is invalid %d", attr->origin);
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
args->total);
@@ -1130,9 +1183,7 @@ bgp_attr_aspath (struct bgp_attr_parser_args *args)
/* In case of IBGP, length will be zero. */
if (! attr->aspath)
{
- zlog (peer->log, LOG_ERR,
- "Malformed AS path from %s, length is %d",
- peer->host, length);
+ zlog_err ("Malformed AS path from %s, length is %d", peer->host, length);
return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
}
@@ -1159,7 +1210,7 @@ bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
(peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
{
- zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
+ zlog_err ("Malformed AS path from %s", peer->host);
bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_MAL_AS_PATH);
return BGP_ATTR_PARSE_ERROR;
@@ -1171,8 +1222,7 @@ bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
if (peer->sort == BGP_PEER_EBGP
&& ! aspath_firstas_check (attr->aspath, peer->as))
{
- zlog (peer->log, LOG_ERR,
- "%s incorrect first AS (must be %u)", peer->host, peer->as);
+ zlog_err ("%s incorrect first AS (must be %u)", peer->host, peer->as);
bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_MAL_AS_PATH);
return BGP_ATTR_PARSE_ERROR;
@@ -1206,9 +1256,7 @@ bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
/* In case of IBGP, length will be zero. */
if (!*as4_path)
{
- zlog (peer->log, LOG_ERR,
- "Malformed AS4 path from %s, length is %d",
- peer->host, length);
+ zlog_err ("Malformed AS4 path from %s, length is %d", peer->host, length);
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_MAL_AS_PATH,
0);
@@ -1234,8 +1282,7 @@ bgp_attr_nexthop (struct bgp_attr_parser_args *args)
/* Check nexthop attribute length. */
if (length != 4)
{
- zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
- length);
+ zlog_err ("Nexthop attribute length isn't four [%d]", length);
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
@@ -1253,7 +1300,7 @@ bgp_attr_nexthop (struct bgp_attr_parser_args *args)
{
char buf[INET_ADDRSTRLEN];
inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN);
- zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
+ zlog_err ("Martian nexthop %s", buf);
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
args->total);
@@ -1276,8 +1323,7 @@ bgp_attr_med (struct bgp_attr_parser_args *args)
/* Length check. */
if (length != 4)
{
- zlog (peer->log, LOG_ERR,
- "MED attribute length isn't four [%d]", length);
+ zlog_err ("MED attribute length isn't four [%d]", length);
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
@@ -1302,8 +1348,7 @@ bgp_attr_local_pref (struct bgp_attr_parser_args *args)
/* Length check. */
if (length != 4)
{
- zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
- length);
+ zlog_err ("LOCAL_PREF attribute length isn't 4 [%u]", length);
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -1330,15 +1375,13 @@ bgp_attr_local_pref (struct bgp_attr_parser_args *args)
static int
bgp_attr_atomic (struct bgp_attr_parser_args *args)
{
- struct peer *const peer = args->peer;
struct attr *const attr = args->attr;
const bgp_size_t length = args->length;
/* Length check. */
if (length != 0)
{
- zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
- length);
+ zlog_err ("ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -1367,8 +1410,7 @@ bgp_attr_aggregator (struct bgp_attr_parser_args *args)
if (length != wantedlen)
{
- zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
- wantedlen, length);
+ zlog_err ("AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -1398,8 +1440,7 @@ bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
if (length != 8)
{
- zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
- length);
+ zlog_err ("New Aggregator length is not 8 [%d]", length);
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
0);
@@ -1562,7 +1603,7 @@ bgp_attr_originator_id (struct bgp_attr_parser_args *args)
/* Length check. */
if (length != 4)
{
- zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
+ zlog_err ("Bad originator ID length %d", length);
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
@@ -1588,7 +1629,7 @@ bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
/* Check length. */
if (length % 4)
{
- zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
+ zlog_err ("Bad cluster list length %d", length);
return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -1698,8 +1739,8 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
char buf1[INET6_ADDRSTRLEN];
char buf2[INET6_ADDRSTRLEN];
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
+ if (bgp_debug_update(peer, NULL, 1))
+ zlog_debug ("%s sent two nexthops %s %s but second one is not a link-local nexthop", peer->host,
inet_ntop (AF_INET6, &attre->mp_nexthop_global,
buf1, INET6_ADDRSTRLEN),
inet_ntop (AF_INET6, &attre->mp_nexthop_local,
@@ -1736,7 +1777,7 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
__func__, peer->host);
return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
}
-
+
mp_update->afi = afi;
mp_update->safi = safi;
mp_update->nlri = stream_pnt (s);
@@ -1837,8 +1878,7 @@ bgp_attr_encap(
if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
|| !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
{
- zlog (peer->log, LOG_ERR,
- "Tunnel Encap attribute flag isn't optional and transitive %d", flag);
+ zlog_err ("Tunnel Encap attribute flag isn't optional and transitive %d", flag);
bgp_notify_send_with_data (peer,
BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
@@ -1851,8 +1891,7 @@ bgp_attr_encap(
uint16_t tlv_length;
if (length < 4) {
- zlog (peer->log, LOG_ERR,
- "Tunnel Encap attribute not long enough to contain outer T,L");
+ zlog_err ("Tunnel Encap attribute not long enough to contain outer T,L");
bgp_notify_send_with_data(peer,
BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
@@ -1864,7 +1903,7 @@ bgp_attr_encap(
length -= 4;
if (tlv_length != length) {
- zlog (peer->log, LOG_ERR, "%s: tlv_length(%d) != length(%d)",
+ zlog_err ("%s: tlv_length(%d) != length(%d)",
__func__, tlv_length, length);
}
}
@@ -1881,8 +1920,7 @@ bgp_attr_encap(
}
if (sublength > length) {
- zlog (peer->log, LOG_ERR,
- "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
+ zlog_err ("Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
sublength, length);
bgp_notify_send_with_data (peer,
BGP_NOTIFY_UPDATE_ERR,
@@ -1923,8 +1961,7 @@ bgp_attr_encap(
if (length) {
/* spurious leftover data */
- zlog (peer->log, LOG_ERR,
- "Tunnel Encap attribute length is bad: %d leftover octets", length);
+ zlog_err ("Tunnel Encap attribute length is bad: %d leftover octets", length);
bgp_notify_send_with_data (peer,
BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
@@ -1949,15 +1986,10 @@ bgp_attr_unknown (struct bgp_attr_parser_args *args)
const u_char flag = args->flags;
const bgp_size_t length = args->length;
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
- peer->host, type, length);
+ if (bgp_debug_update(peer, NULL, 1))
+ zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
+ peer->host, type, length);
- if (BGP_DEBUG (events, EVENTS))
- zlog (peer->log, LOG_DEBUG,
- "Unknown attribute type %d length %d is received", type, length);
-
/* Forward read pointer of input stream. */
stream_forward_getp (peer->ibuf, length);
@@ -2039,9 +2071,7 @@ bgp_attr_check (struct peer *peer, struct attr *attr)
if (type)
{
- zlog (peer->log, LOG_WARNING,
- "%s Missing well-known attribute %d / %s",
- peer->host, type, LOOKUP (attr_str, type));
+ zlog_warn ("%s Missing well-known attribute %d.", peer->host, type);
bgp_notify_send_with_data (peer,
BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_MISS_ATTR,
@@ -2083,10 +2113,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
{
/* XXX warning: long int format, int arg (arg 5) */
- zlog (peer->log, LOG_WARNING,
- "%s: error BGP attribute length %lu is smaller than min len",
- peer->host,
- (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
+ zlog_warn ("%s: error BGP attribute length %lu is smaller than min len",
+ peer->host,
+ (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
bgp_notify_send (peer,
BGP_NOTIFY_UPDATE_ERR,
@@ -2106,10 +2135,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
&& ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
{
- zlog (peer->log, LOG_WARNING,
- "%s: Extended length set, but just %lu bytes of attr header",
- peer->host,
- (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
+ zlog_warn ("%s: Extended length set, but just %lu bytes of attr header",
+ peer->host,
+ (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
bgp_notify_send (peer,
BGP_NOTIFY_UPDATE_ERR,
@@ -2129,9 +2157,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
if (CHECK_BITMAP (seen, type))
{
- zlog (peer->log, LOG_WARNING,
- "%s: error BGP attribute type %d appears twice in a message",
- peer->host, type);
+ zlog_warn ("%s: error BGP attribute type %d appears twice in a message",
+ peer->host, type);
bgp_notify_send (peer,
BGP_NOTIFY_UPDATE_ERR,
@@ -2149,11 +2176,11 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
if (attr_endp > endp)
{
- zlog (peer->log, LOG_WARNING,
- "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ zlog_warn ("%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp);
+ bgp_notify_send_with_data (peer,
+ BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ startp, attr_endp - startp);
return BGP_ATTR_PARSE_ERROR;
}
@@ -2252,10 +2279,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
/* If hard error occured immediately return to the caller. */
if (ret == BGP_ATTR_PARSE_ERROR)
{
- zlog (peer->log, LOG_WARNING,
- "%s: Attribute %s, parse error",
- peer->host,
- LOOKUP (attr_str, type));
+ zlog_warn ("%s: Attribute %s, parse error",
+ peer->host,
+ LOOKUP (attr_str, type));
if (as4_path)
aspath_unintern (&as4_path);
return ret;
@@ -2263,10 +2289,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
if (ret == BGP_ATTR_PARSE_WITHDRAW)
{
- zlog (peer->log, LOG_WARNING,
- "%s: Attribute %s, parse error - treating as withdrawal",
- peer->host,
- LOOKUP (attr_str, type));
+ zlog_warn ("%s: Attribute %s, parse error - treating as withdrawal",
+ peer->host,
+ LOOKUP (attr_str, type));
if (as4_path)
aspath_unintern (&as4_path);
return ret;
@@ -2275,9 +2300,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
/* Check the fetched length. */
if (BGP_INPUT_PNT (peer) != attr_endp)
{
- zlog (peer->log, LOG_WARNING,
- "%s: BGP attribute %s, fetch error",
- peer->host, LOOKUP (attr_str, type));
+ zlog_warn ("%s: BGP attribute %s, fetch error",
+ peer->host, LOOKUP (attr_str, type));
bgp_notify_send (peer,
BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
@@ -2289,9 +2313,8 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
/* Check final read pointer is same as end pointer. */
if (BGP_INPUT_PNT (peer) != endp)
{
- zlog (peer->log, LOG_WARNING,
- "%s: BGP attribute %s, length mismatch",
- peer->host, LOOKUP (attr_str, type));
+ zlog_warn ("%s: BGP attribute %s, length mismatch",
+ peer->host, LOOKUP (attr_str, type));
bgp_notify_send (peer,
BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
@@ -2547,8 +2570,7 @@ bgp_packet_mpattr_tea(
}
if (attrlenfield > 0xffff) {
- zlog (peer->log, LOG_ERR,
- "%s attribute is too long (length=%d), can't send it",
+ zlog_err ("%s attribute is too long (length=%d), can't send it",
attrname,
attrlenfield);
return;
@@ -2705,12 +2727,13 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
}
/* MED attribute. */
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
+ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC) ||
+ bgp->maxmed_active)
{
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
stream_putc (s, 4);
- stream_putl (s, attr->med);
+ stream_putl (s, (bgp->maxmed_active ? bgp->maxmed_value : attr->med));
}
/* Local preference. */
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index fe6c2a1a..87310d50 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -93,6 +93,9 @@ struct attr_extra
uint16_t encap_tunneltype; /* grr */
struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */
+
+ /* route tag */
+ u_short tag;
};
/* BGP core attribute structure. */
@@ -117,6 +120,7 @@ struct attr
struct in_addr nexthop;
u_int32_t med;
u_int32_t local_pref;
+ ifindex_t nh_ifindex;
/* Path origin attribute */
u_char origin;
@@ -140,6 +144,10 @@ struct transit
#define ATTR_FLAG_BIT(X) (1 << ((X) - 1))
+#define BGP_CLUSTER_LIST_LENGTH(attr) \
+ (((attr)->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) ? \
+ (attr)->extra->cluster->length : 0)
+
typedef enum {
BGP_ATTR_PARSE_PROCEED = 0,
BGP_ATTR_PARSE_ERROR = -1,
@@ -158,6 +166,8 @@ extern bgp_attr_parse_ret_t bgp_attr_parse (struct peer *, struct attr *,
extern struct attr_extra *bgp_attr_extra_get (struct attr *);
extern void bgp_attr_extra_free (struct attr *);
extern void bgp_attr_dup (struct attr *, struct attr *);
+extern void bgp_attr_deep_dup (struct attr *, struct attr *);
+extern void bgp_attr_deep_free (struct attr *);
extern struct attr *bgp_attr_intern (struct attr *attr);
extern void bgp_attr_unintern_sub (struct attr *);
extern void bgp_attr_unintern (struct attr **);
@@ -166,7 +176,7 @@ extern struct attr *bgp_attr_default_set (struct attr *attr, u_char);
extern struct attr *bgp_attr_default_intern (u_char);
extern struct attr *bgp_attr_aggregate_intern (struct bgp *, u_char,
struct aspath *,
- struct community *, int as_set);
+ struct community *, int as_set, u_char);
extern bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *,
struct stream *, struct attr *,
struct prefix *, afi_t, safi_t,
diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c
index b408efdd..d298f8ba 100644
--- a/bgpd/bgp_btoa.c
+++ b/bgpd/bgp_btoa.c
@@ -28,6 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "memory.h"
#include "privs.h"
#include "filter.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_dump.h"
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index bb06028b..4abdf0c7 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "prefix.h"
#include "memory.h"
#include "filter.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_community.h"
@@ -707,7 +708,10 @@ community_list_set (struct community_list_handler *ch,
if (community_list_dup_check (list, entry))
community_entry_free (entry);
else
- community_list_entry_add (list, entry);
+ {
+ community_list_entry_add (list, entry);
+ route_map_notify_dependencies(name, RMAP_EVENT_CLIST_ADDED);
+ }
return 0;
}
@@ -733,6 +737,7 @@ community_list_unset (struct community_list_handler *ch,
if (!str)
{
community_list_delete (list);
+ route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
return 0;
}
@@ -758,6 +763,7 @@ community_list_unset (struct community_list_handler *ch,
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
community_list_entry_delete (list, entry, style);
+ route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
return 0;
}
@@ -826,7 +832,10 @@ extcommunity_list_set (struct community_list_handler *ch,
if (community_list_dup_check (list, entry))
community_entry_free (entry);
else
- community_list_entry_add (list, entry);
+ {
+ community_list_entry_add (list, entry);
+ route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_ADDED);
+ }
return 0;
}
@@ -852,6 +861,7 @@ extcommunity_list_unset (struct community_list_handler *ch,
if (!str)
{
community_list_delete (list);
+ route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
return 0;
}
@@ -877,6 +887,7 @@ extcommunity_list_unset (struct community_list_handler *ch,
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
community_list_entry_delete (list, entry, style);
+ route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
return 0;
}
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
index ac647239..1c128cc1 100644
--- a/bgpd/bgp_damp.c
+++ b/bgpd/bgp_damp.c
@@ -27,6 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "log.h"
#include "thread.h"
#include "filter.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_damp.h"
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 60e2777e..2a4997e8 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "log.h"
#include "sockunion.h"
#include "filter.h"
+#include "memory.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h"
@@ -38,24 +39,31 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_community.h"
unsigned long conf_bgp_debug_as4;
-unsigned long conf_bgp_debug_fsm;
+unsigned long conf_bgp_debug_neighbor_events;
unsigned long conf_bgp_debug_events;
unsigned long conf_bgp_debug_packet;
unsigned long conf_bgp_debug_filter;
unsigned long conf_bgp_debug_keepalive;
unsigned long conf_bgp_debug_update;
-unsigned long conf_bgp_debug_normal;
unsigned long conf_bgp_debug_zebra;
+unsigned long conf_bgp_debug_nht;
unsigned long term_bgp_debug_as4;
-unsigned long term_bgp_debug_fsm;
+unsigned long term_bgp_debug_neighbor_events;
unsigned long term_bgp_debug_events;
unsigned long term_bgp_debug_packet;
unsigned long term_bgp_debug_filter;
unsigned long term_bgp_debug_keepalive;
unsigned long term_bgp_debug_update;
-unsigned long term_bgp_debug_normal;
unsigned long term_bgp_debug_zebra;
+unsigned long term_bgp_debug_nht;
+
+struct list *bgp_debug_neighbor_events_peers = NULL;
+struct list *bgp_debug_keepalive_peers = NULL;
+struct list *bgp_debug_update_out_peers = NULL;
+struct list *bgp_debug_update_in_peers = NULL;
+struct list *bgp_debug_update_prefixes = NULL;
+struct list *bgp_debug_zebra_prefixes = NULL;
/* messages for BGP-4 status */
const struct message bgp_status_msg[] =
@@ -90,7 +98,7 @@ static const struct message bgp_notify_msg[] =
{ BGP_NOTIFY_OPEN_ERR, "OPEN Message Error"},
{ BGP_NOTIFY_UPDATE_ERR, "UPDATE Message Error"},
{ BGP_NOTIFY_HOLD_ERR, "Hold Timer Expired"},
- { BGP_NOTIFY_FSM_ERR, "Finite State Machine Error"},
+ { BGP_NOTIFY_FSM_ERR, "Neighbor Events Error"},
{ BGP_NOTIFY_CEASE, "Cease"},
{ BGP_NOTIFY_CAPABILITY_ERR, "CAPABILITY Message Error"},
};
@@ -161,6 +169,151 @@ static const int bgp_notify_capability_msg_max = BGP_NOTIFY_CAPABILITY_MAX;
const char *bgp_origin_str[] = {"i","e","?"};
const char *bgp_origin_long_str[] = {"IGP","EGP","incomplete"};
+
+/* Given a string return a pointer the corresponding peer structure */
+static struct peer *
+bgp_find_peer (struct vty *vty, const char *peer_str)
+{
+ int ret;
+ union sockunion su;
+ struct bgp *bgp;
+
+ bgp = vty->index;
+ ret = str2sockunion (peer_str, &su);
+
+ /* 'swpX' string */
+ if (ret < 0)
+ return peer_lookup_by_conf_if (bgp, peer_str);
+ else
+ return peer_lookup (bgp, &su);
+}
+
+static void
+bgp_debug_list_free(struct list *list)
+{
+ struct bgp_debug_filter *filter;
+ struct listnode *node, *nnode;
+
+ if (list)
+ for (ALL_LIST_ELEMENTS (list, node, nnode, filter))
+ {
+ listnode_delete (list, filter);
+
+ if (filter->p)
+ prefix_free(filter->p);
+
+ if (filter->peer)
+ peer_unlock (filter->peer);
+
+ XFREE (MTYPE_BGP_DEBUG_FILTER, filter);
+ }
+}
+
+/* Print the desc along with a list of peers/prefixes this debug is
+ * enabled for */
+static void
+bgp_debug_list_print (struct vty *vty, const char *desc, struct list *list)
+{
+ struct bgp_debug_filter *filter;
+ struct listnode *node, *nnode;
+ char buf[INET6_ADDRSTRLEN];
+
+ vty_out (vty, "%s", desc);
+
+ if (list && !list_isempty(list))
+ {
+ vty_out (vty, " for");
+ for (ALL_LIST_ELEMENTS (list, node, nnode, filter))
+ {
+ if (filter->peer)
+ vty_out (vty, " %s", filter->peer->host);
+
+ if (filter->p)
+ vty_out (vty, " %s/%d",
+ inet_ntop (filter->p->family, &filter->p->u.prefix, buf, INET6_ADDRSTRLEN),
+ filter->p->prefixlen);
+ }
+ }
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+static void
+bgp_debug_list_add_entry(struct list *list, struct peer *peer, struct prefix *p)
+{
+ struct bgp_debug_filter *filter;
+
+ filter = XCALLOC (MTYPE_BGP_DEBUG_FILTER, sizeof (struct bgp_debug_filter));
+
+ if (peer)
+ {
+ peer_lock (peer);
+ filter->peer = peer;
+ filter->p = NULL;
+ }
+ else if (p)
+ {
+ filter->peer = NULL;
+ filter->p = p;
+ }
+
+ listnode_add(list, filter);
+}
+
+static int
+bgp_debug_list_remove_entry(struct list *list, struct peer *peer, struct prefix *p)
+{
+ struct bgp_debug_filter *filter;
+ struct listnode *node, *nnode;
+
+ for (ALL_LIST_ELEMENTS (list, node, nnode, filter))
+ {
+ if (peer && filter->peer == peer)
+ {
+ listnode_delete (list, filter);
+ peer_unlock (filter->peer);
+ XFREE (MTYPE_BGP_DEBUG_FILTER, filter);
+ return 1;
+ }
+ else if (p && filter->p->prefixlen == p->prefixlen && prefix_match(filter->p, p))
+ {
+ listnode_delete (list, filter);
+ prefix_free (filter->p);
+ XFREE (MTYPE_BGP_DEBUG_FILTER, filter);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+bgp_debug_list_has_entry(struct list *list, struct peer *peer, struct prefix *p)
+{
+ struct bgp_debug_filter *filter;
+ struct listnode *node, *nnode;
+
+ for (ALL_LIST_ELEMENTS (list, node, nnode, filter))
+ {
+ if (peer)
+ {
+ if (filter->peer == peer)
+ {
+ return 1;
+ }
+ }
+ else if (p)
+ {
+ if (filter->p->prefixlen == p->prefixlen && prefix_match(filter->p, p))
+ {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
/* Dump attribute. */
int
bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
@@ -276,18 +429,12 @@ bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify,
break;
}
- if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
+ if (BGP_DEBUG (neighbor_events, NEIGHBOR_EVENTS) || bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
zlog_info ("%%NOTIFICATION: %s neighbor %s %d/%d (%s%s) %d bytes %s",
strcmp (direct, "received") == 0 ? "received from" : "sent to",
peer->host, bgp_notify->code, bgp_notify->subcode,
code_str, subcode_str, bgp_notify->length,
bgp_notify->data ? bgp_notify->data : "");
- else if (BGP_DEBUG (normal, NORMAL))
- plog_debug (peer->log, "%s %s NOTIFICATION %d/%d (%s%s) %d bytes %s",
- peer ? peer->host : "",
- direct, bgp_notify->code, bgp_notify->subcode,
- code_str, subcode_str, bgp_notify->length,
- bgp_notify->data ? bgp_notify->data : "");
}
/* Debug option setting interface. */
@@ -334,13 +481,6 @@ DEFUN (no_debug_bgp_as4,
return CMD_SUCCESS;
}
-ALIAS (no_debug_bgp_as4,
- undebug_bgp_as4_cmd,
- "undebug bgp as4",
- UNDEBUG_STR
- BGP_STR
- "BGP AS4 actions\n")
-
DEFUN (debug_bgp_as4_segment,
debug_bgp_as4_segment_cmd,
"debug bgp as4 segment",
@@ -378,140 +518,163 @@ DEFUN (no_debug_bgp_as4_segment,
return CMD_SUCCESS;
}
-ALIAS (no_debug_bgp_as4_segment,
- undebug_bgp_as4_segment_cmd,
- "undebug bgp as4 segment",
- UNDEBUG_STR
- BGP_STR
- "BGP AS4 actions\n"
- "BGP AS4 aspath segment handling\n")
-
-DEFUN (debug_bgp_fsm,
- debug_bgp_fsm_cmd,
- "debug bgp fsm",
+/* debug bgp neighbor_events */
+DEFUN (debug_bgp_neighbor_events,
+ debug_bgp_neighbor_events_cmd,
+ "debug bgp neighbor-events",
DEBUG_STR
BGP_STR
- "BGP Finite State Machine\n")
+ "BGP Neighbor Events\n")
{
if (vty->node == CONFIG_NODE)
- DEBUG_ON (fsm, FSM);
+ DEBUG_ON (neighbor_events, NEIGHBOR_EVENTS);
else
{
- TERM_DEBUG_ON (fsm, FSM);
- vty_out (vty, "BGP fsm debugging is on%s", VTY_NEWLINE);
+ TERM_DEBUG_ON (neighbor_events, NEIGHBOR_EVENTS);
+ vty_out (vty, "BGP neighbor-events debugging is on%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
}
-DEFUN (no_debug_bgp_fsm,
- no_debug_bgp_fsm_cmd,
- "no debug bgp fsm",
- NO_STR
+DEFUN (debug_bgp_neighbor_events_peer,
+ debug_bgp_neighbor_events_peer_cmd,
+ "debug bgp neighbor-events (A.B.C.D|X:X::X:X|WORD)",
DEBUG_STR
BGP_STR
- "Finite State Machine\n")
+ "BGP Neighbor Events\n"
+ "BGP neighbor IP address to debug\n"
+ "BGP IPv6 neighbor to debug\n"
+ "BGP neighbor on interface to debug\n")
{
+ struct peer *peer;
+
+ peer = bgp_find_peer (vty, argv[0]);
+ if (!peer)
+ {
+ vty_out (vty, "%s is not a configured peer%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!bgp_debug_neighbor_events_peers)
+ bgp_debug_neighbor_events_peers = list_new ();
+
+ if (bgp_debug_list_has_entry(bgp_debug_neighbor_events_peers, peer, NULL))
+ {
+ vty_out (vty, "BGP neighbor-events debugging is already enabled for %s%s", peer->host, VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ bgp_debug_list_add_entry(bgp_debug_neighbor_events_peers, peer, NULL);
+
if (vty->node == CONFIG_NODE)
- DEBUG_OFF (fsm, FSM);
+ DEBUG_ON (neighbor_events, NEIGHBOR_EVENTS);
else
{
- TERM_DEBUG_OFF (fsm, FSM);
- vty_out (vty, "BGP fsm debugging is off%s", VTY_NEWLINE);
+ TERM_DEBUG_ON (neighbor_events, NEIGHBOR_EVENTS);
+ vty_out (vty, "BGP neighbor-events debugging is on for %s%s", argv[0], VTY_NEWLINE);
}
return CMD_SUCCESS;
}
-ALIAS (no_debug_bgp_fsm,
- undebug_bgp_fsm_cmd,
- "undebug bgp fsm",
- UNDEBUG_STR
- BGP_STR
- "Finite State Machine\n")
-
-DEFUN (debug_bgp_events,
- debug_bgp_events_cmd,
- "debug bgp events",
+DEFUN (no_debug_bgp_neighbor_events,
+ no_debug_bgp_neighbor_events_cmd,
+ "no debug bgp neighbor-events",
+ NO_STR
DEBUG_STR
BGP_STR
- "BGP events\n")
+ "Neighbor Events\n")
{
+ bgp_debug_list_free(bgp_debug_neighbor_events_peers);
+
if (vty->node == CONFIG_NODE)
- DEBUG_ON (events, EVENTS);
+ DEBUG_OFF (neighbor_events, NEIGHBOR_EVENTS);
else
{
- TERM_DEBUG_ON (events, EVENTS);
- vty_out (vty, "BGP events debugging is on%s", VTY_NEWLINE);
+ TERM_DEBUG_OFF (neighbor_events, NEIGHBOR_EVENTS);
+ vty_out (vty, "BGP neighbor-events debugging is off%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
}
-DEFUN (no_debug_bgp_events,
- no_debug_bgp_events_cmd,
- "no debug bgp events",
+DEFUN (no_debug_bgp_neighbor_events_peer,
+ no_debug_bgp_neighbor_events_peer_cmd,
+ "no debug bgp neighbor-events (A.B.C.D|X:X::X:X|WORD)",
NO_STR
DEBUG_STR
BGP_STR
- "BGP events\n")
+ "Neighbor Events\n"
+ "BGP neighbor IP address to debug\n"
+ "BGP IPv6 neighbor to debug\n"
+ "BGP neighbor on interface to debug\n")
{
- if (vty->node == CONFIG_NODE)
- DEBUG_OFF (events, EVENTS);
- else
+ int found_peer = 0;
+ struct peer *peer;
+
+ peer = bgp_find_peer (vty, argv[0]);
+ if (!peer)
+ {
+ vty_out (vty, "%s is not a configured peer%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (bgp_debug_neighbor_events_peers && !list_isempty(bgp_debug_neighbor_events_peers))
{
- TERM_DEBUG_OFF (events, EVENTS);
- vty_out (vty, "BGP events debugging is off%s", VTY_NEWLINE);
+ found_peer = bgp_debug_list_remove_entry(bgp_debug_neighbor_events_peers, peer, NULL);
+
+ if (list_isempty(bgp_debug_neighbor_events_peers))
+ {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_OFF (neighbor_events, NEIGHBOR_EVENTS);
+ else
+ TERM_DEBUG_OFF (neighbor_events, NEIGHBOR_EVENTS);
+ }
}
+
+ if (found_peer)
+ vty_out (vty, "BGP neighbor-events debugging is off for %s%s", argv[0], VTY_NEWLINE);
+ else
+ vty_out (vty, "BGP neighbor-events debugging was not enabled for %s%s", argv[0], VTY_NEWLINE);
+
return CMD_SUCCESS;
}
-ALIAS (no_debug_bgp_events,
- undebug_bgp_events_cmd,
- "undebug bgp events",
- UNDEBUG_STR
- BGP_STR
- "BGP events\n")
-
-DEFUN (debug_bgp_filter,
- debug_bgp_filter_cmd,
- "debug bgp filters",
+/* debug bgp nht */
+DEFUN (debug_bgp_nht,
+ debug_bgp_nht_cmd,
+ "debug bgp nht",
DEBUG_STR
BGP_STR
- "BGP filters\n")
+ "BGP nexthop tracking events\n")
{
if (vty->node == CONFIG_NODE)
- DEBUG_ON (filter, FILTER);
+ DEBUG_ON (nht, NHT);
else
{
- TERM_DEBUG_ON (filter, FILTER);
- vty_out (vty, "BGP filters debugging is on%s", VTY_NEWLINE);
+ TERM_DEBUG_ON (nht, NHT);
+ vty_out (vty, "BGP nexthop tracking debugging is on%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
}
-DEFUN (no_debug_bgp_filter,
- no_debug_bgp_filter_cmd,
- "no debug bgp filters",
+DEFUN (no_debug_bgp_nht,
+ no_debug_bgp_nht_cmd,
+ "no debug bgp nht",
NO_STR
DEBUG_STR
BGP_STR
- "BGP filters\n")
+ "BGP nexthop tracking events\n")
{
if (vty->node == CONFIG_NODE)
- DEBUG_OFF (filter, FILTER);
+ DEBUG_OFF (nht, NHT);
else
{
- TERM_DEBUG_OFF (filter, FILTER);
- vty_out (vty, "BGP filters debugging is off%s", VTY_NEWLINE);
+ TERM_DEBUG_OFF (nht, NHT);
+ vty_out (vty, "BGP nexthop tracking debugging is off%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
}
-ALIAS (no_debug_bgp_filter,
- undebug_bgp_filter_cmd,
- "undebug bgp filters",
- UNDEBUG_STR
- BGP_STR
- "BGP filters\n")
-
+/* debug bgp keepalives */
DEFUN (debug_bgp_keepalive,
debug_bgp_keepalive_cmd,
"debug bgp keepalives",
@@ -529,6 +692,46 @@ DEFUN (debug_bgp_keepalive,
return CMD_SUCCESS;
}
+DEFUN (debug_bgp_keepalive_peer,
+ debug_bgp_keepalive_peer_cmd,
+ "debug bgp keepalives (A.B.C.D|X:X::X:X|WORD)",
+ DEBUG_STR
+ BGP_STR
+ "BGP Neighbor Events\n"
+ "BGP neighbor IP address to debug\n"
+ "BGP IPv6 neighbor to debug\n"
+ "BGP neighbor on interface to debug\n")
+{
+ struct peer *peer;
+
+ peer = bgp_find_peer (vty, argv[0]);
+ if (!peer)
+ {
+ vty_out (vty, "%s is not a configured peer%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!bgp_debug_keepalive_peers)
+ bgp_debug_keepalive_peers = list_new ();
+
+ if (bgp_debug_list_has_entry(bgp_debug_keepalive_peers, peer, NULL))
+ {
+ vty_out (vty, "BGP keepalive debugging is already enabled for %s%s", peer->host, VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ bgp_debug_list_add_entry(bgp_debug_keepalive_peers, peer, NULL);
+
+ if (vty->node == CONFIG_NODE)
+ DEBUG_ON (keepalive, KEEPALIVE);
+ else
+ {
+ TERM_DEBUG_ON (keepalive, KEEPALIVE);
+ vty_out (vty, "BGP keepalives debugging is on for %s%s", argv[0], VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_bgp_keepalive,
no_debug_bgp_keepalive_cmd,
"no debug bgp keepalives",
@@ -537,6 +740,8 @@ DEFUN (no_debug_bgp_keepalive,
BGP_STR
"BGP keepalives\n")
{
+ bgp_debug_list_free(bgp_debug_keepalive_peers);
+
if (vty->node == CONFIG_NODE)
DEBUG_OFF (keepalive, KEEPALIVE);
else
@@ -547,13 +752,49 @@ DEFUN (no_debug_bgp_keepalive,
return CMD_SUCCESS;
}
-ALIAS (no_debug_bgp_keepalive,
- undebug_bgp_keepalive_cmd,
- "undebug bgp keepalives",
- UNDEBUG_STR
+DEFUN (no_debug_bgp_keepalive_peer,
+ no_debug_bgp_keepalive_peer_cmd,
+ "no debug bgp keepalives (A.B.C.D|X:X::X:X|WORD)",
+ NO_STR
+ DEBUG_STR
BGP_STR
- "BGP keepalives\n")
+ "BGP keepalives\n"
+ "BGP neighbor IP address to debug\n"
+ "BGP IPv6 neighbor to debug\n"
+ "BGP neighbor on interface to debug\n")
+{
+ int found_peer = 0;
+ struct peer *peer;
+
+ peer = bgp_find_peer (vty, argv[0]);
+ if (!peer)
+ {
+ vty_out (vty, "%s is not a configured peer%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (bgp_debug_keepalive_peers && !list_isempty(bgp_debug_keepalive_peers))
+ {
+ found_peer = bgp_debug_list_remove_entry(bgp_debug_keepalive_peers, peer, NULL);
+
+ if (list_isempty(bgp_debug_keepalive_peers))
+ {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_OFF (keepalive, KEEPALIVE);
+ else
+ TERM_DEBUG_OFF (keepalive, KEEPALIVE);
+ }
+ }
+ if (found_peer)
+ vty_out (vty, "BGP keepalives debugging is off for %s%s", argv[0], VTY_NEWLINE);
+ else
+ vty_out (vty, "BGP keepalives debugging was not enabled for %s%s", argv[0], VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+/* debug bgp updates */
DEFUN (debug_bgp_update,
debug_bgp_update_cmd,
"debug bgp updates",
@@ -615,74 +856,299 @@ DEFUN (debug_bgp_update_direct,
return CMD_SUCCESS;
}
-DEFUN (no_debug_bgp_update,
- no_debug_bgp_update_cmd,
- "no debug bgp updates",
- NO_STR
+DEFUN (debug_bgp_update_direct_peer,
+ debug_bgp_update_direct_peer_cmd,
+ "debug bgp updates (in|out) (A.B.C.D|X:X::X:X|WORD)",
DEBUG_STR
BGP_STR
- "BGP updates\n")
+ "BGP updates\n"
+ "Inbound updates\n"
+ "Outbound updates\n"
+ "BGP neighbor IP address to debug\n"
+ "BGP IPv6 neighbor to debug\n"
+ "BGP neighbor on interface to debug\n")
{
+ struct peer *peer;
+ int inbound;
+
+ peer = bgp_find_peer (vty, argv[1]);
+ if (!peer)
+ {
+ vty_out (vty, "%s is not a configured peer%s", argv[1], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+
+ if (!bgp_debug_update_in_peers)
+ bgp_debug_update_in_peers = list_new ();
+
+ if (!bgp_debug_update_out_peers)
+ bgp_debug_update_out_peers = list_new ();
+
+ if (strncmp ("i", argv[0], 1) == 0)
+ inbound = 1;
+ else
+ inbound = 0;
+
+ if (inbound)
+ {
+ if (bgp_debug_list_has_entry(bgp_debug_update_in_peers, peer, NULL))
+ {
+ vty_out (vty, "BGP inbound update debugging is already enabled for %s%s", peer->host, VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+ }
+
+ else
+ {
+ if (bgp_debug_list_has_entry(bgp_debug_update_out_peers, peer, NULL))
+ {
+ vty_out (vty, "BGP outbound update debugging is already enabled for %s%s", peer->host, VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+ }
+
+ if (inbound)
+ bgp_debug_list_add_entry(bgp_debug_update_in_peers, peer, NULL);
+ else
+ bgp_debug_list_add_entry(bgp_debug_update_out_peers, peer, NULL);
+
if (vty->node == CONFIG_NODE)
{
- DEBUG_OFF (update, UPDATE_IN);
- DEBUG_OFF (update, UPDATE_OUT);
+ if (inbound)
+ {
+ DEBUG_OFF (update, UPDATE_OUT);
+ DEBUG_ON (update, UPDATE_IN);
+ }
+ else
+ {
+ DEBUG_OFF (update, UPDATE_IN);
+ DEBUG_ON (update, UPDATE_OUT);
+ }
}
else
{
- TERM_DEBUG_OFF (update, UPDATE_IN);
- TERM_DEBUG_OFF (update, UPDATE_OUT);
- vty_out (vty, "BGP updates debugging is off%s", VTY_NEWLINE);
+ if (inbound)
+ {
+ TERM_DEBUG_OFF (update, UPDATE_OUT);
+ TERM_DEBUG_ON (update, UPDATE_IN);
+ vty_out (vty, "BGP updates debugging is on (inbound) for %s%s", argv[1], VTY_NEWLINE);
+ }
+ else
+ {
+ TERM_DEBUG_OFF (update, UPDATE_IN);
+ TERM_DEBUG_ON (update, UPDATE_OUT);
+ vty_out (vty, "BGP updates debugging is on (outbound) for %s%s", argv[1], VTY_NEWLINE);
+ }
}
return CMD_SUCCESS;
}
-ALIAS (no_debug_bgp_update,
- undebug_bgp_update_cmd,
- "undebug bgp updates",
- UNDEBUG_STR
+DEFUN (no_debug_bgp_update_direct_peer,
+ no_debug_bgp_update_direct_peer_cmd,
+ "no debug bgp updates (in|out) (A.B.C.D|X:X::X:X|WORD)",
+ NO_STR
+ DEBUG_STR
BGP_STR
- "BGP updates\n")
+ "BGP updates\n"
+ "Inbound updates\n"
+ "Outbound updates\n"
+ "BGP neighbor IP address to debug\n"
+ "BGP IPv6 neighbor to debug\n"
+ "BGP neighbor on interface to debug\n")
+{
+ int inbound;
+ int found_peer = 0;
+ struct peer *peer;
+
+ peer = bgp_find_peer (vty, argv[1]);
+ if (!peer)
+ {
+ vty_out (vty, "%s is not a configured peer%s", argv[1], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (strncmp ("i", argv[0], 1) == 0)
+ inbound = 1;
+ else
+ inbound = 0;
+
+ if (inbound && bgp_debug_update_in_peers &&
+ !list_isempty(bgp_debug_update_in_peers))
+ {
+ found_peer = bgp_debug_list_remove_entry(bgp_debug_update_in_peers, peer, NULL);
+
+ if (list_isempty(bgp_debug_update_in_peers))
+ {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_OFF (update, UPDATE_IN);
+ else
+ {
+ TERM_DEBUG_OFF (update, UPDATE_IN);
+ vty_out (vty, "BGP updates debugging (inbound) is off%s", VTY_NEWLINE);
+ }
+ }
+ }
+
+ if (!inbound && bgp_debug_update_out_peers &&
+ !list_isempty(bgp_debug_update_out_peers))
+ {
+ found_peer = bgp_debug_list_remove_entry(bgp_debug_update_out_peers, peer, NULL);
+
+ if (list_isempty(bgp_debug_update_out_peers))
+ {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_OFF (update, UPDATE_OUT);
+ else
+ {
+ TERM_DEBUG_OFF (update, UPDATE_OUT);
+ vty_out (vty, "BGP updates debugging (outbound) is off%s", VTY_NEWLINE);
+ }
+ }
+ }
+
+ if (found_peer)
+ if (inbound)
+ vty_out (vty, "BGP updates debugging (inbound) is off for %s%s", argv[1], VTY_NEWLINE);
+ else
+ vty_out (vty, "BGP updates debugging (outbound) is off for %s%s", argv[1], VTY_NEWLINE);
+ else
+ if (inbound)
+ vty_out (vty, "BGP updates debugging (inbound) was not enabled for %s%s", argv[1], VTY_NEWLINE);
+ else
+ vty_out (vty, "BGP updates debugging (outbound) was not enabled for %s%s", argv[1], VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
-DEFUN (debug_bgp_normal,
- debug_bgp_normal_cmd,
- "debug bgp",
+DEFUN (debug_bgp_update_prefix,
+ debug_bgp_update_prefix_cmd,
+ "debug bgp updates prefix (A.B.C.D/M|X:X::X:X/M)",
DEBUG_STR
- BGP_STR)
+ BGP_STR
+ "BGP updates\n"
+ "Specify a prefix to debug\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "IPv6 prefix <network>/<length>\n")
+
{
+ struct prefix *argv_p;
+ int ret;
+
+ argv_p = prefix_new();
+ ret = str2prefix (argv[0], argv_p);
+ if (!ret)
+ {
+ prefix_free(argv_p);
+ vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+
+ if (!bgp_debug_update_prefixes)
+ bgp_debug_update_prefixes = list_new ();
+
+ if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, argv_p))
+ {
+ vty_out (vty, "BGP updates debugging is already enabled for %s%s", argv[0], VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, argv_p);
+
if (vty->node == CONFIG_NODE)
- DEBUG_ON (normal, NORMAL);
+ {
+ DEBUG_ON (update, UPDATE_PREFIX);
+ }
else
{
- TERM_DEBUG_ON (normal, NORMAL);
- vty_out (vty, "BGP debugging is on%s", VTY_NEWLINE);
+ TERM_DEBUG_ON (update, UPDATE_PREFIX);
+ vty_out (vty, "BGP updates debugging is on for %s%s", argv[0], VTY_NEWLINE);
}
+
return CMD_SUCCESS;
}
-DEFUN (no_debug_bgp_normal,
- no_debug_bgp_normal_cmd,
- "no debug bgp",
+DEFUN (no_debug_bgp_update_prefix,
+ no_debug_bgp_update_prefix_cmd,
+ "no debug bgp updates prefix (A.B.C.D/M|X:X::X:X/M)",
NO_STR
DEBUG_STR
- BGP_STR)
+ BGP_STR
+ "BGP updates\n"
+ "Specify a prefix to debug\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "IPv6 prefix <network>/<length>\n")
+
{
+ struct prefix *argv_p;
+ int found_prefix = 0;
+ int ret;
+
+ argv_p = prefix_new();
+ ret = str2prefix (argv[0], argv_p);
+ if (!ret)
+ {
+ prefix_free(argv_p);
+ vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (bgp_debug_update_prefixes && !list_isempty(bgp_debug_update_prefixes))
+ {
+ found_prefix = bgp_debug_list_remove_entry(bgp_debug_update_prefixes, NULL, argv_p);
+
+ if (list_isempty(bgp_debug_update_prefixes))
+ {
+ if (vty->node == CONFIG_NODE)
+ {
+ DEBUG_OFF (update, UPDATE_PREFIX);
+ }
+ else
+ {
+ TERM_DEBUG_OFF (update, UPDATE_PREFIX);
+ vty_out (vty, "BGP updates debugging (per prefix) is off%s", VTY_NEWLINE);
+ }
+ }
+ }
+
+ if (found_prefix)
+ vty_out (vty, "BGP updates debugging is off for %s%s", argv[0], VTY_NEWLINE);
+ else
+ vty_out (vty, "BGP updates debugging was not enabled for %s%s", argv[0], VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_update,
+ no_debug_bgp_update_cmd,
+ "no debug bgp updates",
+ NO_STR
+ DEBUG_STR
+ BGP_STR
+ "BGP updates\n")
+{
+ bgp_debug_list_free(bgp_debug_update_in_peers);
+ bgp_debug_list_free(bgp_debug_update_out_peers);
+ bgp_debug_list_free(bgp_debug_update_prefixes);
+
if (vty->node == CONFIG_NODE)
- DEBUG_OFF (normal, NORMAL);
+ {
+ DEBUG_OFF (update, UPDATE_IN);
+ DEBUG_OFF (update, UPDATE_OUT);
+ DEBUG_OFF (update, UPDATE_PREFIX);
+ }
else
{
- TERM_DEBUG_OFF (normal, NORMAL);
- vty_out (vty, "BGP debugging is off%s", VTY_NEWLINE);
+ TERM_DEBUG_OFF (update, UPDATE_IN);
+ TERM_DEBUG_OFF (update, UPDATE_OUT);
+ TERM_DEBUG_OFF (update, UPDATE_PREFIX);
+ vty_out (vty, "BGP updates debugging is off%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
}
-ALIAS (no_debug_bgp_normal,
- undebug_bgp_normal_cmd,
- "undebug bgp",
- UNDEBUG_STR
- BGP_STR)
-
+/* debug bgp zebra */
DEFUN (debug_bgp_zebra,
debug_bgp_zebra_cmd,
"debug bgp zebra",
@@ -700,6 +1166,51 @@ DEFUN (debug_bgp_zebra,
return CMD_SUCCESS;
}
+DEFUN (debug_bgp_zebra_prefix,
+ debug_bgp_zebra_prefix_cmd,
+ "debug bgp zebra prefix (A.B.C.D/M|X:X::X:X/M)",
+ DEBUG_STR
+ BGP_STR
+ "BGP Zebra messages\n"
+ "Specify a prefix to debug\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "IPv6 prefix <network>/<length>\n")
+
+{
+ struct prefix *argv_p;
+ int ret;
+
+ argv_p = prefix_new();
+ ret = str2prefix (argv[0], argv_p);
+ if (!ret)
+ {
+ prefix_free(argv_p);
+ vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!bgp_debug_zebra_prefixes)
+ bgp_debug_zebra_prefixes = list_new();
+
+ if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, argv_p))
+ {
+ vty_out (vty, "BGP zebra debugging is already enabled for %s%s", argv[0], VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, argv_p);
+
+ if (vty->node == CONFIG_NODE)
+ DEBUG_ON (zebra, ZEBRA);
+ else
+ {
+ TERM_DEBUG_ON (zebra, ZEBRA);
+ vty_out (vty, "BGP zebra debugging is on for %s%s", argv[0], VTY_NEWLINE);
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_bgp_zebra,
no_debug_bgp_zebra_cmd,
"no debug bgp zebra",
@@ -708,6 +1219,8 @@ DEFUN (no_debug_bgp_zebra,
BGP_STR
"BGP Zebra messages\n")
{
+ bgp_debug_list_free(bgp_debug_zebra_prefixes);
+
if (vty->node == CONFIG_NODE)
DEBUG_OFF (zebra, ZEBRA);
else
@@ -718,43 +1231,82 @@ DEFUN (no_debug_bgp_zebra,
return CMD_SUCCESS;
}
-ALIAS (no_debug_bgp_zebra,
- undebug_bgp_zebra_cmd,
- "undebug bgp zebra",
- UNDEBUG_STR
+DEFUN (no_debug_bgp_zebra_prefix,
+ no_debug_bgp_zebra_prefix_cmd,
+ "no debug bgp zebra prefix (A.B.C.D/M|X:X::X:X/M)",
+ NO_STR
+ DEBUG_STR
BGP_STR
- "BGP Zebra messages\n")
+ "BGP Zebra messages\n"
+ "Specify a prefix to debug\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "IPv6 prefix <network>/<length>\n")
+
+{
+ struct prefix *argv_p;
+ int found_prefix = 0;
+ int ret;
+
+ argv_p = prefix_new();
+ ret = str2prefix (argv[0], argv_p);
+ if (!ret)
+ {
+ prefix_free(argv_p);
+ vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (bgp_debug_zebra_prefixes && !list_isempty(bgp_debug_zebra_prefixes))
+ {
+ found_prefix = bgp_debug_list_remove_entry(bgp_debug_neighbor_events_peers, NULL, argv_p);
+
+ if (list_isempty(bgp_debug_zebra_prefixes))
+ {
+ if (vty->node == CONFIG_NODE)
+ DEBUG_OFF (zebra, ZEBRA);
+ else
+ {
+ TERM_DEBUG_OFF (zebra, ZEBRA);
+ vty_out (vty, "BGP zebra debugging is off%s", VTY_NEWLINE);
+ }
+ }
+ }
-DEFUN (no_debug_bgp_all,
- no_debug_bgp_all_cmd,
- "no debug all bgp",
+ if (found_prefix)
+ vty_out (vty, "BGP zebra debugging is off for %s%s", argv[0], VTY_NEWLINE);
+ else
+ vty_out (vty, "BGP zebra debugging was not enabled for %s%s", argv[0], VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp,
+ no_debug_bgp_cmd,
+ "no debug bgp",
NO_STR
DEBUG_STR
- "Enable all debugging\n"
BGP_STR)
{
- TERM_DEBUG_OFF (normal, NORMAL);
- TERM_DEBUG_OFF (events, EVENTS);
+ bgp_debug_list_free(bgp_debug_neighbor_events_peers);
+ bgp_debug_list_free(bgp_debug_keepalive_peers);
+ bgp_debug_list_free(bgp_debug_update_in_peers);
+ bgp_debug_list_free(bgp_debug_update_out_peers);
+ bgp_debug_list_free(bgp_debug_update_prefixes);
+ bgp_debug_list_free(bgp_debug_zebra_prefixes);
+
TERM_DEBUG_OFF (keepalive, KEEPALIVE);
TERM_DEBUG_OFF (update, UPDATE_IN);
TERM_DEBUG_OFF (update, UPDATE_OUT);
+ TERM_DEBUG_OFF (update, UPDATE_PREFIX);
TERM_DEBUG_OFF (as4, AS4);
TERM_DEBUG_OFF (as4, AS4_SEGMENT);
- TERM_DEBUG_OFF (fsm, FSM);
- TERM_DEBUG_OFF (filter, FILTER);
+ TERM_DEBUG_OFF (neighbor_events, NEIGHBOR_EVENTS);
TERM_DEBUG_OFF (zebra, ZEBRA);
vty_out (vty, "All possible debugging has been turned off%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
-ALIAS (no_debug_bgp_all,
- undebug_bgp_all_cmd,
- "undebug all bgp",
- UNDEBUG_STR
- "Enable all debugging\n"
- BGP_STR)
-
DEFUN (show_debugging_bgp,
show_debugging_bgp_cmd,
"show debugging bgp",
@@ -764,28 +1316,39 @@ DEFUN (show_debugging_bgp,
{
vty_out (vty, "BGP debugging status:%s", VTY_NEWLINE);
- if (BGP_DEBUG (normal, NORMAL))
- vty_out (vty, " BGP debugging is on%s", VTY_NEWLINE);
- if (BGP_DEBUG (events, EVENTS))
- vty_out (vty, " BGP events debugging is on%s", VTY_NEWLINE);
- if (BGP_DEBUG (keepalive, KEEPALIVE))
- vty_out (vty, " BGP keepalives debugging is on%s", VTY_NEWLINE);
- if (BGP_DEBUG (update, UPDATE_IN) && BGP_DEBUG (update, UPDATE_OUT))
- vty_out (vty, " BGP updates debugging is on%s", VTY_NEWLINE);
- else if (BGP_DEBUG (update, UPDATE_IN))
- vty_out (vty, " BGP updates debugging is on (inbound)%s", VTY_NEWLINE);
- else if (BGP_DEBUG (update, UPDATE_OUT))
- vty_out (vty, " BGP updates debugging is on (outbound)%s", VTY_NEWLINE);
- if (BGP_DEBUG (fsm, FSM))
- vty_out (vty, " BGP fsm debugging is on%s", VTY_NEWLINE);
- if (BGP_DEBUG (filter, FILTER))
- vty_out (vty, " BGP filter debugging is on%s", VTY_NEWLINE);
- if (BGP_DEBUG (zebra, ZEBRA))
- vty_out (vty, " BGP zebra debugging is on%s", VTY_NEWLINE);
if (BGP_DEBUG (as4, AS4))
vty_out (vty, " BGP as4 debugging is on%s", VTY_NEWLINE);
+
if (BGP_DEBUG (as4, AS4_SEGMENT))
vty_out (vty, " BGP as4 aspath segment debugging is on%s", VTY_NEWLINE);
+
+ if (BGP_DEBUG (neighbor_events, NEIGHBOR_EVENTS))
+ bgp_debug_list_print (vty, " BGP neighbor-events debugging is on",
+ bgp_debug_neighbor_events_peers);
+
+ if (BGP_DEBUG (keepalive, KEEPALIVE))
+ bgp_debug_list_print (vty, " BGP keepalives debugging is on",
+ bgp_debug_keepalive_peers);
+
+ if (BGP_DEBUG (nht, NHT))
+ vty_out (vty, " BGP next-hop tracking debugging is on%s", VTY_NEWLINE);
+
+ if (BGP_DEBUG (update, UPDATE_PREFIX))
+ bgp_debug_list_print (vty, " BGP updates debugging is on for",
+ bgp_debug_update_prefixes);
+
+ if (BGP_DEBUG (update, UPDATE_IN))
+ bgp_debug_list_print (vty, " BGP updates debugging is on (inbound)",
+ bgp_debug_update_in_peers);
+
+ if (BGP_DEBUG (update, UPDATE_OUT))
+ bgp_debug_list_print (vty, " BGP updates debugging is on (outbound)",
+ bgp_debug_update_out_peers);
+
+ if (BGP_DEBUG (zebra, ZEBRA))
+ bgp_debug_list_print (vty, " BGP zebra debugging is on",
+ bgp_debug_zebra_prefixes);
+
vty_out (vty, "%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -795,12 +1358,6 @@ bgp_config_write_debug (struct vty *vty)
{
int write = 0;
- if (CONF_BGP_DEBUG (normal, NORMAL))
- {
- vty_out (vty, "debug bgp%s", VTY_NEWLINE);
- write++;
- }
-
if (CONF_BGP_DEBUG (as4, AS4))
{
vty_out (vty, "debug bgp as4%s", VTY_NEWLINE);
@@ -813,12 +1370,6 @@ bgp_config_write_debug (struct vty *vty)
write++;
}
- if (CONF_BGP_DEBUG (events, EVENTS))
- {
- vty_out (vty, "debug bgp events%s", VTY_NEWLINE);
- write++;
- }
-
if (CONF_BGP_DEBUG (keepalive, KEEPALIVE))
{
vty_out (vty, "debug bgp keepalives%s", VTY_NEWLINE);
@@ -841,21 +1392,21 @@ bgp_config_write_debug (struct vty *vty)
write++;
}
- if (CONF_BGP_DEBUG (fsm, FSM))
+ if (CONF_BGP_DEBUG (neighbor_events, NEIGHBOR_EVENTS))
{
- vty_out (vty, "debug bgp fsm%s", VTY_NEWLINE);
+ vty_out (vty, "debug bgp neighbor-events%s", VTY_NEWLINE);
write++;
}
- if (CONF_BGP_DEBUG (filter, FILTER))
+ if (CONF_BGP_DEBUG (zebra, ZEBRA))
{
- vty_out (vty, "debug bgp filters%s", VTY_NEWLINE);
+ vty_out (vty, "debug bgp zebra%s", VTY_NEWLINE);
write++;
}
- if (CONF_BGP_DEBUG (zebra, ZEBRA))
+ if (CONF_BGP_DEBUG (nht, NHT))
{
- vty_out (vty, "debug bgp zebra%s", VTY_NEWLINE);
+ vty_out (vty, "debug bgp nht%s", VTY_NEWLINE);
write++;
}
@@ -881,51 +1432,189 @@ bgp_debug_init (void)
install_element (ENABLE_NODE, &debug_bgp_as4_segment_cmd);
install_element (CONFIG_NODE, &debug_bgp_as4_segment_cmd);
- install_element (ENABLE_NODE, &debug_bgp_fsm_cmd);
- install_element (CONFIG_NODE, &debug_bgp_fsm_cmd);
- install_element (ENABLE_NODE, &debug_bgp_events_cmd);
- install_element (CONFIG_NODE, &debug_bgp_events_cmd);
- install_element (ENABLE_NODE, &debug_bgp_filter_cmd);
- install_element (CONFIG_NODE, &debug_bgp_filter_cmd);
+ install_element (ENABLE_NODE, &debug_bgp_neighbor_events_cmd);
+ install_element (CONFIG_NODE, &debug_bgp_neighbor_events_cmd);
+ install_element (ENABLE_NODE, &debug_bgp_nht_cmd);
+ install_element (CONFIG_NODE, &debug_bgp_nht_cmd);
install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd);
install_element (CONFIG_NODE, &debug_bgp_keepalive_cmd);
install_element (ENABLE_NODE, &debug_bgp_update_cmd);
install_element (CONFIG_NODE, &debug_bgp_update_cmd);
install_element (ENABLE_NODE, &debug_bgp_update_direct_cmd);
install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd);
- install_element (ENABLE_NODE, &debug_bgp_normal_cmd);
- install_element (CONFIG_NODE, &debug_bgp_normal_cmd);
install_element (ENABLE_NODE, &debug_bgp_zebra_cmd);
install_element (CONFIG_NODE, &debug_bgp_zebra_cmd);
+ /* deb bgp updates [in|out] A.B.C.D */
+ install_element (ENABLE_NODE, &debug_bgp_update_direct_peer_cmd);
+ install_element (CONFIG_NODE, &debug_bgp_update_direct_peer_cmd);
+ install_element (ENABLE_NODE, &no_debug_bgp_update_direct_peer_cmd);
+ install_element (CONFIG_NODE, &no_debug_bgp_update_direct_peer_cmd);
+
+ /* deb bgp updates prefix A.B.C.D/M */
+ install_element (ENABLE_NODE, &debug_bgp_update_prefix_cmd);
+ install_element (CONFIG_NODE, &debug_bgp_update_prefix_cmd);
+ install_element (ENABLE_NODE, &no_debug_bgp_update_prefix_cmd);
+ install_element (CONFIG_NODE, &no_debug_bgp_update_prefix_cmd);
+
+ /* deb bgp zebra prefix A.B.C.D/M */
+ install_element (ENABLE_NODE, &debug_bgp_zebra_prefix_cmd);
+ install_element (CONFIG_NODE, &debug_bgp_zebra_prefix_cmd);
+ install_element (ENABLE_NODE, &no_debug_bgp_zebra_prefix_cmd);
+ install_element (CONFIG_NODE, &no_debug_bgp_zebra_prefix_cmd);
+
install_element (ENABLE_NODE, &no_debug_bgp_as4_cmd);
- install_element (ENABLE_NODE, &undebug_bgp_as4_cmd);
install_element (CONFIG_NODE, &no_debug_bgp_as4_cmd);
install_element (ENABLE_NODE, &no_debug_bgp_as4_segment_cmd);
- install_element (ENABLE_NODE, &undebug_bgp_as4_segment_cmd);
install_element (CONFIG_NODE, &no_debug_bgp_as4_segment_cmd);
- install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd);
- install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd);
- install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd);
- install_element (ENABLE_NODE, &no_debug_bgp_events_cmd);
- install_element (ENABLE_NODE, &undebug_bgp_events_cmd);
- install_element (CONFIG_NODE, &no_debug_bgp_events_cmd);
- install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd);
- install_element (ENABLE_NODE, &undebug_bgp_filter_cmd);
- install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd);
+ /* deb bgp neighbor-events A.B.C.D */
+ install_element (ENABLE_NODE, &debug_bgp_neighbor_events_peer_cmd);
+ install_element (CONFIG_NODE, &debug_bgp_neighbor_events_peer_cmd);
+ install_element (ENABLE_NODE, &no_debug_bgp_neighbor_events_peer_cmd);
+ install_element (CONFIG_NODE, &no_debug_bgp_neighbor_events_peer_cmd);
+
+ /* deb bgp keepalive A.B.C.D */
+ install_element (ENABLE_NODE, &debug_bgp_keepalive_peer_cmd);
+ install_element (CONFIG_NODE, &debug_bgp_keepalive_peer_cmd);
+ install_element (ENABLE_NODE, &no_debug_bgp_keepalive_peer_cmd);
+ install_element (CONFIG_NODE, &no_debug_bgp_keepalive_peer_cmd);
+
+ install_element (ENABLE_NODE, &no_debug_bgp_neighbor_events_cmd);
+ install_element (CONFIG_NODE, &no_debug_bgp_neighbor_events_cmd);
+ install_element (ENABLE_NODE, &no_debug_bgp_nht_cmd);
+ install_element (CONFIG_NODE, &no_debug_bgp_nht_cmd);
install_element (ENABLE_NODE, &no_debug_bgp_keepalive_cmd);
- install_element (ENABLE_NODE, &undebug_bgp_keepalive_cmd);
install_element (CONFIG_NODE, &no_debug_bgp_keepalive_cmd);
install_element (ENABLE_NODE, &no_debug_bgp_update_cmd);
- install_element (ENABLE_NODE, &undebug_bgp_update_cmd);
install_element (CONFIG_NODE, &no_debug_bgp_update_cmd);
- install_element (ENABLE_NODE, &no_debug_bgp_normal_cmd);
- install_element (ENABLE_NODE, &undebug_bgp_normal_cmd);
- install_element (CONFIG_NODE, &no_debug_bgp_normal_cmd);
install_element (ENABLE_NODE, &no_debug_bgp_zebra_cmd);
- install_element (ENABLE_NODE, &undebug_bgp_zebra_cmd);
install_element (CONFIG_NODE, &no_debug_bgp_zebra_cmd);
- install_element (ENABLE_NODE, &no_debug_bgp_all_cmd);
- install_element (ENABLE_NODE, &undebug_bgp_all_cmd);
+ install_element (ENABLE_NODE, &no_debug_bgp_cmd);
+}
+
+/* Return true if this prefix is on the per_prefix_list of prefixes to debug
+ * for BGP_DEBUG_TYPE
+ */
+static int
+bgp_debug_per_prefix (struct prefix *p, unsigned long term_bgp_debug_type,
+ unsigned int BGP_DEBUG_TYPE, struct list *per_prefix_list)
+{
+ struct bgp_debug_filter *filter;
+ struct listnode *node, *nnode;
+
+ if (term_bgp_debug_type & BGP_DEBUG_TYPE)
+ {
+ /* We are debugging all prefixes so return true */
+ if (!per_prefix_list || list_isempty(per_prefix_list))
+ return 1;
+
+ else
+ {
+ if (!p)
+ return 0;
+
+ for (ALL_LIST_ELEMENTS (per_prefix_list, node, nnode, filter))
+ if (filter->p->prefixlen == p->prefixlen && prefix_match(filter->p, p))
+ return 1;
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/* Return true if this peer is on the per_peer_list of peers to debug
+ * for BGP_DEBUG_TYPE
+ */
+static int
+bgp_debug_per_peer(struct peer *peer, unsigned long term_bgp_debug_type,
+ unsigned int BGP_DEBUG_TYPE, struct list *per_peer_list)
+{
+ struct bgp_debug_filter *filter;
+ struct listnode *node, *nnode;
+
+ if (term_bgp_debug_type & BGP_DEBUG_TYPE)
+ {
+ /* We are debugging all peers so return true */
+ if (!per_peer_list || list_isempty(per_peer_list))
+ return 1;
+
+ else
+ {
+ if (!peer)
+ return 0;
+
+ for (ALL_LIST_ELEMENTS (per_peer_list, node, nnode, filter))
+ if (filter->peer == peer)
+ return 1;
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+int
+bgp_debug_neighbor_events (struct peer *peer)
+{
+ return bgp_debug_per_peer (peer,
+ term_bgp_debug_neighbor_events,
+ BGP_DEBUG_NEIGHBOR_EVENTS,
+ bgp_debug_neighbor_events_peers);
+}
+
+int
+bgp_debug_keepalive (struct peer *peer)
+{
+ return bgp_debug_per_peer (peer,
+ term_bgp_debug_keepalive,
+ BGP_DEBUG_KEEPALIVE,
+ bgp_debug_keepalive_peers);
+}
+
+int
+bgp_debug_update (struct peer *peer, struct prefix *p, unsigned int inbound)
+{
+ if (inbound)
+ {
+ if (bgp_debug_per_peer (peer, term_bgp_debug_update, BGP_DEBUG_UPDATE_IN,
+ bgp_debug_update_in_peers))
+ return 1;
+ }
+
+ /* outbound */
+ else
+ {
+ if (bgp_debug_per_peer (peer, term_bgp_debug_update,
+ BGP_DEBUG_UPDATE_OUT,
+ bgp_debug_update_out_peers))
+ return 1;
+ }
+
+
+ if (BGP_DEBUG (update, UPDATE_PREFIX))
+ {
+ if (bgp_debug_per_prefix (p, term_bgp_debug_update,
+ BGP_DEBUG_UPDATE_PREFIX,
+ bgp_debug_update_prefixes))
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+bgp_debug_zebra (struct prefix *p)
+{
+ if (BGP_DEBUG (zebra, ZEBRA))
+ {
+ if (bgp_debug_per_prefix (p, term_bgp_debug_zebra, BGP_DEBUG_ZEBRA,
+ bgp_debug_zebra_prefixes))
+ return 1;
+ }
+
+ return 0;
}
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index ce8547b0..b8ad7b9c 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -59,44 +59,49 @@ extern void bgp_packet_dump (struct stream *);
extern int debug (unsigned int option);
extern unsigned long conf_bgp_debug_as4;
-extern unsigned long conf_bgp_debug_fsm;
-extern unsigned long conf_bgp_debug_events;
+extern unsigned long conf_bgp_debug_neighbor_events;
extern unsigned long conf_bgp_debug_packet;
-extern unsigned long conf_bgp_debug_filter;
extern unsigned long conf_bgp_debug_keepalive;
extern unsigned long conf_bgp_debug_update;
-extern unsigned long conf_bgp_debug_normal;
extern unsigned long conf_bgp_debug_zebra;
+extern unsigned long conf_bgp_debug_nht;
extern unsigned long term_bgp_debug_as4;
-extern unsigned long term_bgp_debug_fsm;
-extern unsigned long term_bgp_debug_events;
+extern unsigned long term_bgp_debug_neighbor_events;
extern unsigned long term_bgp_debug_packet;
-extern unsigned long term_bgp_debug_filter;
extern unsigned long term_bgp_debug_keepalive;
extern unsigned long term_bgp_debug_update;
-extern unsigned long term_bgp_debug_normal;
extern unsigned long term_bgp_debug_zebra;
+extern unsigned long term_bgp_debug_nht;
+
+extern struct list *bgp_debug_neighbor_events_peers;
+extern struct list *bgp_debug_keepalive_peers;
+extern struct list *bgp_debug_update_in_peers;
+extern struct list *bgp_debug_update_out_peers;
+extern struct list *bgp_debug_update_prefixes;
+extern struct list *bgp_debug_zebra_prefixes;
+
+struct bgp_debug_filter
+{
+ struct peer *peer;
+ struct prefix *p;
+};
#define BGP_DEBUG_AS4 0x01
#define BGP_DEBUG_AS4_SEGMENT 0x02
-#define BGP_DEBUG_FSM 0x01
-#define BGP_DEBUG_EVENTS 0x01
+#define BGP_DEBUG_NEIGHBOR_EVENTS 0x01
#define BGP_DEBUG_PACKET 0x01
-#define BGP_DEBUG_FILTER 0x01
#define BGP_DEBUG_KEEPALIVE 0x01
#define BGP_DEBUG_UPDATE_IN 0x01
#define BGP_DEBUG_UPDATE_OUT 0x02
-#define BGP_DEBUG_NORMAL 0x01
+#define BGP_DEBUG_UPDATE_PREFIX 0x04
#define BGP_DEBUG_ZEBRA 0x01
+#define BGP_DEBUG_NHT 0x01
#define BGP_DEBUG_PACKET_SEND 0x01
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
-#define BGP_DEBUG_PACKET_RECV 0x01
-#define BGP_DEBUG_PACKET_RECV_DETAIL 0x02
-
#define CONF_DEBUG_ON(a, b) (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b))
#define CONF_DEBUG_OFF(a, b) (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b))
@@ -124,5 +129,9 @@ extern void bgp_notify_print (struct peer *, struct bgp_notify *, const char *);
extern const struct message bgp_status_msg[];
extern const int bgp_status_msg_max;
+extern int bgp_debug_neighbor_events(struct peer *peer);
+extern int bgp_debug_keepalive(struct peer *peer);
+extern int bgp_debug_update(struct peer *peer, struct prefix *p, unsigned int inbound);
+extern int bgp_debug_zebra(struct prefix *p);
#endif /* _QUAGGA_BGP_DEBUG_H */
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 5d69b42c..11b02768 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "prefix.h"
#include "command.h"
#include "filter.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c
index 26819fc1..fd282b8e 100644
--- a/bgpd/bgp_filter.c
+++ b/bgpd/bgp_filter.c
@@ -25,6 +25,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "memory.h"
#include "buffer.h"
#include "filter.h"
+#include "linklist.h"
+#include "prefix.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h"
@@ -48,10 +50,10 @@ struct as_list_master
struct as_list_list str;
/* Hook function which is executed when new access_list is added. */
- void (*add_hook) (void);
+ void (*add_hook) (char *);
/* Hook function which is executed when access_list is deleted. */
- void (*delete_hook) (void);
+ void (*delete_hook) (const char *);
};
/* Element of AS path filter. */
@@ -145,6 +147,11 @@ as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter)
else
aslist->head = asfilter;
aslist->tail = asfilter;
+
+ /* Run hook function. */
+ if (as_list_master.add_hook)
+ (*as_list_master.add_hook) (aslist->name);
+
}
/* Lookup as_list from list of as_list by name. */
@@ -278,13 +285,7 @@ as_list_get (const char *name)
aslist = as_list_lookup (name);
if (aslist == NULL)
- {
- aslist = as_list_insert (name);
-
- /* Run hook function. */
- if (as_list_master.add_hook)
- (*as_list_master.add_hook) ();
- }
+ aslist = as_list_insert (name);
return aslist;
}
@@ -345,6 +346,8 @@ as_list_empty (struct as_list *aslist)
static void
as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter)
{
+ char *name = strdup (aslist->name);
+
if (asfilter->next)
asfilter->next->prev = asfilter->prev;
else
@@ -363,7 +366,9 @@ as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter)
/* Run hook function. */
if (as_list_master.delete_hook)
- (*as_list_master.delete_hook) ();
+ (*as_list_master.delete_hook) (name);
+ if (name)
+ free(name);
}
static int
@@ -396,14 +401,14 @@ as_list_apply (struct as_list *aslist, void *object)
/* Add hook function. */
void
-as_list_add_hook (void (*func) (void))
+as_list_add_hook (void (*func) (char *))
{
as_list_master.add_hook = func;
}
/* Delete hook function. */
void
-as_list_delete_hook (void (*func) (void))
+as_list_delete_hook (void (*func) (const char *))
{
as_list_master.delete_hook = func;
}
@@ -567,7 +572,7 @@ DEFUN (no_ip_as_path_all,
/* Run hook function. */
if (as_list_master.delete_hook)
- (*as_list_master.delete_hook) ();
+ (*as_list_master.delete_hook) (argv[0]);
return CMD_SUCCESS;
}
diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h
index c1da9041..03447942 100644
--- a/bgpd/bgp_filter.h
+++ b/bgpd/bgp_filter.h
@@ -33,7 +33,7 @@ extern void bgp_filter_reset (void);
extern enum as_filter_type as_list_apply (struct as_list *, void *);
extern struct as_list *as_list_lookup (const char *);
-extern void as_list_add_hook (void (*func) (void));
-extern void as_list_delete_hook (void (*func) (void));
+extern void as_list_add_hook (void (*func) (char *));
+extern void as_list_delete_hook (void (*func) (const char *));
#endif /* _QUAGGA_BGP_FILTER_H */
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index c4cfd58e..7dd0b8e2 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -42,6 +42,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_dump.h"
#include "bgpd/bgp_open.h"
+#include "bgpd/bgp_advertise.h"
+#include "bgpd/bgp_nht.h"
#ifdef HAVE_SNMP
#include "bgpd/bgp_snmp.h"
#endif /* HAVE_SNMP */
@@ -63,11 +65,101 @@ static int bgp_keepalive_timer (struct thread *);
/* BGP FSM functions. */
static int bgp_start (struct peer *);
-/* BGP start timer jitter. */
-static int
-bgp_start_jitter (int time)
+static void
+peer_xfer_stats (struct peer *peer_dst, struct peer *peer_src)
{
- return ((random () % (time + 1)) - (time / 2));
+ /* Copy stats over. These are only the pre-established state stats */
+ peer_dst->open_in += peer_src->open_in;
+ peer_dst->open_out += peer_src->open_out;
+ peer_dst->keepalive_in += peer_src->keepalive_in;
+ peer_dst->keepalive_out += peer_src->keepalive_out;
+ peer_dst->notify_in += peer_src->notify_in;
+ peer_dst->notify_out += peer_src->notify_out;
+ peer_dst->dynamic_cap_in += peer_src->dynamic_cap_in;
+ peer_dst->dynamic_cap_out += peer_src->dynamic_cap_out;
+}
+
+static struct peer *
+peer_xfer_conn(struct peer *from_peer)
+{
+ struct peer *peer;
+ afi_t afi;
+ safi_t safi;
+ int fd;
+ int status, pstatus;
+
+ assert(from_peer != NULL);
+
+ peer = from_peer->doppelganger;
+
+ if (!peer || !CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+ return from_peer;
+
+ BGP_WRITE_OFF(peer->t_write);
+ BGP_READ_OFF(peer->t_read);
+ BGP_WRITE_OFF(from_peer->t_write);
+ BGP_READ_OFF(from_peer->t_read);
+
+ fd = peer->fd;
+ peer->fd = from_peer->fd;
+ from_peer->fd = fd;
+ stream_reset(peer->ibuf);
+ stream_fifo_clean(peer->obuf);
+ stream_fifo_clean(from_peer->obuf);
+
+ peer->v_holdtime = from_peer->v_holdtime;
+ peer->v_keepalive = from_peer->v_keepalive;
+ peer->routeadv = from_peer->routeadv;
+ peer->v_routeadv = from_peer->v_routeadv;
+ peer->v_gr_restart = from_peer->v_gr_restart;
+ peer->cap = from_peer->cap;
+ status = peer->status;
+ pstatus = peer->ostatus;
+ peer->status = from_peer->status;
+ peer->ostatus = from_peer->ostatus;
+ from_peer->status = status;
+ from_peer->ostatus = pstatus;
+ peer->remote_id = from_peer->remote_id;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ peer->af_flags[afi][safi] = from_peer->af_flags[afi][safi];
+ peer->af_sflags[afi][safi] = from_peer->af_sflags[afi][safi];
+ peer->af_cap[afi][safi] = from_peer->af_cap[afi][safi];
+ peer->afc_nego[afi][safi] = from_peer->afc_nego[afi][safi];
+ peer->afc_adv[afi][safi] = from_peer->afc_adv[afi][safi];
+ peer->afc_recv[afi][safi] = from_peer->afc_recv[afi][safi];
+ }
+
+ if (bgp_getsockname(peer) < 0)
+ {
+ zlog_err ("%%bgp_getsockname() failed for %s peer %s fd %d (from_peer fd %d)",
+ (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER) ? "accept" : ""),
+ peer->host, peer->fd, from_peer->fd);
+ bgp_stop(peer);
+ bgp_stop(from_peer);
+ return NULL;
+ }
+ if (from_peer->status > Active)
+ {
+ if (bgp_getsockname(from_peer) < 0)
+ {
+ zlog_err ("%%bgp_getsockname() failed for %s from_peer %s fd %d (peer fd %d)",
+ (CHECK_FLAG (from_peer->sflags, PEER_STATUS_ACCEPT_PEER) ? "accept" : ""),
+ from_peer->host, from_peer->fd, peer->fd);
+ bgp_stop(from_peer);
+ from_peer = NULL;
+ }
+ }
+
+ BGP_READ_ON(peer->t_read, bgp_read, peer->fd);
+ BGP_WRITE_ON(peer->t_write, bgp_write, peer->fd);
+
+ if (from_peer)
+ peer_xfer_stats(peer, from_peer);
+
+ return(peer);
}
/* Check if suppress start/restart of sessions to peer. */
@@ -81,8 +173,6 @@ bgp_start_jitter (int time)
void
bgp_timer_set (struct peer *peer)
{
- int jitter = 0;
-
switch (peer->status)
{
case Idle:
@@ -95,9 +185,8 @@ bgp_timer_set (struct peer *peer)
}
else
{
- jitter = bgp_start_jitter (peer->v_start);
BGP_TIMER_ON (peer->t_start, bgp_start_timer,
- peer->v_start + jitter);
+ peer->v_start);
}
BGP_TIMER_OFF (peer->t_connect);
BGP_TIMER_OFF (peer->t_holdtime);
@@ -106,7 +195,7 @@ bgp_timer_set (struct peer *peer)
break;
case Connect:
- /* After start timer is expired, the peer moves to Connnect
+ /* After start timer is expired, the peer moves to Connect
status. Make sure start timer is off and connect timer is
on. */
BGP_TIMER_OFF (peer->t_start);
@@ -205,6 +294,7 @@ bgp_timer_set (struct peer *peer)
BGP_TIMER_OFF (peer->t_holdtime);
BGP_TIMER_OFF (peer->t_keepalive);
BGP_TIMER_OFF (peer->t_routeadv);
+ break;
}
}
@@ -218,9 +308,8 @@ bgp_start_timer (struct thread *thread)
peer = THREAD_ARG (thread);
peer->t_start = NULL;
- if (BGP_DEBUG (fsm, FSM))
- zlog (peer->log, LOG_DEBUG,
- "%s [FSM] Timer (start timer expire).", peer->host);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s [FSM] Timer (start timer expire).", peer->host);
THREAD_VAL (thread) = BGP_Start;
bgp_event (thread); /* bgp_event unlocks peer */
@@ -233,18 +322,27 @@ static int
bgp_connect_timer (struct thread *thread)
{
struct peer *peer;
+ int ret;
peer = THREAD_ARG (thread);
peer->t_connect = NULL;
- if (BGP_DEBUG (fsm, FSM))
- zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (connect timer expire)",
- peer->host);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s [FSM] Timer (connect timer expire)", peer->host);
- THREAD_VAL (thread) = ConnectRetry_timer_expired;
- bgp_event (thread); /* bgp_event unlocks peer */
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ {
+ bgp_stop(peer);
+ ret = -1;
+ }
+ else
+ {
+ THREAD_VAL (thread) = ConnectRetry_timer_expired;
+ bgp_event (thread); /* bgp_event unlocks peer */
+ ret = 0;
+ }
- return 0;
+ return ret;
}
/* BGP holdtime timer. */
@@ -256,10 +354,8 @@ bgp_holdtime_timer (struct thread *thread)
peer = THREAD_ARG (thread);
peer->t_holdtime = NULL;
- if (BGP_DEBUG (fsm, FSM))
- zlog (peer->log, LOG_DEBUG,
- "%s [FSM] Timer (holdtime timer expire)",
- peer->host);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s [FSM] Timer (holdtime timer expire)", peer->host);
THREAD_VAL (thread) = Hold_Timer_expired;
bgp_event (thread); /* bgp_event unlocks peer */
@@ -276,10 +372,8 @@ bgp_keepalive_timer (struct thread *thread)
peer = THREAD_ARG (thread);
peer->t_keepalive = NULL;
- if (BGP_DEBUG (fsm, FSM))
- zlog (peer->log, LOG_DEBUG,
- "%s [FSM] Timer (keepalive timer expire)",
- peer->host);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s [FSM] Timer (keepalive timer expire)", peer->host);
THREAD_VAL (thread) = KeepAlive_timer_expired;
bgp_event (thread); /* bgp_event unlocks peer */
@@ -288,24 +382,40 @@ bgp_keepalive_timer (struct thread *thread)
}
static int
+bgp_routeq_empty (struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ if (!FIFO_EMPTY(&peer->sync[afi][safi]->withdraw) ||
+ !FIFO_EMPTY(&peer->sync[afi][safi]->update))
+ return 0;
+ }
+ return 1;
+}
+
+static int
bgp_routeadv_timer (struct thread *thread)
{
struct peer *peer;
peer = THREAD_ARG (thread);
peer->t_routeadv = NULL;
+ peer->radv_adjusted = 0;
- if (BGP_DEBUG (fsm, FSM))
- zlog (peer->log, LOG_DEBUG,
- "%s [FSM] Timer (routeadv timer expire)",
- peer->host);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s [FSM] Timer (routeadv timer expire)", peer->host);
peer->synctime = bgp_clock ();
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
- BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer,
- peer->v_routeadv);
+ /* MRAI timer is no longer restarted here, it would be done
+ * when the FIFO is built.
+ */
return 0;
}
@@ -357,7 +467,7 @@ bgp_graceful_restart_timer_expire (struct thread *thread)
UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
BGP_TIMER_OFF (peer->t_gr_stale);
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
{
zlog_debug ("%s graceful restart timer expired", peer->host);
zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
@@ -378,7 +488,7 @@ bgp_graceful_stale_timer_expire (struct thread *thread)
peer = THREAD_ARG (thread);
peer->t_gr_stale = NULL;
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s graceful restart stalepath timer expired", peer->host);
/* NSF delete stale route */
@@ -390,11 +500,396 @@ bgp_graceful_stale_timer_expire (struct thread *thread)
return 0;
}
+static int
+bgp_update_delay_applicable (struct bgp *bgp)
+{
+ /* update_delay_over flag should be reset (set to 0) for any new
+ applicability of the update-delay during BGP process lifetime.
+ And it should be set after an occurence of the update-delay is over)*/
+ if (!bgp->update_delay_over)
+ return 1;
+
+ return 0;
+}
+
+int
+bgp_update_delay_active (struct bgp *bgp)
+{
+ if (bgp->t_update_delay)
+ return 1;
+
+ return 0;
+}
+
+int
+bgp_update_delay_configured (struct bgp *bgp)
+{
+ if (bgp->v_update_delay)
+ return 1;
+
+ return 0;
+}
+
+/* Do the post-processing needed when bgp comes out of the read-only mode
+ on ending the update delay. */
+void
+bgp_update_delay_end (struct bgp *bgp)
+{
+ THREAD_TIMER_OFF (bgp->t_update_delay);
+ THREAD_TIMER_OFF (bgp->t_establish_wait);
+
+ /* Reset update-delay related state */
+ bgp->update_delay_over = 1;
+ bgp->established = 0;
+ bgp->restarted_peers = 0;
+ bgp->implicit_eors = 0;
+ bgp->explicit_eors = 0;
+
+ quagga_timestamp(3, bgp->update_delay_end_time,
+ sizeof(bgp->update_delay_end_time));
+
+ /*
+ * Add an end-of-initial-update marker to the main process queues so that
+ * the route advertisement timer for the peers can be started. Also set
+ * the zebra and peer update hold flags. These flags are used to achieve
+ * three stages in the update-delay post processing:
+ * 1. Finish best-path selection for all the prefixes held on the queues.
+ * (routes in BGP are updated, and peers sync queues are populated too)
+ * 2. As the eoiu mark is reached in the bgp process routine, ship all the
+ * routes to zebra. With that zebra should see updates from BGP close
+ * to each other.
+ * 3. Unblock the peer update writes. With that peer update packing with
+ * the prefixes should be at its maximum.
+ */
+ bgp_add_eoiu_mark(bgp, BGP_TABLE_MAIN);
+ bgp_add_eoiu_mark(bgp, BGP_TABLE_RSCLIENT);
+ bgp->main_zebra_update_hold = 1;
+ bgp->main_peers_update_hold = 1;
+ bgp->rsclient_peers_update_hold = 1;
+
+ /* Resume the queue processing. This should trigger the event that would take
+ care of processing any work that was queued during the read-only mode. */
+ work_queue_unplug(bm->process_main_queue);
+ work_queue_unplug(bm->process_rsclient_queue);
+}
+
+/**
+ * see bgp_fsm.h
+ */
+void
+bgp_start_routeadv (struct bgp *bgp)
+{
+ struct listnode *node, *nnode;
+ struct peer *peer;
+
+ zlog_info("bgp_start_routeadv(), update hold status - main: %d, rsclient: %d",
+ bgp->main_peers_update_hold, bgp->rsclient_peers_update_hold);
+
+ if (bgp->main_peers_update_hold || bgp->rsclient_peers_update_hold)
+ return;
+
+ quagga_timestamp(3, bgp->update_delay_peers_resume_time,
+ sizeof(bgp->update_delay_peers_resume_time));
+
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+ if (peer->status != Established)
+ continue;
+ BGP_TIMER_OFF(peer->t_routeadv);
+ BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0);
+ }
+}
+
+/**
+ * see bgp_fsm.h
+ */
+void
+bgp_adjust_routeadv (struct peer *peer)
+{
+ time_t nowtime = bgp_clock();
+ double diff;
+ unsigned long remain;
+
+ /* Bypass checks for special case of MRAI being 0 */
+ if (peer->v_routeadv == 0)
+ {
+ /* Stop existing timer, just in case it is running for a different
+ * duration and schedule write thread immediately.
+ */
+ if (peer->t_routeadv)
+ BGP_TIMER_OFF(peer->t_routeadv);
+
+ peer->synctime = bgp_clock ();
+ BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+ return;
+ }
+
+ /* Mark that we've adjusted the timer */
+ peer->radv_adjusted = 1;
+
+
+ /*
+ * CASE I:
+ * If the last update was written more than MRAI back, expire the timer
+ * instantly so that we can send the update out sooner.
+ *
+ * <------- MRAI --------->
+ * |-----------------|-----------------------|
+ * <------------- m ------------>
+ * ^ ^ ^
+ * | | |
+ * | | current time
+ * | timer start
+ * last write
+ *
+ * m > MRAI
+ */
+ diff = difftime(nowtime, peer->last_write);
+ if (diff > (double) peer->v_routeadv)
+ {
+ BGP_TIMER_OFF(peer->t_routeadv);
+ BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0);
+ if (bgp_debug_update(peer, NULL, 0))
+ zlog_debug ("%s: MRAI timer to expire instantly", peer->host);
+ return;
+ }
+
+ /*
+ * CASE II:
+ * - Find when to expire the MRAI timer.
+ * If MRAI timer is not active, assume we can start it now.
+ *
+ * <------- MRAI --------->
+ * |------------|-----------------------|
+ * <-------- m ----------><----- r ----->
+ * ^ ^ ^
+ * | | |
+ * | | current time
+ * | timer start
+ * last write
+ *
+ * (MRAI - m) < r
+ */
+ if (peer->t_routeadv)
+ remain = thread_timer_remain_second(peer->t_routeadv);
+ else
+ remain = peer->v_routeadv;
+ diff = peer->v_routeadv - diff;
+ if (diff <= (double) remain)
+ {
+ BGP_TIMER_OFF(peer->t_routeadv);
+ BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, diff);
+ if (bgp_debug_update(peer, NULL, 0))
+ zlog_debug ("%s: MRAI timer to expire in %f secs", peer->host, diff);
+ }
+}
+
+static int
+bgp_maxmed_onstartup_applicable (struct bgp *bgp)
+{
+ if (!bgp->maxmed_onstartup_over)
+ return 1;
+
+ return 0;
+}
+
+int
+bgp_maxmed_onstartup_configured (struct bgp *bgp)
+{
+ if (bgp->v_maxmed_onstartup != BGP_MAXMED_ONSTARTUP_UNCONFIGURED)
+ return 1;
+
+ return 0;
+}
+
+int
+bgp_maxmed_onstartup_active (struct bgp *bgp)
+{
+ if (bgp->t_maxmed_onstartup)
+ return 1;
+
+ return 0;
+}
+
+void
+bgp_maxmed_update (struct bgp *bgp)
+{
+ struct listnode *node, *nnode;
+ struct peer *peer;
+ u_char maxmed_active;
+ u_int32_t maxmed_value;
+
+ if (bgp->v_maxmed_admin)
+ {
+ maxmed_active = 1;
+ maxmed_value = bgp->maxmed_admin_value;
+ }
+ else if (bgp->t_maxmed_onstartup)
+ {
+ maxmed_active = 1;
+ maxmed_value = bgp->maxmed_onstartup_value;
+ }
+ else
+ {
+ maxmed_active = 0;
+ maxmed_value = BGP_MAXMED_VALUE_DEFAULT;
+ }
+
+ if (bgp->maxmed_active != maxmed_active ||
+ bgp->maxmed_value != maxmed_value)
+ {
+ bgp->maxmed_active = maxmed_active;
+ bgp->maxmed_value = maxmed_value;
+
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ bgp_announce_route_all (peer);
+ }
+}
+
+/* The maxmed onstartup timer expiry callback. */
+static int
+bgp_maxmed_onstartup_timer (struct thread *thread)
+{
+ struct bgp *bgp;
+
+ zlog_info ("Max med on startup ended - timer expired.");
+
+ bgp = THREAD_ARG (thread);
+ THREAD_TIMER_OFF (bgp->t_maxmed_onstartup);
+ bgp->maxmed_onstartup_over = 1;
+
+ bgp_maxmed_update(bgp);
+
+ return 0;
+}
+
+static void
+bgp_maxmed_onstartup_begin (struct bgp *bgp)
+{
+ /* Applicable only once in the process lifetime on the startup */
+ if (bgp->maxmed_onstartup_over)
+ return;
+
+ zlog_info ("Begin maxmed onstartup mode - timer %d seconds",
+ bgp->v_maxmed_onstartup);
+
+ THREAD_TIMER_ON (bm->master, bgp->t_maxmed_onstartup,
+ bgp_maxmed_onstartup_timer,
+ bgp, bgp->v_maxmed_onstartup);
+
+ if (!bgp->v_maxmed_admin)
+ {
+ bgp->maxmed_active = 1;
+ bgp->maxmed_value = bgp->maxmed_onstartup_value;
+ }
+
+ /* Route announce to all peers should happen after this in bgp_establish() */
+}
+
+static void
+bgp_maxmed_onstartup_process_status_change(struct peer *peer)
+{
+ if (peer->status == Established && !peer->bgp->established)
+ {
+ bgp_maxmed_onstartup_begin(peer->bgp);
+ }
+}
+
+/* The update delay timer expiry callback. */
+static int
+bgp_update_delay_timer (struct thread *thread)
+{
+ struct bgp *bgp;
+
+ zlog_info ("Update delay ended - timer expired.");
+
+ bgp = THREAD_ARG (thread);
+ THREAD_TIMER_OFF (bgp->t_update_delay);
+ bgp_update_delay_end(bgp);
+
+ return 0;
+}
+
+/* The establish wait timer expiry callback. */
+static int
+bgp_establish_wait_timer (struct thread *thread)
+{
+ struct bgp *bgp;
+
+ zlog_info ("Establish wait - timer expired.");
+
+ bgp = THREAD_ARG (thread);
+ THREAD_TIMER_OFF (bgp->t_establish_wait);
+ bgp_check_update_delay(bgp);
+
+ return 0;
+}
+
+/* Steps to begin the update delay:
+ - initialize queues if needed
+ - stop the queue processing
+ - start the timer */
+static void
+bgp_update_delay_begin (struct bgp *bgp)
+{
+ struct listnode *node, *nnode;
+ struct peer *peer;
+
+ if ((bm->process_main_queue == NULL) ||
+ (bm->process_rsclient_queue == NULL))
+ bgp_process_queue_init();
+
+ /* Stop the processing of queued work. Enqueue shall continue */
+ work_queue_plug(bm->process_main_queue);
+ work_queue_plug(bm->process_rsclient_queue);
+
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ peer->update_delay_over = 0;
+
+ /* Start the update-delay timer */
+ THREAD_TIMER_ON (bm->master, bgp->t_update_delay, bgp_update_delay_timer,
+ bgp, bgp->v_update_delay);
+
+ if (bgp->v_establish_wait != bgp->v_update_delay)
+ THREAD_TIMER_ON (bm->master, bgp->t_establish_wait, bgp_establish_wait_timer,
+ bgp, bgp->v_establish_wait);
+
+ quagga_timestamp(3, bgp->update_delay_begin_time,
+ sizeof(bgp->update_delay_begin_time));
+}
+
+static void
+bgp_update_delay_process_status_change(struct peer *peer)
+{
+ if (peer->status == Established)
+ {
+ if (!peer->bgp->established++)
+ {
+ bgp_update_delay_begin(peer->bgp);
+ zlog_info ("Begin read-only mode - update-delay timer %d seconds",
+ peer->bgp->v_update_delay);
+ }
+ if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV))
+ bgp_update_restarted_peers(peer);
+ }
+ if (peer->ostatus == Established && bgp_update_delay_active(peer->bgp))
+ {
+ /* Adjust the update-delay state to account for this flap.
+ NOTE: Intentionally skipping adjusting implicit_eors or explicit_eors
+ counters. Extra sanity check in bgp_check_update_delay() should
+ be enough to take care of any additive discrepancy in bgp eor
+ counters */
+ peer->bgp->established--;
+ peer->update_delay_over = 0;
+ }
+}
+
/* Called after event occured, this function change status and reset
read/write and timer thread. */
void
bgp_fsm_change_status (struct peer *peer, int status)
{
+
bgp_dump_state (peer, peer->status, status);
/* Transition into Clearing or Deleted must /always/ clear all routes..
@@ -422,8 +917,26 @@ bgp_fsm_change_status (struct peer *peer, int status)
/* Preserve old status and change into new status. */
peer->ostatus = peer->status;
peer->status = status;
-
- if (BGP_DEBUG (normal, NORMAL))
+
+ if (status == Established)
+ UNSET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
+
+ /* If max-med processing is applicable, do the necessary. */
+ if (status == Established)
+ {
+ if (bgp_maxmed_onstartup_configured(peer->bgp) &&
+ bgp_maxmed_onstartup_applicable(peer->bgp))
+ bgp_maxmed_onstartup_process_status_change(peer);
+ else
+ peer->bgp->maxmed_onstartup_over = 1;
+ }
+
+ /* If update-delay processing is applicable, do the necessary. */
+ if (bgp_update_delay_configured(peer->bgp) &&
+ bgp_update_delay_applicable(peer->bgp))
+ bgp_update_delay_process_status_change(peer);
+
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s went from %s to %s",
peer->host,
LOOKUP (bgp_status_msg, peer->ostatus),
@@ -435,7 +948,9 @@ static int
bgp_clearing_completed (struct peer *peer)
{
int rc = bgp_stop(peer);
- BGP_EVENT_FLUSH (peer);
+
+ if (rc >= 0)
+ BGP_EVENT_FLUSH (peer);
return rc;
}
@@ -448,6 +963,7 @@ bgp_stop (struct peer *peer)
afi_t afi;
safi_t safi;
char orf_name[BUFSIZ];
+ int ret = 0;
/* Can't do this in Clearing; events are used for state transitions */
if (peer->status != Clearing)
@@ -470,12 +986,12 @@ bgp_stop (struct peer *peer)
if (peer->t_gr_stale)
{
BGP_TIMER_OFF (peer->t_gr_stale);
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
}
if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
{
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
{
zlog_debug ("%s graceful restart timer started for %d sec",
peer->host, peer->v_gr_restart);
@@ -553,9 +1069,11 @@ bgp_stop (struct peer *peer)
/* Received ORF prefix-filter */
peer->orf_plist[afi][safi] = NULL;
- /* ORF received prefix-filter pnt */
- sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi);
- prefix_bgp_orf_remove_all (afi, orf_name);
+ if ((peer->status == OpenConfirm) || (peer->status == Established)) {
+ /* ORF received prefix-filter pnt */
+ sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi);
+ prefix_bgp_orf_remove_all (afi, orf_name);
+ }
}
/* Reset keepalive and holdtime */
@@ -583,7 +1101,18 @@ bgp_stop (struct peer *peer)
peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0;
#endif /* 0 */
- return 0;
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) &&
+ !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE)))
+ {
+ peer_delete(peer);
+ ret = -1;
+ }
+ else
+ {
+ bgp_peer_conf_if_to_su_update(peer);
+ }
+
+ return ret;
}
/* BGP peer is stoped by the error. */
@@ -597,9 +1126,7 @@ bgp_stop_with_error (struct peer *peer)
if (peer->v_start >= (60 * 2))
peer->v_start = (60 * 2);
- bgp_stop (peer);
-
- return 0;
+ return(bgp_stop (peer));
}
@@ -610,21 +1137,10 @@ bgp_stop_with_notify (struct peer *peer, u_char code, u_char sub_code)
/* Send notify to remote peer */
bgp_notify_send (peer, code, sub_code);
- /* Sweep if it is temporary peer. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host);
- peer_delete (peer);
- return -1;
- }
-
/* Clear start timer value to default. */
peer->v_start = BGP_INIT_START_TIMER;
- /* bgp_stop needs to be invoked while in Established state */
- bgp_stop(peer);
-
- return 0;
+ return(bgp_stop(peer));
}
@@ -637,14 +1153,21 @@ bgp_connect_success (struct peer *peer)
{
zlog_err ("bgp_connect_success peer's fd is negative value %d",
peer->fd);
+ bgp_stop(peer);
return -1;
}
- BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- bgp_getsockname (peer);
+ if (bgp_getsockname (peer) < 0)
+ {
+ zlog_err ("%s: bgp_getsockname(): failed for peer %s", __FUNCTION__,
+ peer->host);
+ bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, 0); /* internal error */
+ return -1;
+ }
- if (BGP_DEBUG (normal, NORMAL))
+ BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
+
+ if (bgp_debug_neighbor_events(peer))
{
char buf1[SU_ADDRSTRLEN];
@@ -655,8 +1178,7 @@ bgp_connect_success (struct peer *peer)
zlog_debug ("%s passive open", peer->host);
}
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- bgp_open_send (peer);
+ bgp_open_send (peer);
return 0;
}
@@ -665,8 +1187,7 @@ bgp_connect_success (struct peer *peer)
static int
bgp_connect_fail (struct peer *peer)
{
- bgp_stop (peer);
- return 0;
+ return (bgp_stop (peer));
}
/* This function is the first starting point of all BGP connection. It
@@ -675,11 +1196,14 @@ int
bgp_start (struct peer *peer)
{
int status;
+ int connected = 0;
+
+ bgp_peer_conf_if_to_su_update(peer);
if (BGP_PEER_START_SUPPRESSED (peer))
{
- if (BGP_DEBUG (fsm, FSM))
- plog_err (peer->log, "%s [FSM] Trying to start suppressed peer"
+ if (bgp_debug_neighbor_events(peer))
+ zlog_err ("%s [FSM] Trying to start suppressed peer"
" - this is never supposed to happen!", peer->host);
return -1;
}
@@ -713,26 +1237,32 @@ bgp_start (struct peer *peer)
return 0;
}
+ /* Register to be notified on peer up */
+ if ((peer->ttl == 1) || (peer->gtsm_hops == 1))
+ connected = 1;
+
+ bgp_find_or_add_nexthop(family2afi(peer->su.sa.sa_family), NULL, peer,
+ connected);
status = bgp_connect (peer);
switch (status)
{
case connect_error:
- if (BGP_DEBUG (fsm, FSM))
- plog_debug (peer->log, "%s [FSM] Connect error", peer->host);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s [FSM] Connect error", peer->host);
BGP_EVENT_ADD (peer, TCP_connection_open_failed);
break;
case connect_success:
- if (BGP_DEBUG (fsm, FSM))
- plog_debug (peer->log, "%s [FSM] Connect immediately success",
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s [FSM] Connect immediately success",
peer->host);
BGP_EVENT_ADD (peer, TCP_connection_open);
break;
case connect_in_progress:
/* To check nonblocking connect, we wait until socket is
readable or writable. */
- if (BGP_DEBUG (fsm, FSM))
- plog_debug (peer->log, "%s [FSM] Non blocking connect waiting result",
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s [FSM] Non blocking connect waiting result",
peer->host);
if (peer->fd < 0)
{
@@ -751,9 +1281,14 @@ bgp_start (struct peer *peer)
static int
bgp_reconnect (struct peer *peer)
{
- bgp_stop (peer);
- bgp_start (peer);
- return 0;
+ int ret = 0;
+
+ if (bgp_stop (peer) > 0)
+ bgp_start (peer);
+ else
+ ret = -1;
+
+ return ret;
}
static int
@@ -772,6 +1307,13 @@ bgp_fsm_open (struct peer *peer)
static int
bgp_fsm_keepalive_expire (struct peer *peer)
{
+ /*
+ * If there are UPDATE messages to send, no need to send keepalive. The
+ * peer will note our progress through the UPDATEs.
+ */
+ if (!bgp_routeq_empty(peer))
+ return 0;
+
bgp_keepalive_send (peer);
return 0;
}
@@ -781,7 +1323,7 @@ bgp_fsm_keepalive_expire (struct peer *peer)
static int
bgp_fsm_event_error (struct peer *peer)
{
- plog_err (peer->log, "%s [FSM] unexpected packet received in state %s",
+ zlog_err ("%s [FSM] unexpected packet received in state %s",
peer->host, LOOKUP (bgp_status_msg, peer->status));
return bgp_stop_with_notify (peer, BGP_NOTIFY_FSM_ERR, 0);
@@ -792,8 +1334,8 @@ bgp_fsm_event_error (struct peer *peer)
static int
bgp_fsm_holdtime_expire (struct peer *peer)
{
- if (BGP_DEBUG (fsm, FSM))
- plog_debug (peer->log, "%s [FSM] Hold timer expire", peer->host);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s [FSM] Hold timer expire", peer->host);
return bgp_stop_with_notify (peer, BGP_NOTIFY_HOLD_ERR, 0);
}
@@ -807,6 +1349,19 @@ bgp_establish (struct peer *peer)
afi_t afi;
safi_t safi;
int nsf_af_count = 0;
+ int ret = 0;
+ struct peer *other;
+
+ other = peer->doppelganger;
+ peer = peer_xfer_conn(peer);
+ if (!peer)
+ {
+ zlog_err ("%%Neighbor failed in xfer_conn");
+ return -1;
+ }
+
+ if (other == peer)
+ ret = 1; /* bgp_establish specific code when xfer_conn happens. */
/* Reset capability open status flag. */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
@@ -861,7 +1416,7 @@ bgp_establish (struct peer *peer)
if (peer->t_gr_stale)
{
BGP_TIMER_OFF (peer->t_gr_stale);
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
}
}
@@ -869,7 +1424,7 @@ bgp_establish (struct peer *peer)
if (peer->t_gr_restart)
{
BGP_TIMER_OFF (peer->t_gr_restart);
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s graceful restart timer stopped", peer->host);
}
@@ -893,9 +1448,6 @@ bgp_establish (struct peer *peer)
REFRESH_IMMEDIATE, 0);
}
- if (peer->v_keepalive)
- bgp_keepalive_send (peer);
-
/* First update is deferred until ORF or ROUTE-REFRESH is received */
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
@@ -906,15 +1458,34 @@ bgp_establish (struct peer *peer)
bgp_announce_route_all (peer);
- BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1);
+ /* Start the route advertisement timer to send updates to the peer - if BGP
+ * is not in read-only mode. If it is, the timer will be started at the end
+ * of read-only mode.
+ */
+ if (!bgp_update_delay_active(peer->bgp))
+ BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 0);
- return 0;
+ if (peer->doppelganger && (peer->doppelganger->status != Deleted))
+ {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("[Event] Deleting stub connection for peer %s", peer->host);
+
+ if (peer->doppelganger->status > Active)
+ bgp_notify_send (peer->doppelganger, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
+ else
+ peer_delete(peer->doppelganger);
+ }
+
+ return ret;
}
/* Keepalive packet is received. */
static int
bgp_fsm_keepalive (struct peer *peer)
{
+ bgp_update_implicit_eors(peer);
+
/* peer count update */
peer->keepalive_in++;
@@ -934,11 +1505,50 @@ bgp_fsm_update (struct peer *peer)
static int
bgp_ignore (struct peer *peer)
{
- if (BGP_DEBUG (fsm, FSM))
- zlog (peer->log, LOG_DEBUG, "%s [FSM] bgp_ignore called", peer->host);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s [FSM] bgp_ignore called", peer->host);
return 0;
}
+void
+bgp_fsm_nht_update(struct peer *peer, int valid)
+{
+ int ret = 0;
+
+ if (!peer)
+ return;
+
+ switch (peer->status)
+ {
+ case Idle:
+ if (valid)
+ BGP_EVENT_ADD(peer, BGP_Start);
+ break;
+ case Connect:
+ ret = bgp_connect_check(peer, 0);
+ if (!ret && valid)
+ {
+ BGP_TIMER_OFF(peer->t_connect);
+ BGP_EVENT_ADD(peer, ConnectRetry_timer_expired);
+ }
+ break;
+ case Active:
+ if (valid)
+ {
+ BGP_TIMER_OFF(peer->t_connect);
+ BGP_EVENT_ADD(peer, ConnectRetry_timer_expired);
+ }
+ case OpenSent:
+ case OpenConfirm:
+ case Established:
+ case Clearing:
+ case Deleted:
+ default:
+ break;
+ }
+}
+
+
/* Finite State Machine structure */
static const struct {
int (*func) (struct peer *);
@@ -1108,19 +1718,34 @@ static const char *bgp_event_str[] =
int
bgp_event (struct thread *thread)
{
- int ret = 0;
int event;
- int next;
struct peer *peer;
+ int ret;
peer = THREAD_ARG (thread);
event = THREAD_VAL (thread);
+ ret = bgp_event_update(peer, event);
+
+ return (ret);
+}
+
+int
+bgp_event_update (struct peer *peer, int event)
+{
+ int next;
+ int ret = 0;
+ struct peer *other;
+ int passive_conn = 0;
+
+ other = peer->doppelganger;
+ passive_conn = (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) ? 1 : 0;
+
/* Logging this event. */
next = FSM [peer->status -1][event - 1].next_state;
- if (BGP_DEBUG (fsm, FSM) && peer->status != next)
- plog_debug (peer->log, "%s [FSM] %s (%s->%s)", peer->host,
+ if (bgp_debug_neighbor_events(peer) && peer->status != next)
+ zlog_debug ("%s [FSM] %s (%s->%s)", peer->host,
bgp_event_str[event],
LOOKUP (bgp_status_msg, peer->status),
LOOKUP (bgp_status_msg, next));
@@ -1132,13 +1757,28 @@ bgp_event (struct thread *thread)
/* When function do not want proceed next job return -1. */
if (ret >= 0)
{
+ if (ret == 1 && next == Established)
+ {
+ /* The case when doppelganger swap accurred in bgp_establish.
+ Update the peer pointer accordingly */
+ peer = other;
+ }
+
/* If status is changed. */
if (next != peer->status)
bgp_fsm_change_status (peer, next);
/* Make sure timer is set. */
bgp_timer_set (peer);
+
+ }
+ else if (!passive_conn && peer->bgp)
+ {
+ /* If we got a return value of -1, that means there was an error, restart
+ * the FSM. If the peer structure was deleted
+ */
+ bgp_fsm_change_status(peer, Idle);
+ bgp_timer_set(peer);
}
-
return ret;
}
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
index 752d6e2b..89077857 100644
--- a/bgpd/bgp_fsm.h
+++ b/bgpd/bgp_fsm.h
@@ -71,11 +71,35 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
thread_cancel_event (bm->master, (P)); \
} while (0)
+#define BGP_MSEC_JITTER 10
+
/* Prototypes. */
+extern void bgp_fsm_nht_update(struct peer *, int valid);
extern int bgp_event (struct thread *);
+extern int bgp_event_update (struct peer *, int event);
extern int bgp_stop (struct peer *peer);
extern void bgp_timer_set (struct peer *);
extern void bgp_fsm_change_status (struct peer *peer, int status);
extern const char *peer_down_str[];
+extern void bgp_update_delay_end (struct bgp *);
+extern void bgp_maxmed_update (struct bgp *);
+extern int bgp_maxmed_onstartup_configured (struct bgp *);
+extern int bgp_maxmed_onstartup_active (struct bgp *);
+
+/**
+ * Start the route advertisement timer (that honors MRAI) for all the
+ * peers. Typically called at the end of initial convergence, coming
+ * out of read-only mode.
+ */
+extern void bgp_start_routeadv (struct bgp *);
+
+/**
+ * See if the route advertisement timer needs to be adjusted for a
+ * peer. For example, if the last update was written to the peer a
+ * long while back, we don't need to wait for the periodic advertisement
+ * timer to expire to send the new set of prefixes. It should fire
+ * instantly and updates should go out sooner.
+ */
+extern void bgp_adjust_routeadv (struct peer *);
#endif /* _QUAGGA_BGP_FSM_H */
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 11c73cea..2f157652 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -38,6 +38,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "stream.h"
#include "vrf.h"
#include "workqueue.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
@@ -51,6 +52,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_filter.h"
#include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_network.h"
/* bgpd options, we use GNU getopt library. */
static const struct option longopts[] =
@@ -175,7 +177,7 @@ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
void
sighup (void)
{
- zlog (NULL, LOG_INFO, "SIGHUP received");
+ zlog_info ("SIGHUP received");
/* Terminate all thread. */
bgp_terminate ();
@@ -225,13 +227,13 @@ bgp_exit (int status)
{
struct bgp *bgp;
struct listnode *node, *nnode;
- int *socket;
struct interface *ifp;
- extern struct zclient *zlookup;
/* it only makes sense for this to be called on a clean exit */
assert (status == 0);
+ bgp_close();
+
/* reverse bgp_master_init */
for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
bgp_delete (bgp);
@@ -256,14 +258,6 @@ bgp_exit (int status)
work_queue_free (bm->process_rsclient_queue);
bm->process_rsclient_queue = NULL;
}
-
- /* reverse bgp_master_init */
- for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, socket))
- {
- if (close ((int)(long)socket) == -1)
- zlog_err ("close (%d): %s", (int)(long)socket, safe_strerror (errno));
- }
- list_delete (bm->listen_sockets);
/* reverse bgp_zebra_init/if_init */
if (retain_mode)
@@ -286,11 +280,8 @@ bgp_exit (int status)
/* reverse bgp_route_init */
bgp_route_finish ();
- /* reverse bgp_route_map_init/route_map_init */
- route_map_finish ();
-
- /* reverse bgp_scan_init */
- bgp_scan_finish ();
+ /* cleanup route maps */
+ bgp_route_map_terminate();
/* reverse access_list_init */
access_list_add_hook (NULL);
@@ -316,10 +307,13 @@ bgp_exit (int status)
bgp_address_destroy();
bgp_scan_destroy();
bgp_zebra_destroy();
- if (zlookup)
- zclient_free (zlookup);
if (bgp_nexthop_buf)
stream_free (bgp_nexthop_buf);
+ if (bgp_ifindices_buf)
+ stream_free (bgp_ifindices_buf);
+
+ /* reverse bgp_scan_init */
+ bgp_scan_finish ();
/* reverse bgp_master_init */
if (bm->master)
@@ -328,9 +322,6 @@ bgp_exit (int status)
if (zlog_default)
closezlog (zlog_default);
- if (CONF_BGP_DEBUG (normal, NORMAL))
- log_memstats_stderr ("bgpd");
-
exit (status);
}
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 8e78aafe..3d17ec85 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -74,7 +74,7 @@ bgp_mpath_is_configured (struct bgp *bgp, afi_t afi, safi_t safi)
*/
int
bgp_maximum_paths_set (struct bgp *bgp, afi_t afi, safi_t safi,
- int peertype, u_int16_t maxpaths)
+ int peertype, u_int16_t maxpaths, u_int16_t options)
{
if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
return -1;
@@ -83,6 +83,7 @@ bgp_maximum_paths_set (struct bgp *bgp, afi_t afi, safi_t safi,
{
case BGP_PEER_IBGP:
bgp->maxpaths[afi][safi].maxpaths_ibgp = maxpaths;
+ bgp->maxpaths[afi][safi].ibgp_flags |= options;
break;
case BGP_PEER_EBGP:
bgp->maxpaths[afi][safi].maxpaths_ebgp = maxpaths;
@@ -110,6 +111,7 @@ bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi,
{
case BGP_PEER_IBGP:
bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS;
+ bgp->maxpaths[afi][safi].ibgp_flags = 0;
break;
case BGP_PEER_EBGP:
bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS;
@@ -139,26 +141,45 @@ bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2)
compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop);
- if (!compare && ae1 && ae2 && (ae1->mp_nexthop_len == ae2->mp_nexthop_len))
+ if (!compare && ae1 && ae2)
{
- switch (ae1->mp_nexthop_len)
+ if (ae1->mp_nexthop_len == ae2->mp_nexthop_len)
+ {
+ switch (ae1->mp_nexthop_len)
+ {
+ case 4:
+ case 12:
+ compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in,
+ &ae2->mp_nexthop_global_in);
+ break;
+ case 16:
+ compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
+ &ae2->mp_nexthop_global);
+ break;
+ case 32:
+ compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
+ &ae2->mp_nexthop_global);
+ if (!compare)
+ compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local,
+ &ae2->mp_nexthop_local);
+ break;
+ }
+ }
+
+ /* This can happen if one IPv6 peer sends you global and link-local
+ * nexthops but another IPv6 peer only sends you global
+ */
+ else if (ae1->mp_nexthop_len == 16 || ae1->mp_nexthop_len == 32)
{
- case 4:
- case 12:
- compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in,
- &ae2->mp_nexthop_global_in);
- break;
- case 16:
- compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
- &ae2->mp_nexthop_global);
- break;
- case 32:
compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
&ae2->mp_nexthop_global);
if (!compare)
- compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local,
- &ae2->mp_nexthop_local);
- break;
+ {
+ if (ae1->mp_nexthop_len < ae2->mp_nexthop_len)
+ compare = -1;
+ else
+ compare = 1;
+ }
}
}
@@ -427,7 +448,7 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best,
struct listnode *mp_node, *mp_next_node;
struct bgp_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
int mpath_changed, debug;
- char pfx_buf[INET_ADDRSTRLEN], nh_buf[2][INET_ADDRSTRLEN];
+ char pfx_buf[INET6_ADDRSTRLEN], nh_buf[2][INET6_ADDRSTRLEN];
struct bgp_maxpaths_cfg *mpath_cfg = NULL;
mpath_changed = 0;
@@ -437,8 +458,7 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best,
old_mpath_count = 0;
prev_mpath = new_best;
mp_node = listhead (mp_list);
-
- debug = BGP_DEBUG (events, EVENTS);
+ debug = bgp_debug_update(NULL, &rn->p, 1) || bgp_debug_update(NULL, &rn->p, 0);
if (debug)
prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf));
diff --git a/bgpd/bgp_mpath.h b/bgpd/bgp_mpath.h
index 2a84d5e1..83db8264 100644
--- a/bgpd/bgp_mpath.h
+++ b/bgpd/bgp_mpath.h
@@ -24,6 +24,9 @@
#ifndef _QUAGGA_BGP_MPATH_H
#define _QUAGGA_BGP_MPATH_H
+/* Limit on number of configured maxpaths */
+#define BGP_MAXIMUM_MAXPATHS 255
+
/* BGP default maximum-paths */
#define BGP_DEFAULT_MAXPATHS 1
@@ -49,7 +52,8 @@ struct bgp_info_mpath
};
/* Functions to support maximum-paths configuration */
-extern int bgp_maximum_paths_set (struct bgp *, afi_t, safi_t, int, u_int16_t);
+extern int bgp_maximum_paths_set (struct bgp *, afi_t, safi_t, int, u_int16_t,
+ u_int16_t);
extern int bgp_maximum_paths_unset (struct bgp *, afi_t, safi_t, int);
bool bgp_mpath_is_configured_sort (struct bgp *, bgp_peer_sort_t, afi_t, safi_t);
bool bgp_mpath_is_configured (struct bgp *, afi_t, safi_t);
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 08a4272d..4a8f5eaa 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "memory.h"
#include "stream.h"
#include "filter.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
@@ -133,16 +134,14 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
/* sanity check against packet data */
if (prefixlen < VPN_PREFIXLEN_MIN_BYTES*8)
{
- plog_err (peer->log,
- "%s [Error] Update packet error / VPNv4"
- " (prefix length %d less than VPNv4 min length)",
+ zlog_err ("%s [Error] Update packet error / VPNv4"
+ " (prefix length %d less than VPNv4 min length)",
peer->host, prefixlen);
return -1;
}
if ((pnt + psize) > lim)
{
- plog_err (peer->log,
- "%s [Error] Update packet error / VPNv4"
+ zlog_err ("%s [Error] Update packet error / VPNv4"
" (psize %u exceeds packet size (%u)",
peer->host,
prefixlen, (uint)(lim-pnt));
@@ -152,8 +151,7 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
/* sanity check against storage for the IP address portion */
if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t) sizeof(p.u))
{
- plog_err (peer->log,
- "%s [Error] Update packet error / VPNv4"
+ zlog_err ("%s [Error] Update packet error / VPNv4"
" (psize %u exceeds storage size (%zu)",
peer->host,
prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, sizeof(p.u));
@@ -163,8 +161,7 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
/* Sanity check against max bitlen of the address family */
if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen (&p))
{
- plog_err (peer->log,
- "%s [Error] Update packet error / VPNv4"
+ zlog_err ("%s [Error] Update packet error / VPNv4"
" (psize %u exceeds family (%u) max byte len %u)",
peer->host,
prefixlen - VPN_PREFIXLEN_MIN_BYTES*8,
@@ -214,8 +211,7 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
/* Packet length consistency check. */
if (pnt != lim)
{
- plog_err (peer->log,
- "%s [Error] Update packet error / VPNv4"
+ zlog_err ("%s [Error] Update packet error / VPNv4"
" (%zu data remaining after parsing)",
peer->host, lim - pnt);
return -1;
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 51a6f602..283fa344 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -34,6 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "filter.h"
#include "bgpd/bgpd.h"
+#include "bgpd/bgp_open.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_debug.h"
@@ -67,8 +68,7 @@ bgp_md5_set_socket (int socket, union sockunion *su, const char *password)
#endif /* HAVE_TCP_MD5SIG */
if (ret < 0)
- zlog (NULL, LOG_WARNING, "can't set TCP_MD5SIG option on socket %d: %s",
- socket, safe_strerror (en));
+ zlog_warn ("can't set TCP_MD5SIG option on socket %d: %s", socket, safe_strerror (en));
return ret;
}
@@ -150,7 +150,7 @@ static void
bgp_set_socket_ttl (struct peer *peer, int bgp_sock)
{
char buf[INET_ADDRSTRLEN];
- int ret;
+ int ret = 0;
/* In case of peer is EBGP, we should set TTL for this connection. */
if (!peer->gtsm_hops && (peer_sort (peer) == BGP_PEER_EBGP))
@@ -222,50 +222,90 @@ bgp_accept (struct thread *thread)
/* Set socket send buffer size */
bgp_update_sock_send_buffer_size(bgp_sock);
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf));
-
/* Check remote IP address */
peer1 = peer_lookup (NULL, &su);
- if (! peer1 || peer1->status == Idle)
+ if (! peer1)
{
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(NULL))
{
- if (! peer1)
- zlog_debug ("[Event] BGP connection IP address %s is not configured",
- inet_sutop (&su, buf));
- else
- zlog_debug ("[Event] BGP connection IP address %s is Idle state",
- inet_sutop (&su, buf));
+ zlog_debug ("[Event] BGP connection IP address %s is not configured",
+ inet_sutop (&su, buf));
}
close (bgp_sock);
return -1;
}
+ if (CHECK_FLAG(peer1->flags, PEER_FLAG_SHUTDOWN))
+ {
+ if (bgp_debug_neighbor_events(peer1))
+ zlog_debug ("[Event] connection from %s rejected due to admin shutdown",
+ inet_sutop (&su, buf));
+ close (bgp_sock);
+ return -1;
+ }
+
+ /*
+ * Do not accept incoming connections in Clearing state. This can result
+ * in incorect state transitions - e.g., the connection goes back to
+ * Established and then the Clearing_Completed event is generated. Also,
+ * block incoming connection in Deleted state.
+ */
+ if (peer1->status == Clearing || peer1->status == Deleted)
+ {
+ if (bgp_debug_neighbor_events(peer1))
+ zlog_debug("[Event] Closing incoming conn for %s (%p) state %d",
+ peer1->host, peer1, peer1->status);
+ close (bgp_sock);
+ return -1;
+ }
+
+ if (bgp_debug_neighbor_events(peer1))
+ zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf));
+
+ if (peer1->doppelganger)
+ {
+ /* We have an existing connection. Kill the existing one and run
+ with this one.
+ */
+ if (bgp_debug_neighbor_events(peer1))
+ zlog_debug ("[Event] New active connection from peer %s, Killing"
+ " previous active connection", peer1->host);
+ peer_delete(peer1->doppelganger);
+ }
+
bgp_set_socket_ttl (peer1, bgp_sock);
- /* Make dummy peer until read Open packet. */
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("[Event] Make dummy peer structure until read Open packet");
+ peer = peer_create (&su, peer1->conf_if, peer1->bgp, peer1->local_as,
+ peer1->as, 0, 0);
- {
- char buf[SU_ADDRSTRLEN];
+ peer_xfer_config(peer, peer1);
+ UNSET_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE);
- peer = peer_create_accept (peer1->bgp);
- SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER);
- peer->su = su;
- peer->fd = bgp_sock;
- peer->status = Active;
- peer->local_id = peer1->local_id;
- peer->v_holdtime = peer1->v_holdtime;
- peer->v_keepalive = peer1->v_keepalive;
+ peer->doppelganger = peer1;
+ peer1->doppelganger = peer;
+ peer->fd = bgp_sock;
+ bgp_fsm_change_status(peer, Active);
+ BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */
- /* Make peer's address string. */
- sockunion2str (&su, buf, SU_ADDRSTRLEN);
- peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf);
- }
+ SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER);
- BGP_EVENT_ADD (peer, TCP_connection_open);
+ /* Make dummy peer until read Open packet. */
+ if (peer1->status == Established &&
+ CHECK_FLAG (peer1->sflags, PEER_STATUS_NSF_MODE))
+ {
+ /* If we have an existing established connection with graceful restart
+ * capability announced with one or more address families, then drop
+ * existing established connection and move state to connect.
+ */
+ peer1->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
+ SET_FLAG (peer1->sflags, PEER_STATUS_NSF_WAIT);
+ bgp_event_update(peer1, TCP_connection_closed);
+ }
+
+ if (peer_active (peer))
+ {
+ BGP_EVENT_ADD (peer, TCP_connection_open);
+ }
return 0;
}
@@ -278,11 +318,14 @@ bgp_bind (struct peer *peer)
int ret;
struct ifreq ifreq;
int myerrno;
+ char *name;
- if (! peer->ifname)
+ if (! peer->ifname && !peer->conf_if)
return 0;
- strncpy ((char *)&ifreq.ifr_name, peer->ifname, sizeof (ifreq.ifr_name));
+ name = (peer->conf_if ? peer->conf_if : peer->ifname);
+
+ strncpy ((char *)&ifreq.ifr_name, name, sizeof (ifreq.ifr_name));
if ( bgpd_privs.change (ZPRIVS_RAISE) )
zlog_err ("bgp_bind: could not raise privs");
@@ -296,8 +339,8 @@ bgp_bind (struct peer *peer)
if (ret < 0)
{
- zlog (peer->log, LOG_INFO, "bind to interface %s failed, errno=%d",
- peer->ifname, myerrno);
+ zlog_info ("bind to interface %s failed, errno=%d",
+ name, myerrno);
return ret;
}
#endif /* SO_BINDTODEVICE */
@@ -367,6 +410,11 @@ bgp_connect (struct peer *peer)
{
ifindex_t ifindex = 0;
+ if (peer->conf_if && BGP_PEER_SU_UNSPEC(peer))
+ {
+ zlog_debug("Peer address not learnt: Returning from connect");
+ return 0;
+ }
/* Make socket for the peer. */
peer->fd = sockunion_socket (&peer->su);
if (peer->fd < 0)
@@ -402,19 +450,19 @@ bgp_connect (struct peer *peer)
/* Update source bind. */
bgp_update_source (peer);
- if (peer->ifname)
- ifindex = ifname2ifindex (peer->ifname);
+ if (peer->conf_if || peer->ifname)
+ ifindex = ifname2ifindex (peer->conf_if ? peer->conf_if : peer->ifname);
- if (BGP_DEBUG (events, EVENTS))
- plog_debug (peer->log, "%s [Event] Connect start to %s fd %d",
- peer->host, peer->host, peer->fd);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s [Event] Connect start to %s fd %d",
+ peer->host, peer->host, peer->fd);
/* Connect to the remote peer. */
return sockunion_connect (peer->fd, &peer->su, htons (peer->port), ifindex);
}
/* After TCP connection is established. Get local address and port. */
-void
+int
bgp_getsockname (struct peer *peer)
{
if (peer->su_local)
@@ -430,9 +478,13 @@ bgp_getsockname (struct peer *peer)
}
peer->su_local = sockunion_getsockname (peer->fd);
+ if (!peer->su_local) return -1;
peer->su_remote = sockunion_getpeername (peer->fd);
+ if (!peer->su_remote) return -1;
bgp_nexthop_set (peer->su_local, peer->su_remote, &peer->nexthop, peer);
+
+ return 0;
}
@@ -548,6 +600,9 @@ bgp_close (void)
struct listnode *node, *next;
struct bgp_listener *listener;
+ if (bm->listen_sockets == NULL)
+ return;
+
for (ALL_LIST_ELEMENTS (bm->listen_sockets, node, next, listener))
{
thread_cancel (listener->thread);
diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h
index 12768430..403393e8 100644
--- a/bgpd/bgp_network.h
+++ b/bgpd/bgp_network.h
@@ -26,7 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
extern int bgp_socket (unsigned short, const char *);
extern void bgp_close (void);
extern int bgp_connect (struct peer *);
-extern void bgp_getsockname (struct peer *);
+extern int bgp_getsockname (struct peer *);
extern int bgp_md5_set (struct peer *);
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 24068141..4be27b47 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -31,59 +31,35 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "hash.h"
#include "jhash.h"
#include "filter.h"
+#include "nexthop.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_damp.h"
#include "zebra/rib.h"
#include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */
-struct bgp_nexthop_cache *zlookup_query (struct in_addr);
-struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *);
-
-/* Only one BGP scan thread are activated at the same time. */
-static struct thread *bgp_scan_thread = NULL;
-
-/* BGP import thread */
-static struct thread *bgp_import_thread = NULL;
-
-/* BGP scan interval. */
-static int bgp_scan_interval;
-
-/* BGP import interval. */
-static int bgp_import_interval;
/* Route table for next-hop lookup cache. */
-static struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
+struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
static struct bgp_table *cache1_table[AFI_MAX];
-static struct bgp_table *cache2_table[AFI_MAX];
/* Route table for connected route. */
static struct bgp_table *bgp_connected_table[AFI_MAX];
-/* BGP nexthop lookup query client. */
-struct zclient *zlookup = NULL;
-
-/* Add nexthop to the end of the list. */
-static void
-bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop)
+char *
+bnc_str (struct bgp_nexthop_cache *bnc, char *buf, int size)
{
- struct nexthop *last;
-
- for (last = bnc->nexthop; last && last->next; last = last->next)
- ;
- if (last)
- last->next = nexthop;
- else
- bnc->nexthop = nexthop;
- nexthop->prev = last;
+ prefix2str(&(bnc->node->p), buf, size);
+ return buf;
}
-static void
+void
bnc_nexthop_free (struct bgp_nexthop_cache *bnc)
{
struct nexthop *nexthop;
@@ -96,93 +72,29 @@ bnc_nexthop_free (struct bgp_nexthop_cache *bnc)
}
}
-static struct bgp_nexthop_cache *
+struct bgp_nexthop_cache *
bnc_new (void)
{
- return XCALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache));
+ struct bgp_nexthop_cache *bnc;
+
+ bnc = XCALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache));
+ LIST_INIT(&(bnc->paths));
+ return bnc;
}
-static void
+void
bnc_free (struct bgp_nexthop_cache *bnc)
{
bnc_nexthop_free (bnc);
XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc);
}
-static int
-bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2)
-{
- if (next1->type != next2->type)
- return 0;
-
- switch (next1->type)
- {
- case ZEBRA_NEXTHOP_IPV4:
- if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4))
- return 0;
- break;
- case ZEBRA_NEXTHOP_IPV4_IFINDEX:
- if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)
- || next1->ifindex != next2->ifindex)
- return 0;
- break;
- case ZEBRA_NEXTHOP_IFINDEX:
- case ZEBRA_NEXTHOP_IFNAME:
- if (next1->ifindex != next2->ifindex)
- return 0;
- break;
- case ZEBRA_NEXTHOP_IPV6:
- if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
- return 0;
- break;
- case ZEBRA_NEXTHOP_IPV6_IFINDEX:
- case ZEBRA_NEXTHOP_IPV6_IFNAME:
- if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
- return 0;
- if (next1->ifindex != next2->ifindex)
- return 0;
- break;
- default:
- /* do nothing */
- break;
- }
- return 1;
-}
-
-static int
-bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1,
- struct bgp_nexthop_cache *bnc2)
-{
- int i;
- struct nexthop *next1, *next2;
-
- if (bnc1->nexthop_num != bnc2->nexthop_num)
- return 1;
-
- next1 = bnc1->nexthop;
- next2 = bnc2->nexthop;
-
- for (i = 0; i < bnc1->nexthop_num; i++)
- {
- if (! bgp_nexthop_same (next1, next2))
- return 1;
-
- next1 = next1->next;
- next2 = next2->next;
- }
- return 0;
-}
-
/* If nexthop exists on connected network return 1. */
int
bgp_nexthop_onlink (afi_t afi, struct attr *attr)
{
struct bgp_node *rn;
- /* If zebra is not enabled return */
- if (zlookup->sock < 0)
- return 1;
-
/* Lookup the address is onlink or not. */
if (afi == AFI_IP)
{
@@ -214,325 +126,6 @@ bgp_nexthop_onlink (afi_t afi, struct attr *attr)
return 0;
}
-/* Check specified next-hop is reachable or not. */
-static int
-bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
- int *metricchanged)
-{
- struct bgp_node *rn;
- struct prefix p;
- struct bgp_nexthop_cache *bnc;
- struct attr *attr;
-
- /* If lookup is not enabled, return valid. */
- if (zlookup->sock < 0)
- {
- if (ri->extra)
- ri->extra->igpmetric = 0;
- return 1;
- }
-
- /* Only check IPv6 global address only nexthop. */
- attr = ri->attr;
-
- if (attr->extra->mp_nexthop_len != 16
- || IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global))
- return 1;
-
- memset (&p, 0, sizeof (struct prefix));
- p.family = AF_INET6;
- p.prefixlen = IPV6_MAX_BITLEN;
- p.u.prefix6 = attr->extra->mp_nexthop_global;
-
- /* IBGP or ebgp-multihop */
- rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP6], &p);
-
- if (rn->info)
- {
- bnc = rn->info;
- bgp_unlock_node (rn);
- }
- else
- {
- if (NULL == (bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global)))
- bnc = bnc_new ();
- else
- {
- if (changed)
- {
- struct bgp_table *old;
- struct bgp_node *oldrn;
-
- if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6])
- old = cache2_table[AFI_IP6];
- else
- old = cache1_table[AFI_IP6];
-
- oldrn = bgp_node_lookup (old, &p);
- if (oldrn)
- {
- struct bgp_nexthop_cache *oldbnc = oldrn->info;
-
- bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc);
-
- if (bnc->metric != oldbnc->metric)
- bnc->metricchanged = 1;
-
- bgp_unlock_node (oldrn);
- }
- }
- }
- rn->info = bnc;
- }
-
- if (changed)
- *changed = bnc->changed;
-
- if (metricchanged)
- *metricchanged = bnc->metricchanged;
-
- if (bnc->valid && bnc->metric)
- (bgp_info_extra_get (ri))->igpmetric = bnc->metric;
- else if (ri->extra)
- ri->extra->igpmetric = 0;
-
- return bnc->valid;
-}
-
-/* Check specified next-hop is reachable or not. */
-int
-bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
- int *changed, int *metricchanged)
-{
- struct bgp_node *rn;
- struct prefix p;
- struct bgp_nexthop_cache *bnc;
- struct in_addr addr;
-
- /* If lookup is not enabled, return valid. */
- if (zlookup->sock < 0)
- {
- if (ri->extra)
- ri->extra->igpmetric = 0;
- return 1;
- }
-
- if (afi == AFI_IP6)
- return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged);
-
- addr = ri->attr->nexthop;
-
- memset (&p, 0, sizeof (struct prefix));
- p.family = AF_INET;
- p.prefixlen = IPV4_MAX_BITLEN;
- p.u.prefix4 = addr;
-
- /* IBGP or ebgp-multihop */
- rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP], &p);
-
- if (rn->info)
- {
- bnc = rn->info;
- bgp_unlock_node (rn);
- }
- else
- {
- if (NULL == (bnc = zlookup_query (addr)))
- bnc = bnc_new ();
- else
- {
- if (changed)
- {
- struct bgp_table *old;
- struct bgp_node *oldrn;
-
- if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP])
- old = cache2_table[AFI_IP];
- else
- old = cache1_table[AFI_IP];
-
- oldrn = bgp_node_lookup (old, &p);
- if (oldrn)
- {
- struct bgp_nexthop_cache *oldbnc = oldrn->info;
-
- bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc);
-
- if (bnc->metric != oldbnc->metric)
- bnc->metricchanged = 1;
-
- bgp_unlock_node (oldrn);
- }
- }
- }
- rn->info = bnc;
- }
-
- if (changed)
- *changed = bnc->changed;
-
- if (metricchanged)
- *metricchanged = bnc->metricchanged;
-
- if (bnc->valid && bnc->metric)
- (bgp_info_extra_get(ri))->igpmetric = bnc->metric;
- else if (ri->extra)
- ri->extra->igpmetric = 0;
-
- return bnc->valid;
-}
-
-/* Reset and free all BGP nexthop cache. */
-static void
-bgp_nexthop_cache_reset (struct bgp_table *table)
-{
- struct bgp_node *rn;
- struct bgp_nexthop_cache *bnc;
-
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- if ((bnc = rn->info) != NULL)
- {
- bnc_free (bnc);
- rn->info = NULL;
- bgp_unlock_node (rn);
- }
-}
-
-static void
-bgp_scan (afi_t afi, safi_t safi)
-{
- struct bgp_node *rn;
- struct bgp *bgp;
- struct bgp_info *bi;
- struct bgp_info *next;
- struct peer *peer;
- struct listnode *node, *nnode;
- int valid;
- int current;
- int changed;
- int metricchanged;
-
- /* Change cache. */
- if (bgp_nexthop_cache_table[afi] == cache1_table[afi])
- bgp_nexthop_cache_table[afi] = cache2_table[afi];
- else
- bgp_nexthop_cache_table[afi] = cache1_table[afi];
-
- /* Get default bgp. */
- bgp = bgp_get_default ();
- if (bgp == NULL)
- return;
-
- /* Maximum prefix check */
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- if (peer->status != Established)
- continue;
-
- if (peer->afc[afi][SAFI_UNICAST])
- bgp_maximum_prefix_overflow (peer, afi, SAFI_UNICAST, 1);
- if (peer->afc[afi][SAFI_MULTICAST])
- bgp_maximum_prefix_overflow (peer, afi, SAFI_MULTICAST, 1);
- if (peer->afc[afi][SAFI_MPLS_VPN])
- bgp_maximum_prefix_overflow (peer, afi, SAFI_MPLS_VPN, 1);
- }
-
- for (rn = bgp_table_top (bgp->rib[afi][SAFI_UNICAST]); rn;
- rn = bgp_route_next (rn))
- {
- for (bi = rn->info; bi; bi = next)
- {
- next = bi->next;
-
- if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL)
- {
- changed = 0;
- metricchanged = 0;
-
- if (bi->peer->sort == BGP_PEER_EBGP && bi->peer->ttl == 1
- && !CHECK_FLAG(bi->peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
- valid = bgp_nexthop_onlink (afi, bi->attr);
- else
- valid = bgp_nexthop_lookup (afi, bi->peer, bi,
- &changed, &metricchanged);
-
- current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0;
-
- if (changed)
- SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED);
- else
- UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED);
-
- if (valid != current)
- {
- if (CHECK_FLAG (bi->flags, BGP_INFO_VALID))
- {
- bgp_aggregate_decrement (bgp, &rn->p, bi,
- afi, SAFI_UNICAST);
- bgp_info_unset_flag (rn, bi, BGP_INFO_VALID);
- }
- else
- {
- bgp_info_set_flag (rn, bi, BGP_INFO_VALID);
- bgp_aggregate_increment (bgp, &rn->p, bi,
- afi, SAFI_UNICAST);
- }
- }
-
- if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST],
- BGP_CONFIG_DAMPENING)
- && bi->extra && bi->extra->damp_info )
- if (bgp_damp_scan (bi, afi, SAFI_UNICAST))
- bgp_aggregate_increment (bgp, &rn->p, bi,
- afi, SAFI_UNICAST);
- }
- }
- if (rn->info)
- bgp_process (bgp, rn, afi, SAFI_UNICAST);
- }
-
- /* Flash old cache. */
- if (bgp_nexthop_cache_table[afi] == cache1_table[afi])
- bgp_nexthop_cache_reset (cache2_table[afi]);
- else
- bgp_nexthop_cache_reset (cache1_table[afi]);
-
- if (BGP_DEBUG (events, EVENTS))
- {
- if (afi == AFI_IP)
- zlog_debug ("scanning IPv4 Unicast routing tables");
- else if (afi == AFI_IP6)
- zlog_debug ("scanning IPv6 Unicast routing tables");
- }
-
- /* Reevaluate default-originate route-maps and announce/withdraw
- * default route if neccesary. */
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- if (peer->status == Established
- && CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)
- && peer->default_rmap[afi][safi].name)
- bgp_default_originate (peer, afi, safi, 0);
- }
-}
-
-/* BGP scan thread. This thread check nexthop reachability. */
-static int
-bgp_scan_timer (struct thread *t)
-{
- bgp_scan_thread =
- thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval);
-
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("Performing BGP general scanning");
-
- bgp_scan (AFI_IP, SAFI_UNICAST);
-
- bgp_scan (AFI_IP6, SAFI_UNICAST);
-
- return 0;
-}
-
/* BGP own address structure */
struct bgp_addr
{
@@ -599,6 +192,9 @@ bgp_address_add (struct prefix *p)
tmp.addr = p->u.prefix4;
addr = hash_get (bgp_address_hash, &tmp, bgp_address_hash_alloc);
+ if (!addr)
+ return;
+
addr->refcnt++;
}
@@ -777,652 +373,158 @@ bgp_nexthop_self (struct attr *attr)
return 0;
}
-static struct bgp_nexthop_cache *
-zlookup_read (void)
-{
- struct stream *s;
- uint16_t length;
- u_char marker;
- u_char version;
- uint16_t vrf_id;
- uint16_t command;
- int err;
- struct in_addr raddr __attribute__((unused));
- uint32_t metric;
- int i;
- u_char nexthop_num;
- struct nexthop *nexthop;
- struct bgp_nexthop_cache *bnc;
-
- s = zlookup->ibuf;
- stream_reset (s);
-
- err = zclient_read_header (s, zlookup->sock, &length, &marker, &version,
- &vrf_id, &command);
- if (err < 0)
- {
- zlog_err("%s: zserv_read_header() failed", __func__);
- return NULL;
- }
-
- /* XXX: not doing anything with raddr */
- raddr.s_addr = stream_get_ipv4 (s);
- metric = stream_getl (s);
- nexthop_num = stream_getc (s);
-
- if (nexthop_num)
- {
- bnc = bnc_new ();
- bnc->valid = 1;
- bnc->metric = metric;
- bnc->nexthop_num = nexthop_num;
-
- for (i = 0; i < nexthop_num; i++)
- {
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- nexthop->type = stream_getc (s);
- switch (nexthop->type)
- {
- case ZEBRA_NEXTHOP_IPV4:
- nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
- break;
- case ZEBRA_NEXTHOP_IPV4_IFINDEX:
- nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
- nexthop->ifindex = stream_getl (s);
- break;
- case ZEBRA_NEXTHOP_IFINDEX:
- case ZEBRA_NEXTHOP_IFNAME:
- nexthop->ifindex = stream_getl (s);
- break;
- default:
- /* do nothing */
- break;
- }
- bnc_nexthop_add (bnc, nexthop);
- }
- }
- else
- return NULL;
-
- return bnc;
-}
-
-struct bgp_nexthop_cache *
-zlookup_query (struct in_addr addr)
-{
- int ret;
- struct stream *s;
-
- /* Check socket. */
- if (zlookup->sock < 0)
- return NULL;
-
- s = zlookup->obuf;
- stream_reset (s);
- zclient_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP, VRF_DEFAULT);
- stream_put_in_addr (s, &addr);
-
- stream_putw_at (s, 0, stream_get_endp (s));
-
- ret = writen (zlookup->sock, s->data, stream_get_endp (s));
- if (ret < 0)
- {
- zlog_err ("can't write to zlookup->sock");
- close (zlookup->sock);
- zlookup->sock = -1;
- return NULL;
- }
- if (ret == 0)
- {
- zlog_err ("zlookup->sock connection closed");
- close (zlookup->sock);
- zlookup->sock = -1;
- return NULL;
- }
-
- return zlookup_read ();
-}
-
-static struct bgp_nexthop_cache *
-zlookup_read_ipv6 (void)
-{
- struct stream *s;
- uint16_t length, vrf_id, cmd;
- u_char version, marker;
- struct in6_addr raddr;
- uint32_t metric;
- int i, err;
- u_char nexthop_num;
- struct nexthop *nexthop;
- struct bgp_nexthop_cache *bnc;
-
- s = zlookup->ibuf;
- stream_reset (s);
-
- err = zclient_read_header (s, zlookup->sock, &length, &marker, &version,
- &vrf_id, &cmd);
- if (err < 0)
- {
- zlog_err("%s: zserv_read_header() failed", __func__);
- return NULL;
- }
-
- /* XXX: not actually doing anything with raddr */
- stream_get (&raddr, s, 16);
-
- metric = stream_getl (s);
- nexthop_num = stream_getc (s);
-
- if (nexthop_num)
- {
- bnc = bnc_new ();
- bnc->valid = 1;
- bnc->metric = metric;
- bnc->nexthop_num = nexthop_num;
-
- for (i = 0; i < nexthop_num; i++)
- {
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- nexthop->type = stream_getc (s);
- switch (nexthop->type)
- {
- case ZEBRA_NEXTHOP_IPV6:
- stream_get (&nexthop->gate.ipv6, s, 16);
- break;
- case ZEBRA_NEXTHOP_IPV6_IFINDEX:
- case ZEBRA_NEXTHOP_IPV6_IFNAME:
- stream_get (&nexthop->gate.ipv6, s, 16);
- nexthop->ifindex = stream_getl (s);
- break;
- case ZEBRA_NEXTHOP_IFINDEX:
- case ZEBRA_NEXTHOP_IFNAME:
- nexthop->ifindex = stream_getl (s);
- break;
- default:
- /* do nothing */
- break;
- }
- bnc_nexthop_add (bnc, nexthop);
- }
- }
- else
- return NULL;
-
- return bnc;
-}
-
-struct bgp_nexthop_cache *
-zlookup_query_ipv6 (struct in6_addr *addr)
-{
- int ret;
- struct stream *s;
-
- /* Check socket. */
- if (zlookup->sock < 0)
- return NULL;
-
- s = zlookup->obuf;
- stream_reset (s);
- zclient_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP, VRF_DEFAULT);
- stream_put (s, addr, 16);
- stream_putw_at (s, 0, stream_get_endp (s));
-
- ret = writen (zlookup->sock, s->data, stream_get_endp (s));
- if (ret < 0)
- {
- zlog_err ("can't write to zlookup->sock");
- close (zlookup->sock);
- zlookup->sock = -1;
- return NULL;
- }
- if (ret == 0)
- {
- zlog_err ("zlookup->sock connection closed");
- close (zlookup->sock);
- zlookup->sock = -1;
- return NULL;
- }
-
- return zlookup_read_ipv6 ();
-}
-
-static int
-bgp_import_check (struct prefix *p, u_int32_t *igpmetric,
- struct in_addr *igpnexthop)
-{
- struct stream *s;
- int ret;
- u_int16_t length, vrf_id, command;
- u_char version, marker;
- struct in_addr addr __attribute__((unused));
- struct in_addr nexthop;
- u_int32_t metric = 0;
- u_char nexthop_num;
- u_char nexthop_type;
-
- /* If lookup connection is not available return valid. */
- if (zlookup->sock < 0)
- {
- if (igpmetric)
- *igpmetric = 0;
- return 1;
- }
-
- /* Send query to the lookup connection */
- s = zlookup->obuf;
- stream_reset (s);
- zclient_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP, VRF_DEFAULT);
-
- stream_putc (s, p->prefixlen);
- stream_put_in_addr (s, &p->u.prefix4);
-
- stream_putw_at (s, 0, stream_get_endp (s));
-
- /* Write the packet. */
- ret = writen (zlookup->sock, s->data, stream_get_endp (s));
-
- if (ret < 0)
- {
- zlog_err ("can't write to zlookup->sock");
- close (zlookup->sock);
- zlookup->sock = -1;
- return 1;
- }
- if (ret == 0)
- {
- zlog_err ("zlookup->sock connection closed");
- close (zlookup->sock);
- zlookup->sock = -1;
- return 1;
- }
-
- /* Get result. */
- stream_reset (s);
-
- ret = zclient_read_header (s, zlookup->sock, &length, &marker, &version,
- &vrf_id, &command);
- if (ret < 0)
- {
- zlog_err("%s: zserv_read_header() failed", __func__);
- return 0;
- }
-
- /* XXX: not using addr */
- addr.s_addr = stream_get_ipv4 (s);
- metric = stream_getl (s);
- nexthop_num = stream_getc (s);
-
- /* Set IGP metric value. */
- if (igpmetric)
- *igpmetric = metric;
-
- /* If there is nexthop then this is active route. */
- if (nexthop_num)
- {
- nexthop.s_addr = 0;
- nexthop_type = stream_getc (s);
- switch (nexthop_type)
- {
- case ZEBRA_NEXTHOP_IPV4:
- nexthop.s_addr = stream_get_ipv4 (s);
- break;
- case ZEBRA_NEXTHOP_IPV4_IFINDEX:
- nexthop.s_addr = stream_get_ipv4 (s);
- /* ifindex */ (void)stream_getl (s);
- break;
- default:
- /* do nothing */
- break;
- }
- *igpnexthop = nexthop;
-
- return 1;
- }
- else
- return 0;
-}
-
-/* Scan all configured BGP route then check the route exists in IGP or
- not. */
-static int
-bgp_import (struct thread *t)
-{
- struct bgp *bgp;
- struct bgp_node *rn;
- struct bgp_static *bgp_static;
- struct listnode *node, *nnode;
- int valid;
- u_int32_t metric;
- struct in_addr nexthop;
- afi_t afi;
- safi_t safi;
-
- bgp_import_thread =
- thread_add_timer (bm->master, bgp_import, NULL, bgp_import_interval);
-
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("Import timer expired.");
-
- for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
- {
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MPLS_VPN; safi++)
- for (rn = bgp_table_top (bgp->route[afi][safi]); rn;
- rn = bgp_route_next (rn))
- if ((bgp_static = rn->info) != NULL)
- {
- if (bgp_static->backdoor)
- continue;
-
- valid = bgp_static->valid;
- metric = bgp_static->igpmetric;
- nexthop = bgp_static->igpnexthop;
-
- if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)
- && afi == AFI_IP && safi == SAFI_UNICAST)
- bgp_static->valid = bgp_import_check (&rn->p, &bgp_static->igpmetric,
- &bgp_static->igpnexthop);
- else
- {
- bgp_static->valid = 1;
- bgp_static->igpmetric = 0;
- bgp_static->igpnexthop.s_addr = 0;
- }
-
- if (bgp_static->valid != valid)
- {
- if (bgp_static->valid)
- bgp_static_update (bgp, &rn->p, bgp_static, afi, safi);
- else
- bgp_static_withdraw (bgp, &rn->p, afi, safi);
- }
- else if (bgp_static->valid)
- {
- if (bgp_static->igpmetric != metric
- || bgp_static->igpnexthop.s_addr != nexthop.s_addr
- || bgp_static->rmap.name)
- bgp_static_update (bgp, &rn->p, bgp_static, afi, safi);
- }
- }
- }
- return 0;
-}
-
-/* Connect to zebra for nexthop lookup. */
-static int
-zlookup_connect (struct thread *t)
-{
- struct zclient *zlookup;
-
- zlookup = THREAD_ARG (t);
- zlookup->t_connect = NULL;
-
- if (zlookup->sock != -1)
- return 0;
-
- if (zclient_socket_connect (zlookup) < 0)
- return -1;
-
- return 0;
-}
-
-/* Check specified multiaccess next-hop. */
int
-bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer)
+bgp_multiaccess_check_v4 (struct in_addr nexthop, struct peer *peer)
{
struct bgp_node *rn1;
struct bgp_node *rn2;
- struct prefix p1;
- struct prefix p2;
- struct in_addr addr;
+ struct prefix p;
int ret;
- ret = inet_aton (peer, &addr);
- if (! ret)
- return 0;
-
- memset (&p1, 0, sizeof (struct prefix));
- p1.family = AF_INET;
- p1.prefixlen = IPV4_MAX_BITLEN;
- p1.u.prefix4 = nexthop;
- memset (&p2, 0, sizeof (struct prefix));
- p2.family = AF_INET;
- p2.prefixlen = IPV4_MAX_BITLEN;
- p2.u.prefix4 = addr;
-
- /* If bgp scan is not enabled, return invalid. */
- if (zlookup->sock < 0)
- return 0;
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ p.u.prefix4 = nexthop;
- rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p1);
- if (! rn1)
- return 0;
- bgp_unlock_node (rn1);
-
- rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p2);
- if (! rn2)
+ rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p);
+ if (!rn1)
return 0;
- bgp_unlock_node (rn2);
- /* This is safe, even with above unlocks, since we are just
- comparing pointers to the objects, not the objects themselves. */
- if (rn1 == rn2)
- return 1;
-
- return 0;
-}
-
-DEFUN (bgp_scan_time,
- bgp_scan_time_cmd,
- "bgp scan-time <5-60>",
- "BGP specific commands\n"
- "Configure background scanner interval\n"
- "Scanner interval (seconds)\n")
-{
- bgp_scan_interval = atoi (argv[0]);
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ p.u.prefix4 = peer->su.sin.sin_addr;
- if (bgp_scan_thread)
+ rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p);
+ if (!rn2)
{
- thread_cancel (bgp_scan_thread);
- bgp_scan_thread =
- thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval);
+ bgp_unlock_node(rn1);
+ return 0;
}
- return CMD_SUCCESS;
-}
+ ret = (rn1 == rn2) ? 1 : 0;
-DEFUN (no_bgp_scan_time,
- no_bgp_scan_time_cmd,
- "no bgp scan-time",
- NO_STR
- "BGP specific commands\n"
- "Configure background scanner interval\n")
-{
- bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT;
+ bgp_unlock_node(rn1);
+ bgp_unlock_node(rn2);
- if (bgp_scan_thread)
- {
- thread_cancel (bgp_scan_thread);
- bgp_scan_thread =
- thread_add_timer (bm->master, bgp_scan_timer, NULL, bgp_scan_interval);
- }
-
- return CMD_SUCCESS;
+ return (ret);
}
-ALIAS (no_bgp_scan_time,
- no_bgp_scan_time_val_cmd,
- "no bgp scan-time <5-60>",
- NO_STR
- "BGP specific commands\n"
- "Configure background scanner interval\n"
- "Scanner interval (seconds)\n")
-
static int
-show_ip_bgp_scan_tables (struct vty *vty, const char detail)
+show_ip_bgp_nexthop_table (struct vty *vty, int detail)
{
struct bgp_node *rn;
struct bgp_nexthop_cache *bnc;
char buf[INET6_ADDRSTRLEN];
- u_char i;
-
- if (bgp_scan_thread)
- vty_out (vty, "BGP scan is running%s", VTY_NEWLINE);
- else
- vty_out (vty, "BGP scan is not running%s", VTY_NEWLINE);
- vty_out (vty, "BGP scan interval is %d%s", bgp_scan_interval, VTY_NEWLINE);
+ struct nexthop *nexthop;
+ time_t tbuf;
+ afi_t afi;
vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE);
- for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP]); rn; rn = bgp_route_next (rn))
- if ((bnc = rn->info) != NULL)
- {
- if (bnc->valid)
- {
- vty_out (vty, " %s valid [IGP metric %d]%s",
- inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE);
- if (detail)
- for (i = 0; i < bnc->nexthop_num; i++)
- switch (bnc->nexthop[i].type)
- {
- case NEXTHOP_TYPE_IPV4:
- vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
- break;
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out (vty, " gate %s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN));
- vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE);
- break;
- case NEXTHOP_TYPE_IFINDEX:
- vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE);
- break;
- default:
- vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE);
- }
- }
- else
- vty_out (vty, " %s invalid%s",
- inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
- }
-
- {
- for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]);
- rn;
- rn = bgp_route_next (rn))
- if ((bnc = rn->info) != NULL)
+ for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+ {
+ for (rn = bgp_table_top (bgp_nexthop_cache_table[afi]); rn; rn = bgp_route_next (rn))
{
- if (bnc->valid)
- {
- vty_out (vty, " %s valid [IGP metric %d]%s",
- inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
- bnc->metric, VTY_NEWLINE);
- if (detail)
- for (i = 0; i < bnc->nexthop_num; i++)
- switch (bnc->nexthop[i].type)
+ if ((bnc = rn->info) != NULL)
+ {
+ if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID))
{
- case NEXTHOP_TYPE_IPV6:
- vty_out (vty, " gate %s%s", inet_ntop (AF_INET6, &bnc->nexthop[i].gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
- break;
- case NEXTHOP_TYPE_IFINDEX:
- vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE);
- break;
- default:
- vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE);
+ vty_out (vty, " %s valid [IGP metric %d], #paths %d%s",
+ inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)),
+ bnc->metric, bnc->path_count, VTY_NEWLINE);
+ if (detail)
+ for (nexthop = bnc->nexthop ; nexthop; nexthop = nexthop->next)
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV6:
+ vty_out (vty, " gate %s%s",
+ inet_ntop (AF_INET6, &nexthop->gate.ipv6,
+ buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ vty_out(vty, " gate %s, if %s%s",
+ inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
+ INET6_ADDRSTRLEN),
+ ifindex2ifname(nexthop->ifindex),
+ VTY_NEWLINE);
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ vty_out (vty, " gate %s%s",
+ inet_ntop (AF_INET, &nexthop->gate.ipv4, buf,
+ INET6_ADDRSTRLEN), VTY_NEWLINE);
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out (vty, " if %s%s",
+ ifindex2ifname(nexthop->ifindex), VTY_NEWLINE);
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out (vty, " gate %s, if %s%s",
+ inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
+ INET6_ADDRSTRLEN),
+ ifindex2ifname(nexthop->ifindex), VTY_NEWLINE);
+ break;
+ default:
+ vty_out (vty, " invalid nexthop type %u%s",
+ nexthop->type, VTY_NEWLINE);
+ }
}
- }
- else
- vty_out (vty, " %s invalid%s",
- inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
- VTY_NEWLINE);
+ else
+ vty_out (vty, " %s invalid%s",
+ inet_ntop (AF_INET, &rn->p.u.prefix, buf, sizeof (buf)), VTY_NEWLINE);
+#ifdef HAVE_CLOCK_MONOTONIC
+ tbuf = time(NULL) - (bgp_clock() - bnc->last_update);
+ vty_out (vty, " Last update: %s", ctime(&tbuf));
+#else
+ vty_out (vty, " Last update: %s", ctime(&bnc->uptime));
+#endif /* HAVE_CLOCK_MONOTONIC */
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
}
- }
-
- vty_out (vty, "BGP connected route:%s", VTY_NEWLINE);
- for (rn = bgp_table_top (bgp_connected_table[AFI_IP]);
- rn;
- rn = bgp_route_next (rn))
- if (rn->info != NULL)
- vty_out (vty, " %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
- VTY_NEWLINE);
-
- {
- for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]);
- rn;
- rn = bgp_route_next (rn))
- if (rn->info != NULL)
- vty_out (vty, " %s/%d%s",
- inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
- rn->p.prefixlen,
- VTY_NEWLINE);
- }
-
+ }
return CMD_SUCCESS;
}
-DEFUN (show_ip_bgp_scan,
- show_ip_bgp_scan_cmd,
- "show ip bgp scan",
+DEFUN (show_ip_bgp_nexthop,
+ show_ip_bgp_nexthop_cmd,
+ "show ip bgp nexthop",
SHOW_STR
IP_STR
BGP_STR
- "BGP scan status\n")
+ "BGP nexthop table\n")
{
- return show_ip_bgp_scan_tables (vty, 0);
+ return show_ip_bgp_nexthop_table (vty, 0);
}
-DEFUN (show_ip_bgp_scan_detail,
- show_ip_bgp_scan_detail_cmd,
- "show ip bgp scan detail",
+DEFUN (show_ip_bgp_nexthop_detail,
+ show_ip_bgp_nexthop_detail_cmd,
+ "show ip bgp nexthop detail",
SHOW_STR
IP_STR
BGP_STR
- "BGP scan status\n"
- "More detailed output\n")
+ "BGP nexthop table\n")
{
- return show_ip_bgp_scan_tables (vty, 1);
-}
-
-int
-bgp_config_write_scan_time (struct vty *vty)
-{
- if (bgp_scan_interval != BGP_SCAN_INTERVAL_DEFAULT)
- vty_out (vty, " bgp scan-time %d%s", bgp_scan_interval, VTY_NEWLINE);
- return CMD_SUCCESS;
+ return show_ip_bgp_nexthop_table (vty, 1);
}
void
bgp_scan_init (void)
{
- zlookup = zclient_new (bm->master);
- zlookup->sock = -1;
- zlookup->t_connect = thread_add_event (bm->master, zlookup_connect, zlookup, 0);
-
- bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT;
- bgp_import_interval = BGP_IMPORT_INTERVAL_DEFAULT;
-
cache1_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
- cache2_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
bgp_nexthop_cache_table[AFI_IP] = cache1_table[AFI_IP];
bgp_connected_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST);
cache1_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
- cache2_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
bgp_nexthop_cache_table[AFI_IP6] = cache1_table[AFI_IP6];
bgp_connected_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST);
- /* Make BGP scan thread. */
- bgp_scan_thread = thread_add_timer (bm->master, bgp_scan_timer,
- NULL, bgp_scan_interval);
- /* Make BGP import there. */
- bgp_import_thread = thread_add_timer (bm->master, bgp_import, NULL, 0);
-
- install_element (BGP_NODE, &bgp_scan_time_cmd);
- install_element (BGP_NODE, &no_bgp_scan_time_cmd);
- install_element (BGP_NODE, &no_bgp_scan_time_val_cmd);
- install_element (VIEW_NODE, &show_ip_bgp_scan_cmd);
- install_element (VIEW_NODE, &show_ip_bgp_scan_detail_cmd);
- install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd);
- install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd);
- install_element (ENABLE_NODE, &show_ip_bgp_scan_detail_cmd);
+}
+
+void
+bgp_scan_vty_init()
+{
+ install_element (ENABLE_NODE, &show_ip_bgp_nexthop_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_nexthop_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_nexthop_detail_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_nexthop_detail_cmd);
}
void
@@ -1432,10 +534,6 @@ bgp_scan_finish (void)
bgp_table_unlock (cache1_table[AFI_IP]);
cache1_table[AFI_IP] = NULL;
- if (cache2_table[AFI_IP])
- bgp_table_unlock (cache2_table[AFI_IP]);
- cache2_table[AFI_IP] = NULL;
-
if (bgp_connected_table[AFI_IP])
bgp_table_unlock (bgp_connected_table[AFI_IP]);
bgp_connected_table[AFI_IP] = NULL;
@@ -1444,10 +542,6 @@ bgp_scan_finish (void)
bgp_table_unlock (cache1_table[AFI_IP6]);
cache1_table[AFI_IP6] = NULL;
- if (cache2_table[AFI_IP6])
- bgp_table_unlock (cache2_table[AFI_IP6]);
- cache2_table[AFI_IP6] = NULL;
-
if (bgp_connected_table[AFI_IP6])
bgp_table_unlock (bgp_connected_table[AFI_IP6]);
bgp_connected_table[AFI_IP6] = NULL;
@@ -1456,12 +550,5 @@ bgp_scan_finish (void)
void
bgp_scan_destroy (void)
{
- if (zlookup == NULL)
- return;
- THREAD_OFF(bgp_import_thread);
- THREAD_OFF(bgp_scan_thread);
- THREAD_OFF(zlookup->t_connect);
bgp_scan_finish();
- zclient_free (zlookup);
- zlookup = NULL;
}
diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h
index 85c5a5d0..fe4f5ad4 100644
--- a/bgpd/bgp_nexthop.h
+++ b/bgpd/bgp_nexthop.h
@@ -22,9 +22,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define _QUAGGA_BGP_NEXTHOP_H
#include "if.h"
-
-#define BGP_SCAN_INTERVAL_DEFAULT 60
-#define BGP_IMPORT_INTERVAL_DEFAULT 15
+#include "queue.h"
+#include "prefix.h"
#define NEXTHOP_FAMILY(nexthop_len) ( \
((nexthop_len) == 4 || \
@@ -38,35 +37,48 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* BGP nexthop cache value structure. */
struct bgp_nexthop_cache
{
- /* This nexthop exists in IGP. */
- u_char valid;
-
- /* Nexthop is changed. */
- u_char changed;
-
- /* Nexthop is changed. */
- u_char metricchanged;
-
/* IGP route's metric. */
u_int32_t metric;
/* Nexthop number and nexthop linked list.*/
u_char nexthop_num;
struct nexthop *nexthop;
+ time_t last_update;
+ u_int16_t flags;
+
+#define BGP_NEXTHOP_VALID (1 << 0)
+#define BGP_NEXTHOP_REGISTERED (1 << 1)
+#define BGP_NEXTHOP_CONNECTED (1 << 2)
+#define BGP_NEXTHOP_PEER_NOTIFIED (1 << 3)
+
+ u_int16_t change_flags;
+
+#define BGP_NEXTHOP_CHANGED (1 << 0)
+#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1)
+#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2)
+
+ struct bgp_node *node;
+ void *nht_info; /* In BGP, peer session */
+ LIST_HEAD(path_list, bgp_info) paths;
+ unsigned int path_count;
};
-extern void bgp_scan_init (void);
-extern void bgp_scan_finish (void);
extern int bgp_nexthop_lookup (afi_t, struct peer *peer, struct bgp_info *,
int *, int *);
extern void bgp_connected_add (struct connected *c);
extern void bgp_connected_delete (struct connected *c);
-extern int bgp_multiaccess_check_v4 (struct in_addr, char *);
+extern int bgp_multiaccess_check_v4 (struct in_addr, struct peer *);
extern int bgp_config_write_scan_time (struct vty *);
extern int bgp_nexthop_onlink (afi_t, struct attr *);
extern int bgp_nexthop_self (struct attr *);
extern void bgp_address_init (void);
extern void bgp_address_destroy (void);
extern void bgp_scan_destroy (void);
+extern struct bgp_nexthop_cache *bnc_new(void);
+extern void bnc_free(struct bgp_nexthop_cache *bnc);
+extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc);
+extern char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size);
+extern void bgp_scan_init (void);
+extern void bgp_scan_vty_init (void);
#endif /* _QUAGGA_BGP_NEXTHOP_H */
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
new file mode 100644
index 00000000..34b5fd1c
--- /dev/null
+++ b/bgpd/bgp_nht.c
@@ -0,0 +1,518 @@
+/* BGP Nexthop tracking
+ * 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 "filter.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_nht.h"
+#include "bgpd/bgp_fsm.h"
+
+extern struct zclient *zclient;
+extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
+
+static void register_nexthop(struct bgp_nexthop_cache *bnc);
+static void unregister_nexthop (struct bgp_nexthop_cache *bnc);
+static void evaluate_paths(struct bgp_nexthop_cache *bnc);
+static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p);
+static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc,
+ int keep);
+
+int
+bgp_find_nexthop (struct bgp_info *path, int connected)
+{
+ struct bgp_nexthop_cache *bnc = path->nexthop;
+
+ if (!bnc)
+ return 0;
+
+ if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)))
+ return 0;
+
+ return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
+}
+
+void
+bgp_unlink_nexthop (struct bgp_info *path)
+{
+ struct bgp_nexthop_cache *bnc = path->nexthop;
+
+ if (!bnc)
+ return;
+
+ path_nh_map(path, NULL, 0);
+
+ if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info)
+ {
+ if (BGP_DEBUG(nht, NHT))
+ {
+ char buf[INET6_ADDRSTRLEN];
+ zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
+ bnc_str(bnc, buf, INET6_ADDRSTRLEN));
+ }
+ unregister_nexthop(bnc);
+ bnc->node->info = NULL;
+ bgp_unlock_node(bnc->node);
+ bnc_free(bnc);
+ }
+}
+
+int
+bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, struct peer *peer,
+ int connected)
+{
+ struct bgp_node *rn;
+ struct bgp_nexthop_cache *bnc;
+ struct prefix p;
+
+ if (ri)
+ {
+ if (make_prefix(afi, ri, &p) < 0)
+ return 1;
+ }
+ else if (peer)
+ {
+ if (afi == AFI_IP)
+ {
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ p.u.prefix4 = peer->su.sin.sin_addr;
+ }
+ else if (afi == AFI_IP6)
+ {
+ p.family = AF_INET6;
+ p.prefixlen = IPV6_MAX_BITLEN;
+ p.u.prefix6 = peer->su.sin6.sin6_addr;
+ }
+ }
+
+ rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p);
+
+ if (!rn->info)
+ {
+ bnc = bnc_new();
+ rn->info = bnc;
+ bnc->node = rn;
+ bgp_lock_node(rn);
+ if (connected)
+ SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
+ }
+
+ bnc = rn->info;
+ bgp_unlock_node (rn);
+
+ if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
+ register_nexthop(bnc);
+
+ if (ri)
+ {
+ path_nh_map(ri, bnc, 1);
+
+ if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
+ (bgp_info_extra_get(ri))->igpmetric = bnc->metric;
+ else if (ri->extra)
+ ri->extra->igpmetric = 0;
+ }
+ else if (peer)
+ bnc->nht_info = (void *)peer;
+
+ return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
+}
+
+void
+bgp_parse_nexthop_update (void)
+{
+ struct stream *s;
+ struct bgp_node *rn;
+ struct bgp_nexthop_cache *bnc;
+ struct nexthop *nexthop;
+ struct nexthop *oldnh;
+ struct nexthop *nhlist_head = NULL;
+ struct nexthop *nhlist_tail = NULL;
+ uint32_t metric;
+ u_char nexthop_num;
+ struct prefix p;
+ int i;
+
+ s = zclient->ibuf;
+
+ memset(&p, 0, sizeof(struct prefix));
+ p.family = stream_getw(s);
+ p.prefixlen = stream_getc(s);
+ switch (p.family)
+ {
+ case AF_INET:
+ p.u.prefix4.s_addr = stream_get_ipv4 (s);
+ break;
+ case AF_INET6:
+ stream_get(&p.u.prefix6, s, 16);
+ break;
+ default:
+ break;
+ }
+
+ rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p);
+ if (!rn || !rn->info)
+ {
+ if (BGP_DEBUG(nht, NHT))
+ {
+ char buf[INET6_ADDRSTRLEN];
+ prefix2str(&p, buf, INET6_ADDRSTRLEN);
+ zlog_debug("parse nexthop update(%s): rn not found", buf);
+ }
+ if (rn)
+ bgp_unlock_node (rn);
+ return;
+ }
+
+ bnc = rn->info;
+ bgp_unlock_node (rn);
+ bnc->last_update = bgp_clock();
+ bnc->change_flags = 0;
+ metric = stream_getl (s);
+ nexthop_num = stream_getc (s);
+
+ /* debug print the input */
+ if (BGP_DEBUG(nht, NHT))
+ {
+ char buf[INET6_ADDRSTRLEN];
+ prefix2str(&p, buf, INET6_ADDRSTRLEN);
+ zlog_debug("parse nexthop update(%s): metric=%d, #nexthop=%d", buf,
+ metric, nexthop_num);
+ }
+
+ if (metric != bnc->metric)
+ bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
+
+ if(nexthop_num != bnc->nexthop_num)
+ bnc->change_flags |= BGP_NEXTHOP_CHANGED;
+
+ if (nexthop_num)
+ {
+ bnc->flags |= BGP_NEXTHOP_VALID;
+ bnc->metric = metric;
+ bnc->nexthop_num = nexthop_num;
+
+ for (i = 0; i < nexthop_num; i++)
+ {
+ nexthop = nexthop_new();
+ nexthop->type = stream_getc (s);
+ switch (nexthop->type)
+ {
+ case ZEBRA_NEXTHOP_IPV4:
+ nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
+ break;
+ case ZEBRA_NEXTHOP_IFINDEX:
+ case ZEBRA_NEXTHOP_IFNAME:
+ nexthop->ifindex = stream_getl (s);
+ break;
+ case ZEBRA_NEXTHOP_IPV4_IFINDEX:
+ case ZEBRA_NEXTHOP_IPV4_IFNAME:
+ nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
+ nexthop->ifindex = stream_getl (s);
+ break;
+#ifdef HAVE_IPV6
+ case ZEBRA_NEXTHOP_IPV6:
+ stream_get (&nexthop->gate.ipv6, s, 16);
+ break;
+ case ZEBRA_NEXTHOP_IPV6_IFINDEX:
+ case ZEBRA_NEXTHOP_IPV6_IFNAME:
+ stream_get (&nexthop->gate.ipv6, s, 16);
+ nexthop->ifindex = stream_getl (s);
+ break;
+#endif
+ default:
+ /* do nothing */
+ break;
+ }
+
+ if (nhlist_tail)
+ {
+ nhlist_tail->next = nexthop;
+ nhlist_tail = nexthop;
+ }
+ else
+ {
+ nhlist_tail = nexthop;
+ nhlist_head = nexthop;
+ }
+
+ /* No need to evaluate the nexthop if we have already determined
+ * that there has been a change.
+ */
+ if (bnc->change_flags & BGP_NEXTHOP_CHANGED)
+ continue;
+
+ for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
+ if (nexthop_same_no_recurse(oldnh, nexthop))
+ break;
+
+ if (!oldnh)
+ bnc->change_flags |= BGP_NEXTHOP_CHANGED;
+ }
+ bnc_nexthop_free(bnc);
+ bnc->nexthop = nhlist_head;
+ }
+ else
+ {
+ bnc->flags &= ~BGP_NEXTHOP_VALID;
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
+ bnc_nexthop_free(bnc);
+ bnc->nexthop = NULL;
+ }
+
+ evaluate_paths(bnc);
+}
+
+/**
+ * make_prefix - make a prefix structure from the path (essentially
+ * path's node.
+ */
+static int
+make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
+{
+ memset (p, 0, sizeof (struct prefix));
+ switch (afi)
+ {
+ case AFI_IP:
+ p->family = AF_INET;
+ p->prefixlen = IPV4_MAX_BITLEN;
+ p->u.prefix4 = ri->attr->nexthop;
+ break;
+#ifdef HAVE_IPV6
+ case AFI_IP6:
+ if (ri->attr->extra->mp_nexthop_len != 16
+ || IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global))
+ return -1;
+
+ p->family = AF_INET6;
+ p->prefixlen = IPV6_MAX_BITLEN;
+ p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
+ break;
+#endif
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+ * sendmsg_nexthop -- Format and send a nexthop register/Unregister
+ * command to Zebra.
+ * ARGUMENTS:
+ * struct bgp_nexthop_cache *bnc -- the nexthop structure.
+ * int command -- either ZEBRA_NEXTHOP_REGISTER or ZEBRA_NEXTHOP_UNREGISTER
+ * RETURNS:
+ * void.
+ */
+static void
+sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
+{
+ struct stream *s;
+ struct prefix *p;
+ int ret;
+
+ /* Check socket. */
+ if (!zclient || zclient->sock < 0)
+ {
+ zlog_debug("%s: Can't send NH register, Zebra client not established",
+ __FUNCTION__);
+ return;
+ }
+
+ p = &(bnc->node->p);
+ s = zclient->obuf;
+ stream_reset (s);
+ zclient_create_header (s, command, VRF_DEFAULT);
+ if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
+ stream_putc(s, 1);
+ else
+ stream_putc(s, 0);
+
+ stream_putw(s, PREFIX_FAMILY(p));
+ stream_putc(s, p->prefixlen);
+ switch (PREFIX_FAMILY(p))
+ {
+ case AF_INET:
+ stream_put_in_addr (s, &p->u.prefix4);
+ break;
+ case AF_INET6:
+ stream_put(s, &(p->u.prefix6), 16);
+ break;
+ default:
+ break;
+ }
+ stream_putw_at (s, 0, stream_get_endp (s));
+
+ ret = zclient_send_message(zclient);
+ /* TBD: handle the failure */
+ if (ret < 0)
+ zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
+
+ if (command == ZEBRA_NEXTHOP_REGISTER)
+ SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
+ else if (command == ZEBRA_NEXTHOP_UNREGISTER)
+ UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
+ return;
+}
+
+/**
+ * register_nexthop - register a nexthop with Zebra for notification
+ * when the route to the nexthop changes.
+ * ARGUMENTS:
+ * struct bgp_nexthop_cache *bnc -- the nexthop structure.
+ * RETURNS:
+ * void.
+ */
+static void
+register_nexthop (struct bgp_nexthop_cache *bnc)
+{
+ /* Check if we have already registered */
+ if (bnc->flags & BGP_NEXTHOP_REGISTERED)
+ return;
+ sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER);
+}
+
+/**
+ * unregister_nexthop -- Unregister the nexthop from Zebra.
+ * ARGUMENTS:
+ * struct bgp_nexthop_cache *bnc -- the nexthop structure.
+ * RETURNS:
+ * void.
+ */
+static void
+unregister_nexthop (struct bgp_nexthop_cache *bnc)
+{
+ /* Check if we have already registered */
+ if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
+ return;
+
+ sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER);
+}
+
+/**
+ * evaluate_paths - Evaluate the paths/nets associated with a nexthop.
+ * ARGUMENTS:
+ * struct bgp_nexthop_cache *bnc -- the nexthop structure.
+ * RETURNS:
+ * void.
+ */
+static void
+evaluate_paths (struct bgp_nexthop_cache *bnc)
+{
+ struct bgp_node *rn;
+ struct bgp_info *path;
+ struct bgp *bgp = bgp_get_default();
+ int afi;
+ struct peer *peer = (struct peer *)bnc->nht_info;
+
+ LIST_FOREACH(path, &(bnc->paths), nh_thread)
+ {
+ if (!(path->type == ZEBRA_ROUTE_BGP &&
+ path->sub_type == BGP_ROUTE_NORMAL))
+ continue;
+
+ rn = path->net;
+ afi = family2afi(rn->p.family);
+
+ /* Path becomes valid/invalid depending on whether the nexthop
+ * reachable/unreachable.
+ */
+ if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0) !=
+ (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) ? 1 : 0))
+ {
+ if (CHECK_FLAG (path->flags, BGP_INFO_VALID))
+ {
+ bgp_aggregate_decrement (bgp, &rn->p, path,
+ afi, SAFI_UNICAST);
+ 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);
+ }
+ }
+
+ /* Copy the metric to the path. Will be used for bestpath computation */
+ if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
+ (bgp_info_extra_get(path))->igpmetric = bnc->metric;
+ else if (path->extra)
+ path->extra->igpmetric = 0;
+
+ if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_METRIC_CHANGED) ||
+ CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CHANGED))
+ SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED);
+
+ bgp_process(bgp, rn, afi, SAFI_UNICAST);
+ }
+
+ if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED))
+ {
+ if (BGP_DEBUG(nht, NHT))
+ zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host);
+ bgp_fsm_nht_update(peer, CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
+ SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
+ }
+
+ RESET_FLAG(bnc->change_flags);
+}
+
+/**
+ * path_nh_map - make or break path-to-nexthop association.
+ * ARGUMENTS:
+ * path - pointer to the path structure
+ * bnc - pointer to the nexthop structure
+ * make - if set, make the association. if unset, just break the existing
+ * association.
+ */
+static void
+path_nh_map (struct bgp_info *path, struct bgp_nexthop_cache *bnc, int make)
+{
+ if (path->nexthop)
+ {
+ LIST_REMOVE(path, nh_thread);
+ path->nexthop->path_count--;
+ path->nexthop = NULL;
+ }
+ if (make)
+ {
+ LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread);
+ path->nexthop = bnc;
+ path->nexthop->path_count++;
+ }
+}
diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h
new file mode 100644
index 00000000..2bced7fb
--- /dev/null
+++ b/bgpd/bgp_nht.h
@@ -0,0 +1,58 @@
+/* BGP Nexthop tracking
+ * 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_NHT_H
+#define _BGP_NHT_H
+
+/**
+ * bgp_parse_nexthop_update() - parse a nexthop update message from Zebra.
+ */
+extern void bgp_parse_nexthop_update(void);
+
+/**
+ * bgp_find_nexthop() - lookup the nexthop cache table for the bnc object
+ * ARGUMENTS:
+ * p - path for which the nexthop object is being looked up
+ * connected - True if NH MUST be a connected route
+ */
+extern int bgp_find_nexthop(struct bgp_info *p, int connected);
+
+/**
+ * bgp_find_or_add_nexthop() - lookup the nexthop cache table for the bnc
+ * object. If not found, create a new object and register with ZEBRA for
+ * nexthop notification.
+ * ARGUMENTS:
+ * a - afi: AFI_IP or AF_IP6
+ * p - path for which the nexthop object is being looked up
+ * peer - The BGP peer associated with this NHT
+ * connected - True if NH MUST be a connected route
+ */
+extern int bgp_find_or_add_nexthop(afi_t a, struct bgp_info *p,
+ struct peer *peer, int connected);
+
+/**
+ * bgp_unlink_nexthop() - Unlink the nexthop object from the path structure.
+ * ARGUMENTS:
+ * p - path structure.
+ */
+extern void bgp_unlink_nexthop(struct bgp_info *p);
+
+#endif /* _BGP_NHT_H */
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 7b8b6577..35387f17 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -160,7 +160,7 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
bgp_capability_mp_data (s, &mpc);
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
peer->host, mpc.afi, mpc.safi);
@@ -182,7 +182,7 @@ static void
bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi,
u_char type, u_char mode)
{
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported",
peer->host, afi, safi, type, mode);
}
@@ -221,7 +221,7 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
afi = entry.mpc.afi;
safi = entry.mpc.safi;
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u",
peer->host, entry.mpc.afi, entry.mpc.safi);
@@ -298,7 +298,7 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
continue;
}
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s OPEN has %s ORF capability"
" as %s for afi/safi: %d/%d",
peer->host, LOOKUP (orf_type_str, type),
@@ -353,7 +353,7 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
UNSET_FLAG (restart_flag_time, 0xF000);
peer->v_gr_restart = restart_flag_time;
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
{
zlog_debug ("%s OPEN has Graceful Restart capability", peer->host);
zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
@@ -371,21 +371,21 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
if (!bgp_afi_safi_valid_indices (afi, &safi))
{
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
" Ignore the Graceful Restart capability",
peer->host, afi, safi);
}
else if (!peer->afc[afi][safi])
{
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled."
" Ignore the Graceful Restart capability",
peer->host, afi, safi);
}
else
{
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Address family %s is%spreserved", peer->host,
afi_safi_print (afi, safi),
CHECK_FLAG (peer->af_cap[afi][safi],
@@ -507,7 +507,7 @@ bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability,
return -1;
}
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s OPEN has %s capability (%u), length %u",
peer->host,
LOOKUP (capcode_str, caphdr.code),
@@ -750,7 +750,7 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability)
ret = 0;
error = error_data;
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u",
peer->host, length);
@@ -781,7 +781,7 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability)
return -1;
}
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u",
peer->host, opt_type,
opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" :
@@ -851,12 +851,11 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability)
&& ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]
&& ! peer->afc_nego[AFI_IP6][SAFI_ENCAP])
{
- plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not "
+ zlog_err ("%s [Error] Configured AFI/SAFIs do not "
"overlap with received MP capabilities",
peer->host);
if (error != error_data)
-
bgp_notify_send_with_data (peer,
BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_UNSUP_CAPBL,
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 740b0f1c..3fd584c5 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -103,8 +103,8 @@ bgp_packet_delete (struct peer *peer)
}
/* Check file descriptor whether connect is established. */
-static void
-bgp_connect_check (struct peer *peer)
+int
+bgp_connect_check (struct peer *peer, int change_state)
{
int status;
socklen_t slen;
@@ -121,22 +121,25 @@ bgp_connect_check (struct peer *peer)
/* If getsockopt is fail, this is fatal error. */
if (ret < 0)
{
- zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect");
+ zlog_info ("can't get sockopt for nonblocking connect");
BGP_EVENT_ADD (peer, TCP_fatal_error);
- return;
+ return -1;
}
/* When status is 0 then TCP connection is established. */
if (status == 0)
{
BGP_EVENT_ADD (peer, TCP_connection_open);
+ return 1;
}
else
{
- if (BGP_DEBUG (events, EVENTS))
- plog_debug (peer->log, "%s [Event] Connect failed (%s)",
- peer->host, safe_strerror (errno));
- BGP_EVENT_ADD (peer, TCP_connection_open_failed);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s [Event] Connect failed (%s)",
+ peer->host, safe_strerror (errno));
+ if (change_state)
+ BGP_EVENT_ADD (peer, TCP_connection_open_failed);
+ return 0;
}
}
@@ -153,8 +156,13 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
struct bgp_info *binfo = NULL;
bgp_size_t total_attr_len = 0;
unsigned long attrlen_pos = 0;
+ int space_remaining = 0;
+ int space_needed = 0;
size_t mpattrlen_pos = 0;
size_t mpattr_pos = 0;
+ int num_pfx_adv = 0;
+ char send_attr_str[BUFSIZ];
+ int send_attr_printed = 0;
s = peer->work;
stream_reset (s);
@@ -171,9 +179,12 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
if (adv->binfo)
binfo = adv->binfo;
+ space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) -
+ BGP_MAX_PACKET_SIZE_OVERFLOW;
+ space_needed = BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size (afi, safi, &rn->p);
+
/* When remaining space can't include NLRI and it's length. */
- if (STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) <=
- (BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size(afi,safi,&rn->p)))
+ if (space_remaining < space_needed)
break;
/* If packet is empty, set attribute. */
@@ -217,6 +228,29 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
&rn->p : NULL),
afi, safi,
from, prd, tag);
+ space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) -
+ BGP_MAX_PACKET_SIZE_OVERFLOW;
+ space_needed = BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size (afi, safi, &rn->p);;
+
+ /* If the attributes alone do not leave any room for NLRI then
+ * return */
+ if (space_remaining < space_needed)
+ {
+ zlog_err ("%s cannot send UPDATE, the attributes do not leave "
+ "room for NLRI", peer->host);
+ /* Flush the FIFO update queue */
+ while (adv)
+ adv = bgp_advertise_clean (peer, adv->adj, afi, safi);
+ return NULL;
+ }
+
+ if (BGP_DEBUG (update, UPDATE_OUT) ||
+ BGP_DEBUG (update, UPDATE_PREFIX))
+ {
+ memset (send_attr_str, 0, BUFSIZ);
+ send_attr_printed = 0;
+ bgp_dump_attr (peer, adv->baa->attr, send_attr_str, BUFSIZ);
+ }
}
if (afi == AFI_IP && safi == SAFI_UNICAST)
@@ -237,14 +271,21 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
adv->baa->attr);
bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd, tag);
}
- if (BGP_DEBUG (update, UPDATE_OUT))
+ num_pfx_adv++;
+
+ if (bgp_debug_update(peer, &rn->p, 0))
{
+ if (!send_attr_printed)
+ {
+ zlog_debug ("%s send UPDATE w/ attr: %s", peer->host, send_attr_str);
+ send_attr_printed = 1;
+ }
char buf[INET6_BUFSIZ];
- zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d",
- peer->host,
- inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ),
- rn->p.prefixlen);
+ zlog_debug ("%s send UPDATE %s/%d",
+ peer->host,
+ inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ),
+ rn->p.prefixlen);
}
/* Synchnorize attribute. */
@@ -274,8 +315,11 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
else
packet = stream_dup (s);
bgp_packet_set_size (packet);
+ if (BGP_DEBUG (update, UPDATE_OUT))
+ zlog_debug("%s form UPDATE (adv) total len %zd numPfx %d",
+ peer->host,
+ (stream_get_endp (s) - stream_get_getp (s)), num_pfx_adv);
bgp_packet_add (peer, packet);
- BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
stream_reset (s);
stream_reset (snlri);
return packet;
@@ -291,7 +335,7 @@ bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi)
if (DISABLE_BGP_ANNOUNCE)
return NULL;
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("send End-of-RIB for %s to %s", afi_safi_print (afi, safi), peer->host);
s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -347,6 +391,9 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi)
size_t attrlen_pos = 0;
size_t mplen_pos = 0;
u_char first_time = 1;
+ int space_remaining = 0;
+ int space_needed = 0;
+ int num_pfx_wd = 0;
s = peer->work;
stream_reset (s);
@@ -357,8 +404,12 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi)
adj = adv->adj;
rn = adv->rn;
- if (STREAM_REMAIN (s)
- < (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen)))
+ space_remaining = STREAM_REMAIN (s) -
+ BGP_MAX_PACKET_SIZE_OVERFLOW;
+ space_needed = (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN +
+ bgp_packet_mpattr_prefix_size (afi, safi, &rn->p));
+
+ if (space_remaining < space_needed)
break;
if (stream_empty (s))
@@ -390,15 +441,16 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi)
bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd, NULL);
}
+ num_pfx_wd++;
- if (BGP_DEBUG (update, UPDATE_OUT))
+ if (bgp_debug_update(peer, &rn->p, 0))
{
char buf[INET6_BUFSIZ];
- zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable",
- peer->host,
- inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ),
- rn->p.prefixlen);
+ zlog_debug ("%s send UPDATE %s/%d -- unreachable",
+ peer->host,
+ inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ),
+ rn->p.prefixlen);
}
peer->scount[afi][safi]--;
@@ -426,6 +478,10 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi)
stream_putw_at (s, attrlen_pos, total_attr_len);
}
bgp_packet_set_size (s);
+ if (BGP_DEBUG (update, UPDATE_OUT))
+ zlog_debug("%s form UPDATE (wd) total len %zd numPfx %d",
+ peer->host,
+ (stream_get_endp (s) - stream_get_getp (s)), num_pfx_wd);
packet = stream_dup (s);
bgp_packet_add (peer, packet);
stream_reset (s);
@@ -453,16 +509,16 @@ bgp_default_update_send (struct peer *peer, struct attr *attr,
str2prefix ("::/0", &p);
/* Logging the attribute. */
- if (BGP_DEBUG (update, UPDATE_OUT))
+ if (bgp_debug_update(peer, &p, 0))
{
char attrstr[BUFSIZ];
char buf[INET6_BUFSIZ];
attrstr[0] = '\0';
bgp_dump_attr (peer, attr, attrstr, BUFSIZ);
- zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d %s",
- peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
- p.prefixlen, attrstr);
+ zlog_debug ("%s send UPDATE %s/%d %s",
+ peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
+ p.prefixlen, attrstr);
}
s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -521,13 +577,13 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi)
total_attr_len = 0;
- if (BGP_DEBUG (update, UPDATE_OUT))
+ if (bgp_debug_update(peer, &p, 0))
{
char buf[INET6_BUFSIZ];
- zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable",
- peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
- p.prefixlen);
+ zlog_debug ("%s send UPDATE %s/%d -- unreachable",
+ peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
+ p.prefixlen);
}
s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -589,6 +645,12 @@ bgp_write_packet (struct peer *peer)
if (s)
return s;
+ /* The code beyond this part deals with update packets, check if updates
+ are on hold as part of the update-delay post processing stages. */
+ if (peer->bgp && (peer->bgp->main_peers_update_hold ||
+ peer->bgp->rsclient_peers_update_hold))
+ return NULL;
+
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
{
@@ -607,7 +669,7 @@ bgp_write_packet (struct peer *peer)
adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update);
if (adv)
{
- if (adv->binfo && adv->binfo->uptime < peer->synctime)
+ if (adv->binfo && adv->binfo->uptime <= peer->synctime)
{
if (CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_RCV)
&& CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_ADV)
@@ -645,28 +707,82 @@ bgp_write_packet (struct peer *peer)
return NULL;
}
-/* Is there partially written packet or updates we can send right
- now. */
-static int
-bgp_write_proceed (struct peer *peer)
+/* Are there prefixes queued for being withdrawn? */
+int
+bgp_peer_wd_fifo_exists (struct peer *peer)
{
afi_t afi;
safi_t safi;
- struct bgp_advertise *adv;
-
- if (stream_fifo_head (peer->obuf))
- return 1;
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
if (FIFO_HEAD (&peer->sync[afi][safi]->withdraw))
return 1;
+ return 0;
+}
+
+/* Are there prefixes queued for being advertised?
+ * Are they recent?
+ */
+int
+bgp_peer_adv_fifo_exists (struct peer *peer, int chk_recent)
+{
+ afi_t afi;
+ safi_t safi;
+ struct bgp_advertise *adv;
+
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
if ((adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL)
- if (adv->binfo->uptime < peer->synctime)
- return 1;
+ {
+ if (!chk_recent)
+ return 1;
+ if (adv->binfo->uptime < peer->synctime)
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Schedule updates for the peer, if needed.
+ */
+void
+bgp_peer_schedule_updates(struct peer *peer)
+{
+ /* If withdraw FIFO exists, immediately schedule write */
+ if (bgp_peer_wd_fifo_exists(peer) && !peer->t_write)
+ {
+ if (bgp_debug_update(peer, NULL, 0))
+ zlog_debug("%s scheduling write thread", peer->host);
+ BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+ }
+
+ /* If update FIFO exists, fire MRAI timer */
+ if (bgp_peer_adv_fifo_exists(peer, 0) && !peer->radv_adjusted)
+ {
+ if (bgp_debug_update(peer, NULL, 0))
+ zlog_debug("%s scheduling MRAI timer", peer->host);
+ bgp_adjust_routeadv(peer);
+ }
+}
+
+/* Is there partially written packet or updates we can send right
+ now. */
+static int
+bgp_write_proceed (struct peer *peer)
+{
+ /* If queued packet exists, we should try to write it */
+ if (stream_fifo_head (peer->obuf))
+ return 1;
+
+ /* If there are prefixes to be withdrawn or to be advertised (and
+ * queued before last MRAI timer expiry), schedule write
+ */
+ if (bgp_peer_wd_fifo_exists(peer)
+ || bgp_peer_adv_fifo_exists(peer, 1))
+ return 1;
return 0;
}
@@ -680,6 +796,7 @@ bgp_write (struct thread *thread)
struct stream *s;
int num;
unsigned int count = 0;
+ unsigned int oc = 0;
/* Yes first of all get peer pointer. */
peer = THREAD_ARG (thread);
@@ -688,7 +805,7 @@ bgp_write (struct thread *thread)
/* For non-blocking IO check. */
if (peer->status == Connect)
{
- bgp_connect_check (peer);
+ bgp_connect_check (peer, 1);
return 0;
}
@@ -698,6 +815,8 @@ bgp_write (struct thread *thread)
sockopt_cork (peer->fd, 1);
+ oc = peer->update_out;
+
/* Nonblocking write until TCP output buffer is full. */
do
{
@@ -765,13 +884,17 @@ bgp_write (struct thread *thread)
/* OK we send packet so delete it. */
bgp_packet_delete (peer);
}
- while (++count < BGP_WRITE_PACKET_MAX &&
+ while (++count < peer->bgp->wpkt_quanta &&
(s = bgp_write_packet (peer)) != NULL);
-
+
if (bgp_write_proceed (peer))
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
done:
+ /* Update the last write if some updates were written. */
+ if (peer->update_out > oc)
+ peer->last_write = bgp_clock ();
+
sockopt_cork (peer->fd, 0);
return 0;
}
@@ -826,6 +949,8 @@ bgp_write_notify (struct peer *peer)
if (peer->v_start >= (60 * 2))
peer->v_start = (60 * 2);
+ /* Handle Graceful Restart case where the state changes to
+ Connect instead of Idle */
BGP_EVENT_ADD (peer, BGP_Stop);
return 0;
@@ -836,7 +961,6 @@ void
bgp_keepalive_send (struct peer *peer)
{
struct stream *s;
- int length;
s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -844,16 +968,13 @@ bgp_keepalive_send (struct peer *peer)
bgp_packet_set_marker (s, BGP_MSG_KEEPALIVE);
/* Set packet size. */
- length = bgp_packet_set_size (s);
+ (void)bgp_packet_set_size (s);
/* Dump packet if debug option is set. */
/* bgp_packet_dump (s); */
- if (BGP_DEBUG (keepalive, KEEPALIVE))
+ if (bgp_debug_keepalive(peer))
zlog_debug ("%s sending KEEPALIVE", peer->host);
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s send message type %d, length (incl. header) %d",
- peer->host, BGP_MSG_KEEPALIVE, length);
/* Add packet to the peer. */
bgp_packet_add (peer, s);
@@ -866,7 +987,6 @@ void
bgp_open_send (struct peer *peer)
{
struct stream *s;
- int length;
u_int16_t send_holdtime;
as_t local_as;
@@ -897,17 +1017,13 @@ bgp_open_send (struct peer *peer)
bgp_open_capability (s, peer);
/* Set BGP packet length. */
- length = bgp_packet_set_size (s);
+ (void)bgp_packet_set_size (s);
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s sending OPEN, version %d, my as %u, holdtime %d, id %s",
peer->host, BGP_VERSION_4, local_as,
send_holdtime, inet_ntoa (peer->local_id));
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s send message type %d, length (incl. header) %d",
- peer->host, BGP_MSG_OPEN, length);
-
/* Dump packet if debug option is set. */
/* bgp_packet_dump (s); */
@@ -984,33 +1100,16 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code,
}
}
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s send message type %d, length (incl. header) %d",
- peer->host, BGP_MSG_NOTIFY, length);
-
/* peer reset cause */
if (sub_code != BGP_NOTIFY_CEASE_CONFIG_CHANGE)
{
if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET)
- {
peer->last_reset = PEER_DOWN_USER_RESET;
- zlog_info ("Notification sent to neighbor %s: User reset", peer->host);
- }
else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN)
- {
peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
- zlog_info ("Notification sent to neighbor %s: shutdown", peer->host);
- }
else
- {
peer->last_reset = PEER_DOWN_NOTIFY_SEND;
- zlog_info ("Notification sent to neighbor %s: type %u/%u",
- peer->host, code, sub_code);
- }
}
- else
- zlog_info ("Notification sent to neighbor %s: configuration change",
- peer->host);
/* Call immediately. */
BGP_WRITE_OFF (peer->t_write);
@@ -1031,7 +1130,6 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
u_char orf_type, u_char when_to_refresh, int remove)
{
struct stream *s;
- int length;
struct bgp_filter *filter;
int orf_refresh = 0;
@@ -1074,7 +1172,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
{
UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND);
stream_putc (s, ORF_COMMON_PART_REMOVE_ALL);
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d",
peer->host, orf_type,
(when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"),
@@ -1086,7 +1184,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].plist,
ORF_COMMON_PART_ADD, ORF_COMMON_PART_PERMIT,
ORF_COMMON_PART_DENY);
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d",
peer->host, orf_type,
(when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"),
@@ -1099,16 +1197,13 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
}
/* Set packet size. */
- length = bgp_packet_set_size (s);
+ (void)bgp_packet_set_size (s);
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
{
if (! orf_refresh)
zlog_debug ("%s sending REFRESH_REQ for afi/safi: %d/%d",
peer->host, afi, safi);
- zlog_debug ("%s send message type %d, length (incl. header) %d",
- peer->host, CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV) ?
- BGP_MSG_ROUTE_REFRESH_NEW : BGP_MSG_ROUTE_REFRESH_OLD, length);
}
/* Add packet to the peer. */
@@ -1123,7 +1218,6 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,
int capability_code, int action)
{
struct stream *s;
- int length;
/* Adjust safi code. */
if (safi == SAFI_MPLS_VPN)
@@ -1144,23 +1238,18 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,
stream_putc (s, 0);
stream_putc (s, safi);
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s sending CAPABILITY has %s MP_EXT CAP for afi/safi: %d/%d",
peer->host, action == CAPABILITY_ACTION_SET ?
"Advertising" : "Removing", afi, safi);
}
/* Set packet size. */
- length = bgp_packet_set_size (s);
-
+ (void)bgp_packet_set_size (s);
/* Add packet to the peer. */
bgp_packet_add (peer, s);
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s send message type %d, length (incl. header) %d",
- peer->host, BGP_MSG_CAPABILITY, length);
-
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
}
@@ -1169,13 +1258,7 @@ static int
bgp_collision_detect (struct peer *new, struct in_addr remote_id)
{
struct peer *peer;
- struct listnode *node, *nnode;
- struct bgp *bgp;
- bgp = bgp_get_default ();
- if (! bgp)
- return 0;
-
/* Upon receipt of an OPEN message, the local system must examine
all of its connections that are in the OpenConfirm state. A BGP
speaker may also examine connections in an OpenSent state if it
@@ -1185,31 +1268,42 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id)
OPEN message, then the local system performs the following
collision resolution procedure: */
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ if ((peer = new->doppelganger) != NULL)
{
- /* Under OpenConfirm status, local peer structure already hold
- remote router ID. */
-
- if (peer != new
- && (peer->status == OpenConfirm || peer->status == OpenSent)
- && sockunion_same (&peer->su, &new->su))
+ /* Do not accept the new connection in Established or Clearing states.
+ * Note that a peer GR is handled by closing the existing connection
+ * upon receipt of new one.
+ */
+ if (peer->status == Established || peer->status == Clearing)
+ {
+ bgp_notify_send (new, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
+ return (-1);
+ }
+ else if ((peer->status == OpenConfirm) || (peer->status == OpenSent))
{
/* 1. The BGP Identifier of the local system is compared to
the BGP Identifier of the remote system (as specified in
the OPEN message). */
if (ntohl (peer->local_id.s_addr) < ntohl (remote_id.s_addr))
- {
- /* 2. If the value of the local BGP Identifier is less
- than the remote one, the local system closes BGP
- connection that already exists (the one that is
- already in the OpenConfirm state), and accepts BGP
- connection initiated by the remote system. */
-
- if (peer->fd >= 0)
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
- return 1;
- }
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ {
+ /* 2. If the value of the local BGP Identifier is less
+ than the remote one, the local system closes BGP
+ connection that already exists (the one that is
+ already in the OpenConfirm state), and accepts BGP
+ connection initiated by the remote system. */
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
+ return 1;
+ }
+ else
+ {
+ bgp_notify_send (new, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
+ return -1;
+ }
else
{
/* 3. Otherwise, the local system closes newly created
@@ -1217,11 +1311,18 @@ bgp_collision_detect (struct peer *new, struct in_addr remote_id)
received OPEN message), and continues to use the
existing one (the one that is already in the
OpenConfirm state). */
-
- if (new->fd >= 0)
- bgp_notify_send (new, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
- return -1;
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ {
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
+ return 1;
+ }
+ else
+ {
+ bgp_notify_send (new, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
+ return -1;
+ }
}
}
}
@@ -1238,24 +1339,23 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
u_int16_t send_holdtime;
as_t remote_as;
as_t as4 = 0;
- struct peer *realpeer;
struct in_addr remote_id;
int mp_capability;
u_int8_t notify_data_remote_as[2];
u_int8_t notify_data_remote_id[4];
+ u_int16_t *holdtime_ptr;
- realpeer = NULL;
-
/* Parse open packet. */
version = stream_getc (peer->ibuf);
memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2);
remote_as = stream_getw (peer->ibuf);
+ holdtime_ptr = (u_int16_t *)stream_pnt (peer->ibuf);
holdtime = stream_getw (peer->ibuf);
memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4);
remote_id.s_addr = stream_get_ipv4 (peer->ibuf);
/* Receive OPEN message log */
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s rcv OPEN, version %d, remote-as (in open) %u,"
" holdtime %d, id %s",
peer->host, version, remote_as, holdtime,
@@ -1294,8 +1394,8 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
{
zlog_err ("%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed",
peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_PEER_AS);
+ bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_BAD_PEER_AS);
return -1;
}
@@ -1325,154 +1425,12 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
}
}
- /* Lookup peer from Open packet. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- int as = 0;
-
- realpeer = peer_lookup_with_open (&peer->su, remote_as, &remote_id, &as);
-
- if (! realpeer)
- {
- /* Peer's source IP address is check in bgp_accept(), so this
- must be AS number mismatch or remote-id configuration
- mismatch. */
- if (as)
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad OPEN, wrong router identifier %s",
- peer->host, inet_ntoa (remote_id));
- bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_BGP_IDENT,
- notify_data_remote_id, 4);
- }
- else
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad OPEN, remote AS is %u, expected %u",
- peer->host, remote_as, peer->as);
- bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_PEER_AS,
- notify_data_remote_as, 2);
- }
- return -1;
- }
- }
-
- /* When collision is detected and this peer is closed. Retrun
- immidiately. */
- ret = bgp_collision_detect (peer, remote_id);
- if (ret < 0)
- return ret;
-
- /* Hack part. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- if (realpeer->status == Established
- && CHECK_FLAG (realpeer->sflags, PEER_STATUS_NSF_MODE))
- {
- realpeer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
- SET_FLAG (realpeer->sflags, PEER_STATUS_NSF_WAIT);
- }
- else if (ret == 0 && realpeer->status != Active
- && realpeer->status != OpenSent
- && realpeer->status != OpenConfirm
- && realpeer->status != Connect)
- {
- /* XXX: This is an awful problem..
- *
- * According to the RFC we should just let this connection (of the
- * accepted 'peer') continue on to Established if the other
- * connection (the 'realpeer' one) is in state Connect, and deal
- * with the more larval FSM as/when it gets far enough to receive
- * an Open. We don't do that though, we instead close the (more
- * developed) accepted connection.
- *
- * This means there's a race, which if hit, can loop:
- *
- * FSM for A FSM for B
- * realpeer accept-peer realpeer accept-peer
- *
- * Connect Connect
- * Active
- * OpenSent OpenSent
- * <arrive here,
- * Notify, delete>
- * Idle Active
- * OpenSent OpenSent
- * <arrive here,
- * Notify, delete>
- * Idle
- * <wait> <wait>
- * Connect Connect
- *
- *
- * If both sides are Quagga, they're almost certain to wait for
- * the same amount of time of course (which doesn't preclude other
- * implementations also waiting for same time). The race is
- * exacerbated by high-latency (in bgpd and/or the network).
- *
- * The reason we do this is because our FSM is tied to our peer
- * structure, which carries our configuration information, etc.
- * I.e. we can't let the accepted-peer FSM continue on as it is,
- * cause it's not associated with any actual peer configuration -
- * it's just a dummy.
- *
- * It's possible we could hack-fix this by just bgp_stop'ing the
- * realpeer and continueing on with the 'transfer FSM' below.
- * Ideally, we need to seperate FSMs from struct peer.
- *
- * Setting one side to passive avoids the race, as a workaround.
- */
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s peer status is %s close connection",
- realpeer->host, LOOKUP (bgp_status_msg,
- realpeer->status));
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONNECT_REJECT);
-
- return -1;
- }
-
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s [Event] Transfer accept BGP peer to real (state %s)",
- peer->host,
- LOOKUP (bgp_status_msg, realpeer->status));
-
- bgp_stop (realpeer);
-
- /* Transfer file descriptor. */
- realpeer->fd = peer->fd;
- peer->fd = -1;
-
- /* Transfer input buffer. */
- stream_free (realpeer->ibuf);
- realpeer->ibuf = peer->ibuf;
- realpeer->packet_size = peer->packet_size;
- peer->ibuf = NULL;
-
- /* Transfer status. */
- realpeer->status = peer->status;
- bgp_stop (peer);
-
- /* peer pointer change. Open packet send to neighbor. */
- peer = realpeer;
- bgp_open_send (peer);
- if (peer->fd < 0)
- {
- zlog_err ("bgp_open_receive peer's fd is negative value %d",
- peer->fd);
- return -1;
- }
- BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
- }
-
/* remote router-id check. */
if (remote_id.s_addr == 0
|| IPV4_CLASS_DE (ntohl (remote_id.s_addr))
|| ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr))
{
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s bad OPEN, wrong router identifier %s",
peer->host, inet_ntoa (remote_id));
bgp_notify_send_with_data (peer,
@@ -1490,7 +1448,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
{
u_int16_t maxver = htons(BGP_VERSION_4);
/* XXX this reply may not be correct if version < 4 XXX */
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s bad protocol version, remote requested %d, local request %d",
peer->host, version, BGP_VERSION_4);
/* Data must be in network byte order here */
@@ -1504,7 +1462,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
/* Check neighbor as number. */
if (remote_as != peer->as)
{
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s bad OPEN, remote AS is %u, expected %u",
peer->host, remote_as, peer->as);
bgp_notify_send_with_data (peer,
@@ -1522,9 +1480,10 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
if (holdtime < 3 && holdtime != 0)
{
- bgp_notify_send (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNACEP_HOLDTIME);
+ bgp_notify_send_with_data (peer,
+ BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNACEP_HOLDTIME,
+ (u_int8_t *)holdtime_ptr, 2);
return -1;
}
@@ -1559,7 +1518,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
}
else
{
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s rcvd OPEN w/ OPTION parameter len: 0",
peer->host);
}
@@ -1578,11 +1537,28 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST];
}
+ /* When collision is detected and this peer is closed. Retrun
+ immidiately. */
+ ret = bgp_collision_detect (peer, remote_id);
+ if (ret < 0)
+ return ret;
+
/* Get sockname. */
- bgp_getsockname (peer);
+ if ((ret = bgp_getsockname (peer)) < 0)
+ {
+ zlog_err("%s: bgp_getsockname() failed for peer: %s", __FUNCTION__,
+ peer->host);
+ return (ret);
+ }
peer->rtt = sockopt_tcp_rtt (peer->fd);
- BGP_EVENT_ADD (peer, Receive_OPEN_message);
+ if ((ret = bgp_event_update(peer, Receive_OPEN_message)) < 0)
+ {
+ zlog_err("%s: BGP event update failed for peer: %s", __FUNCTION__,
+ peer->host);
+ /* DD: bgp send notify and reset state */
+ return (ret);
+ }
peer->packet_size = 0;
if (peer->ibuf)
@@ -1609,6 +1585,117 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
return -1;
}
+/* Called when there is a change in the EOR(implicit or explicit) status of a peer.
+ Ends the update-delay if all expected peers are done with EORs. */
+void
+bgp_check_update_delay(struct bgp *bgp)
+{
+ struct listnode *node, *nnode;
+ struct peer *peer = NULL;
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("Checking update delay, T: %d R: %d I:%d E: %d", bgp->established,
+ bgp->restarted_peers, bgp->implicit_eors, bgp->explicit_eors);
+
+ if (bgp->established <=
+ bgp->restarted_peers + bgp->implicit_eors + bgp->explicit_eors)
+ {
+ /* This is an extra sanity check to make sure we wait for all the
+ eligible configured peers. This check is performed if establish wait
+ timer is on, or establish wait option is not given with the
+ update-delay command */
+ if (bgp->t_establish_wait ||
+ (bgp->v_establish_wait == bgp->v_update_delay))
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)
+ && !CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)
+ && !peer->update_delay_over)
+ {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug (" Peer %s pending, continuing read-only mode",
+ peer->host);
+ return;
+ }
+ }
+
+ zlog_info ("Update delay ended, restarted: %d, EORs implicit: %d, explicit: %d",
+ bgp->restarted_peers, bgp->implicit_eors, bgp->explicit_eors);
+ bgp_update_delay_end(bgp);
+ }
+}
+
+/* Called if peer is known to have restarted. The restart-state bit in
+ Graceful-Restart capability is used for that */
+void
+bgp_update_restarted_peers (struct peer *peer)
+{
+ if (!bgp_update_delay_active(peer->bgp)) return; /* BGP update delay has ended */
+ if (peer->update_delay_over) return; /* This peer has already been considered */
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("Peer %s: Checking restarted", peer->host);
+
+ if (peer->status == Established)
+ {
+ peer->update_delay_over = 1;
+ peer->bgp->restarted_peers++;
+ bgp_check_update_delay(peer->bgp);
+ }
+}
+
+/* Called as peer receives a keep-alive. Determines if this occurence can be
+ taken as an implicit EOR for this peer.
+ NOTE: The very first keep-alive after the Established state of a peer is
+ considered implicit EOR for the update-delay purposes */
+void
+bgp_update_implicit_eors (struct peer *peer)
+{
+ if (!bgp_update_delay_active(peer->bgp)) return; /* BGP update delay has ended */
+ if (peer->update_delay_over) return; /* This peer has already been considered */
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("Peer %s: Checking implicit EORs", peer->host);
+
+ if (peer->status == Established)
+ {
+ peer->update_delay_over = 1;
+ peer->bgp->implicit_eors++;
+ bgp_check_update_delay(peer->bgp);
+ }
+}
+
+/* Should be called only when there is a change in the EOR_RECEIVED status
+ for any afi/safi on a peer */
+static void
+bgp_update_explicit_eors (struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+
+ if (!bgp_update_delay_active(peer->bgp)) return; /* BGP update delay has ended */
+ if (peer->update_delay_over) return; /* This peer has already been considered */
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("Peer %s: Checking explicit EORs", peer->host);
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ if (peer->afc_nego[afi][safi] &&
+ !CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED))
+ {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug (" afi %d safi %d didnt receive EOR", afi, safi);
+ return;
+ }
+ }
+
+ peer->update_delay_over = 1;
+ peer->bgp->explicit_eors++;
+ bgp_check_update_delay(peer->bgp);
+}
+
/* Parse BGP Update packet and make attribute object. */
static int
bgp_update_receive (struct peer *peer, bgp_size_t size)
@@ -1646,6 +1733,8 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
memset (&extra, 0, sizeof (struct attr_extra));
memset (&nlris, 0, sizeof nlris);
attr.extra = &extra;
+ memset (peer->rcvd_attr_str, 0, BUFSIZ);
+ peer->rcvd_attr_printed = 0;
s = peer->ibuf;
end = stream_pnt (s) + size;
@@ -1686,8 +1775,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
nlris[NLRI_WITHDRAW].nlri = stream_pnt (s);
nlris[NLRI_WITHDRAW].length = withdraw_len;
- if (BGP_DEBUG (packet, PACKET_RECV))
- zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host);
+ zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host);
stream_forward_getp (s, withdraw_len);
}
@@ -1744,24 +1832,21 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
}
/* Logging the attribute. */
- if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW
- || BGP_DEBUG (update, UPDATE_IN))
+ if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW ||
+ BGP_DEBUG (update, UPDATE_IN) ||
+ BGP_DEBUG (update, UPDATE_PREFIX))
{
- char attrstr[BUFSIZ];
- attrstr[0] = '\0';
-
- ret= bgp_dump_attr (peer, &attr, attrstr, BUFSIZ);
- int lvl = (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW)
- ? LOG_ERR : LOG_DEBUG;
+ ret = bgp_dump_attr (peer, &attr, peer->rcvd_attr_str, BUFSIZ);
if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW)
- zlog (peer->log, LOG_ERR,
- "%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.",
- peer->host);
+ zlog_err ("%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.",
+ peer->host);
- if (ret)
- zlog (peer->log, lvl, "%s rcvd UPDATE w/ attr: %s",
- peer->host, attrstr);
+ if (ret && bgp_debug_update(peer, NULL, 1))
+ {
+ zlog_debug ("%s rcvd UPDATE w/ attr: %s", peer->host, peer->rcvd_attr_str);
+ peer->rcvd_attr_printed = 1;
+ }
}
/* Network Layer Reachability Information. */
@@ -1796,8 +1881,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
*/
if (!bgp_afi_safi_valid_indices (nlris[i].afi, &nlris[i].safi))
{
- plog_info (peer->log,
- "%s [Info] UPDATE with unsupported AFI/SAFI %u/%u",
+ zlog_info ("%s [Info] UPDATE with unsupported AFI/SAFI %u/%u",
peer->host, nlris[i].afi, nlris[i].safi);
continue;
}
@@ -1806,8 +1890,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
Address Family and Subsequent Address Family. */
if (!peer->afc[nlris[i].afi][nlris[i].safi])
{
- plog_info (peer->log,
- "%s [Info] UPDATE for non-enabled AFI/SAFI %u/%u",
+ zlog_info ("%s [Info] UPDATE for non-enabled AFI/SAFI %u/%u",
peer->host, nlris[i].afi, nlris[i].safi);
continue;
}
@@ -1829,8 +1912,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
if (nlri_ret < 0)
{
- plog_err (peer->log,
- "%s [Error] Error parsing NLRI", peer->host);
+ zlog_err ("%s [Error] Error parsing NLRI", peer->host);
if (peer->status == Established)
bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
i <= NLRI_WITHDRAW
@@ -1877,14 +1959,20 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
/* End-of-RIB received */
SET_FLAG (peer->af_sflags[afi][safi],
PEER_STATUS_EOR_RECEIVED);
+ if (!CHECK_FLAG (peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_RECEIVED))
+ {
+ SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST],
+ PEER_STATUS_EOR_RECEIVED);
+ bgp_update_explicit_eors(peer);
+ }
/* NSF delete stale route */
if (peer->nsf[afi][safi])
bgp_clear_stale_route (peer, afi, safi);
- if (BGP_DEBUG (normal, NORMAL))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for %s from %s",
- peer->host, afi_safi_print (afi, safi));
+ zlog_debug ("rcvd End-of-RIB for %s from %s",
+ peer->host, afi_safi_print (afi, safi));
}
}
@@ -1991,7 +2079,7 @@ bgp_notify_receive (struct peer *peer, bgp_size_t size)
static void
bgp_keepalive_receive (struct peer *peer, bgp_size_t size)
{
- if (BGP_DEBUG (keepalive, KEEPALIVE))
+ if (bgp_debug_keepalive(peer))
zlog_debug ("%s KEEPALIVE rcvd", peer->host);
BGP_EVENT_ADD (peer, Receive_KEEPALIVE_message);
@@ -2008,7 +2096,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
/* If peer does not have the capability, send notification. */
if (! CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_ADV))
{
- plog_err (peer->log, "%s [Error] BGP route refresh is not enabled",
+ zlog_err ("%s [Error] BGP route refresh is not enabled",
peer->host);
bgp_notify_send (peer,
BGP_NOTIFY_HEADER_ERR,
@@ -2019,8 +2107,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
/* Status must be Established. */
if (peer->status != Established)
{
- plog_err (peer->log,
- "%s [Error] Route refresh packet received under status %s",
+ zlog_err ("%s [Error] Route refresh packet received under status %s",
peer->host, LOOKUP (bgp_status_msg, peer->status));
bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
return;
@@ -2034,7 +2121,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
stream_getc (s);
safi = stream_getc (s);
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_update(peer, NULL, 0))
zlog_debug ("%s rcvd REFRESH_REQ for afi/safi: %d/%d",
peer->host, afi, safi);
@@ -2043,11 +2130,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
|| (safi != SAFI_UNICAST && safi != SAFI_MULTICAST
&& safi != SAFI_MPLS_LABELED_VPN))
{
- if (BGP_DEBUG (normal, NORMAL))
- {
- zlog_debug ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored",
- peer->host, afi, safi);
- }
+ zlog_info ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored",
+ peer->host, afi, safi);
return;
}
@@ -2092,7 +2176,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
char name[BUFSIZ];
int ret;
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
{
zlog_debug ("%s rcvd Prefixlist ORF(%d) length %d",
peer->host, orf_type, orf_len);
@@ -2119,7 +2203,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
/* after ++: p_pnt <= p_end */
if (common & ORF_COMMON_PART_REMOVE_ALL)
{
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s rcvd Remove-All pfxlist ORF request", peer->host);
prefix_bgp_orf_remove_all (afi, name);
break;
@@ -2158,7 +2242,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
memcpy (&orfp.p.u.prefix, p_pnt, psize);
p_pnt += psize;
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
{
char buf[INET6_BUFSIZ];
@@ -2179,9 +2263,8 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
if (!ok || (ok && ret != CMD_SUCCESS))
{
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Received misformatted prefixlist ORF."
- " Remove All pfxlist", peer->host);
+ zlog_info ("%s Received misformatted prefixlist ORF."
+ " Remove All pfxlist", peer->host);
prefix_bgp_orf_remove_all (afi, name);
break;
}
@@ -2191,7 +2274,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
}
stream_forward_getp (s, orf_len);
}
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s rcvd Refresh %s ORF request", peer->host,
when_to_refresh == REFRESH_DEFER ? "Defer" : "Immediate");
if (when_to_refresh == REFRESH_DEFER)
@@ -2240,7 +2323,7 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
return -1;
}
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s CAPABILITY has action: %d, code: %u, length %u",
peer->host, action, hdr->code, hdr->length);
@@ -2267,14 +2350,14 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
if (!bgp_afi_safi_valid_indices (afi, &safi))
{
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Dynamic Capability MP_EXT afi/safi invalid "
"(%u/%u)", peer->host, afi, safi);
continue;
}
/* Address family check. */
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u",
peer->host,
action == CAPABILITY_ACTION_SET
@@ -2323,13 +2406,13 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size)
/* Fetch pointer. */
pnt = stream_pnt (peer->ibuf);
- if (BGP_DEBUG (normal, NORMAL))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s rcv CAPABILITY", peer->host);
/* If peer does not have the capability, send notification. */
if (! CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV))
{
- plog_err (peer->log, "%s [Error] BGP dynamic capability is not enabled",
+ zlog_err ("%s [Error] BGP dynamic capability is not enabled",
peer->host);
bgp_notify_send (peer,
BGP_NOTIFY_HEADER_ERR,
@@ -2340,8 +2423,8 @@ bgp_capability_receive (struct peer *peer, bgp_size_t size)
/* Status must be Established. */
if (peer->status != Established)
{
- plog_err (peer->log,
- "%s [Error] Dynamic capability packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status));
+ zlog_err ("%s [Error] Dynamic capability packet received under status %s",
+ peer->host, LOOKUP (bgp_status_msg, peer->status));
bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
return -1;
}
@@ -2373,8 +2456,8 @@ bgp_read_packet (struct peer *peer)
if (nbytes == -2)
return -1;
- plog_err (peer->log, "%s [Error] bgp_read_packet error: %s",
- peer->host, safe_strerror (errno));
+ zlog_err ("%s [Error] bgp_read_packet error: %s",
+ peer->host, safe_strerror (errno));
if (peer->status == Established)
{
@@ -2394,9 +2477,9 @@ bgp_read_packet (struct peer *peer)
/* When read byte is zero : clear bgp peer and return */
if (nbytes == 0)
{
- if (BGP_DEBUG (events, EVENTS))
- plog_debug (peer->log, "%s [Event] BGP connection closed fd %d",
- peer->host, peer->fd);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s [Event] BGP connection closed fd %d",
+ peer->host, peer->fd);
if (peer->status == Established)
{
@@ -2451,15 +2534,19 @@ bgp_read (struct thread *thread)
struct peer *peer;
bgp_size_t size;
char notify_data_length[2];
+ u_int32_t notify_out;
/* Yes first of all get peer pointer. */
peer = THREAD_ARG (thread);
peer->t_read = NULL;
+ /* Note notify_out so we can check later to see if we sent another one */
+ notify_out = peer->notify_out;
+
/* For non-blocking IO check. */
if (peer->status == Connect)
{
- bgp_connect_check (peer);
+ bgp_connect_check (peer, 1);
goto done;
}
else
@@ -2490,10 +2577,6 @@ bgp_read (struct thread *thread)
size = stream_getw (peer->ibuf);
type = stream_getc (peer->ibuf);
- if (BGP_DEBUG (normal, NORMAL) && type != 2 && type != 0)
- zlog_debug ("%s rcv message type %d, length (excl. header) %d",
- peer->host, type, size - BGP_HEADER_SIZE);
-
/* Marker check */
if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE))
&& ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE))
@@ -2511,10 +2594,9 @@ bgp_read (struct thread *thread)
&& type != BGP_MSG_ROUTE_REFRESH_OLD
&& type != BGP_MSG_CAPABILITY)
{
- if (BGP_DEBUG (normal, NORMAL))
- plog_debug (peer->log,
- "%s unknown message type 0x%02x",
- peer->host, type);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s unknown message type 0x%02x",
+ peer->host, type);
bgp_notify_send_with_data (peer,
BGP_NOTIFY_HEADER_ERR,
BGP_NOTIFY_HEADER_BAD_MESTYPE,
@@ -2532,12 +2614,11 @@ bgp_read (struct thread *thread)
|| (type == BGP_MSG_ROUTE_REFRESH_OLD && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
|| (type == BGP_MSG_CAPABILITY && size < BGP_MSG_CAPABILITY_MIN_SIZE))
{
- if (BGP_DEBUG (normal, NORMAL))
- plog_debug (peer->log,
- "%s bad message length - %d for %s",
- peer->host, size,
- type == 128 ? "ROUTE-REFRESH" :
- bgp_type_str[(int) type]);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s bad message length - %d for %s",
+ peer->host, size,
+ type == 128 ? "ROUTE-REFRESH" :
+ bgp_type_str[(int) type]);
bgp_notify_send_with_data (peer,
BGP_NOTIFY_HEADER_ERR,
BGP_NOTIFY_HEADER_BAD_MESLEN,
@@ -2591,17 +2672,30 @@ bgp_read (struct thread *thread)
break;
}
+ /* If reading this packet caused us to send a NOTIFICATION then store a copy
+ * of the packet for troubleshooting purposes
+ */
+ if (notify_out < peer->notify_out)
+ {
+ memcpy(peer->last_reset_cause, peer->ibuf->data, peer->packet_size);
+ peer->last_reset_cause_size = peer->packet_size;
+ notify_out = peer->notify_out;
+ }
+
/* Clear input buffer. */
peer->packet_size = 0;
if (peer->ibuf)
stream_reset (peer->ibuf);
done:
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ /* If reading this packet caused us to send a NOTIFICATION then store a copy
+ * of the packet for troubleshooting purposes
+ */
+ if (notify_out < peer->notify_out)
{
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s [Event] Accepting BGP peer delete", peer->host);
- peer_delete (peer);
+ memcpy(peer->last_reset_cause, peer->ibuf->data, peer->packet_size);
+ peer->last_reset_cause_size = peer->packet_size;
}
+
return 0;
}
diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h
index 6b0b7f4d..0e490cf7 100644
--- a/bgpd/bgp_packet.h
+++ b/bgpd/bgp_packet.h
@@ -26,6 +26,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define BGP_UNFEASIBLE_LEN 2U
#define BGP_WRITE_PACKET_MAX 10U
+/* Size of FIFOs upon which write thread is triggered. Note that write
+ * thread is also triggered upon BGP work-queue completion.
+ */
+#define BGP_ADV_FIFO_QUANTA 500
+#define BGP_WD_FIFO_QUANTA 200
+
/* When to refresh */
#define REFRESH_IMMEDIATE 1
#define REFRESH_DEFER 2
@@ -40,6 +46,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* Packet send and receive function prototypes. */
extern int bgp_read (struct thread *);
extern int bgp_write (struct thread *);
+extern int bgp_connect_check (struct peer *, int change_state);
extern void bgp_keepalive_send (struct peer *);
extern void bgp_open_send (struct peer *);
@@ -56,4 +63,10 @@ extern int bgp_capability_receive (struct peer *, bgp_size_t);
extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *);
+extern void bgp_update_restarted_peers (struct peer *);
+extern void bgp_update_implicit_eors (struct peer *);
+extern void bgp_check_update_delay (struct bgp *);
+extern int bgp_peer_wd_fifo_exists (struct peer *);
+extern int bgp_peer_adv_fifo_exists (struct peer *, int);
+extern void bgp_peer_schedule_updates(struct peer *peer);
#endif /* _QUAGGA_BGP_PACKET_H */
diff --git a/bgpd/bgp_regex.c b/bgpd/bgp_regex.c
index 13fa8295..d96f74ce 100644
--- a/bgpd/bgp_regex.c
+++ b/bgpd/bgp_regex.c
@@ -24,6 +24,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "command.h"
#include "memory.h"
#include "filter.h"
+#include "linklist.h"
+#include "prefix.h"
#include "bgpd.h"
#include "bgp_aspath.h"
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index c364372f..4bd6b842 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -55,6 +55,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_mpath.h"
+#include "bgpd/bgp_nht.h"
/* Extern from bgp_dump.c */
extern const char *bgp_origin_str[];
@@ -126,20 +127,14 @@ bgp_info_extra_get (struct bgp_info *ri)
return ri->extra;
}
-/* Allocate new bgp info structure. */
-static struct bgp_info *
-bgp_info_new (void)
-{
- return XCALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info));
-}
-
/* Free bgp route information. */
static void
bgp_info_free (struct bgp_info *binfo)
{
if (binfo->attr)
bgp_attr_unintern (&binfo->attr);
-
+
+ bgp_unlink_nexthop(binfo);
bgp_info_extra_free (&binfo->extra);
bgp_info_mpath_free (&binfo->mpath);
@@ -252,7 +247,7 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri)
|| ri->peer == ri->peer->bgp->peer_self)
return;
- if (BGP_INFO_HOLDDOWN (ri)
+ if (!BGP_INFO_COUNTABLE (ri)
&& CHECK_FLAG (ri->flags, BGP_INFO_COUNTED))
{
@@ -269,7 +264,7 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri)
zlog_warn ("%s: Please report to Quagga bugzilla", __func__);
}
}
- else if (!BGP_INFO_HOLDDOWN (ri)
+ else if (BGP_INFO_COUNTABLE (ri)
&& !CHECK_FLAG (ri->flags, BGP_INFO_COUNTED))
{
SET_FLAG (ri->flags, BGP_INFO_COUNTED);
@@ -286,8 +281,8 @@ bgp_info_set_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag)
{
SET_FLAG (ri->flags, flag);
- /* early bath if we know it's not a flag that changes useability state */
- if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE))
+ /* early bath if we know it's not a flag that changes countability state */
+ if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_HISTORY|BGP_INFO_REMOVED))
return;
bgp_pcount_adjust (rn, ri);
@@ -298,8 +293,8 @@ bgp_info_unset_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag)
{
UNSET_FLAG (ri->flags, flag);
- /* early bath if we know it's not a flag that changes useability state */
- if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE))
+ /* early bath if we know it's not a flag that changes countability state */
+ if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_HISTORY|BGP_INFO_REMOVED))
return;
bgp_pcount_adjust (rn, ri);
@@ -477,6 +472,27 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist,
if (newm > existm)
return 1;
+ /* 8.1. Same IGP metric. Compare the cluster list length as
+ representative of IGP hops metric. Rewrite the metric value
+ pair (newm, existm) with the cluster list length. Prefer the
+ path with smaller cluster list length. */
+ if (newm == existm)
+ {
+ struct bgp_maxpaths_cfg *mpath_cfg = &bgp->maxpaths[afi][safi];
+ if (peer_sort (new->peer) == BGP_PEER_IBGP
+ && peer_sort (exist->peer) == BGP_PEER_IBGP
+ && CHECK_FLAG (mpath_cfg->ibgp_flags,
+ BGP_FLAG_IBGP_MULTIPATH_SAME_CLUSTERLEN))
+ {
+ newm = BGP_CLUSTER_LIST_LENGTH(new->attr);
+ existm = BGP_CLUSTER_LIST_LENGTH(exist->attr);
+ if (newm < existm)
+ ret = 1;
+ if (newm > existm)
+ ret = 0;
+ }
+ }
+
/* 9. Maximum path check. */
if (bgp_mpath_is_configured (bgp, afi, safi))
{
@@ -535,12 +551,8 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist,
return 1;
/* 12. Cluster length comparision. */
- new_cluster = exist_cluster = 0;
-
- if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))
- new_cluster = newattre->cluster->length;
- if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))
- exist_cluster = existattre->cluster->length;
+ new_cluster = BGP_CLUSTER_LIST_LENGTH(new->attr);
+ exist_cluster = BGP_CLUSTER_LIST_LENGTH(exist->attr);
if (new_cluster < exist_cluster)
return -1;
@@ -582,7 +594,7 @@ bgp_input_filter (struct peer *peer, struct prefix *p, struct attr *attr,
#define FILTER_EXIST_WARN(F,f,filter) \
if (BGP_DEBUG (update, UPDATE_IN) \
&& !(F ## _IN (filter))) \
- plog_warn (peer->log, "%s: Could not find configured input %s-list %s!", \
+ zlog_warn ("%s: Could not find configured input %s-list %s!", \
peer->host, #f, F ## _IN_NAME(filter));
if (DISTRIBUTE_IN_NAME (filter)) {
@@ -621,7 +633,7 @@ bgp_output_filter (struct peer *peer, struct prefix *p, struct attr *attr,
#define FILTER_EXIST_WARN(F,f,filter) \
if (BGP_DEBUG (update, UPDATE_OUT) \
&& !(F ## _OUT (filter))) \
- plog_warn (peer->log, "%s: Could not find configured output %s-list %s!", \
+ zlog_warn ("%s: Could not find configured output %s-list %s!", \
peer->host, #f, F ## _OUT_NAME(filter));
if (DISTRIBUTE_OUT_NAME (filter)) {
@@ -694,11 +706,12 @@ bgp_cluster_filter (struct peer *peer, struct attr *attr)
static int
bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr,
- afi_t afi, safi_t safi)
+ afi_t afi, safi_t safi, const char *rmap_name)
{
struct bgp_filter *filter;
struct bgp_info info;
route_map_result_t ret;
+ struct route_map *rmap = NULL;
filter = &peer->filter[afi][safi];
@@ -706,8 +719,18 @@ bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr,
if (peer->weight)
(bgp_attr_extra_get (attr))->weight = peer->weight;
+ if (rmap_name)
+ {
+ rmap = route_map_lookup_by_name(rmap_name);
+ }
+ else
+ {
+ if (ROUTE_MAP_IN_NAME(filter))
+ rmap = ROUTE_MAP_IN (filter);
+ }
+
/* Route map apply. */
- if (ROUTE_MAP_IN_NAME (filter))
+ if (rmap)
{
/* Duplicate current value to new strucutre for modification. */
info.peer = peer;
@@ -716,7 +739,56 @@ bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr,
SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN);
/* Apply BGP route map to the attribute. */
- ret = route_map_apply (ROUTE_MAP_IN (filter), p, RMAP_BGP, &info);
+ ret = route_map_apply (rmap, p, RMAP_BGP, &info);
+
+ peer->rmap_type = 0;
+
+ if (ret == RMAP_DENYMATCH)
+ {
+ /* Free newly generated AS path and community by route-map. */
+ bgp_attr_flush (attr);
+ return RMAP_DENY;
+ }
+ }
+ return RMAP_PERMIT;
+}
+
+static int
+bgp_output_modifier (struct peer *peer, struct prefix *p, struct attr *attr,
+ afi_t afi, safi_t safi, const char *rmap_name)
+{
+ struct bgp_filter *filter;
+ struct bgp_info info;
+ route_map_result_t ret;
+ struct route_map *rmap = NULL;
+
+ filter = &peer->filter[afi][safi];
+
+ /* Apply default weight value. */
+ if (peer->weight)
+ (bgp_attr_extra_get (attr))->weight = peer->weight;
+
+ if (rmap_name)
+ {
+ rmap = route_map_lookup_by_name(rmap_name);
+ }
+ else
+ {
+ if (ROUTE_MAP_OUT_NAME(filter))
+ rmap = ROUTE_MAP_OUT (filter);
+ }
+
+ /* Route map apply. */
+ if (rmap)
+ {
+ /* Duplicate current value to new strucutre for modification. */
+ info.peer = peer;
+ info.attr = attr;
+
+ SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT);
+
+ /* Apply BGP route map to the attribute. */
+ ret = route_map_apply (rmap, p, RMAP_BGP, &info);
peer->rmap_type = 0;
@@ -799,6 +871,55 @@ bgp_import_modifier (struct peer *rsclient, struct peer *peer,
return RMAP_PERMIT;
}
+
+/* If this is an EBGP peer with remove-private-AS */
+static void
+bgp_peer_remove_private_as(struct bgp *bgp, afi_t afi, safi_t safi,
+ struct peer *peer, struct attr *attr)
+{
+ if (peer->sort == BGP_PEER_EBGP &&
+ peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS))
+ {
+ // Take action on the entire aspath
+ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_ALL))
+ {
+ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE))
+ attr->aspath = aspath_replace_private_asns (attr->aspath, bgp->as);
+
+ // The entire aspath consists of private ASNs so create an empty aspath
+ else if (aspath_private_as_check (attr->aspath))
+ attr->aspath = aspath_empty_get ();
+
+ // There are some public and some private ASNs, remove the private ASNs
+ else
+ attr->aspath = aspath_remove_private_asns (attr->aspath);
+ }
+
+ // 'all' was not specified so the entire aspath must be private ASNs
+ // for us to do anything
+ else if (aspath_private_as_check (attr->aspath))
+ {
+ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE))
+ attr->aspath = aspath_replace_private_asns (attr->aspath, bgp->as);
+ else
+ attr->aspath = aspath_empty_get ();
+ }
+ }
+}
+
+/* If this is an EBGP peer with as-override */
+static void
+bgp_peer_as_override(struct bgp *bgp, afi_t afi, safi_t safi,
+ struct peer *peer, struct attr *attr)
+{
+ if (peer->sort == BGP_PEER_EBGP &&
+ peer_af_flag_check (peer, afi, safi, PEER_FLAG_AS_OVERRIDE))
+ {
+ if (aspath_single_asn_check (attr->aspath, peer->as))
+ attr->aspath = aspath_replace_specific_asn (attr->aspath, peer->as, bgp->as);
+ }
+}
+
static int
bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
struct attr *attr, afi_t afi, safi_t safi)
@@ -859,12 +980,11 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
{
if (IPV4_ADDR_SAME (&peer->remote_id, &riattr->extra->originator_id))
{
- if (BGP_DEBUG (filter, FILTER))
- zlog (peer->log, LOG_DEBUG,
- "%s [Update:SEND] %s/%d originator-id is same as remote router-id",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ if (bgp_debug_update(peer, p, 0))
+ zlog_debug("%s [Update:SEND] %s/%d originator-id is same as remote router-id",
+ peer->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
return 0;
}
}
@@ -882,12 +1002,11 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
/* Output filter check. */
if (bgp_output_filter (peer, p, riattr, afi, safi) == FILTER_DENY)
{
- if (BGP_DEBUG (filter, FILTER))
- zlog (peer->log, LOG_DEBUG,
- "%s [Update:SEND] %s/%d is filtered",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ if (bgp_debug_update(peer, p, 0))
+ zlog_debug("%s [Update:SEND] %s/%d is filtered",
+ peer->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
return 0;
}
@@ -895,10 +1014,9 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
/* AS path loop check. */
if (aspath_loop_check (riattr->aspath, peer->as))
{
- if (BGP_DEBUG (filter, FILTER))
- zlog (peer->log, LOG_DEBUG,
- "%s [Update:SEND] suppress announcement to peer AS %u is AS path.",
- peer->host, peer->as);
+ if (bgp_debug_update(peer, p, 0))
+ zlog_debug("%s [Update:SEND] suppress announcement to peer AS %u is AS path.",
+ peer->host, peer->as);
return 0;
}
#endif /* BGP_SEND_ASPATH_CHECK */
@@ -908,11 +1026,10 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
{
if (aspath_loop_check(riattr->aspath, bgp->confed_id))
{
- if (BGP_DEBUG (filter, FILTER))
- zlog (peer->log, LOG_DEBUG,
- "%s [Update:SEND] suppress announcement to peer AS %u is AS path.",
- peer->host,
- bgp->confed_id);
+ if (bgp_debug_update(peer, p, 0))
+ zlog_debug("%s [Update:SEND] suppress announcement to peer AS %u is AS path.",
+ peer->host,
+ bgp->confed_id);
return 0;
}
}
@@ -1003,7 +1120,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
|| (NEXTHOP_IS_V6 &&
IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global))
|| (peer->sort == BGP_PEER_EBGP
- && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0))
+ && (bgp_multiaccess_check_v4 (attr->nexthop, peer) == 0)))
{
/* Set IPv4 nexthop. */
if (NEXTHOP_IS_V4)
@@ -1063,11 +1180,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
}
- /* If this is EBGP peer and remove-private-AS is set. */
- if (peer->sort == BGP_PEER_EBGP
- && peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)
- && aspath_private_as_check (attr->aspath))
- attr->aspath = aspath_empty_get ();
+ bgp_peer_remove_private_as(bgp, afi, safi, peer, attr);
+ bgp_peer_as_override(bgp, afi, safi, peer, attr);
/* Route map & unsuppress-map apply. */
if (ROUTE_MAP_OUT_NAME (filter)
@@ -1084,8 +1198,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
/* The route reflector is not allowed to modify the attributes
of the reflected IBGP routes. */
- if (from->sort == BGP_PEER_IBGP
- && peer->sort == BGP_PEER_IBGP)
+ if ((from->sort == BGP_PEER_IBGP && peer->sort == BGP_PEER_IBGP) &&
+ !bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY))
{
bgp_attr_dup (&dummy_attr, attr);
info.attr = &dummy_attr;
@@ -1119,9 +1233,11 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
struct bgp_info info;
struct peer *from;
struct attr *riattr;
+ struct bgp *bgp;
from = ri->peer;
filter = &rsclient->filter[afi][safi];
+ bgp = rsclient->bgp;
riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr;
if (DISABLE_BGP_ANNOUNCE)
@@ -1153,12 +1269,11 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
if (IPV4_ADDR_SAME (&rsclient->remote_id,
&riattr->extra->originator_id))
{
- if (BGP_DEBUG (filter, FILTER))
- zlog (rsclient->log, LOG_DEBUG,
- "%s [Update:SEND] %s/%d originator-id is same as remote router-id",
- rsclient->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ if (bgp_debug_update(rsclient, p, 0))
+ zlog_debug ("%s [Update:SEND] %s/%d originator-id is same as remote router-id",
+ rsclient->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
return 0;
}
}
@@ -1176,12 +1291,11 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
/* Output filter check. */
if (bgp_output_filter (rsclient, p, riattr, afi, safi) == FILTER_DENY)
{
- if (BGP_DEBUG (filter, FILTER))
- zlog (rsclient->log, LOG_DEBUG,
- "%s [Update:SEND] %s/%d is filtered",
- rsclient->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ if (bgp_debug_update(rsclient, p, 0))
+ zlog_debug ("%s [Update:SEND] %s/%d is filtered",
+ rsclient->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
return 0;
}
@@ -1189,10 +1303,9 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
/* AS path loop check. */
if (aspath_loop_check (riattr->aspath, rsclient->as))
{
- if (BGP_DEBUG (filter, FILTER))
- zlog (rsclient->log, LOG_DEBUG,
- "%s [Update:SEND] suppress announcement to peer AS %u is AS path.",
- rsclient->host, rsclient->as);
+ if (bgp_debug_update(rsclient, p, 0))
+ zlog_debug ("%s [Update:SEND] suppress announcement to peer AS %u is AS path.",
+ rsclient->host, rsclient->as);
return 0;
}
#endif /* BGP_SEND_ASPATH_CHECK */
@@ -1267,11 +1380,8 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
}
- /* If this is EBGP peer and remove-private-AS is set. */
- if (rsclient->sort == BGP_PEER_EBGP
- && peer_af_flag_check (rsclient, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)
- && aspath_private_as_check (attr->aspath))
- attr->aspath = aspath_empty_get ();
+ bgp_peer_remove_private_as(bgp, afi, safi, rsclient, attr);
+ bgp_peer_as_override(bgp, afi, safi, rsclient, attr);
/* Route map & unsuppress-map apply. */
if (ROUTE_MAP_OUT_NAME (filter) || (ri->extra && ri->extra->suppress) )
@@ -1536,8 +1646,23 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
struct bgp_info *old_select;
struct bgp_info_pair old_and_new;
struct listnode *node, *nnode;
- struct peer *rsclient = bgp_node_table (rn)->owner;
-
+ struct peer *rsclient;
+
+ /* Is it end of initial update? (after startup) */
+ if (!rn)
+ {
+ /* This is just to keep the display sane in case all the peers are
+ rsclients only */
+ quagga_timestamp(3, bgp->update_delay_zebra_resume_time,
+ sizeof(bgp->update_delay_zebra_resume_time));
+
+ bgp->rsclient_peers_update_hold = 0;
+ bgp_start_routeadv(bgp);
+ return WQ_SUCCESS;
+ }
+
+ rsclient = bgp_node_table (rn)->owner;
+
/* Best path selection. */
bgp_best_selection (bgp, rn, &old_and_new, afi, safi);
new_select = old_and_new.new;
@@ -1600,20 +1725,38 @@ bgp_process_main (struct work_queue *wq, void *data)
struct bgp_info_pair old_and_new;
struct listnode *node, *nnode;
struct peer *peer;
-
+
+ /* Is it end of initial update? (after startup) */
+ if (!rn)
+ {
+ quagga_timestamp(3, bgp->update_delay_zebra_resume_time,
+ sizeof(bgp->update_delay_zebra_resume_time));
+
+ bgp->main_zebra_update_hold = 0;
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ bgp_zebra_announce_table(bgp, afi, safi);
+ }
+ bgp->main_peers_update_hold = 0;
+
+ bgp_start_routeadv(bgp);
+ return WQ_SUCCESS;
+ }
+
/* Best path selection. */
bgp_best_selection (bgp, rn, &old_and_new, afi, safi);
old_select = old_and_new.old;
new_select = old_and_new.new;
/* Nothing to do. */
- if (old_select && old_select == new_select)
+ if (old_select && old_select == new_select && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR))
{
if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED))
{
if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) ||
CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG))
- bgp_zebra_announce (p, old_select, bgp, safi);
+ bgp_zebra_announce (p, old_select, bgp, afi, safi);
UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
@@ -1621,6 +1764,9 @@ bgp_process_main (struct work_queue *wq, void *data)
}
}
+ /* If the user did "clear ip bgp prefix x.x.x.x" this flag will be set */
+ UNSET_FLAG(rn->flags, BGP_NODE_USER_CLEAR);
+
if (old_select)
bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED);
if (new_select)
@@ -1644,7 +1790,7 @@ bgp_process_main (struct work_queue *wq, void *data)
if (new_select
&& new_select->type == ZEBRA_ROUTE_BGP
&& new_select->sub_type == BGP_ROUTE_NORMAL)
- bgp_zebra_announce (p, new_select, bgp, safi);
+ bgp_zebra_announce (p, new_select, bgp, afi, safi);
else
{
/* Withdraw the route from the kernel. */
@@ -1667,15 +1813,40 @@ static void
bgp_processq_del (struct work_queue *wq, void *data)
{
struct bgp_process_queue *pq = data;
- struct bgp_table *table = bgp_node_table (pq->rn);
-
+ struct bgp_table *table;
+
bgp_unlock (pq->bgp);
- bgp_unlock_node (pq->rn);
- bgp_table_unlock (table);
+ if (pq->rn)
+ {
+ table = bgp_node_table (pq->rn);
+ bgp_unlock_node (pq->rn);
+ bgp_table_unlock (table);
+ }
XFREE (MTYPE_BGP_PROCESS_QUEUE, pq);
}
static void
+bgp_process_queue_complete (struct work_queue *wq)
+{
+ struct bgp *bgp;
+ struct peer *peer;
+ struct listnode *node, *nnode;
+
+ /* Schedule write thread either directly or through the MRAI timer
+ * if needed.
+ */
+ bgp = bgp_get_default ();
+ if (!bgp)
+ return;
+
+ if (BGP_ROUTE_ADV_HOLD(bgp))
+ return;
+
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ bgp_peer_schedule_updates(peer);
+}
+
+void
bgp_process_queue_init (void)
{
bm->process_main_queue
@@ -1691,8 +1862,11 @@ bgp_process_queue_init (void)
bm->process_main_queue->spec.workfunc = &bgp_process_main;
bm->process_main_queue->spec.del_item_data = &bgp_processq_del;
+ bm->process_main_queue->spec.completion_func = &bgp_process_queue_complete;
bm->process_main_queue->spec.max_retries = 0;
bm->process_main_queue->spec.hold = 50;
+ /* Use a higher yield value of 50ms for main queue processing */
+ bm->process_main_queue->spec.yield = 50 * 1000L;
bm->process_rsclient_queue->spec.workfunc = &bgp_process_rsclient;
bm->process_rsclient_queue->spec.del_item_data = &bgp_processq_del;
@@ -1753,6 +1927,36 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
return;
}
+void
+bgp_add_eoiu_mark (struct bgp *bgp, bgp_table_t type)
+{
+ struct bgp_process_queue *pqnode;
+
+ if ( (bm->process_main_queue == NULL) ||
+ (bm->process_rsclient_queue == NULL) )
+ bgp_process_queue_init ();
+
+ pqnode = XCALLOC (MTYPE_BGP_PROCESS_QUEUE,
+ sizeof (struct bgp_process_queue));
+ if (!pqnode)
+ return;
+
+ pqnode->rn = NULL;
+ pqnode->bgp = bgp;
+ bgp_lock (bgp);
+ switch (type)
+ {
+ case BGP_TABLE_MAIN:
+ work_queue_add (bm->process_main_queue, pqnode);
+ break;
+ case BGP_TABLE_RSCLIENT:
+ work_queue_add (bm->process_rsclient_queue, pqnode);
+ break;
+ }
+
+ return;
+}
+
static int
bgp_maximum_prefix_restart_timer (struct thread *thread)
{
@@ -1761,11 +1965,11 @@ bgp_maximum_prefix_restart_timer (struct thread *thread)
peer = THREAD_ARG (thread);
peer->t_pmax_restart = NULL;
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Maximum-prefix restart timer expired, restore peering",
peer->host);
- peer_clear (peer);
+ peer_clear (peer, NULL);
return 0;
}
@@ -1783,10 +1987,9 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
&& ! always)
return 0;
- zlog (peer->log, LOG_INFO,
- "%%MAXPFXEXCEED: No. of %s prefix received from %s %ld exceed, "
- "limit %ld", afi_safi_print (afi, safi), peer->host,
- peer->pcount[afi][safi], peer->pmax[afi][safi]);
+ zlog_info ("%%MAXPFXEXCEED: No. of %s prefix received from %s %ld exceed, "
+ "limit %ld", afi_safi_print (afi, safi), peer->host,
+ peer->pcount[afi][safi], peer->pmax[afi][safi]);
SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT);
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING))
@@ -1816,7 +2019,7 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
{
peer->v_pmax_restart = peer->pmax_restart[afi][safi] * 60;
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Maximum-prefix restart timer started for %d secs",
peer->host, peer->v_pmax_restart);
@@ -1835,10 +2038,9 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
&& ! always)
return 0;
- zlog (peer->log, LOG_INFO,
- "%%MAXPFX: No. of %s prefix received from %s reaches %ld, max %ld",
- afi_safi_print (afi, safi), peer->host, peer->pcount[afi][safi],
- peer->pmax[afi][safi]);
+ zlog_info ("%%MAXPFX: No. of %s prefix received from %s reaches %ld, max %ld",
+ afi_safi_print (afi, safi), peer->host, peer->pcount[afi][safi],
+ peer->pmax[afi][safi]);
SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_THRESHOLD);
}
else
@@ -1882,6 +2084,23 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
bgp_rib_remove (rn, ri, peer, afi, safi);
}
+static struct bgp_info *
+info_make (int type, int sub_type, struct peer *peer, struct attr *attr,
+ struct bgp_node *rn)
+{
+ struct bgp_info *new;
+
+ /* Make new BGP info. */
+ new = XCALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info));
+ new->type = type;
+ new->sub_type = sub_type;
+ new->peer = peer;
+ new->attr = attr;
+ new->uptime = bgp_clock ();
+ new->net = rn;
+ return new;
+}
+
static void
bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
struct attr *attr, struct peer *peer, struct prefix *p, int type,
@@ -1974,14 +2193,12 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
&& attrhash_cmp (ri->attr, attr_new))
{
- bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
+ if (bgp_debug_update(peer, p, 1))
+ zlog_debug ("%s rcvd %s/%d for RS-client %s...duplicate ignored",
+ peer->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen, rsclient->host);
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG,
- "%s rcvd %s/%d for RS-client %s...duplicate ignored",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, rsclient->host);
bgp_unlock_node (rn);
bgp_attr_unintern (&attr_new);
@@ -1994,11 +2211,11 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
bgp_info_restore (rn, ri);
/* Received Logging. */
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, rsclient->host);
+ if (bgp_debug_update(peer, p, 1))
+ zlog_debug ("%s rcvd %s/%d for RS-client %s",
+ peer->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen, rsclient->host);
/* The attribute is changed. */
bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
@@ -2021,21 +2238,15 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
}
/* Received Logging. */
- if (BGP_DEBUG (update, UPDATE_IN))
+ if (bgp_debug_update(peer, p, 1))
{
- zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, rsclient->host);
+ zlog_debug ("%s rcvd %s/%d for RS-client %s",
+ peer->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen, rsclient->host);
}
- /* Make new BGP info. */
- new = bgp_info_new ();
- new->type = type;
- new->sub_type = sub_type;
- new->peer = peer;
- new->attr = attr_new;
- new->uptime = bgp_clock ();
+ new = info_make(type, sub_type, peer, attr_new, rn);
/* Update MPLS tag. */
if (safi == SAFI_MPLS_VPN)
@@ -2057,12 +2268,11 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
filtered:
/* This BGP update is filtered. Log the reason then update BGP entry. */
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG,
- "%s rcvd UPDATE about %s/%d -- DENIED for RS-client %s due to: %s",
- peer->host,
- inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, rsclient->host, reason);
+ if (bgp_debug_update(peer, p, 1))
+ zlog_debug ("%s rcvd UPDATE about %s/%d -- DENIED for RS-client %s due to: %s",
+ peer->host,
+ inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen, rsclient->host, reason);
if (ri)
bgp_rib_remove (rn, ri, peer, afi, safi);
@@ -2094,11 +2304,10 @@ bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
/* Withdraw specified route from routing table. */
if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
bgp_rib_withdraw (rn, ri, peer, afi, safi, prd);
- else if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG,
- "%s Can't find the route %s/%d", peer->host,
- inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ else if (bgp_debug_update(peer, p, 1))
+ zlog_debug ("%s Can't find the route %s/%d", peer->host,
+ inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
/* Unlock bgp_node_get() lock. */
bgp_unlock_node (rn);
@@ -2120,6 +2329,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
struct bgp_info *new;
const char *reason;
char buf[SU_ADDRSTRLEN];
+ int connected = 0;
memset (&new_attr, 0, sizeof(struct attr));
memset (&new_extra, 0, sizeof(struct attr_extra));
@@ -2190,7 +2400,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
* NB: new_attr may now contain newly allocated values from route-map "set"
* commands, so we need bgp_attr_flush in the error paths, until we intern
* the attr (which takes over the memory references) */
- if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY)
+ if (bgp_input_modifier (peer, p, &new_attr, afi, safi, NULL) == RMAP_DENY)
{
reason = "route-map;";
bgp_attr_flush (&new_attr);
@@ -2200,17 +2410,6 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* IPv4 unicast next hop check. */
if (afi == AFI_IP && safi == SAFI_UNICAST)
{
- /* If the peer is EBGP and nexthop is not on connected route,
- discard it. */
- if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1
- && ! bgp_nexthop_onlink (afi, &new_attr)
- && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
- {
- reason = "non-connected next-hop;";
- bgp_attr_flush (&new_attr);
- goto filtered;
- }
-
/* Next hop must not be 0.0.0.0 nor Class D/E address. Next hop
must not be my own address. */
if (new_attr.nexthop.s_addr == 0
@@ -2234,17 +2433,15 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)
&& attrhash_cmp (ri->attr, attr_new))
{
- bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
-
if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
&& peer->sort == BGP_PEER_EBGP
&& CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
{
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ if (bgp_debug_update(peer, p, 1))
+ zlog_debug ("%s rcvd %s/%d",
+ peer->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED)
{
@@ -2254,12 +2451,19 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
}
else /* Duplicate - odd */
{
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG,
- "%s rcvd %s/%d...duplicate ignored",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ if (bgp_debug_update(peer, p, 1))
+ {
+ if (!peer->rcvd_attr_printed)
+ {
+ zlog_debug ("%s rcvd UPDATE w/ attr: %s", peer->host, peer->rcvd_attr_str);
+ peer->rcvd_attr_printed = 1;
+ }
+
+ zlog_debug ("%s rcvd %s/%d...duplicate ignored",
+ peer->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
+ }
/* graceful restart STALE flag unset. */
if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
@@ -2279,20 +2483,20 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* Withdraw/Announce before we fully processed the withdraw */
if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
{
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d, flapped quicker than processing",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ if (bgp_debug_update(peer, p, 1))
+ zlog_debug ("%s rcvd %s/%d, flapped quicker than processing",
+ peer->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
bgp_info_restore (rn, ri);
}
/* Received Logging. */
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ if (bgp_debug_update(peer, p, 1))
+ zlog_debug ("%s rcvd %s/%d",
+ peer->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
/* graceful restart STALE flag unset. */
if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
@@ -2340,20 +2544,29 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
}
/* Nexthop reachability check. */
- if ((afi == AFI_IP || afi == AFI_IP6)
- && safi == SAFI_UNICAST
- && (peer->sort == BGP_PEER_IBGP
- || peer->sort == BGP_PEER_CONFED
- || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
- || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)))
+ if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST)
{
- if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL))
+ if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 &&
+ ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
+ connected = 1;
+ else
+ connected = 0;
+
+ if (bgp_find_or_add_nexthop (afi, ri, NULL, connected))
bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
else
- bgp_info_unset_flag (rn, ri, BGP_INFO_VALID);
+ {
+ if (BGP_DEBUG(nht, NHT))
+ {
+ char buf1[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, INET6_ADDRSTRLEN);
+ zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
+ }
+ bgp_info_unset_flag (rn, ri, BGP_INFO_VALID);
+ }
}
else
- bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
+ bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
bgp_attr_flush (&new_attr);
@@ -2367,38 +2580,48 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
}
/* Received Logging. */
- if (BGP_DEBUG (update, UPDATE_IN))
+ if (bgp_debug_update(peer, p, 1))
{
- zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ if (!peer->rcvd_attr_printed)
+ {
+ zlog_debug ("%s rcvd UPDATE w/ attr: %s", peer->host, peer->rcvd_attr_str);
+ peer->rcvd_attr_printed = 1;
+ }
+
+ zlog_debug ("%s rcvd %s/%d",
+ peer->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
}
/* Make new BGP info. */
- new = bgp_info_new ();
- new->type = type;
- new->sub_type = sub_type;
- new->peer = peer;
- new->attr = attr_new;
- new->uptime = bgp_clock ();
+ new = info_make(type, sub_type, peer, attr_new, rn);
/* Update MPLS tag. */
if (safi == SAFI_MPLS_VPN)
memcpy ((bgp_info_extra_get (new))->tag, tag, 3);
/* Nexthop reachability check. */
- if ((afi == AFI_IP || afi == AFI_IP6)
- && safi == SAFI_UNICAST
- && (peer->sort == BGP_PEER_IBGP
- || peer->sort == BGP_PEER_CONFED
- || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
- || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)))
- {
- if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL))
+ if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST)
+ {
+ if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 &&
+ ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
+ connected = 1;
+ else
+ connected = 0;
+
+ if (bgp_find_or_add_nexthop (afi, new, NULL, connected))
bgp_info_set_flag (rn, new, BGP_INFO_VALID);
else
- bgp_info_unset_flag (rn, new, BGP_INFO_VALID);
+ {
+ if (BGP_DEBUG(nht, NHT))
+ {
+ char buf1[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, INET6_ADDRSTRLEN);
+ zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
+ }
+ bgp_info_unset_flag (rn, new, BGP_INFO_VALID);
+ }
}
else
bgp_info_set_flag (rn, new, BGP_INFO_VALID);
@@ -2427,12 +2650,19 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* This BGP update is filtered. Log the reason then update BGP
entry. */
filtered:
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG,
- "%s rcvd UPDATE about %s/%d -- DENIED due to: %s",
- peer->host,
- inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, reason);
+ if (bgp_debug_update(peer, p, 1))
+ {
+ if (!peer->rcvd_attr_printed)
+ {
+ zlog_debug ("%s rcvd UPDATE w/ attr: %s", peer->host, peer->rcvd_attr_str);
+ peer->rcvd_attr_printed = 1;
+ }
+
+ zlog_debug ("%s rcvd UPDATE about %s/%d -- DENIED due to: %s",
+ peer->host,
+ inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen, reason);
+ }
if (ri)
bgp_rib_remove (rn, ri, peer, afi, safi);
@@ -2495,11 +2725,11 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,
&& peer != bgp->peer_self)
if (!bgp_adj_in_unset (rn, peer))
{
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "%s withdrawing route %s/%d "
- "not in adj-in", peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ if (bgp_debug_update (peer, p, 1))
+ zlog_debug ("%s withdrawing route %s/%d "
+ "not in adj-in", peer->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
bgp_unlock_node (rn);
return 0;
}
@@ -2512,11 +2742,11 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,
}
/* Logging. */
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "%s rcvd UPDATE about %s/%d -- withdrawn",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ if (bgp_debug_update(peer, p, 1))
+ zlog_debug ("%s rcvd UPDATE about %s/%d -- withdrawn",
+ peer->host,
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
/* Lookup withdrawn route. */
for (ri = rn->info; ri; ri = ri->next)
@@ -2526,11 +2756,10 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,
/* Withdraw specified route from routing table. */
if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
bgp_rib_withdraw (rn, ri, peer, afi, safi, prd);
- else if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG,
- "%s Can't find the route %s/%d", peer->host,
- inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ else if (bgp_debug_update(peer, p, 1))
+ zlog_debug ("%s Can't find the route %s/%d", peer->host,
+ inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
/* Unlock bgp_node_get() lock. */
bgp_unlock_node (rn);
@@ -2701,6 +2930,12 @@ bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi)
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
bgp_announce_table (peer, afi, safi, NULL, 1);
+
+ /*
+ * The write thread needs to be scheduled since it may not be done as
+ * part of building adj_out.
+ */
+ bgp_peer_schedule_updates(peer);
}
void
@@ -3261,8 +3496,7 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr,
/* Prefix length check. */
if (p.prefixlen > prefix_blen (&p) * 8)
{
- plog_err (peer->log,
- "%s [Error] Update packet error"
+ zlog_err ("%s [Error] Update packet error"
" (wrong prefix length %u for afi %u)",
peer->host, p.prefixlen, packet->afi);
return -1;
@@ -3274,8 +3508,7 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr,
/* When packet overflow occur return immediately. */
if (pnt + psize > lim)
{
- plog_err (peer->log,
- "%s [Error] Update packet error"
+ zlog_err ("%s [Error] Update packet error"
" (prefix length %u overflows packet)",
peer->host, p.prefixlen);
return -1;
@@ -3284,8 +3517,7 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr,
/* Defensive coding, double-check the psize fits in a struct prefix */
if (psize > (ssize_t) sizeof(p.u))
{
- plog_err (peer->log,
- "%s [Error] Update packet error"
+ zlog_err ("%s [Error] Update packet error"
" (prefix length %u too large for prefix storage %zu!?!!",
peer->host, p.prefixlen, sizeof(p.u));
return -1;
@@ -3306,9 +3538,8 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr,
* (e.g., an unexpected multicast IP address), an error SHOULD
* be logged locally, and the prefix SHOULD be ignored.
*/
- zlog (peer->log, LOG_ERR,
- "%s: IPv4 unicast NLRI is multicast address %s, ignoring",
- peer->host, inet_ntoa (p.u.prefix4));
+ zlog_err ("IPv4 unicast NLRI is multicast address %s",
+ inet_ntoa (p.u.prefix4));
continue;
}
}
@@ -3320,18 +3551,15 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr,
{
char buf[BUFSIZ];
- zlog (peer->log, LOG_ERR,
- "%s: IPv6 unicast NLRI is link-local address %s, ignoring",
- peer->host,
- inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ));
+ zlog_warn ("IPv6 link-local NLRI received %s ignore this NLRI",
+ inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ));
continue;
}
if (IN6_IS_ADDR_MULTICAST (&p.u.prefix6))
{
char buf[BUFSIZ];
- zlog (peer->log, LOG_ERR,
- "%s: IPv6 unicast NLRI is multicast address %s, ignoring",
+ zlog_err ("%s: IPv6 unicast NLRI is multicast address %s, ignoring",
peer->host,
inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ));
continue;
@@ -3355,8 +3583,7 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr,
/* Packet length consistency check. */
if (pnt != lim)
{
- plog_err (peer->log,
- "%s [Error] Update packet error"
+ zlog_err ("%s [Error] Update packet error"
" (prefix length mismatch with total length)",
peer->host);
return -1;
@@ -3480,11 +3707,10 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
== RMAP_DENY)
{
/* This BGP update is filtered. Log the reason then update BGP entry. */
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (rsclient->log, LOG_DEBUG,
- "Static UPDATE about %s/%d -- DENIED for RS-client %s due to: import-policy",
- inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, rsclient->host);
+ if (bgp_debug_update(rsclient, p, 1))
+ zlog_debug ("Static UPDATE about %s/%d -- DENIED for RS-client %s due to: import-policy",
+ inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen, rsclient->host);
bgp->peer_self->rmap_type = 0;
@@ -3530,6 +3756,23 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
ri->attr = attr_new;
ri->uptime = bgp_clock ();
+ /* Nexthop reachability check. */
+ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
+ {
+ if (bgp_find_or_add_nexthop (afi, ri, NULL, 0))
+ bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
+ else
+ {
+ if (BGP_DEBUG(nht, NHT))
+ {
+ char buf1[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET, (const void *)&attr_new->nexthop,
+ buf1, INET6_ADDRSTRLEN);
+ zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
+ }
+ bgp_info_unset_flag (rn, ri, BGP_INFO_VALID);
+ }
+ }
/* Process change. */
bgp_process (bgp, rn, afi, safi);
bgp_unlock_node (rn);
@@ -3538,15 +3781,29 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
return;
}
}
-
+
/* Make new BGP info. */
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_STATIC;
- new->peer = bgp->peer_self;
- SET_FLAG (new->flags, BGP_INFO_VALID);
- new->attr = attr_new;
- new->uptime = bgp_clock ();
+ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self,
+ attr_new, rn);
+ /* Nexthop reachability check. */
+ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
+ {
+ if (bgp_find_or_add_nexthop (afi, new, NULL, 0))
+ bgp_info_set_flag (rn, new, BGP_INFO_VALID);
+ else
+ {
+ if (BGP_DEBUG(nht, NHT))
+ {
+ char buf1[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET, (const void *)&attr_new->nexthop,
+ buf1, INET6_ADDRSTRLEN);
+ zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
+ }
+ bgp_info_unset_flag (rn, new, BGP_INFO_VALID);
+ }
+ }
+ else
+ bgp_info_set_flag (rn, new, BGP_INFO_VALID);
/* Register new BGP information. */
bgp_info_add (rn, new);
@@ -3564,7 +3821,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
static void
bgp_static_update_main (struct bgp *bgp, struct prefix *p,
- struct bgp_static *bgp_static, afi_t afi, safi_t safi)
+ struct bgp_static *bgp_static, afi_t afi, safi_t safi)
{
struct bgp_node *rn;
struct bgp_info *ri;
@@ -3648,6 +3905,23 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
ri->attr = attr_new;
ri->uptime = bgp_clock ();
+ /* Nexthop reachability check. */
+ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
+ {
+ if (bgp_find_or_add_nexthop (afi, ri, NULL, 0))
+ bgp_info_set_flag (rn, ri, BGP_INFO_VALID);
+ else
+ {
+ if (BGP_DEBUG(nht, NHT))
+ {
+ char buf1[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET, (const void *)&attr_new->nexthop,
+ buf1, INET6_ADDRSTRLEN);
+ zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
+ }
+ bgp_info_unset_flag (rn, ri, BGP_INFO_VALID);
+ }
+ }
/* Process change. */
bgp_aggregate_increment (bgp, p, ri, afi, safi);
bgp_process (bgp, rn, afi, safi);
@@ -3659,13 +3933,27 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
}
/* Make new BGP info. */
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_STATIC;
- new->peer = bgp->peer_self;
- SET_FLAG (new->flags, BGP_INFO_VALID);
- new->attr = attr_new;
- new->uptime = bgp_clock ();
+ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, attr_new,
+ rn);
+ /* Nexthop reachability check. */
+ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
+ {
+ if (bgp_find_or_add_nexthop (afi, new, NULL, 0))
+ bgp_info_set_flag (rn, new, BGP_INFO_VALID);
+ else
+ {
+ if (BGP_DEBUG(nht, NHT))
+ {
+ char buf1[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1,
+ INET6_ADDRSTRLEN);
+ zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1);
+ }
+ bgp_info_unset_flag (rn, new, BGP_INFO_VALID);
+ }
+ }
+ else
+ bgp_info_set_flag (rn, new, BGP_INFO_VALID);
/* Aggregate address increment. */
bgp_aggregate_increment (bgp, p, new, afi, safi);
@@ -3706,8 +3994,14 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi,
{
struct bgp_node *rn;
struct bgp_info *ri;
+ struct bgp_info *new;
- rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, NULL);
+ /* Make new BGP info. */
+ rn = bgp_node_get (bgp->rib[afi][safi], p);
+ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self,
+ bgp_attr_default_intern(BGP_ORIGIN_IGP), rn);
+
+ SET_FLAG (new->flags, BGP_INFO_VALID);
/* Check selected route and self inserted route. */
for (ri = rn->info; ri; ri = ri->next)
@@ -3720,6 +4014,7 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi,
if (ri)
{
bgp_aggregate_decrement (bgp, p, ri, afi, safi);
+ bgp_unlink_nexthop(ri);
bgp_info_delete (rn, ri);
bgp_process (bgp, rn, afi, safi);
}
@@ -3877,13 +4172,9 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
/* Make new BGP info. */
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_STATIC;
- new->peer = bgp->peer_self;
- new->attr = attr_new;
+ new = info_make (ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self,
+ attr_new, rn);
SET_FLAG (new->flags, BGP_INFO_VALID);
- new->uptime = bgp_clock ();
new->extra = bgp_info_extra_new();
memcpy (new->extra->tag, bgp_static->tag, 3);
@@ -3982,17 +4273,12 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str,
rn->info = bgp_static;
}
- /* If BGP scan is not enabled, we should install this route here. */
- if (! bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
- {
- bgp_static->valid = 1;
-
- if (need_update)
- bgp_static_withdraw (bgp, &p, afi, safi);
+ bgp_static->valid = 1;
+ if (need_update)
+ bgp_static_withdraw (bgp, &p, afi, safi);
- if (! bgp_static->backdoor)
- bgp_static_update (bgp, &p, bgp_static, afi, safi);
- }
+ if (! bgp_static->backdoor)
+ bgp_static_update (bgp, &p, bgp_static, afi, safi);
return CMD_SUCCESS;
}
@@ -4242,6 +4528,84 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
return CMD_SUCCESS;
}
+static int
+bgp_table_map_set (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *rmap_name)
+{
+ struct bgp_rmap *rmap;
+
+ rmap = &bgp->table_map[afi][safi];
+ if (rmap_name)
+ {
+ if (rmap->name)
+ free (rmap->name);
+ rmap->name = strdup (rmap_name);
+ rmap->map = route_map_lookup_by_name (rmap_name);
+ }
+ else
+ {
+ if (rmap->name)
+ free (rmap->name);
+ rmap->name = NULL;
+ rmap->map = NULL;
+ }
+
+ bgp_zebra_announce_table(bgp, afi, safi);
+
+ return CMD_SUCCESS;
+}
+
+static int
+bgp_table_map_unset (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *rmap_name)
+{
+ struct bgp_rmap *rmap;
+
+ rmap = &bgp->table_map[afi][safi];
+ if (rmap->name)
+ free (rmap->name);
+ rmap->name = NULL;
+ rmap->map = NULL;
+
+ bgp_zebra_announce_table(bgp, afi, safi);
+
+ return CMD_SUCCESS;
+}
+
+int
+bgp_config_write_table_map (struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi, int *write)
+{
+ if (bgp->table_map[afi][safi].name)
+ {
+ bgp_config_write_family_header (vty, afi, safi, write);
+ vty_out (vty, " table-map %s%s",
+ bgp->table_map[afi][safi].name, VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+
+DEFUN (bgp_table_map,
+ bgp_table_map_cmd,
+ "table-map WORD",
+ "BGP table to RIB route download filter\n"
+ "Name of the route map\n")
+{
+ return bgp_table_map_set (vty, vty->index,
+ bgp_node_afi (vty), bgp_node_safi (vty), argv[0]);
+}
+DEFUN (no_bgp_table_map,
+ no_bgp_table_map_cmd,
+ "no table-map WORD",
+ "BGP table to RIB route download filter\n"
+ "Name of the route map\n")
+{
+ return bgp_table_map_unset (vty, vty->index,
+ bgp_node_afi (vty), bgp_node_safi (vty), argv[0]);
+}
+
DEFUN (bgp_network,
bgp_network_cmd,
"network A.B.C.D/M",
@@ -4736,6 +5100,7 @@ bgp_aggregate_free (struct bgp_aggregate *aggregate)
XFREE (MTYPE_BGP_AGGREGATE, aggregate);
}
+/* Update an aggregate as routes are added/removed from the BGP table */
static void
bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
afi_t afi, safi_t safi, struct bgp_info *del,
@@ -4753,6 +5118,7 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
struct bgp_info *new;
int first = 1;
unsigned long match = 0;
+ u_char atomic_aggregate = 0;
/* ORIGIN attribute: If at least one route among routes that are
aggregated has ORIGIN with the value INCOMPLETE, then the
@@ -4797,6 +5163,9 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
}
#endif /* AGGREGATE_NEXTHOP_CHECK */
+ if (ri->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))
+ atomic_aggregate = 1;
+
if (ri->sub_type != BGP_ROUTE_AGGREGATE)
{
if (aggregate->summary_only)
@@ -4808,11 +5177,11 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
aggregate->count++;
+ if (origin < ri->attr->origin)
+ origin = ri->attr->origin;
+
if (aggregate->as_set)
{
- if (origin < ri->attr->origin)
- origin = ri->attr->origin;
-
if (aspath)
{
asmerge = aspath_aggregate (aspath, ri->attr->aspath);
@@ -4849,11 +5218,11 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
if (aggregate->summary_only)
(bgp_info_extra_get (rinew))->suppress++;
+ if (origin < rinew->attr->origin)
+ origin = rinew->attr->origin;
+
if (aggregate->as_set)
{
- if (origin < rinew->attr->origin)
- origin = rinew->attr->origin;
-
if (aspath)
{
asmerge = aspath_aggregate (aspath, rinew->attr->aspath);
@@ -4881,13 +5250,11 @@ bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
if (aggregate->count > 0)
{
rn = bgp_node_get (table, p);
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_AGGREGATE;
- new->peer = bgp->peer_self;
+ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, bgp->peer_self,
+ bgp_attr_aggregate_intern(bgp, origin, aspath, community,
+ aggregate->as_set,
+ atomic_aggregate), rn);
SET_FLAG (new->flags, BGP_INFO_VALID);
- new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set);
- new->uptime = bgp_clock ();
bgp_info_add (rn, new);
bgp_unlock_node (rn);
@@ -4976,6 +5343,7 @@ bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p,
bgp_unlock_node (child);
}
+/* Called via bgp_aggregate_set when the user configures aggregate-address */
static void
bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
struct bgp_aggregate *aggregate)
@@ -4991,6 +5359,7 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
struct aspath *asmerge = NULL;
struct community *community = NULL;
struct community *commerge = NULL;
+ u_char atomic_aggregate = 0;
table = bgp->rib[afi][safi];
@@ -5012,6 +5381,9 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
if (BGP_INFO_HOLDDOWN (ri))
continue;
+ if (ri->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))
+ atomic_aggregate = 1;
+
if (ri->sub_type != BGP_ROUTE_AGGREGATE)
{
/* summary-only aggregate route suppress aggregated
@@ -5022,13 +5394,21 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
match++;
}
+
+ /* If at least one route among routes that are aggregated has
+ * ORIGIN with the value INCOMPLETE, then the aggregated route
+ * MUST have the ORIGIN attribute with the value INCOMPLETE.
+ * Otherwise, if at least one route among routes that are
+ * aggregated has ORIGIN with the value EGP, then the aggregated
+ * route MUST have the ORIGIN attribute with the value EGP.
+ */
+ if (origin < ri->attr->origin)
+ origin = ri->attr->origin;
+
/* as-set aggregate route generate origin, as path,
community aggregation. */
if (aggregate->as_set)
{
- if (origin < ri->attr->origin)
- origin = ri->attr->origin;
-
if (aspath)
{
asmerge = aspath_aggregate (aspath, ri->attr->aspath);
@@ -5065,14 +5445,11 @@ bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
if (aggregate->count)
{
rn = bgp_node_get (table, p);
-
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_AGGREGATE;
- new->peer = bgp->peer_self;
+ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, bgp->peer_self,
+ bgp_attr_aggregate_intern(bgp, origin, aspath, community,
+ aggregate->as_set,
+ atomic_aggregate), rn);
SET_FLAG (new->flags, BGP_INFO_VALID);
- new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set);
- new->uptime = bgp_clock ();
bgp_info_add (rn, new);
bgp_unlock_node (rn);
@@ -5602,8 +5979,8 @@ ALIAS (no_ipv6_aggregate_address_summary_only,
/* Redistribute route treatment. */
void
bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop,
- const struct in6_addr *nexthop6,
- u_int32_t metric, u_char type)
+ const struct in6_addr *nexthop6, unsigned int ifindex,
+ u_int32_t metric, u_char type, u_short tag)
{
struct bgp *bgp;
struct listnode *node, *nnode;
@@ -5620,6 +5997,7 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop,
bgp_attr_default_set (&attr, BGP_ORIGIN_INCOMPLETE);
if (nexthop)
attr.nexthop = *nexthop;
+ attr.nh_ifindex = ifindex;
if (nexthop6)
{
@@ -5630,6 +6008,7 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop,
attr.med = metric;
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
+ attr.extra->tag = tag;
for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
{
@@ -5715,16 +6094,12 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop,
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
return;
- }
+ }
}
- new = bgp_info_new ();
- new->type = type;
- new->sub_type = BGP_ROUTE_REDISTRIBUTE;
- new->peer = bgp->peer_self;
+ new = info_make(type, BGP_ROUTE_REDISTRIBUTE, bgp->peer_self,
+ new_attr, bn);
SET_FLAG (new->flags, BGP_INFO_VALID);
- new->attr = new_attr;
- new->uptime = bgp_clock ();
bgp_aggregate_increment (bgp, p, new, afi, SAFI_UNICAST);
bgp_info_add (bn, new);
@@ -5847,7 +6222,8 @@ route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo)
vty_out (vty, "S");
else if (binfo->extra && binfo->extra->suppress)
vty_out (vty, "s");
- else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+ else if (CHECK_FLAG (binfo->flags, BGP_INFO_VALID) &&
+ ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
vty_out (vty, "*");
else
vty_out (vty, " ");
@@ -6293,7 +6669,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
VTY_NEWLINE);
}
- /* Line 3 display Origin, Med, Locpref, Weight, valid, Int/Ext/Local, Atomic, best */
+ /* Line 3 display Origin, Med, Locpref, Weight, Tag, valid, Int/Ext/Local, Atomic, best */
vty_out (vty, " Origin %s", bgp_origin_long_str[attr->origin]);
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))
@@ -6306,8 +6682,13 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (attr->extra && attr->extra->weight != 0)
vty_out (vty, ", weight %u", attr->extra->weight);
+
+ if (attr->extra && attr->extra->tag != 0)
+ vty_out (vty, ", tag %d", attr->extra->tag);
- if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+ if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID))
+ vty_out (vty, ", invalid");
+ else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
vty_out (vty, ", valid");
if (binfo->peer != bgp->peer_self)
@@ -6756,7 +7137,7 @@ static int
bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
struct bgp_table *rib, const char *ip_str,
afi_t afi, safi_t safi, struct prefix_rd *prd,
- int prefix_check)
+ int prefix_check, enum bgp_path_type pathtype)
{
int ret;
int header;
@@ -6807,7 +7188,12 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
header = 0;
}
display++;
- route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, safi);
+
+ if (pathtype == BGP_PATH_ALL ||
+ (pathtype == BGP_PATH_BESTPATH && CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) ||
+ (pathtype == BGP_PATH_MULTIPATH &&
+ (CHECK_FLAG (ri->flags, BGP_INFO_MULTIPATH) || CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))))
+ route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, safi);
}
bgp_unlock_node (rm);
@@ -6831,7 +7217,12 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
header = 0;
}
display++;
- route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi);
+
+ if (pathtype == BGP_PATH_ALL ||
+ (pathtype == BGP_PATH_BESTPATH && CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) ||
+ (pathtype == BGP_PATH_MULTIPATH &&
+ (CHECK_FLAG (ri->flags, BGP_INFO_MULTIPATH) || CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))))
+ route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi);
}
}
@@ -6852,7 +7243,7 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
static int
bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
afi_t afi, safi_t safi, struct prefix_rd *prd,
- int prefix_check)
+ int prefix_check, enum bgp_path_type pathtype)
{
struct bgp *bgp;
@@ -6877,7 +7268,7 @@ bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
}
return bgp_show_route_in_table (vty, bgp, bgp->rib[afi][safi], ip_str,
- afi, safi, prd, prefix_check);
+ afi, safi, prd, prefix_check, pathtype);
}
/* BGP route print out function. */
@@ -6916,7 +7307,47 @@ DEFUN (show_ip_bgp_route,
BGP_STR
"Network in the BGP routing table to display\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
+}
+
+DEFUN (show_ip_bgp_route_pathtype,
+ show_ip_bgp_route_pathtype_cmd,
+ "show ip bgp A.B.C.D (bestpath|multipath)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Display only the bestpath\n"
+ "Display only multipaths\n")
+{
+ if (strncmp (argv[1], "b", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_BESTPATH);
+ else
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH);
+}
+
+DEFUN (show_bgp_ipv4_safi_route_pathtype,
+ show_bgp_ipv4_safi_route_pathtype_cmd,
+ "show bgp ipv4 (unicast|multicast) A.B.C.D (bestpath|multipath)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Display only the bestpath\n"
+ "Display only multipaths\n")
+{
+ if (strncmp (argv[0], "m", 1) == 0)
+ if (strncmp (argv[2], "b", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0, BGP_PATH_BESTPATH);
+ else
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0, BGP_PATH_MULTIPATH);
+ else
+ if (strncmp (argv[2], "b", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_BESTPATH);
+ else
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH);
}
DEFUN (show_ip_bgp_ipv4_route,
@@ -6931,9 +7362,9 @@ DEFUN (show_ip_bgp_ipv4_route,
"Network in the BGP routing table to display\n")
{
if (strncmp (argv[0], "m", 1) == 0)
- return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0, BGP_PATH_ALL);
- return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
}
DEFUN (show_ip_bgp_vpnv4_all_route,
@@ -6946,9 +7377,10 @@ DEFUN (show_ip_bgp_vpnv4_all_route,
"Display information about all VPNv4 NLRIs\n"
"Network in the BGP routing table to display\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_ALL);
}
+
DEFUN (show_ip_bgp_vpnv4_rd_route,
show_ip_bgp_vpnv4_rd_route_cmd,
"show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D",
@@ -6969,7 +7401,7 @@ DEFUN (show_ip_bgp_vpnv4_rd_route,
vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
return CMD_WARNING;
}
- return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0, BGP_PATH_ALL);
}
DEFUN (show_ip_bgp_prefix,
@@ -6980,7 +7412,23 @@ DEFUN (show_ip_bgp_prefix,
BGP_STR
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
+}
+
+DEFUN (show_ip_bgp_prefix_pathtype,
+ show_ip_bgp_prefix_pathtype_cmd,
+ "show ip bgp A.B.C.D/M (bestpath|multipath)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Display only the bestpath\n"
+ "Display only multipaths\n")
+{
+ if (strncmp (argv[1], "b", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_BESTPATH);
+ else
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_MULTIPATH);
}
DEFUN (show_ip_bgp_ipv4_prefix,
@@ -6995,11 +7443,48 @@ DEFUN (show_ip_bgp_ipv4_prefix,
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
if (strncmp (argv[0], "m", 1) == 0)
- return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1, BGP_PATH_ALL);
+
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
+}
- return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1);
+DEFUN (show_ip_bgp_ipv4_prefix_pathtype,
+ show_ip_bgp_ipv4_prefix_pathtype_cmd,
+ "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M (bestpath|multipath)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Display only the bestpath\n"
+ "Display only multipaths\n")
+{
+ if (strncmp (argv[0], "m", 1) == 0)
+ if (strncmp (argv[2], "b", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1, BGP_PATH_BESTPATH);
+ else
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1, BGP_PATH_MULTIPATH);
+ else
+ if (strncmp (argv[2], "b", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_BESTPATH);
+ else
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_MULTIPATH);
}
+ALIAS (show_ip_bgp_ipv4_prefix_pathtype,
+ show_bgp_ipv4_safi_prefix_pathtype_cmd,
+ "show bgp ipv4 (unicast|multicast) A.B.C.D/M (bestpath|multipath)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Display only the bestpath\n"
+ "Display only multipaths\n")
+
DEFUN (show_ip_bgp_vpnv4_all_prefix,
show_ip_bgp_vpnv4_all_prefix_cmd,
"show ip bgp vpnv4 all A.B.C.D/M",
@@ -7010,7 +7495,7 @@ DEFUN (show_ip_bgp_vpnv4_all_prefix,
"Display information about all VPNv4 NLRIs\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_ip_bgp_vpnv4_rd_prefix,
@@ -7033,7 +7518,7 @@ DEFUN (show_ip_bgp_vpnv4_rd_prefix,
vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
return CMD_WARNING;
}
- return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1, BGP_PATH_ALL);
}
DEFUN (show_ip_bgp_view,
@@ -7068,7 +7553,7 @@ DEFUN (show_ip_bgp_view_route,
"View name\n"
"Network in the BGP routing table to display\n")
{
- return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0);
+ return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
}
DEFUN (show_ip_bgp_view_prefix,
@@ -7081,7 +7566,7 @@ DEFUN (show_ip_bgp_view_prefix,
"View name\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
- return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1);
+ return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp,
@@ -7120,7 +7605,7 @@ DEFUN (show_bgp_route,
BGP_STR
"Network in the BGP routing table to display\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv4_safi,
@@ -7150,9 +7635,58 @@ DEFUN (show_bgp_ipv4_safi_route,
"Network in the BGP routing table to display\n")
{
if (strncmp (argv[0], "m", 1) == 0)
- return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0, BGP_PATH_ALL);
+
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
+}
+
+DEFUN (show_bgp_route_pathtype,
+ show_bgp_route_pathtype_cmd,
+ "show bgp X:X::X:X (bestpath|multipath)",
+ SHOW_STR
+ BGP_STR
+ "Network in the BGP routing table to display\n"
+ "Display only the bestpath\n"
+ "Display only multipaths\n")
+{
+ if (strncmp (argv[1], "b", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_BESTPATH);
+ else
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH);
+}
- return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0);
+ALIAS (show_bgp_route_pathtype,
+ show_bgp_ipv6_route_pathtype_cmd,
+ "show bgp ipv6 X:X::X:X (bestpath|multipath)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Network in the BGP routing table to display\n"
+ "Display only the bestpath\n"
+ "Display only multipaths\n")
+
+DEFUN (show_bgp_ipv6_safi_route_pathtype,
+ show_bgp_ipv6_safi_route_pathtype_cmd,
+ "show bgp ipv6 (unicast|multicast) X:X::X:X (bestpath|multipath)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Network in the BGP routing table to display\n"
+ "Display only the bestpath\n"
+ "Display only multipaths\n")
+{
+ if (strncmp (argv[0], "m", 1) == 0)
+ if (strncmp (argv[2], "b", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0, BGP_PATH_BESTPATH);
+ else
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0, BGP_PATH_MULTIPATH);
+ else
+ if (strncmp (argv[2], "b", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_BESTPATH);
+ else
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH);
}
DEFUN (show_bgp_ipv4_vpn_route,
@@ -7164,7 +7698,7 @@ DEFUN (show_bgp_ipv4_vpn_route,
"Display VPN NLRI specific information\n"
"Network in the BGP routing table to display\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv6_vpn_route,
@@ -7176,7 +7710,7 @@ DEFUN (show_bgp_ipv6_vpn_route,
"Display VPN NLRI specific information\n"
"Network in the BGP routing table to display\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv4_vpn_rd_route,
@@ -7199,7 +7733,7 @@ DEFUN (show_bgp_ipv4_vpn_rd_route,
vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
return CMD_WARNING;
}
- return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv6_vpn_rd_route,
@@ -7222,7 +7756,56 @@ DEFUN (show_bgp_ipv6_vpn_rd_route,
vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
return CMD_WARNING;
}
- return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MPLS_VPN, &prd, 0);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MPLS_VPN, &prd, 0, BGP_PATH_ALL);
+}
+
+DEFUN (show_bgp_prefix_pathtype,
+ show_bgp_prefix_pathtype_cmd,
+ "show bgp X:X::X:X/M (bestpath|multipath)",
+ SHOW_STR
+ BGP_STR
+ "IPv6 prefix <network>/<length>\n"
+ "Display only the bestpath\n"
+ "Display only multipaths\n")
+{
+ if (strncmp (argv[1], "b", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_BESTPATH);
+ else
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_MULTIPATH);
+}
+
+ALIAS (show_bgp_prefix_pathtype,
+ show_bgp_ipv6_prefix_pathtype_cmd,
+ "show bgp ipv6 X:X::X:X/M (bestpath|multipath)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "IPv6 prefix <network>/<length>\n"
+ "Display only the bestpath\n"
+ "Display only multipaths\n")
+
+DEFUN (show_bgp_ipv6_safi_prefix_pathtype,
+ show_bgp_ipv6_safi_prefix_pathtype_cmd,
+ "show bgp ipv6 (unicast|multicast) X:X::X:X/M (bestpath|multipath)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+ "Display only the bestpath\n"
+ "Display only multipaths\n")
+{
+ if (strncmp (argv[0], "m", 1) == 0)
+ if (strncmp (argv[2], "b", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1, BGP_PATH_BESTPATH);
+ else
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1, BGP_PATH_MULTIPATH);
+ else
+ if (strncmp (argv[2], "b", 1) == 0)
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_BESTPATH);
+ else
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_MULTIPATH);
}
DEFUN (show_bgp_ipv4_encap_route,
@@ -7234,7 +7817,7 @@ DEFUN (show_bgp_ipv4_encap_route,
"Display ENCAP NLRI specific information\n"
"Network in the BGP routing table to display\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv6_encap_route,
@@ -7246,7 +7829,7 @@ DEFUN (show_bgp_ipv6_encap_route,
"Display ENCAP NLRI specific information\n"
"Network in the BGP routing table to display\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv4_safi_rd_route,
@@ -7275,7 +7858,7 @@ DEFUN (show_bgp_ipv4_safi_rd_route,
vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
return CMD_WARNING;
}
- return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 0);
+ return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv6_safi_rd_route,
@@ -7304,7 +7887,7 @@ DEFUN (show_bgp_ipv6_safi_rd_route,
vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
return CMD_WARNING;
}
- return bgp_show_route (vty, NULL, argv[2], AFI_IP6, SAFI_ENCAP, &prd, 0);
+ return bgp_show_route (vty, NULL, argv[2], AFI_IP6, SAFI_ENCAP, &prd, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv4_prefix,
@@ -7315,7 +7898,7 @@ DEFUN (show_bgp_ipv4_prefix,
IP_STR
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv4_safi_prefix,
@@ -7329,9 +7912,9 @@ DEFUN (show_bgp_ipv4_safi_prefix,
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
if (strncmp (argv[0], "m", 1) == 0)
- return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1, BGP_PATH_ALL);
- return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv4_vpn_prefix,
@@ -7343,7 +7926,7 @@ DEFUN (show_bgp_ipv4_vpn_prefix,
"Display VPN NLRI specific information\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv6_vpn_prefix,
@@ -7355,7 +7938,7 @@ DEFUN (show_bgp_ipv6_vpn_prefix,
"Display VPN NLRI specific information\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv4_encap_prefix,
@@ -7368,7 +7951,7 @@ DEFUN (show_bgp_ipv4_encap_prefix,
"Display information about ENCAP NLRIs\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv6_encap_prefix,
@@ -7381,7 +7964,7 @@ DEFUN (show_bgp_ipv6_encap_prefix,
"Display information about ENCAP NLRIs\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv4_safi_rd_prefix,
@@ -7411,7 +7994,7 @@ DEFUN (show_bgp_ipv4_safi_rd_prefix,
vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
return CMD_WARNING;
}
- return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 1);
+ return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv6_safi_rd_prefix,
@@ -7441,7 +8024,7 @@ DEFUN (show_bgp_ipv6_safi_rd_prefix,
vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
return CMD_WARNING;
}
- return bgp_show_route (vty, NULL, argv[2], AFI_IP6, safi, &prd, 1);
+ return bgp_show_route (vty, NULL, argv[2], AFI_IP6, safi, &prd, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_afi_safi_view,
@@ -7509,7 +8092,7 @@ DEFUN (show_bgp_view_afi_safi_route,
vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
- return bgp_show_route (vty, argv[0], argv[3], afi, safi, NULL, 0);
+ return bgp_show_route (vty, argv[0], argv[3], afi, safi, NULL, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_view_afi_safi_prefix,
@@ -7538,7 +8121,7 @@ DEFUN (show_bgp_view_afi_safi_prefix,
vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
- return bgp_show_route (vty, argv[0], argv[3], afi, safi, NULL, 1);
+ return bgp_show_route (vty, argv[0], argv[3], afi, safi, NULL, 1, BGP_PATH_ALL);
}
/* new001 */
@@ -7584,7 +8167,7 @@ DEFUN (show_bgp_ipv6_route,
"Address family\n"
"Network in the BGP routing table to display\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv6_safi_route,
@@ -7598,9 +8181,9 @@ DEFUN (show_bgp_ipv6_safi_route,
"Network in the BGP routing table to display\n")
{
if (strncmp (argv[0], "m", 1) == 0)
- return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0, BGP_PATH_ALL);
- return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
}
/* old command */
@@ -7612,7 +8195,7 @@ DEFUN (show_ipv6_bgp_route,
BGP_STR
"Network in the BGP routing table to display\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_prefix,
@@ -7622,7 +8205,7 @@ DEFUN (show_bgp_prefix,
BGP_STR
"IPv6 prefix <network>/<length>\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
}
@@ -7635,7 +8218,7 @@ DEFUN (show_bgp_ipv6_prefix,
"Address family\n"
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_ipv6_safi_prefix,
show_bgp_ipv6_safi_prefix_cmd,
@@ -7648,9 +8231,9 @@ DEFUN (show_bgp_ipv6_safi_prefix,
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
{
if (strncmp (argv[0], "m", 1) == 0)
- return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1, BGP_PATH_ALL);
- return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
}
/* old command */
@@ -7662,7 +8245,7 @@ DEFUN (show_ipv6_bgp_prefix,
BGP_STR
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_view,
@@ -7717,7 +8300,7 @@ DEFUN (show_bgp_view_route,
"View name\n"
"Network in the BGP routing table to display\n")
{
- return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0);
+ return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_view_ipv6_route,
@@ -7730,7 +8313,7 @@ DEFUN (show_bgp_view_ipv6_route,
"Address family\n"
"Network in the BGP routing table to display\n")
{
- return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0);
+ return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
}
/* old command */
@@ -7754,7 +8337,7 @@ DEFUN (show_ipv6_mbgp_route,
MBGP_STR
"Network in the MBGP routing table to display\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 0);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 0, BGP_PATH_ALL);
}
/* old command */
@@ -7766,7 +8349,7 @@ DEFUN (show_ipv6_mbgp_prefix,
MBGP_STR
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
{
- return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1);
+ return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_view_prefix,
@@ -7778,7 +8361,7 @@ DEFUN (show_bgp_view_prefix,
"View name\n"
"IPv6 prefix <network>/<length>\n")
{
- return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1);
+ return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_view_ipv6_prefix,
@@ -7791,7 +8374,7 @@ DEFUN (show_bgp_view_ipv6_prefix,
"Address family\n"
"IPv6 prefix <network>/<length>\n")
{
- return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1);
+ return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
}
static int
@@ -11548,8 +12131,13 @@ peer_lookup_in_view (struct vty *vty, const char *view_name,
ret = str2sockunion (ip_str, &su);
if (ret < 0)
{
- vty_out (vty, "Malformed address: %s%s", ip_str, VTY_NEWLINE);
- return NULL;
+ peer = peer_lookup_by_conf_if (bgp, ip_str);
+ if (!peer)
+ {
+ vty_out (vty, "%% Malformed address or name: %s%s", ip_str, VTY_NEWLINE);
+ return NULL;
+ }
+ return peer;
}
/* Peer structure lookup. */
@@ -11998,8 +12586,7 @@ bgp_peer_count_walker (struct thread *t)
{
pc->count[PCOUNT_COUNTED]++;
if (CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE))
- plog_warn (peer->log,
- "%s [pcount] %s/%d is counted but flags 0x%x",
+ zlog_warn ("%s [pcount] %s/%d is counted but flags 0x%x",
peer->host,
inet_ntop(rn->p.family, &rn->p.u.prefix,
buf, SU_ADDRSTRLEN),
@@ -12009,8 +12596,7 @@ bgp_peer_count_walker (struct thread *t)
else
{
if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE))
- plog_warn (peer->log,
- "%s [pcount] %s/%d not counted but flags 0x%x",
+ zlog_warn ("%s [pcount] %s/%d not counted but flags 0x%x",
peer->host,
inet_ntop(rn->p.family, &rn->p.u.prefix,
buf, SU_ADDRSTRLEN),
@@ -12068,13 +12654,14 @@ bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi)
DEFUN (show_ip_bgp_neighbor_prefix_counts,
show_ip_bgp_neighbor_prefix_counts_cmd,
- "show ip bgp neighbors (A.B.C.D|X:X::X:X) prefix-counts",
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X|WORD) prefix-counts",
SHOW_STR
IP_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display detailed prefix count information\n")
{
struct peer *peer;
@@ -12088,13 +12675,14 @@ DEFUN (show_ip_bgp_neighbor_prefix_counts,
DEFUN (show_bgp_ipv6_neighbor_prefix_counts,
show_bgp_ipv6_neighbor_prefix_counts_cmd,
- "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) prefix-counts",
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) prefix-counts",
SHOW_STR
BGP_STR
"Address family\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display detailed prefix count information\n")
{
struct peer *peer;
@@ -12108,7 +12696,7 @@ DEFUN (show_bgp_ipv6_neighbor_prefix_counts,
DEFUN (show_ip_bgp_ipv4_neighbor_prefix_counts,
show_ip_bgp_ipv4_neighbor_prefix_counts_cmd,
- "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts",
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X|WORD) prefix-counts",
SHOW_STR
IP_STR
BGP_STR
@@ -12118,6 +12706,7 @@ DEFUN (show_ip_bgp_ipv4_neighbor_prefix_counts,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display detailed prefix count information\n")
{
struct peer *peer;
@@ -12134,7 +12723,7 @@ DEFUN (show_ip_bgp_ipv4_neighbor_prefix_counts,
DEFUN (show_ip_bgp_vpnv4_neighbor_prefix_counts,
show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd,
- "show ip bgp vpnv4 all neighbors (A.B.C.D|X:X::X:X) prefix-counts",
+ "show ip bgp vpnv4 all neighbors (A.B.C.D|X:X::X:X|WORD) prefix-counts",
SHOW_STR
IP_STR
BGP_STR
@@ -12144,6 +12733,7 @@ DEFUN (show_ip_bgp_vpnv4_neighbor_prefix_counts,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display detailed prefix count information\n")
{
struct peer *peer;
@@ -12157,7 +12747,7 @@ DEFUN (show_ip_bgp_vpnv4_neighbor_prefix_counts,
DEFUN (show_bgp_ipv4_safi_neighbor_prefix_counts,
show_bgp_ipv4_safi_neighbor_prefix_counts_cmd,
- "show bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts",
+ "show bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X|WORD) prefix-counts",
SHOW_STR
BGP_STR
"Address family\n"
@@ -12168,6 +12758,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_prefix_counts,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display detailed prefix count information\n")
{
struct peer *peer;
@@ -12187,7 +12778,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_prefix_counts,
DEFUN (show_bgp_ipv6_safi_neighbor_prefix_counts,
show_bgp_ipv6_safi_neighbor_prefix_counts_cmd,
- "show bgp ipv6 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts",
+ "show bgp ipv6 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X|WORD) prefix-counts",
SHOW_STR
BGP_STR
"Address family\n"
@@ -12198,6 +12789,7 @@ DEFUN (show_bgp_ipv6_safi_neighbor_prefix_counts,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display detailed prefix count information\n")
{
struct peer *peer;
@@ -12217,7 +12809,7 @@ DEFUN (show_bgp_ipv6_safi_neighbor_prefix_counts,
DEFUN (show_ip_bgp_encap_neighbor_prefix_counts,
show_ip_bgp_encap_neighbor_prefix_counts_cmd,
- "show ip bgp encap all neighbors (A.B.C.D|X:X::X:X) prefix-counts",
+ "show ip bgp encap all neighbors (A.B.C.D|X:X::X:X|WORD) prefix-counts",
SHOW_STR
IP_STR
BGP_STR
@@ -12227,6 +12819,7 @@ DEFUN (show_ip_bgp_encap_neighbor_prefix_counts,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display detailed prefix count information\n")
{
struct peer *peer;
@@ -12238,19 +12831,22 @@ DEFUN (show_ip_bgp_encap_neighbor_prefix_counts,
return bgp_peer_counts (vty, peer, AFI_IP, SAFI_ENCAP);
}
-
static void
show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
- int in)
+ int in, const char *rmap_name)
{
struct bgp_table *table;
struct bgp_adj_in *ain;
struct bgp_adj_out *adj;
unsigned long output_count;
+ unsigned long filtered_count;
struct bgp_node *rn;
int header1 = 1;
struct bgp *bgp;
int header2 = 1;
+ struct attr attr;
+ struct attr_extra extra;
+ int ret;
bgp = peer->bgp;
@@ -12259,8 +12855,8 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
table = bgp->rib[afi][safi];
- output_count = 0;
-
+ output_count = filtered_count = 0;
+
if (! in && CHECK_FLAG (peer->af_sflags[afi][safi],
PEER_STATUS_DEFAULT_ORIGINATE))
{
@@ -12273,6 +12869,7 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
header1 = 0;
}
+ attr.extra = &extra;
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
if (in)
{
@@ -12292,9 +12889,16 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
header2 = 0;
}
if (ain->attr)
- {
- route_vty_out_tmp (vty, &rn->p, ain->attr, safi);
- output_count++;
+ {
+ bgp_attr_dup(&attr, ain->attr);
+ if (bgp_input_modifier(peer, &rn->p, &attr, afi,
+ safi, rmap_name) != RMAP_DENY)
+ {
+ route_vty_out_tmp (vty, &rn->p, &attr, safi);
+ output_count++;
+ }
+ else
+ filtered_count++;
}
}
}
@@ -12316,9 +12920,26 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
header2 = 0;
}
if (adj->attr)
- {
- route_vty_out_tmp (vty, &rn->p, adj->attr, safi);
- output_count++;
+ {
+ if (!CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_REFLECTOR_CLIENT)
+ || bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY))
+ {
+
+ bgp_attr_dup(&attr, adj->attr);
+ ret = bgp_output_modifier(peer, &rn->p, &attr, afi,
+ safi, rmap_name);
+ }
+ else
+ ret = RMAP_PERMIT;
+
+ if (ret != RMAP_DENY)
+ {
+ route_vty_out_tmp (vty, &rn->p, &attr, safi);
+ output_count++;
+ }
+ else
+ filtered_count++;
}
}
}
@@ -12329,7 +12950,8 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
}
static int
-peer_adj_routes (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, int in)
+peer_adj_routes (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
+ int in, const char *rmap_name)
{
if (! peer || ! peer->afc[afi][safi])
{
@@ -12344,14 +12966,36 @@ peer_adj_routes (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, int
return CMD_WARNING;
}
- show_adj_route (vty, peer, afi, safi, in);
+ if (!in && (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)
+ && !bgp_flag_check(peer->bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)))
+ {
+ vty_out (vty, "%% Cannot apply outgoing route-map on route-reflector clients%s",
+ VTY_NEWLINE);
+ vty_out (vty, "%% Enable bgp route-reflector allow-outbound-policy flag%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ show_adj_route (vty, peer, afi, safi, in, rmap_name);
return CMD_SUCCESS;
}
+static int
+peer_adj_routes_decode (struct vty *vty, const char *view, const char *ip_str, afi_t afi, safi_t safi, int in, const char *rmap)
+{
+ struct peer *peer;
+
+ peer = peer_lookup_in_view (vty, view, ip_str);
+ if (!peer)
+ return CMD_WARNING;
+
+ return peer_adj_routes (vty, peer, afi, safi, in, rmap);
+}
+
DEFUN (show_ip_bgp_view_neighbor_advertised_route,
show_ip_bgp_view_neighbor_advertised_route_cmd,
- "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes",
SHOW_STR
IP_STR
BGP_STR
@@ -12362,33 +13006,63 @@ DEFUN (show_ip_bgp_view_neighbor_advertised_route,
"Neighbor to display information about\n"
"Display the routes advertised to a BGP neighbor\n")
{
- struct peer *peer;
-
- if (argc == 2)
- peer = peer_lookup_in_view (vty, argv[0], argv[1]);
- else
- peer = peer_lookup_in_view (vty, NULL, argv[0]);
+ return peer_adj_routes_decode (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, 0, NULL);
+}
- if (! peer)
- return CMD_WARNING;
-
- return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 0);
+DEFUN (show_ip_bgp_view_neighbor_advertised_route_rmap,
+ show_ip_bgp_view_neighbor_advertised_route_rmap_cmd,
+ "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes route-map WORD",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "BGP view\n"
+ "View name\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the routes advertised to a BGP neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ return peer_adj_routes_decode (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, 0, argv[2]);
}
-ALIAS (show_ip_bgp_view_neighbor_advertised_route,
+DEFUN (show_ip_bgp_neighbor_advertised_route,
show_ip_bgp_neighbor_advertised_route_cmd,
- "show ip bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes",
SHOW_STR
IP_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the routes advertised to a BGP neighbor\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, 0, NULL);
+}
-DEFUN (show_ip_bgp_ipv4_neighbor_advertised_route,
- show_ip_bgp_ipv4_neighbor_advertised_route_cmd,
- "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+DEFUN (show_ip_bgp_neighbor_advertised_route_rmap,
+ show_ip_bgp_neighbor_advertised_route_rmap_cmd,
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes route-map WORD",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the routes advertised to a BGP neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, 0, argv[1]);
+}
+
+DEFUN (show_ip_bgp_ipv4_safi_neighbor_advertised_route,
+ show_ip_bgp_ipv4_safi_neighbor_advertised_route_cmd,
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes",
SHOW_STR
IP_STR
BGP_STR
@@ -12398,23 +13072,45 @@ DEFUN (show_ip_bgp_ipv4_neighbor_advertised_route,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the routes advertised to a BGP neighbor\n")
{
- struct peer *peer;
+ safi_t safi = SAFI_UNICAST;
- peer = peer_lookup_in_view (vty, NULL, argv[1]);
- if (! peer)
- return CMD_WARNING;
+ if (strncmp (argv[0], "m", 1) == 0)
+ safi = SAFI_MULTICAST;
+
+ return peer_adj_routes_decode (vty, NULL, argv[1], AFI_IP, safi, 0, NULL);
+}
+
+DEFUN (show_ip_bgp_ipv4_safi_neighbor_advertised_route_rmap,
+ show_ip_bgp_ipv4_safi_neighbor_advertised_route_rmap_cmd,
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes route-map WORD",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Address family\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"
+ "Neighbor on bgp configured interface\n"
+ "Display the routes advertised to a BGP neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ safi_t safi = SAFI_UNICAST;
if (strncmp (argv[0], "m", 1) == 0)
- return peer_adj_routes (vty, peer, AFI_IP, SAFI_MULTICAST, 0);
+ safi = SAFI_MULTICAST;
- return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 0);
+ return peer_adj_routes_decode (vty, NULL, argv[1], AFI_IP, safi, 0, argv[2]);
}
DEFUN (show_bgp_view_neighbor_advertised_route,
show_bgp_view_neighbor_advertised_route_cmd,
- "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "show bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -12422,24 +13118,15 @@ DEFUN (show_bgp_view_neighbor_advertised_route,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the routes advertised to a BGP neighbor\n")
{
- struct peer *peer;
-
- if (argc == 2)
- peer = peer_lookup_in_view (vty, argv[0], argv[1]);
- else
- peer = peer_lookup_in_view (vty, NULL, argv[0]);
-
- if (! peer)
- return CMD_WARNING;
-
- return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 0);
+ return peer_adj_routes_decode (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, 0, NULL);
}
-DEFUN (show_bgp_view_neighbor_received_routes,
- show_bgp_view_neighbor_received_routes_cmd,
- "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes",
+DEFUN (show_bgp_view_neighbor_advertised_route_rmap,
+ show_bgp_view_neighbor_advertised_route_rmap_cmd,
+ "show bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -12447,78 +13134,174 @@ DEFUN (show_bgp_view_neighbor_received_routes,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
- "Display the received routes from neighbor\n")
+ "Neighbor on bgp configured interface\n"
+ "Display the routes advertised to a BGP neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
{
- struct peer *peer;
-
- if (argc == 2)
- peer = peer_lookup_in_view (vty, argv[0], argv[1]);
- else
- peer = peer_lookup_in_view (vty, NULL, argv[0]);
-
- if (! peer)
- return CMD_WARNING;
-
- return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 1);
+ return peer_adj_routes_decode (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, 0, argv[2]);
}
-ALIAS (show_bgp_view_neighbor_advertised_route,
+DEFUN (show_bgp_neighbor_advertised_route,
show_bgp_neighbor_advertised_route_cmd,
- "show bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "show bgp neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes",
SHOW_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the routes advertised to a BGP neighbor\n")
-
-ALIAS (show_bgp_view_neighbor_advertised_route,
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, 0, NULL);
+}
+
+DEFUN (show_bgp_neighbor_advertised_route_rmap,
+ show_bgp_neighbor_advertised_route_rmap_cmd,
+ "show bgp neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes route-map WORD",
+ SHOW_STR
+ BGP_STR
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the routes advertised to a BGP neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, 0, argv[1]);
+}
+
+DEFUN (show_bgp_ipv6_neighbor_advertised_route,
show_bgp_ipv6_neighbor_advertised_route_cmd,
- "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes",
SHOW_STR
BGP_STR
"Address family\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the routes advertised to a BGP neighbor\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, 0, NULL);
+}
-/* old command */
-ALIAS (show_bgp_view_neighbor_advertised_route,
- ipv6_bgp_neighbor_advertised_route_cmd,
- "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+/*old command */
+ALIAS (show_bgp_ipv6_neighbor_advertised_route,
+ show_ipv6_bgp_neighbor_advertised_route_cmd,
+ "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes",
SHOW_STR
IPV6_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the routes advertised to a BGP neighbor\n")
+
+DEFUN (show_bgp_ipv6_neighbor_advertised_route_rmap,
+ show_bgp_ipv6_neighbor_advertised_route_rmap_cmd,
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes route-map WORD",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the routes advertised to a BGP neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, 0, argv[1]);
+}
+
+/* old command */
+ALIAS (show_bgp_ipv6_neighbor_advertised_route_rmap,
+ show_ipv6_bgp_neighbor_advertised_route_rmap_cmd,
+ "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes route-map WORD",
+ SHOW_STR
+ IPV6_STR
+ BGP_STR
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the routes advertised to a BGP neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
/* old command */
DEFUN (ipv6_mbgp_neighbor_advertised_route,
ipv6_mbgp_neighbor_advertised_route_cmd,
- "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes",
SHOW_STR
IPV6_STR
MBGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the routes advertised to a BGP neighbor\n")
{
- struct peer *peer;
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, 0, NULL);
+}
- peer = peer_lookup_in_view (vty, NULL, argv[0]);
- if (! peer)
- return CMD_WARNING;
+DEFUN (ipv6_mbgp_neighbor_advertised_route_rmap,
+ ipv6_mbgp_neighbor_advertised_route_rmap_cmd,
+ "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes route-map WORD",
+ SHOW_STR
+ IPV6_STR
+ MBGP_STR
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the routes advertised to a BGP neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, 0, argv[1]);
+}
- return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 0);
+DEFUN (show_bgp_view_neighbor_received_routes,
+ show_bgp_view_neighbor_received_routes_cmd,
+ "show bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD) received-routes",
+ SHOW_STR
+ BGP_STR
+ "BGP view\n"
+ "View name\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n")
+{
+ return peer_adj_routes_decode (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, 1, NULL);
+}
+
+DEFUN (show_bgp_view_neighbor_received_routes_rmap,
+ show_bgp_view_neighbor_received_routes_rmap_cmd,
+ "show bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD) received-routes route-map WORD",
+ SHOW_STR
+ BGP_STR
+ "BGP view\n"
+ "View name\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ return peer_adj_routes_decode (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, 1, argv[2]);
}
DEFUN (show_ip_bgp_view_neighbor_received_routes,
show_ip_bgp_view_neighbor_received_routes_cmd,
- "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes",
+ "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD) received-routes",
SHOW_STR
IP_STR
BGP_STR
@@ -12527,51 +13310,189 @@ DEFUN (show_ip_bgp_view_neighbor_received_routes,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the received routes from neighbor\n")
{
- struct peer *peer;
+ return peer_adj_routes_decode (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, 1, NULL);
+}
- if (argc == 2)
- peer = peer_lookup_in_view (vty, argv[0], argv[1]);
- else
- peer = peer_lookup_in_view (vty, NULL, argv[0]);
+DEFUN (show_ip_bgp_view_neighbor_received_routes_rmap,
+ show_ip_bgp_view_neighbor_received_routes_rmap_cmd,
+ "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD) received-routes route-map WORD",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "BGP view\n"
+ "View name\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ return peer_adj_routes_decode (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, 1, argv[2]);
+}
- if (! peer)
- return CMD_WARNING;
+DEFUN (show_bgp_view_ipv6_neighbor_received_routes,
+ show_bgp_view_ipv6_neighbor_received_routes_cmd,
+ "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) received-routes",
+ SHOW_STR
+ BGP_STR
+ "BGP view\n"
+ "View name\n"
+ "Address family\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n")
+{
+ return peer_adj_routes_decode (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, 1, NULL);
+}
- return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 1);
+DEFUN (show_bgp_view_ipv6_neighbor_received_routes_rmap,
+ show_bgp_view_ipv6_neighbor_received_routes_rmap_cmd,
+ "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) received-routes route-map WORD",
+ SHOW_STR
+ BGP_STR
+ "BGP view\n"
+ "View name\n"
+ "Address family\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ return peer_adj_routes_decode (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, 1, argv[2]);
}
-ALIAS (show_ip_bgp_view_neighbor_received_routes,
+DEFUN (show_ip_bgp_neighbor_received_routes,
show_ip_bgp_neighbor_received_routes_cmd,
- "show ip bgp neighbors (A.B.C.D|X:X::X:X) received-routes",
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X|WORD) received-routes",
SHOW_STR
IP_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the received routes from neighbor\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, 1, NULL);
+}
+
+DEFUN (show_ip_bgp_neighbor_received_routes_rmap,
+ show_ip_bgp_neighbor_received_routes_rmap_cmd,
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X|WORD) received-routes route-map WORD",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, 1, argv[1]);
+}
-ALIAS (show_bgp_view_neighbor_received_routes,
+DEFUN (show_bgp_ipv6_neighbor_received_routes,
show_bgp_ipv6_neighbor_received_routes_cmd,
- "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes",
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) received-routes",
SHOW_STR
BGP_STR
"Address family\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the received routes from neighbor\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, 1, NULL);
+}
+
+DEFUN (show_bgp_ipv6_neighbor_received_routes_rmap,
+ show_bgp_ipv6_neighbor_received_routes_rmap_cmd,
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) received-routes route-map WORD",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, 1, argv[1]);
+}
+
+/* old command */
+DEFUN (show_ipv6_bgp_neighbor_received_routes,
+ show_ipv6_bgp_neighbor_received_routes_cmd,
+ "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X|WORD) received-routes",
+ SHOW_STR
+ IPV6_STR
+ BGP_STR
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, 1, NULL);
+}
+
+/* old command */
+DEFUN (ipv6_mbgp_neighbor_received_routes,
+ ipv6_mbgp_neighbor_received_routes_cmd,
+ "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X|WORD) received-routes",
+ SHOW_STR
+ IPV6_STR
+ MBGP_STR
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, 1, NULL);
+}
+
+DEFUN (ipv6_mbgp_neighbor_received_routes_rmap,
+ ipv6_mbgp_neighbor_received_routes_rmap_cmd,
+ "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X|WORD) received-routes route-map WORD",
+ SHOW_STR
+ IPV6_STR
+ MBGP_STR
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, 1, argv[1]);
+}
DEFUN (show_bgp_neighbor_received_prefix_filter,
show_bgp_neighbor_received_prefix_filter_cmd,
- "show bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+ "show bgp neighbors (A.B.C.D|X:X::X:X|WORD) received prefix-filter",
SHOW_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display information received from a BGP neighbor\n"
"Display the prefixlist filter\n")
{
@@ -12602,42 +13523,11 @@ DEFUN (show_bgp_neighbor_received_prefix_filter,
return CMD_SUCCESS;
}
-/* old command */
-ALIAS (show_bgp_view_neighbor_received_routes,
- ipv6_bgp_neighbor_received_routes_cmd,
- "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) received-routes",
- SHOW_STR
- IPV6_STR
- BGP_STR
- "Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
- "Neighbor to display information about\n"
- "Display the received routes from neighbor\n")
-/* old command */
-DEFUN (ipv6_mbgp_neighbor_received_routes,
- ipv6_mbgp_neighbor_received_routes_cmd,
- "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) received-routes",
- SHOW_STR
- IPV6_STR
- MBGP_STR
- "Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
- "Neighbor to display information about\n"
- "Display the received routes from neighbor\n")
-{
- struct peer *peer;
-
- peer = peer_lookup_in_view (vty, NULL, argv[0]);
- if (! peer)
- return CMD_WARNING;
-
- return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 1);
-}
DEFUN (show_bgp_view_neighbor_received_prefix_filter,
show_bgp_view_neighbor_received_prefix_filter_cmd,
- "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+ "show bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD) received prefix-filter",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -12684,10 +13574,9 @@ DEFUN (show_bgp_view_neighbor_received_prefix_filter,
return CMD_SUCCESS;
}
-
-DEFUN (show_ip_bgp_ipv4_neighbor_received_routes,
- show_ip_bgp_ipv4_neighbor_received_routes_cmd,
- "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received-routes",
+DEFUN (show_ip_bgp_ipv4_safi_neighbor_received_routes,
+ show_ip_bgp_ipv4_safi_neighbor_received_routes_cmd,
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X|WORD) received-routes",
SHOW_STR
IP_STR
BGP_STR
@@ -12697,23 +13586,49 @@ DEFUN (show_ip_bgp_ipv4_neighbor_received_routes,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the received routes from neighbor\n")
{
- struct peer *peer;
+ safi_t safi;
- peer = peer_lookup_in_view (vty, NULL, argv[1]);
- if (! peer)
+ if (bgp_parse_safi(argv[0], &safi)) {
+ vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
-
- if (strncmp (argv[0], "m", 1) == 0)
- return peer_adj_routes (vty, peer, AFI_IP, SAFI_MULTICAST, 1);
+ }
+
+ return peer_adj_routes_decode (vty, NULL, argv[1], AFI_IP, safi, 1, NULL);
+}
+
+DEFUN (show_ip_bgp_ipv4_safi_neighbor_received_routes_rmap,
+ show_ip_bgp_ipv4_safi_neighbor_received_routes_rmap_cmd,
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X|WORD) received-routes route-map WORD",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Address family\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"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n"
+ "Display routes matching the route-map\n"
+ "A route-map to match on\n")
+{
+ safi_t safi;
- return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 1);
+ if (bgp_parse_safi(argv[0], &safi)) {
+ vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return peer_adj_routes_decode (vty, NULL, argv[1], AFI_IP, safi, 1, argv[1]);
}
DEFUN (show_bgp_ipv4_safi_neighbor_advertised_route,
show_bgp_ipv4_safi_neighbor_advertised_route_cmd,
- "show bgp ipv4 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "show bgp ipv4 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes",
SHOW_STR
BGP_STR
"Address Family modifier\n"
@@ -12721,9 +13636,9 @@ DEFUN (show_bgp_ipv4_safi_neighbor_advertised_route,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the routes advertised to a BGP neighbor\n")
{
- struct peer *peer;
safi_t safi;
if (bgp_parse_safi(argv[0], &safi)) {
@@ -12731,16 +13646,37 @@ DEFUN (show_bgp_ipv4_safi_neighbor_advertised_route,
return CMD_WARNING;
}
- peer = peer_lookup_in_view (vty, NULL, argv[1]);
- if (! peer)
+ return peer_adj_routes_decode (vty, NULL, argv[1], AFI_IP, safi, 0, NULL);
+}
+
+DEFUN (show_bgp_ipv4_safi_neighbor_advertised_route_rmap,
+ show_bgp_ipv4_safi_neighbor_advertised_route_rmap_cmd,
+ "show bgp ipv4 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes route-map WORD",
+ SHOW_STR
+ BGP_STR
+ "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"
+ "Neighbor on bgp configured interface\n"
+ "Display the routes advertised to a BGP neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ safi_t safi;
+
+ if (bgp_parse_safi(argv[0], &safi)) {
+ vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
+ }
- return peer_adj_routes (vty, peer, AFI_IP, safi, 0);
+ return peer_adj_routes_decode (vty, NULL, argv[1], AFI_IP, safi, 0, argv[2]);
}
DEFUN (show_bgp_ipv6_safi_neighbor_advertised_route,
show_bgp_ipv6_safi_neighbor_advertised_route_cmd,
- "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes",
SHOW_STR
BGP_STR
"Address Family modifier\n"
@@ -12749,9 +13685,9 @@ DEFUN (show_bgp_ipv6_safi_neighbor_advertised_route,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the routes advertised to a BGP neighbor\n")
{
- struct peer *peer;
safi_t safi;
if (bgp_parse_safi(argv[0], &safi)) {
@@ -12759,16 +13695,38 @@ DEFUN (show_bgp_ipv6_safi_neighbor_advertised_route,
return CMD_WARNING;
}
- peer = peer_lookup_in_view (vty, NULL, argv[1]);
- if (! peer)
+ return peer_adj_routes_decode (vty, NULL, argv[1], AFI_IP6, safi, 0, NULL);
+}
+
+DEFUN (show_bgp_ipv6_safi_neighbor_advertised_route_rmap,
+ show_bgp_ipv6_safi_neighbor_advertised_route_rmap_cmd,
+ "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes route-map WORD",
+ SHOW_STR
+ BGP_STR
+ "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"
+ "Neighbor on bgp configured interface\n"
+ "Display the routes advertised to a BGP neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ safi_t safi;
+
+ if (bgp_parse_safi(argv[0], &safi)) {
+ vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
+ }
- return peer_adj_routes (vty, peer, AFI_IP6, safi, 0);
+ return peer_adj_routes_decode (vty, NULL, argv[1], AFI_IP6, safi, 0, argv[2]);
}
DEFUN (show_bgp_view_ipv6_neighbor_advertised_route,
show_bgp_view_ipv6_neighbor_advertised_route_cmd,
- "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes",
+ "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -12777,24 +13735,15 @@ DEFUN (show_bgp_view_ipv6_neighbor_advertised_route,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the routes advertised to a BGP neighbor\n")
{
- struct peer *peer;
-
- if (argc == 2)
- peer = peer_lookup_in_view (vty, argv[0], argv[1]);
- else
- peer = peer_lookup_in_view (vty, NULL, argv[0]);
-
- if (! peer)
- return CMD_WARNING;
-
- return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 0);
+ return peer_adj_routes_decode (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, 0, NULL);
}
-DEFUN (show_bgp_view_ipv6_neighbor_received_routes,
- show_bgp_view_ipv6_neighbor_received_routes_cmd,
- "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes",
+DEFUN (show_bgp_view_ipv6_neighbor_advertised_route_rmap,
+ show_bgp_view_ipv6_neighbor_advertised_route_rmap_cmd,
+ "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) advertised-routes route-map WORD",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -12803,24 +13752,17 @@ DEFUN (show_bgp_view_ipv6_neighbor_received_routes,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
- "Display the received routes from neighbor\n")
+ "Neighbor on bgp configured interface\n"
+ "Display the routes advertised to a BGP neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
{
- struct peer *peer;
-
- if (argc == 2)
- peer = peer_lookup_in_view (vty, argv[0], argv[1]);
- else
- peer = peer_lookup_in_view (vty, NULL, argv[0]);
-
- if (! peer)
- return CMD_WARNING;
-
- return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 1);
+ return peer_adj_routes_decode (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, 0, argv[2]);
}
DEFUN (show_bgp_ipv4_safi_neighbor_received_routes,
show_bgp_ipv4_safi_neighbor_received_routes_cmd,
- "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received-routes",
+ "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X|WORD) received-routes",
SHOW_STR
BGP_STR
"Address family\n"
@@ -12831,9 +13773,9 @@ DEFUN (show_bgp_ipv4_safi_neighbor_received_routes,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the received routes from neighbor\n")
{
- struct peer *peer;
safi_t safi;
if (bgp_parse_safi(argv[0], &safi)) {
@@ -12841,16 +13783,40 @@ DEFUN (show_bgp_ipv4_safi_neighbor_received_routes,
return CMD_WARNING;
}
- peer = peer_lookup_in_view (vty, NULL, argv[1]);
- if (! peer)
+ return peer_adj_routes_decode (vty, NULL, argv[1], AFI_IP, safi, 1, NULL);
+}
+
+DEFUN (show_bgp_ipv4_safi_neighbor_received_routes_rmap,
+ show_bgp_ipv4_safi_neighbor_received_routes_rmap_cmd,
+ "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X|WORD) received-routes route-map WORD",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "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"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ safi_t safi;
+
+ if (bgp_parse_safi(argv[0], &safi)) {
+ vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
-
- return peer_adj_routes (vty, peer, AFI_IP, safi, 1);
+ }
+
+ return peer_adj_routes_decode (vty, NULL, argv[1], AFI_IP, safi, 1, argv[2]);
}
DEFUN (show_bgp_ipv6_safi_neighbor_received_routes,
show_bgp_ipv6_safi_neighbor_received_routes_cmd,
- "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received-routes",
+ "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X|WORD) received-routes",
SHOW_STR
BGP_STR
"Address family\n"
@@ -12861,9 +13827,9 @@ DEFUN (show_bgp_ipv6_safi_neighbor_received_routes,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the received routes from neighbor\n")
{
- struct peer *peer;
safi_t safi;
if (bgp_parse_safi(argv[0], &safi)) {
@@ -12871,16 +13837,40 @@ DEFUN (show_bgp_ipv6_safi_neighbor_received_routes,
return CMD_WARNING;
}
- peer = peer_lookup_in_view (vty, NULL, argv[1]);
- if (! peer)
+ return peer_adj_routes_decode (vty, NULL, argv[1], AFI_IP6, safi, 1, NULL);
+}
+
+DEFUN (show_bgp_ipv6_safi_neighbor_received_routes_rmap,
+ show_bgp_ipv6_safi_neighbor_received_routes_rmap_cmd,
+ "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X|WORD) received-routes route-map WORD",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "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"
+ "Neighbor on bgp configured interface\n"
+ "Display the received routes from neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ safi_t safi;
+
+ if (bgp_parse_safi(argv[0], &safi)) {
+ vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
-
- return peer_adj_routes (vty, peer, AFI_IP6, safi, 1);
+ }
+
+ return peer_adj_routes_decode (vty, NULL, argv[1], AFI_IP6, safi, 1, argv[2]);
}
DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes,
show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd,
- "show bgp view WORD (ipv4|ipv6) (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)",
+ "show bgp view WORD (ipv4|ipv6) (unicast|multicast) neighbors (A.B.C.D|X:X::X:X|WORD) (advertised-routes|received-routes)",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -12892,35 +13882,63 @@ DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the advertised routes to neighbor\n"
"Display the received routes from neighbor\n")
{
int afi;
int safi;
int in;
- struct peer *peer;
- peer = peer_lookup_in_view (vty, argv[0], argv[3]);
+ afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
+ safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+ in = (strncmp (argv[4], "r", 1) == 0) ? 1 : 0;
+
+ return peer_adj_routes_decode (vty, argv[0], argv[3], afi, safi, in, NULL);
+}
- if (! peer)
- return CMD_WARNING;
+DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes_rmap,
+ show_bgp_view_afi_safi_neighbor_adv_recd_routes_rmap_cmd,
+ "show bgp view WORD (ipv4|ipv6) (unicast|multicast) neighbors (A.B.C.D|X:X::X:X|WORD) (advertised-routes|received-routes) route-map WORD",
+ SHOW_STR
+ BGP_STR
+ "BGP view\n"
+ "View name\n"
+ "Address family\n"
+ "Address family\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"
+ "Neighbor on bgp configured interface\n"
+ "Display the advertised routes to neighbor\n"
+ "Display the received routes from neighbor\n"
+ "Route-map to control what is displayed\n"
+ "Route-map name\n")
+{
+ int afi;
+ int safi;
+ int in;
afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
in = (strncmp (argv[4], "r", 1) == 0) ? 1 : 0;
- return peer_adj_routes (vty, peer, afi, safi, in);
+ return peer_adj_routes_decode (vty, argv[0], argv[3], afi, safi, in, argv[5]);
}
+
DEFUN (show_ip_bgp_neighbor_received_prefix_filter,
show_ip_bgp_neighbor_received_prefix_filter_cmd,
- "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X|WORD) received prefix-filter",
SHOW_STR
IP_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display information received from a BGP neighbor\n"
"Display the prefixlist filter\n")
{
@@ -12932,13 +13950,19 @@ DEFUN (show_ip_bgp_neighbor_received_prefix_filter,
ret = str2sockunion (argv[0], &su);
if (ret < 0)
{
- vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE);
- return CMD_WARNING;
+ peer = peer_lookup_by_conf_if (NULL, argv[0]);
+ if (!peer)
+ {
+ vty_out (vty, "Malformed address or name: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ else
+ {
+ peer = peer_lookup (NULL, &su);
+ if (! peer)
+ return CMD_WARNING;
}
-
- peer = peer_lookup (NULL, &su);
- if (! peer)
- return CMD_WARNING;
sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST);
count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name);
@@ -12953,7 +13977,7 @@ DEFUN (show_ip_bgp_neighbor_received_prefix_filter,
DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter,
show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd,
- "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X|WORD) received prefix-filter",
SHOW_STR
IP_STR
BGP_STR
@@ -12963,6 +13987,7 @@ DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display information received from a BGP neighbor\n"
"Display the prefixlist filter\n")
{
@@ -12974,13 +13999,19 @@ DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter,
ret = str2sockunion (argv[1], &su);
if (ret < 0)
{
- vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE);
- return CMD_WARNING;
+ peer = peer_lookup_by_conf_if (NULL, argv[1]);
+ if (!peer)
+ {
+ vty_out (vty, "Malformed address or name: %s%s", argv[1], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ else
+ {
+ peer = peer_lookup (NULL, &su);
+ if (! peer)
+ return CMD_WARNING;
}
-
- peer = peer_lookup (NULL, &su);
- if (! peer)
- return CMD_WARNING;
if (strncmp (argv[0], "m", 1) == 0)
{
@@ -13006,19 +14037,23 @@ DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter,
return CMD_SUCCESS;
}
-ALIAS (show_bgp_view_neighbor_received_routes,
+DEFUN (show_bgp_neighbor_received_routes,
show_bgp_neighbor_received_routes_cmd,
- "show bgp neighbors (A.B.C.D|X:X::X:X) received-routes",
+ "show bgp neighbors (A.B.C.D|X:X::X:X|WORD) received-routes",
SHOW_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the received routes from neighbor\n")
+{
+ return peer_adj_routes_decode (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, 1, NULL);
+}
DEFUN (show_bgp_ipv4_safi_neighbor_received_prefix_filter,
show_bgp_ipv4_safi_neighbor_received_prefix_filter_cmd,
- "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+ "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X|WORD) received prefix-filter",
SHOW_STR
BGP_STR
IP_STR
@@ -13066,7 +14101,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_received_prefix_filter,
DEFUN (show_bgp_ipv6_safi_neighbor_received_prefix_filter,
show_bgp_ipv6_safi_neighbor_received_prefix_filter_cmd,
- "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+ "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X|WORD) received prefix-filter",
SHOW_STR
BGP_STR
IP_STR
@@ -13114,13 +14149,14 @@ DEFUN (show_bgp_ipv6_safi_neighbor_received_prefix_filter,
DEFUN (show_bgp_ipv6_neighbor_received_prefix_filter,
show_bgp_ipv6_neighbor_received_prefix_filter_cmd,
- "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) received prefix-filter",
SHOW_STR
BGP_STR
"Address family\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display information received from a BGP neighbor\n"
"Display the prefixlist filter\n")
{
@@ -13132,13 +14168,19 @@ DEFUN (show_bgp_ipv6_neighbor_received_prefix_filter,
ret = str2sockunion (argv[0], &su);
if (ret < 0)
{
- vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE);
- return CMD_WARNING;
+ peer = peer_lookup_by_conf_if (NULL, argv[0]);
+ if (!peer)
+ {
+ vty_out (vty, "Malformed address or name: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ else
+ {
+ peer = peer_lookup (NULL, &su);
+ if (! peer)
+ return CMD_WARNING;
}
-
- peer = peer_lookup (NULL, &su);
- if (! peer)
- return CMD_WARNING;
sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST);
count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name);
@@ -13153,7 +14195,7 @@ DEFUN (show_bgp_ipv6_neighbor_received_prefix_filter,
DEFUN (show_bgp_view_ipv6_neighbor_received_prefix_filter,
show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd,
- "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
+ "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) received prefix-filter",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -13162,6 +14204,7 @@ DEFUN (show_bgp_view_ipv6_neighbor_received_prefix_filter,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display information received from a BGP neighbor\n"
"Display the prefixlist filter\n")
{
@@ -13182,13 +14225,19 @@ DEFUN (show_bgp_view_ipv6_neighbor_received_prefix_filter,
ret = str2sockunion (argv[1], &su);
if (ret < 0)
{
- vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE);
- return CMD_WARNING;
+ peer = peer_lookup_by_conf_if (bgp, argv[1]);
+ if (!peer)
+ {
+ vty_out (vty, "%% Malformed address or name: %s%s", argv[1], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ else
+ {
+ peer = peer_lookup (bgp, &su);
+ if (! peer)
+ return CMD_WARNING;
}
-
- peer = peer_lookup (bgp, &su);
- if (! peer)
- return CMD_WARNING;
sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST);
count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name);
@@ -13215,13 +14264,14 @@ bgp_show_neighbor_route (struct vty *vty, struct peer *peer, afi_t afi,
}
DEFUN (show_ip_bgp_neighbor_routes,
show_ip_bgp_neighbor_routes_cmd,
- "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes",
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X|WORD) routes",
SHOW_STR
IP_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display routes learned from neighbor\n")
{
struct peer *peer;
@@ -13234,15 +14284,17 @@ DEFUN (show_ip_bgp_neighbor_routes,
bgp_show_type_neighbor);
}
+
DEFUN (show_ip_bgp_neighbor_flap,
show_ip_bgp_neighbor_flap_cmd,
- "show ip bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics",
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X|WORD) flap-statistics",
SHOW_STR
IP_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display flap statistics of the routes learned from neighbor\n")
{
struct peer *peer;
@@ -13257,13 +14309,14 @@ DEFUN (show_ip_bgp_neighbor_flap,
DEFUN (show_ip_bgp_neighbor_damp,
show_ip_bgp_neighbor_damp_cmd,
- "show ip bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes",
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X|WORD) dampened-routes",
SHOW_STR
IP_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the dampened routes received from neighbor\n")
{
struct peer *peer;
@@ -13278,7 +14331,7 @@ DEFUN (show_ip_bgp_neighbor_damp,
DEFUN (show_ip_bgp_ipv4_neighbor_routes,
show_ip_bgp_ipv4_neighbor_routes_cmd,
- "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes",
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X|WORD) routes",
SHOW_STR
IP_STR
BGP_STR
@@ -13288,6 +14341,7 @@ DEFUN (show_ip_bgp_ipv4_neighbor_routes,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display routes learned from neighbor\n")
{
struct peer *peer;
@@ -13306,14 +14360,14 @@ DEFUN (show_ip_bgp_ipv4_neighbor_routes,
DEFUN (show_ip_bgp_view_rsclient,
show_ip_bgp_view_rsclient_cmd,
- "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X)",
+ "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
IP_STR
BGP_STR
"BGP view\n"
"View name\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR)
+ NEIGHBOR_ADDR_STR3)
{
struct bgp_table *table;
struct peer *peer;
@@ -13348,16 +14402,16 @@ DEFUN (show_ip_bgp_view_rsclient,
ALIAS (show_ip_bgp_view_rsclient,
show_ip_bgp_rsclient_cmd,
- "show ip bgp rsclient (A.B.C.D|X:X::X:X)",
+ "show ip bgp rsclient (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
IP_STR
BGP_STR
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR)
+ NEIGHBOR_ADDR_STR3)
DEFUN (show_bgp_view_ipv4_safi_rsclient,
show_bgp_view_ipv4_safi_rsclient_cmd,
- "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)",
+ "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -13366,7 +14420,7 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient,
"Address Family modifier\n"
"Address Family modifier\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR)
+ NEIGHBOR_ADDR_STR3)
{
struct bgp_table *table;
struct peer *peer;
@@ -13405,25 +14459,25 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient,
ALIAS (show_bgp_view_ipv4_safi_rsclient,
show_bgp_ipv4_safi_rsclient_cmd,
- "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)",
+ "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR)
+ NEIGHBOR_ADDR_STR3)
DEFUN (show_ip_bgp_view_rsclient_route,
show_ip_bgp_view_rsclient_route_cmd,
- "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D",
+ "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X|WORD) A.B.C.D",
SHOW_STR
IP_STR
BGP_STR
"BGP view\n"
"View name\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"Network in the BGP routing table to display\n")
{
struct bgp *bgp;
@@ -13474,22 +14528,22 @@ DEFUN (show_ip_bgp_view_rsclient_route,
return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST],
(argc == 3) ? argv[2] : argv[1],
- AFI_IP, SAFI_UNICAST, NULL, 0);
+ AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
}
ALIAS (show_ip_bgp_view_rsclient_route,
show_ip_bgp_rsclient_route_cmd,
- "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D",
+ "show ip bgp rsclient (A.B.C.D|X:X::X:X|WORD) A.B.C.D",
SHOW_STR
IP_STR
BGP_STR
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"Network in the BGP routing table to display\n")
DEFUN (show_bgp_ipv4_safi_neighbor_flap,
show_bgp_ipv4_safi_neighbor_flap_cmd,
- "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) flap-statistics",
+ "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X|WORD) flap-statistics",
SHOW_STR
BGP_STR
"Address Family Modifier\n"
@@ -13519,7 +14573,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_flap,
DEFUN (show_bgp_ipv6_safi_neighbor_flap,
show_bgp_ipv6_safi_neighbor_flap_cmd,
- "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) flap-statistics",
+ "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X|WORD) flap-statistics",
SHOW_STR
BGP_STR
"Address Family Modifier\n"
@@ -13549,7 +14603,7 @@ DEFUN (show_bgp_ipv6_safi_neighbor_flap,
DEFUN (show_bgp_ipv4_safi_neighbor_damp,
show_bgp_ipv4_safi_neighbor_damp_cmd,
- "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) dampened-routes",
+ "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X|WORD) dampened-routes",
SHOW_STR
BGP_STR
"Address Family Modifier\n"
@@ -13579,7 +14633,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_damp,
DEFUN (show_bgp_ipv6_safi_neighbor_damp,
show_bgp_ipv6_safi_neighbor_damp_cmd,
- "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) dampened-routes",
+ "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X|WORD) dampened-routes",
SHOW_STR
BGP_STR
"Address Family Modifier\n"
@@ -13609,7 +14663,7 @@ DEFUN (show_bgp_ipv6_safi_neighbor_damp,
DEFUN (show_bgp_ipv4_safi_neighbor_routes,
show_bgp_ipv4_safi_neighbor_routes_cmd,
- "show bgp ipv4 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) routes",
+ "show bgp ipv4 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X|WORD) routes",
SHOW_STR
BGP_STR
"Address family\n"
@@ -13638,7 +14692,7 @@ DEFUN (show_bgp_ipv4_safi_neighbor_routes,
DEFUN (show_bgp_ipv6_safi_neighbor_routes,
show_bgp_ipv6_safi_neighbor_routes_cmd,
- "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) routes",
+ "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X|WORD) routes",
SHOW_STR
BGP_STR
"Address family\n"
@@ -13667,7 +14721,7 @@ DEFUN (show_bgp_ipv6_safi_neighbor_routes,
DEFUN (show_bgp_view_ipv4_safi_rsclient_route,
show_bgp_view_ipv4_safi_rsclient_route_cmd,
- "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D",
+ "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X|WORD) A.B.C.D",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -13676,7 +14730,7 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient_route,
"Address Family modifier\n"
"Address Family modifier\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"Network in the BGP routing table to display\n")
{
struct bgp *bgp;
@@ -13731,25 +14785,25 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient_route,
return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi],
(argc == 4) ? argv[3] : argv[2],
- AFI_IP, safi, NULL, 0);
+ AFI_IP, safi, NULL, 0, BGP_PATH_ALL);
}
ALIAS (show_bgp_view_ipv4_safi_rsclient_route,
show_bgp_ipv4_safi_rsclient_route_cmd,
- "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D",
+ "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X|WORD) A.B.C.D",
SHOW_STR
BGP_STR
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"Network in the BGP routing table to display\n")
DEFUN (show_bgp_view_ipv4_safi_rsclient_prefix,
show_bgp_view_ipv4_safi_rsclient_prefix_cmd,
- "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M",
+ "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X|WORD) A.B.C.D/M",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -13813,19 +14867,19 @@ DEFUN (show_bgp_view_ipv4_safi_rsclient_prefix,
return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi],
(argc == 4) ? argv[3] : argv[2],
- AFI_IP, safi, NULL, 1);
+ AFI_IP, safi, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_ip_bgp_view_rsclient_prefix,
show_ip_bgp_view_rsclient_prefix_cmd,
- "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M",
+ "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X|WORD) A.B.C.D/M",
SHOW_STR
IP_STR
BGP_STR
"BGP view\n"
"View name\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
struct bgp *bgp;
@@ -13876,34 +14930,34 @@ DEFUN (show_ip_bgp_view_rsclient_prefix,
return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST],
(argc == 3) ? argv[2] : argv[1],
- AFI_IP, SAFI_UNICAST, NULL, 1);
+ AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
}
ALIAS (show_ip_bgp_view_rsclient_prefix,
show_ip_bgp_rsclient_prefix_cmd,
- "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M",
+ "show ip bgp rsclient (A.B.C.D|X:X::X:X|WORD) A.B.C.D/M",
SHOW_STR
IP_STR
BGP_STR
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
ALIAS (show_bgp_view_ipv4_safi_rsclient_prefix,
show_bgp_ipv4_safi_rsclient_prefix_cmd,
- "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M",
+ "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X|WORD) A.B.C.D/M",
SHOW_STR
BGP_STR
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
DEFUN (show_bgp_view_ipv6_neighbor_routes,
show_bgp_view_ipv6_neighbor_routes_cmd,
- "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) routes",
+ "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) routes",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -13912,6 +14966,7 @@ DEFUN (show_bgp_view_ipv6_neighbor_routes,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display routes learned from neighbor\n")
{
struct peer *peer;
@@ -13930,7 +14985,7 @@ DEFUN (show_bgp_view_ipv6_neighbor_routes,
DEFUN (show_bgp_view_neighbor_damp,
show_bgp_view_neighbor_damp_cmd,
- "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) dampened-routes",
+ "show bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD) dampened-routes",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -13938,6 +14993,7 @@ DEFUN (show_bgp_view_neighbor_damp,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the dampened routes received from neighbor\n")
{
struct peer *peer;
@@ -13956,7 +15012,7 @@ DEFUN (show_bgp_view_neighbor_damp,
DEFUN (show_bgp_view_ipv6_neighbor_damp,
show_bgp_view_ipv6_neighbor_damp_cmd,
- "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes",
+ "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) dampened-routes",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -13965,6 +15021,7 @@ DEFUN (show_bgp_view_ipv6_neighbor_damp,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the dampened routes received from neighbor\n")
{
struct peer *peer;
@@ -13983,7 +15040,7 @@ DEFUN (show_bgp_view_ipv6_neighbor_damp,
DEFUN (show_bgp_view_ipv6_neighbor_flap,
show_bgp_view_ipv6_neighbor_flap_cmd,
- "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics",
+ "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) flap-statistics",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -13992,6 +15049,7 @@ DEFUN (show_bgp_view_ipv6_neighbor_flap,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the dampened routes received from neighbor\n")
{
struct peer *peer;
@@ -14010,7 +15068,7 @@ DEFUN (show_bgp_view_ipv6_neighbor_flap,
DEFUN (show_bgp_view_neighbor_flap,
show_bgp_view_neighbor_flap_cmd,
- "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) flap-statistics",
+ "show bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD) flap-statistics",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -14018,6 +15076,7 @@ DEFUN (show_bgp_view_neighbor_flap,
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display flap statistics of the routes learned from neighbor\n")
{
struct peer *peer;
@@ -14036,7 +15095,7 @@ DEFUN (show_bgp_view_neighbor_flap,
ALIAS (show_bgp_view_neighbor_flap,
show_bgp_neighbor_flap_cmd,
- "show bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics",
+ "show bgp neighbors (A.B.C.D|X:X::X:X|WORD) flap-statistics",
SHOW_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
@@ -14046,7 +15105,7 @@ ALIAS (show_bgp_view_neighbor_flap,
ALIAS (show_bgp_view_neighbor_damp,
show_bgp_neighbor_damp_cmd,
- "show bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes",
+ "show bgp neighbors (A.B.C.D|X:X::X:X|WORD) dampened-routes",
SHOW_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
@@ -14056,7 +15115,7 @@ ALIAS (show_bgp_view_neighbor_damp,
DEFUN (show_bgp_view_neighbor_routes,
show_bgp_view_neighbor_routes_cmd,
- "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) routes",
+ "show bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD) routes",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -14082,47 +15141,51 @@ DEFUN (show_bgp_view_neighbor_routes,
ALIAS (show_bgp_view_neighbor_routes,
show_bgp_neighbor_routes_cmd,
- "show bgp neighbors (A.B.C.D|X:X::X:X) routes",
+ "show bgp neighbors (A.B.C.D|X:X::X:X|WORD) routes",
SHOW_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display routes learned from neighbor\n")
ALIAS (show_bgp_view_neighbor_routes,
show_bgp_ipv6_neighbor_routes_cmd,
- "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) routes",
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) routes",
SHOW_STR
BGP_STR
"Address family\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display routes learned from neighbor\n")
/* old command */
ALIAS (show_bgp_view_neighbor_routes,
ipv6_bgp_neighbor_routes_cmd,
- "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes",
+ "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X|WORD) routes",
SHOW_STR
IPV6_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display routes learned from neighbor\n")
/* old command */
DEFUN (ipv6_mbgp_neighbor_routes,
ipv6_mbgp_neighbor_routes_cmd,
- "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes",
+ "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X|WORD) routes",
SHOW_STR
IPV6_STR
MBGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display routes learned from neighbor\n")
{
struct peer *peer;
@@ -14137,29 +15200,31 @@ DEFUN (ipv6_mbgp_neighbor_routes,
ALIAS (show_bgp_view_neighbor_flap,
show_bgp_ipv6_neighbor_flap_cmd,
- "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics",
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) flap-statistics",
SHOW_STR
BGP_STR
"Address family\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display flap statistics of the routes learned from neighbor\n")
ALIAS (show_bgp_view_neighbor_damp,
show_bgp_ipv6_neighbor_damp_cmd,
- "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes",
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X|WORD) dampened-routes",
SHOW_STR
BGP_STR
"Address family\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n"
"Display the dampened routes received from neighbor\n")
DEFUN (show_bgp_view_rsclient,
show_bgp_view_rsclient_cmd,
- "show bgp view WORD rsclient (A.B.C.D|X:X::X:X)",
+ "show bgp view WORD rsclient (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -14200,7 +15265,7 @@ DEFUN (show_bgp_view_rsclient,
ALIAS (show_bgp_view_rsclient,
show_bgp_rsclient_cmd,
- "show bgp rsclient (A.B.C.D|X:X::X:X)",
+ "show bgp rsclient (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"Information about Route Server Client\n"
@@ -14208,7 +15273,7 @@ ALIAS (show_bgp_view_rsclient,
DEFUN (show_bgp_view_ipv4_rsclient,
show_bgp_view_ipv4_rsclient_cmd,
- "show bgp view WORD ipv4 rsclient (A.B.C.D|X:X::X:X)",
+ "show bgp view WORD ipv4 rsclient (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -14249,7 +15314,7 @@ DEFUN (show_bgp_view_ipv4_rsclient,
}
DEFUN (show_bgp_view_ipv6_rsclient,
show_bgp_view_ipv6_rsclient_cmd,
- "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X)",
+ "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -14291,25 +15356,25 @@ DEFUN (show_bgp_view_ipv6_rsclient,
ALIAS (show_bgp_view_ipv4_rsclient,
show_bgp_ipv4_rsclient_cmd,
- "show bgp ipv4 rsclient (A.B.C.D|X:X::X:X)",
+ "show bgp ipv4 rsclient (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"Address Family\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR2)
+ NEIGHBOR_ADDR_STR3)
ALIAS (show_bgp_view_ipv6_rsclient,
show_bgp_ipv6_rsclient_cmd,
- "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X)",
+ "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"Address Family\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR2)
+ NEIGHBOR_ADDR_STR3)
DEFUN (show_bgp_view_ipv6_safi_rsclient,
show_bgp_view_ipv6_safi_rsclient_cmd,
- "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)",
+ "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -14318,7 +15383,7 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient,
"Address Family modifier\n"
"Address Family modifier\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR)
+ NEIGHBOR_ADDR_STR3)
{
struct bgp_table *table;
struct peer *peer;
@@ -14357,24 +15422,24 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient,
ALIAS (show_bgp_view_ipv6_safi_rsclient,
show_bgp_ipv6_safi_rsclient_cmd,
- "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)",
+ "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR)
+ NEIGHBOR_ADDR_STR3)
DEFUN (show_bgp_view_rsclient_route,
show_bgp_view_rsclient_route_cmd,
- "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X",
+ "show bgp view WORD rsclient (A.B.C.D|X:X::X:X|WORD) X:X::X:X",
SHOW_STR
BGP_STR
"BGP view\n"
"View name\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"Network in the BGP routing table to display\n")
{
struct bgp *bgp;
@@ -14425,12 +15490,12 @@ DEFUN (show_bgp_view_rsclient_route,
return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST],
(argc == 3) ? argv[2] : argv[1],
- AFI_IP6, SAFI_UNICAST, NULL, 0);
+ AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
}
DEFUN (show_bgp_view_ipv6_rsclient_route,
show_bgp_view_ipv6_rsclient_route_cmd,
- "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X",
+ "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X|WORD) X:X::X:X",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -14488,21 +15553,21 @@ DEFUN (show_bgp_view_ipv6_rsclient_route,
return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST],
(argc == 3) ? argv[2] : argv[1],
- AFI_IP6, SAFI_UNICAST, NULL, 0);
+ AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL);
}
ALIAS (show_bgp_view_ipv6_rsclient_route,
show_bgp_rsclient_route_cmd,
- "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X",
+ "show bgp rsclient (A.B.C.D|X:X::X:X|WORD) X:X::X:X",
SHOW_STR
BGP_STR
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"Network in the BGP routing table to display\n")
ALIAS (show_bgp_view_ipv6_rsclient_route,
show_bgp_ipv6_rsclient_route_cmd,
- "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X",
+ "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X|WORD) X:X::X:X",
SHOW_STR
BGP_STR
IP6_STR
@@ -14512,7 +15577,7 @@ ALIAS (show_bgp_view_ipv6_rsclient_route,
DEFUN (show_bgp_view_ipv6_safi_rsclient_route,
show_bgp_view_ipv6_safi_rsclient_route_cmd,
- "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X",
+ "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X|WORD) X:X::X:X",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -14521,7 +15586,7 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient_route,
"Address Family modifier\n"
"Address Family modifier\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"Network in the BGP routing table to display\n")
{
struct bgp *bgp;
@@ -14576,31 +15641,31 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient_route,
return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][safi],
(argc == 4) ? argv[3] : argv[2],
- AFI_IP6, safi, NULL, 0);
+ AFI_IP6, safi, NULL, 0, BGP_PATH_ALL);
}
ALIAS (show_bgp_view_ipv6_safi_rsclient_route,
show_bgp_ipv6_safi_rsclient_route_cmd,
- "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X",
+ "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X|WORD) X:X::X:X",
SHOW_STR
BGP_STR
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"Network in the BGP routing table to display\n")
DEFUN (show_bgp_view_rsclient_prefix,
show_bgp_view_rsclient_prefix_cmd,
- "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M",
+ "show bgp view WORD rsclient (A.B.C.D|X:X::X:X|WORD) X:X::X:X/M",
SHOW_STR
BGP_STR
"BGP view\n"
"View name\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
{
struct bgp *bgp;
@@ -14651,12 +15716,12 @@ DEFUN (show_bgp_view_rsclient_prefix,
return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST],
(argc == 3) ? argv[2] : argv[1],
- AFI_IP6, SAFI_UNICAST, NULL, 1);
+ AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
}
DEFUN (show_bgp_view_ipv6_rsclient_prefix,
show_bgp_view_ipv6_rsclient_prefix_cmd,
- "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M",
+ "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X|WORD) X:X::X:X/M",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -14714,21 +15779,21 @@ DEFUN (show_bgp_view_ipv6_rsclient_prefix,
return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST],
(argc == 3) ? argv[2] : argv[1],
- AFI_IP6, SAFI_UNICAST, NULL, 1);
+ AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL);
}
ALIAS (show_bgp_view_ipv6_rsclient_prefix,
show_bgp_rsclient_prefix_cmd,
- "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M",
+ "show bgp rsclient (A.B.C.D|X:X::X:X|WORD) X:X::X:X/M",
SHOW_STR
BGP_STR
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
ALIAS (show_bgp_view_ipv6_rsclient_prefix,
show_bgp_ipv6_rsclient_prefix_cmd,
- "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M",
+ "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X|WORD) X:X::X:X/M",
SHOW_STR
BGP_STR
"Information about Route Server Client\n"
@@ -14737,7 +15802,7 @@ ALIAS (show_bgp_view_ipv6_rsclient_prefix,
DEFUN (show_bgp_view_ipv6_safi_rsclient_prefix,
show_bgp_view_ipv6_safi_rsclient_prefix_cmd,
- "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M",
+ "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X|WORD) X:X::X:X/M",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -14746,7 +15811,7 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient_prefix,
"Address Family modifier\n"
"Address Family modifier\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"IP prefix <network>/<length>, e.g., 3ffe::/16\n")
{
struct bgp *bgp;
@@ -14801,19 +15866,19 @@ DEFUN (show_bgp_view_ipv6_safi_rsclient_prefix,
return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][safi],
(argc == 4) ? argv[3] : argv[2],
- AFI_IP6, safi, NULL, 1);
+ AFI_IP6, safi, NULL, 1, BGP_PATH_ALL);
}
ALIAS (show_bgp_view_ipv6_safi_rsclient_prefix,
show_bgp_ipv6_safi_rsclient_prefix_cmd,
- "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M",
+ "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X|WORD) X:X::X:X/M",
SHOW_STR
BGP_STR
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Information about Route Server Client\n"
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR3
"IP prefix <network>/<length>, e.g., 3ffe::/16\n")
struct bgp_table *bgp_distance_table;
@@ -15697,6 +16762,7 @@ bgp_route_init (void)
bgp_distance_table = bgp_table_init (AFI_IP, SAFI_UNICAST);
/* IPv4 BGP commands. */
+ install_element (BGP_NODE, &bgp_table_map_cmd);
install_element (BGP_NODE, &bgp_network_cmd);
install_element (BGP_NODE, &bgp_network_mask_cmd);
install_element (BGP_NODE, &bgp_network_mask_natural_cmd);
@@ -15706,6 +16772,7 @@ bgp_route_init (void)
install_element (BGP_NODE, &bgp_network_backdoor_cmd);
install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd);
install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd);
+ install_element (BGP_NODE, &no_bgp_table_map_cmd);
install_element (BGP_NODE, &no_bgp_network_cmd);
install_element (BGP_NODE, &no_bgp_network_mask_cmd);
install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd);
@@ -15867,9 +16934,13 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_longer_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_longer_cmd);
install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_advertised_route_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_advertised_route_rmap_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_advertised_route_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_advertised_route_rmap_cmd);
install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_received_routes_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_received_routes_rmap_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_received_routes_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_received_routes_rmap_cmd);
install_element (VIEW_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd);
install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_routes_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_routes_cmd);
@@ -16026,9 +17097,13 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_longer_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_longer_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_advertised_route_cmd);
+ install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_advertised_route_rmap_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_advertised_route_cmd);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_advertised_route_rmap_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_received_routes_cmd);
+ install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_received_routes_rmap_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_received_routes_cmd);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_received_routes_rmap_cmd);
install_element (ENABLE_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv4_safi_neighbor_routes_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv6_safi_neighbor_routes_cmd);
@@ -16096,8 +17171,10 @@ bgp_route_init (void)
/* New config IPv6 BGP commands. */
install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd);
install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd);
+ install_element (BGP_IPV6_NODE, &bgp_table_map_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd);
+ install_element (BGP_IPV6_NODE, &no_bgp_table_map_cmd);
install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd);
install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd);
@@ -16136,6 +17213,8 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_bgp_community_list_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_rmap_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd);
@@ -16152,7 +17231,9 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_bgp_view_ipv6_route_cmd);
install_element (VIEW_NODE, &show_bgp_view_ipv6_prefix_cmd);
install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd);
+ install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_rmap_cmd);
install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd);
+ install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_routes_rmap_cmd);
install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd);
install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd);
install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd);
@@ -16213,7 +17294,9 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_bgp_ipv6_safi_community_list_exact_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_rmap_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_rmap_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_flap_cmd);
@@ -16229,7 +17312,9 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_bgp_view_ipv6_route_cmd);
install_element (ENABLE_NODE, &show_bgp_view_ipv6_prefix_cmd);
install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd);
+ install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_rmap_cmd);
install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd);
+ install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_routes_rmap_cmd);
install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd);
install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd);
install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd);
@@ -16264,6 +17349,7 @@ bgp_route_init (void)
install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd);
install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd);
install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd);
+ install_element (BGP_IPV4_NODE, &bgp_table_map_cmd);
/* Deprecated AS-Pathlimit commands */
install_element (BGP_NODE, &bgp_network_ttl_cmd);
@@ -16293,13 +17379,15 @@ bgp_route_init (void)
install_element (BGP_IPV4_NODE, &no_bgp_network_backdoor_ttl_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_network_mask_backdoor_ttl_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd);
-
+ install_element (BGP_IPV4_NODE, &no_bgp_table_map_cmd);
+
install_element (BGP_IPV4M_NODE, &bgp_network_ttl_cmd);
install_element (BGP_IPV4M_NODE, &bgp_network_mask_ttl_cmd);
install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_ttl_cmd);
install_element (BGP_IPV4M_NODE, &bgp_network_backdoor_ttl_cmd);
install_element (BGP_IPV4M_NODE, &bgp_network_mask_backdoor_ttl_cmd);
install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd);
+ install_element (BGP_IPV4M_NODE, &bgp_table_map_cmd);
install_element (BGP_IPV4M_NODE, &no_bgp_network_ttl_cmd);
install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_ttl_cmd);
@@ -16307,6 +17395,7 @@ bgp_route_init (void)
install_element (BGP_IPV4M_NODE, &no_bgp_network_backdoor_ttl_cmd);
install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_backdoor_ttl_cmd);
install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd);
+ install_element (BGP_IPV4M_NODE, &no_bgp_table_map_cmd);
install_element (BGP_IPV6_NODE, &ipv6_bgp_network_ttl_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_ttl_cmd);
@@ -16315,11 +17404,16 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ip_bgp_cmd);
install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_route_pathtype_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd);
install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_pathtype_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_pathtype_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_prefix_pathtype_cmd);
install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd);
install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd);
install_element (VIEW_NODE, &show_ip_bgp_view_cmd);
@@ -16359,10 +17453,14 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd);
install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd);
install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_safi_neighbor_advertised_route_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_safi_neighbor_advertised_route_rmap_cmd);
install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd);
- install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_rmap_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_safi_neighbor_received_routes_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_safi_neighbor_received_routes_rmap_cmd);
install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd);
- install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_rmap_cmd);
install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd);
install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd);
install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
@@ -16392,15 +17490,22 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ip_bgp_rsclient_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_rsclient_prefix_cmd);
install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_advertised_route_rmap_cmd);
install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_received_routes_rmap_cmd);
install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd);
install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_route_pathtype_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_pathtype_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_prefix_pathtype_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_pathtype_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_view_route_cmd);
@@ -16428,11 +17533,16 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_ip_bgp_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_route_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_route_pathtype_cmd);
+ install_element (ENABLE_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_pathtype_cmd);
+ install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_pathtype_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_prefix_pathtype_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_view_cmd);
@@ -16473,10 +17583,13 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd);
- install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_rmap_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_safi_neighbor_advertised_route_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_safi_neighbor_advertised_route_rmap_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_safi_neighbor_received_routes_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_safi_neighbor_received_routes_rmap_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd);
- install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd);
- install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_rmap_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd);
@@ -16506,17 +17619,26 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_ip_bgp_rsclient_route_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_rsclient_prefix_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_advertised_route_rmap_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_received_routes_rmap_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_route_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_prefix_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd);
+
install_element (VIEW_NODE, &show_bgp_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_cmd);
install_element (VIEW_NODE, &show_bgp_route_cmd);
install_element (VIEW_NODE, &show_bgp_prefix_cmd);
+ install_element (VIEW_NODE, &show_bgp_route_pathtype_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_route_pathtype_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_safi_route_pathtype_cmd);
+ install_element (VIEW_NODE, &show_bgp_prefix_pathtype_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_prefix_pathtype_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_pathtype_cmd);
install_element (VIEW_NODE, &show_bgp_regexp_cmd);
install_element (VIEW_NODE, &show_bgp_prefix_list_cmd);
install_element (VIEW_NODE, &show_bgp_filter_list_cmd);
@@ -16536,6 +17658,7 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_exact_cmd);
install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd);
install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd);
+ install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_rmap_cmd);
install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd);
install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd);
install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd);
@@ -16546,7 +17669,9 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_bgp_view_route_cmd);
install_element (VIEW_NODE, &show_bgp_view_prefix_cmd);
install_element (VIEW_NODE, &show_bgp_view_neighbor_advertised_route_cmd);
+ install_element (VIEW_NODE, &show_bgp_view_neighbor_advertised_route_rmap_cmd);
install_element (VIEW_NODE, &show_bgp_view_neighbor_received_routes_cmd);
+ install_element (VIEW_NODE, &show_bgp_view_neighbor_received_routes_rmap_cmd);
install_element (VIEW_NODE, &show_bgp_view_neighbor_routes_cmd);
install_element (VIEW_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd);
install_element (VIEW_NODE, &show_bgp_view_neighbor_flap_cmd);
@@ -16554,6 +17679,12 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd);
install_element (RESTRICTED_NODE, &show_bgp_route_cmd);
install_element (RESTRICTED_NODE, &show_bgp_prefix_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_route_pathtype_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv6_route_pathtype_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_route_pathtype_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_prefix_pathtype_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv6_prefix_pathtype_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_prefix_pathtype_cmd);
install_element (RESTRICTED_NODE, &show_bgp_community_cmd);
install_element (RESTRICTED_NODE, &show_bgp_community2_cmd);
install_element (RESTRICTED_NODE, &show_bgp_community3_cmd);
@@ -16569,6 +17700,12 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_bgp_ipv6_cmd);
install_element (ENABLE_NODE, &show_bgp_route_cmd);
install_element (ENABLE_NODE, &show_bgp_prefix_cmd);
+ install_element (ENABLE_NODE, &show_bgp_route_pathtype_cmd);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_route_pathtype_cmd);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_safi_route_pathtype_cmd);
+ install_element (ENABLE_NODE, &show_bgp_prefix_pathtype_cmd);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_pathtype_cmd);
+ install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_pathtype_cmd);
install_element (ENABLE_NODE, &show_bgp_regexp_cmd);
install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd);
install_element (ENABLE_NODE, &show_bgp_filter_list_cmd);
@@ -16587,6 +17724,7 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd);
install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd);
install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd);
+ install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_rmap_cmd);
install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd);
install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd);
install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd);
@@ -16597,6 +17735,8 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_bgp_view_route_cmd);
install_element (ENABLE_NODE, &show_bgp_view_prefix_cmd);
install_element (ENABLE_NODE, &show_bgp_view_neighbor_advertised_route_cmd);
+ install_element (ENABLE_NODE, &show_bgp_view_neighbor_advertised_route_rmap_cmd);
+ install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_routes_cmd);
install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_routes_cmd);
install_element (ENABLE_NODE, &show_bgp_view_neighbor_routes_cmd);
install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd);
@@ -16677,14 +17817,20 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd);
install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd);
install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd);
- install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd);
- install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd);
+ install_element (VIEW_NODE, &show_ipv6_bgp_neighbor_advertised_route_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_neighbor_advertised_route_cmd);
+ install_element (VIEW_NODE, &show_ipv6_bgp_neighbor_advertised_route_rmap_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_neighbor_advertised_route_rmap_cmd);
install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd);
install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd);
- install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd);
- install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd);
+ install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_rmap_cmd);
+ install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_rmap_cmd);
+ install_element (VIEW_NODE, &show_ipv6_bgp_neighbor_received_routes_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_bgp_neighbor_received_routes_cmd);
install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd);
install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd);
+ install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_rmap_cmd);
+ install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_rmap_cmd);
install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd);
install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd);
install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index c8037592..b54a7941 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -21,8 +21,11 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_ROUTE_H
#define _QUAGGA_BGP_ROUTE_H
+#include "queue.h"
#include "bgp_table.h"
+struct bgp_nexthop_cache;
+
/* Ancillary information to struct bgp_info,
* used for uncommonly used data (aggregation, MPLS, etc.)
* and lazily allocated to save memory.
@@ -47,7 +50,16 @@ struct bgp_info
/* For linked list. */
struct bgp_info *next;
struct bgp_info *prev;
-
+
+ /* For nexthop linked list */
+ LIST_ENTRY(bgp_info) nh_thread;
+
+ /* Back pointer to the prefix node */
+ struct bgp_node *net;
+
+ /* Back pointer to the nexthop structure */
+ struct bgp_nexthop_cache *nexthop;
+
/* Peer structure. */
struct peer *peer;
@@ -127,6 +139,10 @@ struct bgp_static
u_char tag[3];
};
+#define BGP_INFO_COUNTABLE(BI) \
+ (! CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY) \
+ && ! CHECK_FLAG ((BI)->flags, BGP_INFO_REMOVED))
+
/* Flags which indicate a route is unuseable in some form */
#define BGP_INFO_UNUSEABLE \
(BGP_INFO_HISTORY|BGP_INFO_DAMPED|BGP_INFO_REMOVED)
@@ -172,7 +188,15 @@ enum bgp_clear_route_type
BGP_CLEAR_ROUTE_MY_RSCLIENT
};
+enum bgp_path_type
+{
+ BGP_PATH_ALL,
+ BGP_PATH_BESTPATH,
+ BGP_PATH_MULTIPATH
+};
+
/* Prototypes. */
+extern void bgp_process_queue_init (void);
extern void bgp_route_init (void);
extern void bgp_route_finish (void);
extern void bgp_cleanup_routes (void);
@@ -201,8 +225,8 @@ extern int bgp_nlri_parse_ip (struct peer *, struct attr *, struct bgp_nlri *);
extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int);
extern void bgp_redistribute_add (struct prefix *, const struct in_addr *,
- const struct in6_addr *,
- u_int32_t, u_char);
+ const struct in6_addr *, unsigned int ifindex,
+ u_int32_t, u_char, u_short);
extern void bgp_redistribute_delete (struct prefix *, u_char);
extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int);
@@ -226,6 +250,14 @@ extern int bgp_withdraw (struct peer *, struct prefix *, struct attr *,
/* for bgp_nexthop and bgp_damp */
extern void bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t);
+
+/*
+ * Add an end-of-initial-update marker to the process queue. This is just a
+ * queue element with NULL bgp node.
+ */
+extern void bgp_add_eoiu_mark (struct bgp *, bgp_table_t);
+extern int bgp_config_write_table_map (struct vty *, struct bgp *, afi_t, safi_t,
+ int *);
extern int bgp_config_write_network (struct vty *, struct bgp *, afi_t, safi_t, int *);
extern int bgp_config_write_distance (struct vty *, struct bgp *);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 39fa08c8..18ecc6c8 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -39,12 +39,15 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#endif /* HAVE_LIBPCREPOSIX */
#include "buffer.h"
#include "sockunion.h"
+#include "hash.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_clist.h"
@@ -52,6 +55,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_vty.h"
+#include "bgpd/bgp_debug.h"
+
/* Memo of route-map commands.
@@ -59,7 +64,7 @@ o Cisco route-map
match as-path : Done
community : Done
- interface : Not yet
+ interface : Done
ip address : Done
ip next-hop : Done
ip route-source : Done
@@ -71,7 +76,8 @@ o Cisco route-map
length : (This will not be implemented by bgpd)
metric : Done
route-type : (This will not be implemented by bgpd)
- tag : (This will not be implemented by bgpd)
+ tag : Done
+ local-preference : Done
set as-path prepend : Done
as-path tag : Not yet
@@ -90,7 +96,7 @@ o Cisco route-map
metric : Done
metric-type : Not yet
origin : Done
- tag : (This will not be implemented by bgpd)
+ tag : Done
weight : Done
o Local extensions
@@ -613,6 +619,72 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd =
route_match_ip_route_source_prefix_list_free
};
+/* `match local-preference LOCAL-PREF' */
+
+/* Match function return 1 if match is success else return zero. */
+static route_map_result_t
+route_match_local_pref (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_int32_t *local_pref;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ local_pref = rule;
+ bgp_info = object;
+
+ if (bgp_info->attr->local_pref == *local_pref)
+ return RMAP_MATCH;
+ else
+ return RMAP_NOMATCH;
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `match local-preference' match statement.
+ `arg' is local-pref value */
+static void *
+route_match_local_pref_compile (const char *arg)
+{
+ u_int32_t *local_pref;
+ char *endptr = NULL;
+ unsigned long tmpval;
+
+ /* Locpref value shoud be integer. */
+ if (! all_digit (arg))
+ return NULL;
+
+ errno = 0;
+ tmpval = strtoul (arg, &endptr, 10);
+ if (*endptr != '\0' || errno || tmpval > UINT32_MAX)
+ return NULL;
+
+ local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+
+ if (!local_pref)
+ return local_pref;
+
+ *local_pref = tmpval;
+ return local_pref;
+}
+
+/* Free route map's compiled `match local-preference' value. */
+static void
+route_match_local_pref_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for metric matching. */
+struct route_map_rule_cmd route_match_local_pref_cmd =
+{
+ "local-preference",
+ route_match_local_pref,
+ route_match_local_pref_compile,
+ route_match_local_pref_free
+};
+
/* `match metric METRIC' */
/* Match function return 1 if match is success else return zero. */
@@ -657,9 +729,9 @@ route_match_aspath (void *rule, struct prefix *prefix,
as_list = as_list_lookup ((char *) rule);
if (as_list == NULL)
return RMAP_NOMATCH;
-
+
bgp_info = object;
-
+
/* Perform match. */
return ((as_list_apply (as_list, bgp_info->attr->aspath) == AS_FILTER_DENY) ? RMAP_NOMATCH : RMAP_MATCH);
}
@@ -933,10 +1005,127 @@ struct route_map_rule_cmd route_match_probability_cmd =
route_match_probability_free
};
+/* `match interface IFNAME' */
+/* Match function should 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 interface *ifp;
+ struct bgp_info *info;
+
+ if (type == RMAP_BGP)
+ {
+ info = object;
+
+ if (!info || !info->attr)
+ return RMAP_NOMATCH;
+
+ ifp = if_lookup_by_name ((char *)rule);
+
+ if (ifp == NULL || ifp->ifindex != info->attr->nh_ifindex)
+ return RMAP_NOMATCH;
+
+ return RMAP_MATCH;
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `interface' match statement. `arg' should be
+ interface name. */
+static void *
+route_match_interface_compile (const char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `interface' value. */
+static void
+route_match_interface_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+struct route_map_rule_cmd route_match_interface_cmd =
+{
+ "interface",
+ route_match_interface,
+ route_match_interface_compile,
+ route_match_interface_free
+};
+
/* } */
/* `set ip next-hop IP_ADDRESS' */
+/* 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 bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ tag = rule;
+ bgp_info = object;
+
+ if (!bgp_info->attr->extra)
+ return RMAP_NOMATCH;
+
+ return ((bgp_info->attr->extra->tag == *tag)? RMAP_MATCH : 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;
+ u_short tmp;
+
+ /* tag value shoud be integer. */
+ if (! all_digit (arg))
+ return NULL;
+
+ tmp = atoi(arg);
+ if (tmp < 1)
+ return NULL;
+
+ tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
+
+ if (!tag)
+ return tag;
+
+ *tag = tmp;
+
+ 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 nexthop to object. ojbect must be pointer to struct attr. */
struct rmap_ip_nexthop_set
{
@@ -1710,6 +1899,73 @@ struct route_map_rule_cmd route_set_aggregator_as_cmd =
route_set_aggregator_as_free,
};
+/* Set tag to object. object must be pointer to struct bgp_info */
+static route_map_result_t
+route_set_tag (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_short *tag;
+ struct bgp_info *bgp_info;
+ struct attr_extra *ae;
+
+ if (type == RMAP_BGP)
+ {
+ tag = rule;
+ bgp_info = object;
+ ae = bgp_attr_extra_get (bgp_info->attr);
+
+ /* Set tag value */
+ ae->tag=*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;
+ u_short tmp;
+
+ /* tag value shoud be integer. */
+ if (! all_digit (arg))
+ return NULL;
+
+ tmp = atoi(arg);
+
+ if (tmp < 1)
+ return NULL;
+
+ tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
+
+ if (!tag)
+ return tag;
+
+ *tag = tmp;
+
+ return tag;
+}
+
+/* Free route map's tag value. */
+static void
+route_set_tag_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+
+/* Route map commands for tag set. */
+struct route_map_rule_cmd route_set_tag_cmd =
+{
+ "tag",
+ route_set_tag,
+ route_set_tag_compile,
+ route_set_tag_free,
+};
+
+
/* `match ipv6 address IP_ACCESS_LIST' */
static route_map_result_t
@@ -2187,7 +2443,8 @@ struct route_map_rule_cmd route_set_originator_id_cmd =
/* Add bgp route map rule. */
static int
bgp_route_match_add (struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg)
+ const char *command, const char *arg,
+ route_map_event_t type)
{
int ret;
@@ -2197,36 +2454,71 @@ bgp_route_match_add (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% BGP Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% BGP Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
+
+ if (type != RMAP_EVENT_MATCH_ADDED)
+ {
+ route_map_upd8_dependency (type, arg, index->map->name);
+ }
+
return CMD_SUCCESS;
}
/* Delete bgp route map rule. */
static int
bgp_route_match_delete (struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg)
+ const char *command, const char *arg,
+ route_map_event_t type)
{
int ret;
+ char *dep_name = (char *)arg;
+ const char *tmpstr;
+ char *rmap_name = NULL;
+
+ if (type != RMAP_EVENT_MATCH_DELETED)
+ {
+ /* ignore the mundane, the types without any dependency */
+ if (arg == NULL)
+ {
+ if ((tmpstr = route_map_get_match_arg(index, command)) != NULL)
+ dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
+ }
+ rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
+ }
- ret = route_map_delete_match (index, command, arg);
+ ret = route_map_delete_match (index, command, dep_name);
if (ret)
{
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
- return CMD_WARNING;
+ vty_out (vty, "%% BGP Can't find rule.%s", VTY_NEWLINE);
+ break;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
- return CMD_WARNING;
+ vty_out (vty, "%% BGP Argument is malformed.%s", VTY_NEWLINE);
+ break;
}
+ if (arg == NULL && dep_name)
+ XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
+ if (rmap_name)
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+ return CMD_WARNING;
}
+
+ if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
+ route_map_upd8_dependency(type, dep_name, rmap_name);
+
+ if (arg == NULL && dep_name)
+ XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
+ if (rmap_name)
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+
return CMD_SUCCESS;
}
@@ -2243,10 +2535,10 @@ bgp_route_set_add (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% BGP Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% BGP Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -2266,134 +2558,363 @@ bgp_route_set_delete (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% BGP Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% BGP Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
return CMD_SUCCESS;
}
-/* Hook function for updating route_map assignment. */
+/*
+ * This is the workhorse routine for processing in/out/import/export routemap
+ * modifications.
+ */
static void
-bgp_route_map_update (const char *unused)
+bgp_route_map_process_peer (const char *rmap_name, struct peer *peer,
+ int afi, int safi, int route_update)
{
- int i;
- afi_t afi;
- safi_t safi;
- int direct;
- struct listnode *node, *nnode;
- struct listnode *mnode, *mnnode;
- struct bgp *bgp;
- struct peer *peer;
- struct peer_group *group;
+
+ int update;
struct bgp_filter *filter;
- struct bgp_node *bn;
- struct bgp_static *bgp_static;
if (bm->bgp == NULL) /* may be called during cleanup */
return;
- /* For neighbor route-map updates. */
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
+ if (!peer || !rmap_name)
+ return;
+
+ filter = &peer->filter[afi][safi];
+ /*
+ * in is for non-route-server clients,
+ * import/export is for route-server clients,
+ * out is for all peers
+ */
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_RSERVER_CLIENT))
{
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ if (filter->map[RMAP_IN].name &&
+ (strcmp(rmap_name, filter->map[RMAP_IN].name) == 0))
{
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &peer->filter[afi][safi];
-
- for (direct = RMAP_IN; direct < RMAP_MAX; direct++)
- {
- if (filter->map[direct].name)
- filter->map[direct].map =
- route_map_lookup_by_name (filter->map[direct].name);
- else
- filter->map[direct].map = NULL;
- }
-
- if (filter->usmap.name)
- filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
- else
- filter->usmap.map = NULL;
- }
+ filter->map[RMAP_IN].map =
+ route_map_lookup_by_name (filter->map[RMAP_IN].name);
+
+ if (route_update && peer->status == Established)
+ {
+ if (CHECK_FLAG (peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG))
+ {
+ if (bgp_debug_update(peer, NULL, 1))
+ zlog_debug("Processing route_map %s update on "
+ "peer %s (inbound, soft-reconfig)",
+ rmap_name, peer->host);
+
+ bgp_soft_reconfig_in (peer, afi, safi);
+ }
+ else if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ {
+
+ if (bgp_debug_update(peer, NULL, 1))
+ zlog_debug("Processing route_map %s update on "
+ "peer %s (inbound, route-refresh)",
+ rmap_name, peer->host);
+ bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+ }
+ }
+ }
+ }
+
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_RSERVER_CLIENT))
+ {
+ update = 0;
+
+ if (filter->map[RMAP_IMPORT].name &&
+ (strcmp(rmap_name, filter->map[RMAP_IMPORT].name) == 0))
+ {
+ filter->map[RMAP_IMPORT].map =
+ route_map_lookup_by_name (filter->map[RMAP_IMPORT].name);
+ update = 1;
}
- for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
+
+ if (filter->map[RMAP_EXPORT].name &&
+ (strcmp(rmap_name, filter->map[RMAP_EXPORT].name) == 0))
{
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &group->conf->filter[afi][safi];
-
- for (direct = RMAP_IN; direct < RMAP_MAX; direct++)
- {
- if (filter->map[direct].name)
- filter->map[direct].map =
- route_map_lookup_by_name (filter->map[direct].name);
- else
- filter->map[direct].map = NULL;
- }
-
- if (filter->usmap.name)
- filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
- else
- filter->usmap.map = NULL;
- }
+ filter->map[RMAP_EXPORT].map =
+ route_map_lookup_by_name (filter->map[RMAP_EXPORT].name);
+
+ update = 1;
+ }
+
+ if (update && route_update && peer->status == Established)
+ {
+ if (CHECK_FLAG (peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG))
+ {
+ if (bgp_debug_update(peer, NULL, 1))
+ zlog_debug("Processing route_map %s update on "
+ "peer %s (import, soft-reconfig)",
+ rmap_name, peer->host);
+
+ bgp_soft_reconfig_in (peer, afi, safi);
+ }
+ else if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ {
+ if (bgp_debug_update(peer, NULL, 1))
+ zlog_debug("Processing route_map %s update on "
+ "peer %s (import, route-refresh)",
+ rmap_name, peer->host);
+ bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+ }
+ /* DD: Else, what else do we do ? Reset peer ? */
}
}
- /* For default-originate route-map updates. */
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
- {
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ if (filter->map[RMAP_OUT].name &&
+ (strcmp(rmap_name, filter->map[RMAP_OUT].name) == 0))
{
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- if (peer->default_rmap[afi][safi].name)
- peer->default_rmap[afi][safi].map =
- route_map_lookup_by_name (peer->default_rmap[afi][safi].name);
- else
- peer->default_rmap[afi][safi].map = NULL;
- }
+ filter->map[RMAP_OUT].map =
+ route_map_lookup_by_name (filter->map[RMAP_OUT].name);
+
+ if (bgp_debug_update(peer, NULL, 0))
+ zlog_debug("Processing route_map %s update on peer %s (outbound)",
+ rmap_name, peer->host);
+
+ if (route_update)
+ bgp_announce_route_all(peer);
}
+
+ if (filter->usmap.name &&
+ (strcmp(rmap_name, filter->usmap.name) == 0))
+ {
+ filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
+ if (route_update)
+ bgp_announce_route_all(peer);
}
+}
- /* For network route-map updates. */
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
+static void
+bgp_route_map_update_peer_group(const char *rmap_name, struct bgp *bgp)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+ struct bgp_filter *filter;
+ int afi, safi;
+ int direct;
+
+ if (!bgp)
+ return;
+
+ /* All the peers have been updated correctly already. This is
+ * just updating the placeholder data. No real update required.
+ */
+ for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ filter = &group->conf->filter[afi][safi];
+
+ for (direct = RMAP_IN; direct < RMAP_MAX; direct++)
+ {
+ if ((filter->map[direct].name) &&
+ (strcmp(rmap_name, filter->map[direct].name) == 0))
+ filter->map[direct].map =
+ route_map_lookup_by_name (filter->map[direct].name);
+ }
+
+ if (filter->usmap.name &&
+ (strcmp(rmap_name, filter->usmap.name) == 0))
+ filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
+ }
+}
+
+static int
+bgp_route_map_process_update (void *arg, const char *rmap_name, int route_update)
+{
+ int i;
+ afi_t afi;
+ safi_t safi;
+ struct peer *peer;
+ struct bgp_node *bn;
+ struct bgp_static *bgp_static;
+ struct bgp *bgp = (struct bgp *)arg;
+ struct listnode *node, *nnode;
+ char buf[INET6_ADDRSTRLEN];
+
+ if (!bgp)
+ return -1;
+
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
+
+ /* Ignore dummy peer-group structure */
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ continue;
+
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- for (bn = bgp_table_top (bgp->route[afi][safi]); bn;
- bn = bgp_route_next (bn))
- if ((bgp_static = bn->info) != NULL)
+ {
+ /* Ignore inactive AFI/SAFI */
+ if (! peer->afc[afi][safi])
+ continue;
+
+ /* process in/out/import/export route-maps */
+ bgp_route_map_process_peer(rmap_name, peer, afi, safi, route_update);
+
+ /* process default-originate route-map */
+ if (peer->default_rmap[afi][safi].name &&
+ (strcmp (rmap_name, peer->default_rmap[afi][safi].name) == 0))
{
- if (bgp_static->rmap.name)
- bgp_static->rmap.map =
- route_map_lookup_by_name (bgp_static->rmap.name);
- else
- bgp_static->rmap.map = NULL;
+ peer->default_rmap[afi][safi].map =
+ route_map_lookup_by_name (peer->default_rmap[afi][safi].name);
+
+ if (bgp_debug_update(peer, NULL, 0))
+ zlog_debug("Processing route_map %s update on "
+ "default-originate", rmap_name);
+
+ if (route_update)
+ bgp_default_originate (peer, afi, safi, 0);
}
+ }
}
+ bgp_route_map_update_peer_group(rmap_name, bgp);
+
+ /* For table route-map updates. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ if (bgp->table_map[afi][safi].name &&
+ (strcmp(rmap_name, bgp->table_map[afi][safi].name) == 0))
+ {
+ bgp->table_map[afi][safi].map =
+ route_map_lookup_by_name (bgp->table_map[afi][safi].name);
+ if (BGP_DEBUG (zebra, ZEBRA))
+ zlog_debug("Processing route_map %s update on "
+ "table map", rmap_name);
+ if (route_update)
+ bgp_zebra_announce_table(bgp, afi, safi);
+ }
+ }
+
+ /* For network route-map updates. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ for (bn = bgp_table_top (bgp->route[afi][safi]); bn;
+ bn = bgp_route_next (bn))
+ if ((bgp_static = bn->info) != NULL)
+ {
+ if (bgp_static->rmap.name &&
+ (strcmp(rmap_name, bgp_static->rmap.name) == 0))
+ {
+ bgp_static->rmap.map =
+ route_map_lookup_by_name (bgp_static->rmap.name);
+ if (route_update)
+ if (!bgp_static->backdoor)
+ {
+ if (bgp_debug_zebra(&bn->p))
+ zlog_debug("Processing route_map %s update on "
+ "static route %s", rmap_name,
+ inet_ntop (bn->p.family, &bn->p.u.prefix,
+ buf, INET6_ADDRSTRLEN));
+ bgp_static_update (bgp, &bn->p, bgp_static, afi, safi);
+ }
+ }
+ }
+
/* For redistribute route-map updates. */
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (bgp->rmap[afi][i].name &&
+ (strcmp(rmap_name, bgp->rmap[afi][i].name) == 0))
+ {
+ bgp->rmap[afi][i].map =
+ route_map_lookup_by_name (bgp->rmap[afi][i].name);
+
+ if (bgp->redist[afi][i] && route_update)
+ {
+ if (BGP_DEBUG (zebra, ZEBRA))
+ zlog_debug("Processing route_map %s update on "
+ "redistributed routes", rmap_name);
+
+ bgp_redistribute_resend (bgp, afi, i);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+bgp_route_map_process_update_cb (void *arg, char *rmap_name)
+{
+ return bgp_route_map_process_update (arg, rmap_name, 1);
+}
+
+int
+bgp_route_map_update_timer(struct thread *thread)
+{
+ struct bgp *bgp = THREAD_ARG(thread);
+
+ bgp->t_rmap_update = NULL;
+
+ route_map_walk_update_list((void *)bgp, bgp_route_map_process_update_cb);
+
+ return (0);
+}
+
+static void
+bgp_route_map_mark_update (const char *rmap_name)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+
+ for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
{
- for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ if (bgp->t_rmap_update == NULL)
{
- if (bgp->rmap[AFI_IP][i].name)
- bgp->rmap[AFI_IP][i].map =
- route_map_lookup_by_name (bgp->rmap[AFI_IP][i].name);
- if (bgp->rmap[AFI_IP6][i].name)
- bgp->rmap[AFI_IP6][i].map =
- route_map_lookup_by_name (bgp->rmap[AFI_IP][i].name);
+ /* rmap_update_timer of 0 means don't do route updates */
+ if (bgp->rmap_update_timer)
+ bgp->t_rmap_update =
+ thread_add_timer(bm->master, bgp_route_map_update_timer, bgp,
+ bgp->rmap_update_timer);
+ else
+ bgp_route_map_process_update((void *)bgp, rmap_name, 0);
}
}
}
+static void
+bgp_route_map_add (const char *rmap_name)
+{
+ if (route_map_mark_updated(rmap_name, 0) == 0)
+ bgp_route_map_mark_update(rmap_name);
+
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
+}
+
+static void
+bgp_route_map_delete (const char *rmap_name)
+{
+ if (route_map_mark_updated(rmap_name, 1) == 0)
+ bgp_route_map_mark_update(rmap_name);
+
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
+}
+
+static void
+bgp_route_map_event (route_map_event_t event, const char *rmap_name)
+{
+ if (route_map_mark_updated(rmap_name, 0) == 0)
+ bgp_route_map_mark_update(rmap_name);
+
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
+}
+
+
DEFUN (match_peer,
match_peer_cmd,
"match peer (A.B.C.D|X:X::X:X)",
@@ -2402,7 +2923,8 @@ DEFUN (match_peer,
"IPv6 address of peer\n"
"IP address of peer\n")
{
- return bgp_route_match_add (vty, vty->index, "peer", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "peer", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
}
DEFUN (match_peer_local,
@@ -2412,7 +2934,8 @@ DEFUN (match_peer_local,
"Match peer address\n"
"Static or Redistributed routes\n")
{
- return bgp_route_match_add (vty, vty->index, "peer", "local");
+ return bgp_route_match_add (vty, vty->index, "peer", "local",
+ RMAP_EVENT_MATCH_DELETED);
}
DEFUN (no_match_peer,
@@ -2423,9 +2946,11 @@ DEFUN (no_match_peer,
"Match peer address\n")
{
if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "peer", NULL);
+ return bgp_route_match_delete (vty, vty->index, "peer", NULL,
+ RMAP_EVENT_MATCH_DELETED);
- return bgp_route_match_delete (vty, vty->index, "peer", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "peer", argv[0],
+ RMAP_EVENT_MATCH_DELETED);
}
ALIAS (no_match_peer,
@@ -2455,7 +2980,8 @@ DEFUN (match_ip_address,
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ip address", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ip address", argv[0],
+ RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ip_address,
@@ -2467,9 +2993,11 @@ DEFUN (no_match_ip_address,
"Match address of route\n")
{
if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "ip address", NULL);
+ return bgp_route_match_delete (vty, vty->index, "ip address", NULL,
+ RMAP_EVENT_FILTER_DELETED);
- return bgp_route_match_delete (vty, vty->index, "ip address", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ip address", argv[0],
+ RMAP_EVENT_FILTER_DELETED);
}
ALIAS (no_match_ip_address,
@@ -2493,7 +3021,8 @@ DEFUN (match_ip_next_hop,
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ip next-hop", argv[0],
+ RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ip_next_hop,
@@ -2505,9 +3034,11 @@ DEFUN (no_match_ip_next_hop,
"Match next-hop address of route\n")
{
if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+ return bgp_route_match_delete (vty, vty->index, "ip next-hop", NULL,
+ RMAP_EVENT_FILTER_DELETED);
- return bgp_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ip next-hop", argv[0],
+ RMAP_EVENT_FILTER_DELETED);
}
ALIAS (no_match_ip_next_hop,
@@ -2530,7 +3061,8 @@ DEFUN (match_probability,
"Match portion of routes defined by percentage value\n"
"Percentage of routes\n")
{
- return bgp_route_match_add (vty, vty->index, "probability", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "probability", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
}
DEFUN (no_match_probability,
@@ -2540,7 +3072,8 @@ DEFUN (no_match_probability,
MATCH_STR
"Match portion of routes defined by percentage value\n")
{
- return bgp_route_match_delete (vty, vty->index, "probability", argc ? argv[0] : NULL);
+ return bgp_route_match_delete (vty, vty->index, "probability", argc ? argv[0] : NULL,
+ RMAP_EVENT_MATCH_DELETED);
}
ALIAS (no_match_probability,
@@ -2563,7 +3096,8 @@ DEFUN (match_ip_route_source,
"IP access-list number (expanded range)\n"
"IP standard access-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ip route-source", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ip route-source", argv[0],
+ RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ip_route_source,
@@ -2575,9 +3109,11 @@ DEFUN (no_match_ip_route_source,
"Match advertising source address of route\n")
{
if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "ip route-source", NULL);
+ return bgp_route_match_delete (vty, vty->index, "ip route-source", NULL,
+ RMAP_EVENT_FILTER_DELETED);
- return bgp_route_match_delete (vty, vty->index, "ip route-source", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ip route-source",
+ argv[0], RMAP_EVENT_FILTER_DELETED);
}
ALIAS (no_match_ip_route_source,
@@ -2600,7 +3136,8 @@ DEFUN (match_ip_address_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ip address prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ip_address_prefix_list,
@@ -2612,10 +3149,9 @@ DEFUN (no_match_ip_address_prefix_list,
"Match address of route\n"
"Match entries of prefix-lists\n")
{
- if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
-
- return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ip address prefix-list",
+ argc == 0 ? NULL : argv[0],
+ RMAP_EVENT_PLIST_DELETED);
}
ALIAS (no_match_ip_address_prefix_list,
@@ -2637,7 +3173,8 @@ DEFUN (match_ip_next_hop_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ip next-hop prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ip_next_hop_prefix_list,
@@ -2649,10 +3186,9 @@ DEFUN (no_match_ip_next_hop_prefix_list,
"Match next-hop address of route\n"
"Match entries of prefix-lists\n")
{
- if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL);
-
- return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list",
+ argc == 0 ? NULL : argv[0],
+ RMAP_EVENT_PLIST_DELETED);
}
ALIAS (no_match_ip_next_hop_prefix_list,
@@ -2674,7 +3210,8 @@ DEFUN (match_ip_route_source_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ip route-source prefix-list", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ip route-source prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ip_route_source_prefix_list,
@@ -2686,10 +3223,9 @@ DEFUN (no_match_ip_route_source_prefix_list,
"Match advertising source address of route\n"
"Match entries of prefix-lists\n")
{
- if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "ip route-source prefix-list", NULL);
-
- return bgp_route_match_delete (vty, vty->index, "ip route-source prefix-list", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ip route-source prefix-list",
+ argc == 0 ? NULL : argv[0],
+ RMAP_EVENT_PLIST_DELETED);
}
ALIAS (no_match_ip_route_source_prefix_list,
@@ -2709,7 +3245,8 @@ DEFUN (match_metric,
"Match metric of route\n"
"Metric value\n")
{
- return bgp_route_match_add (vty, vty->index, "metric", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "metric", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
}
DEFUN (no_match_metric,
@@ -2719,10 +3256,9 @@ DEFUN (no_match_metric,
MATCH_STR
"Match metric of route\n")
{
- if (argc == 0)
- return bgp_route_match_delete (vty, vty->index, "metric", NULL);
-
- return bgp_route_match_delete (vty, vty->index, "metric", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "metric",
+ argc == 0 ? NULL : argv[0],
+ RMAP_EVENT_MATCH_DELETED);
}
ALIAS (no_match_metric,
@@ -2733,6 +3269,40 @@ ALIAS (no_match_metric,
"Match metric of route\n"
"Metric value\n")
+DEFUN (match_local_pref,
+ match_local_pref_cmd,
+ "match local-preference <0-4294967295>",
+ MATCH_STR
+ "Match local-preference of route\n"
+ "Metric value\n")
+{
+ return bgp_route_match_add (vty, vty->index, "local-preference", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
+}
+
+DEFUN (no_match_local_pref,
+ no_match_local_pref_cmd,
+ "no match local-preference",
+ NO_STR
+ MATCH_STR
+ "Match local preference of route\n")
+{
+ return bgp_route_match_delete (vty, vty->index, "local-preference",
+ argc == 0 ? NULL : argv[0],
+ RMAP_EVENT_MATCH_DELETED);
+
+ return bgp_route_match_delete (vty, vty->index, "local-preference", argv[0],
+ RMAP_EVENT_MATCH_DELETED);
+}
+
+ALIAS (no_match_local_pref,
+ no_match_local_pref_val_cmd,
+ "no match local-preference <0-4294967295>",
+ NO_STR
+ MATCH_STR
+ "Match local preference of route\n"
+ "Local preference value\n")
+
DEFUN (match_community,
match_community_cmd,
"match community (<1-99>|<100-500>|WORD)",
@@ -2742,7 +3312,8 @@ DEFUN (match_community,
"Community-list number (expanded)\n"
"Community-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "community", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "community", argv[0],
+ RMAP_EVENT_CLIST_ADDED);
}
DEFUN (match_community_exact,
@@ -2763,7 +3334,8 @@ DEFUN (match_community_exact,
sprintf (argstr, "%s exact-match", argv[0]);
- ret = bgp_route_match_add (vty, vty->index, "community", argstr);
+ ret = bgp_route_match_add (vty, vty->index, "community", argstr,
+ RMAP_EVENT_CLIST_ADDED);
XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr);
@@ -2777,7 +3349,8 @@ DEFUN (no_match_community,
MATCH_STR
"Match BGP community list\n")
{
- return bgp_route_match_delete (vty, vty->index, "community", NULL);
+ return bgp_route_match_delete (vty, vty->index, "community", NULL,
+ RMAP_EVENT_CLIST_DELETED);
}
ALIAS (no_match_community,
@@ -2810,7 +3383,8 @@ DEFUN (match_ecommunity,
"Extended community-list number (expanded)\n"
"Extended community-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "extcommunity", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "extcommunity", argv[0],
+ RMAP_EVENT_ECLIST_ADDED);
}
DEFUN (no_match_ecommunity,
@@ -2820,7 +3394,8 @@ DEFUN (no_match_ecommunity,
MATCH_STR
"Match BGP/VPN extended community list\n")
{
- return bgp_route_match_delete (vty, vty->index, "extcommunity", NULL);
+ return bgp_route_match_delete (vty, vty->index, "extcommunity", NULL,
+ RMAP_EVENT_ECLIST_DELETED);
}
ALIAS (no_match_ecommunity,
@@ -2840,7 +3415,8 @@ DEFUN (match_aspath,
"Match BGP AS path list\n"
"AS path access-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "as-path", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "as-path", argv[0],
+ RMAP_EVENT_ASLIST_ADDED);
}
DEFUN (no_match_aspath,
@@ -2850,7 +3426,8 @@ DEFUN (no_match_aspath,
MATCH_STR
"Match BGP AS path list\n")
{
- return bgp_route_match_delete (vty, vty->index, "as-path", NULL);
+ return bgp_route_match_delete (vty, vty->index, "as-path", NULL,
+ RMAP_EVENT_ASLIST_DELETED);
}
ALIAS (no_match_aspath,
@@ -2871,11 +3448,14 @@ DEFUN (match_origin,
"unknown heritage\n")
{
if (strncmp (argv[0], "igp", 2) == 0)
- return bgp_route_match_add (vty, vty->index, "origin", "igp");
+ return bgp_route_match_add (vty, vty->index, "origin", "igp",
+ RMAP_EVENT_MATCH_ADDED);
if (strncmp (argv[0], "egp", 1) == 0)
- return bgp_route_match_add (vty, vty->index, "origin", "egp");
+ return bgp_route_match_add (vty, vty->index, "origin", "egp",
+ RMAP_EVENT_MATCH_ADDED);
if (strncmp (argv[0], "incomplete", 2) == 0)
- return bgp_route_match_add (vty, vty->index, "origin", "incomplete");
+ return bgp_route_match_add (vty, vty->index, "origin", "incomplete",
+ RMAP_EVENT_MATCH_ADDED);
return CMD_WARNING;
}
@@ -2887,7 +3467,8 @@ DEFUN (no_match_origin,
MATCH_STR
"BGP origin code\n")
{
- return bgp_route_match_delete (vty, vty->index, "origin", NULL);
+ return bgp_route_match_delete (vty, vty->index, "origin", NULL,
+ RMAP_EVENT_MATCH_DELETED);
}
ALIAS (no_match_origin,
@@ -2900,6 +3481,75 @@ ALIAS (no_match_origin,
"local IGP\n"
"unknown heritage\n")
+DEFUN (match_interface,
+ match_interface_cmd,
+ "match interface WORD",
+ MATCH_STR
+ "Match first hop interface of route\n"
+ "Interface name\n")
+{
+ return bgp_route_match_add (vty, vty->index, "interface", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
+}
+
+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 bgp_route_match_delete (vty, vty->index, "interface", NULL,
+ RMAP_EVENT_MATCH_DELETED);
+
+ return bgp_route_match_delete (vty, vty->index, "interface", argv[0],
+ RMAP_EVENT_MATCH_DELETED);
+}
+
+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_tag,
+ match_tag_cmd,
+ "match tag <1-65535>",
+ MATCH_STR
+ "Match tag of route\n"
+ "Tag value\n")
+{
+ return bgp_route_match_add (vty, vty->index, "tag", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
+}
+
+DEFUN (no_match_tag,
+ no_match_tag_cmd,
+ "no match tag",
+ NO_STR
+ MATCH_STR
+ "Match tag of route\n")
+{
+ if (argc == 0)
+ return bgp_route_match_delete (vty, vty->index, "tag", NULL,
+ RMAP_EVENT_MATCH_DELETED);
+
+ return bgp_route_match_delete (vty, vty->index, "tag", argv[0],
+ RMAP_EVENT_MATCH_DELETED);
+}
+
+ALIAS (no_match_tag,
+ no_match_tag_val_cmd,
+ "no match tag <1-65535>",
+ NO_STR
+ MATCH_STR
+ "Match tag of route\n"
+ "Tag value\n")
+
+
DEFUN (set_ip_nexthop,
set_ip_nexthop_cmd,
"set ip next-hop A.B.C.D",
@@ -3313,7 +3963,7 @@ DEFUN (set_community_delete,
SET_STR
"set BGP community list (for deletion)\n"
"Community-list number (standard)\n"
- "Communitly-list number (expanded)\n"
+ "Community-list number (expanded)\n"
"Community-list name\n"
"Delete matching communities\n")
{
@@ -3346,7 +3996,7 @@ ALIAS (no_set_community_delete,
SET_STR
"set BGP community list (for deletion)\n"
"Community-list number (standard)\n"
- "Communitly-list number (expanded)\n"
+ "Community-list number (expanded)\n"
"Community-list name\n"
"Delete matching communities\n")
@@ -3565,6 +4215,38 @@ ALIAS (no_set_aggregator_as,
"AS number\n"
"IP address of aggregator\n")
+DEFUN (set_tag,
+ set_tag_cmd,
+ "set tag <1-65535>",
+ SET_STR
+ "Tag value for routing protocol\n"
+ "Tag value\n")
+{
+ return bgp_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)
+ bgp_route_set_delete(vty, vty->index, "tag", NULL);
+
+ return bgp_route_set_delete (vty, vty->index, "tag", argv[0]);
+}
+
+ALIAS (no_set_tag,
+ no_set_tag_val_cmd,
+ "no set tag <1-65535>",
+ NO_STR
+ SET_STR
+ "Tag value for routing protocol\n"
+ "Tag value\n")
+
+
DEFUN (match_ipv6_address,
match_ipv6_address_cmd,
"match ipv6 address WORD",
@@ -3573,7 +4255,8 @@ DEFUN (match_ipv6_address,
"Match IPv6 address of route\n"
"IPv6 access-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ipv6 address", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ipv6 address", argv[0],
+ RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ipv6_address,
@@ -3585,7 +4268,8 @@ DEFUN (no_match_ipv6_address,
"Match IPv6 address of route\n"
"IPv6 access-list name\n")
{
- return bgp_route_match_delete (vty, vty->index, "ipv6 address", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ipv6 address", argv[0],
+ RMAP_EVENT_FILTER_DELETED);
}
DEFUN (match_ipv6_next_hop,
@@ -3596,7 +4280,8 @@ DEFUN (match_ipv6_next_hop,
"Match IPv6 next-hop address of route\n"
"IPv6 address of next hop\n")
{
- return bgp_route_match_add (vty, vty->index, "ipv6 next-hop", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ipv6 next-hop", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
}
DEFUN (no_match_ipv6_next_hop,
@@ -3608,7 +4293,8 @@ DEFUN (no_match_ipv6_next_hop,
"Match IPv6 next-hop address of route\n"
"IPv6 address of next hop\n")
{
- return bgp_route_match_delete (vty, vty->index, "ipv6 next-hop", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ipv6 next-hop", argv[0],
+ RMAP_EVENT_MATCH_DELETED);
}
DEFUN (match_ipv6_address_prefix_list,
@@ -3620,7 +4306,8 @@ DEFUN (match_ipv6_address_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return bgp_route_match_add (vty, vty->index, "ipv6 address prefix-list", argv[0]);
+ return bgp_route_match_add (vty, vty->index, "ipv6 address prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ipv6_address_prefix_list,
@@ -3633,7 +4320,8 @@ DEFUN (no_match_ipv6_address_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]);
+ return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list",
+ argv[0], RMAP_EVENT_PLIST_DELETED);
}
DEFUN (set_ipv6_nexthop_peer,
@@ -3863,10 +4551,12 @@ bgp_route_map_init (void)
{
route_map_init ();
route_map_init_vty ();
- route_map_add_hook (bgp_route_map_update);
- route_map_delete_hook (bgp_route_map_update);
+ route_map_add_hook (bgp_route_map_add);
+ route_map_delete_hook (bgp_route_map_delete);
+ route_map_event_hook (bgp_route_map_event);
route_map_install_match (&route_match_peer_cmd);
+ route_map_install_match (&route_match_local_pref_cmd);
route_map_install_match (&route_match_ip_address_cmd);
route_map_install_match (&route_match_ip_next_hop_cmd);
route_map_install_match (&route_match_ip_route_source_cmd);
@@ -3876,9 +4566,12 @@ bgp_route_map_init (void)
route_map_install_match (&route_match_aspath_cmd);
route_map_install_match (&route_match_community_cmd);
route_map_install_match (&route_match_ecommunity_cmd);
+ route_map_install_match (&route_match_local_pref_cmd);
route_map_install_match (&route_match_metric_cmd);
route_map_install_match (&route_match_origin_cmd);
route_map_install_match (&route_match_probability_cmd);
+ route_map_install_match (&route_match_interface_cmd);
+ route_map_install_match (&route_match_tag_cmd);
route_map_install_set (&route_set_ip_nexthop_cmd);
route_map_install_set (&route_set_local_pref_cmd);
@@ -3895,6 +4588,7 @@ bgp_route_map_init (void)
route_map_install_set (&route_set_originator_id_cmd);
route_map_install_set (&route_set_ecommunity_rt_cmd);
route_map_install_set (&route_set_ecommunity_soo_cmd);
+ route_map_install_set (&route_set_tag_cmd);
install_element (RMAP_NODE, &match_peer_cmd);
install_element (RMAP_NODE, &match_peer_local_cmd);
@@ -3926,6 +4620,9 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &match_metric_cmd);
install_element (RMAP_NODE, &no_match_metric_cmd);
install_element (RMAP_NODE, &no_match_metric_val_cmd);
+ install_element (RMAP_NODE, &match_local_pref_cmd);
+ install_element (RMAP_NODE, &no_match_local_pref_cmd);
+ install_element (RMAP_NODE, &no_match_local_pref_val_cmd);
install_element (RMAP_NODE, &match_community_cmd);
install_element (RMAP_NODE, &match_community_exact_cmd);
install_element (RMAP_NODE, &no_match_community_cmd);
@@ -3940,6 +4637,12 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &match_probability_cmd);
install_element (RMAP_NODE, &no_match_probability_cmd);
install_element (RMAP_NODE, &no_match_probability_val_cmd);
+ install_element (RMAP_NODE, &match_interface_cmd);
+ install_element (RMAP_NODE, &no_match_interface_cmd);
+ install_element (RMAP_NODE, &no_match_interface_val_cmd);
+ install_element (RMAP_NODE, &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_ip_nexthop_cmd);
install_element (RMAP_NODE, &set_ip_nexthop_peer_cmd);
@@ -3991,6 +4694,9 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &set_originator_id_cmd);
install_element (RMAP_NODE, &no_set_originator_id_cmd);
install_element (RMAP_NODE, &no_set_originator_id_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);
route_map_install_match (&route_match_ipv6_address_cmd);
route_map_install_match (&route_match_ipv6_next_hop_cmd);
@@ -4024,3 +4730,15 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &no_match_pathlimit_as_cmd);
install_element (RMAP_NODE, &no_match_pathlimit_as_val_cmd);
}
+
+void
+bgp_route_map_terminate (void)
+{
+ /* ToDo: Cleanup all the used memory */
+
+ route_map_add_hook (NULL);
+ route_map_delete_hook (NULL);
+ route_map_event_hook (NULL);
+ route_map_finish();
+
+}
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index 92bb9575..e66e0451 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "sockunion.h"
#include "vty.h"
#include "filter.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
index bee12963..9531b69a 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -65,6 +65,7 @@ struct bgp_node
u_char flags;
#define BGP_NODE_PROCESS_SCHEDULED (1 << 0)
+#define BGP_NODE_USER_CLEAR (1 << 1)
};
/*
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 6db3dcb1..5476a669 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -50,6 +50,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_mpath.h"
+#include "bgpd/bgp_packet.h"
extern struct in_addr router_id_zebra;
@@ -166,15 +167,22 @@ peer_lookup_vty (struct vty *vty, const char *ip_str)
ret = str2sockunion (ip_str, &su);
if (ret < 0)
{
- vty_out (vty, "%% Malformed address: %s%s", ip_str, VTY_NEWLINE);
- return NULL;
+ peer = peer_lookup_by_conf_if (bgp, ip_str);
+ if (!peer)
+ {
+ vty_out (vty, "%% Malformed address or name: %s%s", ip_str, VTY_NEWLINE);
+ return NULL;
+ }
}
-
- peer = peer_lookup (bgp, &su);
- if (! peer)
+ else
{
- vty_out (vty, "%% Specify remote-as or peer-group commands first%s", VTY_NEWLINE);
- return NULL;
+ peer = peer_lookup (bgp, &su);
+ if (! peer)
+ {
+ vty_out (vty, "%% Specify remote-as or peer-group commands first%s",
+ VTY_NEWLINE);
+ return NULL;
+ }
}
return peer;
}
@@ -200,6 +208,10 @@ peer_and_group_lookup_vty (struct vty *vty, const char *peer_str)
}
else
{
+ peer = peer_lookup_by_conf_if (bgp, peer_str);
+ if (peer)
+ return peer;
+
group = peer_group_lookup (bgp, peer_str);
if (group)
return group->conf;
@@ -264,7 +276,7 @@ bgp_vty_return (struct vty *vty, int ret)
str = "Invalid command. Not an internal neighbor";
break;
case BGP_ERR_REMOVE_PRIVATE_AS:
- str = "Private AS cannot be removed for IBGP peers";
+ str = "remove-private-AS cannot be configured for IBGP peers";
break;
case BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP:
str = "Local-AS allowed only for EBGP peers";
@@ -281,6 +293,9 @@ bgp_vty_return (struct vty *vty, int ret)
case BGP_ERR_NO_IBGP_WITH_TTLHACK:
str = "ttl-security only allowed for EBGP peers";
break;
+ case BGP_ERR_AS_OVERRIDE:
+ str = "as-override cannot be configured for IBGP peers";
+ break;
}
if (str)
{
@@ -712,87 +727,408 @@ DEFUN (no_bgp_confederation_peers,
return CMD_SUCCESS;
}
-/* Maximum-paths configuration */
-DEFUN (bgp_maxpaths,
- bgp_maxpaths_cmd,
- "maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM),
- "Forward packets over multiple paths\n"
- "Number of paths\n")
+/**
+ * Central routine for maximum-paths configuration.
+ * @peer_type: BGP_PEER_EBGP or BGP_PEER_IBGP
+ * @set: 1 for setting values, 0 for removing the max-paths config.
+ */
+static int
+bgp_maxpaths_config_vty (struct vty *vty, int peer_type, const char *mpaths,
+ u_int16_t options, int set)
{
struct bgp *bgp;
- u_int16_t maxpaths;
+ u_int16_t maxpaths = 0;
int ret;
+ afi_t afi;
+ safi_t safi;
bgp = vty->index;
+ afi = bgp_node_afi (vty);
+ safi = bgp_node_safi (vty);
- VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, argv[0], 1, 255);
+ if (set)
+ {
+ VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, mpaths, 1,
+ BGP_MAXIMUM_MAXPATHS);
+ ret = bgp_maximum_paths_set (bgp, afi, safi, peer_type, maxpaths,
+ options);
+ }
+ else
+ ret = bgp_maximum_paths_unset (bgp, afi, safi, peer_type);
- ret = bgp_maximum_paths_set (bgp, bgp_node_afi (vty), bgp_node_safi(vty),
- BGP_PEER_EBGP, maxpaths);
if (ret < 0)
{
vty_out (vty,
- "%% Failed to set maximum-paths %u for afi %u, safi %u%s",
- maxpaths, bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE);
+ "%% Failed to %sset maximum-paths %s %u for afi %u, safi %u%s",
+ (set == 1) ? "" : "un",
+ (peer_type == BGP_PEER_EBGP) ? "ebgp" : "ibgp",
+ maxpaths, afi, safi, VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
-DEFUN (bgp_maxpaths_ibgp,
- bgp_maxpaths_ibgp_cmd,
- "maximum-paths ibgp " CMD_RANGE_STR(1, MULTIPATH_NUM),
- "Forward packets over multiple paths\n"
- "iBGP-multipath\n"
- "Number of paths\n")
+DEFUN (bgp_maxmed_admin,
+ bgp_maxmed_admin_cmd,
+ "bgp max-med administrative ",
+ BGP_STR
+ "Advertise routes with max-med\n"
+ "Administratively applied, for an indefinite period\n")
{
struct bgp *bgp;
- u_int16_t maxpaths;
- int ret;
bgp = vty->index;
- VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, argv[0], 1, 255);
+ bgp->v_maxmed_admin = 1;
+ bgp->maxmed_admin_value = BGP_MAXMED_VALUE_DEFAULT;
- ret = bgp_maximum_paths_set (bgp, bgp_node_afi (vty), bgp_node_safi(vty),
- BGP_PEER_IBGP, maxpaths);
- if (ret < 0)
+ bgp_maxmed_update(bgp);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (bgp_maxmed_admin_medv,
+ bgp_maxmed_admin_medv_cmd,
+ "bgp max-med administrative <0-4294967294>",
+ BGP_STR
+ "Advertise routes with max-med\n"
+ "Administratively applied, for an indefinite period\n"
+ "Max MED value to be used\n")
+{
+ struct bgp *bgp;
+
+ bgp = vty->index;
+
+ bgp->v_maxmed_admin = 1;
+ VTY_GET_INTEGER ("max-med admin med-value", bgp->maxmed_admin_value, argv[0]);
+
+ bgp_maxmed_update(bgp);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_maxmed_admin,
+ no_bgp_maxmed_admin_cmd,
+ "no bgp max-med administrative",
+ NO_STR
+ BGP_STR
+ "Advertise routes with max-med\n"
+ "Administratively applied, for an indefinite period\n")
+{
+ struct bgp *bgp;
+
+ bgp = vty->index;
+
+ bgp->v_maxmed_admin = BGP_MAXMED_ADMIN_UNCONFIGURED;
+ bgp->maxmed_admin_value = BGP_MAXMED_VALUE_DEFAULT;
+
+ bgp_maxmed_update(bgp);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_maxmed_admin,
+ no_bgp_maxmed_admin_medv_cmd,
+ "no bgp max-med administrative <0-4294967294>",
+ NO_STR
+ BGP_STR
+ "Advertise routes with max-med\n"
+ "Administratively applied, for an indefinite period\n"
+ "Max MED value to be used\n")
+
+
+DEFUN (bgp_maxmed_onstartup,
+ bgp_maxmed_onstartup_cmd,
+ "bgp max-med on-startup <5-86400>",
+ BGP_STR
+ "Advertise routes with max-med\n"
+ "Effective on a startup\n"
+ "Time (seconds) period for max-med\n")
+{
+ struct bgp *bgp;
+
+ bgp = vty->index;
+
+ if (argc != 1)
{
- vty_out (vty,
- "%% Failed to set maximum-paths ibgp %u for afi %u, safi %u%s",
- maxpaths, bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE);
+ vty_out (vty, "%% Must supply max-med on-startup period");
return CMD_WARNING;
}
+ VTY_GET_INTEGER ("max-med on-startup period", bgp->v_maxmed_onstartup, argv[0]);
+ bgp->maxmed_onstartup_value = BGP_MAXMED_VALUE_DEFAULT;
+
+ bgp_maxmed_update(bgp);
+
return CMD_SUCCESS;
}
-DEFUN (no_bgp_maxpaths,
- no_bgp_maxpaths_cmd,
- "no maximum-paths",
+DEFUN (bgp_maxmed_onstartup_medv,
+ bgp_maxmed_onstartup_medv_cmd,
+ "bgp max-med on-startup <5-86400> <0-4294967294>",
+ BGP_STR
+ "Advertise routes with max-med\n"
+ "Effective on a startup\n"
+ "Time (seconds) period for max-med\n"
+ "Max MED value to be used\n")
+{
+ struct bgp *bgp;
+
+ bgp = vty->index;
+
+ if (argc != 2)
+ {
+ vty_out (vty, "%% Must supply max-med on-startup period and med value");
+ return CMD_WARNING;
+ }
+
+ VTY_GET_INTEGER ("max-med on-startup period", bgp->v_maxmed_onstartup, argv[0]);
+ VTY_GET_INTEGER ("max-med on-startup med-value", bgp->maxmed_onstartup_value, argv[1]);
+
+ bgp_maxmed_update(bgp);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_maxmed_onstartup,
+ no_bgp_maxmed_onstartup_cmd,
+ "no bgp max-med on-startup",
NO_STR
- "Forward packets over multiple paths\n"
- "Number of paths\n")
+ BGP_STR
+ "Advertise routes with max-med\n"
+ "Effective on a startup\n")
{
struct bgp *bgp;
- int ret;
bgp = vty->index;
- ret = bgp_maximum_paths_unset (bgp, bgp_node_afi (vty), bgp_node_safi(vty),
- BGP_PEER_EBGP);
- if (ret < 0)
+ /* Cancel max-med onstartup if its on */
+ if (bgp->t_maxmed_onstartup)
{
- vty_out (vty,
- "%% Failed to unset maximum-paths for afi %u, safi %u%s",
- bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE);
+ THREAD_TIMER_OFF (bgp->t_maxmed_onstartup);
+ bgp->maxmed_onstartup_over = 1;
+ }
+
+ bgp->v_maxmed_onstartup = BGP_MAXMED_ONSTARTUP_UNCONFIGURED;
+ bgp->maxmed_onstartup_value = BGP_MAXMED_VALUE_DEFAULT;
+
+ bgp_maxmed_update(bgp);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_maxmed_onstartup,
+ no_bgp_maxmed_onstartup_period_cmd,
+ "no bgp max-med on-startup <5-86400>",
+ NO_STR
+ BGP_STR
+ "Advertise routes with max-med\n"
+ "Effective on a startup\n"
+ "Time (seconds) period for max-med\n")
+
+ALIAS (no_bgp_maxmed_onstartup,
+ no_bgp_maxmed_onstartup_period_medv_cmd,
+ "no bgp max-med on-startup <5-86400> <0-4294967294>",
+ NO_STR
+ BGP_STR
+ "Advertise routes with max-med\n"
+ "Effective on a startup\n"
+ "Time (seconds) period for max-med\n"
+ "Max MED value to be used\n")
+
+static int
+bgp_update_delay_config_vty (struct vty *vty, const char *delay,
+ const char *wait)
+{
+ struct bgp *bgp;
+ u_int16_t update_delay;
+ u_int16_t establish_wait;
+
+
+ bgp = vty->index;
+
+ VTY_GET_INTEGER_RANGE ("update-delay", update_delay, delay,
+ BGP_UPDATE_DELAY_MIN, BGP_UPDATE_DELAY_MAX);
+
+ if (!wait) /* update-delay <delay> */
+ {
+ bgp->v_update_delay = update_delay;
+ bgp->v_establish_wait = bgp->v_update_delay;
+ return CMD_SUCCESS;
+ }
+
+ /* update-delay <delay> <establish-wait> */
+ establish_wait = atoi (wait);
+ if (update_delay < establish_wait)
+ {
+ vty_out (vty, "%%Failed: update-delay less than the establish-wait!%s",
+ VTY_NEWLINE);
return CMD_WARNING;
}
+ bgp->v_update_delay = update_delay;
+ bgp->v_establish_wait = establish_wait;
+
+ return CMD_SUCCESS;
+}
+
+static int
+bgp_update_delay_deconfig_vty (struct vty *vty)
+{
+ struct bgp *bgp;
+
+ bgp = vty->index;
+
+ bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
+ bgp->v_establish_wait = bgp->v_update_delay;
+
+ return CMD_SUCCESS;
+}
+
+int
+bgp_config_write_update_delay (struct vty *vty, struct bgp *bgp)
+{
+ if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF)
+ {
+ vty_out (vty, " update-delay %d", bgp->v_update_delay);
+ if (bgp->v_update_delay != bgp->v_establish_wait)
+ vty_out (vty, " %d", bgp->v_establish_wait);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+
+/* Update-delay configuration */
+DEFUN (bgp_update_delay,
+ bgp_update_delay_cmd,
+ "update-delay <0-3600>",
+ "Force initial delay for best-path and updates\n"
+ "Seconds\n")
+{
+ return bgp_update_delay_config_vty(vty, argv[0], NULL);
+}
+
+DEFUN (bgp_update_delay_establish_wait,
+ bgp_update_delay_establish_wait_cmd,
+ "update-delay <0-3600> <1-3600>",
+ "Force initial delay for best-path and updates\n"
+ "Seconds\n"
+ "Wait for peers to be established\n"
+ "Seconds\n")
+{
+ return bgp_update_delay_config_vty(vty, argv[0], argv[1]);
+}
+
+/* Update-delay deconfiguration */
+DEFUN (no_bgp_update_delay,
+ no_bgp_update_delay_cmd,
+ "no update-delay <0-3600>",
+ "Force initial delay for best-path and updates\n"
+ "Seconds\n")
+{
+ return bgp_update_delay_deconfig_vty(vty);
+}
+
+ALIAS (no_bgp_update_delay,
+ no_bgp_update_delay_establish_wait_cmd,
+ "no update-delay <0-3600> <1-3600>",
+ "Force initial delay for best-path and updates\n"
+ "Seconds\n"
+ "Wait for peers to be established\n"
+ "Seconds\n")
+
+static int
+bgp_wpkt_quanta_config_vty (struct vty *vty, const char *num, char set)
+{
+ struct bgp *bgp;
+
+ bgp = vty->index;
+
+ if (set)
+ VTY_GET_INTEGER_RANGE ("write-quanta", bgp->wpkt_quanta, num,
+ 1, 10000);
+ else
+ bgp->wpkt_quanta = BGP_WRITE_PACKET_MAX;
+
return CMD_SUCCESS;
}
+int
+bgp_config_write_wpkt_quanta (struct vty *vty, struct bgp *bgp)
+{
+ if (bgp->wpkt_quanta != BGP_WRITE_PACKET_MAX)
+ vty_out (vty, " write-quanta %d%s",
+ bgp->wpkt_quanta, VTY_NEWLINE);
+
+ return 0;
+}
+
+
+/* Update-delay configuration */
+DEFUN (bgp_wpkt_quanta,
+ bgp_wpkt_quanta_cmd,
+ "write-quanta <1-10000>",
+ "How many packets to write to peer socket per run\n"
+ "Number of packets\n")
+{
+ return bgp_wpkt_quanta_config_vty(vty, argv[0], 1);
+}
+
+/* Update-delay deconfiguration */
+DEFUN (no_bgp_wpkt_quanta,
+ no_bgp_wpkt_quanta_cmd,
+ "no write-quanta <1-10000>",
+ "How many packets to write to peer socket per run\n"
+ "Number of packets\n")
+{
+ return bgp_wpkt_quanta_config_vty(vty, argv[0], 0);
+}
+
+/* Maximum-paths configuration */
+DEFUN (bgp_maxpaths,
+ bgp_maxpaths_cmd,
+ "maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM),
+ "Forward packets over multiple paths\n"
+ "Number of paths\n")
+{
+ return bgp_maxpaths_config_vty(vty, BGP_PEER_EBGP, argv[0], 0, 1);
+}
+
+DEFUN (bgp_maxpaths_ibgp,
+ bgp_maxpaths_ibgp_cmd,
+ "maximum-paths ibgp " CMD_RANGE_STR(1, MULTIPATH_NUM),
+ "Forward packets over multiple paths\n"
+ "iBGP-multipath\n"
+ "Number of paths\n")
+{
+ return bgp_maxpaths_config_vty(vty, BGP_PEER_IBGP, argv[0], 0, 1);
+}
+
+DEFUN (bgp_maxpaths_ibgp_cluster,
+ bgp_maxpaths_ibgp_cluster_cmd,
+ "maximum-paths ibgp " CMD_RANGE_STR(1, MULTIPATH_NUM) " equal-cluster-length",
+ "Forward packets over multiple paths\n"
+ "iBGP-multipath\n"
+ "Number of paths\n"
+ "Match the cluster length\n")
+{
+ return bgp_maxpaths_config_vty(vty, BGP_PEER_IBGP, argv[0],
+ BGP_FLAG_IBGP_MULTIPATH_SAME_CLUSTERLEN, 1);
+}
+
+DEFUN (no_bgp_maxpaths,
+ no_bgp_maxpaths_cmd,
+ "no maximum-paths",
+ NO_STR
+ "Forward packets over multiple paths\n"
+ "Number of paths\n")
+{
+ return bgp_maxpaths_config_vty(vty, BGP_PEER_EBGP, NULL, 0, 0);
+}
+
ALIAS (no_bgp_maxpaths,
no_bgp_maxpaths_arg_cmd,
"no maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM),
@@ -808,22 +1144,7 @@ DEFUN (no_bgp_maxpaths_ibgp,
"iBGP-multipath\n"
"Number of paths\n")
{
- struct bgp *bgp;
- int ret;
-
- bgp = vty->index;
-
- ret = bgp_maximum_paths_unset (bgp, bgp_node_afi (vty), bgp_node_safi(vty),
- BGP_PEER_IBGP);
- if (ret < 0)
- {
- vty_out (vty,
- "%% Failed to unset maximum-paths ibgp for afi %u, safi %u%s",
- bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
+ return bgp_maxpaths_config_vty(vty, BGP_PEER_IBGP, NULL, 0, 0);
}
ALIAS (no_bgp_maxpaths_ibgp,
@@ -834,6 +1155,15 @@ ALIAS (no_bgp_maxpaths_ibgp,
"iBGP-multipath\n"
"Number of paths\n")
+ALIAS (no_bgp_maxpaths_ibgp,
+ no_bgp_maxpaths_ibgp_cluster_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)
@@ -848,8 +1178,12 @@ bgp_config_write_maxpaths (struct vty *vty, struct bgp *bgp, afi_t afi,
if (bgp->maxpaths[afi][safi].maxpaths_ibgp != BGP_DEFAULT_MAXPATHS)
{
bgp_config_write_family_header (vty, afi, safi, write);
- vty_out (vty, " maximum-paths ibgp %d%s",
- bgp->maxpaths[afi][safi].maxpaths_ibgp, VTY_NEWLINE);
+ vty_out (vty, " maximum-paths ibgp %d",
+ bgp->maxpaths[afi][safi].maxpaths_ibgp);
+ if (CHECK_FLAG (bgp->maxpaths[afi][safi].ibgp_flags,
+ BGP_FLAG_IBGP_MULTIPATH_SAME_CLUSTERLEN))
+ vty_out (vty, " equal-cluster-length");
+ vty_out (vty, "%s", VTY_NEWLINE);
}
return 0;
@@ -1483,6 +1817,80 @@ ALIAS (no_bgp_default_local_preference,
"local preference (higher=more preferred)\n"
"Configure default local preference value\n")
+static void
+peer_announce_routes_if_rmap_out (struct bgp *bgp)
+{
+ struct peer *peer;
+ struct listnode *node, *nnode;
+ struct bgp_filter *filter;
+ afi_t afi;
+ safi_t safi;
+
+ /* Reannounce all routes to appropriate neighbors */
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
+ {
+ /* check if there's an out route-map on this client */
+ filter = &peer->filter[afi][safi];
+ if (ROUTE_MAP_OUT_NAME(filter))
+ {
+ if (bgp_debug_update(peer, NULL, 0))
+ zlog_debug("%s: Announcing routes again for peer %s"
+ "(afi=%d, safi=%d", __func__, peer->host, afi,
+ safi);
+
+ bgp_announce_route_all(peer);
+ }
+ }
+ }
+ }
+}
+
+DEFUN (bgp_rr_allow_outbound_policy,
+ bgp_rr_allow_outbound_policy_cmd,
+ "bgp route-reflector allow-outbound-policy",
+ "BGP specific commands\n"
+ "Allow modifications made by out route-map\n"
+ "on ibgp neighbors\n")
+{
+ struct bgp *bgp;
+
+ bgp = vty->index;
+
+ if (!bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY))
+ {
+ bgp_flag_set(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY);
+ peer_announce_routes_if_rmap_out(bgp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_rr_allow_outbound_policy,
+ no_bgp_rr_allow_outbound_policy_cmd,
+ "no bgp route-reflector allow-outbound-policy",
+ NO_STR
+ "BGP specific commands\n"
+ "Allow modifications made by out route-map\n"
+ "on ibgp neighbors\n")
+{
+ struct bgp *bgp;
+
+ bgp = vty->index;
+
+ if (bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY))
+ {
+ bgp_flag_unset(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY);
+ peer_announce_routes_if_rmap_out(bgp);
+ }
+
+ return CMD_SUCCESS;
+}
+
static int
peer_remote_as_vty (struct vty *vty, const char *peer_str,
const char *as_str, afi_t afi, safi_t safi)
@@ -1501,24 +1909,31 @@ peer_remote_as_vty (struct vty *vty, const char *peer_str,
ret = str2sockunion (peer_str, &su);
if (ret < 0)
{
- ret = peer_group_remote_as (bgp, peer_str, &as);
+ /* Check for peer by interface */
+ ret = peer_remote_as (bgp, NULL, peer_str, &as, afi, safi);
if (ret < 0)
- {
- vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- return CMD_SUCCESS;
+ {
+ ret = peer_group_remote_as (bgp, peer_str, &as);
+ if (ret < 0)
+ {
+ vty_out (vty, "%% Create the peer-group or interface first%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+ }
}
-
- if (peer_address_self_check (&su))
+ else
{
- vty_out (vty, "%% Can not configure the local system as neighbor%s",
- VTY_NEWLINE);
- return CMD_WARNING;
+ if (peer_address_self_check (&su))
+ {
+ vty_out (vty, "%% Can not configure the local system as neighbor%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ ret = peer_remote_as (bgp, &su, NULL, &as, afi, safi);
}
- ret = peer_remote_as (bgp, &su, &as, afi, safi);
-
/* This peer belongs to peer group. */
switch (ret)
{
@@ -1543,17 +1958,51 @@ DEFUN (neighbor_remote_as,
return peer_remote_as_vty (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST);
}
+DEFUN (neighbor_interface_config,
+ neighbor_interface_config_cmd,
+ "neighbor WORD interface",
+ NEIGHBOR_STR
+ "Interface name or neighbor tag\n"
+ "Enable BGP on interface\n")
+{
+ struct bgp *bgp;
+ struct peer *peer;
+ struct peer_group *group;
+
+ bgp = vty->index;
+ group = peer_group_lookup (bgp, argv[0]);
+ if (group)
+ {
+ vty_out (vty, "%% Name conflict with peer-group %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ peer = peer_conf_interface_get (bgp, argv[0], AFI_IP, SAFI_UNICAST);
+ if (!peer)
+ return CMD_WARNING;
+
+ return CMD_SUCCESS;
+}
+
+
DEFUN (neighbor_peer_group,
neighbor_peer_group_cmd,
"neighbor WORD peer-group",
NEIGHBOR_STR
- "Neighbor tag\n"
+ "Interface name or neighbor tag\n"
"Configure peer-group\n")
{
struct bgp *bgp;
+ struct peer *peer;
struct peer_group *group;
bgp = vty->index;
+ peer = peer_lookup_by_conf_if (bgp, argv[0]);
+ if (peer)
+ {
+ vty_out (vty, "%% Name conflict with interface: %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
group = peer_group_get (bgp, argv[0]);
if (! group)
@@ -1573,10 +2022,19 @@ DEFUN (no_neighbor,
union sockunion su;
struct peer_group *group;
struct peer *peer;
+ struct peer *other;
ret = str2sockunion (argv[0], &su);
if (ret < 0)
{
+ /* look up for neighbor by interface name config. */
+ peer = peer_lookup_by_conf_if (vty->index, argv[0]);
+ if (peer)
+ {
+ peer_delete (peer);
+ return CMD_SUCCESS;
+ }
+
group = peer_group_lookup (vty->index, argv[0]);
if (group)
peer_group_delete (group);
@@ -1590,7 +2048,12 @@ DEFUN (no_neighbor,
{
peer = peer_lookup (vty->index, &su);
if (peer)
- peer_delete (peer);
+ {
+ other = peer->doppelganger;
+ peer_delete (peer);
+ if (other && other->status != Deleted)
+ peer_delete(other);
+ }
}
return CMD_SUCCESS;
@@ -1605,6 +2068,30 @@ ALIAS (no_neighbor,
"Specify a BGP neighbor\n"
AS_STR)
+DEFUN (no_neighbor_interface_config,
+ no_neighbor_interface_config_cmd,
+ "no neighbor WORD interface",
+ NO_STR
+ NEIGHBOR_STR
+ "Interface name\n"
+ "Configure BGP on interface\n")
+{
+ struct peer *peer;
+
+ /* look up for neighbor by interface name config. */
+ peer = peer_lookup_by_conf_if (vty->index, argv[0]);
+ if (peer)
+ {
+ peer_delete (peer);
+ }
+ else
+ {
+ vty_out (vty, "%% Create the bgp interface first%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
DEFUN (no_neighbor_peer_group,
no_neighbor_peer_group_cmd,
"no neighbor WORD peer-group",
@@ -1626,23 +2113,32 @@ DEFUN (no_neighbor_peer_group,
return CMD_SUCCESS;
}
-DEFUN (no_neighbor_peer_group_remote_as,
- no_neighbor_peer_group_remote_as_cmd,
+DEFUN (no_neighbor_interface_peer_group_remote_as,
+ no_neighbor_interface_peer_group_remote_as_cmd,
"no neighbor WORD remote-as " CMD_AS_RANGE,
NO_STR
NEIGHBOR_STR
- "Neighbor tag\n"
+ "Interface name or neighbor tag\n"
"Specify a BGP neighbor\n"
AS_STR)
{
struct peer_group *group;
+ struct peer *peer;
+
+ /* look up for neighbor by interface name config. */
+ peer = peer_lookup_by_conf_if (vty->index, argv[0]);
+ if (peer)
+ {
+ peer_as_change (peer, 0);
+ return CMD_SUCCESS;
+ }
group = peer_group_lookup (vty->index, argv[0]);
if (group)
peer_group_remote_as_delete (group);
else
{
- vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE);
+ vty_out (vty, "%% Create the peer-group or interface first%s", VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
@@ -1837,9 +2333,9 @@ DEFUN (no_neighbor_activate,
DEFUN (neighbor_set_peer_group,
neighbor_set_peer_group_cmd,
- NEIGHBOR_CMD "peer-group WORD",
+ NEIGHBOR_CMD2 "peer-group WORD",
NEIGHBOR_STR
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR2
"Member of the peer-group\n"
"peer-group name\n")
{
@@ -1847,15 +2343,30 @@ DEFUN (neighbor_set_peer_group,
as_t as;
union sockunion su;
struct bgp *bgp;
+ struct peer *peer;
struct peer_group *group;
bgp = vty->index;
+ peer = NULL;
ret = str2sockunion (argv[0], &su);
if (ret < 0)
{
- vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE);
- return CMD_WARNING;
+ peer = peer_lookup_by_conf_if (bgp, argv[0]);
+ if (!peer)
+ {
+ vty_out (vty, "%% Malformed address or name: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ else
+ {
+ if (peer_address_self_check (&su))
+ {
+ vty_out (vty, "%% Can not configure the local system as neighbor%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
}
group = peer_group_lookup (bgp, argv[1]);
@@ -1865,14 +2376,7 @@ DEFUN (neighbor_set_peer_group,
return CMD_WARNING;
}
- if (peer_address_self_check (&su))
- {
- vty_out (vty, "%% Can not configure the local system as neighbor%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- ret = peer_group_bind (bgp, &su, group, bgp_node_afi (vty),
+ ret = peer_group_bind (bgp, &su, peer, group, bgp_node_afi (vty),
bgp_node_safi (vty), &as);
if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT)
@@ -1886,10 +2390,10 @@ DEFUN (neighbor_set_peer_group,
DEFUN (no_neighbor_set_peer_group,
no_neighbor_set_peer_group_cmd,
- NO_NEIGHBOR_CMD "peer-group WORD",
+ NO_NEIGHBOR_CMD2 "peer-group WORD",
NO_STR
NEIGHBOR_STR
- NEIGHBOR_ADDR_STR
+ NEIGHBOR_ADDR_STR2
"Member of the peer-group\n"
"peer-group name\n")
{
@@ -2191,32 +2695,143 @@ DEFUN (no_neighbor_nexthop_self,
PEER_FLAG_NEXTHOP_SELF|PEER_FLAG_NEXTHOP_SELF_ALL);
}
+/* neighbor as-override */
+DEFUN (neighbor_as_override,
+ neighbor_as_override_cmd,
+ NEIGHBOR_CMD2 "as-override",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Override ASNs in outbound updates if aspath equals remote-as\n")
+{
+ return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_AS_OVERRIDE);
+}
+
+DEFUN (no_neighbor_as_override,
+ no_neighbor_as_override_cmd,
+ NO_NEIGHBOR_CMD2 "as-override",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Override ASNs in outbound updates if aspath equals remote-as\n")
+{
+ return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_AS_OVERRIDE);
+}
+
/* neighbor remove-private-AS. */
DEFUN (neighbor_remove_private_as,
neighbor_remove_private_as_cmd,
NEIGHBOR_CMD2 "remove-private-AS",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
- "Remove private AS number from outbound updates\n")
+ "Remove private ASNs in outbound updates\n")
{
+ peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_REMOVE_PRIVATE_AS_ALL|
+ PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE);
return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
bgp_node_safi (vty),
PEER_FLAG_REMOVE_PRIVATE_AS);
}
+DEFUN (neighbor_remove_private_as_all,
+ neighbor_remove_private_as_all_cmd,
+ NEIGHBOR_CMD2 "remove-private-AS all",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Remove private ASNs in outbound updates\n"
+ "Apply to all AS numbers")
+{
+ peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE);
+ return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_REMOVE_PRIVATE_AS|
+ PEER_FLAG_REMOVE_PRIVATE_AS_ALL);
+}
+
+DEFUN (neighbor_remove_private_as_replace_as,
+ neighbor_remove_private_as_replace_as_cmd,
+ NEIGHBOR_CMD2 "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")
+{
+ peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_REMOVE_PRIVATE_AS_ALL);
+ return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_REMOVE_PRIVATE_AS|
+ PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE);
+}
+
+DEFUN (neighbor_remove_private_as_all_replace_as,
+ neighbor_remove_private_as_all_replace_as_cmd,
+ NEIGHBOR_CMD2 "remove-private-AS all replace-AS",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Remove private ASNs in outbound updates\n"
+ "Apply to all AS numbers"
+ "Replace private ASNs with our ASN in outbound updates\n")
+{
+ return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_REMOVE_PRIVATE_AS|
+ PEER_FLAG_REMOVE_PRIVATE_AS_ALL|
+ PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE);
+}
+
DEFUN (no_neighbor_remove_private_as,
no_neighbor_remove_private_as_cmd,
NO_NEIGHBOR_CMD2 "remove-private-AS",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
- "Remove private AS number from outbound updates\n")
+ "Remove private ASNs in outbound updates\n")
{
return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
bgp_node_safi (vty),
- PEER_FLAG_REMOVE_PRIVATE_AS);
+ PEER_FLAG_REMOVE_PRIVATE_AS|
+ PEER_FLAG_REMOVE_PRIVATE_AS_ALL|
+ PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE);
}
+ALIAS (no_neighbor_remove_private_as,
+ no_neighbor_remove_private_as_all_cmd,
+ NO_NEIGHBOR_CMD2 "remove-private-AS all",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Remove private ASNs in outbound updates\n"
+ "Apply to all AS numbers")
+
+ALIAS (no_neighbor_remove_private_as,
+ no_neighbor_remove_private_as_replace_as_cmd,
+ NO_NEIGHBOR_CMD2 "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")
+
+ALIAS (no_neighbor_remove_private_as,
+ no_neighbor_remove_private_as_all_replace_as_cmd,
+ NO_NEIGHBOR_CMD2 "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"
+ "Replace private ASNs with our ASN in outbound updates\n")
+
+
/* neighbor send-community. */
DEFUN (neighbor_send_community,
neighbor_send_community_cmd,
@@ -3090,6 +3705,9 @@ peer_update_source_vty (struct vty *vty, const char *peer_str,
if (! peer)
return CMD_WARNING;
+ if (peer->conf_if)
+ return CMD_WARNING;
+
if (source_str)
{
union sockunion su;
@@ -3539,6 +4157,54 @@ ALIAS (no_neighbor_advertise_interval,
"Minimum interval between sending BGP routing updates\n"
"time in seconds\n")
+/* Time to wait before processing route-map updates */
+DEFUN (bgp_set_route_map_delay_timer,
+ bgp_set_route_map_delay_timer_cmd,
+ "bgp route-map delay-timer <0-600>",
+ SET_STR
+ "BGP route-map delay timer\n"
+ "Time in secs to wait before processing route-map changes\n"
+ "0 disables the timer and no route updates happen when\n"
+ "route-maps change")
+{
+ u_int32_t rmap_delay_timer;
+ struct bgp *bgp;
+
+ bgp = vty->index;
+ if (argv[0])
+ {
+ VTY_GET_INTEGER_RANGE ("delay-timer", rmap_delay_timer, argv[0], 0, 600);
+ bgp->rmap_update_timer = rmap_delay_timer;
+
+ /* if the dynamic update handling is being disabled, and a timer is
+ * running, stop the timer and act as if the timer has already fired.
+ */
+ if (!rmap_delay_timer && bgp->t_rmap_update )
+ {
+ BGP_TIMER_OFF(bgp->t_rmap_update);
+ thread_execute (bm->master, bgp_route_map_update_timer, &bgp, 0);
+ }
+ return CMD_SUCCESS;
+ }
+ else
+ return CMD_WARNING;
+}
+
+DEFUN (no_bgp_set_route_map_delay_timer,
+ no_bgp_set_route_map_delay_timer_cmd,
+ "no bgp route-map delay-timer",
+ NO_STR
+ "Default BGP route-map delay timer\n"
+ "Reset to default time to wait for processing route-map changes")
+{
+ struct bgp *bgp;
+
+ bgp = vty->index;
+ bgp->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER;
+
+ return CMD_SUCCESS;
+}
+
/* neighbor interface */
static int
peer_interface_vty (struct vty *vty, const char *ip_str, const char *str)
@@ -3547,7 +4213,7 @@ peer_interface_vty (struct vty *vty, const char *ip_str, const char *str)
struct peer *peer;
peer = peer_lookup_vty (vty, ip_str);
- if (! peer)
+ if (! peer || peer->conf_if)
return CMD_WARNING;
if (str)
@@ -4437,18 +5103,27 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
struct listnode *node, *nnode;
/* Clear all neighbors. */
+ /*
+ * Pass along pointer to next node to peer_clear() when walking all nodes
+ * on the BGP instance as that may get freed if it is a doppelganger
+ */
if (sort == clear_all)
{
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
if (stype == BGP_CLEAR_SOFT_NONE)
- ret = peer_clear (peer);
+ ret = peer_clear (peer, &nnode);
else
ret = peer_clear_soft (peer, afi, safi, stype);
if (ret < 0)
bgp_clear_vty_error (vty, peer, afi, safi, ret);
}
+
+ /* This is to apply read-only mode on this clear. */
+ if (stype == BGP_CLEAR_SOFT_NONE)
+ bgp->update_delay_over = 0;
+
return CMD_SUCCESS;
}
@@ -4461,19 +5136,26 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
/* Make sockunion for lookup. */
ret = str2sockunion (arg, &su);
if (ret < 0)
- {
- vty_out (vty, "Malformed address: %s%s", arg, VTY_NEWLINE);
- return CMD_WARNING;
- }
- peer = peer_lookup (bgp, &su);
- if (! peer)
- {
- vty_out (vty, "%%BGP: Unknown neighbor - \"%s\"%s", arg, VTY_NEWLINE);
- return CMD_WARNING;
- }
+ {
+ peer = peer_lookup_by_conf_if (bgp, arg);
+ if (!peer)
+ {
+ vty_out (vty, "Malformed address or name: %s%s", arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ else
+ {
+ peer = peer_lookup (bgp, &su);
+ if (! peer)
+ {
+ vty_out (vty, "%%BGP: Unknown neighbor - \"%s\"%s", arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
if (stype == BGP_CLEAR_SOFT_NONE)
- ret = peer_clear (peer);
+ ret = peer_clear (peer, NULL);
else
ret = peer_clear_soft (peer, afi, safi, stype);
@@ -4499,7 +5181,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
{
if (stype == BGP_CLEAR_SOFT_NONE)
{
- ret = peer_clear (peer);
+ ret = peer_clear (peer, NULL);
continue;
}
@@ -4522,7 +5204,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
continue;
if (stype == BGP_CLEAR_SOFT_NONE)
- ret = peer_clear (peer);
+ ret = peer_clear (peer, &nnode);
else
ret = peer_clear_soft (peer, afi, safi, stype);
@@ -4546,7 +5228,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
find = 1;
if (stype == BGP_CLEAR_SOFT_NONE)
- ret = peer_clear (peer);
+ ret = peer_clear (peer, &nnode);
else
ret = peer_clear_soft (peer, afi, safi, stype);
@@ -4562,6 +5244,87 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
return CMD_SUCCESS;
}
+/* Recalculate bestpath and re-advertise a prefix */
+static int
+bgp_clear_prefix (struct vty *vty, char *view_name, const char *ip_str,
+ afi_t afi, safi_t safi, struct prefix_rd *prd)
+{
+ int ret;
+ struct prefix match;
+ struct bgp_node *rn;
+ struct bgp_node *rm;
+ struct bgp *bgp;
+ struct bgp_table *table;
+ struct bgp_table *rib;
+
+ /* BGP structure lookup. */
+ if (view_name)
+ {
+ bgp = bgp_lookup_by_name (view_name);
+ if (bgp == NULL)
+ {
+ vty_out (vty, "%% Can't find BGP view %s%s", view_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ else
+ {
+ bgp = bgp_get_default ();
+ if (bgp == NULL)
+ {
+ vty_out (vty, "%% No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ /* Check IP address argument. */
+ ret = str2prefix (ip_str, &match);
+ if (! ret)
+ {
+ vty_out (vty, "%% address is malformed%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ match.family = afi2family (afi);
+ rib = bgp->rib[afi][safi];
+
+ if (safi == SAFI_MPLS_VPN)
+ {
+ for (rn = bgp_table_top (rib); rn; rn = bgp_route_next (rn))
+ {
+ if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
+ continue;
+
+ if ((table = rn->info) != NULL)
+ {
+ if ((rm = bgp_node_match (table, &match)) != NULL)
+ {
+ if (rm->p.prefixlen == match.prefixlen)
+ {
+ SET_FLAG (rn->flags, BGP_NODE_USER_CLEAR);
+ bgp_process (bgp, rm, afi, safi);
+ }
+ bgp_unlock_node (rm);
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((rn = bgp_node_match (rib, &match)) != NULL)
+ {
+ if (rn->p.prefixlen == match.prefixlen)
+ {
+ SET_FLAG (rn->flags, BGP_NODE_USER_CLEAR);
+ bgp_process (bgp, rn, afi, safi);
+ }
+ bgp_unlock_node (rn);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
static int
bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi,
enum clear_sort sort, enum bgp_clear_type stype,
@@ -4642,32 +5405,35 @@ ALIAS (clear_ip_bgp_all,
DEFUN (clear_ip_bgp_peer,
clear_ip_bgp_peer_cmd,
- "clear ip bgp (A.B.C.D|X:X::X:X)",
+ "clear ip bgp (A.B.C.D|X:X::X:X|WORD)",
CLEAR_STR
IP_STR
BGP_STR
"BGP neighbor IP address to clear\n"
- "BGP IPv6 neighbor to clear\n")
+ "BGP IPv6 neighbor to clear\n"
+ "BGP neighbor on interface to clear\n")
{
return bgp_clear_vty (vty, NULL, 0, 0, clear_peer, BGP_CLEAR_SOFT_NONE, argv[0]);
}
ALIAS (clear_ip_bgp_peer,
clear_bgp_peer_cmd,
- "clear bgp (A.B.C.D|X:X::X:X)",
+ "clear bgp (A.B.C.D|X:X::X:X|WORD)",
CLEAR_STR
BGP_STR
"BGP neighbor address to clear\n"
- "BGP IPv6 neighbor to clear\n")
+ "BGP IPv6 neighbor to clear\n"
+ "BGP neighbor on interface to clear\n")
ALIAS (clear_ip_bgp_peer,
clear_bgp_ipv6_peer_cmd,
- "clear bgp ipv6 (A.B.C.D|X:X::X:X)",
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X|WORD)",
CLEAR_STR
BGP_STR
"Address family\n"
"BGP neighbor address to clear\n"
- "BGP IPv6 neighbor to clear\n")
+ "BGP IPv6 neighbor to clear\n"
+ "BGP neighbor on interface to clear\n")
DEFUN (clear_ip_bgp_peer_group,
clear_ip_bgp_peer_group_cmd,
@@ -4724,6 +5490,27 @@ ALIAS (clear_ip_bgp_external,
"Address family\n"
"Clear all external peers\n")
+DEFUN (clear_ip_bgp_prefix,
+ clear_ip_bgp_prefix_cmd,
+ "clear ip bgp prefix A.B.C.D/M",
+ CLEAR_STR
+ IP_STR
+ BGP_STR
+ "Clear bestpath and re-advertise\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ return bgp_clear_prefix (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL);
+}
+
+ALIAS (clear_ip_bgp_prefix,
+ clear_bgp_prefix_cmd,
+ "clear bgp prefix A.B.C.D/M",
+ CLEAR_STR
+ BGP_STR
+ "Clear bestpath and re-advertise\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
+
DEFUN (clear_ip_bgp_as,
clear_ip_bgp_as_cmd,
"clear ip bgp " CMD_AS_RANGE,
@@ -4758,8 +5545,8 @@ DEFUN (clear_ip_bgp_all_soft_out,
IP_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
if (argc == 1)
return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all,
@@ -4776,7 +5563,7 @@ ALIAS (clear_ip_bgp_all_soft_out,
IP_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
ALIAS (clear_ip_bgp_all_soft_out,
clear_ip_bgp_instance_all_soft_out_cmd,
@@ -4787,8 +5574,8 @@ ALIAS (clear_ip_bgp_all_soft_out,
"BGP view\n"
"view name\n"
"Clear all peers\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_all_ipv4_soft_out,
clear_ip_bgp_all_ipv4_soft_out_cmd,
@@ -4800,8 +5587,8 @@ DEFUN (clear_ip_bgp_all_ipv4_soft_out,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
if (strncmp (argv[0], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all,
@@ -4821,7 +5608,7 @@ ALIAS (clear_ip_bgp_all_ipv4_soft_out,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_instance_all_ipv4_soft_out,
clear_ip_bgp_instance_all_ipv4_soft_out_cmd,
@@ -4835,7 +5622,7 @@ DEFUN (clear_ip_bgp_instance_all_ipv4_soft_out,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
{
if (strncmp (argv[1], "m", 1) == 0)
return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all,
@@ -4854,8 +5641,8 @@ DEFUN (clear_ip_bgp_all_vpnv4_soft_out,
"Clear all peers\n"
"Address family\n"
"Address Family Modifier\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all,
BGP_CLEAR_SOFT_OUT, NULL);
@@ -4870,7 +5657,7 @@ ALIAS (clear_ip_bgp_all_vpnv4_soft_out,
"Clear all peers\n"
"Address family\n"
"Address Family Modifier\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_all_encap_soft_out,
clear_ip_bgp_all_encap_soft_out_cmd,
@@ -4905,8 +5692,8 @@ DEFUN (clear_bgp_all_soft_out,
CLEAR_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
if (argc == 1)
return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all,
@@ -4924,8 +5711,8 @@ ALIAS (clear_bgp_all_soft_out,
"BGP view\n"
"view name\n"
"Clear all peers\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
ALIAS (clear_bgp_all_soft_out,
clear_bgp_all_out_cmd,
@@ -4933,7 +5720,7 @@ ALIAS (clear_bgp_all_soft_out,
CLEAR_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
ALIAS (clear_bgp_all_soft_out,
clear_bgp_ipv6_all_soft_out_cmd,
@@ -4942,8 +5729,8 @@ ALIAS (clear_bgp_all_soft_out,
BGP_STR
"Address family\n"
"Clear all peers\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
ALIAS (clear_bgp_all_soft_out,
clear_bgp_ipv6_all_out_cmd,
@@ -4952,7 +5739,23 @@ ALIAS (clear_bgp_all_soft_out,
BGP_STR
"Address family\n"
"Clear all peers\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
+
+DEFUN (clear_bgp_ipv6_safi_prefix,
+ clear_bgp_ipv6_safi_prefix_cmd,
+ "clear bgp ipv6 (unicast|multicast) prefix X:X::X:X/M",
+ CLEAR_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family Modifier\n"
+ "Clear bestpath and re-advertise\n"
+ "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+ if (strncmp (argv[0], "m", 1) == 0)
+ return bgp_clear_prefix (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL);
+ else
+ return bgp_clear_prefix (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL);
+}
DEFUN (clear_ip_bgp_peer_soft_out,
clear_ip_bgp_peer_soft_out_cmd,
@@ -4961,8 +5764,8 @@ DEFUN (clear_ip_bgp_peer_soft_out,
IP_STR
BGP_STR
"BGP neighbor address to clear\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer,
BGP_CLEAR_SOFT_OUT, argv[0]);
@@ -4975,7 +5778,7 @@ ALIAS (clear_ip_bgp_peer_soft_out,
IP_STR
BGP_STR
"BGP neighbor address to clear\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_peer_ipv4_soft_out,
clear_ip_bgp_peer_ipv4_soft_out_cmd,
@@ -4987,8 +5790,8 @@ DEFUN (clear_ip_bgp_peer_ipv4_soft_out,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
if (strncmp (argv[1], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer,
@@ -5008,7 +5811,7 @@ ALIAS (clear_ip_bgp_peer_ipv4_soft_out,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_peer_vpnv4_soft_out,
clear_ip_bgp_peer_vpnv4_soft_out_cmd,
@@ -5019,8 +5822,8 @@ DEFUN (clear_ip_bgp_peer_vpnv4_soft_out,
"BGP neighbor address to clear\n"
"Address family\n"
"Address Family Modifier\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer,
BGP_CLEAR_SOFT_OUT, argv[0]);
@@ -5035,7 +5838,7 @@ ALIAS (clear_ip_bgp_peer_vpnv4_soft_out,
"BGP neighbor address to clear\n"
"Address family\n"
"Address Family Modifier\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_peer_encap_soft_out,
clear_ip_bgp_peer_encap_soft_out_cmd,
@@ -5066,13 +5869,14 @@ ALIAS (clear_ip_bgp_peer_encap_soft_out,
DEFUN (clear_bgp_peer_soft_out,
clear_bgp_peer_soft_out_cmd,
- "clear bgp (A.B.C.D|X:X::X:X) soft out",
+ "clear bgp (A.B.C.D|X:X::X:X|WORD) soft out",
CLEAR_STR
BGP_STR
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer,
BGP_CLEAR_SOFT_OUT, argv[0]);
@@ -5080,33 +5884,36 @@ DEFUN (clear_bgp_peer_soft_out,
ALIAS (clear_bgp_peer_soft_out,
clear_bgp_ipv6_peer_soft_out_cmd,
- "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft out",
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X|WORD) soft out",
CLEAR_STR
BGP_STR
"Address family\n"
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
ALIAS (clear_bgp_peer_soft_out,
clear_bgp_peer_out_cmd,
- "clear bgp (A.B.C.D|X:X::X:X) out",
+ "clear bgp (A.B.C.D|X:X::X:X|WORD) out",
CLEAR_STR
BGP_STR
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig outbound update\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_OUT_STR)
ALIAS (clear_bgp_peer_soft_out,
clear_bgp_ipv6_peer_out_cmd,
- "clear bgp ipv6 (A.B.C.D|X:X::X:X) out",
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X|WORD) out",
CLEAR_STR
BGP_STR
"Address family\n"
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig outbound update\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_peer_group_soft_out,
clear_ip_bgp_peer_group_soft_out_cmd,
@@ -5116,8 +5923,8 @@ DEFUN (clear_ip_bgp_peer_group_soft_out,
BGP_STR
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group,
BGP_CLEAR_SOFT_OUT, argv[0]);
@@ -5131,7 +5938,7 @@ ALIAS (clear_ip_bgp_peer_group_soft_out,
BGP_STR
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_peer_group_ipv4_soft_out,
clear_ip_bgp_peer_group_ipv4_soft_out_cmd,
@@ -5144,8 +5951,8 @@ DEFUN (clear_ip_bgp_peer_group_ipv4_soft_out,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
if (strncmp (argv[1], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group,
@@ -5166,7 +5973,7 @@ ALIAS (clear_ip_bgp_peer_group_ipv4_soft_out,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_bgp_peer_group_soft_out,
clear_bgp_peer_group_soft_out_cmd,
@@ -5175,8 +5982,8 @@ DEFUN (clear_bgp_peer_group_soft_out,
BGP_STR
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group,
BGP_CLEAR_SOFT_OUT, argv[0]);
@@ -5190,8 +5997,8 @@ ALIAS (clear_bgp_peer_group_soft_out,
"Address family\n"
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
ALIAS (clear_bgp_peer_group_soft_out,
clear_bgp_peer_group_out_cmd,
@@ -5200,7 +6007,7 @@ ALIAS (clear_bgp_peer_group_soft_out,
BGP_STR
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
ALIAS (clear_bgp_peer_group_soft_out,
clear_bgp_ipv6_peer_group_out_cmd,
@@ -5210,7 +6017,7 @@ ALIAS (clear_bgp_peer_group_soft_out,
"Address family\n"
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_external_soft_out,
clear_ip_bgp_external_soft_out_cmd,
@@ -5219,8 +6026,8 @@ DEFUN (clear_ip_bgp_external_soft_out,
IP_STR
BGP_STR
"Clear all external peers\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external,
BGP_CLEAR_SOFT_OUT, NULL);
@@ -5233,7 +6040,7 @@ ALIAS (clear_ip_bgp_external_soft_out,
IP_STR
BGP_STR
"Clear all external peers\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_external_ipv4_soft_out,
clear_ip_bgp_external_ipv4_soft_out_cmd,
@@ -5245,8 +6052,8 @@ DEFUN (clear_ip_bgp_external_ipv4_soft_out,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
if (strncmp (argv[0], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external,
@@ -5266,7 +6073,7 @@ ALIAS (clear_ip_bgp_external_ipv4_soft_out,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_bgp_external_soft_out,
clear_bgp_external_soft_out_cmd,
@@ -5274,8 +6081,8 @@ DEFUN (clear_bgp_external_soft_out,
CLEAR_STR
BGP_STR
"Clear all external peers\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external,
BGP_CLEAR_SOFT_OUT, NULL);
@@ -5288,8 +6095,8 @@ ALIAS (clear_bgp_external_soft_out,
BGP_STR
"Address family\n"
"Clear all external peers\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
ALIAS (clear_bgp_external_soft_out,
clear_bgp_external_out_cmd,
@@ -5297,7 +6104,7 @@ ALIAS (clear_bgp_external_soft_out,
CLEAR_STR
BGP_STR
"Clear all external peers\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
ALIAS (clear_bgp_external_soft_out,
clear_bgp_ipv6_external_out_cmd,
@@ -5306,7 +6113,7 @@ ALIAS (clear_bgp_external_soft_out,
BGP_STR
"Address family\n"
"Clear all external peers\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_as_soft_out,
clear_ip_bgp_as_soft_out_cmd,
@@ -5315,8 +6122,8 @@ DEFUN (clear_ip_bgp_as_soft_out,
IP_STR
BGP_STR
"Clear peers with the AS number\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as,
BGP_CLEAR_SOFT_OUT, argv[0]);
@@ -5329,7 +6136,7 @@ ALIAS (clear_ip_bgp_as_soft_out,
IP_STR
BGP_STR
"Clear peers with the AS number\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_as_ipv4_soft_out,
clear_ip_bgp_as_ipv4_soft_out_cmd,
@@ -5341,8 +6148,8 @@ DEFUN (clear_ip_bgp_as_ipv4_soft_out,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
if (strncmp (argv[1], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as,
@@ -5362,7 +6169,7 @@ ALIAS (clear_ip_bgp_as_ipv4_soft_out,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_as_vpnv4_soft_out,
clear_ip_bgp_as_vpnv4_soft_out_cmd,
@@ -5373,8 +6180,8 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft_out,
"Clear peers with the AS number\n"
"Address family\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as,
BGP_CLEAR_SOFT_OUT, argv[0]);
@@ -5389,7 +6196,7 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_out,
"Clear peers with the AS number\n"
"Address family\n"
"Address Family modifier\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
DEFUN (clear_ip_bgp_as_encap_soft_out,
clear_ip_bgp_as_encap_soft_out_cmd,
@@ -5424,8 +6231,8 @@ DEFUN (clear_bgp_as_soft_out,
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as,
BGP_CLEAR_SOFT_OUT, argv[0]);
@@ -5438,8 +6245,8 @@ ALIAS (clear_bgp_as_soft_out,
BGP_STR
"Address family\n"
"Clear peers with the AS number\n"
- "Soft reconfig\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_OUT_STR)
ALIAS (clear_bgp_as_soft_out,
clear_bgp_as_out_cmd,
@@ -5447,7 +6254,7 @@ ALIAS (clear_bgp_as_soft_out,
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
ALIAS (clear_bgp_as_soft_out,
clear_bgp_ipv6_as_out_cmd,
@@ -5456,7 +6263,7 @@ ALIAS (clear_bgp_as_soft_out,
BGP_STR
"Address family\n"
"Clear peers with the AS number\n"
- "Soft reconfig outbound update\n")
+ BGP_SOFT_OUT_STR)
/* Inbound soft-reconfiguration */
DEFUN (clear_ip_bgp_all_soft_in,
@@ -5466,8 +6273,8 @@ DEFUN (clear_ip_bgp_all_soft_in,
IP_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
if (argc == 1)
return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all,
@@ -5486,8 +6293,8 @@ ALIAS (clear_ip_bgp_all_soft_in,
"BGP view\n"
"view name\n"
"Clear all peers\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
ALIAS (clear_ip_bgp_all_soft_in,
clear_ip_bgp_all_in_cmd,
@@ -5496,7 +6303,7 @@ ALIAS (clear_ip_bgp_all_soft_in,
IP_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_all_in_prefix_filter,
clear_ip_bgp_all_in_prefix_filter_cmd,
@@ -5505,7 +6312,7 @@ DEFUN (clear_ip_bgp_all_in_prefix_filter,
IP_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
if (argc== 1)
@@ -5525,7 +6332,7 @@ ALIAS (clear_ip_bgp_all_in_prefix_filter,
"BGP view\n"
"view name\n"
"Clear all peers\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
@@ -5539,8 +6346,8 @@ DEFUN (clear_ip_bgp_all_ipv4_soft_in,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
if (strncmp (argv[0], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all,
@@ -5560,7 +6367,7 @@ ALIAS (clear_ip_bgp_all_ipv4_soft_in,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_instance_all_ipv4_soft_in,
clear_ip_bgp_instance_all_ipv4_soft_in_cmd,
@@ -5574,8 +6381,8 @@ DEFUN (clear_ip_bgp_instance_all_ipv4_soft_in,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
if (strncmp (argv[1], "m", 1) == 0)
return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all,
@@ -5595,7 +6402,7 @@ DEFUN (clear_ip_bgp_all_ipv4_in_prefix_filter,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
if (strncmp (argv[0], "m", 1) == 0)
@@ -5616,7 +6423,7 @@ DEFUN (clear_ip_bgp_instance_all_ipv4_in_prefix_filter,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
if (strncmp (argv[1], "m", 1) == 0)
@@ -5636,8 +6443,8 @@ DEFUN (clear_ip_bgp_all_vpnv4_soft_in,
"Clear all peers\n"
"Address family\n"
"Address Family Modifier\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all,
BGP_CLEAR_SOFT_IN, NULL);
@@ -5652,7 +6459,7 @@ ALIAS (clear_ip_bgp_all_vpnv4_soft_in,
"Clear all peers\n"
"Address family\n"
"Address Family Modifier\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_all_encap_soft_in,
clear_ip_bgp_all_encap_soft_in_cmd,
@@ -5687,8 +6494,8 @@ DEFUN (clear_bgp_all_soft_in,
CLEAR_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
if (argc == 1)
return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all,
@@ -5706,8 +6513,8 @@ ALIAS (clear_bgp_all_soft_in,
"BGP view\n"
"view name\n"
"Clear all peers\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
ALIAS (clear_bgp_all_soft_in,
clear_bgp_ipv6_all_soft_in_cmd,
@@ -5716,8 +6523,8 @@ ALIAS (clear_bgp_all_soft_in,
BGP_STR
"Address family\n"
"Clear all peers\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
ALIAS (clear_bgp_all_soft_in,
clear_bgp_all_in_cmd,
@@ -5725,7 +6532,7 @@ ALIAS (clear_bgp_all_soft_in,
CLEAR_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
ALIAS (clear_bgp_all_soft_in,
clear_bgp_ipv6_all_in_cmd,
@@ -5734,7 +6541,7 @@ ALIAS (clear_bgp_all_soft_in,
BGP_STR
"Address family\n"
"Clear all peers\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_bgp_all_in_prefix_filter,
clear_bgp_all_in_prefix_filter_cmd,
@@ -5742,7 +6549,7 @@ DEFUN (clear_bgp_all_in_prefix_filter,
CLEAR_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all,
@@ -5756,7 +6563,7 @@ ALIAS (clear_bgp_all_in_prefix_filter,
BGP_STR
"Address family\n"
"Clear all peers\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
DEFUN (clear_ip_bgp_peer_soft_in,
@@ -5766,8 +6573,8 @@ DEFUN (clear_ip_bgp_peer_soft_in,
IP_STR
BGP_STR
"BGP neighbor address to clear\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer,
BGP_CLEAR_SOFT_IN, argv[0]);
@@ -5780,7 +6587,7 @@ ALIAS (clear_ip_bgp_peer_soft_in,
IP_STR
BGP_STR
"BGP neighbor address to clear\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_peer_in_prefix_filter,
clear_ip_bgp_peer_in_prefix_filter_cmd,
@@ -5789,7 +6596,7 @@ DEFUN (clear_ip_bgp_peer_in_prefix_filter,
IP_STR
BGP_STR
"BGP neighbor address to clear\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out the existing ORF prefix-list\n")
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer,
@@ -5806,8 +6613,8 @@ DEFUN (clear_ip_bgp_peer_ipv4_soft_in,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
if (strncmp (argv[1], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer,
@@ -5827,7 +6634,7 @@ ALIAS (clear_ip_bgp_peer_ipv4_soft_in,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_peer_ipv4_in_prefix_filter,
clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd,
@@ -5839,7 +6646,7 @@ DEFUN (clear_ip_bgp_peer_ipv4_in_prefix_filter,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out the existing ORF prefix-list\n")
{
if (strncmp (argv[1], "m", 1) == 0)
@@ -5859,8 +6666,8 @@ DEFUN (clear_ip_bgp_peer_vpnv4_soft_in,
"BGP neighbor address to clear\n"
"Address family\n"
"Address Family Modifier\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer,
BGP_CLEAR_SOFT_IN, argv[0]);
@@ -5875,7 +6682,7 @@ ALIAS (clear_ip_bgp_peer_vpnv4_soft_in,
"BGP neighbor address to clear\n"
"Address family\n"
"Address Family Modifier\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_peer_encap_soft_in,
clear_ip_bgp_peer_encap_soft_in_cmd,
@@ -5906,13 +6713,14 @@ ALIAS (clear_ip_bgp_peer_encap_soft_in,
DEFUN (clear_bgp_peer_soft_in,
clear_bgp_peer_soft_in_cmd,
- "clear bgp (A.B.C.D|X:X::X:X) soft in",
+ "clear bgp (A.B.C.D|X:X::X:X|WORD) soft in",
CLEAR_STR
BGP_STR
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer,
BGP_CLEAR_SOFT_IN, argv[0]);
@@ -5920,42 +6728,46 @@ DEFUN (clear_bgp_peer_soft_in,
ALIAS (clear_bgp_peer_soft_in,
clear_bgp_ipv6_peer_soft_in_cmd,
- "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft in",
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X|WORD) soft in",
CLEAR_STR
BGP_STR
"Address family\n"
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
ALIAS (clear_bgp_peer_soft_in,
clear_bgp_peer_in_cmd,
- "clear bgp (A.B.C.D|X:X::X:X) in",
+ "clear bgp (A.B.C.D|X:X::X:X|WORD) in",
CLEAR_STR
BGP_STR
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig inbound update\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_IN_STR)
ALIAS (clear_bgp_peer_soft_in,
clear_bgp_ipv6_peer_in_cmd,
- "clear bgp ipv6 (A.B.C.D|X:X::X:X) in",
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X|WORD) in",
CLEAR_STR
BGP_STR
"Address family\n"
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig inbound update\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_IN_STR)
DEFUN (clear_bgp_peer_in_prefix_filter,
clear_bgp_peer_in_prefix_filter_cmd,
- "clear bgp (A.B.C.D|X:X::X:X) in prefix-filter",
+ "clear bgp (A.B.C.D|X:X::X:X|WORD) in prefix-filter",
CLEAR_STR
BGP_STR
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig inbound update\n"
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_IN_STR
"Push out the existing ORF prefix-list\n")
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer,
@@ -5964,13 +6776,14 @@ DEFUN (clear_bgp_peer_in_prefix_filter,
ALIAS (clear_bgp_peer_in_prefix_filter,
clear_bgp_ipv6_peer_in_prefix_filter_cmd,
- "clear bgp ipv6 (A.B.C.D|X:X::X:X) in prefix-filter",
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X|WORD) in prefix-filter",
CLEAR_STR
BGP_STR
"Address family\n"
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig inbound update\n"
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_IN_STR
"Push out the existing ORF prefix-list\n")
DEFUN (clear_ip_bgp_peer_group_soft_in,
@@ -5981,8 +6794,8 @@ DEFUN (clear_ip_bgp_peer_group_soft_in,
BGP_STR
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group,
BGP_CLEAR_SOFT_IN, argv[0]);
@@ -5996,7 +6809,7 @@ ALIAS (clear_ip_bgp_peer_group_soft_in,
BGP_STR
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_peer_group_in_prefix_filter,
clear_ip_bgp_peer_group_in_prefix_filter_cmd,
@@ -6006,7 +6819,7 @@ DEFUN (clear_ip_bgp_peer_group_in_prefix_filter,
BGP_STR
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group,
@@ -6024,8 +6837,8 @@ DEFUN (clear_ip_bgp_peer_group_ipv4_soft_in,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
if (strncmp (argv[1], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group,
@@ -6046,7 +6859,7 @@ ALIAS (clear_ip_bgp_peer_group_ipv4_soft_in,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_peer_group_ipv4_in_prefix_filter,
clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd,
@@ -6059,7 +6872,7 @@ DEFUN (clear_ip_bgp_peer_group_ipv4_in_prefix_filter,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
if (strncmp (argv[1], "m", 1) == 0)
@@ -6077,8 +6890,8 @@ DEFUN (clear_bgp_peer_group_soft_in,
BGP_STR
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group,
BGP_CLEAR_SOFT_IN, argv[0]);
@@ -6092,8 +6905,8 @@ ALIAS (clear_bgp_peer_group_soft_in,
"Address family\n"
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
ALIAS (clear_bgp_peer_group_soft_in,
clear_bgp_peer_group_in_cmd,
@@ -6102,7 +6915,7 @@ ALIAS (clear_bgp_peer_group_soft_in,
BGP_STR
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
ALIAS (clear_bgp_peer_group_soft_in,
clear_bgp_ipv6_peer_group_in_cmd,
@@ -6112,7 +6925,7 @@ ALIAS (clear_bgp_peer_group_soft_in,
"Address family\n"
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_bgp_peer_group_in_prefix_filter,
clear_bgp_peer_group_in_prefix_filter_cmd,
@@ -6121,7 +6934,7 @@ DEFUN (clear_bgp_peer_group_in_prefix_filter,
BGP_STR
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group,
@@ -6136,7 +6949,7 @@ ALIAS (clear_bgp_peer_group_in_prefix_filter,
"Address family\n"
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
DEFUN (clear_ip_bgp_external_soft_in,
@@ -6146,8 +6959,8 @@ DEFUN (clear_ip_bgp_external_soft_in,
IP_STR
BGP_STR
"Clear all external peers\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external,
BGP_CLEAR_SOFT_IN, NULL);
@@ -6160,7 +6973,7 @@ ALIAS (clear_ip_bgp_external_soft_in,
IP_STR
BGP_STR
"Clear all external peers\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_external_in_prefix_filter,
clear_ip_bgp_external_in_prefix_filter_cmd,
@@ -6169,7 +6982,7 @@ DEFUN (clear_ip_bgp_external_in_prefix_filter,
IP_STR
BGP_STR
"Clear all external peers\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external,
@@ -6186,8 +6999,8 @@ DEFUN (clear_ip_bgp_external_ipv4_soft_in,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
if (strncmp (argv[0], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external,
@@ -6207,7 +7020,7 @@ ALIAS (clear_ip_bgp_external_ipv4_soft_in,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_external_ipv4_in_prefix_filter,
clear_ip_bgp_external_ipv4_in_prefix_filter_cmd,
@@ -6219,7 +7032,7 @@ DEFUN (clear_ip_bgp_external_ipv4_in_prefix_filter,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
if (strncmp (argv[0], "m", 1) == 0)
@@ -6236,8 +7049,8 @@ DEFUN (clear_bgp_external_soft_in,
CLEAR_STR
BGP_STR
"Clear all external peers\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external,
BGP_CLEAR_SOFT_IN, NULL);
@@ -6250,8 +7063,8 @@ ALIAS (clear_bgp_external_soft_in,
BGP_STR
"Address family\n"
"Clear all external peers\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
ALIAS (clear_bgp_external_soft_in,
clear_bgp_external_in_cmd,
@@ -6259,7 +7072,7 @@ ALIAS (clear_bgp_external_soft_in,
CLEAR_STR
BGP_STR
"Clear all external peers\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
ALIAS (clear_bgp_external_soft_in,
clear_bgp_ipv6_external_in_cmd,
@@ -6268,7 +7081,7 @@ ALIAS (clear_bgp_external_soft_in,
BGP_STR
"Address family\n"
"Clear all external peers\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_bgp_external_in_prefix_filter,
clear_bgp_external_in_prefix_filter_cmd,
@@ -6276,7 +7089,7 @@ DEFUN (clear_bgp_external_in_prefix_filter,
CLEAR_STR
BGP_STR
"Clear all external peers\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external,
@@ -6290,7 +7103,7 @@ ALIAS (clear_bgp_external_in_prefix_filter,
BGP_STR
"Address family\n"
"Clear all external peers\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
DEFUN (clear_ip_bgp_as_soft_in,
@@ -6300,8 +7113,8 @@ DEFUN (clear_ip_bgp_as_soft_in,
IP_STR
BGP_STR
"Clear peers with the AS number\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as,
BGP_CLEAR_SOFT_IN, argv[0]);
@@ -6314,7 +7127,7 @@ ALIAS (clear_ip_bgp_as_soft_in,
IP_STR
BGP_STR
"Clear peers with the AS number\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_as_in_prefix_filter,
clear_ip_bgp_as_in_prefix_filter_cmd,
@@ -6323,7 +7136,7 @@ DEFUN (clear_ip_bgp_as_in_prefix_filter,
IP_STR
BGP_STR
"Clear peers with the AS number\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as,
@@ -6340,8 +7153,8 @@ DEFUN (clear_ip_bgp_as_ipv4_soft_in,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
if (strncmp (argv[1], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as,
@@ -6361,7 +7174,7 @@ ALIAS (clear_ip_bgp_as_ipv4_soft_in,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter,
clear_ip_bgp_as_ipv4_in_prefix_filter_cmd,
@@ -6373,7 +7186,7 @@ DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
if (strncmp (argv[1], "m", 1) == 0)
@@ -6393,8 +7206,8 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft_in,
"Clear peers with the AS number\n"
"Address family\n"
"Address Family modifier\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as,
BGP_CLEAR_SOFT_IN, argv[0]);
@@ -6409,7 +7222,7 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_in,
"Clear peers with the AS number\n"
"Address family\n"
"Address Family modifier\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_ip_bgp_as_encap_soft_in,
clear_ip_bgp_as_encap_soft_in_cmd,
@@ -6444,8 +7257,8 @@ DEFUN (clear_bgp_as_soft_in,
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as,
BGP_CLEAR_SOFT_IN, argv[0]);
@@ -6458,8 +7271,8 @@ ALIAS (clear_bgp_as_soft_in,
BGP_STR
"Address family\n"
"Clear peers with the AS number\n"
- "Soft reconfig\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_STR
+ BGP_SOFT_IN_STR)
ALIAS (clear_bgp_as_soft_in,
clear_bgp_as_in_cmd,
@@ -6467,7 +7280,7 @@ ALIAS (clear_bgp_as_soft_in,
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
ALIAS (clear_bgp_as_soft_in,
clear_bgp_ipv6_as_in_cmd,
@@ -6476,7 +7289,7 @@ ALIAS (clear_bgp_as_soft_in,
BGP_STR
"Address family\n"
"Clear peers with the AS number\n"
- "Soft reconfig inbound update\n")
+ BGP_SOFT_IN_STR)
DEFUN (clear_bgp_as_in_prefix_filter,
clear_bgp_as_in_prefix_filter_cmd,
@@ -6484,7 +7297,7 @@ DEFUN (clear_bgp_as_in_prefix_filter,
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as,
@@ -6498,7 +7311,7 @@ ALIAS (clear_bgp_as_in_prefix_filter,
BGP_STR
"Address family\n"
"Clear peers with the AS number\n"
- "Soft reconfig inbound update\n"
+ BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n")
/* Both soft-reconfiguration */
@@ -6509,7 +7322,7 @@ DEFUN (clear_ip_bgp_all_soft,
IP_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
if (argc == 1)
return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all,
@@ -6528,7 +7341,7 @@ ALIAS (clear_ip_bgp_all_soft,
"BGP view\n"
"view name\n"
"Clear all peers\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
DEFUN (clear_ip_bgp_all_ipv4_soft,
@@ -6541,7 +7354,7 @@ DEFUN (clear_ip_bgp_all_ipv4_soft,
"Address family\n"
"Address Family Modifier\n"
"Address Family Modifier\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
if (strncmp (argv[0], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all,
@@ -6563,7 +7376,7 @@ DEFUN (clear_ip_bgp_instance_all_ipv4_soft,
"Address family\n"
"Address Family Modifier\n"
"Address Family Modifier\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
if (strncmp (argv[1], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all,
@@ -6582,7 +7395,7 @@ DEFUN (clear_ip_bgp_all_vpnv4_soft,
"Clear all peers\n"
"Address family\n"
"Address Family Modifier\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all,
BGP_CLEAR_SOFT_BOTH, argv[0]);
@@ -6609,7 +7422,7 @@ DEFUN (clear_bgp_all_soft,
CLEAR_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
if (argc == 1)
return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all,
@@ -6627,7 +7440,7 @@ ALIAS (clear_bgp_all_soft,
"BGP view\n"
"view name\n"
"Clear all peers\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
ALIAS (clear_bgp_all_soft,
clear_bgp_ipv6_all_soft_cmd,
@@ -6636,7 +7449,7 @@ ALIAS (clear_bgp_all_soft,
BGP_STR
"Address family\n"
"Clear all peers\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
DEFUN (clear_ip_bgp_peer_soft,
clear_ip_bgp_peer_soft_cmd,
@@ -6645,7 +7458,7 @@ DEFUN (clear_ip_bgp_peer_soft,
IP_STR
BGP_STR
"BGP neighbor address to clear\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer,
BGP_CLEAR_SOFT_BOTH, argv[0]);
@@ -6661,7 +7474,7 @@ DEFUN (clear_ip_bgp_peer_ipv4_soft,
"Address family\n"
"Address Family Modifier\n"
"Address Family Modifier\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
if (strncmp (argv[1], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer,
@@ -6680,7 +7493,7 @@ DEFUN (clear_ip_bgp_peer_vpnv4_soft,
"BGP neighbor address to clear\n"
"Address family\n"
"Address Family Modifier\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer,
BGP_CLEAR_SOFT_BOTH, argv[0]);
@@ -6703,12 +7516,13 @@ DEFUN (clear_ip_bgp_peer_encap_soft,
DEFUN (clear_bgp_peer_soft,
clear_bgp_peer_soft_cmd,
- "clear bgp (A.B.C.D|X:X::X:X) soft",
+ "clear bgp (A.B.C.D|X:X::X:X|WORD) soft",
CLEAR_STR
BGP_STR
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer,
BGP_CLEAR_SOFT_BOTH, argv[0]);
@@ -6716,13 +7530,14 @@ DEFUN (clear_bgp_peer_soft,
ALIAS (clear_bgp_peer_soft,
clear_bgp_ipv6_peer_soft_cmd,
- "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft",
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X|WORD) soft",
CLEAR_STR
BGP_STR
"Address family\n"
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_STR)
DEFUN (clear_ip_bgp_peer_group_soft,
clear_ip_bgp_peer_group_soft_cmd,
@@ -6732,7 +7547,7 @@ DEFUN (clear_ip_bgp_peer_group_soft,
BGP_STR
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group,
BGP_CLEAR_SOFT_BOTH, argv[0]);
@@ -6749,7 +7564,7 @@ DEFUN (clear_ip_bgp_peer_group_ipv4_soft,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
if (strncmp (argv[1], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group,
@@ -6766,7 +7581,7 @@ DEFUN (clear_bgp_peer_group_soft,
BGP_STR
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group,
BGP_CLEAR_SOFT_BOTH, argv[0]);
@@ -6780,7 +7595,7 @@ ALIAS (clear_bgp_peer_group_soft,
"Address family\n"
"Clear all members of peer-group\n"
"BGP peer-group name\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
DEFUN (clear_ip_bgp_external_soft,
clear_ip_bgp_external_soft_cmd,
@@ -6789,7 +7604,7 @@ DEFUN (clear_ip_bgp_external_soft,
IP_STR
BGP_STR
"Clear all external peers\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external,
BGP_CLEAR_SOFT_BOTH, NULL);
@@ -6805,7 +7620,7 @@ DEFUN (clear_ip_bgp_external_ipv4_soft,
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
if (strncmp (argv[0], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external,
@@ -6821,7 +7636,7 @@ DEFUN (clear_bgp_external_soft,
CLEAR_STR
BGP_STR
"Clear all external peers\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external,
BGP_CLEAR_SOFT_BOTH, NULL);
@@ -6834,7 +7649,7 @@ ALIAS (clear_bgp_external_soft,
BGP_STR
"Address family\n"
"Clear all external peers\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
DEFUN (clear_ip_bgp_as_soft,
clear_ip_bgp_as_soft_cmd,
@@ -6843,7 +7658,7 @@ DEFUN (clear_ip_bgp_as_soft,
IP_STR
BGP_STR
"Clear peers with the AS number\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as,
BGP_CLEAR_SOFT_BOTH, argv[0]);
@@ -6859,7 +7674,7 @@ DEFUN (clear_ip_bgp_as_ipv4_soft,
"Address family\n"
"Address Family Modifier\n"
"Address Family Modifier\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
if (strncmp (argv[1], "m", 1) == 0)
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as,
@@ -6878,7 +7693,7 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft,
"Clear peers with the AS number\n"
"Address family\n"
"Address Family Modifier\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as,
BGP_CLEAR_SOFT_BOTH, argv[0]);
@@ -6905,7 +7720,7 @@ DEFUN (clear_bgp_as_soft,
CLEAR_STR
BGP_STR
"Clear peers with the AS number\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
{
return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as,
BGP_CLEAR_SOFT_BOTH, argv[0]);
@@ -6918,7 +7733,7 @@ ALIAS (clear_bgp_as_soft,
BGP_STR
"Address family\n"
"Clear peers with the AS number\n"
- "Soft reconfig\n")
+ BGP_SOFT_STR)
/* RS-client soft reconfiguration. */
DEFUN (clear_bgp_all_rsclient,
@@ -6927,7 +7742,7 @@ DEFUN (clear_bgp_all_rsclient,
CLEAR_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig for rsclient RIB\n")
+ BGP_SOFT_RSCLIENT_RIB_STR)
{
if (argc == 1)
return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all,
@@ -6944,7 +7759,7 @@ ALIAS (clear_bgp_all_rsclient,
BGP_STR
"Address family\n"
"Clear all peers\n"
- "Soft reconfig for rsclient RIB\n")
+ BGP_SOFT_RSCLIENT_RIB_STR)
ALIAS (clear_bgp_all_rsclient,
clear_bgp_instance_all_rsclient_cmd,
@@ -6954,7 +7769,7 @@ ALIAS (clear_bgp_all_rsclient,
"BGP view\n"
"view name\n"
"Clear all peers\n"
- "Soft reconfig for rsclient RIB\n")
+ BGP_SOFT_RSCLIENT_RIB_STR)
ALIAS (clear_bgp_all_rsclient,
clear_bgp_ipv6_instance_all_rsclient_cmd,
@@ -6965,7 +7780,7 @@ ALIAS (clear_bgp_all_rsclient,
"BGP view\n"
"view name\n"
"Clear all peers\n"
- "Soft reconfig for rsclient RIB\n")
+ BGP_SOFT_RSCLIENT_RIB_STR)
DEFUN (clear_ip_bgp_all_rsclient,
clear_ip_bgp_all_rsclient_cmd,
@@ -6974,7 +7789,7 @@ DEFUN (clear_ip_bgp_all_rsclient,
IP_STR
BGP_STR
"Clear all peers\n"
- "Soft reconfig for rsclient RIB\n")
+ BGP_SOFT_RSCLIENT_RIB_STR)
{
if (argc == 1)
return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all,
@@ -6993,16 +7808,17 @@ ALIAS (clear_ip_bgp_all_rsclient,
"BGP view\n"
"view name\n"
"Clear all peers\n"
- "Soft reconfig for rsclient RIB\n")
+ BGP_SOFT_RSCLIENT_RIB_STR)
DEFUN (clear_bgp_peer_rsclient,
clear_bgp_peer_rsclient_cmd,
- "clear bgp (A.B.C.D|X:X::X:X) rsclient",
+ "clear bgp (A.B.C.D|X:X::X:X|WORD) rsclient",
CLEAR_STR
BGP_STR
"BGP neighbor IP address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig for rsclient RIB\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_RSCLIENT_RIB_STR)
{
if (argc == 2)
return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_peer,
@@ -7014,28 +7830,30 @@ DEFUN (clear_bgp_peer_rsclient,
ALIAS (clear_bgp_peer_rsclient,
clear_bgp_ipv6_peer_rsclient_cmd,
- "clear bgp ipv6 (A.B.C.D|X:X::X:X) rsclient",
+ "clear bgp ipv6 (A.B.C.D|X:X::X:X|WORD) rsclient",
CLEAR_STR
BGP_STR
"Address family\n"
"BGP neighbor IP address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig for rsclient RIB\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_RSCLIENT_RIB_STR)
ALIAS (clear_bgp_peer_rsclient,
clear_bgp_instance_peer_rsclient_cmd,
- "clear bgp view WORD (A.B.C.D|X:X::X:X) rsclient",
+ "clear bgp view WORD (A.B.C.D|X:X::X:X|WORD) rsclient",
CLEAR_STR
BGP_STR
"BGP view\n"
"view name\n"
"BGP neighbor IP address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig for rsclient RIB\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_RSCLIENT_RIB_STR)
ALIAS (clear_bgp_peer_rsclient,
clear_bgp_ipv6_instance_peer_rsclient_cmd,
- "clear bgp ipv6 view WORD (A.B.C.D|X:X::X:X) rsclient",
+ "clear bgp ipv6 view WORD (A.B.C.D|X:X::X:X|WORD) rsclient",
CLEAR_STR
BGP_STR
"Address family\n"
@@ -7043,17 +7861,19 @@ ALIAS (clear_bgp_peer_rsclient,
"view name\n"
"BGP neighbor IP address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig for rsclient RIB\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_RSCLIENT_RIB_STR)
DEFUN (clear_ip_bgp_peer_rsclient,
clear_ip_bgp_peer_rsclient_cmd,
- "clear ip bgp (A.B.C.D|X:X::X:X) rsclient",
+ "clear ip bgp (A.B.C.D|X:X::X:X|WORD) rsclient",
CLEAR_STR
IP_STR
BGP_STR
"BGP neighbor IP address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig for rsclient RIB\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_RSCLIENT_RIB_STR)
{
if (argc == 2)
return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_peer,
@@ -7065,7 +7885,7 @@ DEFUN (clear_ip_bgp_peer_rsclient,
ALIAS (clear_ip_bgp_peer_rsclient,
clear_ip_bgp_instance_peer_rsclient_cmd,
- "clear ip bgp view WORD (A.B.C.D|X:X::X:X) rsclient",
+ "clear ip bgp view WORD (A.B.C.D|X:X::X:X|WORD) rsclient",
CLEAR_STR
IP_STR
BGP_STR
@@ -7073,7 +7893,8 @@ ALIAS (clear_ip_bgp_peer_rsclient,
"view name\n"
"BGP neighbor IP address to clear\n"
"BGP IPv6 neighbor to clear\n"
- "Soft reconfig for rsclient RIB\n")
+ "BGP neighbor on interface to clear\n"
+ BGP_SOFT_RSCLIENT_RIB_STR)
DEFUN (show_bgp_views,
show_bgp_views_cmd,
@@ -7252,6 +8073,9 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+ continue;
+
if (peer->afc[afi][safi])
{
if (!count)
@@ -7263,6 +8087,39 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
vty_out (vty,
"BGP router identifier %s, local AS number %u%s",
inet_ntoa (bgp->router_id), bgp->as, VTY_NEWLINE);
+ if (bgp_update_delay_configured(bgp))
+ {
+ vty_out (vty, "Read-only mode update-delay limit: %d seconds%s",
+ bgp->v_update_delay, VTY_NEWLINE);
+ if (bgp->v_update_delay != bgp->v_establish_wait)
+ vty_out (vty, " Establish wait: %d seconds%s",
+ bgp->v_establish_wait, VTY_NEWLINE);
+ if (bgp_update_delay_active(bgp))
+ {
+ vty_out (vty, " First neighbor established: %s%s",
+ bgp->update_delay_begin_time, VTY_NEWLINE);
+ vty_out (vty, " Delay in progress%s", VTY_NEWLINE);
+ }
+ else
+ {
+ if (bgp->update_delay_over)
+ {
+ vty_out (vty, " First neighbor established: %s%s",
+ bgp->update_delay_begin_time, VTY_NEWLINE);
+ vty_out (vty, " Best-paths resumed: %s%s",
+ bgp->update_delay_end_time, VTY_NEWLINE);
+ vty_out (vty, " zebra update resumed: %s%s",
+ bgp->update_delay_zebra_resume_time, VTY_NEWLINE);
+ vty_out (vty, " peers update resumed: %s%s",
+ bgp->update_delay_peers_resume_time, VTY_NEWLINE);
+ }
+ }
+ }
+
+ if (bgp_maxmed_onstartup_configured(bgp) && bgp->maxmed_active)
+ vty_out (vty, "Max-med on-startup active%s", VTY_NEWLINE);
+ if (bgp->v_maxmed_admin)
+ vty_out (vty, "Max-med administrative active%s", VTY_NEWLINE);
ents = bgp_table_count (bgp->rib[afi][safi]);
vty_out (vty, "RIB entries %ld, using %s of memory%s", ents,
@@ -7308,14 +8165,16 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
vty_out (vty, "4 ");
- vty_out (vty, "%5u %7d %7d %8d %4d %4lu ",
+ vty_out (vty, "%5u %7d %7d %8d %4d %4d ",
peer->as,
peer->open_in + peer->update_in + peer->keepalive_in
+ peer->notify_in + peer->refresh_in + peer->dynamic_cap_in,
peer->open_out + peer->update_out + peer->keepalive_out
+ peer->notify_out + peer->refresh_out
+ peer->dynamic_cap_out,
- 0, 0, (unsigned long) peer->obuf->count);
+ 0, 0,
+ peer->sync[afi][safi]->update.count +
+ peer->sync[afi][safi]->withdraw.count);
vty_out (vty, "%8s",
peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN));
@@ -7344,6 +8203,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi)
else
vty_out (vty, "No %s neighbor is configured%s",
afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE);
+
return CMD_SUCCESS;
}
@@ -7983,9 +8843,16 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi)
vty_out (vty, " Route-Server Client%s", VTY_NEWLINE);
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
vty_out (vty, " Inbound soft reconfiguration allowed%s", VTY_NEWLINE);
- if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REMOVE_PRIVATE_AS))
- vty_out (vty, " Private AS number removed from updates to this neighbor%s", VTY_NEWLINE);
- if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF))
+ if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE))
+ vty_out (vty, " Private AS numbers replaced in updates to this neighbor%s", VTY_NEWLINE);
+ else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REMOVE_PRIVATE_AS))
+ vty_out (vty, " Private AS numbers removed in updates to this neighbor%s", VTY_NEWLINE);
+
+ if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_AS_OVERRIDE))
+ vty_out (vty, " Override ASNs in outbound updates if aspath equals remote-as%s", VTY_NEWLINE);
+
+ if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF) ||
+ CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF_ALL))
vty_out (vty, " NEXT_HOP is always this router%s", VTY_NEWLINE);
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED))
vty_out (vty, " AS_PATH is propagated unchanged to this neighbor%s", VTY_NEWLINE);
@@ -8122,15 +8989,21 @@ static void
bgp_show_peer (struct vty *vty, struct peer *p)
{
struct bgp *bgp;
- char buf1[BUFSIZ];
+ char buf1[BUFSIZ], buf[SU_ADDRSTRLEN];
char timebuf[BGP_UPTIME_LEN];
afi_t afi;
safi_t safi;
+ u_int16_t i;
+ u_char *msg;
bgp = p->bgp;
- /* Configured IP address. */
- vty_out (vty, "BGP neighbor is %s, ", p->host);
+ if (p->conf_if) /* Configured interface name. */
+ vty_out (vty, "BGP neighbor on %s: %s, ", p->conf_if,
+ BGP_PEER_SU_UNSPEC(p) ? "None" :
+ sockunion2str (&p->su, buf, SU_ADDRSTRLEN));
+ else /* Configured IP address. */
+ vty_out (vty, "BGP neighbor is %s, ", p->host);
vty_out (vty, "remote AS %u, ", p->as);
vty_out (vty, "local AS %u%s%s, ",
p->change_local_as ? p->change_local_as : p->local_as,
@@ -8183,9 +9056,11 @@ bgp_show_peer (struct vty *vty, struct peer *p)
/* read timer */
vty_out (vty, " Last read %s", peer_uptime (p->readtime, timebuf, BGP_UPTIME_LEN));
+ vty_out (vty, ", Last write %s%s",
+ peer_uptime (p->last_write, timebuf, BGP_UPTIME_LEN), VTY_NEWLINE);
/* Configured timer values. */
- vty_out (vty, ", hold time is %d, keepalive interval is %d seconds%s",
+ vty_out (vty, " Hold time is %d, keepalive interval is %d seconds%s",
p->v_holdtime, p->v_keepalive, VTY_NEWLINE);
if (CHECK_FLAG (p->config, PEER_CONFIG_TIMER))
{
@@ -8404,12 +9279,33 @@ bgp_show_peer (struct vty *vty, struct peer *p)
p->established, p->dropped,
VTY_NEWLINE);
- if (! p->dropped)
+ if (! p->last_reset)
vty_out (vty, " Last reset never%s", VTY_NEWLINE);
else
- vty_out (vty, " Last reset %s, due to %s%s",
- peer_uptime (p->resettime, timebuf, BGP_UPTIME_LEN),
- peer_down_str[(int) p->last_reset], VTY_NEWLINE);
+ {
+ vty_out (vty, " Last reset %s, due to %s%s",
+ peer_uptime (p->resettime, timebuf, BGP_UPTIME_LEN),
+ peer_down_str[(int) p->last_reset], VTY_NEWLINE);
+
+ if (p->last_reset_cause_size)
+ {
+ msg = p->last_reset_cause;
+ vty_out(vty, " Message received that caused BGP to send a NOTIFICATION:%s ", VTY_NEWLINE);
+ for (i = 1; i <= p->last_reset_cause_size; i++)
+ {
+ vty_out(vty, "%02X", *msg++);
+
+ if (i != p->last_reset_cause_size)
+ {
+ if (i % 16 == 0)
+ vty_out(vty, "%s ", VTY_NEWLINE);
+ else if (i % 4 == 0)
+ vty_out(vty, " ");
+ }
+ }
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+ }
if (CHECK_FLAG (p->sflags, PEER_STATUS_PREFIX_OVERFLOW))
{
@@ -8488,8 +9384,12 @@ bgp_show_peer (struct vty *vty, struct peer *p)
if (p->t_connect)
vty_out (vty, "Next connect timer due in %ld seconds%s",
thread_timer_remain_second (p->t_connect), VTY_NEWLINE);
-
- vty_out (vty, "Read thread: %s Write thread: %s%s",
+ if (p->t_routeadv)
+ vty_out (vty, "MRAI (interval %d) timer expires in %ld seconds%s",
+ p->v_routeadv, thread_timer_remain_second (p->t_routeadv),
+ VTY_NEWLINE);
+
+ vty_out (vty, "Read thread: %s Write thread: %s%s",
p->t_read ? "on" : "off",
p->t_write ? "on" : "off",
VTY_NEWLINE);
@@ -8503,7 +9403,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
static int
bgp_show_neighbor (struct vty *vty, struct bgp *bgp,
- enum show_type type, union sockunion *su)
+ enum show_type type, union sockunion *su, const char *conf_if)
{
struct listnode *node, *nnode;
struct peer *peer;
@@ -8511,17 +9411,31 @@ bgp_show_neighbor (struct vty *vty, struct bgp *bgp,
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+ continue;
+
switch (type)
{
case show_all:
bgp_show_peer (vty, peer);
break;
case show_peer:
- if (sockunion_same (&peer->su, su))
- {
- find = 1;
- bgp_show_peer (vty, peer);
- }
+ if (conf_if)
+ {
+ if (peer->conf_if && !strcmp(peer->conf_if, conf_if))
+ {
+ find = 1;
+ bgp_show_peer (vty, peer);
+ }
+ }
+ else
+ {
+ if (sockunion_same (&peer->su, su))
+ {
+ find = 1;
+ bgp_show_peer (vty, peer);
+ }
+ }
break;
}
}
@@ -8540,35 +9454,35 @@ bgp_show_neighbor_vty (struct vty *vty, const char *name,
struct bgp *bgp;
union sockunion su;
- if (ip_str)
- {
- ret = str2sockunion (ip_str, &su);
- if (ret < 0)
- {
- vty_out (vty, "%% Malformed address: %s%s", ip_str, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
if (name)
{
bgp = bgp_lookup_by_name (name);
-
if (! bgp)
{
vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE);
return CMD_WARNING;
}
-
- bgp_show_neighbor (vty, bgp, type, &su);
-
- return CMD_SUCCESS;
}
-
- bgp = bgp_get_default ();
+ else
+ {
+ bgp = bgp_get_default ();
+ }
if (bgp)
- bgp_show_neighbor (vty, bgp, type, &su);
+ {
+ if (ip_str)
+ {
+ ret = str2sockunion (ip_str, &su);
+ if (ret < 0)
+ bgp_show_neighbor (vty, bgp, type, NULL, ip_str);
+ else
+ bgp_show_neighbor (vty, bgp, type, &su, NULL);
+ }
+ else
+ {
+ bgp_show_neighbor (vty, bgp, type, NULL, NULL);
+ }
+ }
return CMD_SUCCESS;
}
@@ -8626,20 +9540,21 @@ ALIAS (show_ip_bgp_neighbors,
DEFUN (show_ip_bgp_neighbors_peer,
show_ip_bgp_neighbors_peer_cmd,
- "show ip bgp neighbors (A.B.C.D|X:X::X:X)",
+ "show ip bgp neighbors (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
IP_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
- "Neighbor to display information about\n")
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n")
{
return bgp_show_neighbor_vty (vty, NULL, show_peer, argv[argc - 1]);
}
ALIAS (show_ip_bgp_neighbors_peer,
show_ip_bgp_ipv4_neighbors_peer_cmd,
- "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X)",
+ "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
IP_STR
BGP_STR
@@ -8648,7 +9563,8 @@ ALIAS (show_ip_bgp_neighbors_peer,
"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")
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n")
ALIAS (show_ip_bgp_neighbors_peer,
show_ip_bgp_vpnv4_all_neighbors_peer_cmd,
@@ -8674,13 +9590,14 @@ ALIAS (show_ip_bgp_neighbors_peer,
ALIAS (show_ip_bgp_neighbors_peer,
show_bgp_ipv6_neighbors_peer_cmd,
- "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X)",
+ "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"Address family\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
- "Neighbor to display information about\n")
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n")
DEFUN (show_ip_bgp_instance_neighbors,
show_ip_bgp_instance_neighbors_cmd,
@@ -8707,7 +9624,7 @@ ALIAS (show_ip_bgp_instance_neighbors,
DEFUN (show_ip_bgp_instance_neighbors_peer,
show_ip_bgp_instance_neighbors_peer_cmd,
- "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X)",
+ "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
IP_STR
BGP_STR
@@ -8715,7 +9632,8 @@ DEFUN (show_ip_bgp_instance_neighbors_peer,
"View name\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
- "Neighbor to display information about\n")
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n")
{
return bgp_show_neighbor_vty (vty, argv[0], show_peer, argv[1]);
}
@@ -8765,12 +9683,13 @@ DEFUN (show_bgp_neighbors,
DEFUN (show_bgp_neighbors_peer,
show_bgp_neighbors_peer_cmd,
- "show bgp neighbors (A.B.C.D|X:X::X:X)",
+ "show bgp neighbors (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
- "Neighbor to display information about\n")
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n")
{
return bgp_show_neighbor_vty (vty, NULL, show_peer, argv[argc - 1]);
}
@@ -8789,21 +9708,22 @@ DEFUN (show_bgp_instance_neighbors,
DEFUN (show_bgp_instance_neighbors_peer,
show_bgp_instance_neighbors_peer_cmd,
- "show bgp view WORD neighbors (A.B.C.D|X:X::X:X)",
+ "show bgp view WORD neighbors (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"BGP view\n"
"View name\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
- "Neighbor to display information about\n")
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n")
{
return bgp_show_neighbor_vty (vty, argv[0], show_peer, argv[1]);
}
ALIAS (show_bgp_instance_neighbors_peer,
show_bgp_instance_ipv6_neighbors_peer_cmd,
- "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X)",
+ "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X|WORD)",
SHOW_STR
BGP_STR
"BGP view\n"
@@ -8811,7 +9731,8 @@ ALIAS (show_bgp_instance_neighbors_peer,
"Address family\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
- "Neighbor to display information about\n")
+ "Neighbor to display information about\n"
+ "Neighbor on bgp configured interface\n")
/* Show BGP's AS paths internal data. There are both `show ip bgp
paths' and `show ip mbgp paths'. Those functions results are the
@@ -9407,7 +10328,7 @@ DEFUN (no_bgp_redistribute_ipv4,
return bgp_redistribute_unset (vty->index, AFI_IP, type);
}
-DEFUN (no_bgp_redistribute_ipv4_rmap,
+ALIAS (no_bgp_redistribute_ipv4,
no_bgp_redistribute_ipv4_rmap_cmd,
"no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD",
NO_STR
@@ -9415,21 +10336,8 @@ DEFUN (no_bgp_redistribute_ipv4_rmap,
QUAGGA_IP_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n")
-{
- int type;
-
- type = proto_redistnum (AFI_IP, argv[0]);
- if (type < 0 || type == ZEBRA_ROUTE_BGP)
- {
- vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bgp_redistribute_routemap_unset (vty->index, AFI_IP, type);
- return CMD_SUCCESS;
-}
-DEFUN (no_bgp_redistribute_ipv4_metric,
+ALIAS (no_bgp_redistribute_ipv4,
no_bgp_redistribute_ipv4_metric_cmd,
"no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>",
NO_STR
@@ -9437,21 +10345,8 @@ DEFUN (no_bgp_redistribute_ipv4_metric,
QUAGGA_IP_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n")
-{
- int type;
- type = proto_redistnum (AFI_IP, argv[0]);
- if (type < 0 || type == ZEBRA_ROUTE_BGP)
- {
- vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bgp_redistribute_metric_unset (vty->index, AFI_IP, type);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_bgp_redistribute_ipv4_rmap_metric,
+ALIAS (no_bgp_redistribute_ipv4,
no_bgp_redistribute_ipv4_rmap_metric_cmd,
"no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",
NO_STR
@@ -9461,22 +10356,8 @@ DEFUN (no_bgp_redistribute_ipv4_rmap_metric,
"Pointer to route-map entries\n"
"Metric for redistributed routes\n"
"Default metric\n")
-{
- int type;
- type = proto_redistnum (AFI_IP, argv[0]);
- if (type < 0 || type == ZEBRA_ROUTE_BGP)
- {
- vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bgp_redistribute_metric_unset (vty->index, AFI_IP, type);
- bgp_redistribute_routemap_unset (vty->index, AFI_IP, type);
- return CMD_SUCCESS;
-}
-
-ALIAS (no_bgp_redistribute_ipv4_rmap_metric,
+ALIAS (no_bgp_redistribute_ipv4,
no_bgp_redistribute_ipv4_metric_rmap_cmd,
"no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",
NO_STR
@@ -9620,7 +10501,7 @@ DEFUN (no_bgp_redistribute_ipv6,
return bgp_redistribute_unset (vty->index, AFI_IP6, type);
}
-DEFUN (no_bgp_redistribute_ipv6_rmap,
+ALIAS (no_bgp_redistribute_ipv6,
no_bgp_redistribute_ipv6_rmap_cmd,
"no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD",
NO_STR
@@ -9628,21 +10509,8 @@ DEFUN (no_bgp_redistribute_ipv6_rmap,
QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n")
-{
- int type;
- type = proto_redistnum (AFI_IP6, argv[0]);
- if (type < 0 || type == ZEBRA_ROUTE_BGP)
- {
- vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_bgp_redistribute_ipv6_metric,
+ALIAS (no_bgp_redistribute_ipv6,
no_bgp_redistribute_ipv6_metric_cmd,
"no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>",
NO_STR
@@ -9650,21 +10518,8 @@ DEFUN (no_bgp_redistribute_ipv6_metric,
QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n")
-{
- int type;
-
- type = proto_redistnum (AFI_IP6, argv[0]);
- if (type < 0 || type == ZEBRA_ROUTE_BGP)
- {
- vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- bgp_redistribute_metric_unset (vty->index, AFI_IP6, type);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_bgp_redistribute_ipv6_rmap_metric,
+ALIAS (no_bgp_redistribute_ipv6,
no_bgp_redistribute_ipv6_rmap_metric_cmd,
"no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",
NO_STR
@@ -9674,22 +10529,8 @@ DEFUN (no_bgp_redistribute_ipv6_rmap_metric,
"Pointer to route-map entries\n"
"Metric for redistributed routes\n"
"Default metric\n")
-{
- int type;
-
- type = proto_redistnum (AFI_IP6, argv[0]);
- if (type < 0 || type == ZEBRA_ROUTE_BGP)
- {
- vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- bgp_redistribute_metric_unset (vty->index, AFI_IP6, type);
- bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type);
- return CMD_SUCCESS;
-}
-
-ALIAS (no_bgp_redistribute_ipv6_rmap_metric,
+ALIAS (no_bgp_redistribute_ipv6,
no_bgp_redistribute_ipv6_metric_rmap_cmd,
"no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",
NO_STR
@@ -9864,6 +10705,26 @@ bgp_vty_init (void)
install_element (BGP_NODE, &bgp_confederation_peers_cmd);
install_element (BGP_NODE, &no_bgp_confederation_peers_cmd);
+ /* bgp max-med command */
+ install_element (BGP_NODE, &bgp_maxmed_admin_cmd);
+ install_element (BGP_NODE, &no_bgp_maxmed_admin_cmd);
+ install_element (BGP_NODE, &bgp_maxmed_admin_medv_cmd);
+ install_element (BGP_NODE, &no_bgp_maxmed_admin_medv_cmd);
+ install_element (BGP_NODE, &bgp_maxmed_onstartup_cmd);
+ install_element (BGP_NODE, &no_bgp_maxmed_onstartup_cmd);
+ install_element (BGP_NODE, &no_bgp_maxmed_onstartup_period_cmd);
+ install_element (BGP_NODE, &bgp_maxmed_onstartup_medv_cmd);
+ install_element (BGP_NODE, &no_bgp_maxmed_onstartup_period_medv_cmd);
+
+ /* bgp update-delay command */
+ install_element (BGP_NODE, &bgp_update_delay_cmd);
+ install_element (BGP_NODE, &no_bgp_update_delay_cmd);
+ install_element (BGP_NODE, &bgp_update_delay_establish_wait_cmd);
+ install_element (BGP_NODE, &no_bgp_update_delay_establish_wait_cmd);
+
+ install_element (BGP_NODE, &bgp_wpkt_quanta_cmd);
+ install_element (BGP_NODE, &no_bgp_wpkt_quanta_cmd);
+
/* "maximum-paths" commands. */
install_element (BGP_NODE, &bgp_maxpaths_cmd);
install_element (BGP_NODE, &no_bgp_maxpaths_cmd);
@@ -9871,18 +10732,34 @@ bgp_vty_init (void)
install_element (BGP_IPV4_NODE, &bgp_maxpaths_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_arg_cmd);
+ install_element (BGP_IPV6_NODE, &bgp_maxpaths_cmd);
+ install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_cmd);
+ install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_arg_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, &no_bgp_maxpaths_ibgp_arg_cmd);
+ install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_cluster_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, &no_bgp_maxpaths_ibgp_cmd);
+ install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_cluster_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_arg_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, &no_bgp_maxpaths_ibgp_cmd);
+ install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_arg_cmd);
+ install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_cluster_cmd);
/* "timers bgp" commands. */
install_element (BGP_NODE, &bgp_timers_cmd);
install_element (BGP_NODE, &no_bgp_timers_cmd);
install_element (BGP_NODE, &no_bgp_timers_arg_cmd);
+ /* route-map delay-timer commands */
+ install_element (BGP_NODE, &bgp_set_route_map_delay_timer_cmd);
+ install_element (BGP_NODE, &no_bgp_set_route_map_delay_timer_cmd);
+
/* "bgp client-to-client reflection" commands */
install_element (BGP_NODE, &no_bgp_client_to_client_reflection_cmd);
install_element (BGP_NODE, &bgp_client_to_client_reflection_cmd);
@@ -9951,15 +10828,21 @@ bgp_vty_init (void)
install_element (BGP_NODE, &no_bgp_default_local_preference_cmd);
install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd);
+ /* bgp ibgp-allow-policy-mods command */
+ install_element (BGP_NODE, &bgp_rr_allow_outbound_policy_cmd);
+ install_element (BGP_NODE, &no_bgp_rr_allow_outbound_policy_cmd);
+
/* "neighbor remote-as" commands. */
install_element (BGP_NODE, &neighbor_remote_as_cmd);
+ install_element (BGP_NODE, &neighbor_interface_config_cmd);
install_element (BGP_NODE, &no_neighbor_cmd);
install_element (BGP_NODE, &no_neighbor_remote_as_cmd);
+ install_element (BGP_NODE, &no_neighbor_interface_config_cmd);
/* "neighbor peer-group" commands. */
install_element (BGP_NODE, &neighbor_peer_group_cmd);
install_element (BGP_NODE, &no_neighbor_peer_group_cmd);
- install_element (BGP_NODE, &no_neighbor_peer_group_remote_as_cmd);
+ install_element (BGP_NODE, &no_neighbor_interface_peer_group_remote_as_cmd);
/* "neighbor local-as" commands. */
install_element (BGP_NODE, &neighbor_local_as_cmd);
@@ -10270,17 +11153,61 @@ bgp_vty_init (void)
install_element (BGP_ENCAPV6_NODE, &neighbor_nexthop_self_cmd);
install_element (BGP_ENCAPV6_NODE, &no_neighbor_nexthop_self_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_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_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_VPNV4_NODE, &neighbor_as_override_cmd);
+ install_element (BGP_VPNV4_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_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_IPV4_NODE, &no_neighbor_remove_private_as_all_cmd);
+ install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_replace_as_cmd);
+ install_element (BGP_IPV4_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
+ install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
+ install_element (BGP_IPV4_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_cmd);
install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_cmd);
+ install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_all_cmd);
+ install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_all_cmd);
+ install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_replace_as_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_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_IPV6_NODE, &no_neighbor_remove_private_as_all_cmd);
+ install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_replace_as_cmd);
+ install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
+ install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
+ install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
install_element (BGP_IPV6M_NODE, &neighbor_remove_private_as_cmd);
install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_cmd);
+ install_element (BGP_IPV6M_NODE, &neighbor_remove_private_as_all_cmd);
+ install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_all_cmd);
+ install_element (BGP_IPV6M_NODE, &neighbor_remove_private_as_replace_as_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_VPNV4_NODE, &neighbor_remove_private_as_cmd);
install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_remove_private_as_cmd);
@@ -10289,6 +11216,12 @@ bgp_vty_init (void)
install_element (BGP_ENCAP_NODE, &no_neighbor_remove_private_as_cmd);
install_element (BGP_ENCAPV6_NODE, &neighbor_remove_private_as_cmd);
install_element (BGP_ENCAPV6_NODE, &no_neighbor_remove_private_as_cmd);
+ install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_all_cmd);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_all_cmd);
+ install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_replace_as_cmd);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_replace_as_cmd);
+ install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_all_replace_as_cmd);
+ install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd);
/* "neighbor send-community" commands.*/
install_element (BGP_NODE, &neighbor_send_community_cmd);
@@ -10856,6 +11789,10 @@ bgp_vty_init (void)
install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd);
install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd);
+ /* clear ip bgp prefix */
+ install_element (ENABLE_NODE, &clear_ip_bgp_prefix_cmd);
+ install_element (ENABLE_NODE, &clear_bgp_ipv6_safi_prefix_cmd);
+
/* "clear ip bgp neighbor soft out" */
install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd);
install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd);
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index 7329c5fd..fdbbb782 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -21,10 +21,14 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_VTY_H
#define _QUAGGA_BGP_VTY_H
+#include "bgpd/bgpd.h"
+
#define CMD_AS_RANGE "<1-4294967295>"
extern void bgp_vty_init (void);
extern const char *afi_safi_print (afi_t, safi_t);
+extern int bgp_config_write_update_delay (struct vty *, struct bgp *);
+extern int bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp);
extern int
bgp_parse_afi(const char *str, afi_t *afi);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index d0b9216a..92883d5d 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -39,6 +39,8 @@ Boston, MA 02111-1307, USA. */
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_mpath.h"
+#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_nht.h"
/* All information about zebra. */
struct zclient *zclient = NULL;
@@ -46,6 +48,44 @@ struct in_addr router_id_zebra;
/* Growable buffer for nexthops sent to zebra */
struct stream *bgp_nexthop_buf = NULL;
+struct stream *bgp_ifindices_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
+ frees for the temporary copy of the attributes.
+ Given the zapi api expects the nexthop buffer to contain pointer to
+ pointers for nexthops, we couldnt have used a single nexthop variable
+ on the stack, hence we had two options:
+ 1. maintain a linked-list and free it after zapi_*_route call
+ 2. use an array to avoid number of mallocs.
+ Number of supported next-hops are finite, use of arrays should be ok. */
+struct attr attr_cp[BGP_MAXIMUM_MAXPATHS];
+struct attr_extra attr_extra_cp[BGP_MAXIMUM_MAXPATHS];
+int attr_index = 0;
+
+/* Once per address-family initialization of the attribute array */
+#define BGP_INFO_ATTR_BUF_INIT()\
+do {\
+ memset(attr_cp, 0, BGP_MAXIMUM_MAXPATHS * sizeof(struct attr));\
+ memset(attr_extra_cp, 0, BGP_MAXIMUM_MAXPATHS * sizeof(struct attr_extra));\
+ attr_index = 0;\
+} while (0)
+
+#define BGP_INFO_ATTR_BUF_COPY(info_src, info_dst)\
+do { \
+ *info_dst = *info_src; \
+ assert(attr_index != BGP_MAXIMUM_MAXPATHS);\
+ attr_cp[attr_index].extra = &attr_extra_cp[attr_index]; \
+ bgp_attr_dup (&attr_cp[attr_index], info_src->attr); \
+ bgp_attr_deep_dup (&attr_cp[attr_index], info_src->attr); \
+ info_dst->attr = &attr_cp[attr_index]; \
+ attr_index++;\
+} while (0)
+
+#define BGP_INFO_ATTR_BUF_FREE(info) \
+do { \
+ bgp_attr_deep_free(info->attr); \
+} while (0)
/* Router-id update message from zebra. */
static int
@@ -58,7 +98,7 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length,
zebra_router_id_update_read(zclient->ibuf,&router_id);
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (BGP_DEBUG (zebra, ZEBRA))
{
char buf[128];
prefix2str(&router_id, buf, sizeof(buf));
@@ -76,6 +116,55 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length,
return 0;
}
+/* Nexthop update message from zebra. */
+static int
+bgp_read_nexthop_update (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ bgp_parse_nexthop_update();
+ return 0;
+}
+
+static void
+bgp_nbr_connected_add (struct nbr_connected *ifc)
+{
+ struct listnode *node, *nnode, *mnode;
+ struct bgp *bgp;
+ struct peer *peer;
+
+ for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
+ {
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+ if (peer->conf_if && (strcmp (peer->conf_if, ifc->ifp->name) == 0))
+ {
+ if (peer_active(peer))
+ BGP_EVENT_ADD (peer, BGP_Stop);
+ BGP_EVENT_ADD (peer, BGP_Start);
+ }
+ }
+ }
+}
+
+static void
+bgp_nbr_connected_delete (struct nbr_connected *ifc)
+{
+ struct listnode *node, *nnode, *mnode;
+ struct bgp *bgp;
+ struct peer *peer;
+
+ for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
+ {
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+ if (peer->conf_if && (strcmp (peer->conf_if, ifc->ifp->name) == 0))
+ {
+ BGP_EVENT_ADD (peer, BGP_Stop);
+ }
+ }
+ }
+}
+
/* Inteface addition message from zebra. */
static int
bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length,
@@ -85,7 +174,7 @@ bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length,
ifp = zebra_interface_add_read (zclient->ibuf, vrf_id);
- if (BGP_DEBUG(zebra, ZEBRA) && ifp)
+ if (BGP_DEBUG (zebra, ZEBRA) && ifp)
zlog_debug("Zebra rcvd: interface add %s", ifp->name);
return 0;
@@ -102,7 +191,7 @@ bgp_interface_delete (int command, struct zclient *zclient,
ifp = zebra_interface_state_read (s, vrf_id);
ifp->ifindex = IFINDEX_INTERNAL;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Zebra rcvd: interface delete %s", ifp->name);
return 0;
@@ -115,6 +204,7 @@ bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length,
struct stream *s;
struct interface *ifp;
struct connected *c;
+ struct nbr_connected *nc;
struct listnode *node, *nnode;
s = zclient->ibuf;
@@ -123,12 +213,15 @@ bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length,
if (! ifp)
return 0;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Zebra rcvd: interface %s up", ifp->name);
for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
bgp_connected_add (c);
+ for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc))
+ bgp_nbr_connected_add (nc);
+
return 0;
}
@@ -139,6 +232,7 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length,
struct stream *s;
struct interface *ifp;
struct connected *c;
+ struct nbr_connected *nc;
struct listnode *node, *nnode;
s = zclient->ibuf;
@@ -146,12 +240,15 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length,
if (! ifp)
return 0;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Zebra rcvd: interface %s down", ifp->name);
for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
bgp_connected_delete (c);
+ for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc))
+ bgp_nbr_connected_delete (nc);
+
/* Fast external-failover */
{
struct listnode *mnode;
@@ -188,7 +285,7 @@ bgp_interface_address_add (int command, struct zclient *zclient,
if (ifc == NULL)
return 0;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (bgp_debug_zebra(ifc->address))
{
char buf[128];
prefix2str(ifc->address, buf, sizeof(buf));
@@ -213,7 +310,7 @@ bgp_interface_address_delete (int command, struct zclient *zclient,
if (ifc == NULL)
return 0;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (bgp_debug_zebra(ifc->address))
{
char buf[128];
prefix2str(ifc->address, buf, sizeof(buf));
@@ -229,6 +326,58 @@ bgp_interface_address_delete (int command, struct zclient *zclient,
return 0;
}
+static int
+bgp_interface_nbr_address_add (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct nbr_connected *ifc = NULL;
+
+ ifc = zebra_interface_nbr_address_read (command, zclient->ibuf);
+
+ if (ifc == NULL)
+ return 0;
+
+ if (bgp_debug_zebra(ifc->address))
+ {
+ char buf[128];
+ prefix2str(ifc->address, buf, sizeof(buf));
+ zlog_debug("Zebra rcvd: interface %s nbr address add %s",
+ ifc->ifp->name, buf);
+ }
+
+ if (if_is_operative (ifc->ifp))
+ bgp_nbr_connected_add (ifc);
+
+ return 0;
+}
+
+static int
+bgp_interface_nbr_address_delete (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct nbr_connected *ifc = NULL;
+
+ ifc = zebra_interface_nbr_address_read (command, zclient->ibuf);
+
+ if (ifc == NULL)
+ return 0;
+
+ if (bgp_debug_zebra(ifc->address))
+ {
+ char buf[128];
+ prefix2str(ifc->address, buf, sizeof(buf));
+ zlog_debug("Zebra rcvd: interface %s nbr address delete %s",
+ ifc->ifp->name, buf);
+ }
+
+ if (if_is_operative (ifc->ifp))
+ bgp_nbr_connected_delete (ifc);
+
+ nbr_connected_free (ifc);
+
+ return 0;
+}
+
/* Zebra route add and delete treatment. */
static int
zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
@@ -239,6 +388,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
struct in_addr nexthop;
struct prefix_ipv4 p;
unsigned char plength = 0;
+ ifindex_t ifindex;
s = zclient->ibuf;
nexthop.s_addr = 0;
@@ -264,7 +414,11 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
{
api.ifindex_num = stream_getc (s);
- stream_getl (s); /* ifindex, unused */
+ ifindex = stream_getl (s); /* ifindex, unused */
+ }
+ else
+ {
+ ifindex = 0;
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
@@ -273,33 +427,40 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
else
api.metric = 0;
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+ api.tag = stream_getw (s);
+ else
+ api.tag = 0;
+
if (command == ZEBRA_IPV4_ROUTE_ADD)
{
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (bgp_debug_zebra((struct prefix *)&p))
{
char buf[2][INET_ADDRSTRLEN];
- zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u",
+ zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u tag %d",
zebra_route_string(api.type),
inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
- api.metric);
+ api.metric,
+ api.tag);
}
- bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL,
- api.metric, api.type);
+ bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, ifindex,
+ api.metric, api.type, api.tag);
}
else
{
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (bgp_debug_zebra((struct prefix *)&p))
{
char buf[2][INET_ADDRSTRLEN];
zlog_debug("Zebra rcvd: IPv4 route delete %s %s/%d "
- "nexthop %s metric %u",
+ "nexthop %s metric %u tag %d",
zebra_route_string(api.type),
inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
- api.metric);
+ api.metric,
+ api.tag);
}
bgp_redistribute_delete((struct prefix *)&p, api.type);
}
@@ -317,6 +478,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
struct in6_addr nexthop;
struct prefix_ipv6 p;
unsigned char plength = 0;
+ ifindex_t ifindex;
s = zclient->ibuf;
memset (&nexthop, 0, sizeof (struct in6_addr));
@@ -342,7 +504,11 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
{
api.ifindex_num = stream_getc (s);
- stream_getl (s); /* ifindex, unused */
+ ifindex = stream_getl (s); /* ifindex, unused */
+ }
+ else
+ {
+ ifindex = 0;
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
@@ -353,37 +519,44 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
else
api.metric = 0;
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+ api.tag = stream_getw (s);
+ else
+ api.tag = 0;
+
/* Simply ignore link-local address. */
if (IN6_IS_ADDR_LINKLOCAL (&p.prefix))
return 0;
if (command == ZEBRA_IPV6_ROUTE_ADD)
{
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (bgp_debug_zebra((struct prefix *)&p))
{
char buf[2][INET6_ADDRSTRLEN];
- zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u",
+ zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u tag %d",
zebra_route_string(api.type),
inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
- api.metric);
+ api.metric,
+ api.tag);
}
- bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop,
- api.metric, api.type);
+ bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, ifindex,
+ api.metric, api.type, api.tag);
}
else
{
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (bgp_debug_zebra((struct prefix *)&p))
{
char buf[2][INET6_ADDRSTRLEN];
zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d "
- "nexthop %s metric %u",
+ "nexthop %s metric %u tag %d",
zebra_route_string(api.type),
inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])),
- api.metric);
+ api.metric,
+ api.tag);
}
bgp_redistribute_delete ((struct prefix *) &p, api.type);
}
@@ -571,17 +744,22 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
if (local->sa.sa_family == AF_INET)
{
nexthop->v4 = local->sin.sin_addr;
- ifp = if_lookup_by_ipv4 (&local->sin.sin_addr);
+ if (peer->update_if)
+ ifp = if_lookup_by_name (peer->update_if);
+ else
+ ifp = if_lookup_by_ipv4_exact (&local->sin.sin_addr);
}
if (local->sa.sa_family == AF_INET6)
{
if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr))
{
- if (peer->ifname)
- ifp = if_lookup_by_name (peer->ifname);
+ if (peer->conf_if || peer->ifname)
+ ifp = if_lookup_by_index (if_nametoindex (peer->conf_if ? peer->conf_if : peer->ifname));
}
+ else if (peer->update_if)
+ ifp = if_lookup_by_name (peer->update_if);
else
- ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr);
+ ifp = if_lookup_by_ipv6_exact (&local->sin6.sin6_addr);
}
if (!ifp)
@@ -661,14 +839,73 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
return ret;
}
+static struct in6_addr *
+bgp_info_to_ipv6_nexthop (struct bgp_info *info)
+{
+ struct in6_addr *nexthop = NULL;
+
+ /* Only global address nexthop exists. */
+ if (info->attr->extra->mp_nexthop_len == 16)
+ nexthop = &info->attr->extra->mp_nexthop_global;
+
+ /* If both global and link-local address present. */
+ if (info->attr->extra->mp_nexthop_len == 32)
+ {
+ /* Workaround for Cisco's nexthop bug. */
+ if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
+ && info->peer->su_remote->sa.sa_family == AF_INET6)
+ nexthop = &info->peer->su_remote->sin6.sin6_addr;
+ else
+ nexthop = &info->attr->extra->mp_nexthop_local;
+ }
+
+ return nexthop;
+}
+
+static int
+bgp_table_map_apply (struct route_map *map, struct prefix *p,
+ struct bgp_info *info)
+{
+ if (route_map_apply(map, p, RMAP_BGP, info) != RMAP_DENYMATCH)
+ return 1;
+
+ if (bgp_debug_zebra(p))
+ {
+ if (p->family == AF_INET)
+ {
+ char buf[2][INET_ADDRSTRLEN];
+ zlog_debug("Zebra rmap deny: IPv4 route %s/%d nexthop %s",
+ inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
+ p->prefixlen,
+ inet_ntop(AF_INET, &info->attr->nexthop, buf[1],
+ sizeof(buf[1])));
+ }
+ if (p->family == AF_INET6)
+ {
+ char buf[2][INET6_ADDRSTRLEN];
+ zlog_debug("Zebra rmap deny: IPv6 route %s/%d nexthop %s",
+ inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
+ p->prefixlen,
+ inet_ntop(AF_INET6, bgp_info_to_ipv6_nexthop(info), buf[1],
+ sizeof(buf[1])));
+ }
+ }
+ return 0;
+}
+
void
-bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi)
+bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
+ afi_t afi, safi_t safi)
{
int flags;
u_char distance;
struct peer *peer;
struct bgp_info *mpinfo;
size_t oldsize, newsize;
+ u_int32_t nhcount, metric;
+ struct bgp_info local_info;
+ struct bgp_info *info_cp = &local_info;
+ u_short tag = 0;
if (zclient->sock < 0)
return;
@@ -676,9 +913,15 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_BGP], VRF_DEFAULT))
return;
+ if (bgp->main_zebra_update_hold)
+ return;
+
flags = 0;
peer = info->peer;
+ if ((info->attr->extra) && (info->attr->extra->tag != 0))
+ tag = info->attr->extra->tag;
+
if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED)
{
SET_FLAG (flags, ZEBRA_FLAG_IBGP);
@@ -689,46 +932,108 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
- /* resize nexthop buffer size if necessary */
- if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
- (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1)))
- {
- newsize = (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1));
- newsize = stream_resize (bgp_nexthop_buf, newsize);
- if (newsize == oldsize)
- {
- zlog_err ("can't resize nexthop buffer");
- return;
- }
- }
-
- stream_reset (bgp_nexthop_buf);
+ nhcount = 1 + bgp_info_mpath_count (info);
if (p->family == AF_INET)
{
struct zapi_ipv4 api;
struct in_addr *nexthop;
+ char buf[2][INET_ADDRSTRLEN];
+ int valid_nh_count = 0;
+
+ /* resize nexthop buffer size if necessary */
+ if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
+ (sizeof (struct in_addr *) * nhcount))
+ {
+ newsize = (sizeof (struct in_addr *) * nhcount);
+ newsize = stream_resize (bgp_nexthop_buf, newsize);
+ if (newsize == oldsize)
+ {
+ zlog_err ("can't resize nexthop buffer");
+ return;
+ }
+ }
+ stream_reset (bgp_nexthop_buf);
+ nexthop = NULL;
+
+ /* Metric is currently based on the best-path only. */
+ metric = info->attr->med;
+
+ if (bgp->table_map[afi][safi].name)
+ {
+ BGP_INFO_ATTR_BUF_INIT();
+
+ /* Copy info and attributes, so the route-map apply doesn't modify the
+ BGP route info. */
+ BGP_INFO_ATTR_BUF_COPY(info, info_cp);
+ if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
+ {
+ metric = info_cp->attr->med;
+ nexthop = &info_cp->attr->nexthop;
+
+ if (info_cp->attr->extra)
+ tag = info_cp->attr->extra->tag;
+ }
+ BGP_INFO_ATTR_BUF_FREE(info_cp);
+ }
+ else
+ {
+ nexthop = &info->attr->nexthop;
+ }
+
+ if (nexthop)
+ {
+ stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
+ valid_nh_count++;
+ }
api.vrf_id = VRF_DEFAULT;
api.flags = flags;
nexthop = &info->attr->nexthop;
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
+
for (mpinfo = bgp_info_mpath_first (info); mpinfo;
- mpinfo = bgp_info_mpath_next (mpinfo))
- {
- nexthop = &mpinfo->attr->nexthop;
- stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
- }
+ mpinfo = bgp_info_mpath_next (mpinfo))
+ {
+ nexthop = NULL;
+
+ if (bgp->table_map[afi][safi].name)
+ {
+ /* Copy info and attributes, so the route-map apply doesn't modify the
+ BGP route info. */
+ BGP_INFO_ATTR_BUF_COPY(mpinfo, info_cp);
+ if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
+ nexthop = &info_cp->attr->nexthop;
+ BGP_INFO_ATTR_BUF_FREE(info_cp);
+ }
+ else
+ {
+ nexthop = &mpinfo->attr->nexthop;
+ }
+
+ if (nexthop == NULL)
+ continue;
+
+ stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
+ valid_nh_count++;
+ }
+ api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
- api.nexthop_num = 1 + bgp_info_mpath_count (info);
+ api.nexthop_num = valid_nh_count;
api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf);
api.ifindex_num = 0;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
- api.metric = info->attr->med;
+ api.metric = metric;
+
+ if (tag)
+ {
+ SET_FLAG (api.message, ZAPI_MESSAGE_TAG);
+ api.tag = tag;
+ }
distance = bgp_distance_apply (p, info, bgp);
@@ -738,24 +1043,20 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
api.distance = distance;
}
- if (BGP_DEBUG(zebra, ZEBRA))
- {
- int i;
- char buf[2][INET_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u"
- " count %d",
- inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
- p->prefixlen,
- inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])),
- api.metric, api.nexthop_num);
- for (i = 1; i < api.nexthop_num; i++)
- zlog_debug("Zebra send: IPv4 route add [nexthop %d] %s",
- i, inet_ntop(AF_INET, api.nexthop[i], buf[1],
- sizeof(buf[1])));
- }
-
- zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient,
- (struct prefix_ipv4 *) p, &api);
+ if (bgp_debug_zebra(p))
+ {
+ int i;
+ zlog_debug("Zebra send: IPv4 route %s %s/%d metric %u tag %d"
+ " count %d", (valid_nh_count ? "add":"delete"),
+ 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])));
+ }
+
+ zapi_ipv4_route (valid_nh_count ? ZEBRA_IPV4_ROUTE_ADD: ZEBRA_IPV4_ROUTE_DELETE,
+ zclient, (struct prefix_ipv4 *) p, &api);
}
/* We have to think about a IPv6 link-local address curse. */
@@ -764,40 +1065,131 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
ifindex_t ifindex;
struct in6_addr *nexthop;
struct zapi_ipv6 api;
+ int valid_nh_count = 0;
+ char buf[2][INET6_ADDRSTRLEN];
+
+ /* resize nexthop buffer size if necessary */
+ if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
+ (sizeof (struct in6_addr *) * nhcount))
+ {
+ newsize = (sizeof (struct in6_addr *) * nhcount);
+ newsize = stream_resize (bgp_nexthop_buf, newsize);
+ if (newsize == oldsize)
+ {
+ zlog_err ("can't resize nexthop buffer");
+ return;
+ }
+ }
+ stream_reset (bgp_nexthop_buf);
+
+ /* resize ifindices buffer size if necessary */
+ if ((oldsize = stream_get_size (bgp_ifindices_buf)) <
+ (sizeof (unsigned int) * nhcount))
+ {
+ newsize = (sizeof (unsigned int) * nhcount);
+ newsize = stream_resize (bgp_ifindices_buf, newsize);
+ if (newsize == oldsize)
+ {
+ zlog_err ("can't resize nexthop buffer");
+ return;
+ }
+ }
+ stream_reset (bgp_ifindices_buf);
ifindex = 0;
nexthop = NULL;
-
- assert (info->attr->extra);
-
- /* Only global address nexthop exists. */
- if (info->attr->extra->mp_nexthop_len == 16)
- nexthop = &info->attr->extra->mp_nexthop_global;
-
- /* If both global and link-local address present. */
- if (info->attr->extra->mp_nexthop_len == 32)
- {
- /* Workaround for Cisco's nexthop bug. */
- if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
- && peer->su_remote->sa.sa_family == AF_INET6)
- nexthop = &peer->su_remote->sin6.sin6_addr;
- else
- nexthop = &info->attr->extra->mp_nexthop_local;
- if (info->peer->nexthop.ifp)
- ifindex = info->peer->nexthop.ifp->ifindex;
- }
+ assert (info->attr->extra);
- if (nexthop == NULL)
- return;
+ /* Metric is currently based on the best-path only. */
+ metric = info->attr->med;
+
+ if (bgp->table_map[afi][safi].name)
+ {
+ BGP_INFO_ATTR_BUF_INIT();
+
+ /* Copy info and attributes, so the route-map apply doesn't modify the
+ BGP route info. */
+ BGP_INFO_ATTR_BUF_COPY(info, info_cp);
+ if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
+ {
+ metric = info_cp->attr->med;
+ nexthop = bgp_info_to_ipv6_nexthop(info_cp);
+
+ if (info_cp->attr->extra)
+ tag = info_cp->attr->extra->tag;
+ }
+ BGP_INFO_ATTR_BUF_FREE(info_cp);
+ }
+ else
+ {
+ nexthop = bgp_info_to_ipv6_nexthop(info);
+ }
+
+ if (nexthop)
+ {
+ if (IN6_IS_ADDR_LINKLOCAL (nexthop))
+ {
+ if (info->attr->extra->mp_nexthop_len == 32)
+ if (info->peer->nexthop.ifp)
+ ifindex = info->peer->nexthop.ifp->ifindex;
+
+ if (!ifindex)
+ {
+ if (info->peer->conf_if || info->peer->ifname)
+ ifindex = if_nametoindex (info->peer->conf_if ? info->peer->conf_if : info->peer->ifname);
+ else if (info->peer->nexthop.ifp)
+ ifindex = info->peer->nexthop.ifp->ifindex;
+ }
+ }
+
+ stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
+ stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
+ valid_nh_count++;
+ }
- if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex)
- {
- if (info->peer->ifname)
- ifindex = ifname2ifindex (info->peer->ifname);
- else if (info->peer->nexthop.ifp)
- ifindex = info->peer->nexthop.ifp->ifindex;
- }
+ for (mpinfo = bgp_info_mpath_first (info); mpinfo;
+ mpinfo = bgp_info_mpath_next (mpinfo))
+ {
+ ifindex = 0;
+ nexthop = NULL;
+
+ if (bgp->table_map[afi][safi].name)
+ {
+ /* Copy info and attributes, so the route-map apply doesn't modify the
+ BGP route info. */
+ BGP_INFO_ATTR_BUF_COPY(mpinfo, info_cp);
+ if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
+ nexthop = bgp_info_to_ipv6_nexthop(info_cp);
+ BGP_INFO_ATTR_BUF_FREE(info_cp);
+ }
+ else
+ {
+ nexthop = bgp_info_to_ipv6_nexthop(mpinfo);
+ }
+
+ if (nexthop == NULL)
+ continue;
+
+ if (mpinfo->attr->extra->mp_nexthop_len == 32)
+ if (mpinfo->peer->nexthop.ifp)
+ ifindex = mpinfo->peer->nexthop.ifp->ifindex;
+
+ if (!ifindex)
+ {
+ if (mpinfo->peer->conf_if || mpinfo->peer->ifname)
+ ifindex = if_nametoindex (mpinfo->peer->conf_if ? mpinfo->peer->conf_if : mpinfo->peer->ifname);
+ else if (mpinfo->peer->nexthop.ifp)
+ ifindex = mpinfo->peer->nexthop.ifp->ifindex;
+ }
+
+ if (ifindex == 0)
+ continue;
+
+ stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
+ stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
+ valid_nh_count++;
+ }
/* Make Zebra API structure. */
api.vrf_id = VRF_DEFAULT;
@@ -806,29 +1198,57 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
api.message = 0;
api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
- api.nexthop_num = 1;
- api.nexthop = &nexthop;
+ api.nexthop_num = valid_nh_count;
+ api.nexthop = (struct in6_addr **)STREAM_DATA (bgp_nexthop_buf);
SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
- api.ifindex_num = 1;
- api.ifindex = &ifindex;
+ api.ifindex_num = valid_nh_count;
+ api.ifindex = (ifindex_t *)STREAM_DATA (bgp_ifindices_buf);
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
- api.metric = info->attr->med;
+ api.metric = metric;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (tag)
{
- char buf[2][INET6_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %u",
- inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
- p->prefixlen,
- inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])),
- api.metric);
+ SET_FLAG (api.message, ZAPI_MESSAGE_TAG);
+ api.tag = tag;
}
- zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient,
- (struct prefix_ipv6 *) p, &api);
+ if (bgp_debug_zebra(p))
+ {
+ int i;
+ zlog_debug("Zebra send: IPv6 route %s %s/%d metric %u tag %d",
+ valid_nh_count ? "add" : "delete",
+ 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 (%d)", i+1,
+ inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])),
+ api.ifindex[i]);
+ }
+
+ zapi_ipv6_route (valid_nh_count ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE,
+ zclient, (struct prefix_ipv6 *) p, &api);
}
}
+/* Announce all routes of a table to zebra */
+void
+bgp_zebra_announce_table (struct bgp *bgp, afi_t afi, safi_t safi)
+{
+ struct bgp_node *rn;
+ struct bgp_table *table;
+ struct bgp_info *ri;
+
+ table = bgp->rib[afi][safi];
+ if (!table) return;
+
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ for (ri = rn->info; ri; ri = ri->next)
+ 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);
+}
+
void
bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
{
@@ -842,6 +1262,10 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
return;
peer = info->peer;
+
+ if (peer->bgp && peer->bgp->main_zebra_update_hold)
+ return;
+
flags = 0;
if (peer->sort == BGP_PEER_IBGP)
@@ -869,13 +1293,20 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if ((info->attr->extra) && (info->attr->extra->tag != 0))
+ {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+ api.tag = info->attr->extra->tag;
+ }
+
+ if (bgp_debug_zebra(p))
{
char buf[2][INET_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u",
+ zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u tag %d",
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen,
- api.metric);
+ api.metric,
+ api.tag);
}
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient,
@@ -886,7 +1317,6 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
if (p->family == AF_INET6)
{
struct zapi_ipv6 api;
-
api.vrf_id = VRF_DEFAULT;
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
@@ -897,13 +1327,20 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if ((info->attr->extra) && (info->attr->extra->tag != 0))
+ {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+ api.tag = info->attr->extra->tag;
+ }
+
+ if (bgp_debug_zebra(p))
{
char buf[2][INET6_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u",
+ zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u tag %d",
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
p->prefixlen,
- api.metric);
+ api.metric,
+ api.tag);
}
zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient,
@@ -928,15 +1365,32 @@ bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type)
if (zclient->sock < 0)
return CMD_WARNING;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Zebra send: redistribute add %s", zebra_route_string(type));
-
+
/* Send distribute add message to zebra. */
zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT);
return CMD_SUCCESS;
}
+int
+bgp_redistribute_resend (struct bgp *bgp, afi_t afi, int type)
+{
+ /* Return if zebra connection is not established. */
+ if (zclient->sock < 0)
+ return -1;
+
+ if (BGP_DEBUG (zebra, ZEBRA))
+ zlog_debug("Zebra send: redistribute add %s", zebra_route_string(type));
+
+ /* Send distribute add message to zebra. */
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type, VRF_DEFAULT);
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT);
+
+ return 0;
+}
+
/* Redistribute with route-map specification. */
int
bgp_redistribute_rmap_set (struct bgp *bgp, afi_t afi, int type,
@@ -996,7 +1450,7 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type)
&& zclient->sock >= 0)
{
/* Send distribute delete message to zebra. */
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Zebra send: redistribute delete %s",
zebra_route_string(type));
zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type,
@@ -1009,35 +1463,6 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type)
return CMD_SUCCESS;
}
-/* Unset redistribution route-map configuration. */
-int
-bgp_redistribute_routemap_unset (struct bgp *bgp, afi_t afi, int type)
-{
- if (! bgp->rmap[afi][type].name)
- return 0;
-
- /* Unset route-map. */
- free (bgp->rmap[afi][type].name);
- bgp->rmap[afi][type].name = NULL;
- bgp->rmap[afi][type].map = NULL;
-
- return 1;
-}
-
-/* Unset redistribution metric configuration. */
-int
-bgp_redistribute_metric_unset (struct bgp *bgp, afi_t afi, int type)
-{
- if (! bgp->redist_metric_flag[afi][type])
- return 0;
-
- /* Unset metric. */
- bgp->redist_metric_flag[afi][type] = 0;
- bgp->redist_metric[afi][type] = 0;
-
- return 1;
-}
-
void
bgp_zclient_reset (void)
{
@@ -1062,14 +1487,18 @@ bgp_zebra_init (struct thread_master *master)
zclient->interface_delete = bgp_interface_delete;
zclient->interface_address_add = bgp_interface_address_add;
zclient->interface_address_delete = bgp_interface_address_delete;
+ zclient->interface_nbr_address_add = bgp_interface_nbr_address_add;
+ zclient->interface_nbr_address_delete = bgp_interface_nbr_address_delete;
zclient->ipv4_route_add = zebra_read_ipv4;
zclient->ipv4_route_delete = zebra_read_ipv4;
zclient->interface_up = bgp_interface_up;
zclient->interface_down = bgp_interface_down;
zclient->ipv6_route_add = zebra_read_ipv6;
zclient->ipv6_route_delete = zebra_read_ipv6;
+ zclient->nexthop_update = bgp_read_nexthop_update;
bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE);
+ bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE);
}
void
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index e69a0bc5..0b76263c 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -22,8 +22,10 @@ Boston, MA 02111-1307, USA. */
#define _QUAGGA_BGP_ZEBRA_H
#define BGP_NEXTHOP_BUF_SIZE (8 * sizeof (struct in_addr *))
+#define BGP_IFINDICES_BUF_SIZE (8 * sizeof (unsigned int))
extern struct stream *bgp_nexthop_buf;
+extern struct stream *bgp_ifindices_buf;
extern void bgp_zebra_init (struct thread_master *master);
extern void bgp_zebra_destroy (void);
@@ -32,15 +34,16 @@ extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t,
safi_t, int *);
extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t,
int *);
-extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *, safi_t);
+extern void bgp_zebra_announce (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);
extern int bgp_redistribute_set (struct bgp *, afi_t, int);
+extern int bgp_redistribute_resend (struct bgp *, afi_t, int);
extern int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, const char *);
extern int bgp_redistribute_metric_set (struct bgp *, afi_t, int, u_int32_t);
extern int bgp_redistribute_unset (struct bgp *, afi_t, int);
-extern int bgp_redistribute_routemap_unset (struct bgp *, afi_t, int);
-extern int bgp_redistribute_metric_unset (struct bgp *, afi_t, int);
extern struct interface *if_lookup_by_ipv4 (struct in_addr *);
extern struct interface *if_lookup_by_ipv4_exact (struct in_addr *);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 249d20f3..72ad1c19 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -61,6 +61,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_network.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_mpath.h"
+#include "bgpd/bgp_nht.h"
#ifdef HAVE_SNMP
#include "bgpd/bgp_snmp.h"
#endif /* HAVE_SNMP */
@@ -76,6 +77,44 @@ struct bgp_master *bm;
/* BGP community-list. */
struct community_list_handler *bgp_clist;
+
+static inline void
+bgp_session_reset(struct peer *peer)
+{
+ if (peer->doppelganger && (peer->doppelganger->status != Deleted)
+ && !(CHECK_FLAG(peer->doppelganger->flags, PEER_FLAG_CONFIG_NODE)))
+ peer_delete(peer->doppelganger);
+
+ BGP_EVENT_ADD (peer, BGP_Stop);
+}
+
+/*
+ * During session reset, we may delete the doppelganger peer, which would
+ * be the next node to the current node. If the session reset was invoked
+ * during walk of peer list, we would end up accessing the freed next
+ * node. This function moves the next node along.
+ */
+static inline void
+bgp_session_reset_safe(struct peer *peer, struct listnode **nnode)
+{
+ struct listnode *n;
+ struct peer *npeer;
+
+ n = (nnode) ? *nnode : NULL;
+ npeer = (n) ? listgetdata(n) : NULL;
+
+ if (peer->doppelganger && (peer->doppelganger->status != Deleted)
+ && !(CHECK_FLAG(peer->doppelganger->flags, PEER_FLAG_CONFIG_NODE)))
+ {
+ if (peer->doppelganger == npeer)
+ /* nnode and *nnode are confirmed to be non-NULL here */
+ *nnode = (*nnode)->next;
+ peer_delete(peer->doppelganger);
+ }
+
+ BGP_EVENT_ADD (peer, BGP_Stop);
+}
+
/* BGP global flag manipulation. */
int
bgp_option_set (int flag)
@@ -311,9 +350,8 @@ bgp_confederation_id_set (struct bgp *bgp, as_t as)
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
-
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset_safe(peer, &nnode);
}
}
else
@@ -332,7 +370,7 @@ bgp_confederation_id_set (struct bgp *bgp, as_t as)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset_safe(peer, &nnode);
}
}
}
@@ -362,7 +400,7 @@ bgp_confederation_id_unset (struct bgp *bgp)
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset_safe(peer, &nnode);
}
}
return 0;
@@ -425,7 +463,7 @@ bgp_confederation_peers_add (struct bgp *bgp, as_t as)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset_safe(peer, &nnode);
}
}
}
@@ -481,7 +519,7 @@ bgp_confederation_peers_remove (struct bgp *bgp, as_t as)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset_safe(peer, &nnode);
}
}
}
@@ -530,7 +568,7 @@ peer_rsclient_active (struct peer *peer)
}
/* Peer comparison function for sorting. */
-static int
+int
peer_cmp (struct peer *p1, struct peer *p2)
{
return sockunion_cmp (&p1->su, &p2->su);
@@ -759,6 +797,10 @@ peer_free (struct peer *peer)
XFREE(MTYPE_TMP, peer->notify.data);
bgp_sync_delete (peer);
+
+ if (peer->conf_if)
+ XFREE (MTYPE_PEER_CONF_IF, peer->conf_if);
+
memset (peer, 0, sizeof (struct peer));
XFREE (MTYPE_BGP_PEER, peer);
@@ -801,7 +843,7 @@ peer_unlock_with_caller (const char *name, struct peer *peer)
return peer;
}
-
+
/* Allocate new peer object, implicitely locked. */
static struct peer *
peer_new (struct bgp *bgp)
@@ -825,11 +867,11 @@ peer_new (struct bgp *bgp)
peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
peer->status = Idle;
peer->ostatus = Idle;
- peer->weight = 0;
- peer->password = NULL;
peer->bgp = bgp;
peer = peer_lock (peer); /* initial reference */
bgp_lock (bgp);
+ peer->weight = 0;
+ peer->password = NULL;
/* Set default flags. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
@@ -847,9 +889,22 @@ peer_new (struct bgp *bgp)
/* Create buffers. */
peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE);
peer->obuf = stream_fifo_new ();
- peer->work = stream_new (BGP_MAX_PACKET_SIZE);
+
+ /* We use a larger buffer for peer->work in the event that:
+ * - We RX a BGP_UPDATE where the attributes alone are just
+ * under BGP_MAX_PACKET_SIZE
+ * - The user configures an outbound route-map that does many as-path
+ * prepends or adds many communities. At most they can have CMD_ARGC_MAX
+ * args in a route-map so there is a finite limit on how large they can
+ * make the attributes.
+ *
+ * Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid bounds
+ * checking for every single attribute as we construct an UPDATE.
+ */
+ peer->work = stream_new (BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW);
peer->scratch = stream_new (BGP_MAX_PACKET_SIZE);
+
bgp_sync_init (peer);
/* Get service port number. */
@@ -859,17 +914,149 @@ peer_new (struct bgp *bgp)
return peer;
}
+/*
+ * This function is invoked when a duplicate peer structure associated with
+ * a neighbor is being deleted. If this about-to-be-deleted structure is
+ * the one with all the config, then we have to copy over the info.
+ */
+void
+peer_xfer_config (struct peer *peer_dst, struct peer *peer_src)
+{
+ afi_t afi;
+ safi_t safi;
+
+ assert(peer_src);
+ assert(peer_dst);
+
+ /* The following function is used by both peer group config copy to
+ * individual peer and when we transfer config
+ */
+ if (peer_src->change_local_as)
+ peer_dst->change_local_as = peer_src->change_local_as;
+
+ /* peer flags apply */
+ peer_dst->flags = peer_src->flags;
+ peer_dst->cap = peer_src->cap;
+ peer_dst->config = peer_src->config;
+
+ peer_dst->local_as = peer_src->local_as;
+ peer_dst->ifindex = peer_src->ifindex;
+ peer_dst->port = peer_src->port;
+ peer_sort(peer_dst);
+ peer_dst->rmap_type = peer_src->rmap_type;
+
+ /* Timers */
+ peer_dst->holdtime = peer_src->holdtime;
+ peer_dst->keepalive = peer_src->keepalive;
+ peer_dst->connect = peer_src->connect;
+ peer_dst->v_holdtime = peer_src->v_holdtime;
+ peer_dst->v_keepalive = peer_src->v_keepalive;
+ peer_dst->routeadv = peer_src->routeadv;
+ peer_dst->v_routeadv = peer_src->v_routeadv;
+
+ /* password apply */
+ if (peer_src->password && !peer_dst->password)
+ peer_dst->password = XSTRDUP (MTYPE_PEER_PASSWORD, peer_src->password);
+
+ bgp_md5_set (peer_dst);
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ peer_dst->afc[afi][safi] = peer_src->afc[afi][safi];
+ peer_dst->af_flags[afi][safi] = peer_src->af_flags[afi][safi];
+ peer_dst->allowas_in[afi][safi] = peer_src->allowas_in[afi][safi];
+ }
+
+ /* update-source apply */
+ if (peer_src->update_source)
+ {
+ if (peer_dst->update_source)
+ sockunion_free (peer_dst->update_source);
+ if (peer_dst->update_if)
+ {
+ XFREE (MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
+ peer_dst->update_if = NULL;
+ }
+ peer_dst->update_source = sockunion_dup (peer_src->update_source);
+ }
+ else if (peer_src->update_if)
+ {
+ if (peer_dst->update_if)
+ XFREE (MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
+ if (peer_dst->update_source)
+ {
+ sockunion_free (peer_dst->update_source);
+ peer_dst->update_source = NULL;
+ }
+ peer_dst->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, peer_src->update_if);
+ }
+
+ if (peer_src->ifname)
+ {
+ if (peer_dst->ifname)
+ free(peer_dst->ifname);
+
+ peer_dst->ifname = strdup(peer_src->ifname);
+ }
+}
+
+/*
+ * Set or reset the peer address socketunion structure based on the
+ * learnt peer address. Currently via the source address of the
+ * ipv6 ND router-advertisement.
+ */
+void
+bgp_peer_conf_if_to_su_update (struct peer *peer)
+{
+ struct interface *ifp;
+ struct nbr_connected *ifc;
+
+ if (!peer->conf_if)
+ return;
+
+ if ((ifp = if_lookup_by_name(peer->conf_if)) &&
+ ifp->nbr_connected &&
+ (ifc = listnode_head(ifp->nbr_connected)))
+ {
+ peer->su.sa.sa_family = AF_INET6;
+ memcpy(&peer->su.sin6.sin6_addr, &ifc->address->u.prefix,
+ sizeof (struct in6_addr));
+#ifdef SIN6_LEN
+ peer->su.sin6.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+ }
+ else
+ {
+ /* This works as an indication of unresolved peer address
+ on a BGP interface*/
+ peer->su.sa.sa_family = AF_UNSPEC;
+ memset(&peer->su.sin6.sin6_addr, 0, sizeof (struct in6_addr));
+ }
+}
+
/* Create new BGP peer. */
-static struct peer *
-peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
- as_t remote_as, afi_t afi, safi_t safi)
+struct peer *
+peer_create (union sockunion *su, const char *conf_if, struct bgp *bgp,
+ as_t local_as, as_t remote_as, afi_t afi, safi_t safi)
{
int active;
struct peer *peer;
char buf[SU_ADDRSTRLEN];
peer = peer_new (bgp);
- peer->su = *su;
+ if (conf_if)
+ {
+ peer->conf_if = XSTRDUP (MTYPE_PEER_CONF_IF, conf_if);
+ bgp_peer_conf_if_to_su_update(peer);
+ peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, conf_if);
+ }
+ else if (su)
+ {
+ peer->su = *su;
+ sockunion2str (su, buf, SU_ADDRSTRLEN);
+ peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf);
+ }
peer->local_as = local_as;
peer->as = remote_as;
peer->local_id = bgp->router_id;
@@ -894,9 +1081,7 @@ peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
/* Default TTL set. */
peer->ttl = (peer->sort == BGP_PEER_IBGP) ? 255 : 1;
- /* Make peer's address string. */
- sockunion2str (su, buf, SU_ADDRSTRLEN);
- peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf);
+ SET_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE);
/* Set up peer's events and timers. */
if (! active && peer_active (peer))
@@ -905,6 +1090,26 @@ peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
return peer;
}
+struct peer *
+peer_conf_interface_get(struct bgp *bgp, const char *conf_if, afi_t afi,
+ safi_t safi)
+{
+ struct peer *peer;
+
+ peer = peer_lookup_by_conf_if (bgp, conf_if);
+ if (!peer)
+ {
+ if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)
+ && afi == AFI_IP && safi == SAFI_UNICAST)
+ peer = peer_create (NULL, conf_if, bgp, bgp->as, 0, 0, 0);
+ else
+ peer = peer_create (NULL, conf_if, bgp, bgp->as, 0, afi, safi);
+
+ }
+
+ return peer;
+}
+
/* Make accept BGP peer. Called from bgp_accept (). */
struct peer *
peer_create_accept (struct bgp *bgp)
@@ -912,7 +1117,7 @@ peer_create_accept (struct bgp *bgp)
struct peer *peer;
peer = peer_new (bgp);
-
+
peer = peer_lock (peer); /* bgp peer list reference */
listnode_add_sort (bgp->peer, peer);
@@ -920,7 +1125,7 @@ peer_create_accept (struct bgp *bgp)
}
/* Change peer's AS number. */
-static void
+void
peer_as_change (struct peer *peer, as_t as)
{
bgp_peer_sort_t type;
@@ -936,7 +1141,7 @@ peer_as_change (struct peer *peer, as_t as)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
type = peer_sort (peer);
peer->as = as;
@@ -1000,13 +1205,16 @@ peer_as_change (struct peer *peer, as_t as)
/* If peer does not exist, create new one. If peer already exists,
set AS number to the peer. */
int
-peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as,
- afi_t afi, safi_t safi)
+peer_remote_as (struct bgp *bgp, union sockunion *su, const char *conf_if, as_t *as,
+ afi_t afi, safi_t safi)
{
struct peer *peer;
as_t local_as;
- peer = peer_lookup (bgp, su);
+ if (conf_if)
+ peer = peer_lookup_by_conf_if (bgp, conf_if);
+ else
+ peer = peer_lookup (bgp, su);
if (peer)
{
@@ -1043,6 +1251,8 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as,
}
else
{
+ if (conf_if)
+ return BGP_ERR_NO_INTERFACE_CONFIG;
/* If the peer is not part of our confederation, and its not an
iBGP peer then spoof the source AS */
@@ -1058,9 +1268,9 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as,
if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)
&& afi == AFI_IP && safi == SAFI_UNICAST)
- peer_create (su, bgp, local_as, *as, 0, 0);
+ peer = peer_create (su, conf_if, bgp, local_as, *as, 0, 0);
else
- peer_create (su, bgp, local_as, *as, afi, safi);
+ peer = peer_create (su, conf_if, bgp, local_as, *as, afi, safi);
}
return 0;
@@ -1195,13 +1405,13 @@ peer_nsf_stop (struct peer *peer)
if (peer->t_gr_restart)
{
BGP_TIMER_OFF (peer->t_gr_restart);
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s graceful restart timer stopped", peer->host);
}
if (peer->t_gr_stale)
{
BGP_TIMER_OFF (peer->t_gr_stale);
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
}
bgp_clear_route_all (peer);
@@ -1229,12 +1439,14 @@ peer_delete (struct peer *peer)
struct listnode *pn;
assert (peer->status != Deleted);
-
+
bgp = peer->bgp;
if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
peer_nsf_stop (peer);
+ SET_FLAG(peer->flags, PEER_FLAG_DELETE);
+
/* If this peer belongs to peer group, clear up the
relationship. */
if (peer->group)
@@ -1253,6 +1465,13 @@ peer_delete (struct peer *peer)
*/
peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
bgp_stop (peer);
+ UNSET_FLAG(peer->flags, PEER_FLAG_DELETE);
+
+ if (peer->doppelganger)
+ peer->doppelganger->doppelganger = NULL;
+ peer->doppelganger = NULL;
+
+ UNSET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
bgp_fsm_change_status (peer, Deleted);
/* Password configuration */
@@ -1266,7 +1485,7 @@ peer_delete (struct peer *peer)
}
bgp_timer_set (peer); /* stops all timers for Deleted */
-
+
/* Delete from all peer list. */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
&& (pn = listnode_lookup (bgp->peer, peer)))
@@ -1281,12 +1500,15 @@ peer_delete (struct peer *peer)
peer_unlock (peer); /* rsclient list reference */
list_delete_node (bgp->rsclient, pn);
- /* Clear our own rsclient ribs. */
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- if (CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_RSERVER_CLIENT))
- bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT);
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+ {
+ /* Clear our own rsclient ribs. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_RSERVER_CLIENT))
+ bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT);
+ }
}
/* Free RIB for any family in which peer is RSERVER_CLIENT, and is not
@@ -1765,13 +1987,21 @@ peer_group_delete (struct peer_group *group)
{
struct bgp *bgp;
struct peer *peer;
+ struct peer *other;
struct listnode *node, *nnode;
bgp = group->bgp;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
+ other = peer->doppelganger;
+ peer->group = NULL;
peer_delete (peer);
+ if (other && other->status != Deleted)
+ {
+ other->group = NULL;
+ peer_delete(other);
+ }
}
list_delete (group->peer);
@@ -1792,7 +2022,7 @@ peer_group_delete (struct peer_group *group)
int
peer_group_remote_as_delete (struct peer_group *group)
{
- struct peer *peer;
+ struct peer *peer, *other;
struct listnode *node, *nnode;
if (! group->conf->as)
@@ -1800,7 +2030,16 @@ peer_group_remote_as_delete (struct peer_group *group)
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
+ other = peer->doppelganger;
+
+ peer->group = NULL;
peer_delete (peer);
+
+ if (other && other->status != Deleted)
+ {
+ other->group = NULL;
+ peer_delete(other);
+ }
}
list_delete_all_node (group->peer);
@@ -1811,10 +2050,9 @@ peer_group_remote_as_delete (struct peer_group *group)
/* Bind specified peer to peer group. */
int
-peer_group_bind (struct bgp *bgp, union sockunion *su,
+peer_group_bind (struct bgp *bgp, union sockunion *su, struct peer *peer,
struct peer_group *group, afi_t afi, safi_t safi, as_t *as)
{
- struct peer *peer;
int first_member = 0;
/* Check peer group's address family. */
@@ -1822,7 +2060,8 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
return BGP_ERR_PEER_GROUP_AF_UNCONFIGURED;
/* Lookup the peer. */
- peer = peer_lookup (bgp, su);
+ if (!peer)
+ peer = peer_lookup (bgp, su);
/* Create a new peer. */
if (! peer)
@@ -1830,13 +2069,14 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
if (! group->conf->as)
return BGP_ERR_PEER_GROUP_NO_REMOTE_AS;
- peer = peer_create (su, bgp, bgp->as, group->conf->as, afi, safi);
+ peer = peer_create (su, NULL, bgp, bgp->as, group->conf->as, afi, safi);
peer->group = group;
peer->af_group[afi][safi] = 1;
peer = peer_lock (peer); /* group->peer list reference */
listnode_add (group->peer, peer);
peer_group2peer_config_copy (group, peer, afi, safi);
+ SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
return 0;
}
@@ -1943,6 +2183,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
}
peer_group2peer_config_copy (group, peer, afi, safi);
+ SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
{
@@ -1951,7 +2192,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
return 0;
}
@@ -1960,6 +2201,8 @@ int
peer_group_unbind (struct bgp *bgp, struct peer *peer,
struct peer_group *group, afi_t afi, safi_t safi)
{
+ struct peer *other;
+
if (! peer->af_group[afi][safi])
return 0;
@@ -1979,9 +2222,20 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer,
peer_unlock (peer); /* peer group list reference */
listnode_delete (group->peer, peer);
peer->group = NULL;
+ other = peer->doppelganger;
if (group->conf->as)
{
peer_delete (peer);
+ if (other && other->status != Deleted)
+ {
+ if (other->group)
+ {
+ peer_unlock(other);
+ listnode_delete(group->peer, other);
+ }
+ other->group = NULL;
+ peer_delete(other);
+ }
return 0;
}
peer_global_config_reset (peer);
@@ -1994,7 +2248,7 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
return 0;
}
@@ -2045,6 +2299,7 @@ bgp_create (as_t *as, const char *name)
bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS;
}
+ bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
@@ -2057,6 +2312,10 @@ bgp_create (as_t *as, const char *name)
if (name)
bgp->name = strdup (name);
+ bgp->wpkt_quanta = BGP_WRITE_PACKET_MAX;
+ bgp->adv_quanta = BGP_ADV_FIFO_QUANTA;
+ bgp->wd_quanta = BGP_WD_FIFO_QUANTA;
+
THREAD_TIMER_ON (bm->master, bgp->t_startup, bgp_startup_timer_expire,
bgp, bgp->restart_time);
@@ -2152,6 +2411,9 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name)
bgp_router_id_set(bgp, &router_id_zebra);
*bgp_val = bgp;
+ bgp->t_rmap_update = NULL;
+ bgp->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER;
+
/* Create BGP server socket, if first instance. */
if (list_isempty(bm->bgp)
&& !bgp_option_check (BGP_OPT_NO_LISTEN))
@@ -2180,6 +2442,20 @@ bgp_delete (struct bgp *bgp)
THREAD_OFF (bgp->t_startup);
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer))
+ {
+ if (peer->status == Established ||
+ peer->status == OpenSent ||
+ peer->status == OpenConfirm)
+ {
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_PEER_UNCONFIG);
+ }
+ }
+
+ if (bgp->t_rmap_update)
+ BGP_TIMER_OFF(bgp->t_rmap_update);
+
/* Delete static route. */
bgp_static_delete (bgp);
@@ -2189,17 +2465,6 @@ bgp_delete (struct bgp *bgp)
if (i != ZEBRA_ROUTE_BGP)
bgp_redistribute_unset (bgp, afi, i);
- for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- /* Send notify to remote peer. */
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
- }
-
- peer_delete (peer);
- }
-
for (ALL_LIST_ELEMENTS (bgp->group, node, next, group))
{
for (ALL_LIST_ELEMENTS (group->peer, pnode, pnext, peer))
@@ -2213,6 +2478,17 @@ bgp_delete (struct bgp *bgp)
peer_group_delete (group);
}
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer))
+ {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ {
+ /* Send notify to remote peer. */
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
+ }
+
+ peer_delete (peer);
+ }
+
assert (listcount (bgp->rsclient) == 0);
if (bgp->peer_self) {
@@ -2284,25 +2560,28 @@ bgp_free (struct bgp *bgp)
}
struct peer *
-peer_lookup (struct bgp *bgp, union sockunion *su)
+peer_lookup_by_conf_if (struct bgp *bgp, const char *conf_if)
{
struct peer *peer;
struct listnode *node, *nnode;
+ if (!conf_if)
+ return NULL;
+
if (bgp != NULL)
{
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (sockunion_same (&peer->su, su)
+ if (peer->conf_if && !strcmp(peer->conf_if, conf_if)
&& ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
return peer;
}
else if (bm->bgp != NULL)
{
struct listnode *bgpnode, *nbgpnode;
-
+
for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp))
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (sockunion_same (&peer->su, su)
+ if (peer->conf_if && !strcmp(peer->conf_if, conf_if)
&& ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
return peer;
}
@@ -2310,44 +2589,27 @@ peer_lookup (struct bgp *bgp, union sockunion *su)
}
struct peer *
-peer_lookup_with_open (union sockunion *su, as_t remote_as,
- struct in_addr *remote_id, int *as)
+peer_lookup (struct bgp *bgp, union sockunion *su)
{
struct peer *peer;
- struct listnode *node;
- struct listnode *bgpnode;
- struct bgp *bgp;
-
- if (! bm->bgp)
- return NULL;
+ struct listnode *node, *nnode;
- for (ALL_LIST_ELEMENTS_RO (bm->bgp, bgpnode, bgp))
+ if (bgp != NULL)
{
- for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
- {
- if (sockunion_same (&peer->su, su)
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- if (peer->as == remote_as
- && peer->remote_id.s_addr == remote_id->s_addr)
- return peer;
- if (peer->as == remote_as)
- *as = 1;
- }
- }
-
- for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
- {
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ if (sockunion_same (&peer->su, su)
+ && (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE)))
+ return peer;
+ }
+ else if (bm->bgp != NULL)
+ {
+ struct listnode *bgpnode, *nbgpnode;
+
+ for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp))
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
if (sockunion_same (&peer->su, su)
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- if (peer->as == remote_as
- && peer->remote_id.s_addr == 0)
- return peer;
- if (peer->as == remote_as)
- *as = 1;
- }
- }
+ && (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE)))
+ return peer;
}
return NULL;
}
@@ -2356,6 +2618,8 @@ peer_lookup_with_open (union sockunion *su, as_t remote_as,
int
peer_active (struct peer *peer)
{
+ if (BGP_PEER_SU_UNSPEC(peer))
+ return 0;
if (peer->afc[AFI_IP][SAFI_UNICAST]
|| peer->afc[AFI_IP][SAFI_MULTICAST]
|| peer->afc[AFI_IP][SAFI_MPLS_VPN]
@@ -2404,16 +2668,31 @@ peer_change_action (struct peer *peer, afi_t afi, safi_t safi,
return;
if (type == peer_change_reset)
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ {
+ /* If we're resetting session, we've to delete both peer struct */
+ if ((peer->doppelganger) && (peer->doppelganger->status != Deleted)
+ && (!CHECK_FLAG(peer->doppelganger->flags,
+ PEER_FLAG_CONFIG_NODE)))
+ peer_delete(peer->doppelganger);
+
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
else if (type == peer_change_reset_in)
{
if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
|| CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
else
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ {
+ if ((peer->doppelganger) && (peer->doppelganger->status != Deleted)
+ && (!CHECK_FLAG(peer->doppelganger->flags,
+ PEER_FLAG_CONFIG_NODE)))
+ peer_delete(peer->doppelganger);
+
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
}
else if (type == peer_change_reset_out)
bgp_announce_route (peer, afi, safi);
@@ -2458,11 +2737,14 @@ static const struct peer_flag_action peer_af_flag_action_list[] =
{ PEER_FLAG_NEXTHOP_UNCHANGED, 1, peer_change_reset_out },
{ PEER_FLAG_MED_UNCHANGED, 1, peer_change_reset_out },
{ PEER_FLAG_REMOVE_PRIVATE_AS, 1, peer_change_reset_out },
+ { PEER_FLAG_REMOVE_PRIVATE_AS_ALL, 1, peer_change_reset_out },
+ { PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,1, peer_change_reset_out },
{ PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in },
{ PEER_FLAG_ORF_PREFIX_SM, 1, peer_change_reset },
{ PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset },
{ PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out },
{ PEER_FLAG_NEXTHOP_SELF_ALL, 1, peer_change_reset_out },
+ { PEER_FLAG_AS_OVERRIDE, 1, peer_change_reset_out },
{ 0, 0, 0 }
};
@@ -2530,19 +2812,19 @@ peer_flag_modify_action (struct peer *peer, u_int32_t flag)
if (peer->t_pmax_restart)
{
BGP_TIMER_OFF (peer->t_pmax_restart);
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Maximum-prefix restart timer canceled",
peer->host);
}
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- peer_nsf_stop (peer);
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
+ peer_nsf_stop (peer);
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
else
{
@@ -2563,7 +2845,7 @@ peer_flag_modify_action (struct peer *peer, u_int32_t flag)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
/* Change specified peer flag. */
@@ -2706,6 +2988,11 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
&& peer_sort (peer) == BGP_PEER_IBGP)
return BGP_ERR_REMOVE_PRIVATE_AS;
+ /* as-override is not allowed for IBGP peers */
+ if (flag & PEER_FLAG_AS_OVERRIDE
+ && peer_sort (peer) == BGP_PEER_IBGP)
+ return BGP_ERR_AS_OVERRIDE;
+
/* When unset the peer-group member's flag we have to check
peer-group configuration. */
if (! set && peer->af_group[afi][safi])
@@ -2812,7 +3099,7 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl)
struct listnode *node, *nnode;
struct peer *peer1;
- if (peer->sort == BGP_PEER_IBGP)
+ if (peer->sort == BGP_PEER_IBGP || peer->conf_if)
return 0;
/* see comment in peer_ttl_security_hops_set() */
@@ -2960,7 +3247,7 @@ peer_update_source_if_set (struct peer *peer, const char *ifname)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
return 0;
}
@@ -2992,7 +3279,7 @@ peer_update_source_if_set (struct peer *peer, const char *ifname)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
return 0;
}
@@ -3016,6 +3303,7 @@ peer_update_source_addr_set (struct peer *peer, union sockunion *su)
{
XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
peer->update_if = NULL;
+
}
peer->update_source = sockunion_dup (su);
@@ -3029,7 +3317,7 @@ peer_update_source_addr_set (struct peer *peer, union sockunion *su)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
return 0;
}
@@ -3060,7 +3348,7 @@ peer_update_source_addr_set (struct peer *peer, union sockunion *su)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
return 0;
}
@@ -3111,7 +3399,7 @@ peer_update_source_unset (struct peer *peer)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
return 0;
}
@@ -3141,7 +3429,7 @@ peer_update_source_unset (struct peer *peer)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
return 0;
}
@@ -3642,8 +3930,7 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend, int replace_as)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
-
+ bgp_session_reset(peer);
return 0;
}
@@ -3718,7 +4005,7 @@ peer_local_as_unset (struct peer *peer)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
return 0;
}
@@ -3748,7 +4035,7 @@ peer_password_set (struct peer *peer, const char *password)
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
return (bgp_md5_set (peer) >= 0) ? BGP_SUCCESS : BGP_ERR_TCPSIG_FAILED;
}
@@ -3766,7 +4053,7 @@ peer_password_set (struct peer *peer, const char *password)
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
if (bgp_md5_set (peer) < 0)
ret = BGP_ERR_TCPSIG_FAILED;
@@ -3794,7 +4081,7 @@ peer_password_unset (struct peer *peer)
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
if (peer->password)
XFREE (MTYPE_PEER_PASSWORD, peer->password);
@@ -3817,7 +4104,7 @@ peer_password_unset (struct peer *peer)
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
XFREE (MTYPE_PEER_PASSWORD, peer->password);
peer->password = NULL;
@@ -4250,7 +4537,7 @@ peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct)
}
static void
-peer_aslist_update (void)
+peer_aslist_update (const char *aslist_name)
{
afi_t afi;
safi_t safi;
@@ -4300,8 +4587,42 @@ peer_aslist_update (void)
}
}
}
+static void
+peer_aslist_add (char *aslist_name)
+{
+ peer_aslist_update (aslist_name);
+ route_map_notify_dependencies((char *)aslist_name, RMAP_EVENT_ASLIST_ADDED);
+}
+
+static void
+peer_aslist_del (const char *aslist_name)
+{
+ peer_aslist_update (aslist_name);
+ route_map_notify_dependencies((char *)aslist_name, RMAP_EVENT_ASLIST_DELETED);
+}
+
/* Set route-map to the peer. */
+static void
+peer_reprocess_routes (struct peer *peer, int direct,
+ afi_t afi, safi_t safi)
+{
+ if (peer->status != Established)
+ return;
+
+ if (direct != RMAP_OUT)
+ {
+ if (CHECK_FLAG (peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG))
+ bgp_soft_reconfig_in (peer, afi, safi);
+ else if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+ }
+ else
+ bgp_announce_route(peer, afi, safi);
+}
+
int
peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
@@ -4325,12 +4646,15 @@ peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
if (filter->map[direct].name)
free (filter->map[direct].name);
-
+
filter->map[direct].name = strdup (name);
filter->map[direct].map = route_map_lookup_by_name (name);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ peer_reprocess_routes(peer, direct, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4344,6 +4668,7 @@ peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
free (filter->map[direct].name);
filter->map[direct].name = strdup (name);
filter->map[direct].map = route_map_lookup_by_name (name);
+ peer_reprocess_routes (peer, direct, afi, safi);
}
return 0;
}
@@ -4391,7 +4716,10 @@ peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
filter->map[direct].map = NULL;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ peer_reprocess_routes(peer, direct, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4405,6 +4733,7 @@ peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
free (filter->map[direct].name);
filter->map[direct].name = NULL;
filter->map[direct].map = NULL;
+ peer_reprocess_routes(peer, direct, afi, safi);
}
return 0;
}
@@ -4433,7 +4762,10 @@ peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi,
filter->usmap.map = route_map_lookup_by_name (name);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ bgp_announce_route (peer, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4447,6 +4779,7 @@ peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi,
free (filter->usmap.name);
filter->usmap.name = strdup (name);
filter->usmap.map = route_map_lookup_by_name (name);
+ bgp_announce_route (peer, afi, safi);
}
return 0;
}
@@ -4473,7 +4806,10 @@ peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi)
filter->usmap.map = NULL;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ bgp_announce_route(peer, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4487,6 +4823,7 @@ peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi)
free (filter->usmap.name);
filter->usmap.name = NULL;
filter->usmap.map = NULL;
+ bgp_announce_route(peer, afi, safi);
}
return 0;
}
@@ -4511,24 +4848,33 @@ peer_maximum_prefix_set (struct peer *peer, afi_t afi, safi_t safi,
else
UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
- 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->sflags, PEER_STATUS_GROUP))
{
- if (! peer->af_group[afi][safi])
- continue;
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
+ {
+ if (! peer->af_group[afi][safi])
+ continue;
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
- peer->pmax[afi][safi] = max;
- peer->pmax_threshold[afi][safi] = threshold;
- peer->pmax_restart[afi][safi] = restart;
- if (warning)
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
- else
- UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+ SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+ peer->pmax[afi][safi] = max;
+ peer->pmax_threshold[afi][safi] = threshold;
+ peer->pmax_restart[afi][safi] = restart;
+ if (warning)
+ SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+ else
+ UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+
+ if ((peer->status == Established) && (peer->afc[afi][safi]))
+ bgp_maximum_prefix_overflow (peer, afi, safi, 1);
+ }
+ }
+ else
+ {
+ if ((peer->status == Established) && (peer->afc[afi][safi]))
+ bgp_maximum_prefix_overflow (peer, afi, safi, 1);
}
+
return 0;
}
@@ -4650,7 +4996,11 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
if (peer->fd >= 0)
- sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - gtsm_hops);
+ sockopt_minttl (peer->su.sa.sa_family, peer->fd,
+ MAXTTL + 1 - gtsm_hops);
+ if (peer->status != Established && peer->doppelganger)
+ sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd,
+ MAXTTL + 1 - gtsm_hops);
}
else
{
@@ -4672,9 +5022,9 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops)
}
else if (peer->status < Established)
{
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Min-ttl changed", peer->host);
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
}
}
@@ -4702,6 +5052,9 @@ peer_ttl_security_hops_unset (struct peer *peer)
{
if (peer->fd >= 0)
sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
+
+ if (peer->status != Established && peer->doppelganger)
+ sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd, 0);
}
else
{
@@ -4712,14 +5065,24 @@ peer_ttl_security_hops_unset (struct peer *peer)
if (peer->fd >= 0)
sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
+
+ if (peer->status != Established && peer->doppelganger)
+ sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd, 0);
}
}
return peer_ebgp_multihop_unset (opeer);
}
+/*
+ * If peer clear is invoked in a loop for all peers on the BGP instance,
+ * it may end up freeing the doppelganger, and if this was the next node
+ * to the current node, we would end up accessing the freed next node.
+ * Pass along additional parameter which can be updated if next node
+ * is freed; only required when walking the peer list on BGP instance.
+ */
int
-peer_clear (struct peer *peer)
+peer_clear (struct peer *peer, struct listnode **nnode)
{
if (! CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
{
@@ -4729,7 +5092,7 @@ peer_clear (struct peer *peer)
if (peer->t_pmax_restart)
{
BGP_TIMER_OFF (peer->t_pmax_restart);
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Maximum-prefix restart timer canceled",
peer->host);
}
@@ -4742,7 +5105,7 @@ peer_clear (struct peer *peer)
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_ADMIN_RESET);
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset_safe(peer, nnode);
}
return 0;
}
@@ -4954,7 +5317,11 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
char buf[SU_ADDRSTRLEN];
char *addr;
- addr = peer->host;
+ if (peer->conf_if)
+ addr = peer->conf_if;
+ else
+ addr = peer->host;
+
if (peer_group_active (peer))
g_peer = peer->group->conf;
@@ -4963,6 +5330,9 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
************************************/
if (afi == AFI_IP && safi == SAFI_UNICAST)
{
+ if (peer->conf_if)
+ vty_out (vty, " neighbor %s interface%s", addr, VTY_NEWLINE);
+
/* remote-as. */
if (! peer_group_active (peer))
{
@@ -5173,11 +5543,27 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF_ALL) ?
" all" : "", VTY_NEWLINE);
- /* Remove private AS. */
- if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)
- && ! peer->af_group[afi][safi])
- vty_out (vty, " neighbor %s remove-private-AS%s",
- addr, VTY_NEWLINE);
+ /* remove-private-AS */
+ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) && !peer->af_group[afi][safi])
+ {
+ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_ALL) &&
+ peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE))
+ vty_out (vty, " neighbor %s remove-private-AS all replace-AS%s", addr, VTY_NEWLINE);
+
+ else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE))
+ vty_out (vty, " neighbor %s remove-private-AS replace-AS%s", addr, VTY_NEWLINE);
+
+ else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_ALL))
+ vty_out (vty, " neighbor %s remove-private-AS all%s", addr, VTY_NEWLINE);
+
+ else
+ vty_out (vty, " neighbor %s remove-private-AS%s", addr, VTY_NEWLINE);
+ }
+
+ /* as-override */
+ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_AS_OVERRIDE) &&
+ !peer->af_group[afi][safi])
+ vty_out (vty, " neighbor %s as-override%s", addr, VTY_NEWLINE);
/* send-community print. */
if (! peer->af_group[afi][safi])
@@ -5357,7 +5743,7 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi,
{
if (peer->afc[afi][safi])
{
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ if (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE))
{
bgp_config_write_family_header (vty, afi, safi, &write);
bgp_config_write_peer (vty, bgp, peer, afi, safi);
@@ -5366,6 +5752,7 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi,
}
bgp_config_write_maxpaths (vty, bgp, afi, safi, &write);
+ bgp_config_write_table_map (vty, bgp, afi, safi, &write);
if (write)
vty_out (vty, " exit-address-family%s", VTY_NEWLINE);
@@ -5478,6 +5865,27 @@ bgp_config_write (struct vty *vty)
if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
vty_out (vty, " bgp deterministic-med%s", VTY_NEWLINE);
+ /* BGP update-delay. */
+ bgp_config_write_update_delay (vty, bgp);
+
+ if (bgp->v_maxmed_onstartup != BGP_MAXMED_ONSTARTUP_UNCONFIGURED)
+ {
+ vty_out (vty, " bgp max-med on-startup %d", bgp->v_maxmed_onstartup);
+ if (bgp->maxmed_onstartup_value != BGP_MAXMED_VALUE_DEFAULT)
+ vty_out (vty, " %d", bgp->maxmed_onstartup_value);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ if (bgp->v_maxmed_admin != BGP_MAXMED_ADMIN_UNCONFIGURED)
+ {
+ vty_out (vty, " bgp max-med administrative");
+ if (bgp->maxmed_admin_value != BGP_MAXMED_VALUE_DEFAULT)
+ vty_out (vty, " %d", bgp->maxmed_admin_value);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+
+ /* write quanta */
+ bgp_config_write_wpkt_quanta (vty, bgp);
+
/* BGP graceful-restart. */
if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME)
vty_out (vty, " bgp graceful-restart stalepath-time %d%s",
@@ -5493,6 +5901,10 @@ bgp_config_write (struct vty *vty)
if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) {
vty_out (vty, " bgp bestpath as-path multipath-relax%s", VTY_NEWLINE);
}
+ if (bgp_flag_check (bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) {
+ vty_out (vty, " bgp route-reflector allow-outbound-policy%s",
+ VTY_NEWLINE);
+ }
if (bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID))
vty_out (vty, " bgp bestpath compare-routerid%s", VTY_NEWLINE);
if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED)
@@ -5510,9 +5922,6 @@ bgp_config_write (struct vty *vty)
if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
vty_out (vty, " bgp network import-check%s", VTY_NEWLINE);
- /* BGP scan interval. */
- bgp_config_write_scan_time (vty);
-
/* BGP flag dampening. */
if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST],
BGP_CONFIG_DAMPENING))
@@ -5530,6 +5939,10 @@ bgp_config_write (struct vty *vty)
vty_out (vty, " timers bgp %d %d%s", bgp->default_keepalive,
bgp->default_holdtime, VTY_NEWLINE);
+ if (bgp->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER)
+ vty_out (vty, " bgp route-map delay-timer %d%s", bgp->rmap_update_timer,
+ VTY_NEWLINE);
+
/* peer-group */
for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
{
@@ -5539,12 +5952,13 @@ bgp_config_write (struct vty *vty)
/* Normal neighbor configuration. */
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ if (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE))
bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
}
/* maximum-paths */
bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
+ bgp_config_write_table_map (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
/* Distance configuration. */
bgp_config_write_distance (vty, bgp);
@@ -5598,12 +6012,16 @@ bgp_master_init (void)
void
bgp_init (void)
{
- /* BGP VTY commands installation. */
- bgp_vty_init ();
+
+ /* allocates some vital data structures used by peer commands in vty_init */
+ bgp_scan_init ();
/* Init zebra. */
bgp_zebra_init (bm->master);
+ /* BGP VTY commands installation. */
+ bgp_vty_init ();
+
/* BGP inits. */
bgp_attr_init ();
bgp_debug_init ();
@@ -5611,7 +6029,7 @@ bgp_init (void)
bgp_route_init ();
bgp_route_map_init ();
bgp_address_init ();
- bgp_scan_init ();
+ bgp_scan_vty_init();
bgp_mplsvpn_init ();
bgp_encap_init ();
@@ -5622,8 +6040,8 @@ bgp_init (void)
/* Filter list initialize. */
bgp_filter_init ();
- as_list_add_hook (peer_aslist_update);
- as_list_delete_hook (peer_aslist_update);
+ as_list_add_hook (peer_aslist_add);
+ as_list_delete_hook (peer_aslist_del);
/* Prefix list initialize.*/
prefix_list_init ();
@@ -5646,12 +6064,25 @@ bgp_terminate (void)
struct listnode *node, *nnode;
struct listnode *mnode, *mnnode;
+ /* Close the listener sockets first as this prevents peers from attempting
+ * to reconnect on receiving the peer unconfig message. In the presence
+ * of a large number of peers this will ensure that no peer is left with
+ * a dangling connection
+ */
+ /* reverse bgp_master_init */
+ bgp_close();
+ if (bm->listen_sockets)
+ list_free(bm->listen_sockets);
+ bm->listen_sockets = NULL;
+
for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (peer->status == Established)
+ if (peer->status == Established ||
+ peer->status == OpenSent ||
+ peer->status == OpenConfirm)
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_PEER_UNCONFIG);
-
+
bgp_cleanup_routes ();
if (bm->process_main_queue)
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 7665d9d0..25838edb 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -23,6 +23,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* For union sockunion. */
#include "sockunion.h"
+#include "routemap.h"
/* Typedef BGP specific types. */
typedef u_int32_t as_t;
@@ -62,6 +63,13 @@ struct bgp_master
#define BGP_OPT_NO_LISTEN (1 << 3)
};
+/* BGP route-map structure. */
+struct bgp_rmap
+{
+ char *name;
+ struct route_map *map;
+};
+
/* BGP instance structure. */
struct bgp
{
@@ -104,10 +112,45 @@ struct bgp
as_t *confed_peers;
int confed_peers_cnt;
- struct thread *t_startup;
+ struct thread *t_startup; /* start-up timer on only once at the beginning */
+
+ u_int32_t v_maxmed_onstartup; /* Duration of max-med on start-up */
+#define BGP_MAXMED_ONSTARTUP_UNCONFIGURED 0 /* 0 means off, its the default */
+ u_int32_t maxmed_onstartup_value; /* Max-med value when active on start-up */
+ struct thread *t_maxmed_onstartup; /* non-null when max-med onstartup is on */
+ u_char maxmed_onstartup_over; /* Flag to make it effective only once */
+
+ u_char v_maxmed_admin; /* 1/0 if max-med administrative is on/off */
+#define BGP_MAXMED_ADMIN_UNCONFIGURED 0 /* Off by default */
+ u_int32_t maxmed_admin_value; /* Max-med value when administrative in on */
+#define BGP_MAXMED_VALUE_DEFAULT 4294967294 /* Maximum by default */
+
+ u_char maxmed_active; /* 1/0 if max-med is active or not */
+ u_int32_t maxmed_value; /* Max-med value when its active */
+
+ /* BGP update delay on startup */
+ struct thread *t_update_delay;
+ struct thread *t_establish_wait;
+ u_char update_delay_over;
+ u_char main_zebra_update_hold;
+ u_char main_peers_update_hold;
+ u_char rsclient_peers_update_hold;
+ u_int16_t v_update_delay;
+ u_int16_t v_establish_wait;
+ char update_delay_begin_time[64];
+ char update_delay_end_time[64];
+ char update_delay_zebra_resume_time[64];
+ char update_delay_peers_resume_time[64];
+ u_int32_t established;
+ u_int32_t restarted_peers;
+ u_int32_t implicit_eors;
+ u_int32_t explicit_eors;
+#define BGP_UPDATE_DELAY_DEF 0
+#define BGP_UPDATE_DELAY_MIN 0
+#define BGP_UPDATE_DELAY_MAX 3600
/* BGP flags. */
- u_int16_t flags;
+ u_int32_t flags;
#define BGP_FLAG_ALWAYS_COMPARE_MED (1 << 0)
#define BGP_FLAG_DETERMINISTIC_MED (1 << 1)
#define BGP_FLAG_MED_MISSING_AS_WORST (1 << 2)
@@ -124,6 +167,7 @@ struct bgp
#define BGP_FLAG_ASPATH_CONFED (1 << 13)
#define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 14)
#define BGP_FLAG_DELETING (1 << 15)
+#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 16)
/* BGP Per AF flags */
u_int16_t af_flags[AFI_MAX][SAFI_MAX];
@@ -138,6 +182,9 @@ struct bgp
/* BGP routing information base. */
struct bgp_table *rib[AFI_MAX][SAFI_MAX];
+ /* BGP table route-map. */
+ struct bgp_rmap table_map[AFI_MAX][SAFI_MAX];
+
/* BGP redistribute configuration. */
u_char redist[AFI_MAX][ZEBRA_ROUTE_MAX];
@@ -146,11 +193,12 @@ struct bgp
u_int32_t redist_metric[AFI_MAX][ZEBRA_ROUTE_MAX];
/* BGP redistribute route-map. */
- struct
- {
- char *name;
- struct route_map *map;
- } rmap[AFI_MAX][ZEBRA_ROUTE_MAX];
+ struct bgp_rmap rmap[AFI_MAX][ZEBRA_ROUTE_MAX];
+
+ /* timer to dampen route map changes */
+ struct thread *t_rmap_update; /* Handle route map updates */
+ u_int32_t rmap_update_timer; /* Route map update timer */
+#define RMAP_DEFAULT_UPDATE_TIMER 5 /* disabled by default */
/* BGP distance configuration. */
u_char distance_ebgp;
@@ -172,9 +220,18 @@ struct bgp
struct bgp_maxpaths_cfg {
u_int16_t maxpaths_ebgp;
u_int16_t maxpaths_ibgp;
+ u_int16_t ibgp_flags;
+#define BGP_FLAG_IBGP_MULTIPATH_SAME_CLUSTERLEN (1 << 0)
} maxpaths[AFI_MAX][SAFI_MAX];
+
+ u_int32_t wpkt_quanta; /* per peer packet quanta to write */
+ u_int32_t adv_quanta; /* adv FIFO size that triggers write */
+ u_int32_t wd_quanta; /* withdraw FIFO size that triggers write */
};
+#define BGP_ROUTE_ADV_HOLD(bgp) \
+ (bgp->main_peers_update_hold || bgp->rsclient_peers_update_hold)
+
/* BGP peer-group support. */
struct peer_group
{
@@ -272,6 +329,12 @@ typedef enum
BGP_PEER_CONFED,
} bgp_peer_sort_t;
+/* BGP message header and packet size. */
+#define BGP_MARKER_SIZE 16
+#define BGP_HEADER_SIZE 19
+#define BGP_MAX_PACKET_SIZE 4096
+#define BGP_MAX_PACKET_SIZE_OVERFLOW 1024
+
/* BGP neighbor structure. */
struct peer
{
@@ -320,6 +383,9 @@ struct peer
*/
struct stream *scratch;
+ /* the doppelganger peer structure, due to dual TCP conn setup */
+ struct peer *doppelganger;
+
/* Status of the peer. */
int status;
int ostatus;
@@ -336,15 +402,16 @@ struct peer
unsigned short port; /* Destination port for peer */
char *host; /* Printable address of the peer. */
union sockunion su; /* Sockunion address of the peer. */
+#define BGP_PEER_SU_UNSPEC(peer) (peer->su.sa.sa_family == AF_UNSPEC)
time_t uptime; /* Last Up/Down time */
time_t readtime; /* Last read time */
time_t resettime; /* Last reset time */
ifindex_t ifindex; /* ifindex of the BGP connection. */
+ char *conf_if; /* neighbor interface config name. */
char *ifname; /* bind interface name. */
char *update_if;
union sockunion *update_source;
- struct zlog *log;
union sockunion *su_local; /* Sockunion of local address. */
union sockunion *su_remote; /* Sockunion of remote address. */
@@ -393,6 +460,8 @@ struct peer
#define PEER_FLAG_DISABLE_CONNECTED_CHECK (1 << 6) /* disable-connected-check */
#define PEER_FLAG_LOCAL_AS_NO_PREPEND (1 << 7) /* local-as no-prepend */
#define PEER_FLAG_LOCAL_AS_REPLACE_AS (1 << 8) /* local-as no-prepend replace-as */
+#define PEER_FLAG_DELETE (1 << 9) /* mark the peer for deleting */
+#define PEER_FLAG_CONFIG_NODE (1 << 10) /* the node to update configs on */
/* NSF mode (graceful restart) */
u_char nsf[AFI_MAX][SAFI_MAX];
@@ -417,6 +486,9 @@ struct peer
#define PEER_FLAG_MAX_PREFIX_WARNING (1 << 15) /* maximum prefix warning-only */
#define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1 << 16) /* leave link-local nexthop unchanged */
#define PEER_FLAG_NEXTHOP_SELF_ALL (1 << 17) /* next-hop-self all */
+#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL (1 << 18) /* remove-private-as all */
+#define PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE (1 << 19) /* remove-private-as replace-as */
+#define PEER_FLAG_AS_OVERRIDE (1 << 20) /* as-override */
/* MD5 password */
char *password;
@@ -481,6 +553,8 @@ struct peer
struct thread *t_gr_restart;
struct thread *t_gr_stale;
+ int radv_adjusted; /* flag if MRAI has been adjusted or not */
+
/* workqueues */
struct work_queue *clear_node_queue;
@@ -503,9 +577,13 @@ struct peer
u_int32_t established; /* Established */
u_int32_t dropped; /* Dropped */
+ /* Update delay related fields */
+ u_char update_delay_over; /* When this is set, BGP is no more waiting for EOR */
+
/* Syncronization list and time. */
struct bgp_synchronize *sync[AFI_MAX][SAFI_MAX];
time_t synctime;
+ time_t last_write; /* timestamp when the last UPDATE msg was written */
/* Send prefix count. */
unsigned long scount[AFI_MAX][SAFI_MAX];
@@ -525,6 +603,12 @@ struct peer
/* ORF Prefix-list */
struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX];
+ /* Text description of last attribute rcvd */
+ char rcvd_attr_str[BUFSIZ];
+
+ /* Track if we printed the attribute in debugs */
+ int rcvd_attr_printed;
+
/* Prefix count. */
unsigned long pcount[AFI_MAX][SAFI_MAX];
@@ -561,6 +645,8 @@ struct peer
#define PEER_DOWN_PASSIVE_CHANGE 20 /* neighbor passive command */
#define PEER_DOWN_MULTIHOP_CHANGE 21 /* neighbor multihop command */
#define PEER_DOWN_NSF_CLOSE_SESSION 22 /* NSF tcp session close */
+unsigned long last_reset_cause_size;
+u_char last_reset_cause[BGP_MAX_PACKET_SIZE];
/* The kind of route-map Flags.*/
u_char rmap_type;
@@ -600,11 +686,6 @@ struct bgp_nlri
/* Default BGP port number. */
#define BGP_PORT_DEFAULT 179
-/* BGP message header and packet size. */
-#define BGP_MARKER_SIZE 16
-#define BGP_HEADER_SIZE 19
-#define BGP_MAX_PACKET_SIZE 4096
-
/* BGP minimum message size. */
#define BGP_MSG_OPEN_MIN_SIZE (BGP_HEADER_SIZE + 10)
#define BGP_MSG_UPDATE_MIN_SIZE (BGP_HEADER_SIZE + 4)
@@ -742,7 +823,7 @@ struct bgp_nlri
#define BGP_EVENTS_MAX 15
/* BGP timers default value. */
-#define BGP_INIT_START_TIMER 5
+#define BGP_INIT_START_TIMER 1
#define BGP_DEFAULT_HOLDTIME 180
#define BGP_DEFAULT_KEEPALIVE 60
#define BGP_DEFAULT_EBGP_ROUTEADV 30
@@ -826,8 +907,10 @@ enum bgp_clear_type
#define BGP_ERR_TCPSIG_FAILED -29
#define BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK -30
#define BGP_ERR_NO_IBGP_WITH_TTLHACK -31
-#define BGP_ERR_MAX -32
+#define BGP_ERR_NO_INTERFACE_CONFIG -32
#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS -33
+#define BGP_ERR_AS_OVERRIDE -34
+#define BGP_ERR_MAX -35
extern struct bgp_master *bm;
@@ -842,6 +925,10 @@ extern struct bgp *bgp_get_default (void);
extern struct bgp *bgp_lookup (as_t, const char *);
extern struct bgp *bgp_lookup_by_name (const char *);
extern struct peer *peer_lookup (struct bgp *, union sockunion *);
+extern struct peer *peer_lookup_by_conf_if (struct bgp *, const char *);
+extern struct peer *peer_conf_interface_get(struct bgp *, const char *, afi_t,
+ safi_t);
+extern void bgp_peer_conf_if_to_su_update (struct peer *);
extern struct peer_group *peer_group_lookup (struct bgp *, const char *);
extern struct peer_group *peer_group_get (struct bgp *, const char *);
extern struct peer *peer_lookup_with_open (union sockunion *, as_t, struct in_addr *,
@@ -860,7 +947,10 @@ extern struct peer *peer_unlock_with_caller(const char *, struct peer *);
extern bgp_peer_sort_t peer_sort (struct peer *peer);
extern int peer_active (struct peer *);
extern int peer_active_nego (struct peer *);
+extern struct peer *peer_create(union sockunion *, const char *, struct bgp *,
+ as_t, as_t, afi_t, safi_t);
extern struct peer *peer_create_accept (struct bgp *);
+extern void peer_xfer_config (struct peer *dst, struct peer *src);
extern char *peer_uptime (time_t, char *, size_t);
extern int bgp_config_write (struct vty *);
extern void bgp_config_write_family_header (struct vty *, afi_t, safi_t, int *);
@@ -902,9 +992,12 @@ extern int bgp_timers_unset (struct bgp *);
extern int bgp_default_local_preference_set (struct bgp *, u_int32_t);
extern int bgp_default_local_preference_unset (struct bgp *);
+extern int bgp_update_delay_active (struct bgp *);
+extern int bgp_update_delay_configured (struct bgp *);
extern int peer_rsclient_active (struct peer *);
-
-extern int peer_remote_as (struct bgp *, union sockunion *, as_t *, afi_t, safi_t);
+extern void peer_as_change (struct peer *, as_t);
+extern int peer_remote_as (struct bgp *, union sockunion *,const char *, as_t *,
+ afi_t, safi_t);
extern int peer_group_remote_as (struct bgp *, const char *, as_t *);
extern int peer_delete (struct peer *peer);
extern int peer_group_delete (struct peer_group *);
@@ -913,8 +1006,8 @@ extern int peer_group_remote_as_delete (struct peer_group *);
extern int peer_activate (struct peer *, afi_t, safi_t);
extern int peer_deactivate (struct peer *, afi_t, safi_t);
-extern int peer_group_bind (struct bgp *, union sockunion *, struct peer_group *,
- afi_t, safi_t, as_t *);
+extern int peer_group_bind (struct bgp *, union sockunion *, struct peer *,
+ struct peer_group *, afi_t, safi_t, as_t *);
extern int peer_group_unbind (struct bgp *, struct peer *, struct peer_group *,
afi_t, safi_t);
@@ -984,10 +1077,16 @@ extern int peer_unsuppress_map_unset (struct peer *, afi_t, safi_t);
extern int peer_maximum_prefix_set (struct peer *, afi_t, safi_t, u_int32_t, u_char, int, u_int16_t);
extern int peer_maximum_prefix_unset (struct peer *, afi_t, safi_t);
-extern int peer_clear (struct peer *);
+extern int peer_clear (struct peer *, struct listnode **);
extern int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type);
extern int peer_ttl_security_hops_set (struct peer *, int);
extern int peer_ttl_security_hops_unset (struct peer *);
+extern int bgp_route_map_update_timer (struct thread *thread);
+extern void bgp_route_map_terminate(void);
+
+extern void bgp_scan_finish (void);
+
+extern int peer_cmp (struct peer *p1, struct peer *p2);
#endif /* _QUAGGA_BGPD_H */
diff --git a/doc/bgpd.texi b/doc/bgpd.texi
index 5735111d..3ef7c8f7 100644
--- a/doc/bgpd.texi
+++ b/doc/bgpd.texi
@@ -581,6 +581,41 @@ Redistribute RIP route to BGP process.
Redistribute OSPF route to BGP process.
@end deffn
+@deffn {BGP} {update-delay @var{max-delay}} {}
+@deffnx {BGP} {update-delay @var{max-delay} @var{establish-wait}} {}
+This feature is used to enable read-only mode on BGP process restart or when
+BGP process is cleared using 'clear ip bgp *'. When applicable, read-only mode
+would begin as soon as the first peer reaches Established status and a timer
+for max-delay seconds is started.
+
+During this mode BGP doesn't run any best-path or generate any updates to its
+peers. This mode continues until:
+1. All the configured peers, except the shutdown peers, have sent explicit EOR
+(End-Of-RIB) or an implicit-EOR. The first keep-alive after BGP has reached
+Established is considered an implicit-EOR.
+ If the establish-wait optional value is given, then BGP will wait for
+ peers to reach established from the begining of the update-delay till the
+ establish-wait period is over, i.e. the minimum set of established peers for
+ which EOR is expected would be peers established during the establish-wait
+ window, not necessarily all the configured neighbors.
+2. max-delay period is over.
+On hitting any of the above two conditions, BGP resumes the decision process
+and generates updates to its peers.
+
+Default max-delay is 0, i.e. the feature is off by default.
+@end deffn
+
+@deffn {BGP} {table-map @var{route-map-name}} {}
+This feature is used to apply a route-map on route updates from BGP to Zebra.
+All the applicable match operations are allowed, such as match on prefix,
+next-hop, communities, etc. Set operations for this attach-point are limited
+to metric and next-hop only. Any operation of this feature does not affect
+BGPs internal RIB.
+
+Supported for ipv4 and ipv6 address families. It works on multi-paths as well,
+however, metric setting is based on the best-path only.
+@end deffn
+
@node BGP Peer
@section BGP Peer
@@ -753,6 +788,12 @@ Apply a route-map on the neighbor. @var{direct} must be @code{in} or
@code{out}.
@end deffn
+@deffn {BGP} {bgp route-reflector allow-outbound-policy} {}
+By default, attribute modification via route-map policy out is not reflected
+on reflected routes. This option allows the modifications to be reflected as
+well. Once enabled, it affects all reflected routes.
+@end deffn
+
@c -----------------------------------------------------------------------
@node BGP Peer Group
@section BGP Peer Group
diff --git a/doc/next-hop-tracking.txt b/doc/next-hop-tracking.txt
new file mode 100644
index 00000000..d157866e
--- /dev/null
+++ b/doc/next-hop-tracking.txt
@@ -0,0 +1,326 @@
+0. Introduction
+
+This is the design specification for next hop tracking feature in
+Quagga.
+
+1. Background
+
+Recursive routes are of the form:
+
+ p/m --> n
+ [Ex: 1.1.0.0/16 --> 2.2.2.2]
+
+where 'n' itself is resolved through another route as follows:
+
+ p2/m --> h, interface
+ [Ex: 2.2.2.0/24 --> 3.3.3.3, eth0]
+
+Usually, BGP routes are recursive in nature and BGP nexthops get
+resolved through an IGP route. IGP usually adds its routes pointing to
+an interface (these are called non-recursive routes).
+
+When BGP receives a recursive route from a peer, it needs to validate
+the nexthop. The path is marked valid or invalid based on the
+reachability status of the nexthop. Nexthop validation is also
+important for BGP decision process as the metric to reach the nexthop
+is a parameter to best path selection process.
+
+As it goes with routing, this is a dynamic process. Route to the
+nexthop can change. The nexthop can become unreachable or
+reachable. In the current BGP implementation, the nexthop validation
+is done periodically in the scanner run. The default scanner run
+interval is one minute. Every minute, the scanner task walks the
+entire BGP table. It checks the validity of each nexthop with Zebra
+(the routing table manager) through a request and response message
+exchange between BGP and Zebra process. BGP process is blocked for
+that duration. The mechanism has two major drawbacks:
+
+(1) The scanner task runs to completion. That can potentially starve
+ the other tasks for long periods of time, based on the BGP table
+ size and number of nexthops.
+
+(2) Convergence around routing changes that affect the nexthops can be
+ long (around a minute with the default intervals). The interval
+ can be shortened to achieve faster reaction time, but it makes the
+ first problem worse, with the scanner task consuming most of the
+ CPU resources.
+
+"Next hop tracking" feature makes this process event-driven. It
+eliminates periodic nexthop validation and introduces an asynchronous
+communication path between BGP and Zebra for route change notifications
+that can then be acted upon.
+
+2. Goal
+
+Stating the obvious, the main goal is to remove the two limitations we
+discussed in the previous section. The goals, in a constructive tone,
+are the following:
+
+- fairness: the scanner run should not consume an unjustly high amount
+ of CPU time. This should give an overall good performance and
+ response time to other events (route changes, session events,
+ IO/user interface).
+
+- convergence: BGP must react to nexthop changes instantly and provide
+ sub-second convergence. This may involve diverting the routes from
+ one nexthop to another.
+
+3. Overview of the changes
+
+The changes are in both BGP and Zebra modules. The short summary is
+the following:
+
+- Zebra implements a registration mechanism by which clients can
+ register for next hop notification. Consequently, it maintains a
+ separate table, per (VRF, AF) pair, of next hops and interested
+ client-list per next hop.
+
+- When the main routing table changes in Zebra, it evaluates the next
+ hop table: for each next hop, it checks if the route table
+ modifications have changed its state. If so, it notifies the
+ interested clients.
+
+- BGP is one such client. It registers the next hops corresponding to
+ all of its received routes/paths. It also threads the paths against
+ each nexthop structure.
+
+- When BGP receives a next hop notification from Zebra, it walks the
+ corresponding path list. It makes them valid or invalid depending
+ on the next hop notification. It then re-computes best path for the
+ corresponding destination. This may result in re-announcing those
+ destinations to peers.
+
+4. Design
+
+4.1. Modules
+
+The core design introduces an "nht" (next hop tracking) module in BGP
+and "rnh" (recursive nexthop) module in Zebra. The "nht" module
+provides the following APIs:
+
+bgp_find_or_add_nexthop() : find or add a nexthop in BGP nexthop table
+bgp_find_nexthop() : find a nexthop in BGP nexthop table
+bgp_parse_nexthop_update() : parse a nexthop update message coming
+ from zebra
+
+The "rnh" module provides the following APIs:
+
+zebra_add_rnh() : add a recursive nexthop
+zebra_delete_rnh() : delete a recursive nexthop
+zebra_lookup_rnh() : lookup a recursive nexthop
+
+zebra_add_rnh_client() : register a client for nexthop notifications
+ against a recursive nexthop
+
+zebra_remove_rnh_client(): remove the client registration for a
+ recursive nexthop
+
+zebra_evaluate_rnh_table(): (re)evaluate the recursive nexthop table
+ (most probably because the main routing
+ table has changed).
+
+zebra_cleanup_rnh_client(): Cleanup a client from the "rnh" module
+ data structures (most probably because the
+ client is going away).
+
+4.2. Control flow
+
+The next hop registration control flow is the following:
+
+<==== BGP Process ====>|<==== Zebra Process ====>
+ |
+receive module nht module | zserv module rnh module
+----------------------------------------------------------------------
+ | | |
+bgp_update_ | | |
+ main() | bgp_find_or_add_ | |
+ | nexthop() | |
+ | | |
+ | | zserv_nexthop_ |
+ | | register() |
+ | | | zebra_add_rnh()
+ | | |
+
+
+The next hop notification control flow is the following:
+
+<==== Zebra Process ====>|<==== BGP Process ====>
+ |
+rib module rnh module | zebra module nht module
+----------------------------------------------------------------------
+ | | |
+meta_queue_ | | |
+ process() | zebra_evaluate_ | |
+ | rnh_table() | |
+ | | |
+ | | bgp_read_nexthop_ |
+ | | update() |
+ | | | bgp_parse_
+ | | | nexthop_update()
+ | | |
+
+
+4.3. zclient message format
+
+ZEBRA_NEXTHOP_REGISTER and ZEBRA_NEXTHOP_UNREGISTER messages are
+encoded in the following way:
+
+/*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | AF | prefix len |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * . Nexthop prefix .
+ * . .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * . .
+ * . .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | AF | prefix len |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * . Nexthop prefix .
+ * . .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ZEBRA_NEXTHOP_UPDATE message is encoded as follows:
+
+/*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | AF | prefix len |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * . Nexthop prefix getting resolved .
+ * . .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | metric |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | #nexthops |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | nexthop type |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * . resolving Nexthop details .
+ * . .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * . .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | nexthop type |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * . resolving Nexthop details .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+4.4. BGP data structure
+
+Legend:
+
+/\ struct bgp_node: a BGP destination/route/prefix
+\/
+
+[ ] struct bgp_info: a BGP path (e.g. route received from a peer)
+
+ _
+(_) struct bgp_nexthop_cache: a BGP nexthop
+
+
+
+ /\ NULL
+ \/--+ ^
+ | :
+ +--[ ]--[ ]--[ ]--> NULL
+ /\ :
+ \/--+ :
+ | :
+ +--[ ]--[ ]--> NULL
+ :
+ _ :
+ (_).............
+
+
+4.5. Zebra data structure
+
+rnh table:
+
+ O
+ / \
+ O O
+ / \
+ O O
+
+ struct rnh
+ {
+ u_char flags;
+ struct rib *state;
+ struct list *client_list;
+ struct route_node *node;
+ };
+
+5. User interface changes
+
+quagga# show ip nht
+3.3.3.3
+ resolved via kernel
+ via 11.0.0.6, swp1
+ Client list: bgp(fd 12)
+11.0.0.10
+ resolved via connected
+ is directly connected, swp2
+ Client list: bgp(fd 12)
+11.0.0.18
+ resolved via connected
+ is directly connected, swp4
+ Client list: bgp(fd 12)
+11.11.11.11
+ resolved via kernel
+ via 10.0.1.2, eth0
+ Client list: bgp(fd 12)
+
+quagga# show ip bgp nexthop
+Current BGP nexthop cache:
+ 3.3.3.3 valid [IGP metric 0], #paths 3
+ Last update: Wed Oct 16 04:43:49 2013
+
+ 11.0.0.10 valid [IGP metric 1], #paths 1
+ Last update: Wed Oct 16 04:43:51 2013
+
+ 11.0.0.18 valid [IGP metric 1], #paths 2
+ Last update: Wed Oct 16 04:43:47 2013
+
+ 11.11.11.11 valid [IGP metric 0], #paths 1
+ Last update: Wed Oct 16 04:43:47 2013
+
+quagga# show ipv6 nht
+quagga# show ip bgp nexthop detail
+
+quagga# debug bgp nht
+quagga# debug zebra nht
+
+6. Sample test cases
+
+ r2----r3
+ / \ /
+ r1----r4
+
+- Verify that a change in IGP cost triggers NHT
+ + shutdown the r1-r4 and r2-r4 links
+ + no shut the r1-r4 and r2-r4 links and wait for OSPF to come back
+ up
+ + We should be back to the original nexthop via r4 now
+- Verify that a NH becoming unreachable triggers NHT
+ + Shutdown all links to r4
+- Verify that a NH becoming reachable triggers NHT
+ + no shut all links to r4
+
+7. Future work
+
+- route-policy for next hop validation (e.g. ignore default route)
+- damping for rapid next hop changes
+- prioritized handling of nexthop changes ((un)reachability vs. metric
+ changes)
+- handling recursion loop, e.g.
+ 11.11.11.11/32 -> 12.12.12.12
+ 12.12.12.12/32 -> 11.11.11.11
+ 11.0.0.0/8 -> <interface>
+- better statistics
diff --git a/doc/routemap.texi b/doc/routemap.texi
index 7938c965..b3ef7ca7 100644
--- a/doc/routemap.texi
+++ b/doc/routemap.texi
@@ -151,6 +151,10 @@ Matches the specified @var{as_path}.
Matches the specified @var{metric}.
@end deffn
+@deffn {Route-map Command} {match local-preference @var{metric}} {}
+Matches the specified @var{local-preference}.
+@end deffn
+
@deffn {Route-map Command} {match community @var{community_list}} {}
Matches the specified @var{community_list}
@end deffn
diff --git a/isisd/isisd.c b/isisd/isisd.c
index c446e7fc..b67f1e46 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -782,9 +782,10 @@ print_debug (struct vty *vty, int flags, int onoff)
DEFUN (show_debugging,
show_debugging_cmd,
- "show debugging",
+ "show debugging isis",
SHOW_STR
- "State of each debugging option\n")
+ "State of each debugging option\n"
+ ISIS_STR)
{
vty_out (vty, "IS-IS:%s", VTY_NEWLINE);
print_debug (vty, isis->debugs, 1);
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 57e859d6..a2e65fb0 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -13,7 +13,7 @@ libzebra_la_SOURCES = \
sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \
- sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c
+ sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c nexthop.c
BUILT_SOURCES = memtypes.h route_types.h gitversion.h
@@ -28,7 +28,7 @@ pkginclude_HEADERS = \
str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \
privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
- workqueue.h route_types.h libospf.h vrf.h fifo.h
+ workqueue.h route_types.h libospf.h vrf.h fifo.h nexthop.h
noinst_HEADERS = \
plist_int.h
diff --git a/lib/bitfield.h b/lib/bitfield.h
new file mode 100644
index 00000000..b3f40a94
--- /dev/null
+++ b/lib/bitfield.h
@@ -0,0 +1,102 @@
+/**
+ * A simple bit array implementation to allocate and free IDs. An example
+ * of its usage is in allocating link state IDs for OSPFv3 as OSPFv3 has
+ * removed all address semantics from LS ID. Another usage can be in
+ * allocating IDs for BGP neighbors (and dynamic update groups) for
+ * efficient storage of adj-rib-out.
+ *
+ * An example:
+ * #include "bitfield.h"
+ *
+ * bitfield_t bitfield;
+ *
+ * bf_init(bitfield, 32);
+ * ...
+ * bf_assign_index(bitfield, id1);
+ * bf_assign_index(bitfield, id2);
+ * ...
+ * bf_release_index(bitfield, id1);
+ */
+
+#ifndef _BITFIELD_H
+#define _BITFIELD_H
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+typedef unsigned int word_t;
+#define WORD_MAX 0xFFFFFFFF
+#define WORD_SIZE (sizeof(word_t) * 8)
+
+/**
+ * The bitfield structure.
+ * @data: the bits to manage.
+ * @n: The current word number that is being used.
+ * @m: total number of words in 'data'
+ */
+#define bitfield_t struct { word_t *data; size_t n, m; }
+
+/**
+ * Initialize the bits.
+ * @v: an instance of bitfield_t struct.
+ * @N: number of bits to start with, which equates to how many
+ * IDs can be allocated.
+ */
+#define bf_init(v, N) \
+ do { \
+ (v).n = 0; \
+ (v).m = ((N) / WORD_SIZE + 1); \
+ (v).data = calloc(1, ((v).m * sizeof(word_t))); \
+ } while (0)
+
+/**
+ * allocate and assign an id from bitfield v.
+ */
+#define bf_assign_index(v, id) \
+ do { \
+ bf_find_bit(v, id); \
+ bf_set_bit(v, id); \
+ } while (0)
+
+/**
+ * return an id to bitfield v
+ */
+#define bf_release_index(v, id) \
+ (v).data[bf_index(id)] &= ~(1 << (bf_offset(id)))
+
+#define bf_index(b) ((b) / WORD_SIZE)
+#define bf_offset(b) ((b) % WORD_SIZE)
+
+/**
+ * Set a bit in the array. If it fills up that word and we are
+ * out of words, extend it by one more word.
+ */
+#define bf_set_bit(v, b) \
+ do { \
+ size_t w = bf_index(b); \
+ (v).data[w] |= 1 << (bf_offset(b)); \
+ (v).n += ((v).data[w] == WORD_MAX); \
+ if ((v).n == (v).m) { \
+ (v).m = (v).m + 1; \
+ (v).data = realloc((v).data, (v).m * sizeof(word_t)); \
+ } \
+ } while (0)
+
+/* Find a clear bit in v and assign it to b. */
+#define bf_find_bit(v, b) \
+ do { \
+ word_t word; \
+ unsigned int w, sh; \
+ for (w = 0; w <= (v).n; w++) { \
+ if ((word = (v).data[w]) != WORD_MAX) break; \
+ } \
+ (b) = ((word & 0xFFFF) == 0xFFFF) << 4; word >>= (b); \
+ sh = ((word & 0xFF) == 0xFF) << 3; word >>= sh; (b) |= sh; \
+ sh = ((word & 0xF) == 0xF) << 2; word >>= sh; (b) |= sh; \
+ sh = ((word & 0x3) == 0x3) << 1; word >>= sh; (b) |= sh; \
+ sh = ((word & 0x1) == 0x1) << 0; word >>= sh; (b) |= sh; \
+ (b) += (w * WORD_SIZE); \
+ } while (0)
+
+#endif
diff --git a/lib/command.c b/lib/command.c
index 80893602..9c6e63bd 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -4098,7 +4098,7 @@ DEFUN (show_commandtree,
/* Set config filename. Called from vty.c */
void
-host_config_set (char *filename)
+host_config_set (const char *filename)
{
if (host.config)
XFREE (MTYPE_HOST, host.config);
diff --git a/lib/command.h b/lib/command.h
index 6a20e232..04f9b030 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -479,6 +479,10 @@ struct cmd_token
#define CLEAR_STR "Reset functions\n"
#define RIP_STR "RIP 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"
+#define BGP_SOFT_OUT_STR "Resend all outbound updates\n"
+#define BGP_SOFT_RSCLIENT_RIB_STR "Soft reconfig for rsclient RIB\n"
#define OSPF_STR "OSPF information\n"
#define NEIGHBOR_STR "Specify neighbor router\n"
#define DEBUG_STR "Debugging functions (see also 'undebug')\n"
@@ -516,7 +520,8 @@ struct cmd_token
#define NEIGHBOR_ADDR_STR "Neighbor address\nIPv6 address\n"
#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|X:X::X:X|WORD) "
#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|X:X::X:X|WORD) "
-#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nInterface name or neighbor tag\n"
+#define NEIGHBOR_ADDR_STR3 "Neighbor address\nIPv6 address\nInterface name\n"
#else
#define NEIGHBOR_CMD "neighbor A.B.C.D "
#define NO_NEIGHBOR_CMD "no neighbor A.B.C.D "
@@ -557,7 +562,7 @@ extern struct cmd_element config_quit_cmd;
extern struct cmd_element config_help_cmd;
extern struct cmd_element config_list_cmd;
extern char *host_config_file (void);
-extern void host_config_set (char *);
+extern void host_config_set (const char *);
extern void print_version (const char *);
diff --git a/lib/fifo.h b/lib/fifo.h
index 6be75b76..47a1e888 100644
--- a/lib/fifo.h
+++ b/lib/fifo.h
@@ -25,6 +25,7 @@ struct fifo
{
struct fifo *next;
struct fifo *prev;
+ u_int32_t count;
};
#define FIFO_INIT(F) \
diff --git a/lib/filter.c b/lib/filter.c
index a4729414..9c3d3bd6 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -28,6 +28,7 @@
#include "sockunion.h"
#include "buffer.h"
#include "log.h"
+#include "routemap.h"
struct filter_cisco
{
@@ -460,6 +461,7 @@ access_list_filter_add (struct access_list *access, struct filter *filter)
/* Run hook function. */
if (access->master->add_hook)
(*access->master->add_hook) (access);
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_ADDED);
}
/* If access_list has no filter then return 1. */
@@ -493,6 +495,8 @@ access_list_filter_delete (struct access_list *access, struct filter *filter)
filter_free (filter);
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
+
/* Run hook function. */
if (master->delete_hook)
(*master->delete_hook) (access);
@@ -1337,6 +1341,7 @@ DEFUN (no_access_list_all,
master = access->master;
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
/* Run hook function. */
if (master->delete_hook)
(*master->delete_hook) (access);
@@ -1508,6 +1513,7 @@ DEFUN (no_ipv6_access_list_all,
master = access->master;
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
/* Run hook function. */
if (master->delete_hook)
(*master->delete_hook) (access);
diff --git a/lib/if.c b/lib/if.c
index 44b8586e..fe467c3e 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -135,6 +135,12 @@ if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id)
ifp->connected = list_new ();
ifp->connected->del = (void (*) (void *)) connected_free;
+ ifp->nbr_connected = list_new ();
+ ifp->nbr_connected->del = (void (*) (void *)) nbr_connected_free;
+
+ /* Enable Link-detection by default */
+ SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+
if (if_master.if_new_hook)
(*if_master.if_new_hook) (ifp);
@@ -156,6 +162,9 @@ if_delete_retain (struct interface *ifp)
/* Free connected address list */
list_delete_all_node (ifp->connected);
+
+ /* Free connected nbr address list */
+ list_delete_all_node (ifp->nbr_connected);
}
/* Delete and free interface structure. */
@@ -167,6 +176,7 @@ if_delete (struct interface *ifp)
if_delete_retain(ifp);
list_free (ifp->connected);
+ list_free (ifp->nbr_connected);
XFREE (MTYPE_IF, ifp);
}
@@ -793,6 +803,13 @@ connected_new (void)
return XCALLOC (MTYPE_CONNECTED, sizeof (struct connected));
}
+/* Allocate nbr connected structure. */
+struct nbr_connected *
+nbr_connected_new (void)
+{
+ return XCALLOC (MTYPE_NBR_CONNECTED, sizeof (struct nbr_connected));
+}
+
/* Free connected structure. */
void
connected_free (struct connected *connected)
@@ -809,6 +826,30 @@ connected_free (struct connected *connected)
XFREE (MTYPE_CONNECTED, connected);
}
+/* Free nbr connected structure. */
+void
+nbr_connected_free (struct nbr_connected *connected)
+{
+ if (connected->address)
+ prefix_free (connected->address);
+
+ XFREE (MTYPE_NBR_CONNECTED, connected);
+}
+
+/* If same interface nbr address already exists... */
+struct nbr_connected *
+nbr_connected_check (struct interface *ifp, struct prefix *p)
+{
+ struct nbr_connected *ifc;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO (ifp->nbr_connected, node, ifc))
+ if (prefix_same (ifc->address, p))
+ return ifc;
+
+ return NULL;
+}
+
/* Print if_addr structure. */
static void __attribute__ ((unused))
connected_log (struct connected *connected, char *str)
@@ -835,6 +876,26 @@ connected_log (struct connected *connected, char *str)
zlog (NULL, LOG_INFO, "%s", logbuf);
}
+/* Print if_addr structure. */
+static void __attribute__ ((unused))
+nbr_connected_log (struct nbr_connected *connected, char *str)
+{
+ struct prefix *p;
+ struct interface *ifp;
+ char logbuf[BUFSIZ];
+ char buf[BUFSIZ];
+
+ ifp = connected->ifp;
+ p = connected->address;
+
+ snprintf (logbuf, BUFSIZ, "%s interface %s %s %s/%d ",
+ str, ifp->name, prefix_family_str (p),
+ inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+ p->prefixlen);
+
+ zlog (NULL, LOG_INFO, "%s", logbuf);
+}
+
/* If two connected address has same prefix return 1. */
static int
connected_same_prefix (struct prefix *p1, struct prefix *p2)
diff --git a/lib/if.h b/lib/if.h
index b3d14ba4..f71aa1e4 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -182,6 +182,9 @@ struct interface
/* Connected address list. */
struct list *connected;
+ /* Neighbor connected address list. */
+ struct list *nbr_connected;
+
/* Daemon specific interface data pointer. */
void *info;
@@ -222,6 +225,7 @@ struct connected
u_char flags;
#define ZEBRA_IFA_SECONDARY (1 << 0)
#define ZEBRA_IFA_PEER (1 << 1)
+#define ZEBRA_IFA_UNNUMBERED (1 << 2)
/* N.B. the ZEBRA_IFA_PEER flag should be set if and only if
a peer address has been configured. If this flag is set,
the destination field must contain the peer address.
@@ -240,6 +244,16 @@ struct connected
char *label;
};
+/* Nbr Connected address structure. */
+struct nbr_connected
+{
+ /* Attached interface. */
+ struct interface *ifp;
+
+ /* Address of connected network. */
+ struct prefix *address;
+};
+
/* Does the destination field contain a peer address? */
#define CONNECTED_PEER(C) CHECK_FLAG((C)->flags, ZEBRA_IFA_PEER)
@@ -381,6 +395,9 @@ extern struct connected *connected_delete_by_prefix (struct interface *,
struct prefix *);
extern struct connected *connected_lookup_address (struct interface *,
struct in_addr);
+extern struct nbr_connected *nbr_connected_new (void);
+extern void nbr_connected_free (struct nbr_connected *);
+struct nbr_connected *nbr_connected_check (struct interface *, struct prefix *);
#ifndef HAVE_IF_NAMETOINDEX
extern ifindex_t if_nametoindex (const char *);
diff --git a/lib/libospf.h b/lib/libospf.h
index 9265ca59..a3bbc1dc 100644
--- a/lib/libospf.h
+++ b/lib/libospf.h
@@ -80,6 +80,12 @@
#define OSPF_FAST_HELLO_DEFAULT 0
#define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */
+#define OSPF_AREA_RANGE_COST_UNSPEC -1U
+
+#define OSPF_AREA_DEFAULT 0
+#define OSPF_AREA_STUB 1
+#define OSPF_AREA_NSSA 2
+#define OSPF_AREA_TYPE_MAX 3
/* SPF Throttling timer values. */
#define OSPF_SPF_DELAY_DEFAULT 0
diff --git a/lib/log.c b/lib/log.c
index 0914bf84..d57bb3de 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -621,28 +621,6 @@ ZLOG_FUNC(zlog_debug, LOG_DEBUG)
#undef ZLOG_FUNC
-#define PLOG_FUNC(FUNCNAME,PRIORITY) \
-void \
-FUNCNAME(struct zlog *zl, const char *format, ...) \
-{ \
- va_list args; \
- va_start(args, format); \
- vzlog (zl, PRIORITY, format, args); \
- va_end(args); \
-}
-
-PLOG_FUNC(plog_err, LOG_ERR)
-
-PLOG_FUNC(plog_warn, LOG_WARNING)
-
-PLOG_FUNC(plog_info, LOG_INFO)
-
-PLOG_FUNC(plog_notice, LOG_NOTICE)
-
-PLOG_FUNC(plog_debug, LOG_DEBUG)
-
-#undef PLOG_FUNC
-
void zlog_thread_info (int log_level)
{
if (thread_current)
@@ -895,6 +873,11 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_ROUTER_ID_DELETE),
DESC_ENTRY (ZEBRA_ROUTER_ID_UPDATE),
DESC_ENTRY (ZEBRA_HELLO),
+ DESC_ENTRY (ZEBRA_NEXTHOP_REGISTER),
+ DESC_ENTRY (ZEBRA_NEXTHOP_UNREGISTER),
+ DESC_ENTRY (ZEBRA_NEXTHOP_UPDATE),
+ DESC_ENTRY (ZEBRA_INTERFACE_NBR_ADDRESS_ADD),
+ DESC_ENTRY (ZEBRA_INTERFACE_NBR_ADDRESS_DELETE),
};
#undef DESC_ENTRY
diff --git a/lib/log.h b/lib/log.h
index 514884cc..d7f994a0 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -121,18 +121,6 @@ extern void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_notice (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_debug (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
-/* For bgpd's peer oriented log. */
-extern void plog_err (struct zlog *, const char *format, ...)
- PRINTF_ATTRIBUTE(2, 3);
-extern void plog_warn (struct zlog *, const char *format, ...)
- PRINTF_ATTRIBUTE(2, 3);
-extern void plog_info (struct zlog *, const char *format, ...)
- PRINTF_ATTRIBUTE(2, 3);
-extern void plog_notice (struct zlog *, const char *format, ...)
- PRINTF_ATTRIBUTE(2, 3);
-extern void plog_debug (struct zlog *, const char *format, ...)
- PRINTF_ATTRIBUTE(2, 3);
-
extern void zlog_thread_info (int log_level);
/* Set logging level for the given destination. If the log_level
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 6df14480..f2791595 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -26,6 +26,7 @@ struct memory_list memory_list_lib[] =
{ MTYPE_VTY_HIST, "VTY history" },
{ MTYPE_IF, "Interface" },
{ MTYPE_CONNECTED, "Connected" },
+ { MTYPE_NBR_CONNECTED, "Neighbor Connected" },
{ MTYPE_CONNECTED_LABEL, "Connected interface label" },
{ MTYPE_BUFFER, "Buffer" },
{ MTYPE_BUFFER_DATA, "Buffer data" },
@@ -54,6 +55,7 @@ struct memory_list memory_list_lib[] =
{ MTYPE_ROUTE_MAP_RULE, "Route map rule" },
{ MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" },
{ MTYPE_ROUTE_MAP_COMPILED, "Route map compiled" },
+ { MTYPE_ROUTE_MAP_DEP, "Route map dependency" },
{ MTYPE_CMD_TOKENS, "Command desc" },
{ MTYPE_KEY, "Key" },
{ MTYPE_KEYCHAIN, "Key chain" },
@@ -86,6 +88,7 @@ struct memory_list memory_list_zebra[] =
{ MTYPE_RIB_DEST, "RIB destination" },
{ MTYPE_RIB_TABLE_INFO, "RIB table info" },
{ MTYPE_NETLINK_NAME, "Netlink name" },
+ { MTYPE_RNH, "Nexthop tracking object" },
{ -1, NULL },
};
@@ -145,10 +148,13 @@ struct memory_list memory_list_bgp[] =
{ MTYPE_TRANSIT, "BGP transit attr" },
{ MTYPE_TRANSIT_VAL, "BGP transit val" },
{ 0, NULL },
+ { MTYPE_BGP_DEBUG_FILTER, "BGP debug filter" },
+ { 0, NULL },
{ MTYPE_BGP_DISTANCE, "BGP distance" },
{ MTYPE_BGP_NEXTHOP_CACHE, "BGP nexthop" },
{ MTYPE_BGP_CONFED_LIST, "BGP confed list" },
{ MTYPE_PEER_UPDATE_SOURCE, "BGP peer update interface" },
+ { MTYPE_PEER_CONF_IF, "BGP peer config interface" },
{ MTYPE_BGP_DAMP_INFO, "Dampening info" },
{ MTYPE_BGP_DAMP_ARRAY, "BGP Dampening array" },
{ MTYPE_BGP_REGEXP, "BGP regexp" },
diff --git a/lib/nexthop.c b/lib/nexthop.c
new file mode 100644
index 00000000..5eb2182d
--- /dev/null
+++ b/lib/nexthop.c
@@ -0,0 +1,168 @@
+/* A generic nexthop structure
+ * Copyright (C) 2013 Cumulus Networks, Inc.
+ *
+ * This file is part of Quagga.
+ *
+ * Quagga 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.
+ *
+ * Quagga 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 Quagga; 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 "str.h"
+#include "command.h"
+#include "if.h"
+#include "log.h"
+#include "sockunion.h"
+#include "linklist.h"
+#include "thread.h"
+#include "prefix.h"
+#include "nexthop.h"
+
+/* check if nexthops are same, non-recursive */
+int
+nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2)
+{
+ if (next1->type != next2->type)
+ return 0;
+
+ switch (next1->type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4))
+ return 0;
+ if (next1->ifindex && (next1->ifindex != next2->ifindex))
+ return 0;
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IFNAME:
+ if (next1->ifindex != next2->ifindex)
+ return 0;
+ break;
+#ifdef HAVE_IPV6
+ case NEXTHOP_TYPE_IPV6:
+ if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
+ return 0;
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFNAME:
+ if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6))
+ return 0;
+ if (next1->ifindex != next2->ifindex)
+ return 0;
+ break;
+#endif /* HAVE_IPV6 */
+ default:
+ /* do nothing */
+ break;
+ }
+ return 1;
+}
+
+/*
+ * nexthop_type_to_str
+ */
+const char *
+nexthop_type_to_str (enum nexthop_types_t nh_type)
+{
+ static const char *desc[] = {
+ "none",
+ "Directly connected",
+ "Interface route",
+ "IPv4 nexthop",
+ "IPv4 nexthop with ifindex",
+ "IPv4 nexthop with ifname",
+ "IPv6 nexthop",
+ "IPv6 nexthop with ifindex",
+ "IPv6 nexthop with ifname",
+ "Null0 nexthop",
+ };
+
+ if (nh_type >= ZEBRA_NUM_OF (desc))
+ return "<Invalid nh type>";
+
+ return desc[nh_type];
+}
+
+struct nexthop *
+nexthop_new (void)
+{
+ return XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+}
+
+/* Add nexthop to the end of a nexthop list. */
+void
+nexthop_add (struct nexthop **target, struct nexthop *nexthop)
+{
+ struct nexthop *last;
+
+ for (last = *target; last && last->next; last = last->next)
+ ;
+ if (last)
+ last->next = nexthop;
+ else
+ *target = nexthop;
+ nexthop->prev = last;
+}
+
+void
+copy_nexthops (struct nexthop **tnh, struct nexthop *nh)
+{
+ struct nexthop *nexthop;
+ struct nexthop *nh1;
+
+ for (nh1 = nh; nh1; nh1 = nh1->next)
+ {
+ nexthop = nexthop_new();
+ nexthop->flags = nh->flags;
+ nexthop->type = nh->type;
+ nexthop->ifindex = nh->ifindex;
+ if (nh->ifname)
+ nexthop->ifname = XSTRDUP(0, nh->ifname);
+ memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
+ memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
+ nexthop_add(tnh, nexthop);
+
+ if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))
+ copy_nexthops(&nexthop->resolved, nh1->resolved);
+ }
+}
+
+/* Free nexthop. */
+void
+nexthop_free (struct nexthop *nexthop)
+{
+ if (nexthop->ifname)
+ XFREE (0, nexthop->ifname);
+ if (nexthop->resolved)
+ nexthops_free(nexthop->resolved);
+ XFREE (MTYPE_NEXTHOP, nexthop);
+}
+
+/* Frees a list of nexthops */
+void
+nexthops_free (struct nexthop *nexthop)
+{
+ struct nexthop *nh, *next;
+
+ for (nh = nexthop; nh; nh = next)
+ {
+ next = nh->next;
+ nexthop_free (nh);
+ }
+}
diff --git a/lib/nexthop.h b/lib/nexthop.h
new file mode 100644
index 00000000..d8e82e9d
--- /dev/null
+++ b/lib/nexthop.h
@@ -0,0 +1,93 @@
+/*
+ * Nexthop structure definition.
+ * Copyright (C) 1997, 98, 99, 2001 Kunihiro Ishiguro
+ * Copyright (C) 2013 Cumulus Networks, Inc.
+ *
+ * This file is part of Quagga.
+ *
+ * Quagga 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.
+ *
+ * Quagga 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 Quagga; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _LIB_NEXTHOP_H
+#define _LIB_NEXTHOP_H
+
+#include "prefix.h"
+
+union g_addr {
+ struct in_addr ipv4;
+#ifdef HAVE_IPV6
+ struct in6_addr ipv6;
+#endif /* HAVE_IPV6 */
+};
+
+enum nexthop_types_t
+{
+ NEXTHOP_TYPE_IFINDEX = 1, /* Directly connected. */
+ NEXTHOP_TYPE_IFNAME, /* Interface route. */
+ NEXTHOP_TYPE_IPV4, /* IPv4 nexthop. */
+ NEXTHOP_TYPE_IPV4_IFINDEX, /* IPv4 nexthop with ifindex. */
+ NEXTHOP_TYPE_IPV4_IFNAME, /* IPv4 nexthop with ifname. */
+ NEXTHOP_TYPE_IPV6, /* IPv6 nexthop. */
+ NEXTHOP_TYPE_IPV6_IFINDEX, /* IPv6 nexthop with ifindex. */
+ NEXTHOP_TYPE_IPV6_IFNAME, /* IPv6 nexthop with ifname. */
+ NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */
+};
+
+/* Nexthop structure. */
+struct nexthop
+{
+ struct nexthop *next;
+ struct nexthop *prev;
+
+ /* Interface index. */
+ char *ifname;
+ ifindex_t ifindex;
+
+ enum nexthop_types_t type;
+
+ u_char flags;
+#define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */
+#define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */
+#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */
+#define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */
+#define NEXTHOP_FLAG_MATCHED (1 << 4) /* Already matched vs a nexthop */
+#define NEXTHOP_FLAG_FILTERED (1 << 5) /* rmap filtered, used by static only */
+
+ /* Nexthop address */
+ union g_addr gate;
+ union g_addr src;
+ union g_addr rmap_src; /* Src is set via routemap */
+
+ /* Nexthops obtained by recursive resolution.
+ *
+ * If the nexthop struct needs to be resolved recursively,
+ * NEXTHOP_FLAG_RECURSIVE will be set in flags and the nexthops
+ * obtained by recursive resolution will be added to `resolved'.
+ * Only one level of recursive resolution is currently supported. */
+ struct nexthop *resolved;
+};
+
+struct nexthop *nexthop_new (void);
+void nexthop_add (struct nexthop **target, struct nexthop *nexthop);
+
+void copy_nexthops (struct nexthop **tnh, struct nexthop *nh);
+void nexthop_free (struct nexthop *nexthop);
+void nexthops_free (struct nexthop *nexthop);
+
+extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
+extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2);
+
+#endif /*_LIB_NEXTHOP_H */
diff --git a/lib/plist.c b/lib/plist.c
index 699c9b13..16533881 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -29,6 +29,7 @@
#include "buffer.h"
#include "stream.h"
#include "log.h"
+#include "routemap.h"
#include "plist_int.h"
@@ -330,13 +331,16 @@ prefix_list_delete (struct prefix_list *plist)
cleared. */
master->recent = NULL;
+ route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_DELETED);
+
+ if (master->delete_hook)
+ (*master->delete_hook) (NULL);
+
if (plist->name)
XFREE (MTYPE_PREFIX_LIST_STR, plist->name);
-
+
prefix_list_free (plist);
-
- if (master->delete_hook)
- (*master->delete_hook) (NULL);
+
}
static struct prefix_list_entry *
@@ -457,6 +461,7 @@ prefix_list_entry_delete (struct prefix_list *plist,
if (update_list)
{
+ route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_DELETED);
if (plist->master->delete_hook)
(*plist->master->delete_hook) (plist);
@@ -519,6 +524,7 @@ prefix_list_entry_add (struct prefix_list *plist,
if (plist->master->add_hook)
(*plist->master->add_hook) (plist);
+ route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_ADDED);
plist->master->recent = plist;
}
diff --git a/lib/prefix.h b/lib/prefix.h
index 4a317507..d4f0eb92 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -235,13 +235,26 @@ extern void masklen2ip6 (const int, struct in6_addr *);
extern void str2in6_addr (const char *, struct in6_addr *);
extern const char *inet6_ntoa (struct in6_addr);
+static inline int ipv6_martian (struct in6_addr *addr)
+{
+ struct in6_addr localhost_addr;
+
+ inet_pton (AF_INET6, "::1", &localhost_addr);
+
+ if (IPV6_ADDR_SAME(&localhost_addr, addr))
+ return 1;
+
+ return 0;
+}
+
#endif /* HAVE_IPV6 */
extern int all_digit (const char *);
+/* NOTE: This routine expects the address argument in network byte order. */
static inline int ipv4_martian (struct in_addr *addr)
{
- in_addr_t ip = addr->s_addr;
+ in_addr_t ip = ntohl(addr->s_addr);
if (IPV4_NET0(ip) || IPV4_NET127(ip) || IPV4_CLASS_DE(ip)) {
return 1;
diff --git a/lib/route_types.pl b/lib/route_types.pl
index e1595afc..1e2f20ca 100755..100644
--- a/lib/route_types.pl
+++ b/lib/route_types.pl
@@ -89,7 +89,7 @@ printf <<EOF, $ARGV[0];
#ifndef _QUAGGA_ROUTE_TYPES_H
#define _QUAGGA_ROUTE_TYPES_H
-/* Zebra route's types. */
+/* Zebra route's' types. */
EOF
push @protos, "ZEBRA_ROUTE_MAX";
@@ -133,7 +133,7 @@ printf "#define SHOW_ROUTE_V6_HEADER \\\n%s\n", codelist(@protosv6);
print "\n";
sub collect {
- my ($daemon, $ipv4, $ipv6) = @_;
+ my ($daemon, $ipv4, $ipv6, $any) = @_;
my (@names, @help) = ((), ());
for my $p (@protos) {
next if ($protodetail{$p}->{"daemon"} eq $daemon && $daemon ne "zebra");
@@ -142,6 +142,10 @@ sub collect {
push @names, $protodetail{$p}->{"cname"};
push @help, " \"".$protodetail{$p}->{"longhelp"}."\\n\"";
}
+ if ($any == 1) {
+ push @names, "any";
+ push @help, " \"Any of the above protocols\\n\"";
+ }
return ("\"(" . join("|", @names) . ")\"", join(" \\\n", @help));
}
@@ -149,18 +153,25 @@ for my $daemon (sort keys %daemons) {
next unless ($daemons{$daemon}->{"ipv4"} || $daemons{$daemon}->{"ipv6"});
printf "/* %s */\n", $daemon;
if ($daemons{$daemon}->{"ipv4"} && $daemons{$daemon}->{"ipv6"}) {
- my ($names, $help) = collect($daemon, 1, 1);
+ my ($names, $help) = collect($daemon, 1, 1, 0);
printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names;
printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
- ($names, $help) = collect($daemon, 1, 0);
+ ($names, $help) = collect($daemon, 1, 0, 0);
printf "#define QUAGGA_IP_REDIST_STR_%s \\\n %s\n", uc $daemon, $names;
printf "#define QUAGGA_IP_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
- ($names, $help) = collect($daemon, 0, 1);
+ ($names, $help) = collect($daemon, 0, 1, 0);
printf "#define QUAGGA_IP6_REDIST_STR_%s \\\n %s\n", uc $daemon, $names;
printf "#define QUAGGA_IP6_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
+ ($names, $help) = collect($daemon, 0, 1, 1);
+ if ($daemon eq "zebra") {
+ printf "#define QUAGGA_IP_PROTOCOL_MAP_STR_%s \\\n %s\n", uc $daemon, $names;
+ printf "#define QUAGGA_IP_PROTOCOL_MAP_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
+ printf "#define QUAGGA_IP6_PROTOCOL_MAP_STR_%s \\\n %s\n", uc $daemon, $names;
+ printf "#define QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
+ }
} else {
my ($names, $help) = collect($daemon,
- $daemons{$daemon}->{"ipv4"}, $daemons{$daemon}->{"ipv6"});
+ $daemons{$daemon}->{"ipv4"}, $daemons{$daemon}->{"ipv6"}, 0);
printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names;
printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help;
}
diff --git a/lib/routemap.c b/lib/routemap.c
index 7302e231..1a1d318c 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -28,6 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "command.h"
#include "vty.h"
#include "log.h"
+#include "hash.h"
/* Vector for route match rules. */
static vector route_match_vec;
@@ -60,15 +61,47 @@ struct route_map_list
void (*add_hook) (const char *);
void (*delete_hook) (const char *);
- void (*event_hook) (route_map_event_t, const char *);
+ void (*event_hook) (route_map_event_t, const char *);
};
/* Master list of route map. */
-static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
+static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL, NULL };
+
+enum route_map_upd8_type
+ {
+ ROUTE_MAP_ADD = 1,
+ ROUTE_MAP_DEL,
+ };
+
+/* all possible route-map dependency types */
+enum route_map_dep_type
+ {
+ ROUTE_MAP_DEP_RMAP = 1,
+ ROUTE_MAP_DEP_CLIST,
+ ROUTE_MAP_DEP_ECLIST,
+ ROUTE_MAP_DEP_PLIST,
+ ROUTE_MAP_DEP_ASPATH,
+ ROUTE_MAP_DEP_FILTER,
+ ROUTE_MAP_DEP_MAX,
+ };
+
+struct route_map_dep
+{
+ char *dep_name;
+ struct hash *dep_rmap_hash;
+ struct hash *this_hash; /* ptr to the hash structure this is part of */
+};
-static void
-route_map_rule_delete (struct route_map_rule_list *,
- struct route_map_rule *);
+/* Hashes maintaining dependency between various sublists used by route maps */
+struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
+
+static unsigned int route_map_dep_hash_make_key (void *p);
+static int route_map_dep_hash_cmp (const void *p1, const void *p2);
+static void route_map_init_dep_hashes (void);
+static void route_map_clear_all_references (char *rmap_name);
+static void route_map_rule_delete (struct route_map_rule_list *,
+ struct route_map_rule *);
+static int rmap_debug = 0;
static void
route_map_index_delete (struct route_map_index *, int);
@@ -105,45 +138,72 @@ route_map_add (const char *name)
/* Execute hook. */
if (route_map_master.add_hook)
- (*route_map_master.add_hook) (name);
-
+ {
+ (*route_map_master.add_hook) (name);
+ route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED);
+ }
return map;
}
-/* Route map delete from list. */
+/* this is supposed to be called post processing by
+ * the delete hook function. Don't invoke delete_hook
+ * again in this routine.
+ */
static void
-route_map_delete (struct route_map *map)
+route_map_free_map (struct route_map *map)
{
struct route_map_list *list;
struct route_map_index *index;
- char *name;
-
+
while ((index = map->head) != NULL)
route_map_index_delete (index, 0);
- name = map->name;
-
list = &route_map_master;
- if (map->next)
- map->next->prev = map->prev;
- else
- list->tail = map->prev;
+ if (map != NULL)
+ {
+ if (map->next)
+ map->next->prev = map->prev;
+ else
+ list->tail = map->prev;
- if (map->prev)
- map->prev->next = map->next;
- else
- list->head = map->next;
+ if (map->prev)
+ map->prev->next = map->next;
+ else
+ list->head = map->next;
- XFREE (MTYPE_ROUTE_MAP, map);
+ XFREE (MTYPE_ROUTE_MAP_NAME, map->name);
+ XFREE (MTYPE_ROUTE_MAP, map);
+ }
+}
+/* Route map delete from list. */
+static void
+route_map_delete (struct route_map *map)
+{
+ struct route_map_index *index;
+ char *name;
+
+ while ((index = map->head) != NULL)
+ route_map_index_delete (index, 0);
+
+ name = map->name;
+ map->head = NULL;
+
+ /* Clear all dependencies */
+ route_map_clear_all_references(name);
+ map->deleted = 1;
/* Execute deletion hook. */
if (route_map_master.delete_hook)
- (*route_map_master.delete_hook) (name);
-
- if (name)
- XFREE (MTYPE_ROUTE_MAP_NAME, name);
+ {
+ (*route_map_master.delete_hook) (name);
+ route_map_notify_dependencies(name, RMAP_EVENT_CALL_DELETED);
+ }
+ if (!map->to_be_processed)
+ {
+ route_map_free_map (map);
+ }
}
/* Lookup route map by route map name string. */
@@ -152,12 +212,50 @@ route_map_lookup_by_name (const char *name)
{
struct route_map *map;
+ if (!name)
+ return NULL;
+
for (map = route_map_master.head; map; map = map->next)
- if (strcmp (map->name, name) == 0)
+ if ((strcmp (map->name, name) == 0) && (!map->deleted))
return map;
return NULL;
}
+int
+route_map_mark_updated (const char *name, int del_later)
+{
+ struct route_map *map;
+ int ret = -1;
+
+ /* We need to do this walk manually instead of calling lookup_by_name()
+ * because the lookup function doesn't return route maps marked as
+ * deleted.
+ */
+ for (map = route_map_master.head; map; map = map->next)
+ if (strcmp (map->name, name) == 0)
+ {
+ map->to_be_processed = 1;
+ ret = 0;
+ }
+
+ return(ret);
+}
+
+int
+route_map_clear_updated (struct route_map *map)
+{
+ int ret = -1;
+
+ if (map)
+ {
+ map->to_be_processed = 0;
+ if (map->deleted)
+ route_map_free_map(map);
+ }
+
+ return (ret);
+}
+
/* Lookup route map. If there isn't route map create one and return
it. */
static struct route_map *
@@ -168,9 +266,31 @@ route_map_get (const char *name)
map = route_map_lookup_by_name (name);
if (map == NULL)
map = route_map_add (name);
+
return map;
}
+void
+route_map_walk_update_list (void *arg,
+ int (*route_map_update_fn) (void *arg, char *name))
+{
+ struct route_map *node;
+ struct route_map *nnode = NULL;
+
+ for (node = route_map_master.head; node; node = nnode)
+ {
+ if (node->to_be_processed)
+ {
+ /* DD: Should we add any thread yield code here */
+ route_map_update_fn(arg, node->name);
+ nnode = node->next;
+ route_map_clear_updated(node);
+ }
+ else
+ nnode = node->next;
+ }
+}
+
/* Return route map's type string. */
static const char *
route_map_type_str (enum route_map_type type)
@@ -271,7 +391,8 @@ vty_show_route_map (struct vty *vty, const char *name)
else
{
for (map = route_map_master.head; map; map = map->next)
- vty_show_route_map_entry (vty, map);
+ if (!map->deleted)
+ vty_show_route_map_entry (vty, map);
}
return CMD_SUCCESS;
}
@@ -320,9 +441,11 @@ route_map_index_delete (struct route_map_index *index, int notify)
/* Execute event hook. */
if (route_map_master.event_hook && notify)
- (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
- index->map->name);
-
+ {
+ (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
XFREE (MTYPE_ROUTE_MAP_INDEX, index);
}
@@ -386,9 +509,11 @@ route_map_index_add (struct route_map *map, enum route_map_type type,
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
- map->name);
-
+ {
+ (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
+ map->name);
+ route_map_notify_dependencies (map->name, RMAP_EVENT_CALL_ADDED);
+ }
return index;
}
@@ -521,6 +646,28 @@ rulecmp (const char *dst, const char *src)
return 1;
}
+/* Use this to return the already specified argument for this match. This is
+ * useful to get the specified argument with a route map match rule when the
+ * rule is being deleted and the argument is not provided.
+ */
+const char *
+route_map_get_match_arg(struct route_map_index *index, const char *match_name)
+{
+ struct route_map_rule *rule;
+ struct route_map_rule_cmd *cmd;
+
+ /* First lookup rule for add match statement. */
+ cmd = route_map_lookup_match (match_name);
+ if (cmd == NULL)
+ return NULL;
+
+ for (rule = index->match_list.head; rule; rule = rule->next)
+ if (rule->cmd == cmd && rule->rule_str != NULL)
+ return (rule->rule_str);
+
+ return (NULL);
+}
+
/* Add match statement to route map. */
int
route_map_add_match (struct route_map_index *index, const char *match_name,
@@ -572,10 +719,13 @@ route_map_add_match (struct route_map_index *index, const char *match_name,
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (replaced ?
- RMAP_EVENT_MATCH_REPLACED:
- RMAP_EVENT_MATCH_ADDED,
- index->map->name);
+ {
+ (*route_map_master.event_hook) (replaced ?
+ RMAP_EVENT_MATCH_REPLACED:
+ RMAP_EVENT_MATCH_ADDED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
return 0;
}
@@ -599,8 +749,11 @@ route_map_delete_match (struct route_map_index *index, const char *match_name,
route_map_rule_delete (&index->match_list, rule);
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
- index->map->name);
+ {
+ (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
return 0;
}
/* Can't find matched rule. */
@@ -659,10 +812,13 @@ route_map_add_set (struct route_map_index *index, const char *set_name,
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (replaced ?
- RMAP_EVENT_SET_REPLACED:
- RMAP_EVENT_SET_ADDED,
- index->map->name);
+ {
+ (*route_map_master.event_hook) (replaced ?
+ RMAP_EVENT_SET_REPLACED:
+ RMAP_EVENT_SET_ADDED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
return 0;
}
@@ -685,8 +841,11 @@ route_map_delete_set (struct route_map_index *index, const char *set_name,
route_map_rule_delete (&index->set_list, rule);
/* Execute event hook. */
if (route_map_master.event_hook)
- (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
- index->map->name);
+ {
+ (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
+ index->map->name);
+ route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED);
+ }
return 0;
}
/* Can't find matched rule. */
@@ -902,6 +1061,259 @@ route_map_finish (void)
route_map_delete (route_map_master.head);
}
+/* Routines for route map dependency lists and dependency processing */
+static int
+route_map_rmap_hash_cmp (const void *p1, const void *p2)
+{
+ return (strcmp((char *)p1, (char *)p2) == 0);
+}
+
+static int
+route_map_dep_hash_cmp (const void *p1, const void *p2)
+{
+
+ return (strcmp (((struct route_map_dep *)p1)->dep_name, (char *)p2) == 0);
+}
+
+static void
+route_map_clear_reference(struct hash_backet *backet, void *arg)
+{
+ struct route_map_dep *dep = (struct route_map_dep *)backet->data;
+ char *rmap_name;
+
+ if (dep && arg)
+ {
+ rmap_name = (char *)hash_release(dep->dep_rmap_hash, (void *)arg);
+ if (rmap_name)
+ {
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+ }
+ if (!dep->dep_rmap_hash->count)
+ {
+ dep = hash_release(dep->this_hash, (void *)dep->dep_name);
+ hash_free(dep->dep_rmap_hash);
+ XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
+ XFREE(MTYPE_ROUTE_MAP_DEP, dep);
+ }
+ }
+}
+
+static void
+route_map_clear_all_references (char *rmap_name)
+{
+ int i;
+
+ for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
+ {
+ hash_iterate(route_map_dep_hash[i], route_map_clear_reference,
+ (void *)rmap_name);
+ }
+}
+
+static void *
+route_map_dep_hash_alloc(void *p)
+{
+ char *dep_name = (char *)p;
+ struct route_map_dep *dep_entry;
+
+ dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
+ dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
+ dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key,
+ route_map_rmap_hash_cmp);
+ dep_entry->this_hash = NULL;
+
+ return((void *)dep_entry);
+}
+
+static void *
+route_map_name_hash_alloc(void *p)
+{
+ return((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (char *)p));
+}
+
+static unsigned int
+route_map_dep_hash_make_key (void *p)
+{
+ return (string_hash_make((char *)p));
+}
+
+static void
+route_map_print_dependency (struct hash_backet *backet, void *data)
+{
+ char *rmap_name = (char *)backet->data;
+ char *dep_name = (char *)data;
+
+ if (rmap_name)
+ zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name, rmap_name);
+}
+
+static int
+route_map_dep_update (struct hash *dephash, const char *dep_name,
+ const char *rmap_name,
+ route_map_event_t type)
+{
+ struct route_map_dep *dep = NULL;
+ char *ret_map_name;
+ char *dname, *rname;
+ int ret = 0;
+
+ dname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
+ rname = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
+
+ switch (type)
+ {
+ case RMAP_EVENT_PLIST_ADDED:
+ case RMAP_EVENT_CLIST_ADDED:
+ case RMAP_EVENT_ECLIST_ADDED:
+ case RMAP_EVENT_ASLIST_ADDED:
+ case RMAP_EVENT_CALL_ADDED:
+ case RMAP_EVENT_FILTER_ADDED:
+ if (rmap_debug)
+ zlog_debug("%s: Adding dependency for %s in %s", __FUNCTION__,
+ dep_name, rmap_name);
+ dep = (struct route_map_dep *) hash_get (dephash, dname,
+ route_map_dep_hash_alloc);
+ if (!dep) {
+ ret = -1;
+ goto out;
+ }
+
+ if (!dep->this_hash)
+ dep->this_hash = dephash;
+
+ hash_get(dep->dep_rmap_hash, rname, route_map_name_hash_alloc);
+ break;
+ case RMAP_EVENT_PLIST_DELETED:
+ case RMAP_EVENT_CLIST_DELETED:
+ case RMAP_EVENT_ECLIST_DELETED:
+ case RMAP_EVENT_ASLIST_DELETED:
+ case RMAP_EVENT_CALL_DELETED:
+ case RMAP_EVENT_FILTER_DELETED:
+ if (rmap_debug)
+ zlog_debug("%s: Deleting dependency for %s in %s", __FUNCTION__,
+ dep_name, rmap_name);
+ dep = (struct route_map_dep *) hash_get (dephash, dname, NULL);
+ if (!dep) {
+ goto out;
+ }
+ ret_map_name = (char *)hash_release(dep->dep_rmap_hash, rname);
+ if (ret_map_name)
+ XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
+
+ if (!dep->dep_rmap_hash->count)
+ {
+ dep = hash_release(dephash, (void *)dep_name);
+ hash_free(dep->dep_rmap_hash);
+ XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
+ XFREE(MTYPE_ROUTE_MAP_DEP, dep);
+ dep = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (dep)
+ {
+ if (rmap_debug)
+ hash_iterate (dep->dep_rmap_hash, route_map_print_dependency, (void *)dep_name);
+ }
+
+ out:
+ XFREE(MTYPE_ROUTE_MAP_NAME, rname);
+ XFREE(MTYPE_ROUTE_MAP_NAME, dname);
+ return ret;
+}
+
+static struct hash *
+route_map_get_dep_hash (route_map_event_t event)
+{
+ struct hash *upd8_hash = NULL;
+
+ switch (event)
+ {
+ case RMAP_EVENT_PLIST_ADDED:
+ case RMAP_EVENT_PLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_PLIST];
+ break;
+ case RMAP_EVENT_CLIST_ADDED:
+ case RMAP_EVENT_CLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_CLIST];
+ break;
+ case RMAP_EVENT_ECLIST_ADDED:
+ case RMAP_EVENT_ECLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ECLIST];
+ break;
+ case RMAP_EVENT_ASLIST_ADDED:
+ case RMAP_EVENT_ASLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
+ break;
+ case RMAP_EVENT_CALL_ADDED:
+ case RMAP_EVENT_CALL_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
+ break;
+ case RMAP_EVENT_FILTER_ADDED:
+ case RMAP_EVENT_FILTER_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
+ break;
+ default:
+ upd8_hash = NULL;
+ break;
+ }
+ return (upd8_hash);
+}
+
+static void
+route_map_process_dependency (struct hash_backet *backet, void *data)
+{
+ char *rmap_name;
+ route_map_event_t type = (route_map_event_t )data;
+
+ rmap_name = (char *)backet->data;
+
+ if (rmap_name)
+ {
+ if (rmap_debug)
+ zlog_debug("%s: Notifying %s of dependency", __FUNCTION__,
+ rmap_name);
+ if (route_map_master.event_hook)
+ (*route_map_master.event_hook) (type, rmap_name);
+ }
+}
+
+void
+route_map_upd8_dependency (route_map_event_t type, const char *arg,
+ const char *rmap_name)
+{
+ struct hash *upd8_hash = NULL;
+
+ if ((upd8_hash = route_map_get_dep_hash(type)))
+ route_map_dep_update (upd8_hash, arg, rmap_name, type);
+}
+
+void
+route_map_notify_dependencies (const char *affected_name, route_map_event_t event)
+{
+ struct route_map_dep *dep;
+ struct hash *upd8_hash;
+
+ if (!affected_name)
+ return;
+
+ if ((upd8_hash = route_map_get_dep_hash(event)) == NULL)
+ return;
+
+ dep = (struct route_map_dep *)hash_get (upd8_hash, (void *)affected_name,
+ NULL);
+ if (dep)
+ {
+ if (!dep->this_hash)
+ dep->this_hash = upd8_hash;
+
+ hash_iterate (dep->dep_rmap_hash, route_map_process_dependency, (void *)event);
+ }
+}
+
/* VTY related functions. */
DEFUN (route_map,
route_map_cmd,
@@ -1183,9 +1595,19 @@ DEFUN (rmap_call,
if (index)
{
if (index->nextrm)
- XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
+ {
+ route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
+ index->nextrm,
+ index->map->name);
+ XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
+ }
index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
}
+
+ /* Execute event hook. */
+ route_map_upd8_dependency (RMAP_EVENT_CALL_ADDED,
+ index->nextrm,
+ index->map->name);
return CMD_SUCCESS;
}
@@ -1201,6 +1623,9 @@ DEFUN (no_rmap_call,
if (index->nextrm)
{
+ route_map_upd8_dependency (RMAP_EVENT_CALL_DELETED,
+ index->nextrm,
+ index->map->name);
XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
index->nextrm = NULL;
}
@@ -1299,10 +1724,22 @@ static struct cmd_node rmap_node =
1
};
+static void
+route_map_init_dep_hashes (void)
+{
+ int i;
+
+ for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
+ route_map_dep_hash[i] = hash_create(route_map_dep_hash_make_key,
+ route_map_dep_hash_cmp);
+}
+
/* Initialization of route map vector. */
void
route_map_init_vty (void)
{
+ route_map_init_dep_hashes();
+
/* Install route map top node. */
install_node (&rmap_node, route_map_config_write);
diff --git a/lib/routemap.h b/lib/routemap.h
index 2479c81a..61c14fea 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -67,7 +67,19 @@ typedef enum
RMAP_EVENT_MATCH_DELETED,
RMAP_EVENT_MATCH_REPLACED,
RMAP_EVENT_INDEX_ADDED,
- RMAP_EVENT_INDEX_DELETED
+ RMAP_EVENT_INDEX_DELETED,
+ RMAP_EVENT_CALL_ADDED, /* call to another routemap added */
+ RMAP_EVENT_CALL_DELETED,
+ RMAP_EVENT_PLIST_ADDED,
+ RMAP_EVENT_PLIST_DELETED,
+ RMAP_EVENT_CLIST_ADDED,
+ RMAP_EVENT_CLIST_DELETED,
+ RMAP_EVENT_ECLIST_ADDED,
+ RMAP_EVENT_ECLIST_DELETED,
+ RMAP_EVENT_ASLIST_ADDED,
+ RMAP_EVENT_ASLIST_DELETED,
+ RMAP_EVENT_FILTER_ADDED,
+ RMAP_EVENT_FILTER_DELETED,
} route_map_event_t;
/* Depth limit in RMAP recursion using RMAP_CALL. */
@@ -150,6 +162,10 @@ struct route_map
/* Make linked list. */
struct route_map *next;
struct route_map *prev;
+
+ /* Maintain update info */
+ int to_be_processed; /* True if modification isn't acted on yet */
+ int deleted; /* If 1, then this node will be deleted */
};
/* Prototypes. */
@@ -167,6 +183,9 @@ extern int route_map_delete_match (struct route_map_index *index,
const char *match_name,
const char *match_arg);
+extern const char *route_map_get_match_arg (struct route_map_index *index,
+ const char *match_name);
+
/* Add route-map set statement to the route map. */
extern int route_map_add_set (struct route_map_index *index,
const char *set_name,
@@ -194,6 +213,16 @@ extern route_map_result_t route_map_apply (struct route_map *map,
extern void route_map_add_hook (void (*func) (const char *));
extern void route_map_delete_hook (void (*func) (const char *));
-extern void route_map_event_hook (void (*func) (route_map_event_t, const char *));
+extern void route_map_event_hook (void (*func) (route_map_event_t,
+ const char *));
+extern int route_map_mark_updated (const char *name, int deleted);
+extern int route_map_clear_updated (struct route_map *rmap);
+extern void route_map_walk_update_list (void *arg,
+ int (*update_fn) (void *arg,
+ char *name));
+extern void route_map_upd8_dependency (route_map_event_t type, const char *arg,
+ const char *rmap_name);
+extern void route_map_notify_dependencies (const char *affected_name,
+ route_map_event_t event);
#endif /* _ZEBRA_ROUTEMAP_H */
diff --git a/lib/thread.c b/lib/thread.c
index 5e40261e..f72e67ea 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -57,8 +57,6 @@ static unsigned short timers_inited;
static struct hash *cpu_record = NULL;
-/* Struct timeval's tv_usec one second value. */
-#define TIMER_SECOND_MICRO 1000000L
/* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
And change negative values to 0. */
@@ -691,6 +689,7 @@ thread_get (struct thread_master *m, u_char type,
thread->func = func;
thread->arg = arg;
thread->index = -1;
+ thread->yield = THREAD_YIELD_TIME_SLOT; /* default */
thread->funcname = funcname;
thread->schedfrom = schedfrom;
@@ -1190,7 +1189,8 @@ thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
return timeval_elapsed (now->real, start->real);
}
-/* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds.
+/* We should aim to yield after yield milliseconds, which defaults
+ to THREAD_YIELD_TIME_SLOT .
Note: we are using real (wall clock) time for this calculation.
It could be argued that CPU time may make more sense in certain
contexts. The things to consider are whether the thread may have
@@ -1204,7 +1204,13 @@ thread_should_yield (struct thread *thread)
{
quagga_get_relative (NULL);
return (timeval_elapsed(relative_time, thread->real) >
- THREAD_YIELD_TIME_SLOT);
+ thread->yield);
+}
+
+void
+thread_set_yield_time (struct thread *thread, unsigned long yield_time)
+{
+ thread->yield = yield_time;
}
void
diff --git a/lib/thread.h b/lib/thread.h
index 5bc756c7..1c9f4f18 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -84,6 +84,7 @@ struct thread
const char *funcname;
const char *schedfrom;
int schedfrom_line;
+ unsigned long yield; /* yield time in us */
};
struct cpu_thread_history
@@ -108,6 +109,9 @@ enum quagga_clkid {
QUAGGA_CLK_REALTIME_STABILISED, /* like realtime, but non-decrementing */
};
+/* Struct timeval's tv_usec one second value. */
+#define TIMER_SECOND_MICRO 1000000L
+
/* Thread types. */
#define THREAD_READ 0
#define THREAD_WRITE 1
@@ -212,6 +216,8 @@ extern unsigned long thread_timer_remain_second (struct thread *);
extern struct timeval thread_timer_remain(struct thread*);
extern int thread_should_yield (struct thread *);
extern unsigned long timeval_elapsed (struct timeval a, struct timeval b);
+/* set yield time for thread */
+extern void thread_set_yield_time (struct thread *, unsigned long);
/* Internal libzebra exports */
extern void thread_getrusage (RUSAGE_T *);
diff --git a/lib/workqueue.c b/lib/workqueue.c
index b1a5d5bf..d2d002f2 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -88,6 +88,7 @@ work_queue_new (struct thread_master *m, const char *queue_name)
/* Default values, can be overriden by caller */
new->spec.hold = WORK_QUEUE_DEFAULT_HOLD;
+ new->spec.yield = THREAD_YIELD_TIME_SLOT;
return new;
}
@@ -123,6 +124,9 @@ work_queue_schedule (struct work_queue *wq, unsigned int delay)
{
wq->thread = thread_add_background (wq->master, work_queue_run,
wq, delay);
+ /* set thread yield time, if needed */
+ if (wq->thread && wq->spec.yield != THREAD_YIELD_TIME_SLOT)
+ thread_set_yield_time (wq->thread, wq->spec.yield);
return 1;
}
else
@@ -184,27 +188,27 @@ DEFUN(show_work_queues,
struct work_queue *wq;
vty_out (vty,
- "%c %8s %5s %8s %21s%s",
- ' ', "List","(ms) ","Q. Runs","Cycle Counts ",
+ "%c %8s %5s %8s %8s %21s%s",
+ ' ', "List","(ms) ","Q. Runs","Yields","Cycle Counts ",
VTY_NEWLINE);
vty_out (vty,
- "%c %8s %5s %8s %7s %6s %6s %s%s",
+ "%c %8s %5s %8s %8s %7s %6s %8s %6s %s%s",
'P',
"Items",
"Hold",
- "Total",
- "Best","Gran.","Avg.",
+ "Total","Total",
+ "Best","Gran.","Total","Avg.",
"Name",
VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO (work_queues, node, wq))
{
- vty_out (vty,"%c %8d %5d %8ld %7d %6d %6u %s%s",
+ vty_out (vty,"%c %8d %5d %8ld %8ld %7d %6d %8ld %6u %s%s",
(CHECK_FLAG (wq->flags, WQ_UNPLUGGED) ? ' ' : 'P'),
listcount (wq->items),
wq->spec.hold,
- wq->runs,
- wq->cycles.best, wq->cycles.granularity,
+ wq->runs, wq->yields,
+ wq->cycles.best, wq->cycles.granularity, wq->cycles.total,
(wq->runs) ?
(unsigned int) (wq->cycles.total / wq->runs) : 0,
wq->name,
@@ -260,7 +264,8 @@ work_queue_run (struct thread *thread)
assert (wq && wq->items);
/* calculate cycle granularity:
- * list iteration == 1 cycle
+ * list iteration == 1 run
+ * listnode processing == 1 cycle
* granularity == # cycles between checks whether we should yield.
*
* granularity should be > 0, and can increase slowly after each run to
@@ -319,6 +324,14 @@ work_queue_run (struct thread *thread)
{
item->ran--;
work_queue_item_requeue (wq, node);
+ /* If a single node is being used with a meta-queue (e.g., zebra),
+ * update the next node as we don't want to exit the thread and
+ * reschedule it after every node. By definition, WQ_REQUEUE is
+ * meant to continue the processing; the yield logic will kick in
+ * to terminate the thread when time has exceeded.
+ */
+ if (nnode == NULL)
+ nnode = node;
break;
}
case WQ_RETRY_NOW:
@@ -356,7 +369,7 @@ stats:
/* we yielded, check whether granularity should be reduced */
if (yielded && (cycles < wq->cycles.granularity))
{
- wq->cycles.granularity = ((cycles > 0) ? cycles
+ wq->cycles.granularity = ((cycles > 0) ? cycles
: WORK_QUEUE_MIN_GRANULARITY);
}
/* otherwise, should granularity increase? */
@@ -364,7 +377,7 @@ stats:
{
if (cycles > wq->cycles.best)
wq->cycles.best = cycles;
-
+
/* along with yielded check, provides hysteresis for granularity */
if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR
* WQ_HYSTERESIS_FACTOR))
@@ -376,6 +389,8 @@ stats:
wq->runs++;
wq->cycles.total += cycles;
+ if (yielded)
+ wq->yields++;
#if 0
printf ("%s: cycles %d, new: best %d, worst %d\n",
diff --git a/lib/workqueue.h b/lib/workqueue.h
index 5ad25893..19b44041 100644
--- a/lib/workqueue.h
+++ b/lib/workqueue.h
@@ -84,11 +84,14 @@ struct work_queue
unsigned int max_retries;
unsigned int hold; /* hold time for first run, in ms */
+
+ unsigned long yield; /* yield time in us for associated thread */
} spec;
/* remaining fields should be opaque to users */
struct list *items; /* queue item list */
unsigned long runs; /* runs count */
+ unsigned long yields; /* yields count */
struct {
unsigned int best;
diff --git a/lib/zclient.c b/lib/zclient.c
index 9d50ebc0..78e5aa31 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -516,6 +516,8 @@ zclient_connect (struct thread *t)
* If ZAPI_MESSAGE_METRIC is set, the metric value is written as an 8
* byte value.
*
+ * If ZAPI_MESSAGE_TAG is set, the tag value is written as a 2 byte value
+ *
* XXX: No attention paid to alignment.
*/
int
@@ -574,6 +576,8 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU))
stream_putl (s, api->mtu);
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
+ stream_putw (s, api->tag);
/* Put length at the first point of the stream. */
stream_putw_at (s, 0, stream_get_endp (s));
@@ -610,7 +614,15 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
/* Nexthop, ifindex, distance and metric information. */
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
{
- stream_putc (s, api->nexthop_num + api->ifindex_num);
+ if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
+ {
+ stream_putc (s, 1);
+ stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
+ /* XXX assert(api->nexthop_num == 0); */
+ /* XXX assert(api->ifindex_num == 0); */
+ }
+ else
+ stream_putc (s, api->nexthop_num + api->ifindex_num);
for (i = 0; i < api->nexthop_num; i++)
{
@@ -630,6 +642,8 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
stream_putl (s, api->metric);
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU))
stream_putl (s, api->mtu);
+ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
+ stream_putw (s, api->tag);
/* Put length at the first point of the stream. */
stream_putw_at (s, 0, stream_get_endp (s));
@@ -902,6 +916,81 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
return ifc;
}
+/*
+ * format of message for neighbor connected address is:
+ * 0
+ * 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * | type | ZEBRA_INTERFACE_NBR_ADDRESS_ADD or
+ * +-+-+-+-+-+-+-+-+ ZEBRA_INTERFACE_NBR_ADDRES_DELETE
+ * | |
+ * + +
+ * | ifindex |
+ * + +
+ * | |
+ * + +
+ * | |
+ * +-+-+-+-+-+-+-+-+
+ * | addr_family |
+ * +-+-+-+-+-+-+-+-+
+ * | addr... |
+ * : :
+ * | |
+ * +-+-+-+-+-+-+-+-+
+ * | addr_len | len of addr.
+ * +-+-+-+-+-+-+-+-+
+ */
+struct nbr_connected *
+zebra_interface_nbr_address_read (int type, struct stream *s)
+{
+ unsigned int ifindex;
+ struct interface *ifp;
+ struct prefix p;
+ struct nbr_connected *ifc;
+
+ /* Get interface index. */
+ ifindex = stream_getl (s);
+
+ /* Lookup index. */
+ ifp = if_lookup_by_index (ifindex);
+ if (ifp == NULL)
+ {
+ zlog_warn ("zebra_nbr_interface_address_read(%s): "
+ "Can't find interface by ifindex: %d ",
+ (type == ZEBRA_INTERFACE_NBR_ADDRESS_ADD? "ADD" : "DELETE"),
+ ifindex);
+ return NULL;
+ }
+
+ p.family = stream_getc (s);
+ stream_get (&p.u.prefix, s, prefix_blen (&p));
+ p.prefixlen = stream_getc (s);
+
+ if (type == ZEBRA_INTERFACE_NBR_ADDRESS_ADD)
+ {
+ /* Currently only supporting P2P links, so any new RA source address is
+ considered as the replacement of the previously learnt Link-Local address. */
+ if (!(ifc = listnode_head(ifp->nbr_connected)))
+ {
+ ifc = nbr_connected_new ();
+ ifc->address = prefix_new ();
+ ifc->ifp = ifp;
+ listnode_add (ifp->nbr_connected, ifc);
+ }
+
+ prefix_copy(ifc->address, &p);
+ }
+ else
+ {
+ assert (type == ZEBRA_INTERFACE_NBR_ADDRESS_DELETE);
+
+ ifc = nbr_connected_check(ifp, &p);
+ if (ifc)
+ listnode_delete (ifp->nbr_connected, ifc);
+ }
+
+ return ifc;
+}
/* Zebra client message read function. */
static int
@@ -1021,6 +1110,14 @@ zclient_read (struct thread *thread)
if (zclient->interface_address_delete)
(*zclient->interface_address_delete) (command, zclient, length, vrf_id);
break;
+ case ZEBRA_INTERFACE_NBR_ADDRESS_ADD:
+ if (zclient->interface_nbr_address_add)
+ (*zclient->interface_nbr_address_add) (command, zclient, length, vrf_id);
+ break;
+ case ZEBRA_INTERFACE_NBR_ADDRESS_DELETE:
+ if (zclient->interface_nbr_address_delete)
+ (*zclient->interface_nbr_address_delete) (command, zclient, length, vrf_id);
+ break;
case ZEBRA_INTERFACE_UP:
if (zclient->interface_up)
(*zclient->interface_up) (command, zclient, length, vrf_id);
@@ -1045,6 +1142,12 @@ zclient_read (struct thread *thread)
if (zclient->ipv6_route_delete)
(*zclient->ipv6_route_delete) (command, zclient, length, vrf_id);
break;
+ case ZEBRA_NEXTHOP_UPDATE:
+ if (zclient_debug)
+ zlog_debug("zclient rcvd nexthop update\n");
+ if (zclient->nexthop_update)
+ (*zclient->nexthop_update) (command, zclient, length, vrf_id);
+ break;
default:
break;
}
diff --git a/lib/zclient.h b/lib/zclient.h
index d069eb22..5a3dac87 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -85,10 +85,13 @@ struct zclient
int (*interface_down) (int, struct zclient *, uint16_t, vrf_id_t);
int (*interface_address_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*interface_address_delete) (int, struct zclient *, uint16_t, vrf_id_t);
+ int (*interface_nbr_address_add) (int, struct zclient *, uint16_t, vrf_id_t);
+ int (*interface_nbr_address_delete) (int, struct zclient *, uint16_t, vrf_id_t);
int (*ipv4_route_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*ipv4_route_delete) (int, struct zclient *, uint16_t, vrf_id_t);
int (*ipv6_route_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*ipv6_route_delete) (int, struct zclient *, uint16_t, vrf_id_t);
+ int (*nexthop_update) (int, struct zclient *, uint16_t, vrf_id_t);
};
/* Zebra API message flag. */
@@ -97,6 +100,7 @@ struct zclient
#define ZAPI_MESSAGE_DISTANCE 0x04
#define ZAPI_MESSAGE_METRIC 0x08
#define ZAPI_MESSAGE_MTU 0x10
+#define ZAPI_MESSAGE_TAG 0x20
/* Zserv protocol message header */
struct zserv_header
@@ -130,6 +134,8 @@ struct zapi_ipv4
u_char distance;
+ u_short tag;
+
u_int32_t metric;
u_int32_t mtu;
@@ -179,6 +185,7 @@ extern struct interface *zebra_interface_state_read (struct stream *,
vrf_id_t);
extern struct connected *zebra_interface_address_read (int, struct stream *,
vrf_id_t);
+extern struct nbr_connected *zebra_interface_nbr_address_read (int, struct stream *);
extern void zebra_interface_if_set_value (struct stream *, struct interface *);
extern void zebra_router_id_update_read (struct stream *s, struct prefix *rid);
extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *,
@@ -205,6 +212,8 @@ struct zapi_ipv6
u_char distance;
+ u_short tag;
+
u_int32_t metric;
u_int32_t mtu;
diff --git a/lib/zebra.h b/lib/zebra.h
index d9802830..7fc00d57 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -415,7 +415,12 @@ struct in_pktinfo
#define ZEBRA_HELLO 23
#define ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB 24
#define ZEBRA_VRF_UNREGISTER 25
-#define ZEBRA_MESSAGE_MAX 26
+#define ZEBRA_NEXTHOP_REGISTER 26
+#define ZEBRA_NEXTHOP_UNREGISTER 27
+#define ZEBRA_NEXTHOP_UPDATE 28
+#define ZEBRA_INTERFACE_NBR_ADDRESS_ADD 29
+#define ZEBRA_INTERFACE_NBR_ADDRESS_DELETE 30
+#define ZEBRA_MESSAGE_MAX 31
/* Marker value used in new Zserv, in the byte location corresponding
* the command value in the old zserv header. To allow old and new
@@ -509,6 +514,7 @@ typedef enum {
#define CHECK_FLAG(V,F) ((V) & (F))
#define SET_FLAG(V,F) (V) |= (F)
#define UNSET_FLAG(V,F) (V) &= ~(F)
+#define RESET_FLAG(V) (V) = 0
typedef u_int8_t safi_t;
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index bb79900e..33299f48 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -38,6 +38,7 @@
#include "ospf6_route.h"
#include "ospf6_lsdb.h"
#include "ospf6_message.h"
+#include "ospf6_zebra.h"
#include "ospf6_top.h"
#include "ospf6_area.h"
@@ -67,53 +68,56 @@ ospf6_is_router_abr (struct ospf6 *o)
return 0;
}
+static int
+ospf6_abr_nexthops_belong_to_area (struct ospf6_route *route,
+ struct ospf6_area *area)
+{
+ struct ospf6_interface *oi;
+
+ oi = ospf6_interface_lookup_by_ifindex (ospf6_route_get_first_nh_index(route));
+ if (oi && oi->area && oi->area == area)
+ return 1;
+ else
+ return 0;
+}
+
+static void
+ospf6_abr_delete_route (struct ospf6_route *range, struct ospf6_route *summary,
+ struct ospf6_route_table *summary_table,
+ struct ospf6_lsa *old)
+{
+ if (summary)
+ {
+ ospf6_route_remove (summary, summary_table);
+ }
+
+ if (old && !OSPF6_LSA_IS_MAXAGE (old))
+ ospf6_lsa_purge (old);
+}
+
void
ospf6_abr_enable_area (struct ospf6_area *area)
{
struct ospf6_area *oa;
- struct ospf6_route *ro;
struct listnode *node, *nnode;
for (ALL_LIST_ELEMENTS (area->ospf6->area_list, node, nnode, oa))
- {
- /* update B bit for each area */
- OSPF6_ROUTER_LSA_SCHEDULE (oa);
-
- /* install other area's configured address range */
- if (oa != area)
- {
- for (ro = ospf6_route_head (oa->range_table); ro;
- ro = ospf6_route_next (ro))
- {
- if (CHECK_FLAG (ro->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
- ospf6_abr_originate_summary_to_area (ro, area);
- }
- }
- }
-
- /* install calculated routes to border routers */
- for (ro = ospf6_route_head (area->ospf6->brouter_table); ro;
- ro = ospf6_route_next (ro))
- ospf6_abr_originate_summary_to_area (ro, area);
-
- /* install calculated routes to network (may be rejected by ranges) */
- for (ro = ospf6_route_head (area->ospf6->route_table); ro;
- ro = ospf6_route_next (ro))
- ospf6_abr_originate_summary_to_area (ro, area);
+ /* update B bit for each area */
+ OSPF6_ROUTER_LSA_SCHEDULE (oa);
}
void
ospf6_abr_disable_area (struct ospf6_area *area)
{
struct ospf6_area *oa;
- struct ospf6_route *ro;
+ struct ospf6_route *ro, *nro;
struct ospf6_lsa *old;
struct listnode *node, *nnode;
/* Withdraw all summary prefixes previously originated */
- for (ro = ospf6_route_head (area->summary_prefix); ro;
- ro = ospf6_route_next (ro))
+ for (ro = ospf6_route_head (area->summary_prefix); ro; ro = nro)
{
+ nro = ospf6_route_next (ro);
old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id,
area->ospf6->router_id, area->lsdb);
if (old)
@@ -122,9 +126,9 @@ ospf6_abr_disable_area (struct ospf6_area *area)
}
/* Withdraw all summary router-routes previously originated */
- for (ro = ospf6_route_head (area->summary_router); ro;
- ro = ospf6_route_next (ro))
+ for (ro = ospf6_route_head (area->summary_router); ro; ro = nro)
{
+ nro = ospf6_route_next (ro);
old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id,
area->ospf6->router_id, area->lsdb);
if (old)
@@ -139,12 +143,13 @@ ospf6_abr_disable_area (struct ospf6_area *area)
}
/* RFC 2328 12.4.3. Summary-LSAs */
-void
+/* Returns 1 if a summary LSA has been generated for the area */
+/* This is used by the area/range logic to add/remove blackhole routes */
+int
ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
struct ospf6_area *area)
{
struct ospf6_lsa *lsa, *old = NULL;
- struct ospf6_interface *oi;
struct ospf6_route *summary, *range = NULL;
struct ospf6_area *route_area;
char buffer[OSPF6_MAX_LSASIZE];
@@ -157,6 +162,54 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
char buf[64];
int is_debug = 0;
+ /* Only destination type network, range or ASBR are considered */
+ if (route->type != OSPF6_DEST_TYPE_NETWORK &&
+ route->type != OSPF6_DEST_TYPE_RANGE &&
+ ((route->type != OSPF6_DEST_TYPE_ROUTER) ||
+ !CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E)))
+ {
+ if (is_debug)
+ zlog_debug ("Route type is none of network, range nor ASBR, ignore");
+ return 0;
+ }
+
+ /* AS External routes are never considered */
+ if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 ||
+ route->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
+ {
+ if (is_debug)
+ zlog_debug ("Path type is external, skip");
+ return 0;
+ }
+
+ /* do not generate if the path's area is the same as target area */
+ if (route->path.area_id == area->area_id)
+ {
+ if (is_debug)
+ zlog_debug ("The route is in the area itself, ignore");
+ return 0;
+ }
+
+ /* do not generate if the nexthops belongs to the target area */
+ if (ospf6_abr_nexthops_belong_to_area (route, area))
+ {
+ if (is_debug)
+ zlog_debug ("The route's nexthop is in the same area, ignore");
+ return 0;
+ }
+
+ if (route->type == OSPF6_DEST_TYPE_ROUTER)
+ {
+ if (ADV_ROUTER_IN_PREFIX (&route->prefix) == area->ospf6->router_id)
+ {
+ inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf,
+ sizeof (buf));
+ zlog_debug ("%s: Skipping ASBR announcement for ABR (%s)", __func__,
+ buf);
+ return 0;
+ }
+ }
+
if (route->type == OSPF6_DEST_TYPE_ROUTER)
{
if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_ROUTER))
@@ -192,76 +245,62 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
{
if (is_debug)
zlog_debug ("The route has just removed, purge previous LSA");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
- }
- /* Only destination type network, range or ASBR are considered */
- if (route->type != OSPF6_DEST_TYPE_NETWORK &&
- route->type != OSPF6_DEST_TYPE_RANGE &&
- (route->type != OSPF6_DEST_TYPE_ROUTER ||
- ! CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E)))
- {
- if (is_debug)
- zlog_debug ("Route type is none of network, range nor ASBR, withdraw");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
- }
+ if (route->type == OSPF6_DEST_TYPE_RANGE)
+ {
+ /* Whether the route have active longer prefix */
+ if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
+ {
+ if (is_debug)
+ zlog_debug ("The range is not active. withdraw");
+
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ }
+ }
+ else
+ if (old)
+ ospf6_lsa_purge (old);
- /* AS External routes are never considered */
- if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 ||
- route->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
- {
- if (is_debug)
- zlog_debug ("Path type is external, withdraw");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ return 0;
}
- /* do not generate if the path's area is the same as target area */
- if (route->path.area_id == area->area_id)
+ if ((route->type == OSPF6_DEST_TYPE_ROUTER) && IS_AREA_STUB(area))
{
if (is_debug)
- zlog_debug ("The route is in the area itself, ignore");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ zlog_debug ("Area has been stubbed, purge Inter-Router LSA");
+
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ return 0;
}
- /* do not generate if the nexthops belongs to the target area */
- oi = ospf6_interface_lookup_by_ifindex (route->nexthop[0].ifindex);
- if (oi && oi->area && oi->area == area)
+ if (area->no_summary && (route->path.subtype != OSPF6_PATH_SUBTYPE_DEFAULT_RT))
{
if (is_debug)
- zlog_debug ("The route's nexthop is in the same area, ignore");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ zlog_debug ("Area has been stubbed, purge prefix LSA");
+
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ return 0;
}
/* do not generate if the route cost is greater or equal to LSInfinity */
if (route->path.cost >= OSPF_LS_INFINITY)
{
- if (is_debug)
- zlog_debug ("The cost exceeds LSInfinity, withdraw");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ /* When we're clearing the range route because all active prefixes
+ * under the range are gone, we set the range's cost to
+ * OSPF_AREA_RANGE_COST_UNSPEC, which is > OSPF_LS_INFINITY. We
+ * don't want to trigger the code here for that. This code is for
+ * handling routes that have gone to infinity. The range removal happens
+ * elsewhere.
+ */
+ if ((route->type != OSPF6_DEST_TYPE_RANGE) &&
+ (route->path.cost != OSPF_AREA_RANGE_COST_UNSPEC))
+ {
+ if (is_debug)
+ zlog_debug ("The cost exceeds LSInfinity, withdraw");
+ if (old)
+ ospf6_lsa_purge (old);
+ return 0;
+ }
}
/* if this is a route to ASBR */
@@ -272,11 +311,8 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
{
if (is_debug)
zlog_debug ("This is the secondary path to the ASBR, ignore");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ return 0;
}
/* Do not generate if the area is stub */
@@ -305,12 +341,8 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
zlog_debug ("Suppressed by range %s of area %s",
buf, route_area->name);
}
-
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ return 0;
}
}
@@ -322,23 +354,17 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
{
if (is_debug)
zlog_debug ("This is the range with DoNotAdvertise set. ignore");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ return 0;
}
- /* Whether the route have active longer prefix */
+ /* If there are no active prefixes in this range, remove */
if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
{
if (is_debug)
zlog_debug ("The range is not active. withdraw");
- if (summary)
- ospf6_route_remove (summary, summary_table);
- if (old)
- ospf6_lsa_purge (old);
- return;
+ ospf6_abr_delete_route (route, summary, summary_table, old);
+ return 0;
}
}
@@ -359,7 +385,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
buf, sizeof(buf));
zlog_debug ("prefix %s was denied by export list", buf);
}
- return;
+ return 0;
}
}
@@ -380,7 +406,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
buf, sizeof (buf));
zlog_debug ("prefix %s was denied by filter-list out", buf);
}
- return;
+ return 0;
}
}
@@ -388,15 +414,23 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
if (summary == NULL)
{
summary = ospf6_route_copy (route);
- if (route->type == OSPF6_DEST_TYPE_NETWORK ||
- route->type == OSPF6_DEST_TYPE_RANGE)
- summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX);
- else
- summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER);
summary->path.origin.adv_router = area->ospf6->router_id;
- summary->path.origin.id =
- ospf6_new_ls_id (summary->path.origin.type,
- summary->path.origin.adv_router, area->lsdb);
+
+ if (route->type == OSPF6_DEST_TYPE_ROUTER)
+ {
+ summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER);
+ summary->path.origin.id = ADV_ROUTER_IN_PREFIX (&route->prefix);
+ }
+ else
+ {
+ summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+ if (route->type == OSPF6_DEST_TYPE_RANGE)
+ summary->path.origin.id = route->linkstate_id;
+ else
+ summary->path.origin.id =
+ ospf6_new_ls_id (summary->path.origin.type,
+ summary->path.origin.adv_router, area->lsdb);
+ }
summary = ospf6_route_add (summary, summary_table);
}
else
@@ -412,8 +446,9 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
summary->path.prefix_options = route->path.prefix_options;
summary->path.area_id = area->area_id;
summary->path.type = OSPF6_PATH_TYPE_INTER;
+ summary->path.subtype = route->path.subtype;
summary->path.cost = route->path.cost;
- summary->nexthop[0] = route->nexthop[0];
+ /* summary->nexthop[0] = route->nexthop[0]; */
/* prepare buffer */
memset (buffer, 0, sizeof (buffer));
@@ -470,35 +505,138 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
/* Originate */
ospf6_lsa_originate_area (lsa, area);
+
+ return 1;
+}
+
+void
+ospf6_abr_range_reset_cost (struct ospf6 *ospf6)
+{
+ struct listnode *node, *nnode;
+ struct ospf6_area *oa;
+ struct ospf6_route *range;
+
+ for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
+ for (range = ospf6_route_head (oa->range_table); range;
+ range = ospf6_route_next (range))
+ OSPF6_ABR_RANGE_CLEAR_COST(range);
+}
+
+static inline u_int32_t
+ospf6_abr_range_compute_cost (struct ospf6_route *range, struct ospf6 *o)
+{
+ struct ospf6_route *ro;
+ u_int32_t cost = 0;
+
+ for (ro = ospf6_route_match_head (&range->prefix, o->route_table);
+ ro; ro = ospf6_route_match_next (&range->prefix, ro))
+ {
+ if (ro->path.area_id == range->path.area_id &&
+ (ro->path.type == OSPF6_PATH_TYPE_INTRA) &&
+ ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE))
+ cost = MAX (cost, ro->path.cost);
+ }
+
+ return cost;
+}
+
+static inline int
+ospf6_abr_range_summary_needs_update (struct ospf6_route *range,
+ u_int32_t cost)
+{
+ int redo_summary = 0;
+
+ if (CHECK_FLAG(range->flag, OSPF6_ROUTE_REMOVE))
+ {
+ UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+ redo_summary = 1;
+ }
+ else if (CHECK_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE))
+ {
+ if (range->path.cost != 0)
+ {
+ range->path.cost = 0;
+ redo_summary = 1;
+ }
+ }
+ else if (cost)
+ {
+ if ((OSPF6_PATH_COST_IS_CONFIGURED(range->path) &&
+ range->path.cost != range->path.u.cost_config))
+ {
+ range->path.cost = range->path.u.cost_config;
+ SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+ redo_summary = 1;
+ }
+ else if (!OSPF6_PATH_COST_IS_CONFIGURED(range->path) &&
+ range->path.cost != cost)
+ {
+ range->path.cost = cost;
+ SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+ redo_summary = 1;
+ }
+ }
+ else if (CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
+ {
+ /* Cost is zero, meaning no active range */
+ UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+ range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC;
+ redo_summary = 1;
+ }
+
+ return (redo_summary);
}
static void
ospf6_abr_range_update (struct ospf6_route *range)
{
u_int32_t cost = 0;
- struct ospf6_route *ro;
+ struct listnode *node, *nnode;
+ struct ospf6_area *oa;
+ int summary_orig = 0;
assert (range->type == OSPF6_DEST_TYPE_RANGE);
/* update range's cost and active flag */
- for (ro = ospf6_route_match_head (&range->prefix, ospf6->route_table);
- ro; ro = ospf6_route_match_next (&range->prefix, ro))
+ cost = ospf6_abr_range_compute_cost (range, ospf6);
+
+ /* Non-zero cost is a proxy for active longer prefixes in this range.
+ * If there are active routes covered by this range AND either the configured
+ * cost has changed or the summarized cost has changed then redo summaries.
+ * Alternately, if there are no longer active prefixes and there are
+ * summary announcements, withdraw those announcements.
+ *
+ * The don't advertise code relies on the path.cost being set to UNSPEC to
+ * work the first time. Subsequent times the path.cost is not 0 anyway if there
+ * were active ranges.
+ */
+
+ if (ospf6_abr_range_summary_needs_update (range, cost))
{
- if (ro->path.area_id == range->path.area_id &&
- ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE))
- cost = MAX (cost, ro->path.cost);
- }
+ for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
+ summary_orig += ospf6_abr_originate_summary_to_area (range, oa);
- if (range->path.cost != cost)
- {
- range->path.cost = cost;
+ if (CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY) && summary_orig)
+ {
+ if (! CHECK_FLAG (range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED))
+ {
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_debug ("Add discard route");
- if (range->path.cost)
- SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+ ospf6_zebra_add_discard (range);
+ }
+ }
else
- UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
-
- ospf6_abr_originate_summary (range);
+ {
+ /* Summary removed or no summary generated as no specifics exist */
+ if (CHECK_FLAG (range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED))
+ {
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_debug ("Delete discard route");
+
+ ospf6_zebra_delete_discard (range);
+ }
+ }
}
}
@@ -514,13 +652,63 @@ ospf6_abr_originate_summary (struct ospf6_route *route)
oa = ospf6_area_lookup (route->path.area_id, ospf6);
range = ospf6_route_lookup_bestmatch (&route->prefix, oa->range_table);
if (range)
- ospf6_abr_range_update (range);
+ {
+ ospf6_abr_range_update (range);
+ }
}
for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
ospf6_abr_originate_summary_to_area (route, oa);
}
+void
+ospf6_abr_defaults_to_stub (struct ospf6 *o)
+{
+ struct listnode *node, *nnode;
+ struct ospf6_area *oa;
+ struct ospf6_route *def, *route;
+
+ if (!o->backbone)
+ return;
+
+ def = ospf6_route_create();
+ def->type = OSPF6_DEST_TYPE_NETWORK;
+ def->prefix.family = AF_INET6;
+ def->prefix.prefixlen = 0;
+ memset (&def->prefix.u.prefix6, 0, sizeof(struct in6_addr));
+ def->type = OSPF6_DEST_TYPE_NETWORK;
+ def->path.type = OSPF6_PATH_TYPE_INTER;
+ def->path.subtype = OSPF6_PATH_SUBTYPE_DEFAULT_RT;
+ def->path.area_id = o->backbone->area_id;
+
+ for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
+ {
+ if (!IS_AREA_STUB (oa))
+ {
+ /* withdraw defaults when an area switches from stub to non-stub */
+ route = ospf6_route_lookup (&def->prefix, oa->summary_prefix);
+ if (route && (route->path.subtype == def->path.subtype))
+ {
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_debug ("Withdrawing default route from non-stubby area %s",
+ oa->name);
+ SET_FLAG (def->flag, OSPF6_ROUTE_REMOVE);
+ ospf6_abr_originate_summary_to_area (def, oa);
+ }
+ }
+ else
+ {
+ /* announce defaults to stubby areas */
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_debug ("Announcing default route into stubby area %s",
+ oa->name);
+ UNSET_FLAG (def->flag, OSPF6_ROUTE_REMOVE);
+ ospf6_abr_originate_summary_to_area (def, oa);
+ }
+ }
+ ospf6_route_delete (def);
+}
+
/* RFC 2328 16.2. Calculating the inter-area routes */
void
ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
@@ -534,7 +722,6 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
u_int8_t prefix_options = 0;
u_int32_t cost = 0;
u_char router_bits = 0;
- int i;
char buf[64];
int is_debug = 0;
struct ospf6_inter_prefix_lsa *prefix_lsa = NULL;
@@ -575,6 +762,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
ospf6_linkstate_prefix (router_lsa->router_id, htonl (0), &prefix);
if (is_debug)
inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf));
+
table = oa->ospf6->brouter_table;
type = OSPF6_DEST_TYPE_ROUTER;
options[0] = router_lsa->options[0];
@@ -600,6 +788,8 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
old = route;
route = ospf6_route_next (route);
}
+ if (route)
+ ospf6_route_unlock (route);
/* (1) if cost == LSInfinity or if the LSA is MaxAge */
if (cost == OSPF_LS_INFINITY)
@@ -666,8 +856,22 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
zlog_debug ("Prefix has NU/LA bit set, ignore");
if (old)
ospf6_route_remove (old, table);
+
return;
}
+ /* Avoid infinite recursion if someone has maliciously announced an
+ Inter-Router LSA for an ABR
+ */
+ if (lsa->header->adv_router == router_lsa->router_id)
+ {
+ if (is_debug)
+ zlog_debug ("Ignorning Inter-Router LSA for an ABR (%s)",
+ buf);
+ if (old)
+ ospf6_route_remove (old, table);
+
+ return;
+ }
}
/* (4) if the routing table entry for the ABR does not exist */
@@ -718,7 +922,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
}
}
- /* (5),(6),(7) the path preference is handled by the sorting
+ /* (5),(6): the path preference is handled by the sorting
in the routing table. Always install the path by substituting
old route (if any). */
if (old)
@@ -739,12 +943,33 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
route->path.area_id = oa->area_id;
route->path.type = OSPF6_PATH_TYPE_INTER;
route->path.cost = abr_entry->path.cost + cost;
- for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
- route->nexthop[i] = abr_entry->nexthop[i];
- if (is_debug)
- zlog_debug ("Install route: %s", buf);
- ospf6_route_add (route, table);
+ ospf6_route_copy_nexthops (route, abr_entry);
+
+ /* (7) If the routes are identical, copy the next hops over to existing
+ route. ospf6's route table implementation will otherwise string both
+ routes, but keep the older one as the best route since the routes
+ are identical.
+ */
+ old = ospf6_route_lookup (&prefix, table);
+
+ if (old && (ospf6_route_cmp (route, old) == 0))
+ {
+ ospf6_route_merge_nexthops (old, route);
+ /* Update RIB/FIB */
+ if (table->hook_add)
+ (*table->hook_add) (old);
+
+ /* Delete new route */
+ ospf6_route_delete (route);
+ }
+ else
+ {
+ if (is_debug)
+ zlog_debug ("Install route: %s", buf);
+ /* ospf6_ia_add_nw_route (table, &prefix, route); */
+ ospf6_route_add (route, table);
+ }
}
void
@@ -752,21 +977,22 @@ ospf6_abr_examin_brouter (u_int32_t router_id)
{
struct ospf6_lsa *lsa;
struct ospf6_area *oa;
- struct listnode *node, *nnode;
u_int16_t type;
- for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
- {
- type = htons (OSPF6_LSTYPE_INTER_ROUTER);
- for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa;
- lsa = ospf6_lsdb_type_router_next (type, router_id, lsa))
- ospf6_abr_examin_summary (lsa, oa);
+ if (ospf6_is_router_abr (ospf6))
+ oa = ospf6->backbone;
+ else
+ oa = listgetdata(listhead(ospf6->area_list));
- type = htons (OSPF6_LSTYPE_INTER_PREFIX);
- for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa;
- lsa = ospf6_lsdb_type_router_next (type, router_id, lsa))
- ospf6_abr_examin_summary (lsa, oa);
- }
+ type = htons (OSPF6_LSTYPE_INTER_ROUTER);
+ for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa;
+ lsa = ospf6_lsdb_type_router_next (type, router_id, lsa))
+ ospf6_abr_examin_summary (lsa, oa);
+
+ type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+ for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa;
+ lsa = ospf6_lsdb_type_router_next (type, router_id, lsa))
+ ospf6_abr_examin_summary (lsa, oa);
}
void
@@ -786,6 +1012,21 @@ ospf6_abr_reimport (struct ospf6_area *oa)
ospf6_abr_examin_summary (lsa, oa);
}
+void
+ospf6_abr_prefix_resummarize (struct ospf6 *o)
+{
+ struct ospf6_route *route;
+
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_debug ("Re-examining Inter-Prefix Summaries");
+
+ for (route = ospf6_route_head (o->route_table); route;
+ route = ospf6_route_next (route))
+ ospf6_abr_originate_summary(route);
+
+ if (IS_OSPF6_DEBUG_ABR)
+ zlog_debug ("Finished re-examining Inter-Prefix Summaries");
+}
/* Display functions */
diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h
index e5e2660b..5bc2469e 100644
--- a/ospf6d/ospf6_abr.h
+++ b/ospf6d/ospf6_abr.h
@@ -59,17 +59,22 @@ struct ospf6_inter_router_lsa
{ (E)->metric &= htonl (0x00000000); \
(E)->metric |= htonl (0x00ffffff) & htonl (C); }
+#define OSPF6_ABR_RANGE_CLEAR_COST(range) (range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC)
+
extern int ospf6_is_router_abr (struct ospf6 *o);
extern void ospf6_abr_enable_area (struct ospf6_area *oa);
extern void ospf6_abr_disable_area (struct ospf6_area *oa);
-extern void ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
+extern int ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
struct ospf6_area *area);
extern void ospf6_abr_originate_summary (struct ospf6_route *route);
extern void ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa);
+extern void ospf6_abr_defaults_to_stub (struct ospf6 *);
extern void ospf6_abr_examin_brouter (u_int32_t router_id);
extern void ospf6_abr_reimport (struct ospf6_area *oa);
+extern void ospf6_abr_range_reset_cost (struct ospf6 *ospf6);
+extern void ospf6_abr_prefix_resummarize (struct ospf6 *ospf6);
extern int config_write_ospf6_debug_abr (struct vty *vty);
extern void install_element_ospf6_debug_abr (void);
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
index 9b704221..71787541 100644
--- a/ospf6d/ospf6_area.c
+++ b/ospf6d/ospf6_area.c
@@ -43,6 +43,7 @@
#include "ospf6_interface.h"
#include "ospf6_intra.h"
#include "ospf6_abr.h"
+#include "ospf6_asbr.h"
#include "ospf6d.h"
int
@@ -133,12 +134,82 @@ ospf6_area_route_hook_remove (struct ospf6_route *route)
ospf6_route_remove (copy, ospf6->route_table);
}
+static void
+ospf6_area_stub_update (struct ospf6_area *area)
+{
+
+ if (IS_AREA_STUB (area))
+ {
+ if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER))
+ zlog_debug ("Stubbing out area for if %s\n", area->name);
+ OSPF6_OPT_CLEAR (area->options, OSPF6_OPT_E);
+ }
+ else if (IS_AREA_ENABLED (area))
+ {
+ if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER))
+ zlog_debug ("Normal area for if %s\n", area->name);
+ OSPF6_OPT_SET (area->options, OSPF6_OPT_E);
+ ospf6_asbr_send_externals_to_area (area);
+ }
+
+ OSPF6_ROUTER_LSA_SCHEDULE(area);
+}
+
+static int
+ospf6_area_stub_set (struct ospf6 *ospf6, struct ospf6_area *area)
+{
+ if (!IS_AREA_STUB(area))
+ {
+ SET_FLAG (area->flag, OSPF6_AREA_STUB);
+ ospf6_area_stub_update (area);
+ }
+
+ return (1);
+}
+
+static void
+ospf6_area_stub_unset (struct ospf6 *ospf6, struct ospf6_area *area)
+{
+ if (IS_AREA_STUB (area))
+ {
+ UNSET_FLAG (area->flag, OSPF6_AREA_STUB);
+ ospf6_area_stub_update (area);
+ }
+}
+
+static void
+ospf6_area_no_summary_set (struct ospf6 *ospf6, struct ospf6_area *area)
+{
+ if (area)
+ {
+ if (!area->no_summary)
+ {
+ area->no_summary = 1;
+ ospf6_abr_range_reset_cost (ospf6);
+ ospf6_abr_prefix_resummarize (ospf6);
+ }
+ }
+}
+
+static void
+ospf6_area_no_summary_unset (struct ospf6 *ospf6, struct ospf6_area *area)
+{
+ if (area)
+ {
+ if (area->no_summary)
+ {
+ area->no_summary = 0;
+ ospf6_abr_range_reset_cost (ospf6);
+ ospf6_abr_prefix_resummarize (ospf6);
+ }
+ }
+}
+
/* Make new area structure */
struct ospf6_area *
ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
{
struct ospf6_area *oa;
- struct ospf6_route *route;
oa = XCALLOC (MTYPE_OSPF6_AREA, sizeof (struct ospf6_area));
@@ -160,6 +231,7 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
oa->range_table = OSPF6_ROUTE_TABLE_CREATE (AREA, PREFIX_RANGES);
oa->range_table->scope = oa;
+ bf_init(oa->range_table->idspace, 32);
oa->summary_prefix = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_PREFIXES);
oa->summary_prefix->scope = oa;
oa->summary_router = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_ROUTERS);
@@ -179,13 +251,16 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
OSPF6_OPT_SET (oa->options, OSPF6_OPT_E);
+ SET_FLAG (oa->flag, OSPF6_AREA_ACTIVE);
+ SET_FLAG (oa->flag, OSPF6_AREA_ENABLE);
+
oa->ospf6 = o;
listnode_add_sort (o->area_list, oa);
- /* import athoer area's routes as inter-area routes */
- for (route = ospf6_route_head (o->route_table); route;
- route = ospf6_route_next (route))
- ospf6_abr_originate_summary_to_area (route, oa);
+ if (area_id == OSPF_AREA_BACKBONE)
+ {
+ o->backbone = oa;
+ }
return oa;
}
@@ -196,10 +271,6 @@ ospf6_area_delete (struct ospf6_area *oa)
struct listnode *n;
struct ospf6_interface *oi;
- ospf6_route_table_delete (oa->range_table);
- ospf6_route_table_delete (oa->summary_prefix);
- ospf6_route_table_delete (oa->summary_router);
-
/* The ospf6_interface structs store configuration
* information which should not be lost/reset when
* deleting an area.
@@ -217,8 +288,9 @@ ospf6_area_delete (struct ospf6_area *oa)
ospf6_route_table_delete (oa->spf_table);
ospf6_route_table_delete (oa->route_table);
- THREAD_OFF (oa->thread_spf_calculation);
- THREAD_OFF (oa->thread_route_calculation);
+ ospf6_route_table_delete (oa->range_table);
+ ospf6_route_table_delete (oa->summary_prefix);
+ ospf6_route_table_delete (oa->summary_router);
listnode_delete (oa->ospf6->area_list, oa);
oa->ospf6 = NULL;
@@ -281,9 +353,6 @@ ospf6_area_disable (struct ospf6_area *oa)
ospf6_spf_table_finish(oa->spf_table);
ospf6_route_remove_all(oa->route_table);
- THREAD_OFF (oa->thread_spf_calculation);
- THREAD_OFF (oa->thread_route_calculation);
-
THREAD_OFF (oa->thread_router_lsa);
THREAD_OFF (oa->thread_intra_prefix_lsa);
}
@@ -294,16 +363,46 @@ ospf6_area_show (struct vty *vty, struct ospf6_area *oa)
{
struct listnode *i;
struct ospf6_interface *oi;
+ unsigned long result;
- vty_out (vty, " Area %s%s", oa->name, VNL);
+ if (!IS_AREA_STUB (oa))
+ vty_out (vty, " Area %s%s", oa->name, VNL);
+ else
+ {
+ if (oa->no_summary)
+ {
+ vty_out (vty, " Area %s[Stub, No Summary]%s", oa->name, VNL);
+ }
+ else
+ {
+ vty_out (vty, " Area %s[Stub]%s", oa->name, VNL);
+ }
+ }
vty_out (vty, " Number of Area scoped LSAs is %u%s",
oa->lsdb->count, VNL);
vty_out (vty, " Interface attached to this area:");
for (ALL_LIST_ELEMENTS_RO (oa->if_list, i, oi))
vty_out (vty, " %s", oi->interface->name);
-
vty_out (vty, "%s", VNL);
+
+ if (oa->ts_spf.tv_sec || oa->ts_spf.tv_usec)
+ {
+ result = timeval_elapsed (recent_relative_time (), oa->ts_spf);
+ if (result/TIMER_SECOND_MICRO > 0)
+ {
+ vty_out (vty, "SPF last executed %ld.%lds ago%s",
+ result/TIMER_SECOND_MICRO,
+ result%TIMER_SECOND_MICRO, VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out (vty, "SPF last executed %ldus ago%s",
+ result, VTY_NEWLINE);
+ }
+ }
+ else
+ vty_out (vty, "SPF has not been run%s", VTY_NEWLINE);
}
@@ -347,19 +446,16 @@ DEFUN (area_range,
struct ospf6_area *oa;
struct prefix prefix;
struct ospf6_route *range;
+ u_int32_t cost = OSPF_AREA_RANGE_COST_UNSPEC;
OSPF6_CMD_AREA_GET (argv[0], oa);
- argc--;
- argv++;
- ret = str2prefix (argv[0], &prefix);
+ ret = str2prefix (argv[1], &prefix);
if (ret != 1 || prefix.family != AF_INET6)
{
- vty_out (vty, "Malformed argument: %s%s", argv[0], VNL);
+ vty_out (vty, "Malformed argument: %s%s", argv[1], VNL);
return CMD_SUCCESS;
}
- argc--;
- argv++;
range = ospf6_route_lookup (&prefix, oa->range_table);
if (range == NULL)
@@ -367,23 +463,43 @@ DEFUN (area_range,
range = ospf6_route_create ();
range->type = OSPF6_DEST_TYPE_RANGE;
range->prefix = prefix;
+ range->path.area_id = oa->area_id;
+ range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC;
+ range->linkstate_id =
+ (u_int32_t) htonl(ospf6_new_range_ls_id (oa->range_table));
}
- if (argc)
+ if (argc > 2)
{
- if (! strcmp (argv[0], "not-advertise"))
- SET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
- else if (! strcmp (argv[0], "advertise"))
- UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
+ if (strcmp (argv[2], "not-advertise") == 0)
+ {
+ SET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
+ }
+ else if (strcmp (argv[2], "advertise") == 0)
+ {
+ UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
+ }
+ else
+ {
+ VTY_GET_INTEGER_RANGE ("cost", cost, argv[2], 0, OSPF_LS_INFINITY);
+ UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
+ }
}
- if (range->rnode)
+ range->path.u.cost_config = cost;
+
+ zlog_debug ("%s: for prefix %s, flag = %x\n", __func__, argv[1], range->flag);
+ if (range->rnode == NULL)
{
- vty_out (vty, "Range already defined: %s%s", argv[-1], VNL);
- return CMD_WARNING;
+ ospf6_route_add (range, oa->range_table);
+ }
+
+ if (ospf6_is_router_abr (ospf6))
+ {
+ /* Redo summaries if required */
+ ospf6_abr_prefix_resummarize (ospf6);
}
- ospf6_route_add (range, oa->range_table);
return CMD_SUCCESS;
}
@@ -396,6 +512,26 @@ ALIAS (area_range,
"Specify IPv6 prefix\n"
)
+ALIAS (area_range,
+ area_range_cost_cmd,
+ "area (A.B.C.D|<0-4294967295>) range X:X::X:X/M cost <0-16777215>",
+ "OSPF area parameters\n"
+ OSPF6_AREA_ID_STR
+ "Summarize routes matching address/mask (border routers only)\n"
+ "Area range prefix\n"
+ "User specified metric for this range\n"
+ "Advertised metric for this range\n")
+
+ALIAS (area_range,
+ area_range_advertise_cost_cmd,
+ "area (A.B.C.D|<0-4294967295>) range X:X::X:X/M advertise cost <0-16777215>",
+ "OSPF area parameters\n"
+ OSPF6_AREA_ID_STR
+ "Summarize routes matching address/mask (border routers only)\n"
+ "Area range prefix\n"
+ "User specified metric for this range\n"
+ "Advertised metric for this range\n")
+
DEFUN (no_area_range,
no_area_range_cmd,
"no area A.B.C.D range X:X::X:X/M",
@@ -408,7 +544,7 @@ DEFUN (no_area_range,
int ret;
struct ospf6_area *oa;
struct prefix prefix;
- struct ospf6_route *range;
+ struct ospf6_route *range, *route;
OSPF6_CMD_AREA_GET (argv[0], oa);
argc--;
@@ -428,6 +564,21 @@ DEFUN (no_area_range,
return CMD_SUCCESS;
}
+ if (ospf6_is_router_abr(oa->ospf6))
+ {
+ /* Blow away the aggregated LSA and route */
+ SET_FLAG (range->flag, OSPF6_ROUTE_REMOVE);
+
+ /* Redo summaries if required */
+ for (route = ospf6_route_head (ospf6->route_table); route;
+ route = ospf6_route_next (route))
+ ospf6_abr_originate_summary(route);
+
+ /* purge the old aggregated summary LSA */
+ ospf6_abr_originate_summary(range);
+ }
+ ospf6_release_range_ls_id(oa->range_table,
+ (u_int32_t) ntohl(range->linkstate_id));
ospf6_route_remove (range, oa->range_table);
return CMD_SUCCESS;
@@ -449,6 +600,13 @@ ospf6_area_config_write (struct vty *vty)
prefix2str (&range->prefix, buf, sizeof (buf));
vty_out (vty, " area %s range %s%s", oa->name, buf, VNL);
}
+ if (IS_AREA_STUB (oa))
+ {
+ if (oa->no_summary)
+ vty_out (vty, " area %s stub no-summary%s", oa->name, VNL);
+ else
+ vty_out (vty, " area %s stub%s", oa->name, VNL);
+ }
if (PREFIX_NAME_IN (oa))
vty_out (vty, " area %s filter-list prefix %s in%s",
oa->name, PREFIX_NAME_IN (oa), VNL);
@@ -666,6 +824,8 @@ DEFUN (show_ipv6_ospf6_spf_tree,
struct ospf6_route *route;
struct prefix prefix;
+ OSPF6_CMD_CHECK_RUNNING ();
+
ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix);
for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa))
@@ -701,6 +861,8 @@ DEFUN (show_ipv6_ospf6_area_spf_tree,
struct ospf6_route *route;
struct prefix prefix;
+ OSPF6_CMD_CHECK_RUNNING ();
+
ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix);
if (inet_pton (AF_INET, argv[0], &area_id) != 1)
@@ -747,6 +909,8 @@ DEFUN (show_ipv6_ospf6_simulate_spf_tree_root,
struct ospf6_route_table *spf_table;
unsigned char tmp_debug_ospf6_spf = 0;
+ OSPF6_CMD_CHECK_RUNNING ();
+
inet_pton (AF_INET, argv[0], &router_id);
ospf6_linkstate_prefix (router_id, htonl (0), &prefix);
@@ -786,6 +950,94 @@ DEFUN (show_ipv6_ospf6_simulate_spf_tree_root,
return CMD_SUCCESS;
}
+DEFUN (ospf6_area_stub,
+ ospf6_area_stub_cmd,
+ "area (A.B.C.D|<0-4294967295>) stub",
+ "OSPF6 area parameters\n"
+ "OSPF6 area ID in IP address format\n"
+ "OSPF6 area ID as a decimal value\n"
+ "Configure OSPF6 area as stub\n")
+{
+ struct ospf6_area *area;
+
+ OSPF6_CMD_AREA_GET(argv[0], area);
+
+ if (!ospf6_area_stub_set (ospf6, area))
+ {
+ vty_out (vty, "First deconfigure all virtual link through this area%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ospf6_area_no_summary_unset (ospf6, area);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_area_stub_no_summary,
+ ospf6_area_stub_no_summary_cmd,
+ "area (A.B.C.D|<0-4294967295>) stub no-summary",
+ "OSPF6 stub parameters\n"
+ "OSPF6 area ID in IP address format\n"
+ "OSPF6 area ID as a decimal value\n"
+ "Configure OSPF6 area as stub\n"
+ "Do not inject inter-area routes into stub\n")
+{
+ struct ospf6_area *area;
+
+ OSPF6_CMD_AREA_GET(argv[0], area);
+
+ if (!ospf6_area_stub_set (ospf6, area))
+ {
+ vty_out (vty, "First deconfigure all virtual link through this area%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ospf6_area_no_summary_set (ospf6, area);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_area_stub,
+ no_ospf6_area_stub_cmd,
+ "no area (A.B.C.D|<0-4294967295>) stub",
+ NO_STR
+ "OSPF6 area parameters\n"
+ "OSPF6 area ID in IP address format\n"
+ "OSPF6 area ID as a decimal value\n"
+ "Configure OSPF6 area as stub\n")
+{
+ struct ospf6_area *area;
+
+ OSPF6_CMD_AREA_GET(argv[0], area);
+
+ ospf6_area_stub_unset (ospf6, area);
+ ospf6_area_no_summary_unset (ospf6, area);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_area_stub_no_summary,
+ no_ospf6_area_stub_no_summary_cmd,
+ "no area (A.B.C.D|<0-4294967295>) stub no-summary",
+ NO_STR
+ "OSPF6 area parameters\n"
+ "OSPF6 area ID in IP address format\n"
+ "OSPF6 area ID as a decimal value\n"
+ "Configure OSPF6 area as stub\n"
+ "Do not inject inter-area routes into area\n")
+{
+ struct ospf6_area *area;
+
+ OSPF6_CMD_AREA_GET(argv[0], area);
+
+ ospf6_area_stub_unset (ospf6, area);
+ ospf6_area_no_summary_unset (ospf6, area);
+
+ return CMD_SUCCESS;
+}
+
void
ospf6_area_init (void)
{
@@ -799,7 +1051,14 @@ ospf6_area_init (void)
install_element (OSPF6_NODE, &area_range_cmd);
install_element (OSPF6_NODE, &area_range_advertise_cmd);
+ install_element (OSPF6_NODE, &area_range_cost_cmd);
+ install_element (OSPF6_NODE, &area_range_advertise_cost_cmd);
install_element (OSPF6_NODE, &no_area_range_cmd);
+ install_element (OSPF6_NODE, &ospf6_area_stub_no_summary_cmd);
+ install_element (OSPF6_NODE, &ospf6_area_stub_cmd);
+ install_element (OSPF6_NODE, &no_ospf6_area_stub_no_summary_cmd);
+ install_element (OSPF6_NODE, &no_ospf6_area_stub_cmd);
+
install_element (OSPF6_NODE, &area_import_list_cmd);
install_element (OSPF6_NODE, &no_area_import_list_cmd);
diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h
index 655967a9..3b752d94 100644
--- a/ospf6d/ospf6_area.h
+++ b/ospf6d/ospf6_area.h
@@ -46,6 +46,9 @@ struct ospf6_area
struct ospf6_route_table *summary_prefix;
struct ospf6_route_table *summary_router;
+ /* Area type */
+ int no_summary;
+
/* OSPF interface list */
struct list *if_list;
@@ -55,8 +58,6 @@ struct ospf6_area
struct ospf6_route_table *spf_table;
struct ospf6_route_table *route_table;
- struct thread *thread_spf_calculation;
- struct thread *thread_route_calculation;
u_int32_t spf_calculation; /* SPF calculation count */
struct thread *thread_router_lsa;
@@ -98,6 +99,8 @@ struct ospf6_area
#define PREFIX_NAME_OUT(A) (A)->plist_out.name
#define PREFIX_LIST_OUT(A) (A)->plist_out.list
+ /* Time stamps. */
+ struct timeval ts_spf; /* SPF calculation time stamp. */
};
#define OSPF6_AREA_ENABLE 0x01
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 6eca142d..136824bc 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -154,7 +154,6 @@ ospf6_asbr_lsa_add (struct ospf6_lsa *lsa)
struct prefix asbr_id;
struct ospf6_route *asbr_entry, *route;
char buf[64];
- int i;
external = (struct ospf6_as_external_lsa *)
OSPF6_LSA_HEADER_END (lsa->header);
@@ -213,18 +212,17 @@ ospf6_asbr_lsa_add (struct ospf6_lsa *lsa)
route->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
route->path.metric_type = 2;
route->path.cost = asbr_entry->path.cost;
- route->path.cost_e2 = OSPF6_ASBR_METRIC (external);
+ route->path.u.cost_e2 = OSPF6_ASBR_METRIC (external);
}
else
{
route->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
route->path.metric_type = 1;
route->path.cost = asbr_entry->path.cost + OSPF6_ASBR_METRIC (external);
- route->path.cost_e2 = 0;
+ route->path.u.cost_e2 = 0;
}
- for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
- ospf6_nexthop_copy (&route->nexthop[i], &asbr_entry->nexthop[i]);
+ ospf6_route_copy_nexthops (route, asbr_entry);
if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL))
{
@@ -240,7 +238,7 @@ ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa)
{
struct ospf6_as_external_lsa *external;
struct prefix prefix;
- struct ospf6_route *route;
+ struct ospf6_route *route, *nroute;
char buf[64];
external = (struct ospf6_as_external_lsa *)
@@ -274,8 +272,9 @@ ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa)
for (ospf6_route_lock (route);
route && ospf6_route_is_prefix (&prefix, route);
- route = ospf6_route_next (route))
+ route = nroute)
{
+ nroute = ospf6_route_next (route);
if (route->type != OSPF6_DEST_TYPE_NETWORK)
continue;
if (route->path.origin.type != lsa->header->type)
@@ -403,13 +402,29 @@ ospf6_asbr_redistribute_unset (int type)
if (info->type != type)
continue;
- ospf6_asbr_redistribute_remove (info->type, route->nexthop[0].ifindex,
- &route->prefix);
+ ospf6_asbr_redistribute_remove (info->type, 0, &route->prefix);
}
ospf6_asbr_routemap_unset (type);
}
+/* When an area is unstubified, flood all the external LSAs in the area */
+void
+ospf6_asbr_send_externals_to_area (struct ospf6_area *oa)
+{
+ struct ospf6_lsa *lsa;
+
+ for (lsa = ospf6_lsdb_head (oa->ospf6->lsdb); lsa;
+ lsa = ospf6_lsdb_next (lsa))
+ {
+ if (ntohs (lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL)
+ {
+ zlog_debug ("%s: Flooding AS-External LSA %s\n", __func__, lsa->name);
+ ospf6_flood_area (NULL, lsa, oa);
+ }
+ }
+}
+
void
ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix,
u_int nexthop_num, struct in6_addr *nexthop)
@@ -483,9 +498,11 @@ ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix,
}
info->type = type;
- match->nexthop[0].ifindex = ifindex;
+
if (nexthop_num && nexthop)
- memcpy (&match->nexthop[0].address, nexthop, sizeof (struct in6_addr));
+ ospf6_route_add_nexthop (match, ifindex, nexthop);
+ else
+ ospf6_route_add_nexthop (match, ifindex, NULL);
/* create/update binding in external_id_table */
prefix_id.family = AF_INET;
@@ -528,9 +545,10 @@ ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix,
}
info->type = type;
- route->nexthop[0].ifindex = ifindex;
if (nexthop_num && nexthop)
- memcpy (&route->nexthop[0].address, nexthop, sizeof (struct in6_addr));
+ ospf6_route_add_nexthop (route, ifindex, nexthop);
+ else
+ ospf6_route_add_nexthop (route, ifindex, NULL);
/* create/update binding in external_id_table */
prefix_id.family = AF_INET;
@@ -680,6 +698,15 @@ DEFUN (no_ospf6_redistribute,
return CMD_SUCCESS;
}
+ALIAS (no_ospf6_redistribute,
+ no_ospf6_redistribute_route_map_cmd,
+ "no redistribute " QUAGGA_REDIST_STR_OSPF6D " route-map WORD",
+ NO_STR
+ "Redistribute\n"
+ QUAGGA_REDIST_HELP_STR_OSPF6D
+ "Route map reference\n"
+ "Route map name\n")
+
int
ospf6_redistribute_config_write (struct vty *vty)
{
@@ -968,13 +995,13 @@ route_map_command_status (struct vty *vty, int ret)
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "Can't find rule.%s", VNL);
+ vty_out (vty, "OSPF6 Can't find rule.%s", VNL);
break;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "Argument is malformed.%s", VNL);
+ vty_out (vty, "OSPF6 Argument is malformed.%s", VNL);
break;
default:
- vty_out (vty, "route-map add set failed.%s", VNL);
+ vty_out (vty, "OSPF6 route-map add set failed.%s", VNL);
break;
}
return CMD_WARNING;
@@ -1089,17 +1116,30 @@ DEFUN (set_metric,
/* delete "set metric" */
DEFUN (no_set_metric,
no_set_metric_cmd,
- "no set metric <0-4294967295>",
+ "no set metric",
NO_STR
- "Set value\n"
- "Metric\n"
- "METRIC value\n")
+ SET_STR
+ "Metric value for destination routing protocol\n")
{
- int ret = route_map_delete_set ((struct route_map_index *) vty->index,
- "metric", argv[0]);
+ int ret = 0;
+
+ if (argc == 0)
+ ret = route_map_delete_set ((struct route_map_index *) vty->index,
+ "metric", NULL);
+ else
+ ret = route_map_delete_set ((struct route_map_index *) vty->index,
+ "metric", argv[0]);
return route_map_command_status (vty, ret);
}
+ALIAS (no_set_metric,
+ no_set_metric_val_cmd,
+ "no set metric <0-4294967295>",
+ NO_STR
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n")
+
/* add "set forwarding-address" */
DEFUN (ospf6_routemap_set_forwarding,
ospf6_routemap_set_forwarding_cmd,
@@ -1158,6 +1198,7 @@ ospf6_routemap_init (void)
/* ASE Metric */
install_element (RMAP_NODE, &set_metric_cmd);
install_element (RMAP_NODE, &no_set_metric_cmd);
+ install_element (RMAP_NODE, &no_set_metric_val_cmd);
/* ASE Metric */
install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
@@ -1256,13 +1297,13 @@ ospf6_asbr_external_route_show (struct vty *vty, struct ospf6_route *route)
inet_ntop (AF_INET6, &info->forwarding, forwarding, sizeof (forwarding));
else
snprintf (forwarding, sizeof (forwarding), ":: (ifindex %d)",
- route->nexthop[0].ifindex);
+ ospf6_route_get_first_nh_index (route));
vty_out (vty, "%c %-32s %-15s type-%d %5lu %s%s",
zebra_route_char(info->type),
prefix, id, route->path.metric_type,
(u_long) (route->path.metric_type == 2 ?
- route->path.cost_e2 : route->path.cost),
+ route->path.u.cost_e2 : route->path.cost),
forwarding, VNL);
}
@@ -1277,6 +1318,8 @@ DEFUN (show_ipv6_ospf6_redistribute,
{
struct ospf6_route *route;
+ OSPF6_CMD_CHECK_RUNNING ();
+
ospf6_redistribute_show_config (vty);
for (route = ospf6_route_head (ospf6->external_table); route;
@@ -1308,6 +1351,7 @@ ospf6_asbr_init (void)
install_element (OSPF6_NODE, &ospf6_redistribute_cmd);
install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd);
+ install_element (OSPF6_NODE, &no_ospf6_redistribute_route_map_cmd);
}
void
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index f3df90b1..645e8fd9 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -91,6 +91,7 @@ extern int ospf6_redistribute_config_write (struct vty *vty);
extern void ospf6_asbr_init (void);
extern void ospf6_asbr_redistribute_reset (void);
extern void ospf6_asbr_terminate (void);
+extern void ospf6_asbr_send_externals_to_area (struct ospf6_area *);
extern int config_write_ospf6_debug_asbr (struct vty *vty);
extern void install_element_ospf6_debug_asbr (void);
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index 815db7b7..82cf6a6c 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -422,7 +422,7 @@ ospf6_flood_interface (struct ospf6_neighbor *from,
}
}
-static void
+void
ospf6_flood_area (struct ospf6_neighbor *from,
struct ospf6_lsa *lsa, struct ospf6_area *oa)
{
@@ -892,6 +892,9 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
table calculation (replacing database copy) */
ospf6_install_lsa (new);
+ if (OSPF6_LSA_IS_MAXAGE (new))
+ ospf6_maxage_remove (from->ospf6_if->area->ospf6);
+
/* (e) possibly acknowledge */
ospf6_acknowledge_lsa (new, ismore_recent, from);
diff --git a/ospf6d/ospf6_flood.h b/ospf6d/ospf6_flood.h
index 3a6f300b..ba7fd25f 100644
--- a/ospf6d/ospf6_flood.h
+++ b/ospf6d/ospf6_flood.h
@@ -52,6 +52,8 @@ extern void ospf6_decrement_retrans_count (struct ospf6_lsa *lsa);
/* flooding & clear flooding */
extern void ospf6_flood_clear (struct ospf6_lsa *lsa);
extern void ospf6_flood (struct ospf6_neighbor *from, struct ospf6_lsa *lsa);
+extern void ospf6_flood_area (struct ospf6_neighbor *from,
+ struct ospf6_lsa *lsa, struct ospf6_area *oa);
/* receive & install */
extern void ospf6_receive_lsa (struct ospf6_neighbor *from,
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 26f68ac5..a52da720 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -392,6 +392,7 @@ ospf6_interface_connected_route_update (struct interface *ifp)
struct ospf6_route *route;
struct connected *c;
struct listnode *node, *nnode;
+ struct in6_addr nh_addr;
oi = (struct ospf6_interface *) ifp->info;
if (oi == NULL)
@@ -447,8 +448,8 @@ ospf6_interface_connected_route_update (struct interface *ifp)
route->path.area_id = oi->area->area_id;
route->path.type = OSPF6_PATH_TYPE_INTRA;
route->path.cost = oi->cost;
- route->nexthop[0].ifindex = oi->interface->ifindex;
- inet_pton (AF_INET6, "::1", &route->nexthop[0].address);
+ inet_pton (AF_INET6, "::1", &nh_addr);
+ ospf6_route_add_nexthop (route, oi->interface->ifindex, &nh_addr);
ospf6_route_add (route, oi->route_connected);
}
@@ -728,7 +729,18 @@ interface_up (struct thread *thread)
}
/* Join AllSPFRouters */
- ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP);
+ if (ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP) < 0)
+ {
+ if (oi->sso_try_cnt++ < OSPF6_INTERFACE_SSO_RETRY_MAX)
+ {
+ zlog_info("Scheduling %s for sso retry, trial count: %d",
+ oi->interface->name, oi->sso_try_cnt);
+ thread_add_timer (master, interface_up, oi,
+ OSPF6_INTERFACE_SSO_RETRY_INT);
+ }
+ return 0;
+ }
+ oi->sso_try_cnt = 0; /* Reset on success */
/* Update interface route */
ospf6_interface_connected_route_update (oi->interface);
@@ -1915,6 +1927,66 @@ ospf6_interface_init (void)
install_element (OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd);
}
+/* Clear the specified interface structure */
+static void
+ospf6_interface_clear (struct vty *vty, struct interface *ifp)
+{
+ struct ospf6_interface *oi;
+
+ if (!if_is_operative (ifp))
+ return;
+
+ if (ifp->info == NULL)
+ return;
+
+ oi = (struct ospf6_interface *) ifp->info;
+
+ if (IS_OSPF6_DEBUG_INTERFACE)
+ zlog_debug ("Interface %s: clear by reset", ifp->name);
+
+ /* Reset the interface */
+ thread_add_event (master, interface_down, oi, 0);
+ thread_add_event (master, interface_up, oi, 0);
+}
+
+/* Clear interface */
+DEFUN (clear_ipv6_ospf6_interface,
+ clear_ipv6_ospf6_interface_cmd,
+ "clear ipv6 ospf6 interface [IFNAME]",
+ CLEAR_STR
+ IP6_STR
+ OSPF6_STR
+ INTERFACE_STR
+ IFNAME_STR
+ )
+{
+ struct interface *ifp;
+ struct listnode *node;
+
+ if (argc == 0) /* Clear all the ospfv3 interfaces. */
+ {
+ for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+ ospf6_interface_clear (vty, ifp);
+ }
+ else /* Interface name is specified. */
+ {
+ if ((ifp = if_lookup_by_name (argv[0])) == NULL)
+ {
+ vty_out (vty, "No such Interface: %s%s", argv[0], VNL);
+ return CMD_WARNING;
+ }
+ ospf6_interface_clear (vty, ifp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+void
+install_element_ospf6_clear_interface (void)
+{
+ install_element (ENABLE_NODE, &clear_ipv6_ospf6_interface_cmd);
+}
+
DEFUN (debug_ospf6_interface,
debug_ospf6_interface_cmd,
"debug ospf6 interface",
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
index 95a377fb..dde589b8 100644
--- a/ospf6d/ospf6_interface.h
+++ b/ospf6d/ospf6_interface.h
@@ -78,6 +78,9 @@ struct ospf6_interface
/* Interface State */
u_char state;
+ /* Interface socket setting trial counter, resets on success */
+ u_char sso_try_cnt;
+
/* OSPF6 Interface flag */
char flag;
@@ -140,7 +143,8 @@ extern const char *ospf6_interface_state_str[];
#define OSPF6_INTERFACE_INSTANCE_ID 0
#define OSPF6_INTERFACE_BANDWIDTH 10000 /* Kbps */
#define OSPF6_REFERENCE_BANDWIDTH 100000 /* Kbps */
-
+#define OSPF6_INTERFACE_SSO_RETRY_INT 1
+#define OSPF6_INTERFACE_SSO_RETRY_MAX 5
/* Function Prototypes */
@@ -166,6 +170,8 @@ extern int neighbor_change (struct thread *);
extern void ospf6_interface_init (void);
+extern void install_element_ospf6_clear_interface (void);
+
extern int config_write_ospf6_debug_interface (struct vty *vty);
extern void install_element_ospf6_debug_interface (void);
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index 6606c96d..f2cade22 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -140,6 +140,31 @@ ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
return 0;
}
+static void
+ospf6_router_lsa_options_set (struct ospf6_area *oa,
+ struct ospf6_router_lsa *router_lsa)
+{
+ OSPF6_OPT_CLEAR_ALL (router_lsa->options);
+ memcpy (router_lsa->options, oa->options, 3);
+
+ if (ospf6_is_router_abr (ospf6))
+ SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
+ else
+ UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
+
+ if (!IS_AREA_STUB (oa) && ospf6_asbr_is_asbr (oa->ospf6))
+ {
+ SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
+ }
+ else
+ {
+ UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
+ }
+
+ UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V);
+ UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W);
+}
+
int
ospf6_router_is_stub_router (struct ospf6_lsa *lsa)
{
@@ -194,23 +219,7 @@ ospf6_router_lsa_originate (struct thread *thread)
router_lsa = (struct ospf6_router_lsa *)
((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
- OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6);
- OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E);
- OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC);
- OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N);
- OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R);
- OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC);
-
- if (ospf6_is_router_abr (ospf6))
- SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
- else
- UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
- if (ospf6_asbr_is_asbr (ospf6))
- SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
- else
- UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
- UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V);
- UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W);
+ ospf6_router_lsa_options_set (oa, router_lsa);
/* describe links for each interfaces */
lsdesc = (struct ospf6_router_lsdesc *)
@@ -228,7 +237,7 @@ ospf6_router_lsa_originate (struct thread *thread)
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on))
if (on->state == OSPF6_NEIGHBOR_FULL)
count++;
-
+
if (count == 0)
continue;
@@ -246,30 +255,6 @@ ospf6_router_lsa_originate (struct thread *thread)
return 0;
}
- /* Fill LSA Header */
- lsa_header->age = 0;
- lsa_header->type = htons (OSPF6_LSTYPE_ROUTER);
- lsa_header->id = htonl (link_state_id);
- lsa_header->adv_router = oa->ospf6->router_id;
- lsa_header->seqnum =
- ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id,
- lsa_header->adv_router, oa->lsdb);
- lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer);
-
- /* LSA checksum */
- ospf6_lsa_checksum (lsa_header);
-
- /* create LSA */
- lsa = ospf6_lsa_create (lsa_header);
-
- /* Originate */
- ospf6_lsa_originate_area (lsa, oa);
-
- /* Reset setting for consecutive origination */
- memset ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa),
- 0, (caddr_t) lsdesc - (caddr_t) router_lsa);
- lsdesc = (struct ospf6_router_lsdesc *)
- ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa));
link_state_id ++;
}
@@ -338,7 +323,7 @@ ospf6_router_lsa_originate (struct thread *thread)
lsa_header->adv_router = oa->ospf6->router_id;
lsa_header->seqnum =
ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id,
- lsa_header->adv_router, oa->lsdb);
+ lsa_header->adv_router, oa->lsdb);
lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer);
/* LSA checksum */
@@ -355,14 +340,25 @@ ospf6_router_lsa_originate (struct thread *thread)
/* Do premature-aging of rest, undesired Router-LSAs */
type = ntohs (OSPF6_LSTYPE_ROUTER);
router = oa->ospf6->router_id;
+ count = 0;
for (lsa = ospf6_lsdb_type_router_head (type, router, oa->lsdb); lsa;
lsa = ospf6_lsdb_type_router_next (type, router, lsa))
{
if (ntohl (lsa->header->id) < link_state_id)
continue;
ospf6_lsa_purge (lsa);
+ count++;
}
+ /*
+ * Waiting till the LSA is actually removed from the database to trigger
+ * SPF delays network convergence. Unlike IPv4, for an ABR, when all
+ * interfaces associated with an area are gone, triggering an SPF right away
+ * helps convergence with inter-area routes.
+ */
+ if (count && !link_state_id)
+ ospf6_spf_schedule (oa->ospf6, OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED);
+
return 0;
}
@@ -459,7 +455,15 @@ ospf6_network_lsa_originate (struct thread *thread)
if (oi->state != OSPF6_INTERFACE_DR)
{
if (old)
- ospf6_lsa_purge (old);
+ {
+ ospf6_lsa_purge (old);
+ /*
+ * Waiting till the LSA is actually removed from the database to
+ * trigger SPF delays network convergence.
+ */
+ ospf6_spf_schedule (oi->area->ospf6,
+ OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED);
+ }
return 0;
}
@@ -468,11 +472,11 @@ ospf6_network_lsa_originate (struct thread *thread)
/* If none of neighbor is adjacent to us */
count = 0;
-
+
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on))
if (on->state == OSPF6_NEIGHBOR_FULL)
count++;
-
+
if (count == 0)
{
if (IS_OSPF6_DEBUG_ORIGINATE (NETWORK))
@@ -1078,7 +1082,7 @@ ospf6_intra_prefix_lsa_originate_transit (struct thread *thread)
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on))
if (on->state == OSPF6_NEIGHBOR_FULL)
full_count++;
-
+
if (full_count == 0)
{
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
@@ -1214,7 +1218,7 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
struct prefix ls_prefix;
struct ospf6_route *route, *ls_entry;
- int i, prefix_num;
+ int prefix_num;
struct ospf6_prefix *op;
char *start, *current, *end;
char buf[64];
@@ -1275,14 +1279,13 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
break;
/* Appendix A.4.1.1 */
- if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU) ||
- CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_LA))
+ if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU))
{
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
{
ospf6_linkstate_prefix2str ((struct prefix *)OSPF6_PREFIX_BODY(op),
buf, sizeof (buf));
- zlog_debug ("%s: Skipping Prefix %s has NU/LA option set",
+ zlog_debug ("%s: Skipping Prefix %s has NU option set",
__func__, buf);
}
continue;
@@ -1310,13 +1313,11 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
{
ifp = if_lookup_prefix(&route->prefix);
if (ifp)
- route->nexthop[0].ifindex = ifp->ifindex;
+ ospf6_route_add_nexthop (route, ifp->ifindex, NULL);
}
else
{
- for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) &&
- i < OSPF6_MULTI_PATH_LIMIT; i++)
- ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]);
+ ospf6_route_copy_nexthops (route, ls_entry);
}
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
@@ -1339,7 +1340,7 @@ ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa)
struct ospf6_area *oa;
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
struct prefix prefix;
- struct ospf6_route *route;
+ struct ospf6_route *route, *nroute;
int prefix_num;
struct ospf6_prefix *op;
char *start, *current, *end;
@@ -1377,8 +1378,9 @@ ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa)
for (ospf6_route_lock (route);
route && ospf6_route_is_prefix (&prefix, route);
- route = ospf6_route_next (route))
+ route = nroute)
{
+ nroute = ospf6_route_next (route);
if (route->type != OSPF6_DEST_TYPE_NETWORK)
continue;
if (route->path.area_id != oa->area_id)
@@ -1408,7 +1410,7 @@ ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa)
void
ospf6_intra_route_calculation (struct ospf6_area *oa)
{
- struct ospf6_route *route;
+ struct ospf6_route *route, *nroute;
u_int16_t type;
struct ospf6_lsa *lsa;
void (*hook_add) (struct ospf6_route *) = NULL;
@@ -1435,8 +1437,9 @@ ospf6_intra_route_calculation (struct ospf6_area *oa)
oa->route_table->hook_remove = hook_remove;
for (route = ospf6_route_head (oa->route_table); route;
- route = ospf6_route_next (route))
+ route = nroute)
{
+ nroute = ospf6_route_next (route);
if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) &&
CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD))
{
@@ -1452,7 +1455,11 @@ ospf6_intra_route_calculation (struct ospf6_area *oa)
if (hook_add)
(*hook_add) (route);
}
-
+ else
+ {
+ /* Redo the summaries as things might have changed */
+ ospf6_abr_originate_summary (route);
+ }
route->flag = 0;
}
@@ -1510,13 +1517,13 @@ ospf6_brouter_debug_print (struct ospf6_route *brouter)
id, adv_router);
zlog_info (" options: %s router-bits: %s metric-type: %d metric: %d/%d",
options, capa, brouter->path.metric_type,
- brouter->path.cost, brouter->path.cost_e2);
+ brouter->path.cost, brouter->path.u.cost_e2);
}
void
ospf6_intra_brouter_calculation (struct ospf6_area *oa)
{
- struct ospf6_route *brouter, *copy;
+ struct ospf6_route *brouter, *nbrouter, *copy;
void (*hook_add) (struct ospf6_route *) = NULL;
void (*hook_remove) (struct ospf6_route *) = NULL;
u_int32_t brouter_id;
@@ -1538,7 +1545,7 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa)
inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name));
if (brouter->path.area_id != oa->area_id)
continue;
- brouter->flag = OSPF6_ROUTE_REMOVE;
+ SET_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE);
if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) ||
IS_OSPF6_DEBUG_ROUTE (MEMORY))
@@ -1585,8 +1592,9 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa)
oa->ospf6->brouter_table->hook_remove = hook_remove;
for (brouter = ospf6_route_head (oa->ospf6->brouter_table); brouter;
- brouter = ospf6_route_next (brouter))
+ brouter = nbrouter)
{
+ nbrouter = ospf6_route_next (brouter);
brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix);
inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name));
@@ -1631,9 +1639,11 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa)
IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id))
zlog_info ("brouter %s still exists via area %s",
brouter_name, oa->name);
+ /* But re-originate summaries */
+ ospf6_abr_originate_summary (brouter);
}
-
- brouter->flag = 0;
+ UNSET_FLAG (brouter->flag, OSPF6_ROUTE_ADD);
+ UNSET_FLAG (brouter->flag, OSPF6_ROUTE_CHANGE);
}
if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id))
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
index a85ca66d..aa64a772 100644
--- a/ospf6d/ospf6_lsa.h
+++ b/ospf6d/ospf6_lsa.h
@@ -141,6 +141,7 @@ struct ospf6_lsa
#define OSPF6_LSA_FLOODBACK 0x02
#define OSPF6_LSA_DUPLICATE 0x04
#define OSPF6_LSA_IMPLIEDACK 0x08
+#define OSPF6_LSA_UNAPPROVED 0x10
#define OSPF6_LSA_SEQWRAPPED 0x20
struct ospf6_lsa_handler
diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c
index b5a4587c..d103d23f 100644
--- a/ospf6d/ospf6_lsdb.c
+++ b/ospf6d/ospf6_lsdb.c
@@ -31,7 +31,9 @@
#include "ospf6_proto.h"
#include "ospf6_lsa.h"
#include "ospf6_lsdb.h"
+#include "ospf6_route.h"
#include "ospf6d.h"
+#include "bitfield.h"
struct ospf6_lsdb *
ospf6_lsdb_create (void *data)
@@ -545,21 +547,42 @@ ospf6_lsdb_show (struct vty *vty, enum ospf_lsdb_show_level level,
}
}
-/* Decide new Link State ID to originate.
- note return value is network byte order */
+/* Decide new Link State ID to originate for the range. */
+u_int32_t
+ospf6_new_range_ls_id (struct ospf6_route_table *range_table)
+{
+ u_int32_t id;
+
+ bf_assign_index(range_table->idspace, id);
+ return (id);
+}
+
+/* Release the LS ID back to the ID pool */
+void
+ospf6_release_range_ls_id (struct ospf6_route_table *range_table,
+ u_int32_t id)
+{
+ bf_release_index(range_table->idspace, id);
+}
+
u_int32_t
ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router,
struct ospf6_lsdb *lsdb)
{
struct ospf6_lsa *lsa;
- u_int32_t id = 1;
+ u_int32_t id = 1, tmp_id;
+ /* This routine is curently invoked only for Inter-Prefix LSAs for
+ * non-summarized routes (no area/range).
+ */
for (lsa = ospf6_lsdb_type_router_head (type, adv_router, lsdb); lsa;
lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa))
{
- if (ntohl (lsa->header->id) < id)
- continue;
- if (ntohl (lsa->header->id) > id)
+ tmp_id = ntohl (lsa->header->id);
+ if (tmp_id < id)
+ continue;
+
+ if (tmp_id > id)
{
ospf6_lsdb_lsa_unlock (lsa);
break;
diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h
index 425f6153..a8bfcae8 100644
--- a/ospf6d/ospf6_lsdb.h
+++ b/ospf6d/ospf6_lsdb.h
@@ -24,6 +24,7 @@
#include "prefix.h"
#include "table.h"
+#include "ospf6_route.h"
struct ospf6_lsdb
{
@@ -80,6 +81,9 @@ extern void ospf6_lsdb_show (struct vty *vty,
extern u_int32_t ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router,
struct ospf6_lsdb *lsdb);
+extern u_int32_t ospf6_new_range_ls_id (struct ospf6_route_table *range_table);
+extern void ospf6_release_range_ls_id (struct ospf6_route_table *range_table,
+ u_int32_t id);
extern u_int32_t ospf6_new_ls_seqnum (u_int16_t type, u_int32_t id,
u_int32_t adv_router,
struct ospf6_lsdb *lsdb);
diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c
index 1afe84a7..11cd195f 100644
--- a/ospf6d/ospf6_main.c
+++ b/ospf6d/ospf6_main.c
@@ -21,6 +21,7 @@
#include <zebra.h>
#include <lib/version.h>
+#include <stdlib.h>
#include "getopt.h"
#include "thread.h"
@@ -238,6 +239,9 @@ main (int argc, char *argv[], char *envp[])
/* Preserve name of myself. */
progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+ /* Seed random number for LSA ID */
+ srand (time(NULL));
+
/* Command line argument treatment. */
while (1)
{
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index d382f038..b0e94288 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -245,6 +245,7 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst,
char *p;
int twoway = 0;
int neighborchange = 0;
+ int neighbor_ifindex_change = 0;
int backupseen = 0;
hello = (struct ospf6_hello *)
@@ -285,10 +286,16 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst,
on->priority = hello->priority;
}
- /* always override neighbor's source address and ifindex */
- on->ifindex = ntohl (hello->interface_id);
+ /* Always override neighbor's source address */
memcpy (&on->linklocal_addr, src, sizeof (struct in6_addr));
+ /* Neighbor ifindex check */
+ if (on->ifindex != (ifindex_t)ntohl (hello->interface_id))
+ {
+ on->ifindex = ntohl (hello->interface_id);
+ neighbor_ifindex_change++;
+ }
+
/* TwoWay check */
for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello));
p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh);
@@ -348,6 +355,9 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst,
thread_add_event (master, backup_seen, oi, 0);
if (neighborchange)
thread_add_event (master, neighbor_change, oi, 0);
+
+ if (neighbor_ifindex_change && on->state == OSPF6_NEIGHBOR_FULL)
+ OSPF6_ROUTER_LSA_SCHEDULE (oi->area);
}
static void
diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c
index a7737502..53d6c359 100644
--- a/ospf6d/ospf6_network.c
+++ b/ospf6d/ospf6_network.c
@@ -112,7 +112,7 @@ ospf6_serv_sock (void)
}
/* ospf6 set socket option */
-void
+int
ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option)
{
struct ipv6_mreq mreq6;
@@ -125,8 +125,12 @@ ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option)
ret = setsockopt (ospf6_sock, IPPROTO_IPV6, option,
&mreq6, sizeof (mreq6));
if (ret < 0)
- zlog_err ("Network: setsockopt (%d) on ifindex %d failed: %s",
- option, ifindex, safe_strerror (errno));
+ {
+ zlog_err ("Network: setsockopt (%d) on ifindex %d failed: %s",
+ option, ifindex, safe_strerror (errno));
+ }
+
+ return ret;
}
static int
diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h
index f4b74faa..4fa28395 100644
--- a/ospf6d/ospf6_network.h
+++ b/ospf6d/ospf6_network.h
@@ -29,7 +29,7 @@ extern struct in6_addr allspfrouters6;
extern struct in6_addr alldrouters6;
extern int ospf6_serv_sock (void);
-extern void ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option);
+extern int ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option);
extern int ospf6_sendmsg (struct in6_addr *, struct in6_addr *,
ifindex_t *, struct iovec *);
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index 50575564..e53ff365 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -37,6 +37,7 @@
#include "ospf6_area.h"
#include "ospf6_interface.h"
#include "ospf6d.h"
+#include "ospf6_zebra.h"
unsigned char conf_debug_ospf6_route = 0;
@@ -173,18 +174,232 @@ const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] =
{ "??", "IA", "IE", "E1", "E2", };
+struct ospf6_nexthop *
+ospf6_nexthop_create (void)
+{
+ struct ospf6_nexthop *nh;
+
+ nh = XCALLOC (MTYPE_OSPF6_NEXTHOP, sizeof (struct ospf6_nexthop));
+ return nh;
+}
+
+void
+ospf6_nexthop_delete (struct ospf6_nexthop *nh)
+{
+ if (nh)
+ XFREE (MTYPE_OSPF6_NEXTHOP, nh);
+}
+
+void
+ospf6_free_nexthops (struct list *nh_list)
+{
+ struct ospf6_nexthop *nh;
+ struct listnode *node, *nnode;
+
+ if (nh_list)
+ {
+ for (ALL_LIST_ELEMENTS (nh_list, node, nnode, nh))
+ ospf6_nexthop_delete (nh);
+ }
+}
+
+void
+ospf6_clear_nexthops (struct list *nh_list)
+{
+ struct listnode *node;
+ struct ospf6_nexthop *nh;
+
+ if (nh_list)
+ {
+ for (ALL_LIST_ELEMENTS_RO (nh_list, node, nh))
+ ospf6_nexthop_clear (nh);
+ }
+}
+
+static struct ospf6_nexthop *
+ospf6_route_find_nexthop (struct list *nh_list, struct ospf6_nexthop *nh_match)
+{
+ struct listnode *node;
+ struct ospf6_nexthop *nh;
+
+ if (nh_list && nh_match)
+ {
+ for (ALL_LIST_ELEMENTS_RO (nh_list, node, nh))
+ {
+ if (ospf6_nexthop_is_same (nh, nh_match))
+ return (nh);
+ }
+ }
+
+ return (NULL);
+}
+
+void
+ospf6_copy_nexthops (struct list *dst, struct list *src)
+{
+ struct ospf6_nexthop *nh_new, *nh;
+ struct listnode *node;
+
+ if (dst && src)
+ {
+ for (ALL_LIST_ELEMENTS_RO (src, node, nh))
+ {
+ if (ospf6_nexthop_is_set (nh))
+ {
+ nh_new = ospf6_nexthop_create ();
+ ospf6_nexthop_copy (nh_new, nh);
+ listnode_add (dst, nh_new);
+ }
+ }
+ }
+}
+
+void
+ospf6_merge_nexthops (struct list *dst, struct list *src)
+{
+ struct listnode *node;
+ struct ospf6_nexthop *nh, *nh_new;
+
+ if (src && dst)
+ {
+ for (ALL_LIST_ELEMENTS_RO (src, node, nh))
+ {
+ if (!ospf6_route_find_nexthop (dst, nh))
+ {
+ nh_new = ospf6_nexthop_create ();
+ ospf6_nexthop_copy (nh_new, nh);
+ listnode_add (dst, nh_new);
+ }
+ }
+ }
+}
+
+int
+ospf6_route_cmp_nexthops (struct ospf6_route *a, struct ospf6_route *b)
+{
+ struct listnode *anode, *bnode;
+ struct ospf6_nexthop *anh, *bnh;
+
+ if (a && b)
+ {
+ if (listcount(a->nh_list) == listcount(b->nh_list))
+ {
+ for (ALL_LIST_ELEMENTS_RO (a->nh_list, anode, anh))
+ {
+ for (ALL_LIST_ELEMENTS_RO (b->nh_list, bnode, bnh))
+ if (!ospf6_nexthop_is_same (anh, bnh))
+ return (1);
+ }
+ return (0);
+ }
+ else
+ return (1);
+ }
+ /* One of the routes doesn't exist ? */
+ return (1);
+}
+
+int
+ospf6_num_nexthops (struct list *nh_list)
+{
+ return (listcount(nh_list));
+}
+
+void
+ospf6_add_nexthop (struct list *nh_list, int ifindex,
+ struct in6_addr *addr)
+{
+ struct ospf6_nexthop *nh;
+ struct ospf6_nexthop nh_match;
+
+ if (nh_list)
+ {
+ nh_match.ifindex = ifindex;
+ if (addr != NULL)
+ memcpy (&nh_match.address, addr, sizeof (struct in6_addr));
+ else
+ memset (&nh_match.address, 0, sizeof (struct in6_addr));
+
+ if (!ospf6_route_find_nexthop (nh_list, &nh_match))
+ {
+ nh = ospf6_nexthop_create();
+ ospf6_nexthop_copy (nh, &nh_match);
+ listnode_add (nh_list, nh);
+ }
+ }
+}
+
+void
+ospf6_route_zebra_copy_nexthops (struct ospf6_route *route,
+ ifindex_t *ifindexes,
+ struct in6_addr **nexthop_addr,
+ int entries)
+{
+ struct ospf6_nexthop *nh;
+ struct listnode *node;
+ char buf[64];
+ int i;
+
+ if (route)
+ {
+ i = 0;
+ for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh))
+ {
+ if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+ {
+ char ifname[IFNAMSIZ];
+ inet_ntop (AF_INET6, &nh->address, buf, sizeof (buf));
+ if (!if_indextoname(nh->ifindex, ifname))
+ strlcpy(ifname, "unknown", sizeof(ifname));
+ zlog_debug (" nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname,
+ nh->ifindex);
+ }
+ if (i < entries)
+ {
+ nexthop_addr[i] = &nh->address;
+ ifindexes[i] = nh->ifindex;
+ i++;
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+}
+
+int
+ospf6_route_get_first_nh_index (struct ospf6_route *route)
+{
+ struct ospf6_nexthop *nh;
+
+ if (route)
+ {
+ if ((nh = (struct ospf6_nexthop *)listhead (route->nh_list)))
+ return (nh->ifindex);
+ }
+
+ return (-1);
+}
+
struct ospf6_route *
ospf6_route_create (void)
{
struct ospf6_route *route;
route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route));
+ route->nh_list = list_new();
return route;
}
void
ospf6_route_delete (struct ospf6_route *route)
{
- XFREE (MTYPE_OSPF6_ROUTE, route);
+ if (route)
+ {
+ ospf6_free_nexthops (route->nh_list);
+ list_free (route->nh_list);
+ XFREE (MTYPE_OSPF6_ROUTE, route);
+ }
}
struct ospf6_route *
@@ -193,7 +408,15 @@ ospf6_route_copy (struct ospf6_route *route)
struct ospf6_route *new;
new = ospf6_route_create ();
- memcpy (new, route, sizeof (struct ospf6_route));
+ new->type = route->type;
+ memcpy (&new->prefix, &route->prefix, sizeof (struct prefix));
+ new->installed = route->installed;
+ new->changed = route->changed;
+ new->flag = route->flag;
+ new->route_option = route->route_option;
+ new->linkstate_id = route->linkstate_id;
+ new->path = route->path;
+ ospf6_copy_nexthops (new->nh_list, route->nh_list);
new->rnode = NULL;
new->prev = NULL;
new->next = NULL;
@@ -226,7 +449,7 @@ ospf6_route_unlock (struct ospf6_route *route)
/* Route compare function. If ra is more preferred, it returns
less than 0. If rb is more preferred returns greater than 0.
Otherwise (neither one is preferred), returns 0 */
-static int
+int
ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
{
assert (ospf6_route_is_same (ra, rb));
@@ -246,8 +469,8 @@ ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
{
- if (ra->path.cost_e2 != rb->path.cost_e2)
- return (ra->path.cost_e2 - rb->path.cost_e2);
+ if (ra->path.u.cost_e2 != rb->path.u.cost_e2)
+ return (ra->path.u.cost_e2 - rb->path.u.cost_e2);
}
else
{
@@ -620,7 +843,7 @@ ospf6_route_remove (struct ospf6_route *route,
if (node->info == route)
{
- if (route->next && ospf6_route_is_same (route->next, route))
+ if (route->next && route->next->rnode == node)
{
node->info = route->next;
SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST);
@@ -795,6 +1018,8 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route)
char duration[16];
const char *ifname;
struct timeval now, res;
+ struct listnode *node;
+ struct ospf6_nexthop *nh;
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
timersub (&now, &route->changed, &res);
@@ -810,27 +1035,26 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route)
else
prefix2str (&route->prefix, destination, sizeof (destination));
- /* nexthop */
- inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop,
- sizeof (nexthop));
- ifname = ifindex2ifname (route->nexthop[0].ifindex);
-
- vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
- (ospf6_route_is_best (route) ? '*' : ' '),
- OSPF6_DEST_TYPE_SUBSTR (route->type),
- OSPF6_PATH_TYPE_SUBSTR (route->path.type),
- destination, nexthop, IFNAMSIZ, ifname, duration, VNL);
-
- for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) &&
- i < OSPF6_MULTI_PATH_LIMIT; i++)
+ i = 0;
+ for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh))
{
/* nexthop */
- inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
+ inet_ntop (AF_INET6, &nh->address, nexthop,
sizeof (nexthop));
- ifname = ifindex2ifname (route->nexthop[i].ifindex);
-
- vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
- ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL);
+ ifname = ifindex2ifname (nh->ifindex);
+
+ if (!i)
+ {
+ vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
+ (ospf6_route_is_best (route) ? '*' : ' '),
+ OSPF6_DEST_TYPE_SUBSTR (route->type),
+ OSPF6_PATH_TYPE_SUBSTR (route->path.type),
+ destination, nexthop, IFNAMSIZ, ifname, duration, VNL);
+ i++;
+ }
+ else
+ vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
+ ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL);
}
}
@@ -842,7 +1066,8 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
char area_id[16], id[16], adv_router[16], capa[16], options[16];
struct timeval now, res;
char duration[16];
- int i;
+ struct listnode *node;
+ struct ospf6_nexthop *nh;
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
@@ -914,17 +1139,16 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
vty_out (vty, "Metric Type: %d%s", route->path.metric_type,
VNL);
vty_out (vty, "Metric: %d (%d)%s",
- route->path.cost, route->path.cost_e2, VNL);
+ route->path.cost, route->path.u.cost_e2, VNL);
/* Nexthops */
vty_out (vty, "Nexthop:%s", VNL);
- for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) &&
- i < OSPF6_MULTI_PATH_LIMIT; i++)
+ for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh))
{
/* nexthop */
- inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
+ inet_ntop (AF_INET6, &nh->address, nexthop,
sizeof (nexthop));
- ifname = ifindex2ifname (route->nexthop[i].ifindex);
+ ifname = ifindex2ifname (nh->ifindex);
vty_out (vty, " %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL);
}
vty_out (vty, "%s", VNL);
@@ -937,7 +1161,7 @@ ospf6_route_show_table_summary (struct vty *vty,
struct ospf6_route *route, *prev = NULL;
int i, pathtype[OSPF6_PATH_TYPE_MAX];
unsigned int number = 0;
- int nhinval = 0, ecmp = 0;
+ int nh_count =0 , nhinval = 0, ecmp = 0;
int alternative = 0, destination = 0;
for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
@@ -950,9 +1174,10 @@ ospf6_route_show_table_summary (struct vty *vty,
destination++;
else
alternative++;
- if (! ospf6_nexthop_is_set (&route->nexthop[0]))
+ nh_count = ospf6_num_nexthops (route->nh_list);
+ if (!nh_count)
nhinval++;
- else if (ospf6_nexthop_is_set (&route->nexthop[1]))
+ else if (nh_count > 1)
ecmp++;
pathtype[route->path.type]++;
number++;
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
index 2fb2c1d7..0836031b 100644
--- a/ospf6d/ospf6_route.h
+++ b/ospf6d/ospf6_route.h
@@ -96,7 +96,10 @@ struct ospf6_path
/* Cost */
u_int8_t metric_type;
u_int32_t cost;
- u_int32_t cost_e2;
+ union {
+ u_int32_t cost_e2;
+ u_int32_t cost_config;
+ } u;
};
#define OSPF6_PATH_TYPE_NONE 0
@@ -107,8 +110,13 @@ struct ospf6_path
#define OSPF6_PATH_TYPE_REDISTRIBUTE 5
#define OSPF6_PATH_TYPE_MAX 6
+#define OSPF6_PATH_SUBTYPE_DEFAULT_RT 1
+
+#define OSPF6_PATH_COST_IS_CONFIGURED(path) (path.u.cost_config != OSPF_AREA_RANGE_COST_UNSPEC)
+
#include "prefix.h"
#include "table.h"
+#include "bitfield.h"
struct ospf6_route
{
@@ -136,17 +144,18 @@ struct ospf6_route
/* flag */
u_char flag;
- /* path */
- struct ospf6_path path;
-
- /* nexthop */
- struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT];
-
/* route option */
void *route_option;
/* link state id for advertising */
u_int32_t linkstate_id;
+
+ /* path */
+ struct ospf6_path path;
+
+ /* nexthop */
+ struct list *nh_list;
+
};
#define OSPF6_DEST_TYPE_NONE 0
@@ -164,6 +173,7 @@ struct ospf6_route
#define OSPF6_ROUTE_ACTIVE_SUMMARY 0x10
#define OSPF6_ROUTE_DO_NOT_ADVERTISE 0x20
#define OSPF6_ROUTE_WAS_REMOVED 0x40
+#define OSPF6_ROUTE_BLACKHOLE_ADDED 0x80
struct ospf6_route_table
{
@@ -176,6 +186,8 @@ struct ospf6_route_table
u_int32_t count;
+ bitfield_t idspace;
+
/* hooks */
void (*hook_add) (struct ospf6_route *);
void (*hook_change) (struct ospf6_route *);
@@ -235,8 +247,8 @@ extern const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX];
((ra)->type == (rb)->type && \
memcmp (&(ra)->prefix, &(rb)->prefix, sizeof (struct prefix)) == 0 && \
memcmp (&(ra)->path, &(rb)->path, sizeof (struct ospf6_path)) == 0 && \
- memcmp (&(ra)->nexthop, &(rb)->nexthop, \
- sizeof (struct ospf6_nexthop) * OSPF6_MULTI_PATH_LIMIT) == 0)
+ ospf6_route_cmp_nexthops (ra, rb) == 0)
+
#define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST))
#define ospf6_linkstate_prefix_adv_router(x) \
@@ -255,9 +267,35 @@ extern void ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
extern void ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf,
int size);
+extern struct ospf6_nexthop *ospf6_nexthop_create (void);
+extern void ospf6_nexthop_delete (struct ospf6_nexthop *nh);
+extern void ospf6_free_nexthops (struct list *nh_list);
+extern void ospf6_clear_nexthops (struct list *nh_list);
+extern int ospf6_num_nexthops (struct list *nh_list);
+extern void ospf6_copy_nexthops (struct list *dst, struct list *src);
+extern void ospf6_merge_nexthops (struct list *dst, struct list *src);
+extern void ospf6_add_nexthop (struct list *nh_list, int ifindex,
+ struct in6_addr *addr);
+extern int ospf6_num_nexthops (struct list *nh_list);
+extern int ospf6_route_cmp_nexthops (struct ospf6_route *a,
+ struct ospf6_route *b);
+extern void ospf6_route_zebra_copy_nexthops (struct ospf6_route *route,
+ ifindex_t *ifindices,
+ struct in6_addr **addr,
+ int entries);
+extern int ospf6_route_get_first_nh_index (struct ospf6_route *route);
+
+/* Hide abstraction of nexthop implementation in route from outsiders */
+#define ospf6_route_copy_nexthops(dst, src) ospf6_copy_nexthops(dst->nh_list, src->nh_list)
+#define ospf6_route_merge_nexthops(dst, src) ospf6_merge_nexthops(dst->nh_list, src->nh_list)
+#define ospf6_route_num_nexthops(route) ospf6_num_nexthops(route->nh_list)
+#define ospf6_route_add_nexthop(route, ifindex, addr) \
+ ospf6_add_nexthop(route->nh_list, ifindex, addr)
+
extern struct ospf6_route *ospf6_route_create (void);
extern void ospf6_route_delete (struct ospf6_route *);
extern struct ospf6_route *ospf6_route_copy (struct ospf6_route *route);
+extern int ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb);
extern void ospf6_route_lock (struct ospf6_route *route);
extern void ospf6_route_unlock (struct ospf6_route *route);
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
index 858398eb..c2cee36d 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -36,6 +36,8 @@
#include "ospf6_lsdb.h"
#include "ospf6_route.h"
#include "ospf6_area.h"
+#include "ospf6_proto.h"
+#include "ospf6_abr.h"
#include "ospf6_spf.h"
#include "ospf6_intra.h"
#include "ospf6_interface.h"
@@ -44,6 +46,41 @@
unsigned char conf_debug_ospf6_spf = 0;
+static void
+ospf6_spf_copy_nexthops_to_route (struct ospf6_route *rt,
+ struct ospf6_vertex *v)
+{
+ if (rt && v)
+ ospf6_copy_nexthops (rt->nh_list, v->nh_list);
+}
+
+static void
+ospf6_spf_merge_nexthops_to_route (struct ospf6_route *rt,
+ struct ospf6_vertex *v)
+{
+ if (rt && v)
+ ospf6_merge_nexthops (rt->nh_list, v->nh_list);
+}
+
+static unsigned int
+ospf6_spf_get_ifindex_from_nh (struct ospf6_vertex *v)
+{
+ struct ospf6_nexthop *nh;
+ struct listnode *node;
+
+ if (v)
+ {
+ node = listhead(v->nh_list);
+ if (node)
+ {
+ nh = listgetdata (node);
+ if (nh)
+ return (nh->ifindex);
+ }
+ }
+ return 0;
+}
+
static int
ospf6_vertex_cmp (void *a, void *b)
{
@@ -77,7 +114,6 @@ static struct ospf6_vertex *
ospf6_vertex_create (struct ospf6_lsa *lsa)
{
struct ospf6_vertex *v;
- int i;
v = (struct ospf6_vertex *)
XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
@@ -97,6 +133,10 @@ ospf6_vertex_create (struct ospf6_lsa *lsa)
/* name */
ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
+ if (IS_OSPF6_DEBUG_SPF (PROCESS))
+ zlog_debug ("%s: Creating vertex %s of type %s", __func__, v->name,
+ ((ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER) ? "Router" : "N/W"));
+
/* Associated LSA */
v->lsa = lsa;
@@ -106,8 +146,7 @@ ospf6_vertex_create (struct ospf6_lsa *lsa)
v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2);
v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3);
- for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
- ospf6_nexthop_clear (&v->nexthop[i]);
+ v->nh_list = list_new();
v->parent = NULL;
v->child_list = list_new ();
@@ -235,11 +274,14 @@ ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
char buf[64];
assert (VERTEX_IS_TYPE (ROUTER, w));
- ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex :
- /* v is the local router & the interface_id is a local ifindex */
- (ifindex_t) ROUTER_LSDESC_GET_IFID (lsdesc));
- assert (ifindex >= 0);
-
+ ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? ospf6_spf_get_ifindex_from_nh (v) :
+ ROUTER_LSDESC_GET_IFID (lsdesc));
+ if (ifindex == 0)
+ {
+ zlog_err ("No nexthop ifindex at vertex %s", v->name);
+ return;
+ }
+
oi = ospf6_interface_lookup_by_ifindex (ifindex);
if (oi == NULL)
{
@@ -268,13 +310,8 @@ ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
zlog_debug (" nexthop %s from %s", buf, lsa->name);
}
- if (i < OSPF6_MULTI_PATH_LIMIT)
- {
- memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr,
- sizeof (struct in6_addr));
- w->nexthop[i].ifindex = ifindex;
- i++;
- }
+ ospf6_add_nexthop (w->nh_list, ifindex, &link_lsa->linklocal_addr);
+ i++;
}
if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS))
@@ -285,8 +322,7 @@ static int
ospf6_spf_install (struct ospf6_vertex *v,
struct ospf6_route_table *result_table)
{
- struct ospf6_route *route;
- int i, j;
+ struct ospf6_route *route, *parent_route;
struct ospf6_vertex *prev;
if (IS_OSPF6_DEBUG_SPF (PROCESS))
@@ -307,23 +343,7 @@ ospf6_spf_install (struct ospf6_vertex *v,
if (IS_OSPF6_DEBUG_SPF (PROCESS))
zlog_debug (" another path found, merge");
- for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
- i < OSPF6_MULTI_PATH_LIMIT; i++)
- {
- for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
- {
- if (ospf6_nexthop_is_set (&route->nexthop[j]))
- {
- if (ospf6_nexthop_is_same (&route->nexthop[j],
- &v->nexthop[i]))
- break;
- else
- continue;
- }
- ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
- break;
- }
- }
+ ospf6_spf_merge_nexthops_to_route (route, v);
prev = (struct ospf6_vertex *) route->route_option;
assert (prev->hops <= v->hops);
@@ -350,15 +370,35 @@ ospf6_spf_install (struct ospf6_vertex *v,
route->path.origin.adv_router = v->lsa->header->adv_router;
route->path.metric_type = 1;
route->path.cost = v->cost;
- route->path.cost_e2 = v->hops;
+ route->path.u.cost_e2 = v->hops;
route->path.router_bits = v->capability;
route->path.options[0] = v->options[0];
route->path.options[1] = v->options[1];
route->path.options[2] = v->options[2];
- for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
- i < OSPF6_MULTI_PATH_LIMIT; i++)
- ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]);
+ ospf6_spf_copy_nexthops_to_route (route, v);
+
+ /*
+ * The SPF logic implementation does not transfer the multipathing properties
+ * of a parent to a child node. Thus if there was a 3-way multipath to a
+ * node's parent and a single hop from the parent to the child, the logic of
+ * creating new vertices and computing next hops prevents there from being 3
+ * paths to the child node. This is primarily because the resolution of
+ * multipath is done in this routine, not in the main spf loop.
+ *
+ * The following logic addresses that problem by merging the parent's nexthop
+ * information with the child's, if the parent is not the root of the tree.
+ * This is based on the assumption that before a node's route is installed,
+ * its parent's route's nexthops have already been installed.
+ */
+ if (v->parent && v->parent->hops)
+ {
+ parent_route = ospf6_route_lookup (&v->parent->vertex_id, result_table);
+ if (parent_route)
+ {
+ ospf6_route_merge_nexthops (route, parent_route);
+ }
+ }
if (v->parent)
listnode_add_sort (v->parent->child_list, v);
@@ -371,11 +411,12 @@ ospf6_spf_install (struct ospf6_vertex *v,
void
ospf6_spf_table_finish (struct ospf6_route_table *result_table)
{
- struct ospf6_route *route;
+ struct ospf6_route *route, *nroute;
struct ospf6_vertex *v;
for (route = ospf6_route_head (result_table); route;
- route = ospf6_route_next (route))
+ route = nroute)
{
+ nroute = ospf6_route_next (route);
v = (struct ospf6_vertex *) route->route_option;
ospf6_vertex_delete (v);
ospf6_route_remove (route, result_table);
@@ -421,19 +462,24 @@ ospf6_spf_calculation (u_int32_t router_id,
{
struct pqueue *candidate_list;
struct ospf6_vertex *root, *v, *w;
- int i;
int size;
caddr_t lsdesc;
struct ospf6_lsa *lsa;
+ struct in6_addr address;
ospf6_spf_table_finish (result_table);
/* Install the calculating router itself as the root of the SPF tree */
/* construct root vertex */
lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
- router_id, oa->lsdb);
+ router_id, oa->lsdb_self);
if (lsa == NULL)
- return;
+ {
+ if (IS_OSPF6_DEBUG_SPF (PROCESS))
+ zlog_debug ("%s: No router LSA for area %s\n",
+ __func__, oa->name);
+ return;
+ }
/* initialize */
candidate_list = pqueue_create ();
@@ -443,8 +489,7 @@ ospf6_spf_calculation (u_int32_t router_id,
root->area = oa;
root->cost = 0;
root->hops = 0;
- root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */
- inet_pton (AF_INET6, "::1", &root->nexthop[0].address);
+ inet_pton (AF_INET6, "::1", &address);
/* Actually insert root to the candidate-list as the only candidate */
pqueue_enqueue (root, candidate_list);
@@ -475,6 +520,9 @@ ospf6_spf_calculation (u_int32_t router_id,
if (lsa == NULL)
continue;
+ if (OSPF6_LSA_IS_MAXAGE (lsa))
+ continue;
+
if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
continue;
@@ -494,14 +542,12 @@ ospf6_spf_calculation (u_int32_t router_id,
/* nexthop calculation */
if (w->hops == 0)
- w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
+ ospf6_add_nexthop (w->nh_list, ROUTER_LSDESC_GET_IFID (lsdesc), NULL);
else if (w->hops == 1 && v->hops == 0)
ospf6_nexthop_calc (w, v, lsdesc);
else
{
- for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
- i < OSPF6_MULTI_PATH_LIMIT; i++)
- ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
+ ospf6_copy_nexthops (w->nh_list, v->nh_list);
}
/* add new candidate to the candidate_list */
@@ -549,7 +595,6 @@ ospf6_spf_calculation_thread (struct thread *t)
struct ospf6 *ospf6;
struct timeval start, end, runtime;
struct listnode *node;
- struct ospf6_route *route;
int areas_processed = 0;
char rbuf[32];
@@ -559,6 +604,9 @@ ospf6_spf_calculation_thread (struct thread *t)
/* execute SPF calculation */
quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
+ if (ospf6_is_router_abr (ospf6))
+ ospf6_abr_range_reset_cost (ospf6);
+
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa))
{
@@ -592,10 +640,8 @@ ospf6_spf_calculation_thread (struct thread *t)
areas_processed++;
}
- /* Redo summaries if required */
- for (route = ospf6_route_head (ospf6->route_table); route;
- route = ospf6_route_next (route))
- ospf6_abr_originate_summary(route);
+ if (ospf6_is_router_abr (ospf6))
+ ospf6_abr_defaults_to_stub (ospf6);
quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
timersub (&end, &start, &runtime);
diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h
index b3481dc3..7bf525d6 100644
--- a/ospf6d/ospf6_spf.h
+++ b/ospf6d/ospf6_spf.h
@@ -60,9 +60,6 @@ struct ospf6_vertex
/* Router hops to this node */
u_char hops;
- /* nexthops to this node */
- struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT];
-
/* capability bits */
u_char capability;
@@ -72,6 +69,9 @@ struct ospf6_vertex
/* For tree display */
struct ospf6_vertex *parent;
struct list *child_list;
+
+ /* nexthops to this node */
+ struct list *nh_list;
};
#define OSPF6_VERTEX_TYPE_ROUTER 0x01
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 7fffba83..798a1cda 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -92,6 +92,7 @@ ospf6_top_route_hook_add (struct ospf6_route *route)
static void
ospf6_top_route_hook_remove (struct ospf6_route *route)
{
+ route->flag |= OSPF6_ROUTE_REMOVE;
ospf6_abr_originate_summary (route);
ospf6_zebra_route_update_remove (route);
}
@@ -107,6 +108,7 @@ ospf6_top_brouter_hook_add (struct ospf6_route *route)
static void
ospf6_top_brouter_hook_remove (struct ospf6_route *route)
{
+ route->flag |= OSPF6_ROUTE_REMOVE;
ospf6_abr_examin_brouter (ADV_ROUTER_IN_PREFIX (&route->prefix));
ospf6_asbr_lsentry_remove (route);
ospf6_abr_originate_summary (route);
@@ -721,6 +723,8 @@ DEFUN (show_ipv6_ospf6_route,
ROUTE_STR
)
{
+ OSPF6_CMD_CHECK_RUNNING ();
+
ospf6_route_table_show (vty, argc, argv, ospf6->route_table);
return CMD_SUCCESS;
}
@@ -752,6 +756,8 @@ DEFUN (show_ipv6_ospf6_route_match,
const char *sargv[CMD_ARGC_MAX];
int i, sargc;
+ OSPF6_CMD_CHECK_RUNNING ();
+
/* copy argv to sargv and then append "match" */
for (i = 0; i < argc; i++)
sargv[i] = argv[i];
@@ -786,6 +792,8 @@ DEFUN (show_ipv6_ospf6_route_match_detail,
sargv[sargc++] = "detail";
sargv[sargc] = NULL;
+ OSPF6_CMD_CHECK_RUNNING ();
+
ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table);
return CMD_SUCCESS;
}
@@ -850,6 +858,8 @@ DEFUN (show_ipv6_ospf6_route_type_detail,
sargv[sargc++] = "detail";
sargv[sargc] = NULL;
+ OSPF6_CMD_CHECK_RUNNING ();
+
ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table);
return CMD_SUCCESS;
}
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index c8f20d86..5f3b66a2 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -371,7 +371,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request)
int nhcount;
struct in6_addr **nexthops;
ifindex_t *ifindexes;
- int i, ret = 0;
+ int ret = 0;
struct prefix_ipv6 *dest;
if (IS_OSPF6_DEBUG_ZEBRA (SEND))
@@ -417,11 +417,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request)
return;
}
- nhcount = 0;
- for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
- if (ospf6_nexthop_is_set (&request->nexthop[i]))
- nhcount++;
-
+ nhcount = ospf6_route_num_nexthops (request);
if (nhcount == 0)
{
if (IS_OSPF6_DEBUG_ZEBRA (SEND))
@@ -448,20 +444,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request)
return;
}
- for (i = 0; i < nhcount; i++)
- {
- if (IS_OSPF6_DEBUG_ZEBRA (SEND))
- {
- const char *ifname;
- inet_ntop (AF_INET6, &request->nexthop[i].address,
- buf, sizeof (buf));
- ifname = ifindex2ifname (request->nexthop[i].ifindex);
- zlog_debug (" nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname,
- request->nexthop[i].ifindex);
- }
- nexthops[i] = &request->nexthop[i].address;
- ifindexes[i] = request->nexthop[i].ifindex;
- }
+ ospf6_route_zebra_copy_nexthops (request, ifindexes, nexthops, nhcount);
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_OSPF6;
@@ -476,7 +459,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request)
api.ifindex = ifindexes;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = (request->path.metric_type == 2 ?
- request->path.cost_e2 : request->path.cost);
+ request->path.u.cost_e2 : request->path.cost);
dest = (struct prefix_ipv6 *) &request->prefix;
if (type == REM)
@@ -518,6 +501,90 @@ ospf6_zebra_route_update_remove (struct ospf6_route *request)
ospf6_zebra_route_update (REM, request);
}
+void
+ospf6_zebra_add_discard (struct ospf6_route *request)
+{
+ struct zapi_ipv6 api;
+ char buf[INET6_ADDRSTRLEN];
+ struct prefix_ipv6 *dest;
+
+ if (zclient->redist[ZEBRA_ROUTE_OSPF6])
+ {
+ if (!CHECK_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED))
+ {
+ api.type = ZEBRA_ROUTE_OSPF6;
+ api.flags = ZEBRA_FLAG_BLACKHOLE;
+ api.message = 0;
+ api.safi = SAFI_UNICAST;
+ SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+ api.nexthop_num = 0;
+ api.ifindex_num = 0;
+
+ dest = (struct prefix_ipv6 *) &request->prefix;
+
+ zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, dest, &api);
+
+ if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+ zlog_debug ("Zebra: Route add discard %s/%d",
+ inet_ntop (AF_INET6, &dest->prefix,
+ buf, INET6_ADDRSTRLEN),
+ dest->prefixlen);
+ SET_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED);
+ }
+ else
+ {
+ dest = (struct prefix_ipv6 *) &request->prefix;
+
+ if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+ zlog_debug ("Zebra: Blackhole route present already %s/%d",
+ inet_ntop (AF_INET6, &dest->prefix,
+ buf, INET6_ADDRSTRLEN),
+ dest->prefixlen);
+ }
+ }
+}
+
+void
+ospf6_zebra_delete_discard (struct ospf6_route *request)
+{
+ struct zapi_ipv6 api;
+ char buf[INET6_ADDRSTRLEN];
+ struct prefix_ipv6 *dest;
+
+ if (zclient->redist[ZEBRA_ROUTE_OSPF6])
+ {
+ if (CHECK_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED))
+ {
+
+ api.type = ZEBRA_ROUTE_OSPF6;
+ api.flags = ZEBRA_FLAG_BLACKHOLE;
+ api.message = 0;
+ api.safi = SAFI_UNICAST;
+ SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+ api.nexthop_num = 0;
+ api.ifindex_num = 0;
+
+ dest = (struct prefix_ipv6 *) &request->prefix;
+
+ zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, dest, &api);
+
+ if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+ zlog_debug ("Zebra: Route delete discard %s/%d",
+ inet_ntop (AF_INET6, &dest->prefix, buf,
+ INET6_ADDRSTRLEN), dest->prefixlen);
+ UNSET_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED);
+ }
+ else
+ {
+ dest = (struct prefix_ipv6 *) &request->prefix;
+ if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+ zlog_debug ("Zebra: Blackhole route already deleted %s/%d",
+ inet_ntop (AF_INET6, &dest->prefix, buf,
+ INET6_ADDRSTRLEN), dest->prefixlen);
+ }
+ }
+}
+
DEFUN (redistribute_ospf6,
redistribute_ospf6_cmd,
"redistribute ospf6",
diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h
index 05694d39..4d028182 100644
--- a/ospf6d/ospf6_zebra.h
+++ b/ospf6d/ospf6_zebra.h
@@ -45,6 +45,8 @@ extern void ospf6_zebra_no_redistribute (int);
#define ospf6_zebra_is_redistribute(type) \
vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)
extern void ospf6_zebra_init(struct thread_master *);
+extern void ospf6_zebra_add_discard (struct ospf6_route *request);
+extern void ospf6_zebra_delete_discard (struct ospf6_route *request);
extern int config_write_ospf6_debug_zebra (struct vty *vty);
extern void install_element_ospf6_debug_zebra (void);
diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c
index c2baa314..c929dfff 100644
--- a/ospf6d/ospf6d.c
+++ b/ospf6d/ospf6d.c
@@ -1690,6 +1690,8 @@ DEFUN (show_ipv6_ospf6_linkstate,
struct listnode *node;
struct ospf6_area *oa;
+ OSPF6_CMD_CHECK_RUNNING ();
+
for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa))
{
vty_out (vty, "%s SPF Result in Area %s%s%s",
@@ -1738,6 +1740,8 @@ DEFUN (show_ipv6_ospf6_linkstate_detail,
struct listnode *node;
struct ospf6_area *oa;
+ OSPF6_CMD_CHECK_RUNNING ();
+
/* copy argv to sargv and then append "detail" */
for (i = 0; i < argc; i++)
sargv[i] = argv[i];
@@ -1790,6 +1794,8 @@ ospf6_init (void)
install_element_ospf6_debug_abr ();
install_element_ospf6_debug_flood ();
+ install_element_ospf6_clear_interface ();
+
install_element (VIEW_NODE, &show_version_ospf6_cmd);
install_element (ENABLE_NODE, &show_version_ospf6_cmd);
@@ -1892,6 +1898,8 @@ ospf6_init (void)
void
ospf6_clean (void)
{
+ if (!ospf6)
+ return;
if (ospf6->route_table)
ospf6_route_remove_all (ospf6->route_table);
if (ospf6->brouter_table)
diff --git a/ospfd/ospf_abr.h b/ospfd/ospf_abr.h
index e367e447..2a728936 100644
--- a/ospfd/ospf_abr.h
+++ b/ospfd/ospf_abr.h
@@ -52,7 +52,6 @@ struct ospf_area_range
/* Configured range cost. */
u_int32_t cost_config;
-#define OSPF_AREA_RANGE_COST_UNSPEC -1U
};
/* Prototypes. */
diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c
index 122e70b4..4b536903 100644
--- a/ospfd/ospf_asbr.c
+++ b/ospfd/ospf_asbr.c
@@ -135,7 +135,8 @@ ospf_route_map_set_compare (struct route_map_set_values *values1,
/* Add an External info for AS-external-LSA. */
struct external_info *
ospf_external_info_add (u_char type, struct prefix_ipv4 p,
- ifindex_t ifindex, struct in_addr nexthop)
+ ifindex_t ifindex, struct in_addr nexthop,
+ u_short tag)
{
struct external_info *new;
struct route_node *rn;
@@ -162,7 +163,7 @@ ospf_external_info_add (u_char type, struct prefix_ipv4 p,
new->p = p;
new->ifindex = ifindex;
new->nexthop = nexthop;
- new->tag = 0;
+ new->tag = tag;
if (rn)
rn->info = new;
diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h
index d151cb14..2709a6c0 100644
--- a/ospfd/ospf_asbr.h
+++ b/ospfd/ospf_asbr.h
@@ -62,7 +62,8 @@ extern int ospf_route_map_set_compare (struct route_map_set_values *,
extern struct external_info *ospf_external_info_add (u_char,
struct prefix_ipv4,
ifindex_t,
- struct in_addr);
+ struct in_addr,
+ u_short);
extern void ospf_external_info_delete (u_char, struct prefix_ipv4);
extern struct external_info *ospf_external_info_lookup (u_char,
struct prefix_ipv4 *);
diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c
index fb43210a..68792e21 100644
--- a/ospfd/ospf_dump.c
+++ b/ospfd/ospf_dump.c
@@ -204,7 +204,7 @@ ospf_if_name_string (struct ospf_interface *oi)
static char buf[OSPF_IF_STRING_MAXLEN] = "";
u_int32_t ifaddr;
- if (!oi)
+ if (!oi || !oi->address)
return "inactive";
if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index f4242b0b..fd3e239f 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -347,7 +347,12 @@ ospf_if_is_configured (struct ospf *ospf, struct in_addr *address)
for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi))
if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
{
- if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+ if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
+ {
+ if (htonl(oi->ifp->ifindex) == address->s_addr)
+ return oi;
+ }
+ else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
{
/* special leniency: match if addr is anywhere on peer subnet */
if (prefix_match(CONNECTED_PREFIX(oi->connected),
@@ -471,8 +476,10 @@ ospf_if_lookup_recv_if (struct ospf *ospf, struct in_addr src,
if (if_is_loopback (oi->ifp))
continue;
- if (prefix_match (CONNECTED_PREFIX(oi->connected),
- (struct prefix *) &addr))
+ if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
+ match = oi;
+ else if (prefix_match (CONNECTED_PREFIX(oi->connected),
+ (struct prefix *) &addr))
{
if ( (match == NULL) ||
(match->address->prefixlen < oi->address->prefixlen)
@@ -866,6 +873,11 @@ ospf_vl_new (struct ospf *ospf, struct ospf_vl_data *vl_data)
snprintf (ifname, sizeof(ifname), "VLINK%d", vlink_count);
vi = if_create (ifname, strnlen(ifname, sizeof(ifname)));
+ /*
+ * if_create sets ZEBRA_INTERFACE_LINKDETECTION
+ * virtual links don't need this.
+ */
+ UNSET_FLAG (vi->status, ZEBRA_INTERFACE_LINKDETECTION);
co = connected_new ();
co->ifp = vi;
listnode_add (vi->connected, co);
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 634bc435..e9d1a858 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -543,7 +543,7 @@ lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi)
{
int links = 0;
struct ospf_neighbor *nbr;
- struct in_addr id, mask;
+ struct in_addr id, mask, data;
u_int16_t cost = ospf_link_cost (oi);
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
@@ -552,19 +552,34 @@ lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi)
if ((nbr = ospf_nbr_lookup_ptop (oi)))
if (nbr->state == NSM_Full)
{
- /* For unnumbered point-to-point networks, the Link Data field
- should specify the interface's MIB-II ifIndex value. */
- links += link_info_set (s, nbr->router_id, oi->address->u.prefix4,
- LSA_LINK_TYPE_POINTOPOINT, 0, cost);
+ if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
+ {
+ /* For unnumbered point-to-point networks, the Link Data field
+ should specify the interface's MIB-II ifIndex value. */
+ data.s_addr = htonl(oi->ifp->ifindex);
+ links += link_info_set (s, nbr->router_id, data,
+ LSA_LINK_TYPE_POINTOPOINT, 0, cost);
+ }
+ else
+ {
+ links += link_info_set (s, nbr->router_id,
+ oi->address->u.prefix4,
+ LSA_LINK_TYPE_POINTOPOINT, 0, cost);
+ }
}
- /* Regardless of the state of the neighboring router, we must
- add a Type 3 link (stub network).
- N.B. Options 1 & 2 share basically the same logic. */
- masklen2ip (oi->address->prefixlen, &mask);
- id.s_addr = CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr & mask.s_addr;
- links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0,
- oi->output_cost);
+ /* no need for a stub link for unnumbered interfaces */
+ if (!CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
+ {
+ /* Regardless of the state of the neighboring router, we must
+ add a Type 3 link (stub network).
+ N.B. Options 1 & 2 share basically the same logic. */
+ masklen2ip (oi->address->prefixlen, &mask);
+ id.s_addr = CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr & mask.s_addr;
+ links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0,
+ oi->output_cost);
+ }
+
return links;
}
@@ -1649,8 +1664,8 @@ ospf_external_lsa_body_set (struct stream *s, struct external_info *ei,
/* Put forwarding address. */
stream_put_ipv4 (s, fwd_addr.s_addr);
- /* Put route tag -- This value should be introduced from configuration. */
- stream_putl (s, 0);
+ /* Put route tag -- only first 16bits are used for compatibility */
+ stream_putl (s, ei->tag);
}
/* Create new external-LSA. */
@@ -2163,7 +2178,7 @@ ospf_default_originate_timer (struct thread *thread)
/* If there is no default route via redistribute,
then originate AS-external-LSA with nexthop 0 (self). */
nexthop.s_addr = 0;
- ospf_external_info_add (DEFAULT_ROUTE, p, 0, nexthop);
+ ospf_external_info_add (DEFAULT_ROUTE, p, 0, nexthop, 0);
}
if ((ei = ospf_default_external_info (ospf)))
diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c
index f373650c..32b64e2a 100644
--- a/ospfd/ospf_main.c
+++ b/ospfd/ospf_main.c
@@ -303,6 +303,7 @@ main (int argc, char **argv)
/* OSPF vty inits. */
ospf_vty_init ();
ospf_vty_show_init ();
+ ospf_vty_clear_init ();
ospf_route_map_init ();
#ifdef HAVE_SNMP
diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c
index 02ddf92f..62ea6da4 100644
--- a/ospfd/ospf_network.c
+++ b/ospfd/ospf_network.c
@@ -163,6 +163,9 @@ ospf_sock_init (void)
{
int ospf_sock;
int ret, hincl = 1;
+ int bufsize = (8 * 1024 * 1024);
+ int optval;
+ socklen_t optlen = sizeof(optval);
if ( ospfd_privs.change (ZPRIVS_RAISE) )
zlog_err ("ospf_sock_init: could not raise privs, %s",
@@ -221,6 +224,39 @@ ospf_sock_init (void)
zlog_err ("ospf_sock_init: could not lower privs, %s",
safe_strerror (errno) );
}
+
+ if ((ret = setsockopt (ospf_sock, SOL_SOCKET, SO_RCVBUF,
+ &bufsize, sizeof (bufsize))) < 0)
+ {
+ zlog_err ("Couldn't increase raw rbuf size: %s\n", safe_strerror(errno));
+ }
+
+ if ((ret = getsockopt (ospf_sock, SOL_SOCKET, SO_RCVBUF,
+ &optval, &optlen)) < 0)
+ {
+ zlog_err("getsockopt of SO_RCVBUF failed with error %s\n", safe_strerror(errno));
+ }
+ if (optval < bufsize)
+ {
+ zlog_err("Unable to SO_RCVBUF to %d, set to %d\n", bufsize, optval);
+ }
+
+
+ if ((ret = setsockopt (ospf_sock, SOL_SOCKET, SO_SNDBUF,
+ &bufsize, sizeof (bufsize))) < 0)
+ {
+ zlog_err ("Couldn't increase raw wbuf size: %s\n", safe_strerror(errno));
+ }
+
+ if ((ret = getsockopt (ospf_sock, SOL_SOCKET, SO_SNDBUF,
+ &optval, &optlen)) < 0)
+ {
+ zlog_err ("getsockopt of SO_SNDBUF failed with error %s\n", safe_strerror(errno));
+ }
+ if (optval < bufsize)
+ {
+ zlog_err ("Unable to SO_SNDBUF to %d, set to %d\n", bufsize, optval);
+ }
return ospf_sock;
}
diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c
index b43d8855..64cc246b 100644
--- a/ospfd/ospf_nsm.c
+++ b/ospfd/ospf_nsm.c
@@ -316,7 +316,8 @@ nsm_exchange_done (struct ospf_neighbor *nbr)
return NSM_Full;
/* Send Link State Request. */
- ospf_ls_req_send (nbr);
+ if (nbr->t_ls_req == NULL)
+ ospf_ls_req_send (nbr);
return NSM_Loading;
}
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 25f70bba..48fe0829 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -633,6 +633,7 @@ ospf_write (struct thread *thread)
{
struct ospf *ospf = THREAD_ARG (thread);
struct ospf_interface *oi;
+ struct ospf_interface *last_serviced_oi = NULL;
struct ospf_packet *op;
struct sockaddr_in sa_dst;
struct ip iph;
@@ -647,6 +648,7 @@ ospf_write (struct thread *thread)
u_int16_t maxdatasize;
#endif /* WANT_OSPF_WRITE_FRAGMENT */
#define OSPF_WRITE_IPHL_SHIFT 2
+ int pkt_count = 0;
ospf->t_write = NULL;
@@ -659,143 +661,173 @@ ospf_write (struct thread *thread)
/* seed ipid static with low order bits of time */
if (ipid == 0)
ipid = (time(NULL) & 0xffff);
-
- /* convenience - max OSPF data per packet,
- * and reliability - not more data, than our
- * socket can accept
- */
- maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) -
- sizeof (struct ip);
#endif /* WANT_OSPF_WRITE_FRAGMENT */
-
- /* Get one packet from queue. */
- op = ospf_fifo_head (oi->obuf);
- assert (op);
- assert (op->length >= OSPF_HEADER_SIZE);
-
- if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS)
- || op->dst.s_addr == htonl (OSPF_ALLDROUTERS))
- ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex);
-
- /* Rewrite the md5 signature & update the seq */
- ospf_make_md5_digest (oi, op);
- /* Retrieve OSPF packet type. */
- stream_set_getp (op->s, 1);
- type = stream_getc (op->s);
+ while ((pkt_count < ospf->write_oi_count) && oi && (last_serviced_oi != oi))
+ {
+ /* If there is only packet in the queue, the oi is removed from
+ write-q, so fix up the last interface that was serviced */
+ if (last_serviced_oi == NULL) {
+ last_serviced_oi = oi;
+ }
+ pkt_count++;
+ /* convenience - max OSPF data per packet,
+ * and reliability - not more data, than our
+ * socket can accept
+ */
+#if defined (WANT_OSPF_WRITE_FRAGMENT)
+ maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) -
+ sizeof (struct ip);
+#endif
+
+ /* Get one packet from queue. */
+ op = ospf_fifo_head (oi->obuf);
+ assert (op);
+ assert (op->length >= OSPF_HEADER_SIZE);
+
+ if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS)
+ || op->dst.s_addr == htonl (OSPF_ALLDROUTERS))
+ ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex);
+
+ /* Rewrite the md5 signature & update the seq */
+ ospf_make_md5_digest (oi, op);
+
+ /* Retrieve OSPF packet type. */
+ stream_set_getp (op->s, 1);
+ type = stream_getc (op->s);
- /* reset get pointer */
- stream_set_getp (op->s, 0);
+ /* reset get pointer */
+ stream_set_getp (op->s, 0);
- memset (&iph, 0, sizeof (struct ip));
- memset (&sa_dst, 0, sizeof (sa_dst));
+ memset (&iph, 0, sizeof (struct ip));
+ memset (&sa_dst, 0, sizeof (sa_dst));
- sa_dst.sin_family = AF_INET;
+ sa_dst.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- sa_dst.sin_len = sizeof(sa_dst);
+ sa_dst.sin_len = sizeof(sa_dst);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- sa_dst.sin_addr = op->dst;
- sa_dst.sin_port = htons (0);
-
- /* Set DONTROUTE flag if dst is unicast. */
- if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
- if (!IN_MULTICAST (htonl (op->dst.s_addr)))
- flags = MSG_DONTROUTE;
-
- iph.ip_hl = sizeof (struct ip) >> OSPF_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 << OSPF_WRITE_IPHL_SHIFT) )
- iph.ip_hl++; /* we presume sizeof struct ip cant overflow ip_hl.. */
+ sa_dst.sin_addr = op->dst;
+ sa_dst.sin_port = htons (0);
+
+ /* Set DONTROUTE flag if dst is unicast. */
+ if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
+ if (!IN_MULTICAST (htonl (op->dst.s_addr)))
+ flags = MSG_DONTROUTE;
+
+ iph.ip_hl = sizeof (struct ip) >> OSPF_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 << OSPF_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 << OSPF_WRITE_IPHL_SHIFT) + op->length;
+ iph.ip_v = IPVERSION;
+ iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
+ iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length;
#if defined(__DragonFly__)
- /*
- * DragonFly's raw socket expects ip_len/ip_off in network byte order.
- */
- iph.ip_len = htons(iph.ip_len);
+ /*
+ * DragonFly's raw socket expects ip_len/ip_off in network byte order.
+ */
+ iph.ip_len = htons(iph.ip_len);
#endif
#ifdef WANT_OSPF_WRITE_FRAGMENT
- /* XXX-MT: not thread-safe at all..
- * XXX: this presumes this is only programme sending OSPF packets
- * otherwise, no guarantee ipid will be unique
- */
- iph.ip_id = ++ipid;
+ /* XXX-MT: not thread-safe at all..
+ * XXX: this presumes this is only programme sending OSPF packets
+ * otherwise, no guarantee ipid will be unique
+ */
+ iph.ip_id = ++ipid;
#endif /* WANT_OSPF_WRITE_FRAGMENT */
- iph.ip_off = 0;
- if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
- iph.ip_ttl = OSPF_VL_IP_TTL;
- else
- iph.ip_ttl = OSPF_IP_TTL;
- iph.ip_p = IPPROTO_OSPFIGP;
- iph.ip_sum = 0;
- iph.ip_src.s_addr = oi->address->u.prefix4.s_addr;
- iph.ip_dst.s_addr = op->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 << OSPF_WRITE_IPHL_SHIFT;
- iov[1].iov_base = STREAM_PNT (op->s);
- iov[1].iov_len = op->length;
+ iph.ip_off = 0;
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ iph.ip_ttl = OSPF_VL_IP_TTL;
+ else
+ iph.ip_ttl = OSPF_IP_TTL;
+ iph.ip_p = IPPROTO_OSPFIGP;
+ iph.ip_sum = 0;
+ iph.ip_src.s_addr = oi->address->u.prefix4.s_addr;
+ iph.ip_dst.s_addr = op->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 << OSPF_WRITE_IPHL_SHIFT;
+ iov[1].iov_base = STREAM_PNT (op->s);
+ iov[1].iov_len = op->length;
- /* Sadly we can not rely on kernels to fragment packets because of either
- * IP_HDRINCL and/or multicast destination being set.
- */
+ /* Sadly we can not rely on kernels to fragment packets because of either
+ * IP_HDRINCL and/or multicast destination being set.
+ */
#ifdef WANT_OSPF_WRITE_FRAGMENT
- if ( op->length > maxdatasize )
- ospf_write_frags (ospf->fd, op, &iph, &msg, maxdatasize,
- oi->ifp->mtu, flags, type);
+ if ( op->length > maxdatasize )
+ ospf_write_frags (ospf->fd, op, &iph, &msg, maxdatasize,
+ oi->ifp->mtu, flags, type);
#endif /* WANT_OSPF_WRITE_FRAGMENT */
- /* send final fragment (could be first) */
- sockopt_iphdrincl_swab_htosys (&iph);
- ret = sendmsg (ospf->fd, &msg, flags);
- sockopt_iphdrincl_swab_systoh (&iph);
+ /* send final fragment (could be first) */
+ sockopt_iphdrincl_swab_htosys (&iph);
+ ret = sendmsg (ospf->fd, &msg, flags);
+ sockopt_iphdrincl_swab_systoh (&iph);
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug ("ospf_write to %s, "
+ "id %d, off %d, len %d, interface %s, mtu %u:",
+ inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len,
+ oi->ifp->name, oi->ifp->mtu);
- if (ret < 0)
- zlog_warn ("*** sendmsg in ospf_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,
- oi->ifp->name, oi->ifp->mtu, safe_strerror (errno));
+ if (ret < 0)
+ zlog_warn ("*** sendmsg in ospf_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,
+ oi->ifp->name, oi->ifp->mtu, safe_strerror (errno));
- /* Show debug sending packet. */
- if (IS_DEBUG_OSPF_PACKET (type - 1, SEND))
- {
- if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
- {
- zlog_debug ("-----------------------------------------------------");
- ospf_ip_header_dump (&iph);
- stream_set_getp (op->s, 0);
- ospf_packet_dump (op->s);
- }
+ /* Show debug sending packet. */
+ if (IS_DEBUG_OSPF_PACKET (type - 1, SEND))
+ {
+ if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
+ {
+ zlog_debug ("-----------------------------------------------------");
+ ospf_ip_header_dump (&iph);
+ stream_set_getp (op->s, 0);
+ ospf_packet_dump (op->s);
+ }
- zlog_debug ("%s sent to [%s] via [%s].",
- LOOKUP (ospf_packet_type_str, type), inet_ntoa (op->dst),
- IF_NAME (oi));
+ zlog_debug ("%s sent to [%s] via [%s].",
+ LOOKUP (ospf_packet_type_str, type), inet_ntoa (op->dst),
+ IF_NAME (oi));
- if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
- zlog_debug ("-----------------------------------------------------");
- }
+ if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
+ zlog_debug ("-----------------------------------------------------");
+ }
- /* Now delete packet from queue. */
- ospf_packet_delete (oi);
+ /* Now delete packet from queue. */
+ ospf_packet_delete (oi);
- /* Move this interface to the tail of write_q to
+ /* Move this interface to the tail of write_q to
serve everyone in a round robin fashion */
- listnode_move_to_tail (ospf->oi_write_q, node);
- if (ospf_fifo_head (oi->obuf) == NULL)
- {
- oi->on_write_q = 0;
list_delete_node (ospf->oi_write_q, node);
+ if (ospf_fifo_head (oi->obuf) == NULL)
+ {
+ oi->on_write_q = 0;
+ last_serviced_oi = NULL;
+ oi = NULL;
+ }
+ else
+ {
+ listnode_add (ospf->oi_write_q, oi);
+ }
+
+ /* Setup to service from the head of the queue again */
+ if (!list_isempty (ospf->oi_write_q))
+ {
+ node = listhead (ospf->oi_write_q);
+ assert (node);
+ oi = listgetdata (node);
+ assert (oi);
+ }
}
/* If packets still remain in queue, call write thread. */
@@ -1162,6 +1194,9 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi,
/* Save received neighbor values from DD. */
ospf_db_desc_save_current (nbr, dd);
+
+ if (!nbr->t_ls_req)
+ ospf_ls_req_send (nbr);
}
static int
@@ -3022,7 +3057,8 @@ ospf_make_hello (struct ospf_interface *oi, struct stream *s)
int flag = 0;
/* Set netmask of interface. */
- if (oi->type != OSPF_IFTYPE_POINTOPOINT &&
+ if (!(CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED) &&
+ oi->type == OSPF_IFTYPE_POINTOPOINT) &&
oi->type != OSPF_IFTYPE_VIRTUALLINK)
masklen2ip (oi->address->prefixlen, &mask);
else
@@ -3830,9 +3866,12 @@ ospf_ls_ack_send_list (struct ospf_interface *oi, struct list *ack,
/* Set packet length. */
op->length = length;
- /* Set destination IP address. */
- op->dst = dst;
-
+ /* Decide destination address. */
+ if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+ op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
+ else
+ op->dst.s_addr = dst.s_addr;
+
/* Add packet to the interface output queue. */
ospf_packet_add (oi, op);
diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c
index eb7829ac..51e6ebae 100644
--- a/ospfd/ospf_route.c
+++ b/ospfd/ospf_route.c
@@ -783,7 +783,7 @@ ospf_route_copy_nexthops_from_vertex (struct ospf_route *to,
path = ospf_path_new ();
path->nexthop = nexthop->router;
path->ifindex = nexthop->oi->ifp->ifindex;
- listnode_add (to->paths, path);
+ listnode_add (to->paths, path);
}
}
}
diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c
index d0ebce66..133b1e36 100644
--- a/ospfd/ospf_routemap.c
+++ b/ospfd/ospf_routemap.c
@@ -108,10 +108,10 @@ ospf_route_match_delete (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -131,10 +131,10 @@ ospf_route_match_add (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -154,10 +154,10 @@ ospf_route_set_add (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -178,10 +178,10 @@ ospf_route_set_delete (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -417,6 +417,67 @@ struct route_map_rule_cmd route_match_interface_cmd =
route_match_interface_free
};
+/* 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 external_info *ei;
+
+ if (type == RMAP_OSPF)
+ {
+ tag = rule;
+ ei = object;
+
+ return ((ei->tag == *tag)? RMAP_MATCH : 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;
+ u_short tmp;
+
+ /* tag value shoud be integer. */
+ if (! all_digit (arg))
+ return NULL;
+
+ tmp = atoi(arg);
+ if (tmp < 1)
+ return NULL;
+
+ tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
+
+ if (!tag)
+ return tag;
+
+ *tag = tmp;
+
+ 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 METRIC' */
/* Set metric to attribute. */
static route_map_result_t
@@ -445,6 +506,21 @@ route_set_metric_compile (const char *arg)
u_int32_t *metric;
int32_t ret;
+ /* OSPF doesn't support the +/- in
+ set metric <+/-metric> check
+ Ignore the +/- component */
+ if (! all_digit (arg))
+ {
+ if ((strncmp (arg, "+", 1) == 0 || strncmp (arg, "-", 1) == 0) &&
+ all_digit (arg+1))
+ {
+ zlog_warn ("OSPF does not support 'set metric +/-'");
+ arg++;
+ }
+ else
+ return NULL;
+ }
+
metric = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
ret = atoi (arg);
@@ -531,6 +607,67 @@ struct route_map_rule_cmd route_set_metric_type_cmd =
route_set_metric_type_free,
};
+static route_map_result_t
+route_set_tag (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_short *tag;
+ struct external_info *ei;
+
+ if (type == RMAP_OSPF)
+ {
+ tag = rule;
+ ei = object;
+
+ /* Set tag value */
+ ei->tag=*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;
+ u_short tmp;
+
+ /* tag value shoud be integer. */
+ if (! all_digit (arg))
+ return NULL;
+
+ tmp = atoi(arg);
+
+ if (tmp < 1)
+ return NULL;
+
+ tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
+
+ if (!tag)
+ return tag;
+
+ *tag = tmp;
+
+ return tag;
+}
+
+/* Free route map's tag value. */
+static void
+route_set_tag_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for tag set. */
+struct route_map_rule_cmd route_set_tag_cmd =
+{
+ "tag",
+ route_set_tag,
+ route_set_tag_compile,
+ route_set_tag_free,
+};
+
DEFUN (match_ip_nexthop,
match_ip_nexthop_cmd,
"match ip next-hop (<1-199>|<1300-2699>|WORD)",
@@ -716,6 +853,37 @@ ALIAS (no_match_interface,
"Match first hop interface of route\n"
"Interface name\n")
+DEFUN (match_tag,
+ match_tag_cmd,
+ "match tag <1-65535>",
+ MATCH_STR
+ "Match tag of route\n"
+ "Tag value\n")
+{
+ return ospf_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 ospf_route_match_delete (vty, vty->index, "tag", NULL);
+
+ return ospf_route_match_delete (vty, vty->index, "tag", argv[0]);
+}
+
+ALIAS (no_match_tag,
+ no_match_tag_val_cmd,
+ "no match tag <1-65535>",
+ NO_STR
+ MATCH_STR
+ "Match tag of route\n"
+ "Tag value\n")
+
DEFUN (set_metric,
set_metric_cmd,
"set metric <0-4294967295>",
@@ -785,6 +953,37 @@ ALIAS (no_set_metric_type,
"OSPF[6] external type 1 metric\n"
"OSPF[6] external type 2 metric\n")
+DEFUN (set_tag,
+ set_tag_cmd,
+ "set tag <1-65535>",
+ SET_STR
+ "Tag value for routing protocol\n"
+ "Tag value\n")
+{
+ return ospf_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)
+ ospf_route_set_delete(vty, vty->index, "tag", NULL);
+
+ return ospf_route_set_delete (vty, vty->index, "tag", argv[0]);
+}
+
+ALIAS (no_set_tag,
+ no_set_tag_val_cmd,
+ "no set tag <1-65535>",
+ NO_STR
+ SET_STR
+ "Tag value for routing protocol\n"
+ "Tag value\n")
+
/* Route-map init */
void
ospf_route_map_init (void)
@@ -801,9 +1000,11 @@ ospf_route_map_init (void)
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_interface_cmd);
+ route_map_install_match (&route_match_tag_cmd);
route_map_install_set (&route_set_metric_cmd);
route_map_install_set (&route_set_metric_type_cmd);
+ route_map_install_set (&route_set_tag_cmd);
install_element (RMAP_NODE, &match_ip_nexthop_cmd);
install_element (RMAP_NODE, &no_match_ip_nexthop_cmd);
@@ -820,6 +1021,9 @@ ospf_route_map_init (void)
install_element (RMAP_NODE, &match_interface_cmd);
install_element (RMAP_NODE, &no_match_interface_cmd);
install_element (RMAP_NODE, &no_match_interface_val_cmd);
+ install_element (RMAP_NODE, &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, &no_set_metric_cmd);
@@ -827,4 +1031,7 @@ ospf_route_map_init (void)
install_element (RMAP_NODE, &set_metric_type_cmd);
install_element (RMAP_NODE, &no_set_metric_type_cmd);
install_element (RMAP_NODE, &no_set_metric_type_val_cmd);
+ install_element (RMAP_NODE, &set_tag_cmd);
+ install_element (RMAP_NODE, &no_set_tag_cmd);
+ install_element (RMAP_NODE, &no_set_tag_val_cmd);
}
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
index 58a39921..2806c1a0 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
@@ -837,13 +837,6 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB)
continue;
- /* Infinite distance links shouldn't be followed, except
- * for local links (a stub-routed router still wants to
- * calculate tree, so must follow its own links).
- */
- if ((v != area->spf) && l->m[0].metric >= OSPF_OUTPUT_COST_INFINITE)
- continue;
-
/* (b) Otherwise, W is a transit vertex (router or transit
network). Look up the vertex W's LSA (router-LSA or
network-LSA) in Area A's link state database. */
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index fb17dff3..a49fdfce 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -2655,6 +2655,52 @@ DEFUN (no_ospf_auto_cost_reference_bandwidth,
return CMD_SUCCESS;
}
+DEFUN (ospf_write_multiplier,
+ ospf_write_multiplier_cmd,
+ "ospf write-multiplier <1-100>",
+ "OSPF specific commands\n"
+ "Write multiplier\n"
+ "Maximum number of interface serviced per write\n")
+{
+ struct ospf *ospf = vty->index;
+ u_int32_t write_oi_count;
+
+ write_oi_count = strtol (argv[0], NULL, 10);
+ if (write_oi_count < 1 || write_oi_count > 100)
+ {
+ vty_out (vty, "write-multiplier value is invalid%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ospf->write_oi_count = write_oi_count;
+ return CMD_SUCCESS;
+}
+
+ALIAS (ospf_write_multiplier,
+ write_multiplier_cmd,
+ "write-multiplier <1-100>",
+ "Write multiplier\n"
+ "Maximum number of interface serviced per write\n")
+
+DEFUN (no_ospf_write_multiplier,
+ no_ospf_write_multiplier_cmd,
+ "no ospf write-multiplier",
+ NO_STR
+ "OSPF specific commands\n"
+ "Write multiplier\n")
+{
+ struct ospf *ospf = vty->index;
+
+ ospf->write_oi_count = OSPF_WRITE_INTERFACE_COUNT_DEFAULT;
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ospf_write_multiplier,
+ no_write_multiplier_cmd,
+ "no write-multiplier",
+ NO_STR
+ "Write multiplier\n")
+
const char *ospf_abr_type_descr_str[] =
{
"Unknown",
@@ -2878,6 +2924,10 @@ DEFUN (show_ip_ospf,
ospf_timer_dump (ospf->t_spf_calc, timebuf, sizeof (timebuf)),
VTY_NEWLINE);
+ /* Show write multiplier values */
+ vty_out (vty, " Write Multiplier set to %d %s",
+ ospf->write_oi_count, VTY_NEWLINE);
+
/* Show refresh parameters. */
vty_out (vty, " Refresh timer %d secs%s",
ospf->lsa_refresh_interval, VTY_NEWLINE);
@@ -2955,30 +3005,37 @@ show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf,
if (oi == NULL)
continue;
- /* Show OSPF interface information. */
- vty_out (vty, " Internet Address %s/%d,",
- inet_ntoa (oi->address->u.prefix4), oi->address->prefixlen);
-
- if (oi->connected->destination || oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
{
- struct in_addr *dest;
- const char *dstr;
-
- if (CONNECTED_PEER(oi->connected)
- || oi->type == OSPF_IFTYPE_VIRTUALLINK)
- dstr = "Peer";
- else
- dstr = "Broadcast";
-
- /* For Vlinks, showing the peer address is probably more
- * informative than the local interface that is being used
- */
- if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
- dest = &oi->vl_data->peer_addr;
- else
- dest = &oi->connected->destination->u.prefix4;
-
- vty_out (vty, " %s %s,", dstr, inet_ntoa (*dest));
+ vty_out (vty, " This interface is UNNUMBERED,");
+ }
+ else
+ {
+ /* Show OSPF interface information. */
+ vty_out (vty, " Internet Address %s/%d,",
+ inet_ntoa (oi->address->u.prefix4), oi->address->prefixlen);
+
+ if (oi->connected->destination || oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ {
+ struct in_addr *dest;
+ const char *dstr;
+
+ if (CONNECTED_PEER(oi->connected)
+ || oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ dstr = "Peer";
+ else
+ dstr = "Broadcast";
+
+ /* For Vlinks, showing the peer address is probably more
+ * informative than the local interface that is being used
+ */
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ dest = &oi->vl_data->peer_addr;
+ else
+ dest = &oi->connected->destination->u.prefix4;
+
+ vty_out (vty, " %s %s,", dstr, inet_ntoa (*dest));
+ }
}
vty_out (vty, " Area %s%s", ospf_area_desc_string (oi->area),
@@ -3030,7 +3087,7 @@ show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf,
inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE);
}
}
-
+
/* Next network-LSA sequence number we'll use, if we're elected DR */
if (oi->params && ntohl (oi->params->network_lsa_seqnum)
!= OSPF_INITIAL_SEQUENCE_NUMBER)
@@ -3117,7 +3174,7 @@ DEFUN (show_ip_ospf_interface,
static void
show_ip_ospf_neighbour_header (struct vty *vty)
{
- vty_out (vty, "%s%15s %3s %-15s %9s %-15s %-20s %5s %5s %5s%s",
+ vty_out (vty, "%s%-15s %3s %-15s %9s %-15s %-20s %5s %5s %5s%s",
VTY_NEWLINE,
"Neighbor ID", "Pri", "State", "Dead Time",
"Address", "Interface", "RXmtL", "RqstL", "DBsmL",
@@ -5184,11 +5241,12 @@ ALIAS (ip_ospf_dead_interval_minimal,
DEFUN (no_ip_ospf_dead_interval,
no_ip_ospf_dead_interval_addr_cmd,
- "no ip ospf dead-interval A.B.C.D",
+ "no ip ospf dead-interval <1-65535> A.B.C.D",
NO_STR
"IP Information\n"
"OSPF interface commands\n"
"Interval after which a neighbor is declared dead\n"
+ "Seconds\n"
"Address of interface")
{
struct interface *ifp = vty->index;
@@ -5201,9 +5259,9 @@ DEFUN (no_ip_ospf_dead_interval,
ifp = vty->index;
params = IF_DEF_PARAMS (ifp);
- if (argc == 1)
+ if (argc == 2)
{
- ret = inet_aton(argv[0], &addr);
+ ret = inet_aton(argv[1], &addr);
if (!ret)
{
vty_out (vty, "Please specify interface address by A.B.C.D%s",
@@ -5251,6 +5309,15 @@ DEFUN (no_ip_ospf_dead_interval,
}
ALIAS (no_ip_ospf_dead_interval,
+ no_ip_ospf_dead_interval_seconds_cmd,
+ "no ip ospf dead-interval <1-65535>",
+ NO_STR
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Interval after which a neighbor is declared dead\n"
+ "Seconds\n")
+
+ALIAS (no_ip_ospf_dead_interval,
no_ip_ospf_dead_interval_cmd,
"no ip ospf dead-interval",
NO_STR
@@ -5328,11 +5395,12 @@ ALIAS (ip_ospf_hello_interval,
DEFUN (no_ip_ospf_hello_interval,
no_ip_ospf_hello_interval_addr_cmd,
- "no ip ospf hello-interval A.B.C.D",
+ "no ip ospf hello-interval <1-65535> A.B.C.D",
NO_STR
"IP Information\n"
"OSPF interface commands\n"
"Time between HELLO packets\n"
+ "Seconds\n"
"Address of interface")
{
struct interface *ifp = vty->index;
@@ -5343,9 +5411,9 @@ DEFUN (no_ip_ospf_hello_interval,
ifp = vty->index;
params = IF_DEF_PARAMS (ifp);
- if (argc == 1)
+ if (argc == 2)
{
- ret = inet_aton(argv[0], &addr);
+ ret = inet_aton(argv[1], &addr);
if (!ret)
{
vty_out (vty, "Please specify interface address by A.B.C.D%s",
@@ -5371,6 +5439,15 @@ DEFUN (no_ip_ospf_hello_interval,
}
ALIAS (no_ip_ospf_hello_interval,
+ no_ip_ospf_hello_interval_seconds_cmd,
+ "no ip ospf hello-interval <1-65535>",
+ NO_STR
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Time between HELLO packets\n"
+ "Seconds\n")
+
+ALIAS (no_ip_ospf_hello_interval,
no_ip_ospf_hello_interval_cmd,
"no ip ospf hello-interval",
NO_STR
@@ -6525,7 +6602,7 @@ DEFUN (no_ospf_max_metric_router_lsa_startup,
DEFUN (ospf_max_metric_router_lsa_shutdown,
ospf_max_metric_router_lsa_shutdown_cmd,
- "max-metric router-lsa on-shutdown <5-86400>",
+ "max-metric router-lsa on-shutdown <5-100>",
"OSPF maximum / infinite-distance metric\n"
"Advertise own Router-LSA with infinite distance (stub router)\n"
"Advertise stub-router prior to full shutdown of OSPF\n"
@@ -7454,6 +7531,11 @@ ospf_config_write (struct vty *vty)
ospf->spf_delay, ospf->spf_holdtime,
ospf->spf_max_holdtime, VTY_NEWLINE);
+ /* Write multiplier print. */
+ if (ospf->write_oi_count != OSPF_WRITE_INTERFACE_COUNT_DEFAULT)
+ vty_out (vty, " ospf write-multiplier %d%s",
+ ospf->write_oi_count, VTY_NEWLINE);
+
/* Max-metric router-lsa print */
config_write_stub_router (vty, ospf);
@@ -7637,12 +7719,14 @@ ospf_vty_if_init (void)
install_element (INTERFACE_NODE, &ip_ospf_dead_interval_minimal_cmd);
install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_addr_cmd);
install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_cmd);
+ install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_seconds_cmd);
/* "ip ospf hello-interval" commands. */
install_element (INTERFACE_NODE, &ip_ospf_hello_interval_addr_cmd);
install_element (INTERFACE_NODE, &ip_ospf_hello_interval_cmd);
install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_addr_cmd);
install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd);
+ install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_seconds_cmd);
/* "ip ospf network" commands. */
install_element (INTERFACE_NODE, &ip_ospf_network_cmd);
@@ -7730,6 +7814,51 @@ static struct cmd_node ospf_node =
1
};
+static void
+ospf_interface_clear (struct interface *ifp)
+{
+ if (!if_is_operative (ifp)) return;
+
+ if (IS_DEBUG_OSPF (ism, ISM_EVENTS))
+ zlog (NULL, LOG_DEBUG, "ISM[%s]: clear by reset", ifp->name);
+
+ ospf_if_reset(ifp);
+}
+
+DEFUN (clear_ip_ospf_interface,
+ clear_ip_ospf_interface_cmd,
+ "clear ip ospf interface [IFNAME]",
+ CLEAR_STR
+ IP_STR
+ "OSPF information\n"
+ "Interface information\n"
+ "Interface name\n")
+{
+ struct interface *ifp;
+ struct listnode *node;
+
+ if (argc == 0) /* Clear all the ospfv2 interfaces. */
+ {
+ for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+ ospf_interface_clear(ifp);
+ }
+ else /* Interface name is specified. */
+ {
+ if ((ifp = if_lookup_by_name (argv[0])) == NULL)
+ vty_out (vty, "No such interface name%s", VTY_NEWLINE);
+ else
+ ospf_interface_clear(ifp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+void
+ospf_vty_clear_init (void)
+{
+ install_element (ENABLE_NODE, &clear_ip_ospf_interface_cmd);
+}
+
/* Install OSPF related vty commands. */
void
@@ -7898,6 +8027,12 @@ ospf_vty_init (void)
install_element (OSPF_NODE, &no_ospf_neighbor_priority_cmd);
install_element (OSPF_NODE, &no_ospf_neighbor_poll_interval_cmd);
+ /* write multiplier commands */
+ install_element (OSPF_NODE, &ospf_write_multiplier_cmd);
+ install_element (OSPF_NODE, &no_ospf_write_multiplier_cmd);
+ install_element (OSPF_NODE, &write_multiplier_cmd);
+ install_element (OSPF_NODE, &no_write_multiplier_cmd);
+
/* Init interface related vty commands. */
ospf_vty_if_init ();
diff --git a/ospfd/ospf_vty.h b/ospfd/ospf_vty.h
index da0ed1cc..28bb419a 100644
--- a/ospfd/ospf_vty.h
+++ b/ospfd/ospf_vty.h
@@ -53,5 +53,6 @@
/* Prototypes. */
extern void ospf_vty_init (void);
extern void ospf_vty_show_init (void);
+extern void ospf_vty_clear_init (void);
#endif /* _QUAGGA_OSPF_VTY_H */
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 89404552..a4aae87f 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -351,6 +351,12 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
if (distance)
SET_FLAG (message, ZAPI_MESSAGE_DISTANCE);
+ /* Check if path type is ASE and use only 16bit tags */
+ if (((or->path_type == OSPF_PATH_TYPE1_EXTERNAL) ||
+ (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)) &&
+ (or->u.ext.tag > 0) && (or->u.ext.tag < UINT16_MAX))
+ SET_FLAG (message, ZAPI_MESSAGE_TAG);
+
/* Make packet. */
s = zclient->obuf;
stream_reset (s);
@@ -397,12 +403,13 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
{
char buf[2][INET_ADDRSTRLEN];
- zlog_debug("Zebra: Route add %s/%d nexthop %s",
+ zlog_debug("Zebra: Route add %s/%d nexthop %s, ifindex=%d",
inet_ntop(AF_INET, &p->prefix,
buf[0], sizeof(buf[0])),
p->prefixlen,
inet_ntop(AF_INET, &path->nexthop,
- buf[1], sizeof(buf[1])));
+ buf[1], sizeof(buf[1])),
+ path->ifindex);
}
}
@@ -418,6 +425,9 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
stream_putl (s, or->cost);
}
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG))
+ stream_putw (s, (u_short)or->u.ext.tag);
+
stream_putw_at (s, 0, stream_get_endp (s));
zclient_send_message(zclient);
@@ -526,6 +536,7 @@ ospf_zebra_add_discard (struct prefix_ipv4 *p)
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 0;
api.ifindex_num = 0;
+ api.tag = 0;
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, p, &api);
@@ -550,6 +561,7 @@ ospf_zebra_delete_discard (struct prefix_ipv4 *p)
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 0;
api.ifindex_num = 0;
+ api.tag = 0;
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api);
@@ -869,6 +881,10 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
api.distance = stream_getc (s);
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl (s);
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+ api.tag = stream_getw (s);
+ else
+ api.tag = 0;
ospf = ospf_lookup ();
if (ospf == NULL)
@@ -886,8 +902,12 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
* || CHECK_FLAG (api.flags, ZEBRA_FLAG_REJECT))
* return 0;
*/
-
- ei = ospf_external_info_add (api.type, p, ifindex, nexthop);
+
+ /* Protocol tag overwrites all other tag value send by zebra */
+ if (ospf->dtag[api.type] > 0)
+ api.tag = ospf->dtag[api.type];
+
+ ei = ospf_external_info_add (api.type, p, ifindex, nexthop, api.tag);
if (ospf->router_id.s_addr == 0)
/* Set flags to generate AS-external-LSA originate event
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index c9fcdc39..36ace1e5 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -197,6 +197,7 @@ ospf_new (void)
{
new->dmetric[i].type = -1;
new->dmetric[i].value = -1;
+ new->dtag[i] = 0;
}
new->default_metric = -1;
new->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH;
@@ -245,6 +246,7 @@ ospf_new (void)
}
new->t_read = thread_add_read (master, ospf_read, new, new->fd);
new->oi_write_q = list_new ();
+ new->write_oi_count = OSPF_WRITE_INTERFACE_COUNT_DEFAULT;
return new;
}
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 098fc5f4..c5f7fa14 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -214,6 +214,8 @@ struct ospf
struct thread *t_deferred_shutdown; /* deferred/stub-router shutdown timer*/
struct thread *t_write;
+#define OSPF_WRITE_INTERFACE_COUNT_DEFAULT 20
+ int write_oi_count; /* Num of packets sent per thread invocation */
struct thread *t_read;
int fd;
unsigned int maxsndbuflen;
@@ -237,6 +239,9 @@ struct ospf
-1 means metric value is not set. */
} dmetric [ZEBRA_ROUTE_MAX + 1];
+ /* Redistribute tag info. */
+ u_short dtag [ZEBRA_ROUTE_MAX + 1];
+
/* For redistribute route map. */
struct
{
@@ -299,10 +304,6 @@ struct ospf_area
/* Configured variables. */
int external_routing; /* ExternalRoutingCapability. */
-#define OSPF_AREA_DEFAULT 0
-#define OSPF_AREA_STUB 1
-#define OSPF_AREA_NSSA 2
-#define OSPF_AREA_TYPE_MAX 3
int no_summary; /* Don't inject summaries into stub.*/
int shortcut_configured; /* Area configured as shortcut. */
#define OSPF_SHORTCUT_DEFAULT 0
diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c
index 37a986c5..e04e43d4 100644
--- a/ripd/rip_routemap.c
+++ b/ripd/rip_routemap.c
@@ -58,10 +58,10 @@ rip_route_match_add (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% RIP Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% RIP Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -81,10 +81,10 @@ rip_route_match_delete (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% RIP Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% RIP Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -104,7 +104,7 @@ rip_route_set_add (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% RIP Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
/* rip, ripng and other protocols share the set metric command
@@ -112,7 +112,7 @@ rip_route_set_add (struct vty *vty, struct route_map_index *index,
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);
+ vty_out (vty, "%% RIP Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -133,10 +133,10 @@ rip_route_set_delete (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% RIP Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% RIP Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -485,9 +485,22 @@ static void *
route_match_tag_compile (const char *arg)
{
u_short *tag;
+ u_short tmp;
+
+ /* tag value shoud be integer. */
+ if (! all_digit (arg))
+ return NULL;
+
+ tmp = atoi(arg);
+ if (tmp < 1)
+ return NULL;
tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
- *tag = atoi (arg);
+
+ if (!tag)
+ return tag;
+
+ *tag = tmp;
return tag;
}
@@ -937,7 +950,7 @@ ALIAS (no_match_ip_address_prefix_list,
DEFUN (match_tag,
match_tag_cmd,
- "match tag <0-65535>",
+ "match tag <1-65535>",
MATCH_STR
"Match tag of route\n"
"Metric value\n")
@@ -960,7 +973,7 @@ DEFUN (no_match_tag,
ALIAS (no_match_tag,
no_match_tag_val_cmd,
- "no match tag <0-65535>",
+ "no match tag <1-65535>",
NO_STR
MATCH_STR
"Match tag of route\n"
@@ -1000,11 +1013,18 @@ DEFUN (no_set_metric,
ALIAS (no_set_metric,
no_set_metric_val_cmd,
- "no set metric (<0-4294967295>|<+/-metric>)",
+ "no set metric <0-4294967295>",
+ NO_STR
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n")
+
+ALIAS (no_set_metric,
+ no_set_metric_addsub_cmd,
+ "no set metric <+/-metric>",
NO_STR
SET_STR
"Metric value for destination routing protocol\n"
- "Metric value\n"
"Add or subtract metric\n")
DEFUN (set_ip_nexthop,
@@ -1053,7 +1073,7 @@ ALIAS (no_set_ip_nexthop,
DEFUN (set_tag,
set_tag_cmd,
- "set tag <0-65535>",
+ "set tag <1-65535>",
SET_STR
"Tag value for routing protocol\n"
"Tag value\n")
@@ -1076,7 +1096,7 @@ DEFUN (no_set_tag,
ALIAS (no_set_tag,
no_set_tag_val_cmd,
- "no set tag <0-65535>",
+ "no set tag <1-65535>",
NO_STR
SET_STR
"Tag value for routing protocol\n"
@@ -1135,6 +1155,7 @@ rip_route_map_init ()
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, &no_set_metric_addsub_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);
diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c
index f4fadb67..eae4566a 100644
--- a/ripngd/ripng_routemap.c
+++ b/ripngd/ripng_routemap.c
@@ -55,10 +55,10 @@ ripng_route_match_add (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -77,10 +77,10 @@ ripng_route_match_delete (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -99,10 +99,10 @@ ripng_route_set_add (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -121,10 +121,10 @@ ripng_route_set_delete (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -564,7 +564,7 @@ ALIAS (no_match_interface,
DEFUN (match_tag,
match_tag_cmd,
- "match tag <0-65535>",
+ "match tag <1-65535>",
MATCH_STR
"Match tag of route\n"
"Metric value\n")
@@ -587,7 +587,7 @@ DEFUN (no_match_tag,
ALIAS (no_match_tag,
no_match_tag_val_cmd,
- "no match tag <0-65535>",
+ "no match tag <1-65535>",
NO_STR
MATCH_STR
"Match tag of route\n"
@@ -675,7 +675,7 @@ ALIAS (no_set_ipv6_nexthop_local,
DEFUN (set_tag,
set_tag_cmd,
- "set tag <0-65535>",
+ "set tag <1-65535>",
SET_STR
"Tag value for routing protocol\n"
"Tag value\n")
@@ -698,7 +698,7 @@ DEFUN (no_set_tag,
ALIAS (no_set_tag,
no_set_tag_val_cmd,
- "no set tag <0-65535>",
+ "no set tag <1-65535>",
NO_STR
SET_STR
"Tag value for routing protocol\n"
diff --git a/tests/aspath_test.c b/tests/aspath_test.c
index 5a0899ec..d75cf9c4 100644
--- a/tests/aspath_test.c
+++ b/tests/aspath_test.c
@@ -25,6 +25,7 @@
#include "stream.h"
#include "privs.h"
#include "filter.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h"
diff --git a/tests/bgp_capability_test.c b/tests/bgp_capability_test.c
index a3813518..c53b0590 100644
--- a/tests/bgp_capability_test.c
+++ b/tests/bgp_capability_test.c
@@ -26,6 +26,7 @@
#include "privs.h"
#include "memory.h"
#include "filter.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_open.h"
@@ -635,15 +636,11 @@ main (void)
struct peer *peer;
int i, j;
- conf_bgp_debug_fsm = -1UL;
- conf_bgp_debug_events = -1UL;
+ conf_bgp_debug_neighbor_events = -1UL;
conf_bgp_debug_packet = -1UL;
- conf_bgp_debug_normal = -1UL;
conf_bgp_debug_as4 = -1UL;
- term_bgp_debug_fsm = -1UL;
- term_bgp_debug_events = -1UL;
+ term_bgp_debug_neighbor_events = -1UL;
term_bgp_debug_packet = -1UL;
- term_bgp_debug_normal = -1UL;
term_bgp_debug_as4 = -1UL;
master = thread_master_create ();
diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c
index 5400dd17..2df2a2e6 100644
--- a/tests/bgp_mp_attr_test.c
+++ b/tests/bgp_mp_attr_test.c
@@ -26,6 +26,7 @@
#include "privs.h"
#include "memory.h"
#include "filter.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
@@ -742,15 +743,11 @@ main (void)
struct peer *peer;
int i, j;
- conf_bgp_debug_fsm = -1UL;
- conf_bgp_debug_events = -1UL;
+ conf_bgp_debug_neighbor_events = -1UL;
conf_bgp_debug_packet = -1UL;
- conf_bgp_debug_normal = -1UL;
conf_bgp_debug_as4 = -1UL;
- term_bgp_debug_fsm = -1UL;
- term_bgp_debug_events = -1UL;
+ term_bgp_debug_neighbor_events = -1UL;
term_bgp_debug_packet = -1UL;
- term_bgp_debug_normal = -1UL;
term_bgp_debug_as4 = -1UL;
master = thread_master_create ();
diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c
index 174d2998..75797147 100644
--- a/tests/bgp_mpath_test.c
+++ b/tests/bgp_mpath_test.c
@@ -158,9 +158,9 @@ run_bgp_cfg_maximum_paths (testcase_t *t)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
{
/* test bgp_maximum_paths_set */
- api_result = bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_EBGP, 10);
+ api_result = bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_EBGP, 10, 0);
EXPECT_TRUE (api_result == 0, test_result);
- api_result = bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_IBGP, 10);
+ api_result = bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_IBGP, 10, 0);
EXPECT_TRUE (api_result == 0, test_result);
EXPECT_TRUE (bgp->maxpaths[afi][safi].maxpaths_ebgp == 10, test_result);
EXPECT_TRUE (bgp->maxpaths[afi][safi].maxpaths_ibgp == 10, test_result);
diff --git a/tests/ecommunity_test.c b/tests/ecommunity_test.c
index 23ee4058..ac2f5d00 100644
--- a/tests/ecommunity_test.c
+++ b/tests/ecommunity_test.c
@@ -25,6 +25,7 @@
#include "privs.h"
#include "memory.h"
#include "filter.h"
+#include "linklist.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index ca869b64..65de23f7 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -45,7 +45,7 @@ $ignore{'"router zebra"'} = "ignore";
$ignore{'"address-family ipv4"'} = "ignore";
$ignore{'"address-family ipv4 (unicast|multicast)"'} = "ignore";
$ignore{'"address-family ipv6"'} = "ignore";
-$ignore{'"address-family ipv6 unicast"'} = "ignore";
+$ignore{'"address-family ipv6 (unicast|multicast)"'} = "ignore";
$ignore{'"address-family vpnv4"'} = "ignore";
$ignore{'"address-family vpnv4 unicast"'} = "ignore";
$ignore{'"address-family ipv4 vrf NAME"'} = "ignore";
@@ -180,7 +180,7 @@ foreach (@ARGV) {
}
}
-my $bad_cli_stomps = 89;
+my $bad_cli_stomps = 105;
# Currently we have $bad_cli_stomps. This was determined by
# running this script and counting up the collisions from what
# was returned.
@@ -220,7 +220,7 @@ foreach (keys %live) {
# Output install_element
print <<EOF;
void
-vtysh_init_cmd ()
+vtysh_init_cmd (void)
{
EOF
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 63b596a5..0d585f55 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -34,6 +34,9 @@
#include "memory.h"
#include "vtysh/vtysh.h"
#include "log.h"
+#include "filter.h"
+#include "linklist.h"
+#include "prefix.h"
#include "bgpd/bgp_vty.h"
#include "vrf.h"
@@ -423,6 +426,157 @@ vtysh_execute (const char *line)
return vtysh_execute_func (line, 1);
}
+int
+vtysh_mark_file (const char *filename)
+{
+ struct vty *vty;
+ FILE *confp = NULL;
+ int ret;
+ vector vline;
+ int tried = 0;
+ struct cmd_element *cmd;
+ int saved_ret, prev_node;
+ int lineno = 0;
+
+ if (strncmp("-", filename, 1) == 0)
+ confp = stdin;
+ else
+ confp = fopen (filename, "r");
+
+ if (confp == NULL)
+ return (1);
+
+ vty = vty_new ();
+ vty->fd = 0; /* stdout */
+ vty->type = VTY_TERM;
+ vty->node = CONFIG_NODE;
+
+ vtysh_execute_no_pager ("enable");
+ vtysh_execute_no_pager ("configure terminal");
+
+ while (fgets (vty->buf, VTY_BUFSIZ, confp))
+ {
+ lineno++;
+ tried = 0;
+
+ if (vty->buf[0] == '!' || vty->buf[1] == '#')
+ {
+ fprintf(stdout, "%s", vty->buf);
+ continue;
+ }
+
+ /* Split readline string up into the vector. */
+ vline = cmd_make_strvec (vty->buf);
+
+ if (vline == NULL)
+ {
+ fprintf(stdout, "%s", vty->buf);
+ continue;
+ }
+
+ prev_node = vty->node;
+ saved_ret = ret = cmd_execute_command_strict (vline, vty, &cmd);
+
+ /* If command doesn't succeeded in current node, try to walk up in node tree.
+ * Changing vty->node is enough to try it just out without actual walkup in
+ * the vtysh. */
+ while (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON && ret != CMD_WARNING
+ && vty->node > CONFIG_NODE)
+ {
+ vty->node = node_parent(vty->node);
+ ret = cmd_execute_command_strict (vline, vty, &cmd);
+ tried++;
+ }
+
+ /* If command succeeded in any other node than current (tried > 0) we have
+ * to move into node in the vtysh where it succeeded. */
+ if (ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON || ret == CMD_WARNING)
+ {
+ if ((prev_node == BGP_VPNV4_NODE || prev_node == BGP_IPV4_NODE
+ || prev_node == BGP_IPV6_NODE || prev_node == BGP_IPV4M_NODE
+ || prev_node == BGP_IPV6M_NODE)
+ && (tried == 1))
+ {
+ fprintf(stdout, "exit-address-family\n");
+ }
+ else if ((prev_node == KEYCHAIN_KEY_NODE) && (tried == 1))
+ {
+ fprintf(stdout, "exit\n");
+ }
+ else if (tried)
+ {
+ fprintf(stdout, "end\n");
+ }
+ }
+ /* If command didn't succeed in any node, continue with return value from
+ * first try. */
+ else if (tried)
+ {
+ ret = saved_ret;
+ vty->node = prev_node;
+ }
+
+ cmd_free_strvec (vline);
+ switch (ret)
+ {
+ case CMD_WARNING:
+ if (vty->type == VTY_FILE)
+ fprintf (stderr,"line %d: Warning...: %s\n", lineno, vty->buf);
+ fclose(confp);
+ vty_close(vty);
+ return (1);
+ case CMD_ERR_AMBIGUOUS:
+ fprintf (stderr,"line %d: %% Ambiguous command: %s\n", lineno, vty->buf);
+ fclose(confp);
+ vty_close(vty);
+ return(1);
+ case CMD_ERR_NO_MATCH:
+ fprintf (stderr,"line %d: %% Unknown command: %s\n", lineno, vty->buf);
+ fclose(confp);
+ vty_close(vty);
+ return(1);
+ case CMD_ERR_INCOMPLETE:
+ fprintf (stderr,"line %d: %% Command incomplete: %s\n", lineno, vty->buf);
+ fclose(confp);
+ vty_close(vty);
+ return(1);
+ case CMD_SUCCESS:
+ fprintf(stdout, "%s", vty->buf);
+ break;
+ case CMD_SUCCESS_DAEMON:
+ {
+ u_int i;
+ int cmd_stat = CMD_SUCCESS;
+
+ fprintf(stdout, "%s", vty->buf);
+ for (i = 0; i < array_size(vtysh_client); i++)
+ {
+ if (cmd->daemon & vtysh_client[i].flag)
+ {
+ cmd_stat = vtysh_client_execute (&vtysh_client[i],
+ vty->buf, stdout);
+ if (cmd_stat != CMD_SUCCESS)
+ break;
+ }
+ }
+ if (cmd_stat != CMD_SUCCESS)
+ break;
+
+ if (cmd->func)
+ (*cmd->func) (cmd, vty, 0, NULL);
+ }
+ }
+ }
+ /* This is the end */
+ fprintf(stdout, "end\n");
+ vty_close(vty);
+
+ if (confp != stdin)
+ fclose(confp);
+
+ return (0);
+}
+
/* Configration make from file. */
int
vtysh_config_from_file (struct vty *vty, FILE *fp)
@@ -441,13 +595,13 @@ vtysh_config_from_file (struct vty *vty, FILE *fp)
fprintf (stdout,"Warning...\n");
break;
case CMD_ERR_AMBIGUOUS:
- fprintf (stdout,"%% Ambiguous command.\n");
+ fprintf (stdout,"%% Ambiguous command: %s\n", vty->buf);
break;
case CMD_ERR_NO_MATCH:
fprintf (stdout,"%% Unknown command: %s", vty->buf);
break;
case CMD_ERR_INCOMPLETE:
- fprintf (stdout,"%% Command incomplete.\n");
+ fprintf (stdout,"%% Command incomplete: %s\n", vty->buf);
break;
case CMD_SUCCESS_DAEMON:
{
@@ -1897,6 +2051,7 @@ write_config_integrated(void)
for (i = 0; i < array_size(vtysh_client); i++)
vtysh_client_execute (&vtysh_client[i], line, NULL);
+ vtysh_config_write ();
vtysh_config_dump (fp);
fclose (fp);
@@ -2500,6 +2655,7 @@ vtysh_init_vty (void)
#ifdef HAVE_IPV6
install_element (BGP_NODE, &address_family_ipv6_cmd);
install_element (BGP_NODE, &address_family_ipv6_unicast_cmd);
+ install_element (BGP_NODE, &address_family_ipv6_multicast_cmd);
#endif
install_element (BGP_VPNV4_NODE, &exit_address_family_cmd);
install_element (BGP_VPNV6_NODE, &exit_address_family_cmd);
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index 1681a71a..9f8fb238 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -53,7 +53,9 @@ void vtysh_config_write (void);
int vtysh_config_from_file (struct vty *, FILE *);
-int vtysh_read_config (char *);
+int vtysh_mark_file(const char *filename);
+
+int vtysh_read_config (const char *);
void vtysh_config_parse (char *);
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index a069164b..4c972460 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -397,7 +397,7 @@ vtysh_read_file (FILE *confp)
/* Read up configuration file from config_default_dir. */
int
-vtysh_read_config (char *config_default_dir)
+vtysh_read_config (const char *config_default_dir)
{
FILE *confp = NULL;
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index 02a19b7c..8ed69e05 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -135,8 +135,10 @@ usage (int status)
"-b, --boot Execute boot startup configuration\n" \
"-c, --command Execute argument as command\n" \
"-d, --daemon Connect only to the specified daemon\n" \
+ "-f, --inputfile Execute commands from specific file and exit\n" \
"-E, --echo Echo prompt and command in -c mode\n" \
"-C, --dryrun Check configuration for validity and exit\n" \
+ "-m, --markfile Mark input file with context end\n"
"-h, --help Display this help and exit\n\n" \
"Note that multiple commands may be executed from the command\n" \
"line by passing multiple -c args, or by embedding linefeed\n" \
@@ -154,10 +156,12 @@ struct option longopts[] =
{ "eval", required_argument, NULL, 'e'},
{ "command", required_argument, NULL, 'c'},
{ "daemon", required_argument, NULL, 'd'},
+ { "inputfile", required_argument, NULL, 'f'},
{ "echo", no_argument, NULL, 'E'},
{ "dryrun", no_argument, NULL, 'C'},
{ "help", no_argument, NULL, 'h'},
{ "noerror", no_argument, NULL, 'n'},
+ { "mark", no_argument, NULL, 'm'},
{ 0 }
};
@@ -216,6 +220,7 @@ main (int argc, char **argv, char **env)
int dryrun = 0;
int boot_flag = 0;
const char *daemon_name = NULL;
+ const char *inputfile = NULL;
struct cmd_rec {
const char *line;
struct cmd_rec *next;
@@ -224,6 +229,7 @@ main (int argc, char **argv, char **env)
int echo_command = 0;
int no_error = 0;
char *homedir = NULL;
+ int markfile = 0;
/* Preserve name of myself. */
progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
@@ -235,7 +241,7 @@ main (int argc, char **argv, char **env)
/* Option handling. */
while (1)
{
- opt = getopt_long (argc, argv, "be:c:d:nEhC", longopts, 0);
+ opt = getopt_long (argc, argv, "be:c:d:nf:mEhC", longopts, 0);
if (opt == EOF)
break;
@@ -264,6 +270,12 @@ main (int argc, char **argv, char **env)
case 'd':
daemon_name = optarg;
break;
+ case 'f':
+ inputfile = optarg;
+ break;
+ case 'm':
+ markfile = 1;
+ break;
case 'n':
no_error = 1;
break;
@@ -298,12 +310,28 @@ main (int argc, char **argv, char **env)
vty_init_vtysh ();
/* Read vtysh configuration file before connecting to daemons. */
- vtysh_read_config (config_default);
+ vtysh_read_config(config_default);
+
+ if (markfile)
+ {
+ if (!inputfile)
+ {
+ fprintf(stderr, "-f option MUST be specified with -m option\n");
+ return(1);
+ }
+ return(vtysh_mark_file(inputfile));
+ }
/* Start execution only if not in dry-run mode */
if(dryrun)
- return(0);
-
+ {
+ if (inputfile)
+ {
+ vtysh_read_config(inputfile);
+ }
+ return(0);
+ }
+
/* Ignore error messages */
if (no_error)
freopen("/dev/null", "w", stdout);
@@ -339,6 +367,12 @@ main (int argc, char **argv, char **env)
}
}
+ if (inputfile)
+ {
+ vtysh_read_config(inputfile);
+ exit(0);
+ }
+
/* If eval mode. */
if (cmd)
{
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
index 90ce7b97..0210b81e 100644
--- a/zebra/Makefile.am
+++ b/zebra/Makefile.am
@@ -30,17 +30,17 @@ zebra_SOURCES = \
zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \
redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \
irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \
- $(othersrc)
+ $(othersrc) zebra_rnh.c
testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
- zebra_vty.c \
- kernel_null.c redistribute_null.c ioctl_null.c misc_null.c
+ zebra_vty.c zebra_routemap.c \
+ kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c
noinst_HEADERS = \
connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \
interface.h ipforward.h irdp.h router-id.h kernel_socket.h \
rt_netlink.h zebra_fpm.h zebra_fpm_private.h \
- ioctl_solaris.h
+ ioctl_solaris.h zebra_rnh.h
zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP)
diff --git a/zebra/connected.c b/zebra/connected.c
index 84b0d1cb..f2f523fa 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -30,6 +30,7 @@
#include "table.h"
#include "log.h"
#include "memory.h"
+#include "vty.h"
#include "zebra/zserv.h"
#include "zebra/redistribute.h"
@@ -77,7 +78,15 @@ connected_announce (struct interface *ifp, struct connected *ifc)
{
if (!ifc)
return;
-
+
+ if (!if_is_loopback(ifp) && ifc->address->family == AF_INET)
+ {
+ if (ifc->address->prefixlen == 32)
+ SET_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED);
+ else
+ UNSET_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED);
+ }
+
listnode_add (ifp->connected, ifc);
/* Update interface address information to protocol daemon. */
@@ -209,6 +218,9 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
struct prefix_ipv4 *p;
struct connected *ifc;
+ if (ipv4_martian(addr))
+ return;
+
/* Make connected structure. */
ifc = connected_new ();
ifc->ifp = ifp;
@@ -370,6 +382,9 @@ connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
struct prefix_ipv6 *p;
struct connected *ifc;
+ if (ipv6_martian(addr))
+ return;
+
/* Make connected structure. */
ifc = connected_new ();
ifc->ifp = ifp;
@@ -464,4 +479,20 @@ connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
rib_update (ifp->vrf_id);
}
+
+int
+connected_is_unnumbered (struct interface *ifp)
+{
+ struct connected *connected;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
+ {
+ if (CHECK_FLAG (connected->conf, ZEBRA_IFC_REAL) &&
+ connected->address->family == AF_INET)
+ return CHECK_FLAG(connected->flags, ZEBRA_IFA_UNNUMBERED);
+ }
+ return 0;
+}
+
#endif /* HAVE_IPV6 */
diff --git a/zebra/connected.h b/zebra/connected.h
index 9595ddb1..c589bd67 100644
--- a/zebra/connected.h
+++ b/zebra/connected.h
@@ -52,4 +52,5 @@ extern void connected_down_ipv6 (struct interface *ifp, struct connected *);
#endif /* HAVE_IPV6 */
+extern int connected_is_unnumbered (struct interface *);
#endif /*_ZEBRA_CONNECTED_H */
diff --git a/zebra/debug.c b/zebra/debug.c
index 537c4766..fbeef52b 100644
--- a/zebra/debug.c
+++ b/zebra/debug.c
@@ -30,6 +30,7 @@ unsigned long zebra_debug_packet;
unsigned long zebra_debug_kernel;
unsigned long zebra_debug_rib;
unsigned long zebra_debug_fpm;
+unsigned long zebra_debug_nht;
DEFUN (show_debugging_zebra,
show_debugging_zebra_cmd,
@@ -74,6 +75,8 @@ DEFUN (show_debugging_zebra,
if (IS_ZEBRA_DEBUG_FPM)
vty_out (vty, " Zebra FPM debugging is on%s", VTY_NEWLINE);
+ if (IS_ZEBRA_DEBUG_NHT)
+ vty_out (vty, " Zebra next-hop tracking debugging is on%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -89,6 +92,17 @@ DEFUN (debug_zebra_events,
return CMD_WARNING;
}
+DEFUN (debug_zebra_nht,
+ debug_zebra_nht_cmd,
+ "debug zebra nht",
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra next hop tracking\n")
+{
+ zebra_debug_nht = ZEBRA_DEBUG_NHT;
+ return CMD_WARNING;
+}
+
DEFUN (debug_zebra_packet,
debug_zebra_packet_cmd,
"debug zebra packet",
@@ -197,6 +211,18 @@ DEFUN (no_debug_zebra_events,
return CMD_SUCCESS;
}
+DEFUN (no_debug_zebra_nht,
+ no_debug_zebra_nht_cmd,
+ "no debug zebra nht",
+ NO_STR
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra next hop tracking\n")
+{
+ zebra_debug_nht = 0;
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_zebra_packet,
no_debug_zebra_packet_cmd,
"no debug zebra packet",
@@ -353,6 +379,7 @@ zebra_debug_init (void)
install_element (ENABLE_NODE, &show_debugging_zebra_cmd);
install_element (ENABLE_NODE, &debug_zebra_events_cmd);
+ install_element (ENABLE_NODE, &debug_zebra_nht_cmd);
install_element (ENABLE_NODE, &debug_zebra_packet_cmd);
install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd);
install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd);
@@ -361,6 +388,7 @@ zebra_debug_init (void)
install_element (ENABLE_NODE, &debug_zebra_rib_q_cmd);
install_element (ENABLE_NODE, &debug_zebra_fpm_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_events_cmd);
+ install_element (ENABLE_NODE, &no_debug_zebra_nht_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_rib_cmd);
@@ -368,6 +396,7 @@ zebra_debug_init (void)
install_element (ENABLE_NODE, &no_debug_zebra_fpm_cmd);
install_element (CONFIG_NODE, &debug_zebra_events_cmd);
+ install_element (CONFIG_NODE, &debug_zebra_nht_cmd);
install_element (CONFIG_NODE, &debug_zebra_packet_cmd);
install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd);
install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd);
@@ -376,6 +405,7 @@ zebra_debug_init (void)
install_element (CONFIG_NODE, &debug_zebra_rib_q_cmd);
install_element (CONFIG_NODE, &debug_zebra_fpm_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_events_cmd);
+ install_element (CONFIG_NODE, &no_debug_zebra_nht_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_rib_cmd);
diff --git a/zebra/debug.h b/zebra/debug.h
index d9231a22..0fb4dd9f 100644
--- a/zebra/debug.h
+++ b/zebra/debug.h
@@ -37,6 +37,7 @@
#define ZEBRA_DEBUG_RIB_Q 0x02
#define ZEBRA_DEBUG_FPM 0x01
+#define ZEBRA_DEBUG_NHT 0x01
/* Debug related macro. */
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
@@ -52,12 +53,14 @@
#define IS_ZEBRA_DEBUG_RIB_Q (zebra_debug_rib & ZEBRA_DEBUG_RIB_Q)
#define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM)
+#define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT)
extern unsigned long zebra_debug_event;
extern unsigned long zebra_debug_packet;
extern unsigned long zebra_debug_kernel;
extern unsigned long zebra_debug_rib;
extern unsigned long zebra_debug_fpm;
+extern unsigned long zebra_debug_nht;
extern void zebra_debug_init (void);
diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c
index 8df877db..99328a1d 100644
--- a/zebra/if_ioctl.c
+++ b/zebra/if_ioctl.c
@@ -30,6 +30,7 @@
#include "memory.h"
#include "log.h"
#include "vrf.h"
+#include "vty.h"
#include "zebra/interface.h"
#include "zebra/rib.h"
diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c
index 50b4aca6..b399812e 100644
--- a/zebra/if_ioctl_solaris.c
+++ b/zebra/if_ioctl_solaris.c
@@ -31,6 +31,7 @@
#include "log.h"
#include "privs.h"
#include "vrf.h"
+#include "vty.h"
#include "zebra/interface.h"
#include "zebra/ioctl_solaris.h"
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 245b7b25..2d062e01 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -21,6 +21,7 @@
*/
#include <zebra.h>
+#include <vty.h>
#include "zebra/zserv.h"
#include "rt_netlink.h"
diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c
index bb48f618..8c4761bb 100644
--- a/zebra/if_sysctl.c
+++ b/zebra/if_sysctl.c
@@ -29,6 +29,7 @@
#include "memory.h"
#include "ioctl.h"
#include "log.h"
+#include "vty.h"
#include "interface.h"
#include "vrf.h"
diff --git a/zebra/interface.c b/zebra/interface.c
index 8a9225ac..4ba92ba8 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -632,12 +632,30 @@ connected_dump_vty (struct vty *vty, struct connected *connected)
if (CHECK_FLAG (connected->flags, ZEBRA_IFA_SECONDARY))
vty_out (vty, " secondary");
+ if (CHECK_FLAG (connected->flags, ZEBRA_IFA_UNNUMBERED))
+ vty_out (vty, " unnumbered");
+
if (connected->label)
vty_out (vty, " %s", connected->label);
vty_out (vty, "%s", VTY_NEWLINE);
}
+/* Dump interface neighbor address information to vty. */
+static void
+nbr_connected_dump_vty (struct vty *vty, struct nbr_connected *connected)
+{
+ struct prefix *p;
+
+ /* Print interface address. */
+ p = connected->address;
+ vty_out (vty, " %s ", prefix_family_str (p));
+ prefix_vty_out (vty, p);
+ vty_out (vty, "/%d", p->prefixlen);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+}
+
#if defined (HAVE_RTADV)
/* Dump interface ND information to vty. */
static void
@@ -706,6 +724,7 @@ static void
if_dump_vty (struct vty *vty, struct interface *ifp)
{
struct connected *connected;
+ struct nbr_connected *nbr_connected;
struct listnode *node;
struct route_node *rn;
struct zebra_if *zebra_if;
@@ -793,6 +812,10 @@ if_dump_vty (struct vty *vty, struct interface *ifp)
#if defined (HAVE_RTADV)
nd_dump_vty (vty, ifp);
#endif /* HAVE_RTADV */
+ if (listhead(ifp->nbr_connected))
+ vty_out (vty, " Neighbor address(s):%s", VTY_NEWLINE);
+ for (ALL_LIST_ELEMENTS_RO (ifp->nbr_connected, node, nbr_connected))
+ nbr_connected_dump_vty (vty, nbr_connected);
#ifdef HAVE_PROC_NET_DEV
/* Statistics print out using proc file system. */
@@ -1381,6 +1404,12 @@ ip_address_install (struct vty *vty, struct interface *ifp,
return CMD_WARNING;
}
+ if (ipv4_martian(&cp.prefix))
+ {
+ vty_out (vty, "%% Invalid address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
ifc = connected_check (ifp, (struct prefix *) &cp);
if (! ifc)
{
@@ -1565,6 +1594,12 @@ ipv6_address_install (struct vty *vty, struct interface *ifp,
return CMD_WARNING;
}
+ if (ipv6_martian(&cp.prefix))
+ {
+ vty_out (vty, "%% Invalid address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
ifc = connected_check (ifp, (struct prefix *) &cp);
if (! ifc)
{
diff --git a/zebra/ioctl.c b/zebra/ioctl.c
index f7a7ff40..c3a1b603 100644
--- a/zebra/ioctl.c
+++ b/zebra/ioctl.c
@@ -28,6 +28,7 @@
#include "ioctl.h"
#include "log.h"
#include "privs.h"
+#include "vty.h"
#include "zebra/rib.h"
#include "zebra/rt.h"
diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c
index 12737cbf..b5bf1ccb 100644
--- a/zebra/ioctl_solaris.c
+++ b/zebra/ioctl_solaris.c
@@ -28,6 +28,7 @@
#include "ioctl.h"
#include "log.h"
#include "privs.h"
+#include "vty.h"
#include "zebra/rib.h"
#include "zebra/rt.h"
diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c
index 1a16a75a..3813e45a 100644
--- a/zebra/kernel_null.c
+++ b/zebra/kernel_null.c
@@ -23,6 +23,7 @@
#include <zebra.h>
#include <log.h>
+#include <vty.h>
#include "zebra/zserv.h"
#include "zebra/rt.h"
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 5e68c567..aee0cb55 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -34,6 +34,7 @@
#include "rib.h"
#include "privs.h"
#include "vrf.h"
+#include "vty.h"
#include "zebra/interface.h"
#include "zebra/zserv.h"
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 57b515e1..dd45af66 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -159,7 +159,10 @@ zebra_redistribute (struct zserv *client, int type, vrf_id_t vrf_id)
&& newrib->type == type
&& newrib->distance != DISTANCE_INFINITY
&& zebra_check_addr (&rn->p))
- zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib);
+ {
+ client->redist_v4_add_cnt++;
+ zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib);
+ }
}
#ifdef HAVE_IPV6
@@ -171,7 +174,10 @@ zebra_redistribute (struct zserv *client, int type, vrf_id_t vrf_id)
&& newrib->type == type
&& newrib->distance != DISTANCE_INFINITY
&& zebra_check_addr (&rn->p))
- zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib);
+ {
+ client->redist_v6_add_cnt++;
+ zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib);
+ }
#endif /* HAVE_IPV6 */
}
@@ -188,11 +194,15 @@ redistribute_add (struct prefix *p, struct rib *rib)
|| vrf_bitmap_check (client->redist[rib->type], rib->vrf_id))
{
if (p->family == AF_INET)
- zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib);
-#ifdef HAVE_IPV6
+ {
+ client->redist_v4_add_cnt++;
+ zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib);
+ }
if (p->family == AF_INET6)
- zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib);
-#endif /* HAVE_IPV6 */
+ {
+ client->redist_v6_add_cnt++;
+ zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib);
+ }
}
}
}
@@ -281,7 +291,9 @@ zebra_interface_up_update (struct interface *ifp)
zlog_debug ("MESSAGE: ZEBRA_INTERFACE_UP %s", ifp->name);
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
- zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp);
+ {
+ zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp);
+ }
}
/* Interface down information. */
@@ -295,7 +307,9 @@ zebra_interface_down_update (struct interface *ifp)
zlog_debug ("MESSAGE: ZEBRA_INTERFACE_DOWN %s", ifp->name);
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
- zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp);
+ {
+ zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp);
+ }
}
/* Interface information update. */
@@ -310,7 +324,10 @@ zebra_interface_add_update (struct interface *ifp)
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
if (client->ifinfo)
- zsend_interface_add (client, ifp);
+ {
+ client->ifadd_cnt++;
+ zsend_interface_add (client, ifp);
+ }
}
void
@@ -324,7 +341,10 @@ zebra_interface_delete_update (struct interface *ifp)
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
if (client->ifinfo)
- zsend_interface_delete (client, ifp);
+ {
+ client->ifdel_cnt++;
+ zsend_interface_delete (client, ifp);
+ }
}
/* Interface address addition. */
@@ -353,7 +373,10 @@ zebra_interface_address_add_update (struct interface *ifp,
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
- zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc);
+ {
+ client->connected_rt_add_cnt++;
+ zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc);
+ }
}
/* Interface address deletion. */
@@ -379,5 +402,8 @@ zebra_interface_address_delete_update (struct interface *ifp,
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
- zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc);
+ {
+ client->connected_rt_del_cnt++;
+ zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc);
+ }
}
diff --git a/zebra/redistribute_null.c b/zebra/redistribute_null.c
index c68cec6a..7a39de46 100644
--- a/zebra/redistribute_null.c
+++ b/zebra/redistribute_null.c
@@ -20,6 +20,7 @@
*/
#include <zebra.h>
+#include <vty.h>
#include "zebra/rib.h"
#include "zebra/zserv.h"
diff --git a/zebra/rib.h b/zebra/rib.h
index 1dacc7f7..a916aa99 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -27,18 +27,10 @@
#include "prefix.h"
#include "table.h"
#include "queue.h"
+#include "nexthop.h"
#define DISTANCE_INFINITY 255
-/* Routing information base. */
-
-union g_addr {
- struct in_addr ipv4;
-#ifdef HAVE_IPV6
- struct in6_addr ipv6;
-#endif /* HAVE_IPV6 */
-};
-
struct rib
{
/* Link list. */
@@ -73,6 +65,9 @@ struct rib
/* Distance. */
u_char distance;
+ /* Tag */
+ u_short tag;
+
/* Flags of this route.
* This flag's definition is in lib/zebra.h ZEBRA_FLAG_* and is exposed
* to clients via Zserv
@@ -81,9 +76,10 @@ struct rib
/* RIB internal status */
u_char status;
-#define RIB_ENTRY_REMOVED (1 << 0)
-#define RIB_ENTRY_CHANGED (1 << 1)
-#define RIB_ENTRY_SELECTED_FIB (1 << 2)
+#define RIB_ENTRY_REMOVED (1 << 0)
+ /* to simplify NHT logic when NHs change, instead of doing a NH by NH cmp */
+#define RIB_ENTRY_NEXTHOPS_CHANGED (1 << 1)
+#define RIB_ENTRY_SELECTED_FIB (1 << 2)
/* Nexthop information. */
u_char nexthop_num;
@@ -186,6 +182,9 @@ struct static_route
/* Administrative distance. */
u_char distance;
+ /* Tag */
+ u_short tag;
+
/* Flag for this static route's type. */
u_char type;
#define STATIC_IPV4_GATEWAY 1
@@ -207,50 +206,6 @@ struct static_route
*/
};
-enum nexthop_types_t
-{
- NEXTHOP_TYPE_IFINDEX = 1, /* Directly connected. */
- NEXTHOP_TYPE_IFNAME, /* Interface route. */
- NEXTHOP_TYPE_IPV4, /* IPv4 nexthop. */
- NEXTHOP_TYPE_IPV4_IFINDEX, /* IPv4 nexthop with ifindex. */
- NEXTHOP_TYPE_IPV4_IFNAME, /* IPv4 nexthop with ifname. */
- NEXTHOP_TYPE_IPV6, /* IPv6 nexthop. */
- NEXTHOP_TYPE_IPV6_IFINDEX, /* IPv6 nexthop with ifindex. */
- NEXTHOP_TYPE_IPV6_IFNAME, /* IPv6 nexthop with ifname. */
- NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */
-};
-
-/* Nexthop structure. */
-struct nexthop
-{
- struct nexthop *next;
- struct nexthop *prev;
-
- /* Interface index. */
- char *ifname;
- ifindex_t ifindex;
-
- enum nexthop_types_t type;
-
- u_char flags;
-#define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */
-#define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */
-#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */
-#define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */
-
- /* Nexthop address */
- union g_addr gate;
- union g_addr src;
-
- /* Nexthops obtained by recursive resolution.
- *
- * If the nexthop struct needs to be resolved recursively,
- * NEXTHOP_FLAG_RECURSIVE will be set in flags and the nexthops
- * obtained by recursive resolution will be added to `resolved'.
- * Only one level of recursive resolution is currently supported. */
- struct nexthop *resolved;
-};
-
/* The following for loop allows to iterate over the nexthop
* structure of routes.
*
@@ -297,15 +252,6 @@ struct nexthop
: ((tnexthop) = (nexthop)->next)) \
: (((recursing) = 0),((tnexthop) = (tnexthop)->next)))
-/* Structure holding nexthop & VRF identifier,
- * used for applying the route-map. */
-struct nexthop_vrfid
-{
- struct nexthop *nexthop;
- vrf_id_t vrf_id;
-};
-
-
#if defined (HAVE_RTADV)
/* Structure which hold status of router advertisement. */
struct rtadv
@@ -370,6 +316,9 @@ struct zebra_vrf
#if defined (HAVE_RTADV)
struct rtadv rtadv;
#endif /* HAVE_RTADV */
+
+ /* Recursive Nexthop table */
+ struct route_table *rnh_table[AFI_MAX];
};
/*
@@ -425,15 +374,19 @@ extern void multicast_mode_ipv4_set (enum multicast_mode mode);
extern enum multicast_mode multicast_mode_ipv4_get (void);
extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
-extern struct nexthop *nexthop_ifindex_add (struct rib *, ifindex_t);
-extern struct nexthop *nexthop_ifname_add (struct rib *, char *);
-extern struct nexthop *nexthop_blackhole_add (struct rib *);
-extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *,
- struct in_addr *);
-extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *,
- struct in_addr *,
- struct in_addr *,
- ifindex_t);
+extern struct nexthop *rib_nexthop_ifindex_add (struct rib *, ifindex_t);
+extern struct nexthop *rib_nexthop_ifname_add (struct rib *, char *);
+extern struct nexthop *rib_nexthop_blackhole_add (struct rib *);
+extern struct nexthop *rib_nexthop_ipv4_add (struct rib *, struct in_addr *,
+ struct in_addr *);
+extern struct nexthop *rib_nexthop_ipv4_ifindex_add (struct rib *,
+ struct in_addr *,
+ struct in_addr *,
+ ifindex_t);
+
+extern void rib_nexthop_add (struct rib *rib, struct nexthop *nexthop);
+extern void rib_copy_nexthops (struct rib *rib, struct nexthop *nexthop);
+
extern int nexthop_has_fib_child(struct nexthop *);
extern void rib_lookup_and_dump (struct prefix_ipv4 *);
extern void rib_lookup_and_pushup (struct prefix_ipv4 *);
@@ -448,8 +401,11 @@ extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *,
#define ZEBRA_RIB_FOUND_CONNECTED 2
#define ZEBRA_RIB_NOTFOUND 3
-extern struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *);
+extern struct nexthop *rib_nexthop_ipv6_add (struct rib *, struct in6_addr *);
+extern struct nexthop *rib_nexthop_ipv6_ifindex_add (struct rib *rib,
+ struct in6_addr *ipv6, ifindex_t ifindex);
+extern struct zebra_vrf *zebra_vrf_lookup (vrf_id_t vrf_id);
extern struct zebra_vrf *zebra_vrf_alloc (vrf_id_t);
extern struct route_table *zebra_vrf_table (afi_t, safi_t, vrf_id_t);
extern struct route_table *zebra_vrf_static_table (afi_t, safi_t, vrf_id_t);
@@ -469,7 +425,7 @@ extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
vrf_id_t, safi_t safi);
extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi,
- int skip_bgp, struct route_node **rn_out,
+ struct route_node **rn_out,
vrf_id_t);
extern struct rib *rib_match_ipv4_multicast (struct in_addr addr,
struct route_node **rn_out,
@@ -484,14 +440,17 @@ extern void rib_close_table (struct route_table *);
extern void rib_close (void);
extern void rib_init (void);
extern unsigned long rib_score_proto (u_char proto);
+struct zebra_t;
+extern void rib_queue_add (struct zebra_t *zebra, struct route_node *rn);
+
extern int
static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
- const char *ifname, u_char flags, u_char distance,
+ const char *ifname, u_char flags, u_short tag, u_char distance,
vrf_id_t vrf_id);
extern int
static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
- const char *ifname, u_char distance, vrf_id_t vrf_id);
+ const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id);
extern int
rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
@@ -511,12 +470,15 @@ extern struct route_table *rib_table_ipv6;
extern int
static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
- const char *ifname, u_char flags, u_char distance,
+ const char *ifname, u_char flags, u_short tag, u_char distance,
vrf_id_t vrf_id);
extern int
+rib_add_ipv6_multipath (struct prefix_ipv6 *, struct rib *, safi_t);
+
+extern int
static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
- const char *ifname, u_char distance, vrf_id_t vrf_id);
+ const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id);
extern int rib_gc_dest (struct route_node *rn);
extern struct route_table *rib_tables_iter_next (rib_tables_iter_t *iter);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index e4505de3..131b37a6 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -38,6 +38,8 @@
#include "thread.h"
#include "privs.h"
#include "vrf.h"
+#include "nexthop.h"
+#include "vty.h"
#include "zebra/zserv.h"
#include "zebra/rt.h"
@@ -851,12 +853,12 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
if (gate)
{
if (index)
- nexthop_ipv4_ifindex_add (rib, gate, src, index);
+ rib_nexthop_ipv4_ifindex_add (rib, gate, src, index);
else
- nexthop_ipv4_add (rib, gate, src);
+ rib_nexthop_ipv4_add (rib, gate, src);
}
else
- nexthop_ifindex_add (rib, index);
+ rib_nexthop_ifindex_add (rib, index);
len -= NLMSG_ALIGN(rtnh->rtnh_len);
rtnh = RTNH_NEXT(rtnh);
@@ -907,6 +909,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
int len;
struct rtmsg *rtm;
struct rtattr *tb[RTA_MAX + 1];
+ u_char zebra_flags = 0;
char anyaddr[16] = { 0 };
@@ -964,6 +967,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
return 0;
+ if (rtm->rtm_protocol == RTPROT_ZEBRA)
+ SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE);
if (rtm->rtm_src_len != 0)
{
@@ -1065,12 +1070,12 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
if (gate)
{
if (index)
- nexthop_ipv4_ifindex_add (rib, gate, src, index);
+ rib_nexthop_ipv4_ifindex_add (rib, gate, src, index);
else
- nexthop_ipv4_add (rib, gate, src);
+ rib_nexthop_ipv4_add (rib, gate, src);
}
else
- nexthop_ifindex_add (rib, index);
+ rib_nexthop_ifindex_add (rib, index);
len -= NLMSG_ALIGN(rtnh->rtnh_len);
rtnh = RTNH_NEXT(rtnh);
@@ -1083,8 +1088,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
}
}
else
- rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id,
- SAFI_UNICAST);
+ rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, gate,
+ index, vrf_id, SAFI_UNICAST);
}
#ifdef HAVE_IPV6
@@ -1108,7 +1113,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table,
0, mtu, 0, SAFI_UNICAST);
else
- rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id,
+ rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, gate, index, vrf_id,
SAFI_UNICAST);
}
#endif /* HAVE_IPV6 */
@@ -1470,7 +1475,8 @@ _netlink_route_build_singlepath(
struct nexthop *nexthop,
struct nlmsghdr *nlmsg,
struct rtmsg *rtmsg,
- size_t req_size)
+ size_t req_size,
+ int cmd)
{
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
rtmsg->rtm_flags |= RTNH_F_ONLINK;
@@ -1479,7 +1485,11 @@ _netlink_route_build_singlepath(
{
addattr_l (nlmsg, req_size, RTA_GATEWAY,
&nexthop->gate.ipv4, bytelen);
- if (nexthop->src.ipv4.s_addr)
+
+ if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
+ addattr_l (nlmsg, req_size, RTA_PREFSRC,
+ &nexthop->rmap_src.ipv4, bytelen);
+ else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
addattr_l (nlmsg, req_size, RTA_PREFSRC,
&nexthop->src.ipv4, bytelen);
@@ -1512,7 +1522,10 @@ _netlink_route_build_singlepath(
{
addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
- if (nexthop->src.ipv4.s_addr)
+ if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
+ addattr_l (nlmsg, req_size, RTA_PREFSRC,
+ &nexthop->rmap_src.ipv4, bytelen);
+ else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
addattr_l (nlmsg, req_size, RTA_PREFSRC,
&nexthop->src.ipv4, bytelen);
@@ -1573,8 +1586,10 @@ _netlink_route_build_multipath(
&nexthop->gate.ipv4, bytelen);
rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
- if (nexthop->src.ipv4.s_addr)
- *src = &nexthop->src;
+ if (nexthop->rmap_src.ipv4.s_addr)
+ *src = &nexthop->rmap_src;
+ else if (nexthop->src.ipv4.s_addr)
+ *src = &nexthop->src;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("netlink_route_multipath() (%s): "
@@ -1606,8 +1621,12 @@ _netlink_route_build_multipath(
|| nexthop->type == NEXTHOP_TYPE_IFNAME)
{
rtnh->rtnh_ifindex = nexthop->ifindex;
- if (nexthop->src.ipv4.s_addr)
+
+ if (nexthop->rmap_src.ipv4.s_addr)
+ *src = &nexthop->rmap_src;
+ else if (nexthop->src.ipv4.s_addr)
*src = &nexthop->src;
+
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("netlink_route_multipath() (%s): "
"nexthop via if %u", routedesc, nexthop->ifindex);
@@ -1670,6 +1689,8 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib)
int discard;
int family = PREFIX_FAMILY(p);
const char *routedesc;
+ int setsrc = 0;
+ union g_addr src;
struct
{
@@ -1708,6 +1729,10 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib)
req.r.rtm_type = RTN_UNREACHABLE;
else
assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s: Adding discard route for family %s\n",
+ __FUNCTION__, family == AF_INET ? "IPv4" : "IPv6");
}
else
req.r.rtm_type = RTN_UNICAST;
@@ -1773,7 +1798,23 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib)
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
{
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- continue;
+ {
+ /* This only works for IPv4 now */
+ if (!setsrc)
+ {
+ if (nexthop->rmap_src.ipv4.s_addr != 0)
+ {
+ src.ipv4 = nexthop->rmap_src.ipv4;
+ setsrc = 1;
+ }
+ else if (nexthop->src.ipv4.s_addr != 0)
+ {
+ src.ipv4 = nexthop->src.ipv4;
+ setsrc = 1;
+ }
+ }
+ continue;
+ }
if ((cmd == RTM_NEWROUTE
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
@@ -1785,7 +1826,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib)
_netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf);
_netlink_route_build_singlepath(routedesc, bytelen,
nexthop, &req.n, &req.r,
- sizeof req);
+ sizeof req, cmd);
if (cmd == RTM_NEWROUTE)
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
@@ -1794,13 +1835,15 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib)
break;
}
}
+ if (setsrc && (cmd == RTM_NEWROUTE))
+ addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen);
}
else
{
char buf[NL_PKT_BUF_SIZE];
struct rtattr *rta = (void *) buf;
struct rtnexthop *rtnh;
- union g_addr *src = NULL;
+ union g_addr *src1 = NULL;
rta->rta_type = RTA_MULTIPATH;
rta->rta_len = RTA_LENGTH (0);
@@ -1813,7 +1856,23 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib)
break;
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- continue;
+ {
+ /* This only works for IPv4 now */
+ if (!setsrc)
+ {
+ if (nexthop->rmap_src.ipv4.s_addr != 0)
+ {
+ src.ipv4 = nexthop->rmap_src.ipv4;
+ setsrc = 1;
+ }
+ else if (nexthop->src.ipv4.s_addr != 0)
+ {
+ src.ipv4 = nexthop->src.ipv4;
+ setsrc = 1;
+ }
+ }
+ continue;
+ }
if ((cmd == RTM_NEWROUTE
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
@@ -1826,15 +1885,21 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib)
_netlink_route_debug(cmd, p, nexthop,
routedesc, family, zvrf);
_netlink_route_build_multipath(routedesc, bytelen,
- nexthop, rta, rtnh, &src);
+ nexthop, rta, rtnh, &src1);
rtnh = RTNH_NEXT (rtnh);
if (cmd == RTM_NEWROUTE)
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ if (!setsrc && src1)
+ {
+ src.ipv4 = src1->ipv4;
+ setsrc = 1;
+ }
}
}
- if (src)
- addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
+ if (setsrc && (cmd == RTM_NEWROUTE))
+ addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen);
if (rta->rta_len > RTA_LENGTH (0))
addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 9450f9a9..8660f733 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -402,14 +402,83 @@ rtadv_process_solicit (struct interface *ifp)
}
static void
-rtadv_process_advert (void)
+rtadv_process_advert (u_char *msg, unsigned int len, struct interface *ifp,
+ struct sockaddr_in6 *addr)
{
- zlog_info ("Router advertisement received");
+ struct nd_router_advert *radvert;
+ char addr_str[INET6_ADDRSTRLEN];
+ struct zebra_if *zif;
+
+ zif = ifp->info;
+
+ inet_ntop (AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
+
+ zlog_info ("Router advertisement received on %s from : %s", ifp->name, addr_str);
+
+ if (len < sizeof(struct nd_router_advert)) {
+ zlog_warn("received icmpv6 RA packet with invalid length (%d) from %s",
+ len, addr_str);
+ return;
+ }
+ if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
+ zlog_warn("received icmpv6 RA packet with non-linklocal source address from %s",
+ addr_str);
+ return;
+ }
+
+ radvert = (struct nd_router_advert *) msg;
+
+ if ((radvert->nd_ra_curhoplimit && zif->rtadv.AdvCurHopLimit) &&
+ (radvert->nd_ra_curhoplimit != zif->rtadv.AdvCurHopLimit))
+ {
+ zlog_warn("our AdvCurHopLimit on %s doesn't agree with %s",
+ ifp->name, addr_str);
+ }
+
+ if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) &&
+ !zif->rtadv.AdvManagedFlag)
+ {
+ zlog_warn("our AdvManagedFlag on %s doesn't agree with %s",
+ ifp->name, addr_str);
+ }
+
+ if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) &&
+ !zif->rtadv.AdvOtherConfigFlag)
+ {
+ zlog_warn("our AdvOtherConfigFlag on %s doesn't agree with %s",
+ ifp->name, addr_str);
+ }
+
+ if ((radvert->nd_ra_reachable && zif->rtadv.AdvReachableTime) &&
+ (ntohl(radvert->nd_ra_reachable) != zif->rtadv.AdvReachableTime))
+ {
+ zlog_warn("our AdvReachableTime on %s doesn't agree with %s",
+ ifp->name, addr_str);
+ }
+
+ if ((radvert->nd_ra_retransmit && zif->rtadv.AdvRetransTimer) &&
+ (ntohl(radvert->nd_ra_retransmit) != (unsigned int)zif->rtadv.AdvRetransTimer))
+ {
+ zlog_warn("our AdvRetransTimer on %s doesn't agree with %s",
+ ifp->name, addr_str);
+ }
+
+ /* Currently supporting only P2P links, so any new RA source address is
+ considered as the replacement of the previously learnt Link-Local address.
+ As per the RFC, lifetime zero is to be considered a delete */
+ if (ntohs(radvert->nd_ra_router_lifetime))
+ nbr_connected_replacement_add_ipv6(ifp, &addr->sin6_addr, 128);
+ else
+ nbr_connected_delete_ipv6(ifp, &addr->sin6_addr, 128);
+
+ return;
}
+
static void
-rtadv_process_packet (u_char *buf, unsigned int len, ifindex_t ifindex,
- int hoplimit, vrf_id_t vrf_id)
+rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex,
+ int hoplimit, vrf_id_t vrf_id,
+ struct sockaddr_in6 *from)
{
struct icmp6_hdr *icmph;
struct interface *ifp;
@@ -460,7 +529,7 @@ rtadv_process_packet (u_char *buf, unsigned int len, ifindex_t ifindex,
if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
rtadv_process_solicit (ifp);
else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
- rtadv_process_advert ();
+ rtadv_process_advert (buf, len, ifp, from);
return;
}
@@ -490,7 +559,7 @@ rtadv_read (struct thread *thread)
return len;
}
- rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit, zvrf->vrf_id);
+ rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit, zvrf->vrf_id, &from);
return 0;
}
@@ -1539,8 +1608,6 @@ rtadv_config_write (struct vty *vty, struct interface *ifp)
{
if (zif->rtadv.AdvSendAdvertisements)
vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
- else
- vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
}
diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c
index 89153941..e1ec6709 100644
--- a/zebra/rtread_getmsg.c
+++ b/zebra/rtread_getmsg.c
@@ -26,6 +26,7 @@
#include "log.h"
#include "if.h"
#include "vrf.h"
+#include "vty.h"
#include "zebra/rib.h"
#include "zebra/zserv.h"
diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c
index 1f658646..a9d9c86c 100644
--- a/zebra/rtread_netlink.c
+++ b/zebra/rtread_netlink.c
@@ -21,6 +21,7 @@
*/
#include <zebra.h>
+#include <vty.h>
#include "zebra/zserv.h"
#include "rt_netlink.h"
diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c
index 385e1506..9108d2ca 100644
--- a/zebra/rtread_sysctl.c
+++ b/zebra/rtread_sysctl.c
@@ -25,6 +25,7 @@
#include "memory.h"
#include "log.h"
#include "vrf.h"
+#include "vty.h"
#include "zebra/zserv.h"
#include "zebra/rt.h"
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index 01730007..c53d282b 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -29,6 +29,7 @@
#include "rib.h"
#include "rt_netlink.h"
+#include "nexthop.h"
#include "zebra_fpm_private.h"
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 1650dabf..53691c76 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -35,13 +35,16 @@
#include "prefix.h"
#include "routemap.h"
#include "vrf.h"
+#include "nexthop.h"
+#include "zebra/connected.h"
#include "zebra/rib.h"
#include "zebra/rt.h"
#include "zebra/zserv.h"
#include "zebra/redistribute.h"
#include "zebra/debug.h"
#include "zebra/zebra_fpm.h"
+#include "zebra/zebra_rnh.h"
/* Default rtm_table for all clients */
extern struct zebra_t zebrad;
@@ -110,57 +113,38 @@ _rnode_zlog(const char *_func, struct route_node *rn, int priority,
#define rnode_info(node, ...) \
_rnode_zlog(__func__, node, LOG_INFO, __VA_ARGS__)
-/*
- * nexthop_type_to_str
- */
-const char *
-nexthop_type_to_str (enum nexthop_types_t nh_type)
-{
- static const char *desc[] = {
- "none",
- "Directly connected",
- "Interface route",
- "IPv4 nexthop",
- "IPv4 nexthop with ifindex",
- "IPv4 nexthop with ifname",
- "IPv6 nexthop",
- "IPv6 nexthop with ifindex",
- "IPv6 nexthop with ifname",
- "Null0 nexthop",
- };
-
- if (nh_type >= ZEBRA_NUM_OF (desc))
- return "<Invalid nh type>";
-
- return desc[nh_type];
-}
-
-/* Add nexthop to the end of a nexthop list. */
-static void
-_nexthop_add (struct nexthop **target, struct nexthop *nexthop)
+/* Add nexthop to the end of a rib node's nexthop list */
+void
+rib_nexthop_add (struct rib *rib, struct nexthop *nexthop)
{
- struct nexthop *last;
-
- for (last = *target; last && last->next; last = last->next)
- ;
- if (last)
- last->next = nexthop;
- else
- *target = nexthop;
- nexthop->prev = last;
+ nexthop_add(&rib->nexthop, nexthop);
+ rib->nexthop_num++;
}
-/* Add nexthop to the end of a rib node's nexthop list */
-static void
-nexthop_add (struct rib *rib, struct nexthop *nexthop)
+/**
+ * copy_nexthop - copy a nexthop to the rib structure.
+ */
+void
+rib_copy_nexthops (struct rib *rib, struct nexthop *nh)
{
- _nexthop_add(&rib->nexthop, nexthop);
- rib->nexthop_num++;
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->flags = nh->flags;
+ nexthop->type = nh->type;
+ nexthop->ifindex = nh->ifindex;
+ if (nh->ifname)
+ nexthop->ifname = XSTRDUP(0, nh->ifname);
+ memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
+ memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
+ rib_nexthop_add(rib, nexthop);
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
+ copy_nexthops(&nexthop->resolved, nh->resolved);
}
/* Delete specified nexthop from the list. */
static void
-nexthop_delete (struct rib *rib, struct nexthop *nexthop)
+rib_nexthop_delete (struct rib *rib, struct nexthop *nexthop)
{
if (nexthop->next)
nexthop->next->prev = nexthop->prev;
@@ -171,150 +155,130 @@ nexthop_delete (struct rib *rib, struct nexthop *nexthop)
rib->nexthop_num--;
}
-static void nexthops_free(struct nexthop *nexthop);
-
-/* Free nexthop. */
-static void
-nexthop_free (struct nexthop *nexthop)
-{
- if (nexthop->ifname)
- XFREE (0, nexthop->ifname);
- if (nexthop->resolved)
- nexthops_free(nexthop->resolved);
- XFREE (MTYPE_NEXTHOP, nexthop);
-}
-
-/* Frees a list of nexthops */
-static void
-nexthops_free (struct nexthop *nexthop)
-{
- struct nexthop *nh, *next;
-
- for (nh = nexthop; nh; nh = next)
- {
- next = nh->next;
- nexthop_free (nh);
- }
-}
-
struct nexthop *
-nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex)
+rib_nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IFINDEX;
nexthop->ifindex = ifindex;
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
struct nexthop *
-nexthop_ifname_add (struct rib *rib, char *ifname)
+rib_nexthop_ifname_add (struct rib *rib, char *ifname)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IFNAME;
nexthop->ifname = XSTRDUP (0, ifname);
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
struct nexthop *
-nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src)
+rib_nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IPV4;
nexthop->gate.ipv4 = *ipv4;
if (src)
nexthop->src.ipv4 = *src;
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
struct nexthop *
-nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
- struct in_addr *src, ifindex_t ifindex)
+rib_nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
+ struct in_addr *src, ifindex_t ifindex)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
nexthop->gate.ipv4 = *ipv4;
if (src)
nexthop->src.ipv4 = *src;
nexthop->ifindex = ifindex;
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
struct nexthop *
-nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6)
+rib_nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IPV6;
nexthop->gate.ipv6 = *ipv6;
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
static struct nexthop *
-nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6,
- char *ifname)
+rib_nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6,
+ char *ifname)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME;
nexthop->gate.ipv6 = *ipv6;
nexthop->ifname = XSTRDUP (0, ifname);
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
-static struct nexthop *
-nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6,
- ifindex_t ifindex)
+struct nexthop *
+rib_nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6,
+ ifindex_t ifindex)
{
struct nexthop *nexthop;
+ struct interface *ifp;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
nexthop->gate.ipv6 = *ipv6;
nexthop->ifindex = ifindex;
+ ifp = if_lookup_by_index (nexthop->ifindex);
+ if (connected_is_unnumbered(ifp))
+ {
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
+ }
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
struct nexthop *
-nexthop_blackhole_add (struct rib *rib)
+rib_nexthop_blackhole_add (struct rib *rib)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE);
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
@@ -348,8 +312,9 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
struct route_node *rn;
struct rib *match;
int resolved;
- struct nexthop *newhop;
+ struct nexthop *newhop, *tnewhop;
struct nexthop *resolved_hop;
+ int recursing = 0;
if (nexthop->type == NEXTHOP_TYPE_IPV4)
nexthop->ifindex = 0;
@@ -357,11 +322,18 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
if (set)
{
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ zebra_deregister_rnh_static_nexthops (nexthop->resolved, top);
nexthops_free(nexthop->resolved);
nexthop->resolved = NULL;
rib->nexthop_mtu = 0;
}
+ /* Skip nexthops that have been filtered out due to route-map */
+ /* The nexthops are specific to this route and so the same */
+ /* nexthop for a different route may not have this flag set */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED))
+ return 0;
+
/* Make lookup prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4));
p.family = AF_INET;
@@ -393,8 +365,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
/* If there is no selected route or matched route is EGP, go up
tree. */
- if (! match
- || match->type == ZEBRA_ROUTE_BGP)
+ if (! match)
{
do {
rn = rn->parent;
@@ -429,6 +400,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
if (set)
{
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ SET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -455,7 +427,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
resolved_hop->ifindex = newhop->ifindex;
}
- _nexthop_add(&nexthop->resolved, resolved_hop);
+ nexthop_add(&nexthop->resolved, resolved_hop);
}
resolved = 1;
}
@@ -463,6 +435,57 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
rib->nexthop_mtu = match->mtu;
return resolved;
}
+ else if (rib->type == ZEBRA_ROUTE_STATIC)
+ {
+ resolved = 0;
+ for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing))
+ if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
+ {
+ if (set)
+ {
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+
+ resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
+ SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
+ /* If the resolving route specifies a gateway, use it */
+ if (newhop->type == NEXTHOP_TYPE_IPV4
+ || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IPV4_IFNAME)
+ {
+ resolved_hop->type = newhop->type;
+ resolved_hop->gate.ipv4 = newhop->gate.ipv4;
+
+ if (newhop->ifindex)
+ {
+ resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ resolved_hop->ifindex = newhop->ifindex;
+ }
+ }
+
+ /* If the resolving route is an interface route,
+ * it means the gateway we are looking up is connected
+ * to that interface. (The actual network is _not_ onlink).
+ * Therefore, the resolved route should have the original
+ * gateway as nexthop as it is directly connected.
+ *
+ * On Linux, we have to set the onlink netlink flag because
+ * otherwise, the kernel won't accept the route.
+ */
+ if (newhop->type == NEXTHOP_TYPE_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IFNAME)
+ {
+ resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
+ resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
+ resolved_hop->ifindex = newhop->ifindex;
+ }
+
+ nexthop_add(&nexthop->resolved, resolved_hop);
+ }
+ resolved = 1;
+ }
+ return resolved;
+ }
else
{
return 0;
@@ -483,8 +506,10 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
struct route_node *rn;
struct rib *match;
int resolved;
- struct nexthop *newhop;
+ struct nexthop *newhop, *tnewhop;
+ int recursing = 0;
struct nexthop *resolved_hop;
+ struct interface *ifp;
if (nexthop->type == NEXTHOP_TYPE_IPV6)
nexthop->ifindex = 0;
@@ -492,10 +517,36 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
if (set)
{
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ zebra_deregister_rnh_static_nexthops (nexthop->resolved, top);
nexthops_free(nexthop->resolved);
nexthop->resolved = NULL;
}
+ /* Skip nexthops that have been filtered out due to route-map */
+ /* The nexthops are specific to this route and so the same */
+ /* nexthop for a different route may not have this flag set */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED))
+ return 0;
+
+ /*
+ * Check to see if we should trust the passed in information
+ * for UNNUMBERED interfaces as that we won't find the GW
+ * address in the routing table.
+ */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
+ {
+ ifp = if_lookup_by_index (nexthop->ifindex);
+ if (ifp && connected_is_unnumbered(ifp))
+ {
+ if (if_is_operative(ifp))
+ return 1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+ }
+
/* Make lookup prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));
p.family = AF_INET6;
@@ -527,8 +578,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
/* If there is no selected route or matched route is EGP, go up
tree. */
- if (! match
- || match->type == ZEBRA_ROUTE_BGP)
+ if (! match)
{
do {
rn = rn->parent;
@@ -564,6 +614,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
if (set)
{
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ SET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -592,7 +643,50 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
resolved_hop->ifindex = newhop->ifindex;
}
- _nexthop_add(&nexthop->resolved, resolved_hop);
+ nexthop_add(&nexthop->resolved, resolved_hop);
+ }
+ resolved = 1;
+ }
+ return resolved;
+ }
+ else if (rib->type == ZEBRA_ROUTE_STATIC)
+ {
+ resolved = 0;
+ for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing))
+ if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
+ {
+ if (set)
+ {
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+
+ resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
+ SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
+ /* See nexthop_active_ipv4 for a description how the
+ * resolved nexthop is constructed. */
+ if (newhop->type == NEXTHOP_TYPE_IPV6
+ || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+ {
+ resolved_hop->type = newhop->type;
+ resolved_hop->gate.ipv6 = newhop->gate.ipv6;
+
+ if (newhop->ifindex)
+ {
+ resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ resolved_hop->ifindex = newhop->ifindex;
+ }
+ }
+
+ if (newhop->type == NEXTHOP_TYPE_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IFNAME)
+ {
+ resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
+ resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
+ resolved_hop->ifindex = newhop->ifindex;
+ }
+
+ nexthop_add(&nexthop->resolved, resolved_hop);
}
resolved = 1;
}
@@ -608,7 +702,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
}
struct rib *
-rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp,
+rib_match_ipv4_safi (struct in_addr addr, safi_t safi,
struct route_node **rn_out, vrf_id_t vrf_id)
{
struct route_table *table;
@@ -639,7 +733,7 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp,
/* If there is no selected route or matched route is EGP, go up
tree. */
- if (!match || (skip_bgp && (match->type == ZEBRA_ROUTE_BGP)))
+ if (! match)
{
do {
rn = rn->parent;
@@ -676,29 +770,22 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out,
{
struct rib *rib = NULL, *mrib = NULL, *urib = NULL;
struct route_node *m_rn = NULL, *u_rn = NULL;
- int skip_bgp = 0; /* bool */
switch (ipv4_multicast_mode)
{
case MCAST_MRIB_ONLY:
- return rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, rn_out,
- vrf_id);
+ return rib_match_ipv4_safi (addr, SAFI_MULTICAST, rn_out, vrf_id);
case MCAST_URIB_ONLY:
- return rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, rn_out,
- vrf_id);
+ return rib_match_ipv4_safi (addr, SAFI_UNICAST, rn_out, vrf_id);
case MCAST_NO_CONFIG:
case MCAST_MIX_MRIB_FIRST:
- rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn,
- vrf_id);
+ rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, &m_rn, vrf_id);
if (!mrib)
- rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn,
- vrf_id);
+ rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, &u_rn, vrf_id);
break;
case MCAST_MIX_DISTANCE:
- mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn,
- vrf_id);
- urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn,
- vrf_id);
+ mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, &m_rn, vrf_id);
+ urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, &u_rn, vrf_id);
if (mrib && urib)
rib = urib->distance < mrib->distance ? urib : mrib;
else if (mrib)
@@ -707,10 +794,8 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out,
rib = urib;
break;
case MCAST_MIX_PFXLEN:
- mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn,
- vrf_id);
- urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn,
- vrf_id);
+ mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, &m_rn, vrf_id);
+ urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, &u_rn, vrf_id);
if (mrib && urib)
rib = u_rn->p.prefixlen > m_rn->p.prefixlen ? urib : mrib;
else if (mrib)
@@ -782,7 +867,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p, vrf_id_t vrf_id)
break;
}
- if (! match || match->type == ZEBRA_ROUTE_BGP)
+ if (! match)
return NULL;
if (match->type == ZEBRA_ROUTE_CONNECT)
@@ -910,8 +995,7 @@ rib_match_ipv6 (struct in6_addr *addr, vrf_id_t vrf_id)
/* If there is no selected route or matched route is EGP, go up
tree. */
- if (! match
- || match->type == ZEBRA_ROUTE_BGP)
+ if (! match)
{
do {
rn = rn->parent;
@@ -956,9 +1040,8 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
rib_table_info_t *info = rn->table->info;
struct interface *ifp;
route_map_result_t ret = RMAP_MATCH;
- extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1];
- struct route_map *rmap;
int family;
+ char buf[INET6_ADDRSTRLEN+1];
family = 0;
switch (nexthop->type)
@@ -1045,19 +1128,21 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
if (!family)
family = info->afi;
- rmap = 0;
- if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX &&
- proto_rm[family][rib->type])
- rmap = route_map_lookup_by_name (proto_rm[family][rib->type]);
- if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX])
- rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]);
- if (rmap) {
- struct nexthop_vrfid nh_vrf = {nexthop, rib->vrf_id};
- ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, &nh_vrf);
- }
+ memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
+ /* It'll get set if required inside */
+ ret = zebra_route_map_check(family, rib->type, &rn->p, nexthop, rib->vrf_id);
if (ret == RMAP_DENYMATCH)
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ {
+ if (IS_ZEBRA_DEBUG_RIB)
+ {
+ inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf));
+ zlog_debug("%s: Filtering out %s with NH out %s due to route map",
+ __FUNCTION__, buf, nexthop->ifname);
+ }
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ }
+
return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
}
@@ -1074,22 +1159,35 @@ static int
nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
{
struct nexthop *nexthop;
- unsigned int prev_active, new_active;
+ union g_addr prev_src;
+ unsigned int prev_active, new_active, old_num_nh;
ifindex_t prev_index;
-
+
+ old_num_nh = rib->nexthop_active_num;
+
rib->nexthop_active_num = 0;
- UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED);
+ UNSET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
{
+ /* No protocol daemon provides src and so we're skipping tracking it */
+ prev_src = nexthop->rmap_src;
prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
prev_index = nexthop->ifindex;
if ((new_active = nexthop_active_check (rn, rib, nexthop, set)))
rib->nexthop_active_num++;
+ /* Don't allow src setting on IPv6 addr for now */
if (prev_active != new_active ||
- prev_index != nexthop->ifindex)
- SET_FLAG (rib->status, RIB_ENTRY_CHANGED);
+ prev_index != nexthop->ifindex ||
+ ((nexthop->type >= NEXTHOP_TYPE_IFINDEX &&
+ nexthop->type < NEXTHOP_TYPE_IPV6) &&
+ prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr))
+ SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
}
+
+ if (old_num_nh != rib->nexthop_active_num)
+ SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
+
return rib->nexthop_active_num;
}
@@ -1275,6 +1373,8 @@ rib_process (struct route_node *rn)
RNODE_FOREACH_RIB (rn, rib)
{
+ UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
+
/* Currently installed rib. */
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
{
@@ -1292,7 +1392,18 @@ rib_process (struct route_node *rn)
continue;
/* Skip unreachable nexthop. */
- if (! nexthop_active_update (rn, rib, 0))
+ /* This first call to nexthop_active_update is merely to determine if
+ * there's any change to nexthops associated with this RIB entry. Now,
+ * rib_process() can be invoked due to an external event such as link
+ * down or due to next-hop-tracking evaluation. In the latter case,
+ * a decision has already been made that the NHs have changed. So, no
+ * need to invoke a potentially expensive call again. Further, since
+ * the change might be in a recursive NH which is not caught in
+ * the nexthop_active_update() code. Thus, we might miss changes to
+ * recursive NHs.
+ */
+ if (!CHECK_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED) &&
+ ! nexthop_active_update (rn, rib, 0))
continue;
/* Infinit distance. */
@@ -1327,7 +1438,7 @@ rib_process (struct route_node *rn)
/* Update kernel if FIB entry has changed */
if (old_fib != new_fib
- || (new_fib && CHECK_FLAG (new_fib->status, RIB_ENTRY_CHANGED)))
+ || (new_fib && CHECK_FLAG (new_fib->status, RIB_ENTRY_NEXTHOPS_CHANGED)))
{
if (old_fib && old_fib != new_fib)
{
@@ -1365,7 +1476,7 @@ rib_process (struct route_node *rn)
/* Redistribute SELECTED entry */
if (old_selected != new_selected
- || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_CHANGED)))
+ || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_NEXTHOPS_CHANGED)))
{
if (old_selected)
{
@@ -1436,6 +1547,18 @@ process_subq (struct list * subq, u_char qindex)
return 1;
}
+/*
+ * All meta queues have been processed. Trigger next-hop evaluation.
+ */
+static void
+meta_queue_process_complete (struct work_queue *dummy)
+{
+ zebra_evaluate_rnh_table(0, AF_INET, 0);
+#ifdef HAVE_IPV6
+ zebra_evaluate_rnh_table(0, AF_INET6, 0);
+#endif /* HAVE_IPV6 */
+}
+
/* Dispatch the meta queue by picking, processing and unlocking the next RN from
* a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and data
* is pointed to the meta queue structure.
@@ -1507,7 +1630,7 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn)
}
/* Add route_node to work queue and schedule processing */
-static void
+void
rib_queue_add (struct zebra_t *zebra, struct route_node *rn)
{
assert (zebra && rn);
@@ -1588,6 +1711,7 @@ rib_queue_init (struct zebra_t *zebra)
/* fill in the work queue spec */
zebra->ribq->spec.workfunc = &meta_queue_process;
zebra->ribq->spec.errorfunc = NULL;
+ zebra->ribq->spec.completion_func = &meta_queue_process_complete;
/* XXX: TODO: These should be runtime configurable via vty */
zebra->ribq->spec.max_retries = 3;
zebra->ribq->spec.hold = rib_process_hold_time;
@@ -1720,7 +1844,8 @@ rib_unlink (struct route_node *rn, struct rib *rib)
}
/* free RIB and nexthops */
- nexthops_free(rib->nexthop);
+ zebra_deregister_rnh_static_nexthops (rib->nexthop, rn);
+ nexthops_free (rib->nexthop);
XFREE (MTYPE_RIB, rib);
}
@@ -1811,12 +1936,12 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
if (gate)
{
if (ifindex)
- nexthop_ipv4_ifindex_add (rib, gate, src, ifindex);
+ rib_nexthop_ipv4_ifindex_add (rib, gate, src, ifindex);
else
- nexthop_ipv4_add (rib, gate, src);
+ rib_nexthop_ipv4_add (rib, gate, src);
}
else
- nexthop_ifindex_add (rib, ifindex);
+ rib_nexthop_ifindex_add (rib, ifindex);
/* If this route is kernel route, set FIB flag to the route. */
if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
@@ -2009,6 +2134,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi)
struct route_node *rn;
struct rib *same;
struct nexthop *nexthop;
+ int ret = 0;
/* Lookup table. */
table = zebra_vrf_table (AFI_IP, safi, rib->vrf_id);
@@ -2051,6 +2177,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi)
/* Link new rib to node.*/
rib_addnode (rn, rib);
+ ret = 1;
if (IS_ZEBRA_DEBUG_RIB)
{
zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry",
@@ -2068,10 +2195,11 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi)
rib_dump (p, same);
}
rib_delnode (rn, same);
+ ret = -1;
}
route_unlock_node (rn);
- return 0;
+ return ret;
}
/* XXX factor with rib_delete_ipv6 */
@@ -2178,14 +2306,19 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
kernel. */
if (! same)
{
- if (fib && type == ZEBRA_ROUTE_KERNEL)
- {
- /* Unset flags. */
- for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
-
- UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB);
- }
+ if (fib && type == ZEBRA_ROUTE_KERNEL &&
+ CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE))
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ zlog_debug ("Zebra route %s/%d was deleted by others from kernel",
+ inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),
+ p->prefixlen);
+ }
+ /* This means someone else, other than Zebra, has deleted
+ * a Zebra router from the kernel. We will add it back */
+ rib_update_kernel(rn, NULL, fib);
+ }
else
{
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -2222,6 +2355,7 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
struct rib *rib;
struct route_node *rn;
struct route_table *table;
+ struct prefix nh_p;
/* Lookup table. */
table = zebra_vrf_table (afi, safi, si->vrf_id);
@@ -2241,28 +2375,40 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
if (rib)
{
+ /* if tag value changed , update old value in RIB */
+ if (rib->tag != si->tag)
+ rib->tag = si->tag;
+
/* Same distance static route is there. Update it with new
nexthop. */
route_unlock_node (rn);
switch (si->type)
{
case STATIC_IPV4_GATEWAY:
- nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
+ rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
+ nh_p.family = AF_INET;
+ nh_p.prefixlen = IPV4_MAX_BITLEN;
+ nh_p.u.prefix4 = si->addr.ipv4;
+ zebra_register_rnh_static_nh(&nh_p, rn);
break;
case STATIC_IPV4_IFNAME:
- nexthop_ifname_add (rib, si->ifname);
+ rib_nexthop_ifname_add (rib, si->ifname);
break;
case STATIC_IPV4_BLACKHOLE:
- nexthop_blackhole_add (rib);
+ rib_nexthop_blackhole_add (rib);
break;
case STATIC_IPV6_GATEWAY:
- nexthop_ipv6_add (rib, &si->addr.ipv6);
+ rib_nexthop_ipv6_add (rib, &si->addr.ipv6);
+ nh_p.family = AF_INET6;
+ nh_p.prefixlen = IPV6_MAX_BITLEN;
+ nh_p.u.prefix6 = si->addr.ipv6;
+ zebra_register_rnh_static_nh(&nh_p, rn);
break;
case STATIC_IPV6_IFNAME:
- nexthop_ifname_add (rib, si->ifname);
+ rib_nexthop_ifname_add (rib, si->ifname);
break;
case STATIC_IPV6_GATEWAY_IFNAME:
- nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname);
+ rib_nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname);
break;
}
rib_queue_add (&zebrad, rn);
@@ -2278,26 +2424,35 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
rib->vrf_id = si->vrf_id;
rib->table = zebrad.rtm_table_default;
rib->nexthop_num = 0;
+ rib->tag = si->tag;
switch (si->type)
{
case STATIC_IPV4_GATEWAY:
- nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
+ rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
+ nh_p.family = AF_INET;
+ nh_p.prefixlen = IPV4_MAX_BITLEN;
+ nh_p.u.prefix4 = si->addr.ipv4;
+ zebra_register_rnh_static_nh(&nh_p, rn);
break;
case STATIC_IPV4_IFNAME:
- nexthop_ifname_add (rib, si->ifname);
+ rib_nexthop_ifname_add (rib, si->ifname);
break;
case STATIC_IPV4_BLACKHOLE:
- nexthop_blackhole_add (rib);
+ rib_nexthop_blackhole_add (rib);
break;
case STATIC_IPV6_GATEWAY:
- nexthop_ipv6_add (rib, &si->addr.ipv6);
+ rib_nexthop_ipv6_add (rib, &si->addr.ipv6);
+ nh_p.family = AF_INET6;
+ nh_p.prefixlen = IPV6_MAX_BITLEN;
+ nh_p.u.prefix6 = si->addr.ipv6;
+ zebra_register_rnh_static_nh(&nh_p, rn);
break;
case STATIC_IPV6_IFNAME:
- nexthop_ifname_add (rib, si->ifname);
+ rib_nexthop_ifname_add (rib, si->ifname);
break;
case STATIC_IPV6_GATEWAY_IFNAME:
- nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname);
+ rib_nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname);
break;
}
@@ -2347,6 +2502,7 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_
struct rib *rib;
struct nexthop *nexthop;
struct route_table *table;
+ struct prefix nh_p;
/* Lookup table. */
table = zebra_vrf_table (afi, safi, si->vrf_id);
@@ -2363,7 +2519,8 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
continue;
- if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+ if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance &&
+ rib->tag == si->tag)
break;
}
@@ -2392,7 +2549,21 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_
{
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
rib_uninstall (rn, rib);
- nexthop_delete (rib, nexthop);
+
+ if (afi == AF_INET)
+ {
+ nh_p.family = AF_INET;
+ nh_p.prefixlen = IPV4_MAX_BITLEN;
+ nh_p.u.prefix4 = nexthop->gate.ipv4;
+ }
+ else
+ {
+ nh_p.family = AF_INET6;
+ nh_p.prefixlen = IPV6_MAX_BITLEN;
+ nh_p.u.prefix6 = nexthop->gate.ipv6;
+ }
+ rib_nexthop_delete (rib, nexthop);
+ zebra_deregister_rnh_static_nh(&nh_p, rn);
nexthop_free (nexthop);
rib_queue_add (&zebrad, rn);
}
@@ -2402,7 +2573,7 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_
int
static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
- const char *ifname, u_char flags, u_char distance,
+ const char *ifname, u_char flags, u_short tag, u_char distance,
vrf_id_t vrf_id)
{
u_char type = 0;
@@ -2435,7 +2606,8 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
&& (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4))
&& (! ifname || strcmp (ifname, si->ifname) == 0))
{
- if (distance == si->distance)
+ if (distance == si->distance &&
+ tag == si->tag)
{
route_unlock_node (rn);
return 0;
@@ -2445,15 +2617,16 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
}
}
- /* Distance changed. */
+ /* Distance or tag changed. */
if (update)
- static_delete_ipv4_safi (safi, p, gate, ifname, update->distance, vrf_id);
+ static_delete_ipv4_safi (safi, p, gate, ifname, update->tag, update->distance, vrf_id);
/* Make new static route structure. */
si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route));
si->type = type;
si->distance = distance;
+ si->tag = tag;
si->flags = flags;
si->vrf_id = vrf_id;
@@ -2497,7 +2670,7 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
int
static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
- const char *ifname, u_char distance, vrf_id_t vrf_id)
+ const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id)
{
u_char type = 0;
struct route_node *rn;
@@ -2526,7 +2699,8 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
for (si = rn->info; si; si = si->next)
if (type == si->type
&& (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4))
- && (! ifname || strcmp (ifname, si->ifname) == 0))
+ && (! ifname || strcmp (ifname, si->ifname) == 0)
+ && (! tag || (tag == si->tag)))
break;
/* Can't find static route. */
@@ -2628,12 +2802,12 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
if (gate)
{
if (ifindex)
- nexthop_ipv6_ifindex_add (rib, gate, ifindex);
+ rib_nexthop_ipv6_ifindex_add (rib, gate, ifindex);
else
- nexthop_ipv6_add (rib, gate);
+ rib_nexthop_ipv6_add (rib, gate);
}
else
- nexthop_ifindex_add (rib, ifindex);
+ rib_nexthop_ifindex_add (rib, ifindex);
/* If this route is kernel route, set FIB flag to the route. */
if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
@@ -2665,6 +2839,86 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
return 0;
}
+int
+rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi)
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *same = NULL;
+ struct nexthop *nexthop;
+ int ret = 0;
+
+ if (!rib)
+ return 0; /* why are we getting called with NULL rib */
+
+ /* Lookup table. */
+ table = zebra_vrf_table (AFI_IP6, safi, rib->vrf_id);
+
+ if (! table)
+ return 0;
+
+ /* Make sure mask is applied. */
+ apply_mask_ipv6 (p);
+
+ /* Set default distance by route type. */
+ if (rib->distance == 0)
+ {
+ rib->distance = route_info[rib->type].distance;
+
+ /* iBGP distance is 200. */
+ if (rib->type == ZEBRA_ROUTE_BGP
+ && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP))
+ rib->distance = 200;
+ }
+
+ /* Lookup route node.*/
+ rn = route_node_get (table, (struct prefix *) p);
+
+ /* If same type of route are installed, treat it as a implicit
+ withdraw. */
+ RNODE_FOREACH_RIB (rn, same) {
+ if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED)) {
+ continue;
+ }
+ if (same->type != rib->type) {
+ continue;
+ }
+
+ if (same->table != rib->table) {
+ continue;
+ }
+ if (same->type != ZEBRA_ROUTE_CONNECT) {
+ break;
+ }
+ }
+
+ /* If this route is kernel route, set FIB flag to the route. */
+ if (rib->type == ZEBRA_ROUTE_KERNEL || rib->type == ZEBRA_ROUTE_CONNECT) {
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) {
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
+ }
+
+ /* Link new rib to node.*/
+ rib_addnode (rn, rib);
+ ret = 1;
+ /* Free implicit route.*/
+ if (same)
+ {
+ if (IS_ZEBRA_DEBUG_RIB)
+ {
+ zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry",
+ __func__, rn, same);
+ rib_dump ((struct prefix *)p, same);
+ }
+ rib_delnode (rn, same);
+ ret = -1;
+ }
+
+ route_unlock_node (rn);
+ return ret;
+}
+
/* XXX factor with rib_delete_ipv6 */
int
rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
@@ -2757,14 +3011,19 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
kernel. */
if (! same)
{
- if (fib && type == ZEBRA_ROUTE_KERNEL)
- {
- /* Unset flags. */
- for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
-
- UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB);
- }
+ if (fib && type == ZEBRA_ROUTE_KERNEL &&
+ CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE))
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ zlog_debug ("Zebra route %s/%d was deleted by others from kernel",
+ inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),
+ p->prefixlen);
+ }
+ /* This means someone else, other than Zebra, has deleted a Zebra
+ * route from the kernel. We will add it back */
+ rib_update_kernel(rn, NULL, fib);
+ }
else
{
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -2794,12 +3053,11 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
return 0;
}
-
/* Add static route into static route configuration. */
int
static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
- const char *ifname, u_char flags, u_char distance,
- vrf_id_t vrf_id)
+ const char *ifname, u_char flags, u_short tag,
+ u_char distance, vrf_id_t vrf_id)
{
struct route_node *rn;
struct static_route *si;
@@ -2827,6 +3085,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
for (si = rn->info; si; si = si->next)
{
if (type == si->type
+ && tag == si->tag
&& (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6))
&& (! ifname || strcmp (ifname, si->ifname) == 0))
{
@@ -2841,13 +3100,14 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
}
if (update)
- static_delete_ipv6(p, type, gate, ifname, si->distance, vrf_id);
+ static_delete_ipv6(p, type, gate, ifname, tag, si->distance, vrf_id);
/* Make new static route structure. */
si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route));
si->type = type;
si->distance = distance;
+ si->tag = tag;
si->flags = flags;
si->vrf_id = vrf_id;
@@ -2894,7 +3154,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
/* Delete static route from static route configuration. */
int
static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
- const char *ifname, u_char distance, vrf_id_t vrf_id)
+ const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id)
{
struct route_node *rn;
struct static_route *si;
@@ -2915,7 +3175,8 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
if (distance == si->distance
&& type == si->type
&& (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6))
- && (! ifname || strcmp (ifname, si->ifname) == 0))
+ && (! ifname || strcmp (ifname, si->ifname) == 0)
+ && (! tag || (tag == si->tag)))
break;
/* Can't find static route. */
@@ -3237,6 +3498,13 @@ rib_tables_iter_next (rib_tables_iter_t *iter)
return table;
}
+/* Lookup VRF by identifier. */
+struct zebra_vrf *
+zebra_vrf_lookup (vrf_id_t vrf_id)
+{
+ return vrf_info_lookup (vrf_id);
+}
+
/*
* Create a routing table for the specific AFI/SAFI in the given VRF.
*/
@@ -3279,6 +3547,9 @@ zebra_vrf_alloc (vrf_id_t vrf_id)
zvrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init ();
zvrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init ();
+ zvrf->rnh_table[AFI_IP] = route_table_init();
+ zvrf->rnh_table[AFI_IP6] = route_table_init();
+
/* Set VRF ID */
zvrf->vrf_id = vrf_id;
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
new file mode 100644
index 00000000..5f68f64f
--- /dev/null
+++ b/zebra/zebra_rnh.c
@@ -0,0 +1,761 @@
+/* Zebra next hop tracking code
+ * 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 "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "str.h"
+#include "command.h"
+#include "if.h"
+#include "log.h"
+#include "sockunion.h"
+#include "linklist.h"
+#include "thread.h"
+#include "workqueue.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "stream.h"
+#include "nexthop.h"
+
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+#include "zebra/zebra_rnh.h"
+
+#define lookup_rnh_table(v, f) \
+({ \
+ struct zebra_vrf *zvrf; \
+ struct route_table *t = NULL; \
+ zvrf = zebra_vrf_lookup(v); \
+ if (zvrf) \
+ t = zvrf->rnh_table[family2afi(f)]; \
+ t; \
+})
+
+/* Default rtm_table for all clients */
+extern struct zebra_t zebrad;
+
+static void rib_free_state(struct rib *rib, struct route_node *rn);
+static void copy_state(struct rnh *rnh, struct rib *rib, struct route_node *rn);
+static int compare_state(struct rib *r1, struct rib *r2);
+static int send_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id);
+static void print_rnh(struct route_node *rn, struct vty *vty);
+
+char *
+rnh_str (struct rnh *rnh, char *buf, int size)
+{
+ prefix2str(&(rnh->node->p), buf, size);
+ return buf;
+}
+
+struct rnh *
+zebra_add_rnh (struct prefix *p, vrf_id_t vrfid)
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rnh *rnh = NULL;
+
+ if (IS_ZEBRA_DEBUG_NHT)
+ {
+ char buf[INET6_ADDRSTRLEN];
+ prefix2str(p, buf, INET6_ADDRSTRLEN);
+ zlog_debug("add rnh %s in vrf %d", buf, vrfid);
+ }
+ table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p));
+ if (!table)
+ {
+ zlog_debug("add_rnh: rnh table not found\n");
+ return NULL;
+ }
+
+ /* Make it sure prefixlen is applied to the prefix. */
+ apply_mask (p);
+
+ /* Lookup (or add) route node.*/
+ rn = route_node_get (table, p);
+
+ if (!rn->info)
+ {
+ rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
+ rnh->client_list = list_new();
+ rnh->zebra_static_route_list = list_new();
+ route_lock_node (rn);
+ rn->info = rnh;
+ rnh->node = rn;
+ }
+
+ route_unlock_node (rn);
+ return (rn->info);
+}
+
+struct rnh *
+zebra_lookup_rnh (struct prefix *p, vrf_id_t vrfid)
+{
+ struct route_table *table;
+ struct route_node *rn;
+
+ table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p));
+ if (!table)
+ return NULL;
+
+ /* Make it sure prefixlen is applied to the prefix. */
+ apply_mask (p);
+
+ /* Lookup route node.*/
+ rn = route_node_lookup (table, p);
+ if (!rn)
+ return NULL;
+
+ route_unlock_node (rn);
+ return (rn->info);
+}
+
+void
+zebra_delete_rnh (struct rnh *rnh)
+{
+ struct route_node *rn;
+
+ if (!rnh || !(rn = rnh->node))
+ return;
+
+ if (IS_ZEBRA_DEBUG_NHT)
+ {
+ char buf[INET6_ADDRSTRLEN];
+ zlog_debug("delete rnh %s", rnh_str(rnh, buf, INET6_ADDRSTRLEN));
+ }
+
+ list_free(rnh->client_list);
+ list_free(rnh->zebra_static_route_list);
+ rib_free_state(rnh->state, rn);
+ XFREE(MTYPE_RNH, rn->info);
+ rn->info = NULL;
+ route_unlock_node (rn);
+ return;
+}
+
+void
+zebra_add_rnh_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id)
+{
+ if (IS_ZEBRA_DEBUG_NHT)
+ {
+ char buf[INET6_ADDRSTRLEN];
+ zlog_debug("client %s registers rnh %s",
+ zebra_route_string(client->proto),
+ rnh_str(rnh, buf, INET6_ADDRSTRLEN));
+ }
+ if (!listnode_lookup(rnh->client_list, client))
+ {
+ listnode_add(rnh->client_list, client);
+ send_client(rnh, client, vrf_id);
+ }
+}
+
+void
+zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client)
+{
+ if (IS_ZEBRA_DEBUG_NHT)
+ {
+ char buf[INET6_ADDRSTRLEN];
+ zlog_debug("client %s unregisters rnh %s",
+ zebra_route_string(client->proto),
+ rnh_str(rnh, buf, INET6_ADDRSTRLEN));
+ }
+ listnode_delete(rnh->client_list, client);
+ if (list_isempty(rnh->client_list) &&
+ list_isempty(rnh->zebra_static_route_list))
+ zebra_delete_rnh(rnh);
+}
+
+void
+zebra_register_rnh_static_nh(struct prefix *nh, struct route_node *static_rn)
+{
+ struct rnh *rnh;
+
+ rnh = zebra_add_rnh(nh, 0);
+ if (rnh && !listnode_lookup(rnh->zebra_static_route_list, static_rn))
+ {
+ listnode_add(rnh->zebra_static_route_list, static_rn);
+ }
+}
+
+void
+zebra_deregister_rnh_static_nh(struct prefix *nh, struct route_node *static_rn)
+{
+ struct rnh *rnh;
+
+ rnh = zebra_lookup_rnh(nh, 0);
+ if (!rnh)
+ return;
+
+ listnode_delete(rnh->zebra_static_route_list, static_rn);
+
+ if (list_isempty(rnh->client_list) &&
+ list_isempty(rnh->zebra_static_route_list))
+ zebra_delete_rnh(rnh);
+}
+
+void
+zebra_deregister_rnh_static_nexthops (struct nexthop *nexthop, struct route_node *rn)
+{
+ struct nexthop *nh;
+ struct prefix nh_p;
+
+ for (nh = nexthop; nh ; nh = nh->next)
+ {
+ if (nh->type == NEXTHOP_TYPE_IPV4)
+ {
+ nh_p.family = AF_INET;
+ nh_p.prefixlen = IPV4_MAX_BITLEN;
+ nh_p.u.prefix4 = nh->gate.ipv4;
+ }
+ else if (nh->type == NEXTHOP_TYPE_IPV6)
+ {
+ nh_p.family = AF_INET6;
+ nh_p.prefixlen = IPV6_MAX_BITLEN;
+ nh_p.u.prefix6 = nh->gate.ipv6;
+ }
+ zebra_deregister_rnh_static_nh(&nh_p, rn);
+ }
+}
+
+static int
+zebra_evaluate_rnh_nexthops(int family, struct rib *rib, struct route_node *prn,
+ int proto)
+{
+ int at_least_one = 0;
+ int rmap_family; /* Route map has diff AF family enum */
+ struct nexthop *nexthop;
+ int ret;
+
+ rmap_family = (family == AF_INET) ? AFI_IP : AFI_IP6;
+
+ if (prn && rib)
+ {
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ ret = zebra_nht_route_map_check(rmap_family, proto, &prn->p, rib,
+ nexthop);
+ if (ret != RMAP_DENYMATCH)
+ {
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ at_least_one++; /* at least one valid NH */
+ }
+ else
+ {
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ }
+ }
+ }
+ return (at_least_one);
+}
+
+int
+zebra_evaluate_rnh_table (vrf_id_t vrfid, int family, int force)
+{
+ struct route_table *ptable;
+ struct route_table *ntable;
+ struct route_node *prn;
+ struct route_node *nrn;
+ struct rnh *rnh;
+ struct zserv *client;
+ struct listnode *node;
+ struct rib *rib, *srib;
+ int state_changed = 0;
+ int at_least_one = 0;
+ char bufn[INET6_ADDRSTRLEN];
+ char bufp[INET6_ADDRSTRLEN];
+ char bufs[INET6_ADDRSTRLEN];
+ struct route_node *static_rn;
+ struct nexthop *nexthop;
+ ntable = lookup_rnh_table(vrfid, family);
+ if (!ntable)
+ {
+ zlog_debug("evaluate_rnh_table: rnh table not found\n");
+ return -1;
+ }
+
+ ptable = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid);
+ if (!ptable)
+ {
+ zlog_debug("evaluate_rnh_table: prefix table not found\n");
+ return -1;
+ }
+
+ for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
+ {
+ if (!nrn->info)
+ continue;
+
+ rnh = nrn->info;
+ at_least_one = 0;
+
+ prn = route_node_match(ptable, &nrn->p);
+ if (!prn)
+ rib = NULL;
+ else
+ {
+ RNODE_FOREACH_RIB(prn, rib)
+ {
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+ continue;
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ {
+ if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
+ {
+ if (rib->type == ZEBRA_ROUTE_CONNECT)
+ break;
+ }
+ else
+ break;
+ }
+ }
+ }
+
+ state_changed = 0;
+
+ if (compare_state(rib, rnh->state))
+ {
+ if (rib)
+ UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
+
+ copy_state(rnh, rib, nrn);
+ state_changed = 1;
+ }
+
+ if (IS_ZEBRA_DEBUG_NHT && (state_changed || force))
+ {
+ prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
+ if (prn)
+ prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
+ else
+ strcpy(bufp, "null");
+
+ zlog_debug("%s: State changed for %s/%s", __FUNCTION__, bufn, bufp);
+
+ }
+
+ /* Notify registered clients */
+ rib = rnh->state;
+
+ if (state_changed || force)
+ {
+ for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
+ {
+ if (prn && rib)
+ {
+ at_least_one = zebra_evaluate_rnh_nexthops(family, rib, prn,
+ client->proto);
+ if (at_least_one)
+ rnh->filtered[client->proto] = 0;
+ else
+ rnh->filtered[client->proto] = 1;
+ }
+ else if (state_changed)
+ rnh->filtered[client->proto] = 0;
+
+ if (IS_ZEBRA_DEBUG_NHT && (state_changed || force))
+ zlog_debug("%srnh %s resolved through route %s - sending "
+ "nexthop %s event to clients",
+ at_least_one ? "":"(filtered)", bufn, bufp,
+ rib ? "reachable" : "unreachable");
+
+ send_client(rnh, client, vrfid); /* Route-map passed */
+ }
+
+ /* Now evaluate static client */
+ if (prn && rib)
+ {
+ at_least_one = zebra_evaluate_rnh_nexthops(family, rib, prn,
+ ZEBRA_ROUTE_STATIC);
+ if (at_least_one)
+ rnh->filtered[ZEBRA_ROUTE_STATIC] = 0;
+ else
+ rnh->filtered[ZEBRA_ROUTE_STATIC] = 1;
+ }
+ else if (state_changed)
+ rnh->filtered[ZEBRA_ROUTE_STATIC] = 0;
+
+ for (ALL_LIST_ELEMENTS_RO(rnh->zebra_static_route_list, node,
+ static_rn))
+ {
+ RNODE_FOREACH_RIB(static_rn, srib)
+ {
+ break; /* pick the first and only(?) rib for static */
+ }
+
+ if (!srib)
+ {
+ if (IS_ZEBRA_DEBUG_NHT)
+ {
+ prefix2str(&static_rn->p, bufs, INET6_ADDRSTRLEN);
+ zlog_debug("%s: Unable to find RIB for static route %s, skipping NH resolution",
+ __FUNCTION__, bufs);
+ continue;
+ }
+ }
+
+ /* Mark the appropriate static route's NH as filtered */
+ for (nexthop = srib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ /* Don't see a use case for *_IFNAME */
+ if (nexthop->gate.ipv4.s_addr == nrn->p.u.prefix4.s_addr)
+ {
+ if (at_least_one)
+ UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED);
+ else
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED);
+ }
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ /* Don't see a use case for *_IFNAME */
+ if (memcmp(&nexthop->gate.ipv6,&nrn->p.u.prefix6, 16) == 0)
+ {
+ if (at_least_one)
+ UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED);
+ else
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (IS_ZEBRA_DEBUG_NHT && (state_changed || force))
+ zlog_debug("%srnh %s resolved through route %s - sending "
+ "nexthop %s event to zebra",
+ at_least_one ? "":"(filtered)", bufn, bufp,
+ rib ? "reachable" : "unreachable");
+
+ if (srib && (state_changed || force))
+ {
+ SET_FLAG(srib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
+ rib_queue_add(&zebrad, static_rn);
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+int
+zebra_dispatch_rnh_table (vrf_id_t vrfid, int family, struct zserv *client)
+{
+ struct route_table *ntable;
+ struct route_node *nrn;
+ struct rnh *rnh;
+
+ ntable = lookup_rnh_table(vrfid, family);
+ if (!ntable)
+ {
+ zlog_debug("dispatch_rnh_table: rnh table not found\n");
+ return -1;
+ }
+
+ for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
+ {
+ if (!nrn->info)
+ continue;
+
+ rnh = nrn->info;
+ if (IS_ZEBRA_DEBUG_NHT)
+ {
+ char bufn[INET6_ADDRSTRLEN];
+ prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
+ zlog_debug("rnh %s - sending nexthop %s event to client %s", bufn,
+ rnh->state ? "reachable" : "unreachable",
+ zebra_route_string(client->proto));
+ }
+ send_client(rnh, client, vrfid);
+ }
+ return 1;
+}
+
+void
+zebra_print_rnh_table (vrf_id_t vrfid, int af, struct vty *vty)
+{
+ struct route_table *table;
+ struct route_node *rn;
+
+ table = lookup_rnh_table(vrfid, af);
+ if (!table)
+ {
+ zlog_debug("print_rnhs: rnh table not found\n");
+ return;
+ }
+
+ for (rn = route_top(table); rn; rn = route_next(rn))
+ if (rn->info)
+ print_rnh(rn, vty);
+}
+
+int
+zebra_cleanup_rnh_client (vrf_id_t vrfid, int family, struct zserv *client)
+{
+ struct route_table *ntable;
+ struct route_node *nrn;
+ struct rnh *rnh;
+
+ ntable = lookup_rnh_table(vrfid, family);
+ if (!ntable)
+ {
+ zlog_debug("cleanup_rnh_client: rnh table not found\n");
+ return -1;
+ }
+
+ for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
+ {
+ if (!nrn->info)
+ continue;
+
+ rnh = nrn->info;
+ if (IS_ZEBRA_DEBUG_NHT)
+ {
+ char bufn[INET6_ADDRSTRLEN];
+ prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
+ zlog_debug("rnh %s - cleaning state for client %s", bufn,
+ zebra_route_string(client->proto));
+ }
+ zebra_remove_rnh_client(rnh, client);
+ }
+ return 1;
+}
+
+/**
+ * free_state - free up the rib structure associated with the rnh.
+ */
+static void
+rib_free_state (struct rib *rib, struct route_node *rn)
+{
+
+ if (!rib)
+ return;
+
+ /* free RIB and nexthops */
+ zebra_deregister_rnh_static_nexthops (rib->nexthop, rn);
+ nexthops_free(rib->nexthop);
+ XFREE (MTYPE_RIB, rib);
+}
+
+static void
+copy_state (struct rnh *rnh, struct rib *rib, struct route_node *rn)
+{
+ struct rib *state;
+ struct nexthop *nh;
+
+ if (rnh->state)
+ {
+ rib_free_state(rnh->state, rn);
+ rnh->state = NULL;
+ }
+
+ if (!rib)
+ return;
+
+ state = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+ state->type = rib->type;
+ state->metric = rib->metric;
+
+ for (nh = rib->nexthop; nh; nh = nh->next)
+ rib_copy_nexthops(state, nh);
+ rnh->state = state;
+}
+
+static int
+compare_state (struct rib *r1, struct rib *r2)
+{
+
+ if (!r1 && !r2)
+ return 0;
+
+ if ((!r1 && r2) || (r1 && !r2))
+ return 1;
+
+ if (r1->metric != r2->metric)
+ return 1;
+
+ if (r1->nexthop_num != r2->nexthop_num)
+ return 1;
+
+ if (CHECK_FLAG(r1->status, RIB_ENTRY_NEXTHOPS_CHANGED))
+ return 1;
+
+ return 0;
+}
+
+static int
+send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id)
+{
+ struct stream *s;
+ struct rib *rib;
+ unsigned long nump;
+ u_char num;
+ struct nexthop *nexthop;
+ struct route_node *rn;
+
+ rn = rnh->node;
+ rib = rnh->state;
+
+ /* Get output stream. */
+ s = client->obuf;
+ stream_reset (s);
+
+ zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE, vrf_id);
+
+ stream_putw(s, rn->p.family);
+ stream_put_prefix (s, &rn->p);
+
+ if (rib)
+ {
+ stream_putl (s, rib->metric);
+ num = 0;
+ nump = stream_get_endp(s);
+ stream_putc (s, 0);
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ if ((CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ||
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) &&
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ {
+ stream_putc (s, nexthop->type);
+ switch (nexthop->type)
+ {
+ case ZEBRA_NEXTHOP_IPV4:
+ stream_put_in_addr (s, &nexthop->gate.ipv4);
+ break;
+ case ZEBRA_NEXTHOP_IFINDEX:
+ case ZEBRA_NEXTHOP_IFNAME:
+ stream_putl (s, nexthop->ifindex);
+ break;
+ case ZEBRA_NEXTHOP_IPV4_IFINDEX:
+ case ZEBRA_NEXTHOP_IPV4_IFNAME:
+ stream_put_in_addr (s, &nexthop->gate.ipv4);
+ stream_putl (s, nexthop->ifindex);
+ break;
+#ifdef HAVE_IPV6
+ case ZEBRA_NEXTHOP_IPV6:
+ stream_put (s, &nexthop->gate.ipv6, 16);
+ break;
+ case ZEBRA_NEXTHOP_IPV6_IFINDEX:
+ case ZEBRA_NEXTHOP_IPV6_IFNAME:
+ stream_put (s, &nexthop->gate.ipv6, 16);
+ stream_putl (s, nexthop->ifindex);
+ break;
+#endif /* HAVE_IPV6 */
+ default:
+ /* do nothing */
+ break;
+ }
+ num++;
+ }
+ stream_putc_at (s, nump, num);
+ }
+ else
+ {
+ stream_putl (s, 0);
+ stream_putc (s, 0);
+ }
+ stream_putw_at (s, 0, stream_get_endp (s));
+
+ client->nh_last_upd_time = quagga_time(NULL);
+ client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE;
+ return zebra_server_send_message(client);
+}
+
+static void
+print_nh (struct nexthop *nexthop, struct vty *vty)
+{
+ char buf[BUFSIZ];
+
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
+ if (nexthop->ifindex)
+ vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFNAME:
+ vty_out (vty, " %s",
+ inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
+ if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+ vty_out (vty, ", %s", nexthop->ifname);
+ else if (nexthop->ifindex)
+ vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out (vty, " is directly connected, %s",
+ ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " is directly connected, %s", nexthop->ifname);
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ vty_out (vty, " is directly connected, Null0");
+ break;
+ default:
+ break;
+ }
+ vty_out(vty, "%s", VTY_NEWLINE);
+}
+
+static void
+print_rnh (struct route_node *rn, struct vty *vty)
+{
+ struct rnh *rnh;
+ struct nexthop *nexthop;
+ struct listnode *node;
+ struct zserv *client;
+ char buf[BUFSIZ];
+
+ rnh = rn->info;
+ vty_out(vty, "%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
+ VTY_NEWLINE);
+ if (rnh->state)
+ {
+ vty_out(vty, " resolved via %s%s",
+ zebra_route_string(rnh->state->type), VTY_NEWLINE);
+ for (nexthop = rnh->state->nexthop; nexthop; nexthop = nexthop->next)
+ print_nh(nexthop, vty);
+ }
+ else
+ vty_out(vty, " unresolved%s%s",
+ CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "",
+ VTY_NEWLINE);
+
+ vty_out(vty, " Client list:");
+ for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
+ vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto),
+ client->sock, rnh->filtered[client->proto] ? "(filtered)" : "");
+ if (!list_isempty(rnh->zebra_static_route_list))
+ vty_out(vty, " zebra%s", rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : "");
+ vty_out(vty, "%s", VTY_NEWLINE);
+}
diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h
new file mode 100644
index 00000000..77a913aa
--- /dev/null
+++ b/zebra/zebra_rnh.h
@@ -0,0 +1,54 @@
+/*
+ * Zebra next hop tracking header
+ * 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 _ZEBRA_RNH_H
+#define _ZEBRA_RNH_H
+
+#include "prefix.h"
+#include "vty.h"
+
+/* Nexthop structure. */
+struct rnh
+{
+ u_char flags;
+#define ZEBRA_NHT_CONNECTED 0x1
+ struct rib *state;
+ struct list *client_list;
+ struct list *zebra_static_route_list; /* static routes dependent on this NH */
+ struct route_node *node;
+ int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client */
+};
+
+extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid);
+extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid);
+extern void zebra_delete_rnh(struct rnh *rnh);
+extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id_t);
+extern void zebra_register_rnh_static_nh(struct prefix *, struct route_node *);
+extern void zebra_deregister_rnh_static_nh(struct prefix *, struct route_node *);
+extern void zebra_deregister_rnh_static_nexthops (struct nexthop *, struct route_node *);
+extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client);
+extern int zebra_evaluate_rnh_table(vrf_id_t vrfid, int family, int force);
+extern int zebra_dispatch_rnh_table(vrf_id_t vrfid, int family, struct zserv *cl);
+extern void zebra_print_rnh_table(vrf_id_t vrfid, int family, struct vty *vty);
+extern char *rnh_str(struct rnh *rnh, char *buf, int size);
+extern int zebra_cleanup_rnh_client(vrf_id_t vrf, int family, struct zserv *client);
+#endif /*_ZEBRA_RNH_H */
diff --git a/zebra/zebra_rnh_null.c b/zebra/zebra_rnh_null.c
new file mode 100644
index 00000000..c30e3e4e
--- /dev/null
+++ b/zebra/zebra_rnh_null.c
@@ -0,0 +1,21 @@
+#include <zebra.h>
+#include <vty.h>
+
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/zebra_rnh.h"
+
+int zebra_evaluate_rnh_table (vrf_id_t vrfid, int family, int force)
+{ return 0; }
+
+void zebra_print_rnh_table (vrf_id_t vrfid, int family, struct vty *vty)
+{}
+
+void zebra_register_rnh_static_nh(struct prefix *p, struct route_node *rn)
+{}
+
+void zebra_deregister_rnh_static_nh(struct prefix *p, struct route_node *rn)
+{}
+
+void zebra_deregister_rnh_static_nexthops (struct nexthop *nexthop, struct route_node *rn)
+{}
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index da9cb130..5184589c 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -29,13 +29,34 @@
#include "filter.h"
#include "plist.h"
#include "vrf.h"
+#include "nexthop.h"
#include "zebra/zserv.h"
+#include "zebra/debug.h"
+#include "zebra/zebra_rnh.h"
+
+static u_int32_t zebra_rmap_update_timer = ZEBRA_RMAP_DEFAULT_UPDATE_TIMER;
+static struct thread *zebra_t_rmap_update = NULL;
+char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */
+/* NH Tracking route map */
+char *nht_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */
+
+extern struct zebra_t zebrad;
+struct nh_rmap_obj
+{
+ struct nexthop *nexthop;
+ vrf_id_t vrf_id;
+ u_int32_t source_protocol;
+ int metric;
+};
+
+static void zebra_route_map_set_delay_timer(u_int32_t value);
/* Add zebra route map rule */
static int
zebra_route_match_add(struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg)
+ const char *command, const char *arg,
+ route_map_event_t type)
{
int ret;
@@ -45,22 +66,42 @@ zebra_route_match_add(struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
+
+ if (type != RMAP_EVENT_MATCH_ADDED)
+ {
+ route_map_upd8_dependency (type, arg, index->map->name);
+ }
return CMD_SUCCESS;
}
/* Delete zebra route map rule. */
static int
zebra_route_match_delete (struct vty *vty, struct route_map_index *index,
- const char *command, const char *arg)
+ const char *command, const char *arg,
+ route_map_event_t type)
{
int ret;
+ char *dep_name = (char *)arg;
+ const char *tmpstr;
+ char *rmap_name = NULL;
+
+ if (type != RMAP_EVENT_MATCH_DELETED)
+ {
+ /* ignore the mundane, the types without any dependency */
+ if (arg == NULL)
+ {
+ if ((tmpstr = route_map_get_match_arg(index, command)) != NULL)
+ dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
+ }
+ rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
+ }
ret = route_map_delete_match (index, command, arg);
if (ret)
@@ -68,13 +109,22 @@ zebra_route_match_delete (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
+
+ if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
+ route_map_upd8_dependency(type, dep_name, rmap_name);
+
+ if (arg == NULL && dep_name)
+ XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
+ if (rmap_name)
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+
return CMD_SUCCESS;
}
@@ -91,10 +141,10 @@ zebra_route_set_add (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -114,10 +164,10 @@ zebra_route_set_delete (struct vty *vty, struct route_map_index *index,
switch (ret)
{
case RMAP_RULE_MISSING:
- vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE);
return CMD_WARNING;
case RMAP_COMPILE_ERROR:
- vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE);
return CMD_WARNING;
}
}
@@ -131,7 +181,7 @@ static route_map_result_t
route_match_interface (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
- struct nexthop_vrfid *nh_vrf;
+ struct nh_rmap_obj *nh_data;
struct nexthop *nexthop;
char *ifname = rule;
ifindex_t ifindex;
@@ -140,13 +190,13 @@ route_match_interface (void *rule, struct prefix *prefix,
{
if (strcasecmp(ifname, "any") == 0)
return RMAP_MATCH;
- nh_vrf = object;
- if (!nh_vrf)
+ nh_data = object;
+ if (!nh_data)
return RMAP_NOMATCH;
- ifindex = ifname2ifindex_vrf (ifname, nh_vrf->vrf_id);
+ ifindex = ifname2ifindex_vrf (ifname, nh_data->vrf_id);
if (ifindex == 0)
return RMAP_NOMATCH;
- nexthop = nh_vrf->nexthop;
+ nexthop = nh_data->nexthop;
if (!nexthop)
return RMAP_NOMATCH;
if (nexthop->ifindex == ifindex)
@@ -185,7 +235,8 @@ DEFUN (match_interface,
"match first hop interface of route\n"
"Interface name\n")
{
- return zebra_route_match_add (vty, vty->index, "interface", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "interface", argv[0],
+ RMAP_EVENT_MATCH_ADDED);
}
DEFUN (no_match_interface,
@@ -196,9 +247,9 @@ DEFUN (no_match_interface,
"Match first hop interface of route\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "interface", NULL);
+ return zebra_route_match_delete (vty, vty->index, "interface", NULL, RMAP_EVENT_MATCH_DELETED);
- return zebra_route_match_delete (vty, vty->index, "interface", argv[0]);
+ return zebra_route_match_delete (vty, vty->index, "interface", argv[0], RMAP_EVENT_MATCH_DELETED);
}
ALIAS (no_match_interface,
@@ -219,7 +270,7 @@ DEFUN (match_ip_next_hop,
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
- return zebra_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "ip next-hop", argv[0], RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ip_next_hop,
@@ -231,9 +282,11 @@ DEFUN (no_match_ip_next_hop,
"Match next-hop address of route\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+ return zebra_route_match_delete (vty, vty->index, "ip next-hop", NULL,
+ RMAP_EVENT_FILTER_DELETED);
- return zebra_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+ return zebra_route_match_delete (vty, vty->index, "ip next-hop", argv[0],
+ RMAP_EVENT_FILTER_DELETED);
}
ALIAS (no_match_ip_next_hop,
@@ -256,7 +309,8 @@ DEFUN (match_ip_next_hop_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ip_next_hop_prefix_list,
@@ -269,9 +323,13 @@ DEFUN (no_match_ip_next_hop_prefix_list,
"Match entries of prefix-lists\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL);
+ return zebra_route_match_delete (vty, vty->index,
+ "ip next-hop prefix-list", NULL,
+ RMAP_EVENT_PLIST_DELETED);
- return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+ return zebra_route_match_delete (vty, vty->index,
+ "ip next-hop prefix-list", argv[0],
+ RMAP_EVENT_PLIST_DELETED);
}
ALIAS (no_match_ip_next_hop_prefix_list,
@@ -295,7 +353,8 @@ DEFUN (match_ip_address,
"IP Access-list name\n")
{
- return zebra_route_match_add (vty, vty->index, "ip address", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "ip address", argv[0],
+ RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_ip_address,
@@ -307,9 +366,11 @@ DEFUN (no_match_ip_address,
"Match address of route\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "ip address", NULL);
+ return zebra_route_match_delete (vty, vty->index, "ip address", NULL,
+ RMAP_EVENT_FILTER_DELETED);
- return zebra_route_match_delete (vty, vty->index, "ip address", argv[0]);
+ return zebra_route_match_delete (vty, vty->index, "ip address", argv[0],
+ RMAP_EVENT_FILTER_DELETED);
}
ALIAS (no_match_ip_address,
@@ -332,7 +393,8 @@ DEFUN (match_ip_address_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
{
- return zebra_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]);
+ return zebra_route_match_add (vty, vty->index, "ip address prefix-list",
+ argv[0], RMAP_EVENT_PLIST_ADDED);
}
DEFUN (no_match_ip_address_prefix_list,
@@ -345,9 +407,13 @@ DEFUN (no_match_ip_address_prefix_list,
"Match entries of prefix-lists\n")
{
if (argc == 0)
- return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
+ return zebra_route_match_delete (vty, vty->index,
+ "ip address prefix-list", NULL,
+ RMAP_EVENT_PLIST_DELETED);
- return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
+ return zebra_route_match_delete (vty, vty->index,
+ "ip address prefix-list", argv[0],
+ RMAP_EVENT_PLIST_DELETED);
}
ALIAS (no_match_ip_address_prefix_list,
@@ -360,6 +426,129 @@ ALIAS (no_match_ip_address_prefix_list,
"Match entries of prefix-lists\n"
"IP prefix-list name\n")
+DEFUN (match_ip_address_prefix_len,
+ match_ip_address_prefix_len_cmd,
+ "match ip address prefix-len NUMBER",
+ MATCH_STR
+ IP_STR
+ "Match prefix length of ip address\n"
+ "Match prefix length of ip address\n"
+ "Prefix length\n")
+{
+ return zebra_route_match_add (vty, vty->index, "ip address prefix-len",
+ argv[0], RMAP_EVENT_MATCH_ADDED);
+}
+
+DEFUN (no_match_ip_address_prefix_len,
+ no_match_ip_address_prefix_len_cmd,
+ "no match ip address prefix-len",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match prefixlen of ip address of route\n"
+ "prefix length of ip address\n")
+{
+ if (argc == 0)
+ return zebra_route_match_delete (vty, vty->index,
+ "ip address prefix-len", NULL,
+ RMAP_EVENT_MATCH_DELETED);
+
+ return zebra_route_match_delete (vty, vty->index,
+ "ip address prefix-len", argv[0],
+ RMAP_EVENT_MATCH_DELETED);
+}
+
+ALIAS (no_match_ip_address_prefix_len,
+ no_match_ip_address_prefix_len_val_cmd,
+ "no match ip address prefix-len NUMBER",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match prefixlen of ip address of route\n"
+ "prefix length of ip address\n")
+
+DEFUN (match_ip_nexthop_prefix_len,
+ match_ip_nexthop_prefix_len_cmd,
+ "match ip next-hop prefix-len NUMBER",
+ MATCH_STR
+ IP_STR
+ "Match prefixlen of nexthop ip address\n"
+ "Match prefixlen of given nexthop\n"
+ "Prefix length\n")
+{
+ return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-len",
+ argv[0], RMAP_EVENT_MATCH_ADDED);
+}
+
+DEFUN (no_match_ip_nexthop_prefix_len,
+ no_match_ip_nexthop_prefix_len_cmd,
+ "no match ip next-hop prefix-len",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match prefixlen of nexthop ip address\n"
+ "Match prefix length of nexthop\n")
+{
+ if (argc == 0)
+ return zebra_route_match_delete (vty, vty->index,
+ "ip next-hop prefix-len", NULL,
+ RMAP_EVENT_MATCH_DELETED);
+
+ return zebra_route_match_delete (vty, vty->index,
+ "ip next-hop prefix-len", argv[0],
+ RMAP_EVENT_MATCH_DELETED);
+}
+
+ALIAS (no_match_ip_nexthop_prefix_len,
+ no_match_ip_nexthop_prefix_len_val_cmd,
+ "no match ip next-hop prefix-len NUMBER",
+ MATCH_STR
+ "Match prefixlen of ip address of route\n"
+ "prefix length of ip address\n")
+
+DEFUN (match_source_protocol,
+ match_source_protocol_cmd,
+ "match source-protocol (bgp|ospf|rip|ripng|isis|ospf6|connected|system|kernel|static)",
+ MATCH_STR
+ "Match protocol via which the route was learnt\n")
+{
+ int i;
+
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return zebra_route_match_add (vty, vty->index, "source-protocol",
+ argv[0], RMAP_EVENT_MATCH_ADDED);
+}
+
+DEFUN (no_match_source_protocol,
+ no_match_source_protocol_cmd,
+ "no match source-protocol (bgp|ospf|rip|ripng|isis|ospf6|connected|system|kernel|static)",
+ NO_STR
+ MATCH_STR
+ "No match protocol via which the route was learnt\n")
+{
+ int i;
+
+ if (argc >= 1)
+ {
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ return zebra_route_match_delete (vty, vty->index,
+ "source-protocol", argv[0] ? argv[0] : NULL,
+ RMAP_EVENT_MATCH_DELETED);
+}
+
/* set functions */
DEFUN (set_src,
@@ -413,6 +602,340 @@ ALIAS (no_set_src,
"src address for route\n"
"src address\n")
+DEFUN (zebra_route_map_timer,
+ zebra_route_map_timer_cmd,
+ "zebra route-map delay-timer <0-600>",
+ "Time to wait before route-map updates are processed\n"
+ "0 means event-driven updates are disabled\n")
+{
+ u_int32_t rmap_delay_timer;
+
+ VTY_GET_INTEGER_RANGE ("delay-timer", rmap_delay_timer, argv[0], 0, 600);
+ zebra_route_map_set_delay_timer(rmap_delay_timer);
+
+ return (CMD_SUCCESS);
+}
+
+DEFUN (no_zebra_route_map_timer,
+ no_zebra_route_map_timer_cmd,
+ "no zebra route-map delay-timer",
+ NO_STR
+ "Time to wait before route-map updates are processed\n"
+ "Reset delay-timer to default value, 30 secs\n")
+{
+ zebra_route_map_set_delay_timer(ZEBRA_RMAP_DEFAULT_UPDATE_TIMER);
+
+ return (CMD_SUCCESS);
+}
+
+DEFUN (ip_protocol,
+ ip_protocol_cmd,
+ "ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+ IP_STR
+ "Filter routing info exchanged between zebra and protocol\n"
+ QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "Route map name\n")
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (proto_rm[AFI_IP][i])
+ {
+ if (strcmp(proto_rm[AFI_IP][i], argv[1]) == 0)
+ return CMD_SUCCESS;
+
+ XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]);
+ }
+ proto_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
+ rib_update(VRF_DEFAULT);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_protocol,
+ no_ip_protocol_cmd,
+ "no ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA,
+ NO_STR
+ IP_STR
+ "Stop filtering routing info between zebra and protocol\n"
+ QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "Protocol from which to stop filtering routes\n")
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!proto_rm[AFI_IP][i])
+ return CMD_SUCCESS;
+
+ if ((argc == 2 && strcmp(argv[1], proto_rm[AFI_IP][i]) == 0) ||
+ (argc < 2))
+ {
+ XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]);
+ proto_rm[AFI_IP][i] = NULL;
+ rib_update(VRF_DEFAULT);
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_protocol,
+ no_ip_protocol_val_cmd,
+ "no ip protocol " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+ NO_STR
+ IP_STR
+ "Stop filtering routing info between zebra and protocol\n"
+ QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "route map name")
+
+DEFUN (show_ip_protocol,
+ show_ip_protocol_cmd,
+ "show ip protocol",
+ SHOW_STR
+ IP_STR
+ "IP protocol filtering status\n")
+{
+ int i;
+
+ vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE);
+ vty_out(vty, "------------------------%s", VTY_NEWLINE);
+ for (i=0;i<ZEBRA_ROUTE_MAX;i++)
+ {
+ if (proto_rm[AFI_IP][i])
+ vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i),
+ proto_rm[AFI_IP][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE);
+ }
+ if (proto_rm[AFI_IP][i])
+ vty_out (vty, "%-10s : %-10s%s", "any", proto_rm[AFI_IP][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_protocol_nht_rmap,
+ ip_protocol_nht_rmap_cmd,
+ "ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+ IP_STR
+ "Filter Next Hop tracking route resolution\n"
+ QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "Route map name\n")
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (nht_rm[AFI_IP][i])
+ {
+ if (strcmp(nht_rm[AFI_IP][i], argv[1]) == 0)
+ return CMD_SUCCESS;
+
+ XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP][i]);
+ }
+
+ nht_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
+ zebra_evaluate_rnh_table(0, AF_INET, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_protocol_nht_rmap,
+ no_ip_protocol_nht_rmap_cmd,
+ "no ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA,
+ NO_STR
+ IP_STR
+ "Filter Next Hop tracking route resolution\n"
+ QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA)
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!nht_rm[AFI_IP][i])
+ return CMD_SUCCESS;
+
+ if ((argc == 2 && strcmp(argv[1], nht_rm[AFI_IP][i]) == 0) ||
+ (argc < 2))
+ {
+ XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP][i]);
+ nht_rm[AFI_IP][i] = NULL;
+ zebra_evaluate_rnh_table(0, AF_INET, 1);
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_protocol_nht_rmap,
+ no_ip_protocol_nht_rmap_val_cmd,
+ "no ip nht " QUAGGA_IP_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+ IP_STR
+ "Filter Next Hop tracking route resolution\n"
+ QUAGGA_IP_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "Route map name\n")
+
+DEFUN (show_ip_protocol_nht,
+ show_ip_protocol_nht_cmd,
+ "show ip nht route-map",
+ SHOW_STR
+ IP_STR
+ "IP Next Hop tracking filtering status\n")
+{
+ int i;
+
+ vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE);
+ vty_out(vty, "------------------------%s", VTY_NEWLINE);
+ for (i=0;i<ZEBRA_ROUTE_MAX;i++)
+ {
+ if (nht_rm[AFI_IP][i])
+ vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i),
+ nht_rm[AFI_IP][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE);
+ }
+ if (nht_rm[AFI_IP][i])
+ vty_out (vty, "%-10s : %-10s%s", "any", nht_rm[AFI_IP][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_protocol_nht_rmap,
+ ipv6_protocol_nht_rmap_cmd,
+ "ipv6 nht " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+ IP6_STR
+ "Filter Next Hop tracking route resolution\n"
+ QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "Route map name\n")
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (nht_rm[AFI_IP6][i])
+ XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]);
+ nht_rm[AFI_IP6][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
+ zebra_evaluate_rnh_table(0, AF_INET6, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_protocol_nht_rmap,
+ no_ipv6_protocol_nht_rmap_cmd,
+ "no ipv6 nht " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA,
+ NO_STR
+ IP6_STR
+ "Filter Next Hop tracking route resolution\n"
+ QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA)
+{
+ int i;
+
+ if (strcasecmp(argv[0], "any") == 0)
+ i = ZEBRA_ROUTE_MAX;
+ else
+ i = proto_name2num(argv[0]);
+ if (i < 0)
+ {
+ vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (nht_rm[AFI_IP6][i])
+ XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]);
+
+ if ((argc == 2 && strcmp(argv[1], nht_rm[AFI_IP6][i]) == 0) ||
+ (argc < 2))
+ {
+ XFREE (MTYPE_ROUTE_MAP_NAME, nht_rm[AFI_IP6][i]);
+ nht_rm[AFI_IP6][i] = NULL;
+ zebra_evaluate_rnh_table(0, AF_INET6, 1);
+ }
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ipv6_protocol_nht_rmap,
+ no_ipv6_protocol_nht_rmap_val_cmd,
+ "no ipv6 nht " QUAGGA_IP6_PROTOCOL_MAP_STR_ZEBRA " route-map ROUTE-MAP",
+ NO_STR
+ IP6_STR
+ "Filter Next Hop tracking route resolution\n"
+ QUAGGA_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA
+ "Route map name\n")
+
+DEFUN (show_ipv6_protocol_nht,
+ show_ipv6_protocol_nht_cmd,
+ "show ipv6 nht route-map",
+ SHOW_STR
+ IP6_STR
+ "IPv6 protocol Next Hop filtering status\n")
+{
+ int i;
+
+ vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE);
+ vty_out(vty, "------------------------%s", VTY_NEWLINE);
+ for (i=0;i<ZEBRA_ROUTE_MAX;i++)
+ {
+ if (nht_rm[AFI_IP6][i])
+ vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i),
+ nht_rm[AFI_IP6][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE);
+ }
+ if (nht_rm[AFI_IP][i])
+ vty_out (vty, "%-10s : %-10s%s", "any", nht_rm[AFI_IP6][i],
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
/*XXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
/* `match ip next-hop IP_ACCESS_LIST' */
@@ -423,13 +946,16 @@ route_match_ip_next_hop (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
struct access_list *alist;
- struct nexthop *nexthop;
+ struct nh_rmap_obj *nh_data;
struct prefix_ipv4 p;
if (type == RMAP_ZEBRA)
{
- nexthop = object;
- switch (nexthop->type) {
+ nh_data = object;
+ if (!nh_data)
+ return RMAP_DENYMATCH;
+
+ switch (nh_data->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
case NEXTHOP_TYPE_IFNAME:
/* Interface routes can't match ip next-hop */
@@ -438,7 +964,7 @@ route_match_ip_next_hop (void *rule, struct prefix *prefix,
case NEXTHOP_TYPE_IPV4_IFNAME:
case NEXTHOP_TYPE_IPV4:
p.family = AF_INET;
- p.prefix = nexthop->gate.ipv4;
+ p.prefix = nh_data->nexthop->gate.ipv4;
p.prefixlen = IPV4_MAX_BITLEN;
break;
default:
@@ -485,13 +1011,16 @@ route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
struct prefix_list *plist;
- struct nexthop *nexthop;
+ struct nh_rmap_obj *nh_data;
struct prefix_ipv4 p;
if (type == RMAP_ZEBRA)
{
- nexthop = object;
- switch (nexthop->type) {
+ nh_data = (struct nh_rmap_obj *)object;
+ if (!nh_data)
+ return RMAP_DENYMATCH;
+
+ switch (nh_data->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
case NEXTHOP_TYPE_IFNAME:
/* Interface routes can't match ip next-hop */
@@ -500,7 +1029,7 @@ route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
case NEXTHOP_TYPE_IPV4_IFNAME:
case NEXTHOP_TYPE_IPV4:
p.family = AF_INET;
- p.prefix = nexthop->gate.ipv4;
+ p.prefix = nh_data->nexthop->gate.ipv4;
p.prefixlen = IPV4_MAX_BITLEN;
break;
default:
@@ -623,6 +1152,154 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
};
+/* `match ip address prefix-len PREFIXLEN' */
+
+static route_map_result_t
+route_match_ip_address_prefix_len (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_int32_t *prefixlen = (u_int32_t *)rule;
+
+ if (type == RMAP_ZEBRA)
+ {
+ return ((prefix->prefixlen == *prefixlen) ? RMAP_MATCH : RMAP_NOMATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_ip_address_prefix_len_compile (const char *arg)
+{
+ u_int32_t *prefix_len;
+ char *endptr = NULL;
+ unsigned long tmpval;
+
+ /* prefix len value shoud be integer. */
+ if (! all_digit (arg))
+ return NULL;
+
+ errno = 0;
+ tmpval = strtoul (arg, &endptr, 10);
+ if (*endptr != '\0' || errno || tmpval > UINT32_MAX)
+ return NULL;
+
+ prefix_len = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+
+ if (!prefix_len)
+ return prefix_len;
+
+ *prefix_len = tmpval;
+ return prefix_len;
+}
+
+static void
+route_match_ip_address_prefix_len_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_ip_address_prefix_len_cmd =
+{
+ "ip address prefix-len",
+ route_match_ip_address_prefix_len,
+ route_match_ip_address_prefix_len_compile,
+ route_match_ip_address_prefix_len_free
+};
+
+
+/* `match ip nexthop prefix-len PREFIXLEN' */
+
+static route_map_result_t
+route_match_ip_nexthop_prefix_len (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_int32_t *prefixlen = (u_int32_t *)rule;
+ struct nh_rmap_obj *nh_data;
+ struct prefix_ipv4 p;
+
+ if (type == RMAP_ZEBRA)
+ {
+ nh_data = (struct nh_rmap_obj *)object;
+ if (!nh_data || !nh_data->nexthop)
+ return RMAP_DENYMATCH;
+
+ switch (nh_data->nexthop->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IFNAME:
+ /* Interface routes can't match ip next-hop */
+ return RMAP_NOMATCH;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFNAME:
+ case NEXTHOP_TYPE_IPV4:
+ p.family = AF_INET;
+ p.prefix = nh_data->nexthop->gate.ipv4;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ break;
+ default:
+ return RMAP_NOMATCH;
+ }
+ return ((p.prefixlen == *prefixlen) ? RMAP_MATCH : RMAP_NOMATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+static struct route_map_rule_cmd route_match_ip_nexthop_prefix_len_cmd =
+{
+ "ip next-hop prefix-len",
+ route_match_ip_nexthop_prefix_len,
+ route_match_ip_address_prefix_len_compile, /* reuse */
+ route_match_ip_address_prefix_len_free /* reuse */
+};
+
+/* `match source-protocol PROTOCOL' */
+
+static route_map_result_t
+route_match_source_protocol (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_int32_t *rib_type = (u_int32_t *)rule;
+ struct nh_rmap_obj *nh_data;
+
+ if (type == RMAP_ZEBRA)
+ {
+ nh_data = (struct nh_rmap_obj *)object;
+ if (!nh_data)
+ return RMAP_DENYMATCH;
+
+ return ((nh_data->source_protocol == *rib_type)
+ ? RMAP_MATCH : RMAP_NOMATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_source_protocol_compile (const char *arg)
+{
+ u_int32_t *rib_type;
+ int i;
+
+ i = proto_name2num(arg);
+ rib_type = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+
+ *rib_type = i;
+
+ return rib_type;
+}
+
+static void
+route_match_source_protocol_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_source_protocol_cmd =
+{
+ "source-protocol",
+ route_match_source_protocol,
+ route_match_source_protocol_compile,
+ route_match_source_protocol_free
+};
+
/* `set src A.B.C.D' */
/* Set src. */
@@ -630,12 +1307,12 @@ static route_map_result_t
route_set_src (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
+ struct nh_rmap_obj *nh_data;
+
if (type == RMAP_ZEBRA)
{
- struct nexthop *nexthop;
-
- nexthop = object;
- nexthop->src = *(union g_addr *)rule;
+ nh_data = (struct nh_rmap_obj *)object;
+ nh_data->nexthop->rmap_src = *(union g_addr *)rule;
}
return RMAP_OKAY;
}
@@ -675,17 +1352,199 @@ static struct route_map_rule_cmd route_set_src_cmd =
route_set_src_free,
};
+static int
+zebra_route_map_update_timer (struct thread *thread)
+{
+ zebra_t_rmap_update = NULL;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("Event driven route-map update triggered");
+
+ rib_update(VRF_DEFAULT);
+ zebra_evaluate_rnh_table(0, AF_INET, 1);
+ zebra_evaluate_rnh_table(0, AF_INET6, 1);
+
+ return (0);
+}
+
+static void
+zebra_route_map_set_delay_timer(u_int32_t value)
+{
+ zebra_rmap_update_timer = value;
+ if (!value && zebra_t_rmap_update)
+ {
+ /* Event driven route map updates is being disabled */
+ /* But there's a pending timer. Fire it off now */
+ thread_cancel(zebra_t_rmap_update);
+ zebra_route_map_update_timer(zebra_t_rmap_update);
+ }
+}
+
+void
+zebra_route_map_write_delay_timer (struct vty *vty)
+{
+ if (vty && (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER))
+ vty_out (vty, "zebra route-map delay-timer %d%s", zebra_rmap_update_timer,
+ VTY_NEWLINE);
+ return;
+}
+
+route_map_result_t
+zebra_route_map_check (int family, int rib_type, struct prefix *p,
+ struct nexthop *nexthop, vrf_id_t vrf_id)
+{
+ struct route_map *rmap = NULL;
+ route_map_result_t ret = RMAP_MATCH;
+ struct nh_rmap_obj nh_obj;
+
+ nh_obj.nexthop = nexthop;
+ nh_obj.vrf_id = vrf_id;
+ nh_obj.source_protocol = rib_type;
+ nh_obj.metric = 0;
+
+ if (rib_type >= 0 && rib_type < ZEBRA_ROUTE_MAX)
+ rmap = route_map_lookup_by_name (proto_rm[family][rib_type]);
+ if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX])
+ rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]);
+ if (rmap) {
+ ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj);
+ }
+
+ return (ret);
+}
+
+route_map_result_t
+zebra_nht_route_map_check (int family, int client_proto, struct prefix *p,
+ struct rib * rib, struct nexthop *nexthop)
+{
+ struct route_map *rmap = NULL;
+ route_map_result_t ret = RMAP_MATCH;
+ struct nh_rmap_obj nh_obj;
+
+ nh_obj.nexthop = nexthop;
+ nh_obj.vrf_id = rib->vrf_id;
+ nh_obj.source_protocol = rib->type;
+ nh_obj.metric = rib->metric;
+
+ if (client_proto >= 0 && client_proto < ZEBRA_ROUTE_MAX)
+ rmap = route_map_lookup_by_name (nht_rm[family][client_proto]);
+ if (!rmap && nht_rm[family][ZEBRA_ROUTE_MAX])
+ rmap = route_map_lookup_by_name (nht_rm[family][ZEBRA_ROUTE_MAX]);
+ if (rmap) {
+ ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj);
+ }
+
+ return (ret);
+}
+
+static void
+zebra_route_map_mark_update (const char *rmap_name)
+{
+ /* rmap_update_timer of 0 means don't do route updates */
+ if (zebra_rmap_update_timer && !zebra_t_rmap_update)
+ zebra_t_rmap_update =
+ thread_add_timer(zebrad.master, zebra_route_map_update_timer, NULL,
+ zebra_rmap_update_timer);
+}
+
+static void
+zebra_route_map_add (const char *rmap_name)
+{
+ zebra_route_map_mark_update(rmap_name);
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
+}
+
+static void
+zebra_route_map_delete (const char *rmap_name)
+{
+ zebra_route_map_mark_update(rmap_name);
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
+}
+
+static void
+zebra_route_map_event (route_map_event_t event, const char *rmap_name)
+{
+ zebra_route_map_mark_update(rmap_name);
+ route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
+}
+
+/* ip protocol configuration write function */
+static int config_write_protocol(struct vty *vty)
+{
+ int i;
+
+ for (i=0;i<ZEBRA_ROUTE_MAX;i++)
+ {
+ if (proto_rm[AFI_IP][i])
+ vty_out (vty, "ip protocol %s route-map %s%s", zebra_route_string(i),
+ proto_rm[AFI_IP][i], VTY_NEWLINE);
+
+ if (nht_rm[AFI_IP][i])
+ vty_out (vty, "ip nht %s route-map %s%s", zebra_route_string(i),
+ nht_rm[AFI_IP][i], VTY_NEWLINE);
+
+ if (nht_rm[AFI_IP6][i])
+ vty_out (vty, "ipv6 nht %s route-map %s%s", zebra_route_string(i),
+ nht_rm[AFI_IP6][i], VTY_NEWLINE);
+ }
+
+ if (proto_rm[AFI_IP][ZEBRA_ROUTE_MAX])
+ vty_out (vty, "ip protocol %s route-map %s%s", "any",
+ proto_rm[AFI_IP][ZEBRA_ROUTE_MAX], VTY_NEWLINE);
+
+ if (nht_rm[AFI_IP][ZEBRA_ROUTE_MAX])
+ vty_out (vty, "ip nht %s route-map %s%s", "any",
+ nht_rm[AFI_IP][ZEBRA_ROUTE_MAX], VTY_NEWLINE);
+
+ if (nht_rm[AFI_IP6][ZEBRA_ROUTE_MAX])
+ vty_out (vty, "ipv6 nht %s route-map %s%s", "any",
+ nht_rm[AFI_IP6][ZEBRA_ROUTE_MAX], VTY_NEWLINE);
+
+ if (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER)
+ vty_out (vty, "zebra route-map delay-timer %d%s", zebra_rmap_update_timer,
+ VTY_NEWLINE);
+ return 1;
+}
+/* table node for protocol filtering */
+static struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 };
+
void
zebra_route_map_init ()
{
+ install_node (&protocol_node, config_write_protocol);
+ install_element (CONFIG_NODE, &ip_protocol_cmd);
+ install_element (CONFIG_NODE, &no_ip_protocol_cmd);
+ install_element (CONFIG_NODE, &no_ip_protocol_val_cmd);
+ install_element (VIEW_NODE, &show_ip_protocol_cmd);
+ install_element (ENABLE_NODE, &show_ip_protocol_cmd);
+ install_element (CONFIG_NODE, &ip_protocol_nht_rmap_cmd);
+ install_element (CONFIG_NODE, &no_ip_protocol_nht_rmap_cmd);
+ install_element (CONFIG_NODE, &no_ip_protocol_nht_rmap_val_cmd);
+ install_element (VIEW_NODE, &show_ip_protocol_nht_cmd);
+ install_element (ENABLE_NODE, &show_ip_protocol_nht_cmd);
+ install_element (CONFIG_NODE, &ipv6_protocol_nht_rmap_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_protocol_nht_rmap_cmd);
+ install_element (ENABLE_NODE, &no_ipv6_protocol_nht_rmap_val_cmd);
+ install_element (VIEW_NODE, &show_ipv6_protocol_nht_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_protocol_nht_cmd);
+ install_element (CONFIG_NODE, &zebra_route_map_timer_cmd);
+ install_element (CONFIG_NODE, &no_zebra_route_map_timer_cmd);
+
route_map_init ();
route_map_init_vty ();
+ route_map_add_hook (zebra_route_map_add);
+ route_map_delete_hook (zebra_route_map_delete);
+ route_map_event_hook (zebra_route_map_event);
+
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_ip_address_prefix_len_cmd);
+ route_map_install_match (&route_match_ip_nexthop_prefix_len_cmd);
+ route_map_install_match (&route_match_source_protocol_cmd);
/* */
route_map_install_set (&route_set_src_cmd);
/* */
@@ -704,7 +1563,15 @@ zebra_route_map_init ()
install_element (RMAP_NODE, &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, &match_ip_nexthop_prefix_len_cmd);
+ install_element (RMAP_NODE, &no_match_ip_nexthop_prefix_len_cmd);
+ install_element (RMAP_NODE, &no_match_ip_nexthop_prefix_len_val_cmd);
+ install_element (RMAP_NODE, &match_ip_address_prefix_len_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_prefix_len_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_prefix_len_val_cmd);
+ install_element (RMAP_NODE, &match_source_protocol_cmd);
+ install_element (RMAP_NODE, &no_match_source_protocol_cmd);
+ /* */
install_element (RMAP_NODE, &set_src_cmd);
install_element (RMAP_NODE, &no_set_src_cmd);
}
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 21b92ea9..965ea89c 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -28,8 +28,10 @@
#include "table.h"
#include "rib.h"
#include "vrf.h"
+#include "nexthop.h"
#include "zebra/zserv.h"
+#include "zebra/zebra_rnh.h"
static int do_show_ip_route(struct vty *vty, safi_t safi, vrf_id_t vrf_id);
static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn,
@@ -42,7 +44,8 @@ static int
zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd,
const char *dest_str, const char *mask_str,
const char *gate_str, const char *flag_str,
- const char *distance_str, const char *vrf_id_str)
+ const char *tag_str, const char *distance_str,
+ const char *vrf_id_str)
{
int ret;
u_char distance;
@@ -51,6 +54,7 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd,
struct in_addr mask;
const char *ifname;
u_char flag = 0;
+ u_short tag = 0;
vrf_id_t vrf_id = VRF_DEFAULT;
ret = str2prefix (dest_str, &p);
@@ -81,10 +85,18 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd,
else
distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
+ /* tag */
+ if (tag_str)
+ tag = atoi (tag_str);
+
/* VRF id */
if (vrf_id_str)
VTY_GET_INTEGER ("VRF ID", vrf_id, vrf_id_str);
+ /* tag */
+ if (tag_str)
+ tag = atoi(tag_str);
+
/* Null0 static route. */
if ((gate_str != NULL) && (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0))
{
@@ -94,9 +106,9 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd,
return CMD_WARNING;
}
if (add_cmd)
- static_add_ipv4_safi (safi, &p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, vrf_id);
+ static_add_ipv4_safi (safi, &p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, tag, distance, vrf_id);
else
- static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, vrf_id);
+ static_delete_ipv4_safi (safi, &p, NULL, NULL, tag, distance, vrf_id);
return CMD_SUCCESS;
}
@@ -120,9 +132,9 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd,
if (gate_str == NULL)
{
if (add_cmd)
- static_add_ipv4_safi (safi, &p, NULL, NULL, flag, distance, vrf_id);
+ static_add_ipv4_safi (safi, &p, NULL, NULL, flag, tag, distance, vrf_id);
else
- static_delete_ipv4_safi (safi, &p, NULL, NULL, distance, vrf_id);
+ static_delete_ipv4_safi (safi, &p, NULL, NULL, tag, distance, vrf_id);
return CMD_SUCCESS;
}
@@ -136,23 +148,13 @@ zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd,
ifname = gate_str;
if (add_cmd)
- static_add_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, flag, distance, vrf_id);
+ static_add_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, flag, tag, distance, vrf_id);
else
- static_delete_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, distance, vrf_id);
+ static_delete_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, tag, distance, vrf_id);
return CMD_SUCCESS;
}
-static int
-zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str,
- const char *mask_str, const char *gate_str,
- const char *flag_str, const char *distance_str,
- const char *vrf_id_str)
-{
- return zebra_static_ipv4_safi (vty, SAFI_UNICAST, add_cmd, dest_str, mask_str,
- gate_str, flag_str, distance_str, vrf_id_str);
-}
-
/* Static unicast routes for multicast RPF lookup. */
DEFUN (ip_mroute_dist,
ip_mroute_dist_cmd,
@@ -166,7 +168,7 @@ DEFUN (ip_mroute_dist,
{
VTY_WARN_EXPERIMENTAL();
return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1],
- NULL, argc > 2 ? argv[2] : NULL, NULL);
+ NULL, NULL, argc > 2 ? argv[2] : NULL, NULL);
}
ALIAS (ip_mroute_dist,
@@ -191,7 +193,7 @@ DEFUN (ip_mroute_dist_vrf,
{
VTY_WARN_EXPERIMENTAL();
return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1],
- NULL, argc > 3 ? argv[2] : NULL,
+ NULL, NULL, argc > 3 ? argv[2] : NULL,
argc > 3 ? argv[3] : argv[2]);
}
@@ -217,7 +219,7 @@ DEFUN (no_ip_mroute_dist,
{
VTY_WARN_EXPERIMENTAL();
return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1],
- NULL, argc > 2 ? argv[2] : NULL, NULL);
+ NULL, NULL, argc > 2 ? argv[2] : NULL, NULL);
}
ALIAS (no_ip_mroute_dist,
@@ -243,7 +245,7 @@ DEFUN (no_ip_mroute_dist_vrf,
{
VTY_WARN_EXPERIMENTAL();
return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1],
- NULL, argc > 3 ? argv[2] : NULL,
+ NULL, NULL, argc > 3 ? argv[2] : NULL,
argc > 3 ? argv[3] : argv[2]);
}
@@ -467,8 +469,41 @@ DEFUN (ip_route,
"IP gateway interface name\n"
"Null interface\n")
{
- return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL,
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1],
+ NULL, NULL, NULL, NULL);
+}
+
+DEFUN (ip_route_tag,
+ ip_route_tag_cmd,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ argv[1], NULL, argv[2], NULL, NULL);
+}
+
+DEFUN (ip_route_tag_vrf,
+ ip_route_tag_vrf_cmd,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ argv[1], NULL, argv[2], NULL, argv[3]);
}
DEFUN (ip_route_flags,
@@ -482,8 +517,44 @@ DEFUN (ip_route_flags,
"Emit an ICMP unreachable when matched\n"
"Silently discard pkts when matched\n")
{
- return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL,
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1],
+ argv[2], NULL, NULL, NULL);
+}
+
+DEFUN (ip_route_flags_tag,
+ ip_route_flags_tag_cmd,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1],
+ argv[2], argv[3], NULL, NULL);
+}
+
+DEFUN (ip_route_flags_tag_vrf,
+ ip_route_flags_tag_vrf_cmd,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1],
+ argv[2], argv[3], NULL, argv[4]);
}
DEFUN (ip_route_flags2,
@@ -495,8 +566,39 @@ DEFUN (ip_route_flags2,
"Emit an ICMP unreachable when matched\n"
"Silently discard pkts when matched\n")
{
- return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL,
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ NULL, argv[1], NULL, NULL, NULL);
+}
+
+DEFUN (ip_route_flags2_tag,
+ ip_route_flags2_tag_cmd,
+ "ip route A.B.C.D/M (reject|blackhole) tag <1-65535>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL,
+ argv[1], argv[2], NULL, NULL);
+}
+
+DEFUN (ip_route_flags2_tag_vrf,
+ ip_route_flags2_tag_vrf_cmd,
+ "ip route A.B.C.D/M (reject|blackhole) tag <1-65535>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL,
+ argv[1], argv[2], NULL, argv[3]);
}
/* Mask as A.B.C.D format. */
@@ -511,8 +613,44 @@ DEFUN (ip_route_mask,
"IP gateway interface name\n"
"Null interface\n")
{
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL,
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ argv[2], NULL, NULL, NULL, NULL);
+}
+
+DEFUN (ip_route_mask_tag,
+ ip_route_mask_tag_cmd,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2],
+ NULL, argv[3], NULL, NULL);
+}
+
+DEFUN (ip_route_mask_tag_vrf,
+ ip_route_mask_tag_vrf_cmd,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2],
+ NULL, argv[3], NULL, argv[4]);
}
DEFUN (ip_route_mask_flags,
@@ -527,8 +665,45 @@ DEFUN (ip_route_mask_flags,
"Emit an ICMP unreachable when matched\n"
"Silently discard pkts when matched\n")
{
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL,
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ argv[2], argv[3], NULL, NULL, NULL);
+}
+
+DEFUN (ip_route_mask_flags_tag,
+ ip_route_mask_flags_tag_cmd,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ argv[2], argv[3], argv[4], NULL, NULL);
+}
+
+DEFUN (ip_route_mask_flags_tag_vrf,
+ ip_route_mask_flags_tag_vrf_cmd,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ argv[2], argv[3], argv[4], NULL, argv[5]);
}
DEFUN (ip_route_mask_flags2,
@@ -541,8 +716,41 @@ DEFUN (ip_route_mask_flags2,
"Emit an ICMP unreachable when matched\n"
"Silently discard pkts when matched\n")
{
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL,
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ NULL, argv[2], NULL, NULL, NULL);
+}
+
+DEFUN (ip_route_mask_flags2_tag,
+ ip_route_mask_flags2_tag_cmd,
+ "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL,
+ argv[2], argv[3], NULL, NULL);
+}
+
+DEFUN (ip_route_mask_flags2_tag_vrf,
+ ip_route_mask_flags2_tag_vrf_cmd,
+ "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL,
+ argv[2], argv[3], NULL, argv[4]);
}
/* Distance option value. */
@@ -557,8 +765,43 @@ DEFUN (ip_route_distance,
"Null interface\n"
"Distance value for this route\n")
{
- return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2],
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ argv[1], NULL, NULL, argv[2], NULL);
+}
+
+DEFUN (ip_route_tag_distance,
+ ip_route_tag_distance_cmd,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ argv[1], NULL, argv[2], argv[3], NULL);
+}
+
+DEFUN (ip_route_tag_distance_vrf,
+ ip_route_tag_distance_vrf_cmd,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ argv[1], NULL, argv[2], argv[3], argv[4]);
}
DEFUN (ip_route_flags_distance,
@@ -573,8 +816,45 @@ DEFUN (ip_route_flags_distance,
"Silently discard pkts when matched\n"
"Distance value for this route\n")
{
- return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3],
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1],
+ argv[2], NULL, argv[3], NULL);
+}
+
+DEFUN (ip_route_flags_tag_distance,
+ ip_route_flags_tag_distance_cmd,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1],
+ argv[2], argv[3], argv[4], NULL);
+}
+
+DEFUN (ip_route_flags_tag_distance_vrf,
+ ip_route_flags_tag_distance_vrf_cmd,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1],
+ argv[2], argv[3], argv[4], argv[5]);
}
DEFUN (ip_route_flags_distance2,
@@ -587,8 +867,41 @@ DEFUN (ip_route_flags_distance2,
"Silently discard pkts when matched\n"
"Distance value for this route\n")
{
- return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2],
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ NULL, argv[1], NULL, argv[2], NULL);
+}
+
+DEFUN (ip_route_flags_tag_distance2,
+ ip_route_flags_tag_distance2_cmd,
+ "ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ NULL, argv[1], argv[2], argv[3], NULL);
+}
+
+DEFUN (ip_route_flags_tag_distance2_vrf,
+ ip_route_flags_tag_distance2_vrf_cmd,
+ "ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ NULL, argv[1], argv[2], argv[3], argv[4]);
}
DEFUN (ip_route_mask_distance,
@@ -603,8 +916,85 @@ DEFUN (ip_route_mask_distance,
"Null interface\n"
"Distance value for this route\n")
{
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3],
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2],
+ NULL, NULL, argv[3], NULL);
+}
+
+DEFUN (ip_route_mask_tag_distance,
+ ip_route_mask_tag_distance_cmd,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ argv[2], NULL, argv[3], argv[4], NULL);
+}
+
+DEFUN (ip_route_mask_tag_distance_vrf,
+ ip_route_mask_tag_distance_vrf_cmd,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ argv[2], NULL, argv[3], argv[4], argv[5]);
+}
+
+
+DEFUN (ip_route_mask_flags_tag_distance,
+ ip_route_mask_flags_tag_distance_cmd,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2],
+ argv[3], argv[4], argv[5], NULL);
+}
+
+DEFUN (ip_route_mask_flags_tag_distance_vrf,
+ ip_route_mask_flags_tag_distance_vrf_cmd,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2],
+ argv[3], argv[4], argv[5], argv[6]);
}
DEFUN (ip_route_mask_flags_distance,
@@ -620,8 +1010,8 @@ DEFUN (ip_route_mask_flags_distance,
"Silently discard pkts when matched\n"
"Distance value for this route\n")
{
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4],
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2],
+ argv[3], NULL, argv[4], NULL);
}
DEFUN (ip_route_mask_flags_distance2,
@@ -635,8 +1025,43 @@ DEFUN (ip_route_mask_flags_distance2,
"Silently discard pkts when matched\n"
"Distance value for this route\n")
{
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3],
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ NULL, argv[2], NULL, argv[3], NULL);
+}
+
+DEFUN (ip_route_mask_flags_tag_distance2,
+ ip_route_mask_flags_tag_distance2_cmd,
+ "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL,
+ argv[2], argv[3], argv[4], NULL);
+}
+
+DEFUN (ip_route_mask_flags_tag_distance2_vrf,
+ ip_route_mask_flags_tag_distance2_vrf_cmd,
+ "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL,
+ argv[2], argv[3], argv[4], argv[5]);
}
DEFUN (no_ip_route,
@@ -650,8 +1075,43 @@ DEFUN (no_ip_route,
"IP gateway interface name\n"
"Null interface\n")
{
- return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL,
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL,
+ argv[1], NULL, NULL, NULL, NULL);
+}
+
+DEFUN (no_ip_route_tag,
+ no_ip_route_tag_cmd,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Tag of this route\n"
+ "Tag value\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1],
+ NULL, argv[2], NULL, NULL);
+}
+
+DEFUN (no_ip_route_tag_vrf,
+ no_ip_route_tag_vrf_cmd,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1],
+ NULL, argv[2], NULL, argv[3]);
}
ALIAS (no_ip_route,
@@ -666,6 +1126,20 @@ ALIAS (no_ip_route,
"Emit an ICMP unreachable when matched\n"
"Silently discard pkts when matched\n")
+ALIAS (no_ip_route_tag,
+ no_ip_route_flags_tag_cmd,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n")
+
DEFUN (no_ip_route_flags2,
no_ip_route_flags2_cmd,
"no ip route A.B.C.D/M (reject|blackhole)",
@@ -676,8 +1150,41 @@ DEFUN (no_ip_route_flags2,
"Emit an ICMP unreachable when matched\n"
"Silently discard pkts when matched\n")
{
- return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, NULL,
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL,
+ NULL, NULL, NULL, NULL, NULL);
+}
+
+DEFUN (no_ip_route_flags2_tag,
+ no_ip_route_flags2_tag_cmd,
+ "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL,
+ NULL, argv[1], NULL, NULL);
+}
+
+DEFUN (no_ip_route_flags2_tag_vrf,
+ no_ip_route_flags2_tag_vrf_cmd,
+ "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL,
+ NULL, argv[1], NULL, argv[2]);
}
DEFUN (no_ip_route_mask,
@@ -692,8 +1199,26 @@ DEFUN (no_ip_route_mask,
"IP gateway interface name\n"
"Null interface\n")
{
- return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, NULL,
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1],
+ argv[2], NULL, NULL, NULL, NULL);
+}
+
+DEFUN (no_ip_route_mask_tag,
+ no_ip_route_mask_tag_cmd,
+ "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Tag of this route\n"
+ "Tag value\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2],
+ NULL, argv[3], NULL, NULL);
}
ALIAS (no_ip_route_mask,
@@ -709,6 +1234,21 @@ ALIAS (no_ip_route_mask,
"Emit an ICMP unreachable when matched\n"
"Silently discard pkts when matched\n")
+ALIAS (no_ip_route_mask_tag,
+ no_ip_route_mask_flags_tag_cmd,
+ "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n")
+
DEFUN (no_ip_route_mask_flags2,
no_ip_route_mask_flags2_cmd,
"no ip route A.B.C.D A.B.C.D (reject|blackhole)",
@@ -720,8 +1260,43 @@ DEFUN (no_ip_route_mask_flags2,
"Emit an ICMP unreachable when matched\n"
"Silently discard pkts when matched\n")
{
- return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, NULL,
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1],
+ NULL, NULL, NULL, NULL, NULL);
+}
+
+DEFUN (no_ip_route_mask_flags2_tag,
+ no_ip_route_mask_flags2_tag_cmd,
+ "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1],
+ NULL, NULL, argv[2], NULL, NULL);
+}
+
+DEFUN (no_ip_route_mask_flags2_tag_vrf,
+ no_ip_route_mask_flags2_tag_vrf_cmd,
+ "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1],
+ NULL, NULL, argv[2], NULL, argv[3]);
}
DEFUN (no_ip_route_distance,
@@ -736,8 +1311,45 @@ DEFUN (no_ip_route_distance,
"Null interface\n"
"Distance value for this route\n")
{
- return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2],
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL,
+ argv[1], NULL, NULL, argv[2], NULL);
+}
+
+DEFUN (no_ip_route_tag_distance,
+ no_ip_route_tag_distance_cmd,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1],
+ NULL, argv[2], argv[3], NULL);
+}
+
+DEFUN (no_ip_route_tag_distance_vrf,
+ no_ip_route_tag_distance_vrf_cmd,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1],
+ NULL, argv[2], argv[3], argv[4]);
}
DEFUN (no_ip_route_flags_distance,
@@ -753,8 +1365,47 @@ DEFUN (no_ip_route_flags_distance,
"Silently discard pkts when matched\n"
"Distance value for this route\n")
{
- return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3],
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL,
+ argv[1], argv[2], NULL, argv[3], NULL);
+}
+
+DEFUN (no_ip_route_flags_tag_distance,
+ no_ip_route_flags_tag_distance_cmd,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1],
+ argv[2], argv[3], argv[4], NULL);
+}
+
+DEFUN (no_ip_route_flags_tag_distance_vrf,
+ no_ip_route_flags_tag_distance_vrf_cmd,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1],
+ argv[2], argv[3], argv[4], argv[5]);
}
DEFUN (no_ip_route_flags_distance2,
@@ -768,8 +1419,43 @@ DEFUN (no_ip_route_flags_distance2,
"Silently discard pkts when matched\n"
"Distance value for this route\n")
{
- return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2],
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL,
+ argv[1], NULL, argv[2], NULL);
+}
+
+DEFUN (no_ip_route_flags_tag_distance2,
+ no_ip_route_flags_tag_distance2_cmd,
+ "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL,
+ argv[1], argv[2] , argv[3], NULL);
+}
+
+DEFUN (no_ip_route_flags_tag_distance2_vrf,
+ no_ip_route_flags_tag_distance2_vrf_cmd,
+ "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL,
+ argv[1], argv[2] , argv[3], argv[4]);
}
DEFUN (no_ip_route_mask_distance,
@@ -785,8 +1471,47 @@ DEFUN (no_ip_route_mask_distance,
"Null interface\n"
"Distance value for this route\n")
{
- return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3],
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1],
+ argv[2], NULL, NULL, argv[3], NULL);
+}
+
+DEFUN (no_ip_route_mask_tag_distance,
+ no_ip_route_mask_tag_distance_cmd,
+ "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1],
+ argv[2], NULL, argv[3], argv[4], NULL);
+}
+
+DEFUN (no_ip_route_mask_tag_distance_vrf,
+ no_ip_route_mask_tag_distance_vrf_cmd,
+ "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Null interface\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1],
+ argv[2], NULL, argv[3], argv[4], argv[5]);
}
DEFUN (no_ip_route_mask_flags_distance,
@@ -803,8 +1528,49 @@ DEFUN (no_ip_route_mask_flags_distance,
"Silently discard pkts when matched\n"
"Distance value for this route\n")
{
- return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4],
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1],
+ argv[2], argv[3], NULL, argv[4], NULL);
+}
+
+DEFUN (no_ip_route_mask_flags_tag_distance,
+ no_ip_route_mask_flags_tag_distance_cmd,
+ "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ "Distance value for this route\n")
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], argv[3],
+ argv[4], argv[5], NULL);
+}
+
+DEFUN (no_ip_route_mask_flags_tag_distance_vrf,
+ no_ip_route_mask_flags_tag_distance_vrf_cmd,
+ "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR)
+{
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], argv[3],
+ argv[4], argv[5], argv[6]);
}
DEFUN (no_ip_route_mask_flags_distance2,
@@ -819,8 +1585,8 @@ DEFUN (no_ip_route_mask_flags_distance2,
"Silently discard pkts when matched\n"
"Distance value for this route\n")
{
- return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3],
- NULL);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1],
+ NULL, argv[2], NULL, argv[3], NULL);
}
DEFUN (ip_route_vrf,
@@ -834,8 +1600,8 @@ DEFUN (ip_route_vrf,
"Null interface\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL,
- argv[2]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ argv[1], NULL, NULL, NULL, argv[2]);
}
DEFUN (ip_route_flags_vrf,
@@ -850,8 +1616,8 @@ DEFUN (ip_route_flags_vrf,
"Silently discard pkts when matched\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL,
- argv[3]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ argv[1], argv[2], NULL, NULL, argv[3]);
}
DEFUN (ip_route_flags2_vrf,
@@ -864,8 +1630,8 @@ DEFUN (ip_route_flags2_vrf,
"Silently discard pkts when matched\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL,
- argv[2]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ NULL, argv[1], NULL, NULL, argv[2]);
}
/* Mask as A.B.C.D format. */
@@ -881,8 +1647,8 @@ DEFUN (ip_route_mask_vrf,
"Null interface\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL,
- argv[3]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ argv[2], NULL, NULL, NULL, argv[3]);
}
DEFUN (ip_route_mask_flags_vrf,
@@ -898,8 +1664,8 @@ DEFUN (ip_route_mask_flags_vrf,
"Silently discard pkts when matched\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL,
- argv[4]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ argv[2], argv[3], NULL, NULL, argv[4]);
}
DEFUN (ip_route_mask_flags2_vrf,
@@ -913,8 +1679,8 @@ DEFUN (ip_route_mask_flags2_vrf,
"Silently discard pkts when matched\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL,
- argv[3]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ NULL, argv[2], NULL, NULL, argv[3]);
}
/* Distance option value. */
@@ -930,8 +1696,8 @@ DEFUN (ip_route_distance_vrf,
"Distance value for this route\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2],
- argv[3]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ argv[1], NULL, NULL, argv[2], argv[3]);
}
DEFUN (ip_route_flags_distance_vrf,
@@ -947,8 +1713,8 @@ DEFUN (ip_route_flags_distance_vrf,
"Distance value for this route\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3],
- argv[4]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ argv[1], argv[2], NULL, argv[3], argv[4]);
}
DEFUN (ip_route_flags_distance2_vrf,
@@ -962,8 +1728,8 @@ DEFUN (ip_route_flags_distance2_vrf,
"Distance value for this route\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2],
- argv[3]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL,
+ NULL, argv[1], NULL, argv[2], argv[3]);
}
DEFUN (ip_route_mask_distance_vrf,
@@ -979,8 +1745,8 @@ DEFUN (ip_route_mask_distance_vrf,
"Distance value for this route\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3],
- argv[4]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ argv[2], NULL, NULL, argv[3], argv[4]);
}
DEFUN (ip_route_mask_flags_distance_vrf,
@@ -997,8 +1763,8 @@ DEFUN (ip_route_mask_flags_distance_vrf,
"Distance value for this route\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ argv[2], argv[3], NULL, argv[4], argv[5]);
}
DEFUN (ip_route_mask_flags_distance2_vrf,
@@ -1013,8 +1779,8 @@ DEFUN (ip_route_mask_flags_distance2_vrf,
"Distance value for this route\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3],
- argv[4]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1],
+ NULL, argv[2], NULL, argv[3], argv[4]);
}
DEFUN (no_ip_route_vrf,
@@ -1029,8 +1795,9 @@ DEFUN (no_ip_route_vrf,
"Null interface\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL,
- (argc > 3) ? argv[3] : argv[2]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0],
+ NULL, argv[1], NULL, NULL, NULL,
+ (argc > 3) ? argv[3] : argv[2]);
}
ALIAS (no_ip_route_vrf,
@@ -1057,8 +1824,8 @@ DEFUN (no_ip_route_flags2_vrf,
"Silently discard pkts when matched\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, NULL,
- argv[2]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0],
+ NULL, NULL, NULL, NULL, NULL, argv[2]);
}
DEFUN (no_ip_route_mask_vrf,
@@ -1074,8 +1841,9 @@ DEFUN (no_ip_route_mask_vrf,
"Null interface\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, NULL,
- (argc > 4) ? argv[4] : argv[3]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1],
+ argv[2], NULL, NULL, NULL,
+ (argc > 4) ? argv[4] : argv[3]);
}
ALIAS (no_ip_route_mask_vrf,
@@ -1104,8 +1872,8 @@ DEFUN (no_ip_route_mask_flags2_vrf,
"Silently discard pkts when matched\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, NULL,
- argv[2]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1],
+ NULL, NULL, NULL, NULL, argv[2]);
}
DEFUN (no_ip_route_distance_vrf,
@@ -1121,8 +1889,8 @@ DEFUN (no_ip_route_distance_vrf,
"Distance value for this route\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2],
- argv[3]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL,
+ argv[1], NULL, NULL, argv[2], argv[3]);
}
DEFUN (no_ip_route_flags_distance_vrf,
@@ -1139,8 +1907,8 @@ DEFUN (no_ip_route_flags_distance_vrf,
"Distance value for this route\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3],
- argv[4]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1],
+ argv[2], NULL, argv[3], argv[4]);
}
DEFUN (no_ip_route_flags_distance2_vrf,
@@ -1155,8 +1923,8 @@ DEFUN (no_ip_route_flags_distance2_vrf,
"Distance value for this route\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2],
- argv[3]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL,
+ argv[1], NULL, argv[2], argv[3]);
}
DEFUN (no_ip_route_mask_distance_vrf,
@@ -1173,8 +1941,8 @@ DEFUN (no_ip_route_mask_distance_vrf,
"Distance value for this route\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3],
- argv[4]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1],
+ argv[2], NULL, NULL, argv[3], argv[4]);
}
DEFUN (no_ip_route_mask_flags_distance_vrf,
@@ -1192,8 +1960,8 @@ DEFUN (no_ip_route_mask_flags_distance_vrf,
"Distance value for this route\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2],
+ argv[3], NULL, argv[4], argv[5]);
}
DEFUN (no_ip_route_mask_flags_distance2_vrf,
@@ -1209,63 +1977,49 @@ DEFUN (no_ip_route_mask_flags_distance2_vrf,
"Distance value for this route\n"
VRF_CMD_HELP_STR)
{
- return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3],
- argv[4]);
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL,
+ argv[2], NULL, argv[3], argv[4]);
}
-char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */
-
-DEFUN (ip_protocol,
- ip_protocol_cmd,
- "ip protocol PROTO route-map ROUTE-MAP",
+DEFUN (no_ip_route_mask_flags_tag_distance2,
+ no_ip_route_mask_flags_tag_distance2_cmd,
+ "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>",
NO_STR
- "Apply route map to PROTO\n"
- "Protocol name\n"
- "Route map name\n")
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ "Distance value for this route\n")
{
- int i;
-
- if (strcasecmp(argv[0], "any") == 0)
- i = ZEBRA_ROUTE_MAX;
- else
- i = proto_name2num(argv[0]);
- if (i < 0)
- {
- vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- if (proto_rm[AFI_IP][i])
- XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]);
- proto_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]);
- return CMD_SUCCESS;
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL,
+ argv[2], argv[3], argv[4], NULL);
}
-DEFUN (no_ip_protocol,
- no_ip_protocol_cmd,
- "no ip protocol PROTO",
+DEFUN (no_ip_route_mask_flags_tag_distance2_vrf,
+ no_ip_route_mask_flags_tag_distance2_vrf_cmd,
+ "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR,
NO_STR
- "Remove route map from PROTO\n"
- "Protocol name\n")
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Tag of this route\n"
+ "Tag value\n"
+ "Distance value for this route\n"
+ VRF_CMD_HELP_STR)
{
- int i;
-
- if (strcasecmp(argv[0], "any") == 0)
- i = ZEBRA_ROUTE_MAX;
- else
- i = proto_name2num(argv[0]);
- if (i < 0)
- {
- vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- if (proto_rm[AFI_IP][i])
- XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]);
- proto_rm[AFI_IP][i] = NULL;
- return CMD_SUCCESS;
+ return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL,
+ argv[2], argv[3], argv[4], argv[5]);
}
+extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */
+
/* New RIB. Detailed information for IPv4 route. */
static void
vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast)
@@ -1292,6 +2046,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast)
vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric);
if (rib->mtu)
vty_out (vty, ", mtu %u", rib->mtu);
+ vty_out (vty, ", tag %d", rib->tag);
vty_out (vty, ", vrf %u", rib->vrf_id);
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
vty_out (vty, ", best");
@@ -1609,6 +2364,81 @@ ALIAS (show_ip_route,
"IP routing table\n"
VRF_CMD_HELP_STR)
+DEFUN (show_ip_nht,
+ show_ip_nht_cmd,
+ "show ip nht",
+ SHOW_STR
+ IP_STR
+ "IP nexthop tracking table\n")
+{
+ zebra_print_rnh_table(0, AF_INET, vty);
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_nht,
+ show_ipv6_nht_cmd,
+ "show ipv6 nht",
+ SHOW_STR
+ IP_STR
+ "IPv6 nexthop tracking table\n")
+{
+ zebra_print_rnh_table(0, AF_INET6, vty);
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_tag,
+ show_ip_route_tag_cmd,
+ "show ip route tag <1-65535>",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "Show only routes with tag\n"
+ "Tag value\n")
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *rib;
+ int first = 1;
+ u_short tag = 0;
+ vrf_id_t vrf_id = VRF_DEFAULT;
+
+ if (argv[0])
+ tag = atoi(argv[0]);
+
+ if (argc == 2)
+ VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+
+ table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
+ if (! table)
+ return CMD_SUCCESS;
+
+ /* Show all IPv4 routes with matching tag value. */
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ RNODE_FOREACH_RIB (rn, rib)
+ {
+ if (rib->tag != tag)
+ continue;
+
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V4_HEADER);
+ first = 0;
+ }
+ vty_show_ip_route (vty, rn, rib);
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS (show_ip_route_tag,
+ show_ip_route_tag_vrf_cmd,
+ "show ip route tag <1-65535>" VRF_CMD_STR,
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "Show only routes with tag\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+
DEFUN (show_ip_route_prefix_longer,
show_ip_route_prefix_longer_cmd,
"show ip route A.B.C.D/M longer-prefixes",
@@ -2443,6 +3273,9 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd)
vty_out (vty, " %s", "blackhole");
}
+ if (si->tag)
+ vty_out (vty, " tag %d", si->tag);
+
if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
vty_out (vty, " %d", si->distance);
@@ -2457,42 +3290,12 @@ static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd)
return write;
}
-DEFUN (show_ip_protocol,
- show_ip_protocol_cmd,
- "show ip protocol",
- SHOW_STR
- IP_STR
- "IP protocol filtering status\n")
-{
- int i;
-
- vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE);
- vty_out(vty, "------------------------%s", VTY_NEWLINE);
- for (i=0;i<ZEBRA_ROUTE_MAX;i++)
- {
- if (proto_rm[AFI_IP][i])
- vty_out (vty, "%-10s : %-10s%s", zebra_route_string(i),
- proto_rm[AFI_IP][i],
- VTY_NEWLINE);
- else
- vty_out (vty, "%-10s : none%s", zebra_route_string(i), VTY_NEWLINE);
- }
- if (proto_rm[AFI_IP][i])
- vty_out (vty, "%-10s : %-10s%s", "any", proto_rm[AFI_IP][i],
- VTY_NEWLINE);
- else
- vty_out (vty, "%-10s : none%s", "any", VTY_NEWLINE);
-
- return CMD_SUCCESS;
-}
-
-#ifdef HAVE_IPV6
/* General fucntion for IPv6 static route. */
static int
static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
const char *gate_str, const char *ifname,
- const char *flag_str, const char *distance_str,
- const char *vrf_id_str)
+ const char *flag_str, const char *tag_str,
+ const char *distance_str, const char *vrf_id_str)
{
int ret;
u_char distance;
@@ -2502,6 +3305,7 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
u_char type = 0;
vrf_id_t vrf_id = VRF_DEFAULT;
u_char flag = 0;
+ u_short tag = 0;
ret = str2prefix (dest_str, &p);
if (ret <= 0)
@@ -2536,6 +3340,14 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
else
distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
+ /* tag */
+ if (tag_str)
+ tag = atoi (tag_str);
+
+ /* tag */
+ if (tag_str)
+ tag = atoi(tag_str);
+
/* When gateway is valid IPv6 addrees, then gate is treated as
nexthop address other case gate is treated as interface name. */
ret = inet_pton (AF_INET6, gate_str, &gate_addr);
@@ -2571,9 +3383,9 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
VTY_GET_INTEGER ("VRF ID", vrf_id, vrf_id_str);
if (add_cmd)
- static_add_ipv6 (&p, type, gate, ifname, flag, distance, vrf_id);
+ static_add_ipv6 (&p, type, gate, ifname, flag, tag, distance, vrf_id);
else
- static_delete_ipv6 (&p, type, gate, ifname, distance, vrf_id);
+ static_delete_ipv6 (&p, type, gate, ifname, tag, distance, vrf_id);
return CMD_SUCCESS;
}
@@ -2588,7 +3400,36 @@ DEFUN (ipv6_route,
"IPv6 gateway interface name\n")
{
return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL,
- NULL);
+ NULL, NULL);
+}
+
+DEFUN (ipv6_route_tag,
+ ipv6_route_tag_cmd,
+ "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>",
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], NULL, NULL);
+}
+
+DEFUN (ipv6_route_tag_vrf,
+ ipv6_route_tag_vrf_cmd,
+ "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], NULL, argv[3]);
}
DEFUN (ipv6_route_flags,
@@ -2603,7 +3444,40 @@ DEFUN (ipv6_route_flags,
"Silently discard pkts when matched\n")
{
return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL,
- NULL);
+ NULL, NULL);
+}
+
+DEFUN (ipv6_route_flags_tag,
+ ipv6_route_flags_tag_cmd,
+ "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>",
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], NULL, NULL);
+}
+
+DEFUN (ipv6_route_flags_tag_vrf,
+ ipv6_route_flags_tag_vrf_cmd,
+ "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], NULL, argv[4]);
}
DEFUN (ipv6_route_ifname,
@@ -2616,7 +3490,36 @@ DEFUN (ipv6_route_ifname,
"IPv6 gateway interface name\n")
{
return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL,
- NULL);
+ NULL, NULL);
+}
+
+DEFUN (ipv6_route_ifname_tag,
+ ipv6_route_ifname_tag_cmd,
+ "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>",
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], NULL, NULL);
+}
+
+DEFUN (ipv6_route_ifname_tag_vrf,
+ ipv6_route_ifname_tag_vrf_cmd,
+ "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], NULL, argv[4]);
}
DEFUN (ipv6_route_ifname_flags,
@@ -2631,7 +3534,40 @@ DEFUN (ipv6_route_ifname_flags,
"Silently discard pkts when matched\n")
{
return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL,
- NULL);
+ NULL, NULL);
+}
+
+DEFUN (ipv6_route_ifname_flags_tag,
+ ipv6_route_ifname_flags_tag_cmd,
+ "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>",
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], NULL, NULL);
+}
+
+DEFUN (ipv6_route_ifname_flags_tag_vrf,
+ ipv6_route_ifname_flags_tag_vrf_cmd,
+ "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], NULL, argv[5]);
}
DEFUN (ipv6_route_pref,
@@ -2644,10 +3580,41 @@ DEFUN (ipv6_route_pref,
"IPv6 gateway interface name\n"
"Distance value for this prefix\n")
{
- return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2],
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, argv[2],
NULL);
}
+DEFUN (ipv6_route_pref_tag,
+ ipv6_route_pref_tag_cmd,
+ "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n")
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], argv[3], NULL);
+}
+
+DEFUN (ipv6_route_pref_tag_vrf,
+ ipv6_route_pref_tag_vrf_cmd,
+ "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], argv[3], argv[4]);
+}
+
DEFUN (ipv6_route_flags_pref,
ipv6_route_flags_pref_cmd,
"ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255>",
@@ -2660,10 +3627,45 @@ DEFUN (ipv6_route_flags_pref,
"Silently discard pkts when matched\n"
"Distance value for this prefix\n")
{
- return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3],
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, argv[3],
NULL);
}
+DEFUN (ipv6_route_flags_pref_tag,
+ ipv6_route_flags_pref_tag_cmd,
+ "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n")
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], NULL);
+}
+
+DEFUN (ipv6_route_flags_pref_tag_vrf,
+ ipv6_route_flags_pref_tag_vrf_cmd,
+ "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], argv[5]);
+}
+
DEFUN (ipv6_route_ifname_pref,
ipv6_route_ifname_pref_cmd,
"ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>",
@@ -2674,10 +3676,41 @@ DEFUN (ipv6_route_ifname_pref,
"IPv6 gateway interface name\n"
"Distance value for this prefix\n")
{
- return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3],
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, argv[3],
NULL);
}
+DEFUN (ipv6_route_ifname_pref_tag,
+ ipv6_route_ifname_pref_tag_cmd,
+ "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n")
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], NULL);
+}
+
+DEFUN (ipv6_route_ifname_pref_tag_vrf,
+ ipv6_route_ifname_pref_tag_vrf_cmd,
+ "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], argv[5]);
+}
+
DEFUN (ipv6_route_ifname_flags_pref,
ipv6_route_ifname_flags_pref_cmd,
"ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255>",
@@ -2690,10 +3723,45 @@ DEFUN (ipv6_route_ifname_flags_pref,
"Silently discard pkts when matched\n"
"Distance value for this prefix\n")
{
- return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4],
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, argv[4],
NULL);
}
+DEFUN (ipv6_route_ifname_flags_pref_tag,
+ ipv6_route_ifname_flags_pref_tag_cmd,
+ "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n")
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], NULL);
+}
+
+DEFUN (ipv6_route_ifname_flags_pref_tag_vrf,
+ ipv6_route_ifname_flags_pref_tag_vrf_cmd,
+ "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR,
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
+}
+
DEFUN (no_ipv6_route,
no_ipv6_route_cmd,
"no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)",
@@ -2704,10 +3772,41 @@ DEFUN (no_ipv6_route,
"IPv6 gateway address\n"
"IPv6 gateway interface name\n")
{
- return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL,
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, NULL,
NULL);
}
+DEFUN (no_ipv6_route_tag,
+ no_ipv6_route_tag_cmd,
+ "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], NULL, NULL);
+}
+
+DEFUN (no_ipv6_route_tag_vrf,
+ no_ipv6_route_tag_vrf_cmd,
+ "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], NULL, argv[3]);
+}
+
ALIAS (no_ipv6_route,
no_ipv6_route_flags_cmd,
"no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole)",
@@ -2720,6 +3819,20 @@ ALIAS (no_ipv6_route,
"Emit an ICMP unreachable when matched\n"
"Silently discard pkts when matched\n")
+ALIAS (no_ipv6_route_tag,
+ no_ipv6_route_flags_tag_cmd,
+ "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+
DEFUN (no_ipv6_route_ifname,
no_ipv6_route_ifname_cmd,
"no ipv6 route X:X::X:X/M X:X::X:X INTERFACE",
@@ -2730,10 +3843,41 @@ DEFUN (no_ipv6_route_ifname,
"IPv6 gateway address\n"
"IPv6 gateway interface name\n")
{
- return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL,
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, NULL,
NULL);
}
+DEFUN (no_ipv6_route_ifname_tag,
+ no_ipv6_route_ifname_tag_cmd,
+ "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], NULL, NULL);
+}
+
+DEFUN (no_ipv6_route_ifname_tag_vrf,
+ no_ipv6_route_ifname_tag_vrf_cmd,
+ "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], NULL, argv[4]);
+}
+
ALIAS (no_ipv6_route_ifname,
no_ipv6_route_ifname_flags_cmd,
"no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole)",
@@ -2746,6 +3890,20 @@ ALIAS (no_ipv6_route_ifname,
"Emit an ICMP unreachable when matched\n"
"Silently discard pkts when matched\n")
+ALIAS (no_ipv6_route_ifname_tag,
+ no_ipv6_route_ifname_flags_tag_cmd,
+ "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n")
+
DEFUN (no_ipv6_route_pref,
no_ipv6_route_pref_cmd,
"no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>",
@@ -2757,10 +3915,43 @@ DEFUN (no_ipv6_route_pref,
"IPv6 gateway interface name\n"
"Distance value for this prefix\n")
{
- return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2],
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, argv[2],
NULL);
}
+DEFUN (no_ipv6_route_pref_tag,
+ no_ipv6_route_pref_tag_cmd,
+ "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n")
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], argv[3], NULL);
+}
+
+DEFUN (no_ipv6_route_pref_tag_vrf,
+ no_ipv6_route_pref_tag_vrf_cmd,
+ "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], argv[3], argv[4]);
+}
+
DEFUN (no_ipv6_route_flags_pref,
no_ipv6_route_flags_pref_cmd,
"no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255>",
@@ -2775,10 +3966,49 @@ DEFUN (no_ipv6_route_flags_pref,
"Distance value for this prefix\n")
{
/* We do not care about argv[2] */
- return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3],
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], NULL, argv[3],
NULL);
}
+DEFUN (no_ipv6_route_flags_pref_tag,
+ no_ipv6_route_flags_pref_tag_cmd,
+ "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n")
+{
+ /* We do not care about argv[2] */
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], NULL);
+}
+
+DEFUN (no_ipv6_route_flags_pref_tag_vrf,
+ no_ipv6_route_flags_pref_tag_vrf_cmd,
+ "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ VRF_CMD_HELP_STR)
+{
+ /* We do not care about argv[2] */
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], argv[5]);
+}
+
DEFUN (no_ipv6_route_ifname_pref,
no_ipv6_route_ifname_pref_cmd,
"no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>",
@@ -2790,10 +4020,43 @@ DEFUN (no_ipv6_route_ifname_pref,
"IPv6 gateway interface name\n"
"Distance value for this prefix\n")
{
- return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3],
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, argv[3],
NULL);
}
+DEFUN (no_ipv6_route_ifname_pref_tag,
+ no_ipv6_route_ifname_pref_tag_cmd,
+ "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n")
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], NULL);
+}
+
+DEFUN (no_ipv6_route_ifname_pref_tag_vrf,
+ no_ipv6_route_ifname_pref_tag_vrf_cmd,
+ "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], argv[5]);
+}
+
DEFUN (no_ipv6_route_ifname_flags_pref,
no_ipv6_route_ifname_flags_pref_cmd,
"no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255>",
@@ -2807,10 +4070,47 @@ DEFUN (no_ipv6_route_ifname_flags_pref,
"Silently discard pkts when matched\n"
"Distance value for this prefix\n")
{
- return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4],
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], NULL, argv[4],
NULL);
}
+DEFUN (no_ipv6_route_ifname_flags_pref_tag,
+ no_ipv6_route_ifname_flags_pref_tag_cmd,
+ "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n")
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], NULL);
+}
+
+DEFUN (no_ipv6_route_ifname_flags_pref_tag_vrf,
+ no_ipv6_route_ifname_flags_pref_tag_vrf_cmd,
+ "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>" VRF_CMD_STR,
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Emit an ICMP unreachable when matched\n"
+ "Silently discard pkts when matched\n"
+ "Set tag for this route\n"
+ "Tag value\n"
+ "Distance value for this prefix\n"
+ VRF_CMD_HELP_STR)
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
+}
+
DEFUN (ipv6_route_vrf,
ipv6_route_vrf_cmd,
"ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) " VRF_CMD_STR,
@@ -2821,7 +4121,7 @@ DEFUN (ipv6_route_vrf,
"IPv6 gateway interface name\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL,
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, NULL,
argv[2]);
}
@@ -2837,7 +4137,7 @@ DEFUN (ipv6_route_flags_vrf,
"Silently discard pkts when matched\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL,
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, NULL,
argv[3]);
}
@@ -2851,7 +4151,7 @@ DEFUN (ipv6_route_ifname_vrf,
"IPv6 gateway interface name\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL,
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, NULL,
argv[3]);
}
@@ -2867,7 +4167,7 @@ DEFUN (ipv6_route_ifname_flags_vrf,
"Silently discard pkts when matched\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL,
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, NULL,
argv[4]);
}
@@ -2882,7 +4182,7 @@ DEFUN (ipv6_route_pref_vrf,
"Distance value for this prefix\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2],
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, argv[2],
argv[3]);
}
@@ -2899,7 +4199,7 @@ DEFUN (ipv6_route_flags_pref_vrf,
"Distance value for this prefix\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3],
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, argv[3],
argv[4]);
}
@@ -2914,7 +4214,7 @@ DEFUN (ipv6_route_ifname_pref_vrf,
"Distance value for this prefix\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3],
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, argv[3],
argv[4]);
}
@@ -2931,7 +4231,7 @@ DEFUN (ipv6_route_ifname_flags_pref_vrf,
"Distance value for this prefix\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4],
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, argv[4],
argv[5]);
}
@@ -2946,7 +4246,7 @@ DEFUN (no_ipv6_route_vrf,
"IPv6 gateway interface name\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL,
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, NULL,
(argc > 3) ? argv[3] : argv[2]);
}
@@ -2974,7 +4274,7 @@ DEFUN (no_ipv6_route_ifname_vrf,
"IPv6 gateway interface name\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL,
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, NULL,
(argc > 4) ? argv[4] : argv[3]);
}
@@ -3003,7 +4303,7 @@ DEFUN (no_ipv6_route_pref_vrf,
"Distance value for this prefix\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2],
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, argv[2],
argv[3]);
}
@@ -3022,7 +4322,7 @@ DEFUN (no_ipv6_route_flags_pref_vrf,
VRF_CMD_HELP_STR)
{
/* We do not care about argv[2] */
- return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3],
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], NULL, argv[3],
argv[4]);
}
@@ -3038,7 +4338,7 @@ DEFUN (no_ipv6_route_ifname_pref_vrf,
"Distance value for this prefix\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3],
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, argv[3],
argv[4]);
}
@@ -3056,7 +4356,7 @@ DEFUN (no_ipv6_route_ifname_flags_pref_vrf,
"Distance value for this prefix\n"
VRF_CMD_HELP_STR)
{
- return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4],
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], NULL, argv[4],
argv[5]);
}
@@ -3102,6 +4402,59 @@ ALIAS (show_ipv6_route,
"IPv6 routing table\n"
VRF_CMD_HELP_STR)
+DEFUN (show_ipv6_route_tag,
+ show_ipv6_route_tag_cmd,
+ "show ipv6 route tag <1-65535>",
+ SHOW_STR
+ IP_STR
+ "IPv6 routing table\n"
+ "Show only routes with tag\n"
+ "Tag value\n")
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *rib;
+ int first = 1;
+ u_short tag = 0;
+ vrf_id_t vrf_id = VRF_DEFAULT;
+
+ if (argv[0])
+ tag = atoi(argv[0]);
+
+ if (argc == 2)
+ VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+
+ table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
+ if (! table)
+ return CMD_SUCCESS;
+
+ /* Show all IPv6 routes with matching tag value. */
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ RNODE_FOREACH_RIB (rn, rib)
+ {
+ if (rib->tag != tag)
+ continue;
+
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V6_HEADER);
+ first = 0;
+ }
+ vty_show_ip_route (vty, rn, rib);
+ }
+ return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_route_tag,
+ show_ipv6_route_tag_vrf_cmd,
+ "show ipv6 route tag <1-65535>" VRF_CMD_STR,
+ SHOW_STR
+ IP_STR
+ "IPv6 routing table\n"
+ "Show only routes with tag\n"
+ "Tag value\n"
+ VRF_CMD_HELP_STR)
+
DEFUN (show_ipv6_route_prefix_longer,
show_ipv6_route_prefix_longer_cmd,
"show ipv6 route X:X::X:X/M longer-prefixes",
@@ -3773,6 +5126,9 @@ static_config_ipv6 (struct vty *vty)
if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE))
vty_out (vty, " %s", "blackhole");
+ if (si->tag)
+ vty_out (vty, " tag %d", si->tag);
+
if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
vty_out (vty, " %d", si->distance);
@@ -3786,7 +5142,6 @@ static_config_ipv6 (struct vty *vty)
}
return write;
}
-#endif /* HAVE_IPV6 */
/* Static ip route configuration write function. */
static int
@@ -3828,7 +5183,7 @@ static int config_write_vty(struct vty *vty)
proto_rm[AFI_IP][ZEBRA_ROUTE_MAX], VTY_NEWLINE);
return 1;
-}
+}
/* table node for protocol filtering */
static struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 };
@@ -3850,35 +5205,82 @@ zebra_vty_init (void)
install_element (CONFIG_NODE, &ip_multicast_mode_cmd);
install_element (CONFIG_NODE, &no_ip_multicast_mode_cmd);
install_element (CONFIG_NODE, &no_ip_multicast_mode_noarg_cmd);
- install_element (CONFIG_NODE, &ip_protocol_cmd);
- install_element (CONFIG_NODE, &no_ip_protocol_cmd);
- install_element (VIEW_NODE, &show_ip_protocol_cmd);
- install_element (ENABLE_NODE, &show_ip_protocol_cmd);
+
install_element (CONFIG_NODE, &ip_route_cmd);
+ install_element (CONFIG_NODE, &ip_route_tag_cmd);
+ install_element (CONFIG_NODE, &ip_route_tag_vrf_cmd);
install_element (CONFIG_NODE, &ip_route_flags_cmd);
+ install_element (CONFIG_NODE, &ip_route_flags_tag_cmd);
+ install_element (CONFIG_NODE, &ip_route_flags_tag_vrf_cmd);
install_element (CONFIG_NODE, &ip_route_flags2_cmd);
+ install_element (CONFIG_NODE, &ip_route_flags2_tag_cmd);
+ install_element (CONFIG_NODE, &ip_route_flags2_tag_vrf_cmd);
install_element (CONFIG_NODE, &ip_route_mask_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_tag_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_tag_vrf_cmd);
install_element (CONFIG_NODE, &ip_route_mask_flags_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_flags_tag_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_flags_tag_vrf_cmd);
install_element (CONFIG_NODE, &ip_route_mask_flags2_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_flags2_tag_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_flags2_tag_vrf_cmd);
install_element (CONFIG_NODE, &no_ip_route_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_tag_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_tag_vrf_cmd);
install_element (CONFIG_NODE, &no_ip_route_flags_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_flags_tag_cmd);
install_element (CONFIG_NODE, &no_ip_route_flags2_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_flags2_tag_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_flags2_tag_vrf_cmd);
install_element (CONFIG_NODE, &no_ip_route_mask_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_tag_cmd);
install_element (CONFIG_NODE, &no_ip_route_mask_flags_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_cmd);
install_element (CONFIG_NODE, &no_ip_route_mask_flags2_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_flags2_tag_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_flags2_tag_vrf_cmd);
install_element (CONFIG_NODE, &ip_route_distance_cmd);
+ install_element (CONFIG_NODE, &ip_route_tag_distance_cmd);
+ install_element (CONFIG_NODE, &ip_route_tag_distance_vrf_cmd);
install_element (CONFIG_NODE, &ip_route_flags_distance_cmd);
+ install_element (CONFIG_NODE, &ip_route_flags_tag_distance_cmd);
+ install_element (CONFIG_NODE, &ip_route_flags_tag_distance_vrf_cmd);
install_element (CONFIG_NODE, &ip_route_flags_distance2_cmd);
+ install_element (CONFIG_NODE, &ip_route_flags_tag_distance2_cmd);
+ install_element (CONFIG_NODE, &ip_route_flags_tag_distance2_vrf_cmd);
install_element (CONFIG_NODE, &ip_route_mask_distance_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_tag_distance_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_tag_distance_vrf_cmd);
install_element (CONFIG_NODE, &ip_route_mask_flags_distance_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance_vrf_cmd);
install_element (CONFIG_NODE, &ip_route_mask_flags_distance2_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance2_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance2_vrf_cmd);
install_element (CONFIG_NODE, &no_ip_route_distance_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_tag_distance_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_tag_distance_vrf_cmd);
install_element (CONFIG_NODE, &no_ip_route_flags_distance_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance_vrf_cmd);
install_element (CONFIG_NODE, &no_ip_route_flags_distance2_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance2_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance2_vrf_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_distance_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_tag_distance_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_tag_distance_vrf_cmd);
install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance_vrf_cmd);
install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance2_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance2_vrf_cmd);
install_element (VIEW_NODE, &show_ip_route_cmd);
+ install_element (VIEW_NODE, &show_ip_route_tag_cmd);
+ install_element (VIEW_NODE, &show_ip_route_tag_vrf_cmd);
+ install_element (VIEW_NODE, &show_ip_nht_cmd);
+ install_element (VIEW_NODE, &show_ipv6_nht_cmd);
install_element (VIEW_NODE, &show_ip_route_addr_cmd);
install_element (VIEW_NODE, &show_ip_route_prefix_cmd);
install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd);
@@ -3887,6 +5289,10 @@ zebra_vty_init (void)
install_element (VIEW_NODE, &show_ip_route_summary_cmd);
install_element (VIEW_NODE, &show_ip_route_summary_prefix_cmd);
install_element (ENABLE_NODE, &show_ip_route_cmd);
+ install_element (ENABLE_NODE, &show_ip_route_tag_cmd);
+ install_element (ENABLE_NODE, &show_ip_route_tag_vrf_cmd);
+ install_element (ENABLE_NODE, &show_ip_nht_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_nht_cmd);
install_element (ENABLE_NODE, &show_ip_route_addr_cmd);
install_element (ENABLE_NODE, &show_ip_route_prefix_cmd);
install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd);
@@ -3991,7 +5397,39 @@ zebra_vty_init (void)
install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_cmd);
install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd);
install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_tag_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_flags_tag_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_flags_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_ifname_tag_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_ifname_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_ifname_flags_tag_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_ifname_flags_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_pref_tag_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_pref_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_flags_pref_tag_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_flags_pref_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_ifname_pref_tag_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_ifname_pref_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_tag_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_tag_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_flags_tag_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_ifname_tag_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_ifname_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_tag_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_pref_tag_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_pref_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_tag_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_tag_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_tag_vrf_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_tag_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_tag_vrf_cmd);
install_element (VIEW_NODE, &show_ipv6_route_cmd);
+ install_element (VIEW_NODE, &show_ipv6_route_tag_cmd);
+ install_element (VIEW_NODE, &show_ipv6_route_tag_vrf_cmd);
install_element (VIEW_NODE, &show_ipv6_route_summary_cmd);
install_element (VIEW_NODE, &show_ipv6_route_summary_prefix_cmd);
install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd);
@@ -3999,6 +5437,8 @@ zebra_vty_init (void)
install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd);
install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd);
install_element (ENABLE_NODE, &show_ipv6_route_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_route_tag_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_route_tag_vrf_cmd);
install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd);
install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd);
install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd);
diff --git a/zebra/zserv.c b/zebra/zserv.c
index e624ef2f..0f8562e2 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -37,12 +37,14 @@
#include "network.h"
#include "buffer.h"
#include "vrf.h"
+#include "nexthop.h"
#include "zebra/zserv.h"
#include "zebra/router-id.h"
#include "zebra/redistribute.h"
#include "zebra/debug.h"
#include "zebra/ipforward.h"
+#include "zebra/zebra_rnh.h"
/* Event list of zebra. */
enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
@@ -99,14 +101,19 @@ zserv_flush_data(struct thread *thread)
case BUFFER_EMPTY:
break;
}
+
+ client->last_write_time = quagga_time(NULL);
return 0;
}
-static int
+int
zebra_server_send_message(struct zserv *client)
{
if (client->t_suicide)
return -1;
+
+ stream_set_getp(client->obuf, 0);
+ client->last_write_cmd = stream_getw_from(client->obuf, 4);
switch (buffer_write(client->wb, client->sock, STREAM_DATA(client->obuf),
stream_get_endp(client->obuf)))
{
@@ -128,10 +135,12 @@ zebra_server_send_message(struct zserv *client)
zserv_flush_data, client, client->sock);
break;
}
+
+ client->last_write_time = quagga_time(NULL);
return 0;
}
-static void
+void
zserv_create_header (struct stream *s, uint16_t cmd, vrf_id_t vrf_id)
{
/* length placeholder, caller can update */
@@ -189,6 +198,7 @@ zsend_interface_add (struct zserv *client, struct interface *ifp)
zserv_create_header (s, ZEBRA_INTERFACE_ADD, ifp->vrf_id);
zserv_encode_interface (s, ifp);
+ client->ifadd_cnt++;
return zebra_server_send_message(client);
}
@@ -208,6 +218,7 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp)
zserv_create_header (s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id);
zserv_encode_interface (s, ifp);
+ client->ifdel_cnt++;
return zebra_server_send_message (client);
}
@@ -293,9 +304,147 @@ zsend_interface_address (int cmd, struct zserv *client,
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
+ client->connected_rt_add_cnt++;
+ return zebra_server_send_message(client);
+}
+
+static int
+zsend_interface_nbr_address (int cmd, struct zserv *client,
+ struct interface *ifp, struct nbr_connected *ifc)
+{
+ int blen;
+ struct stream *s;
+ struct prefix *p;
+
+ /* Check this client need interface information. */
+ if (! client->ifinfo)
+ return 0;
+
+ s = client->obuf;
+ stream_reset (s);
+
+ zserv_create_header (s, cmd, ifp->vrf_id);
+ stream_putl (s, ifp->ifindex);
+
+ /* Prefix information. */
+ p = ifc->address;
+ stream_putc (s, p->family);
+ blen = prefix_blen (p);
+ stream_put (s, &p->u.prefix, blen);
+
+ /*
+ * XXX gnu version does not send prefixlen for ZEBRA_INTERFACE_ADDRESS_DELETE
+ * but zebra_interface_address_delete_read() in the gnu version
+ * expects to find it
+ */
+ stream_putc (s, p->prefixlen);
+
+ /* Write packet size. */
+ stream_putw_at (s, 0, stream_get_endp (s));
+
return zebra_server_send_message(client);
}
+/* Interface address addition. */
+static void
+zebra_interface_nbr_address_add_update (struct interface *ifp,
+ struct nbr_connected *ifc)
+{
+ struct listnode *node, *nnode;
+ struct zserv *client;
+ struct prefix *p;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ {
+ char buf[INET6_ADDRSTRLEN];
+
+ p = ifc->address;
+ zlog_debug ("MESSAGE: ZEBRA_INTERFACE_NBR_ADDRESS_ADD %s/%d on %s",
+ inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN),
+ p->prefixlen, ifc->ifp->name);
+ }
+
+ for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+ if (client->ifinfo)
+ zsend_interface_nbr_address (ZEBRA_INTERFACE_NBR_ADDRESS_ADD, client, ifp, ifc);
+}
+
+/* Interface address deletion. */
+static void
+zebra_interface_nbr_address_delete_update (struct interface *ifp,
+ struct nbr_connected *ifc)
+{
+ struct listnode *node, *nnode;
+ struct zserv *client;
+ struct prefix *p;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ {
+ char buf[INET6_ADDRSTRLEN];
+
+ p = ifc->address;
+ zlog_debug ("MESSAGE: ZEBRA_INTERFACE_NBR_ADDRESS_DELETE %s/%d on %s",
+ inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN),
+ p->prefixlen, ifc->ifp->name);
+ }
+
+ for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+ if (client->ifinfo)
+ zsend_interface_nbr_address (ZEBRA_INTERFACE_NBR_ADDRESS_DELETE, client, ifp, ifc);
+}
+
+/* Add new nbr connected IPv6 address if none exists already, or replace the
+ existing one if an ifc entry is found on the interface. */
+void
+nbr_connected_replacement_add_ipv6 (struct interface *ifp, struct in6_addr *address,
+ u_char prefixlen)
+{
+ struct nbr_connected *ifc;
+ struct prefix p;
+
+ p.family = AF_INET6;
+ IPV6_ADDR_COPY (&p.u.prefix, address);
+ p.prefixlen = prefixlen;
+
+ if (nbr_connected_check(ifp, &p))
+ return;
+
+ if (!(ifc = listnode_head(ifp->nbr_connected)))
+ {
+ /* new addition */
+ ifc = nbr_connected_new ();
+ ifc->address = prefix_new();
+ ifc->ifp = ifp;
+ listnode_add (ifp->nbr_connected, ifc);
+ }
+
+ prefix_copy(ifc->address, &p);
+
+ zebra_interface_nbr_address_add_update (ifp, ifc);
+}
+
+void
+nbr_connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
+ u_char prefixlen)
+{
+ struct nbr_connected *ifc;
+ struct prefix p;
+
+ p.family = AF_INET6;
+ IPV6_ADDR_COPY (&p.u.prefix, address);
+ p.prefixlen = prefixlen;
+
+ ifc = nbr_connected_check(ifp, &p);
+ if (!ifc)
+ return;
+
+ listnode_delete (ifp->nbr_connected, ifc);
+
+ zebra_interface_nbr_address_delete_update (ifp, ifc);
+
+ nbr_connected_free (ifc);
+}
+
/*
* The cmd passed to zsend_interface_update may be ZEBRA_INTERFACE_UP or
* ZEBRA_INTERFACE_DOWN.
@@ -321,6 +470,11 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp)
zserv_create_header (s, cmd, ifp->vrf_id);
zserv_encode_interface (s, ifp);
+ if (cmd == ZEBRA_INTERFACE_UP)
+ client->ifup_cnt++;
+ else
+ client->ifdown_cnt++;
+
return zebra_server_send_message(client);
}
@@ -453,6 +607,12 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
stream_putl (s, rib->metric);
SET_FLAG (zapi_flags, ZAPI_MESSAGE_MTU);
stream_putl (s, rib->mtu);
+ /* tag */
+ if (rib->tag)
+ {
+ SET_FLAG(zapi_flags, ZAPI_MESSAGE_TAG);
+ stream_putw(s, rib->tag);
+ }
}
/* write real message flags value */
@@ -532,7 +692,7 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr,
}
stream_putw_at (s, 0, stream_get_endp (s));
-
+
return zebra_server_send_message(client);
}
#endif /* HAVE_IPV6 */
@@ -548,7 +708,7 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr,
struct nexthop *nexthop;
/* Lookup nexthop - eBGP excluded */
- rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL, vrf_id);
+ rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, NULL, vrf_id);
/* Get output stream. */
s = client->obuf;
@@ -677,6 +837,75 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr,
return zebra_server_send_message(client);
}
+/* Nexthop register */
+static int
+zserv_nexthop_register (struct zserv *client, int sock, u_short length, vrf_id_t vrf_id)
+{
+ struct rnh *rnh;
+ struct stream *s;
+ struct prefix p;
+ u_short l = 0;
+ u_char connected;
+
+ if (IS_ZEBRA_DEBUG_NHT)
+ zlog_debug("nexthop_register msg from client %s: length=%d\n",
+ zebra_route_string(client->proto), length);
+
+ s = client->ibuf;
+
+ while (l < length)
+ {
+ connected = stream_getc(s);
+ p.family = stream_getw(s);
+ p.prefixlen = stream_getc(s);
+ l += 4;
+ stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+ l += PSIZE(p.prefixlen);
+ rnh = zebra_add_rnh(&p, 0);
+ if (connected)
+ SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED);
+
+ client->nh_reg_time = quagga_time(NULL);
+ zebra_add_rnh_client(rnh, client, vrf_id);
+ }
+ zebra_evaluate_rnh_table(0, AF_INET, 0);
+ zebra_evaluate_rnh_table(0, AF_INET6, 0);
+ return 0;
+}
+
+/* Nexthop register */
+static int
+zserv_nexthop_unregister (struct zserv *client, int sock, u_short length)
+{
+ struct rnh *rnh;
+ struct stream *s;
+ struct prefix p;
+ u_short l = 0;
+
+ if (IS_ZEBRA_DEBUG_NHT)
+ zlog_debug("nexthop_unregister msg from client %s: length=%d\n",
+ zebra_route_string(client->proto), length);
+
+ s = client->ibuf;
+
+ while (l < length)
+ {
+ (void)stream_getc(s);
+ p.family = stream_getw(s);
+ p.prefixlen = stream_getc(s);
+ l += 4;
+ stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
+ l += PSIZE(p.prefixlen);
+ rnh = zebra_lookup_rnh(&p, 0);
+ if (rnh)
+ {
+ client->nh_dereg_time = quagga_time(NULL);
+ zebra_remove_rnh_client(rnh, client);
+ }
+ }
+ return 0;
+}
+
static int
zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p,
vrf_id_t vrf_id)
@@ -736,7 +965,7 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p,
}
stream_putw_at (s, 0, stream_get_endp (s));
-
+
return zebra_server_send_message(client);
}
@@ -779,6 +1008,7 @@ zread_interface_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
struct listnode *cnode, *cnnode;
struct interface *ifp;
struct connected *c;
+ struct nbr_connected *nc;
/* Interface information is needed. */
vrf_bitmap_set (client->ifinfo, vrf_id);
@@ -799,6 +1029,13 @@ zread_interface_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
ifp, c) < 0))
return -1;
}
+ for (ALL_LIST_ELEMENTS (ifp->nbr_connected, cnode, cnnode, nc))
+ {
+ if (zsend_interface_nbr_address (ZEBRA_INTERFACE_NBR_ADDRESS_ADD, client,
+ ifp, nc) < 0)
+ return -1;
+ }
+
}
return 0;
}
@@ -830,7 +1067,7 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
ifindex_t ifindex;
u_char ifname_len;
safi_t safi;
-
+ int ret;
/* Get input stream. */
s = client->ibuf;
@@ -867,7 +1104,7 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
{
case ZEBRA_NEXTHOP_IFINDEX:
ifindex = stream_getl (s);
- nexthop_ifindex_add (rib, ifindex);
+ rib_nexthop_ifindex_add (rib, ifindex);
break;
case ZEBRA_NEXTHOP_IFNAME:
ifname_len = stream_getc (s);
@@ -875,18 +1112,18 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
break;
case ZEBRA_NEXTHOP_IPV4:
nexthop.s_addr = stream_get_ipv4 (s);
- nexthop_ipv4_add (rib, &nexthop, NULL);
+ rib_nexthop_ipv4_add (rib, &nexthop, NULL);
break;
case ZEBRA_NEXTHOP_IPV4_IFINDEX:
nexthop.s_addr = stream_get_ipv4 (s);
ifindex = stream_getl (s);
- nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex);
+ rib_nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex);
break;
case ZEBRA_NEXTHOP_IPV6:
stream_forward_getp (s, IPV6_MAX_BYTELEN);
break;
case ZEBRA_NEXTHOP_BLACKHOLE:
- nexthop_blackhole_add (rib);
+ rib_nexthop_blackhole_add (rib);
break;
}
}
@@ -902,10 +1139,19 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU))
rib->mtu = stream_getl (s);
+ /* Tag */
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG))
+ rib->tag = stream_getw (s);
/* Table */
rib->table=zebrad.rtm_table_default;
- rib_add_ipv4_multipath (&p, rib, safi);
+ ret = rib_add_ipv4_multipath (&p, rib, safi);
+
+ /* Stats */
+ if (ret > 0)
+ client->v4_route_add_cnt++;
+ else if (ret < 0)
+ client->v4_route_upd8_cnt++;
return 0;
}
@@ -986,8 +1232,15 @@ zread_ipv4_delete (struct zserv *client, u_short length, vrf_id_t vrf_id)
else
api.metric = 0;
+ /* tag */
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+ api.tag = stream_getw (s);
+ else
+ api.tag = 0;
+
rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex,
vrf_id, api.safi);
+ client->v4_route_del_cnt++;
return 0;
}
@@ -1040,34 +1293,51 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
{
int i;
struct stream *s;
- struct zapi_ipv6 api;
struct in6_addr nexthop;
- unsigned long ifindex;
+ struct rib *rib;
+ u_char message;
+ u_char gateway_num;
+ u_char nexthop_type;
struct prefix_ipv6 p;
-
+ safi_t safi;
+ static struct in6_addr nexthops[MULTIPATH_NUM];
+ static unsigned int ifindices[MULTIPATH_NUM];
+ int ret;
+
+ /* Get input stream. */
s = client->ibuf;
- ifindex = 0;
+
memset (&nexthop, 0, sizeof (struct in6_addr));
+ /* Allocate new rib. */
+ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+
/* Type, flags, message. */
- api.type = stream_getc (s);
- api.flags = stream_getc (s);
- api.message = stream_getc (s);
- api.safi = stream_getw (s);
+ rib->type = stream_getc (s);
+ rib->flags = stream_getc (s);
+ message = stream_getc (s);
+ safi = stream_getw (s);
+ rib->uptime = time (NULL);
- /* IPv4 prefix. */
+ /* IPv6 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));
p.family = AF_INET6;
p.prefixlen = stream_getc (s);
stream_get (&p.prefix, s, PSIZE (p.prefixlen));
- /* Nexthop, ifindex, distance, metric. */
- if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+ /* We need to give nh-addr, nh-ifindex with the same next-hop object
+ * to the rib to ensure that IPv6 multipathing works; need to coalesce
+ * these. Clients should send the same number of paired set of
+ * next-hop-addr/next-hop-ifindices. */
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP))
{
- u_char nexthop_type;
+ int nh_count = 0;
+ int if_count = 0;
+ int max_nh_if = 0;
+ unsigned int ifindex;
- api.nexthop_num = stream_getc (s);
- for (i = 0; i < api.nexthop_num; i++)
+ gateway_num = stream_getc (s);
+ for (i = 0; i < gateway_num; i++)
{
nexthop_type = stream_getc (s);
@@ -1075,37 +1345,64 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
{
case ZEBRA_NEXTHOP_IPV6:
stream_get (&nexthop, s, 16);
+ if (nh_count < MULTIPATH_NUM) {
+ nexthops[nh_count++] = nexthop;
+ }
break;
case ZEBRA_NEXTHOP_IFINDEX:
ifindex = stream_getl (s);
+ if (if_count < MULTIPATH_NUM) {
+ ifindices[if_count++] = ifindex;
+ }
break;
+ case ZEBRA_NEXTHOP_BLACKHOLE:
+ rib_nexthop_blackhole_add (rib);
+ break;
+ }
+ }
+
+ max_nh_if = (nh_count > if_count) ? nh_count : if_count;
+ for (i = 0; i < max_nh_if; i++)
+ {
+ 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]);
+ else
+ rib_nexthop_ipv6_add (rib, &nexthops[i]);
+ }
+ else
+ {
+ if ((i < if_count) && ifindices[i])
+ rib_nexthop_ifindex_add (rib, ifindices[i]);
}
}
}
- if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
- api.distance = stream_getc (s);
- else
- api.distance = 0;
+ /* Distance. */
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
+ rib->distance = stream_getc (s);
- if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
- api.metric = stream_getl (s);
- else
- api.metric = 0;
+ /* Metric. */
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
+ rib->metric = stream_getl (s);
+
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU))
+ rib->mtu = stream_getl (s);
+
+ /* Tag */
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG))
+ rib->tag = stream_getw (s);
+
+ /* Table */
+ rib->table=zebrad.rtm_table_default;
+ ret = rib_add_ipv6_multipath (&p, rib, safi);
+ /* Stats */
+ if (ret > 0)
+ client->v6_route_add_cnt++;
+ else if (ret < 0)
+ client->v6_route_upd8_cnt++;
- if (CHECK_FLAG (api.message, ZAPI_MESSAGE_MTU))
- api.mtu = stream_getl (s);
- else
- api.mtu = 0;
-
- if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
- rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex,
- vrf_id, zebrad.rtm_table_default, api.metric,
- api.mtu, api.distance, api.safi);
- else
- rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex,
- vrf_id, zebrad.rtm_table_default, api.metric,
- api.mtu, api.distance, api.safi);
return 0;
}
@@ -1158,21 +1455,32 @@ zread_ipv6_delete (struct zserv *client, u_short length, vrf_id_t vrf_id)
}
}
+ /* Distance. */
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
else
api.distance = 0;
+
+ /* Metric. */
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl (s);
else
api.metric = 0;
+ /* tag */
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+ api.tag = stream_getw (s);
+ else
+ api.tag = 0;
+
if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, vrf_id,
api.safi);
else
rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, vrf_id,
api.safi);
+
+ client->v6_route_del_cnt++;
return 0;
}
@@ -1236,6 +1544,7 @@ zread_hello (struct zserv *client)
client->sock);
route_type_oaths[proto] = client->sock;
+ client->proto = proto;
}
}
@@ -1276,6 +1585,9 @@ zebra_score_rib (int client_sock)
static void
zebra_client_close (struct zserv *client)
{
+ zebra_cleanup_rnh_client(0, AF_INET, client);
+ zebra_cleanup_rnh_client(0, AF_INET6, client);
+
/* Close file descriptor. */
if (client->sock)
{
@@ -1329,6 +1641,7 @@ zebra_client_create (int sock)
client->redist_default = vrf_bitmap_init ();
client->ifinfo = vrf_bitmap_init ();
client->ridinfo = vrf_bitmap_init ();
+ client->connect_time = quagga_time(NULL);
/* Add this client to linked list. */
listnode_add (zebrad.client_list, client);
@@ -1444,6 +1757,9 @@ zebra_client_read (struct thread *thread)
zlog_debug ("zebra message received [%s] %d in VRF %u",
zserv_command_string (command), length, vrf_id);
+ client->last_read_time = quagga_time(NULL);
+ client->last_read_cmd = command;
+
switch (command)
{
case ZEBRA_ROUTER_ID_ADD:
@@ -1503,6 +1819,11 @@ zebra_client_read (struct thread *thread)
break;
case ZEBRA_VRF_UNREGISTER:
zread_vrf_unregister (client, length, vrf_id);
+ case ZEBRA_NEXTHOP_REGISTER:
+ zserv_nexthop_register(client, sock, length, vrf_id);
+ break;
+ case ZEBRA_NEXTHOP_UNREGISTER:
+ zserv_nexthop_unregister(client, sock, length);
break;
default:
zlog_info ("Zebra received unknown command %d", command);
@@ -1701,6 +2022,127 @@ zebra_event (enum event event, int sock, struct zserv *client)
}
}
+#define ZEBRA_TIME_BUF 32
+static char *
+zserv_time_buf(time_t *time1, char *buf, int buflen)
+{
+ struct tm *tm;
+ time_t now;
+
+ assert (buf != NULL);
+ assert (buflen >= ZEBRA_TIME_BUF);
+ assert (time1 != NULL);
+
+ if (!*time1)
+ {
+ snprintf(buf, buflen, "never ");
+ return (buf);
+ }
+
+ now = quagga_time(NULL);
+ now -= *time1;
+ tm = gmtime(&now);
+
+ /* Making formatted timer strings. */
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+ if (now < ONE_DAY_SECOND)
+ snprintf (buf, buflen, "%02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ else if (now < ONE_WEEK_SECOND)
+ snprintf (buf, buflen, "%dd%02dh%02dm",
+ tm->tm_yday, tm->tm_hour, tm->tm_min);
+ else
+ snprintf (buf, buflen, "%02dw%dd%02dh",
+ tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+ return buf;
+}
+
+static void
+zebra_show_client_detail (struct vty *vty, struct zserv *client)
+{
+ char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
+ char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF];
+
+ vty_out (vty, "Client: %s %s",
+ zebra_route_string(client->proto), VTY_NEWLINE);
+ vty_out (vty, "------------------------ %s", VTY_NEWLINE);
+ vty_out (vty, "FD: %d %s", client->sock, VTY_NEWLINE);
+ vty_out (vty, "Route Table ID: %d %s", client->rtm_table, VTY_NEWLINE);
+
+ vty_out (vty, "Connect Time: %s %s",
+ zserv_time_buf(&client->connect_time, cbuf, ZEBRA_TIME_BUF),
+ VTY_NEWLINE);
+ if (client->nh_reg_time)
+ {
+ vty_out (vty, "Nexthop Registry Time: %s %s",
+ zserv_time_buf(&client->nh_reg_time, nhbuf, ZEBRA_TIME_BUF),
+ VTY_NEWLINE);
+ if (client->nh_last_upd_time)
+ vty_out (vty, "Nexthop Last Update Time: %s %s",
+ zserv_time_buf(&client->nh_last_upd_time, mbuf, ZEBRA_TIME_BUF),
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "No Nexthop Update sent%s", VTY_NEWLINE);
+ }
+ else
+ vty_out (vty, "Not registered for Nexthop Updates%s", VTY_NEWLINE);
+
+ vty_out (vty, "Last Msg Rx Time: %s %s",
+ zserv_time_buf(&client->last_read_time, rbuf, ZEBRA_TIME_BUF),
+ VTY_NEWLINE);
+ vty_out (vty, "Last Msg Tx Time: %s %s",
+ zserv_time_buf(&client->last_write_time, wbuf, ZEBRA_TIME_BUF),
+ VTY_NEWLINE);
+ if (client->last_read_time)
+ vty_out (vty, "Last Rcvd Cmd: %s %s",
+ zserv_command_string(client->last_read_cmd), VTY_NEWLINE);
+ if (client->last_write_time)
+ vty_out (vty, "Last Sent Cmd: %s %s",
+ zserv_command_string(client->last_write_cmd), VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_out (vty, "Type Add Update Del %s", VTY_NEWLINE);
+ vty_out (vty, "================================================== %s", VTY_NEWLINE);
+ vty_out (vty, "IPv4 %-12d%-12d%-12d%s", client->v4_route_add_cnt,
+ client->v4_route_upd8_cnt, client->v4_route_del_cnt, VTY_NEWLINE);
+ vty_out (vty, "IPv6 %-12d%-12d%-12d%s", client->v6_route_add_cnt,
+ client->v6_route_upd8_cnt, client->v6_route_del_cnt, VTY_NEWLINE);
+ vty_out (vty, "Redist:v4 %-12d%-12d%-12d%s", client->redist_v4_add_cnt, 0,
+ client->redist_v4_del_cnt, VTY_NEWLINE);
+ vty_out (vty, "Redist:v6 %-12d%-12d%-12d%s", client->redist_v6_add_cnt, 0,
+ client->redist_v6_del_cnt, VTY_NEWLINE);
+ vty_out (vty, "Connected %-12d%-12d%-12d%s", client->ifadd_cnt, 0,
+ client->ifdel_cnt, VTY_NEWLINE);
+ vty_out (vty, "Interface Up Notifications: %d%s", client->ifup_cnt,
+ VTY_NEWLINE);
+ vty_out (vty, "Interface Down Notifications: %d%s", client->ifdown_cnt,
+ VTY_NEWLINE);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ return;
+}
+
+static void
+zebra_show_client_brief (struct vty *vty, struct zserv *client)
+{
+ char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
+ char wbuf[ZEBRA_TIME_BUF];
+
+ vty_out (vty, "%-8s%12s %12s%12s%8d/%-8d%8d/%-8d%s",
+ zebra_route_string(client->proto),
+ zserv_time_buf(&client->connect_time, cbuf, ZEBRA_TIME_BUF),
+ zserv_time_buf(&client->last_read_time, rbuf, ZEBRA_TIME_BUF),
+ zserv_time_buf(&client->last_write_time, wbuf, ZEBRA_TIME_BUF),
+ client->v4_route_add_cnt+client->v4_route_upd8_cnt,
+ client->v4_route_del_cnt,
+ client->v6_route_add_cnt+client->v6_route_upd8_cnt,
+ client->v6_route_del_cnt, VTY_NEWLINE);
+
+}
+
+
/* Display default rtm_table for all clients. */
DEFUN (show_table,
show_table_cmd,
@@ -1778,8 +2220,31 @@ DEFUN (show_zebra_client,
struct zserv *client;
for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
- vty_out (vty, "Client fd %d%s", client->sock, VTY_NEWLINE);
-
+ zebra_show_client_detail(vty, client);
+
+ return CMD_SUCCESS;
+}
+
+/* This command is for debugging purpose. */
+DEFUN (show_zebra_client_summary,
+ show_zebra_client_summary_cmd,
+ "show zebra client summary",
+ SHOW_STR
+ "Zebra information brief"
+ "Client information brief")
+{
+ struct listnode *node;
+ struct zserv *client;
+
+ vty_out (vty, "Name Connect Time Last Read Last Write IPv4 Routes IPv6 Routes %s",
+ VTY_NEWLINE);
+ vty_out (vty,"--------------------------------------------------------------------------------%s",
+ VTY_NEWLINE);
+
+ for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
+ zebra_show_client_brief(vty, client);
+
+ vty_out (vty, "Routes column shows (added+updated)/deleted%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -1938,6 +2403,7 @@ zebra_init (void)
install_element (CONFIG_NODE, &ip_forwarding_cmd);
install_element (CONFIG_NODE, &no_ip_forwarding_cmd);
install_element (ENABLE_NODE, &show_zebra_client_cmd);
+ install_element (ENABLE_NODE, &show_zebra_client_summary_cmd);
#ifdef HAVE_NETLINK
install_element (VIEW_NODE, &show_table_cmd);
diff --git a/zebra/zserv.h b/zebra/zserv.h
index fc01f961..3f8af08e 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -26,6 +26,7 @@
#include "if.h"
#include "workqueue.h"
#include "vrf.h"
+#include "routemap.h"
/* Default port information. */
#define ZEBRA_VTY_PORT 2601
@@ -33,6 +34,8 @@
/* Default configuration filename. */
#define DEFAULT_CONFIG_FILE "zebra.conf"
+#define ZEBRA_RMAP_DEFAULT_UPDATE_TIMER 5 /* disabled by default */
+
/* Client structure. */
struct zserv
{
@@ -67,6 +70,37 @@ struct zserv
/* Router-id information. */
vrf_bitmap_t ridinfo;
+
+ /* client's protocol */
+ u_char proto;
+
+ /* Statistics */
+ u_int32_t redist_v4_add_cnt;
+ u_int32_t redist_v4_del_cnt;
+ u_int32_t redist_v6_add_cnt;
+ u_int32_t redist_v6_del_cnt;
+ u_int32_t v4_route_add_cnt;
+ u_int32_t v4_route_upd8_cnt;
+ u_int32_t v4_route_del_cnt;
+ u_int32_t v6_route_add_cnt;
+ u_int32_t v6_route_del_cnt;
+ u_int32_t v6_route_upd8_cnt;
+ u_int32_t connected_rt_add_cnt;
+ u_int32_t connected_rt_del_cnt;
+ u_int32_t ifup_cnt;
+ u_int32_t ifdown_cnt;
+ u_int32_t ifadd_cnt;
+ u_int32_t ifdel_cnt;
+
+ time_t connect_time;
+ time_t last_read_time;
+ time_t last_write_time;
+ time_t nh_reg_time;
+ time_t nh_dereg_time;
+ time_t nh_last_upd_time;
+
+ int last_read_cmd;
+ int last_write_cmd;
};
/* Zebra instance */
@@ -105,6 +139,9 @@ extern int zsend_interface_add (struct zserv *, struct interface *);
extern int zsend_interface_delete (struct zserv *, struct interface *);
extern int zsend_interface_address (int, struct zserv *, struct interface *,
struct connected *);
+extern void nbr_connected_replacement_add_ipv6 (struct interface *,
+ struct in6_addr *, u_char);
+extern void nbr_connected_delete_ipv6 (struct interface *, struct in6_addr *, u_char);
extern int zsend_interface_update (int, struct zserv *, struct interface *);
extern int zsend_route_multipath (int, struct zserv *, struct prefix *,
struct rib *);
@@ -113,4 +150,18 @@ extern int zsend_router_id_update (struct zserv *, struct prefix *,
extern pid_t pid;
+extern void zserv_create_header(struct stream *s, uint16_t cmd, vrf_id_t);
+extern int zebra_server_send_message(struct zserv *client);
+
+extern void zebra_route_map_write_delay_timer(struct vty *);
+extern route_map_result_t zebra_route_map_check (int family, int rib_type,
+ struct prefix *p,
+ struct nexthop *nexthop,
+ vrf_id_t vrf_id);
+extern route_map_result_t zebra_nht_route_map_check (int family,
+ int client_proto,
+ struct prefix *p,
+ struct rib *,
+ struct nexthop *nexthop);
+
#endif /* _ZEBRA_ZEBRA_H */