summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_route.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_route.c')
-rw-r--r--bgpd/bgp_route.c348
1 files changed, 217 insertions, 131 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 820c3cfd9..6c7a24239 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1226,6 +1226,15 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
bgp = SUBGRP_INST(subgrp);
riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr;
+ /* With addpath we may be asked to TX all kinds of paths so make sure
+ * ri is valid */
+ if (!CHECK_FLAG (ri->flags, BGP_INFO_VALID) ||
+ CHECK_FLAG (ri->flags, BGP_INFO_HISTORY) ||
+ CHECK_FLAG (ri->flags, BGP_INFO_REMOVED))
+ {
+ return 0;
+ }
+
/* Aggregate-address suppress check. */
if (ri->extra && ri->extra->suppress)
if (! UNSUPPRESS_MAP_NAME (filter))
@@ -1917,7 +1926,8 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
int
subgroup_process_announce_selected (struct update_subgroup *subgrp,
struct bgp_info *selected,
- struct bgp_node *rn)
+ struct bgp_node *rn,
+ u_int32_t addpath_tx_id)
{
struct prefix *p;
struct peer *onlypeer;
@@ -1945,20 +1955,37 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp,
case BGP_TABLE_MAIN:
/* Announcement to the subgroup. If the route is filtered,
withdraw it. */
- if (selected && subgroup_announce_check(selected, subgrp, p, &attr))
- bgp_adj_out_set_subgroup(rn, subgrp, &attr, selected);
- else
- bgp_adj_out_unset_subgroup(rn, subgrp, 1);
+ if (selected)
+ {
+ if (subgroup_announce_check(selected, subgrp, p, &attr))
+ bgp_adj_out_set_subgroup(rn, subgrp, &attr, selected);
+ else
+ bgp_adj_out_unset_subgroup(rn, subgrp, 1, selected->addpath_tx_id);
+ }
+ /* If selected is NULL we must withdraw the path using addpath_tx_id */
+ else
+ {
+ bgp_adj_out_unset_subgroup(rn, subgrp, 1, addpath_tx_id);
+ }
break;
+
case BGP_TABLE_RSCLIENT:
/* Announcement to peer->conf. If the route is filtered,
withdraw it. */
- if (selected &&
- subgroup_announce_check_rsclient (selected, subgrp, p, &attr))
- bgp_adj_out_set_subgroup (rn, subgrp, &attr, selected);
+ if (selected)
+ {
+ if (subgroup_announce_check_rsclient(selected, subgrp, p, &attr))
+ bgp_adj_out_set_subgroup(rn, subgrp, &attr, selected);
+ else
+ bgp_adj_out_unset_subgroup(rn, subgrp, 1, selected->addpath_tx_id);
+ }
+
+ /* If selected is NULL we must withdraw the path using addpath_tx_id */
else
- bgp_adj_out_unset_subgroup(rn, subgrp, 1);
+ {
+ bgp_adj_out_unset_subgroup(rn, subgrp, 1, addpath_tx_id);
+ }
break;
}
@@ -2033,7 +2060,7 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
subgrp = PAF_SUBGRP(paf);
if (!subgrp) /* not an established session */
continue;
- subgroup_process_announce_selected (subgrp, new_select, rn);
+ subgroup_process_announce_selected (subgrp, new_select, rn, new_select->addpath_tx_id);
}
}
else
@@ -2048,7 +2075,7 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
}
paf = peer_af_find(rsclient, afi, safi);
if (paf && (subgrp = PAF_SUBGRP(paf))) /* if an established session */
- subgroup_process_announce_selected (subgrp, new_select, rn);
+ subgroup_process_announce_selected (subgrp, new_select, rn, new_select->addpath_tx_id);
}
if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
@@ -2095,18 +2122,18 @@ bgp_process_main (struct work_queue *wq, void *data)
new_select = old_and_new.new;
/* Nothing to do. */
- 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, afi, safi);
+ if (old_select && old_select == new_select &&
+ !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR) &&
+ !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) &&
+ !bgp->addpath_tx_used[afi][safi])
+ {
+ 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, afi, safi);
- UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
- UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
- return WQ_SUCCESS;
- }
+ UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
+ UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
+ return WQ_SUCCESS;
}
/* If the user did "clear ip bgp prefix x.x.x.x" this flag will be set */
@@ -2157,7 +2184,7 @@ bgp_process_main (struct work_queue *wq, void *data)
}
}
- /* Reap old select bgp_info, it it has been removed */
+ /* Reap old select bgp_info, if it has been removed */
if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
bgp_info_reap (rn, old_select);
@@ -2433,6 +2460,7 @@ info_make (int type, int sub_type, u_short instance, struct peer *peer, struct a
new->attr = attr;
new->uptime = bgp_clock ();
new->net = rn;
+ new->addpath_tx_id = ++peer->bgp->addpath_tx_id;
return new;
}
@@ -3032,7 +3060,6 @@ bgp_update_main (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
/* Addpath ID */
new->addpath_rx_id = addpath_id;
- new->addpath_tx_id = 0;
/* Increment prefix */
bgp_aggregate_increment (bgp, p, new, afi, safi);
@@ -3527,17 +3554,6 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi,
ain = ain_next;
}
- /*
- * Can't do this anymore. adj-outs are not maintained per peer.
- *
- for (aout = rn->adj_out; aout; aout = aout->next)
- if (aout->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT)
- {
- bgp_adj_out_remove (rn, aout, peer, afi, safi);
- bgp_unlock_node (rn);
- break;
- }
- */
for (ri = rn->info; ri; ri = ri->next)
if (ri->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT)
{
@@ -3728,6 +3744,13 @@ bgp_reset (void)
prefix_list_reset ();
}
+static int
+bgp_addpath_encode_rx (struct peer *peer, afi_t afi, safi_t safi)
+{
+ return (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) &&
+ CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV));
+}
+
/* Parse NLRI stream. Withdraw NLRI is recognized by NULL attr
value. */
int
@@ -3740,7 +3763,7 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
int ret;
afi_t afi;
safi_t safi;
- u_char addpath_encoded;
+ int addpath_encoded;
u_int32_t addpath_id;
/* Check peer status. */
@@ -3752,9 +3775,7 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
afi = packet->afi;
safi = packet->safi;
addpath_id = 0;
-
- addpath_encoded = (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) &&
- CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV));
+ addpath_encoded = bgp_addpath_encode_rx (peer, afi, safi);
for (; pnt < lim; pnt += psize)
{
@@ -3856,13 +3877,11 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, safi_t safi, u_char *pnt,
u_char *end;
u_char prefixlen;
int psize;
- u_char addpath_encoded;
+ int addpath_encoded;
*numpfx = 0;
end = pnt + length;
-
- addpath_encoded = (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) &&
- CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV));
+ addpath_encoded = bgp_addpath_encode_rx (peer, afi, safi);
/* RFC1771 6.3 The NLRI field in the UPDATE message is checked for
syntactic validity. If the field is syntactically incorrect,
@@ -7213,6 +7232,57 @@ flap_route_vty_out (struct vty *vty, struct prefix *p, struct bgp_info *binfo,
}
static void
+route_vty_out_advertised_to (struct vty *vty, struct peer *peer, int *first,
+ const char *header, json_object *json_adv_to)
+{
+ char buf1[INET6_ADDRSTRLEN];
+ json_object *json_peer = NULL;
+
+ if (json_adv_to)
+ {
+ /* 'advertised-to' is a dictionary of peers we have advertised this
+ * prefix too. The key is the peer's IP or swpX, the value is the
+ * hostname if we know it and "" if not.
+ */
+ json_peer = json_object_new_object();
+
+ if (peer->hostname)
+ json_object_string_add(json_peer, "hostname", peer->hostname);
+
+ if (peer->conf_if)
+ json_object_object_add(json_adv_to, peer->conf_if, json_peer);
+ else
+ json_object_object_add(json_adv_to,
+ sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN),
+ json_peer);
+ }
+ else
+ {
+ if (*first)
+ {
+ vty_out (vty, "%s", header);
+ *first = 0;
+ }
+
+ if (peer->hostname && bgp_flag_check(peer->bgp, BGP_FLAG_SHOW_HOSTNAME))
+ {
+ if (peer->conf_if)
+ vty_out (vty, " %s(%s)", peer->hostname, peer->conf_if);
+ else
+ vty_out (vty, " %s(%s)", peer->hostname,
+ sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN));
+ }
+ else
+ {
+ if (peer->conf_if)
+ vty_out (vty, " %s", peer->conf_if);
+ else
+ vty_out (vty, " %s", sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN));
+ }
+ }
+}
+
+static void
route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
struct bgp_info *binfo, afi_t afi, safi_t safi,
json_object *json_paths)
@@ -7235,6 +7305,12 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
json_object *json_path = NULL;
json_object *json_peer = NULL;
json_object *json_string = NULL;
+ json_object *json_adv_to = NULL;
+ int first = 0;
+ struct listnode *node, *nnode;
+ struct peer *peer;
+ int addpath_capable;
+ int has_adj;
if (json_paths)
{
@@ -7775,6 +7851,45 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
}
}
+ /* If we used addpath to TX a non-bestpath we need to display
+ * "Advertised to" on a path-by-path basis */
+ if (bgp->addpath_tx_used[afi][safi])
+ {
+ first = 1;
+
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+ addpath_capable = bgp_addpath_encode_tx (peer, afi, safi);
+ has_adj = bgp_adj_out_lookup (peer, binfo->net, binfo->addpath_tx_id);
+
+ if ((addpath_capable && has_adj) ||
+ (!addpath_capable && has_adj && CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)))
+ {
+ if (json_path && !json_adv_to)
+ json_adv_to = json_object_new_object();
+
+ route_vty_out_advertised_to(vty, peer, &first,
+ " Advertised to:",
+ json_adv_to);
+ }
+ }
+
+ if (json_path)
+ {
+ if (json_adv_to)
+ {
+ json_object_object_add(json_path, "advertisedTo", json_adv_to);
+ }
+ }
+ else
+ {
+ if (!first)
+ {
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ }
+ }
+
/* Line 8 display Uptime */
#ifdef HAVE_CLOCK_MONOTONIC
tbuf = time(NULL) - (bgp_clock() - binfo->uptime);
@@ -8161,9 +8276,8 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
int no_export = 0;
int no_advertise = 0;
int local_as = 0;
- int first = 0;
+ int first = 1;
json_object *json_adv_to = NULL;
- json_object *json_peer = NULL;
p = &rn->p;
@@ -8226,70 +8340,38 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
vty_out (vty, ")%s", VTY_NEWLINE);
}
- /* advertised peer */
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ /* If we are not using addpath then we can display Advertised to and that will
+ * show what peers we advertised the bestpath to. If we are using addpath
+ * though then we must display Advertised to on a path-by-path basis. */
+ if (!bgp->addpath_tx_used[afi][safi])
{
- if (bgp_adj_out_lookup (peer, p, afi, safi, rn))
- {
- if (json)
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+ if (bgp_adj_out_lookup (peer, rn, 0))
{
- /* 'advertised-to' is a dictionary of peers we have advertised this
- * prefix too. The key is the peer's IP or swpX, the value is the
- * hostname if we know it and "" if not.
- */
- json_peer = json_object_new_object();
-
- if (peer->hostname)
- json_object_string_add(json_peer, "hostname", peer->hostname);
-
- if (!json_adv_to)
+ if (json && !json_adv_to)
json_adv_to = json_object_new_object();
- if (peer->conf_if)
- json_object_object_add(json_adv_to, peer->conf_if, json_peer);
- else
- json_object_object_add(json_adv_to,
- sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN),
- json_peer);
+ route_vty_out_advertised_to(vty, peer, &first,
+ " Advertised to non peer-group peers:\n ",
+ json_adv_to);
}
- else
- {
- if (! first)
- vty_out (vty, " Advertised to non peer-group peers:%s ", VTY_NEWLINE);
+ }
- if (peer->hostname && bgp_flag_check(peer->bgp, BGP_FLAG_SHOW_HOSTNAME))
- {
- if (peer->conf_if)
- vty_out (vty, " %s(%s)", peer->hostname, peer->conf_if);
- else
- vty_out (vty, " %s(%s)", peer->hostname,
- sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN));
- }
- else
- {
- if (peer->conf_if)
- vty_out (vty, " %s", peer->conf_if);
- else
- vty_out (vty, " %s", sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN));
- }
+ if (json)
+ {
+ if (json_adv_to)
+ {
+ json_object_object_add(json, "advertisedTo", json_adv_to);
}
- first = 1;
- }
- }
-
- if (json)
- {
- if (first)
+ }
+ else
{
- json_object_object_add(json, "advertisedTo", json_adv_to);
+ if (first)
+ vty_out (vty, " Not advertised to any peer");
+ vty_out (vty, "%s", VTY_NEWLINE);
}
}
- else
- {
- if (!first)
- vty_out (vty, " Not advertised to any peer");
- vty_out (vty, "%s", VTY_NEWLINE);
- }
}
/* Display specified route of BGP table. */
@@ -12093,6 +12175,7 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
json_object *json_scode = NULL;
json_object *json_ocode = NULL;
json_object *json_ar = NULL;
+ struct peer_af *paf;
if (use_json)
{
@@ -12206,46 +12289,49 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
}
else
{
- adj = bgp_adj_peer_lookup(peer, rn);
- if (adj)
- {
- if (header1)
+ for (adj = rn->adj_out; adj; adj = adj->next)
+ SUBGRP_FOREACH_PEER(adj->subgroup, paf)
+ if (paf->peer == peer)
{
- if (use_json)
+ if (header1)
{
- json_object_int_add(json, "bgpTableVersion", table->version);
- json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id));
- json_object_object_add(json, "bgpStatusCodes", json_scode);
- json_object_object_add(json, "bgpOriginCodes", json_ocode);
+ if (use_json)
+ {
+ json_object_int_add(json, "bgpTableVersion", table->version);
+ json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id));
+ json_object_object_add(json, "bgpStatusCodes", json_scode);
+ json_object_object_add(json, "bgpOriginCodes", json_ocode);
+ }
+ else
+ {
+ vty_out (vty, "BGP table version is %" PRIu64 ", local router ID is %s%s", table->version,
+ inet_ntoa (bgp->router_id), VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ }
+ header1 = 0;
}
- else
+
+ if (header2)
{
- vty_out (vty, "BGP table version is %" PRIu64 ", local router ID is %s%s", table->version,
- inet_ntoa (bgp->router_id), VTY_NEWLINE);
- vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
- vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ if (!use_json)
+ vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE);
+ header2 = 0;
}
- header1 = 0;
- }
- if (header2)
- {
- if (!use_json)
- vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE);
- header2 = 0;
- }
- if (adj->attr)
- {
- bgp_attr_dup(&attr, adj->attr);
- ret = bgp_output_modifier(peer, &rn->p, &attr, afi, safi, rmap_name);
- if (ret != RMAP_DENY)
+
+ if (adj->attr)
{
- route_vty_out_tmp (vty, &rn->p, &attr, safi, use_json, json_ar);
- output_count++;
+ bgp_attr_dup(&attr, adj->attr);
+ ret = bgp_output_modifier(peer, &rn->p, &attr, afi, safi, rmap_name);
+ if (ret != RMAP_DENY)
+ {
+ route_vty_out_tmp (vty, &rn->p, &attr, safi, use_json, json_ar);
+ output_count++;
+ }
+ else
+ filtered_count++;
}
- else
- filtered_count++;
}
- }
}
}
if (use_json)