summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Walton <dwalton@cumulusnetworks.com>2017-08-25 20:27:49 +0200
committerDaniel Walton <dwalton@cumulusnetworks.com>2017-08-25 20:27:49 +0200
commit7f32323620077157dda1127c86ea792e4f5fcd89 (patch)
tree108e276beea142633182c52f7fbe301a3034afe9
parentMerge pull request #939 from jbonor/optimization (diff)
downloadfrr-7f32323620077157dda1127c86ea792e4f5fcd89.tar.xz
frr-7f32323620077157dda1127c86ea792e4f5fcd89.zip
bgpd: implement draft-ietf-grow-bgp-gshut-10
Signed-off-by: Daniel Walton <dwalton@cumulusnetworks.com>
-rw-r--r--bgpd/bgp_attr.c16
-rw-r--r--bgpd/bgp_clist.c7
-rw-r--r--bgpd/bgp_community.c18
-rw-r--r--bgpd/bgp_community.h1
-rw-r--r--bgpd/bgp_route.c124
-rw-r--r--bgpd/bgp_route.h1
-rw-r--r--bgpd/bgp_routemap.c5
-rw-r--r--bgpd/bgp_updgrp_adv.c6
-rw-r--r--bgpd/bgp_vty.c68
-rw-r--r--bgpd/bgpd.c4
-rw-r--r--bgpd/bgpd.h5
11 files changed, 218 insertions, 37 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index b03b408f7..0487cb4e3 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -848,10 +848,24 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, u_char origin,
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
if (community) {
+ u_int32_t gshut = COMMUNITY_GSHUT;
+
+ /* If we are not shutting down ourselves and we are
+ * aggregating a route that contains the GSHUT community we
+ * need to remove that community when creating the aggregate */
+ if (!bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN) &&
+ community_include(community, gshut)) {
+ community_del_val(community, &gshut);
+ }
+
attr.community = community;
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
}
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
+ bgp_attr_add_gshut_community(&attr);
+ }
+
attr.label_index = BGP_INVALID_LABEL_INDEX;
attr.label = MPLS_INVALID_LABEL;
attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
@@ -1400,7 +1414,7 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args)
attr->local_pref = stream_getl(peer->ibuf);
- /* Set atomic aggregate flag. */
+ /* Set the local-pref flag. */
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
return BGP_ATTR_PARSE_PROCEED;
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 13587b359..94ea35fa0 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -355,6 +355,9 @@ static char *community_str_get(struct community *com, int i)
case COMMUNITY_LOCAL_AS:
len = strlen(" local-AS");
break;
+ case COMMUNITY_GSHUT:
+ len = strlen(" graceful-shutdown");
+ break;
default:
len = strlen(" 65536:65535");
break;
@@ -380,6 +383,10 @@ static char *community_str_get(struct community *com, int i)
strcpy(pnt, "local-AS");
pnt += strlen("local-AS");
break;
+ case COMMUNITY_GSHUT:
+ strcpy(pnt, "graceful-shutdown");
+ pnt += strlen("graceful-shutdown");
+ break;
default:
as = (comval >> 16) & 0xFFFF;
val = comval & 0xFFFF;
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c
index 389d723e0..7e8411b6a 100644
--- a/bgpd/bgp_community.c
+++ b/bgpd/bgp_community.c
@@ -191,6 +191,7 @@ struct community *community_uniq_sort(struct community *com)
0xFFFFFF01 "no-export"
0xFFFFFF02 "no-advertise"
0xFFFFFF03 "local-AS"
+ 0xFFFF0000 "graceful-shutdown"
For other values, "AS:VAL" format is used. */
static void set_community_string(struct community *com)
@@ -244,6 +245,9 @@ static void set_community_string(struct community *com)
case COMMUNITY_LOCAL_AS:
len += strlen(" local-AS");
break;
+ case COMMUNITY_GSHUT:
+ len += strlen(" graceful-shutdown");
+ break;
default:
len += strlen(" 65536:65535");
break;
@@ -289,6 +293,12 @@ static void set_community_string(struct community *com)
json_string = json_object_new_string("localAs");
json_object_array_add(json_community_list, json_string);
break;
+ case COMMUNITY_GSHUT:
+ strcpy(pnt, "graceful-shutdown");
+ pnt += strlen("graceful-shutdown");
+ json_string = json_object_new_string("gracefulShutdown");
+ json_object_array_add(json_community_list, json_string);
+ break;
default:
as = (comval >> 16) & 0xFFFF;
val = comval & 0xFFFF;
@@ -480,6 +490,7 @@ enum community_token {
community_token_no_export,
community_token_no_advertise,
community_token_local_as,
+ community_token_gshut,
community_token_unknown
};
@@ -523,6 +534,12 @@ community_gettoken(const char *buf, enum community_token *token, u_int32_t *val)
p += strlen("local-AS");
return p;
}
+ if (strncmp(p, "graceful-shutdown", strlen("graceful-shutdown")) == 0) {
+ *val = COMMUNITY_GSHUT;
+ *token = community_token_gshut;
+ p += strlen("graceful-shutdown");
+ return p;
+ }
/* Unknown string. */
*token = community_token_unknown;
@@ -595,6 +612,7 @@ struct community *community_str2com(const char *str)
case community_token_no_export:
case community_token_no_advertise:
case community_token_local_as:
+ case community_token_gshut:
if (com == NULL) {
com = community_new();
com->json = NULL;
diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h
index c59eebf2e..f728debdb 100644
--- a/bgpd/bgp_community.h
+++ b/bgpd/bgp_community.h
@@ -48,6 +48,7 @@ struct community {
#define COMMUNITY_NO_ADVERTISE 0xFFFFFF02
#define COMMUNITY_NO_EXPORT_SUBCONFED 0xFFFFFF03
#define COMMUNITY_LOCAL_AS 0xFFFFFF03
+#define COMMUNITY_GSHUT 0xFFFF0000
/* Macros of community attribute. */
#define com_length(X) ((X)->size * 4)
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index bb204b01f..e12c6fb7d 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1267,6 +1267,39 @@ static void bgp_peer_as_override(struct bgp *bgp, afi_t afi, safi_t safi,
}
}
+void bgp_attr_add_gshut_community(struct attr *attr)
+{
+ struct community *old;
+ struct community *new;
+ struct community *merge;
+ struct community *gshut;
+
+ old = attr->community;
+ gshut = community_str2com("graceful-shutdown");
+
+ if (old) {
+ merge = community_merge(community_dup(old), gshut);
+
+ if (old->refcnt== 0)
+ community_free(old);
+
+ new = community_uniq_sort(merge);
+ community_free(merge);
+ } else {
+ new = community_dup(gshut);
+ }
+
+ community_free(gshut);
+ attr->community = new;
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
+
+ /* When we add the graceful-shutdown community we must also
+ * lower the local-preference */
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
+ attr->local_pref = BGP_GSHUT_LOCAL_PREF;
+}
+
+
static void subgroup_announce_reset_nhop(u_char family, struct attr *attr)
{
if (family == AF_INET)
@@ -1623,6 +1656,15 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri,
}
}
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
+ if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) {
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
+ attr->local_pref = BGP_GSHUT_LOCAL_PREF;
+ } else {
+ bgp_attr_add_gshut_community(attr);
+ }
+ }
+
/* After route-map has been applied, we check to see if the nexthop to
* be carried in the attribute (that is used for the announcement) can
* be cleared off or not. We do this in all cases where we would be
@@ -2725,6 +2767,22 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
goto filtered;
}
+ if (peer->sort == BGP_PEER_EBGP) {
+
+ /* If we receive the graceful-shutdown community from an eBGP peer we
+ * must lower local-preference */
+ if (new_attr.community &&
+ community_include(new_attr.community, COMMUNITY_GSHUT)) {
+ new_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
+ new_attr.local_pref = BGP_GSHUT_LOCAL_PREF;
+
+ /* If graceful-shutdown is configured then add the GSHUT community to
+ * all paths received from eBGP peers */
+ } else if (bgp_flag_check(peer->bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
+ bgp_attr_add_gshut_community(&new_attr);
+ }
+ }
+
/* next hop check. */
if (bgp_update_martian_nexthop(bgp, afi, safi, &new_attr)) {
reason = "martian or self next-hop;";
@@ -4044,9 +4102,18 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
bgp_static_withdraw(bgp, p, afi, safi);
return;
}
+
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+ bgp_attr_add_gshut_community(&attr_tmp);
+
attr_new = bgp_attr_intern(&attr_tmp);
- } else
+ } else {
+
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+ bgp_attr_add_gshut_community(&attr);
+
attr_new = bgp_attr_intern(&attr);
+ }
for (ri = rn->info; ri; ri = ri->next)
if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP
@@ -6152,6 +6219,9 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
}
}
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+ bgp_attr_add_gshut_community(&attr_new);
+
bn = bgp_afi_node_get(bgp->rib[afi][SAFI_UNICAST], afi,
SAFI_UNICAST, p, NULL);
@@ -8019,8 +8089,8 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
enum bgp_show_type type);
static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi,
safi_t safi, enum bgp_show_type type);
-static int bgp_show_community(struct vty *vty, struct bgp *bgp, int argc,
- struct cmd_token **argv, int exact, afi_t afi,
+static int bgp_show_community(struct vty *vty, struct bgp *bgp,
+ const char *comstr, int exact, afi_t afi,
safi_t safi);
static int bgp_show_table(struct vty *vty, struct bgp *bgp,
@@ -8846,7 +8916,7 @@ DEFUN (show_ip_bgp,
|prefix-list WORD\
|filter-list WORD\
|statistics\
- |community [<AA:NN|local-AS|no-advertise|no-export> [exact-match]]\
+ |community [<AA:NN|local-AS|no-advertise|no-export|graceful-shutdown> [exact-match]]\
|community-list <(1-500)|WORD> [exact-match]\
|A.B.C.D/M longer-prefixes\
|X:X::X:X/M longer-prefixes>\
@@ -8874,6 +8944,7 @@ DEFUN (show_ip_bgp,
"Do not send outside local AS (well-known community)\n"
"Do not advertise to any peer (well-known community)\n"
"Do not export to next AS (well-known community)\n"
+ "Graceful shutdown (well-known community)\n"
"Exact match of the communities\n"
"Display routes matching the community-list\n"
"community-list number\n"
@@ -8891,6 +8962,7 @@ DEFUN (show_ip_bgp,
enum bgp_show_type sh_type = bgp_show_type_normal;
struct bgp *bgp = NULL;
int idx = 0;
+ int idx_community_type = 0;
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp);
@@ -8934,12 +9006,15 @@ DEFUN (show_ip_bgp,
if (argv_find(argv, argc, "community", &idx)) {
/* show a specific community */
- if (argv_find(argv, argc, "local-AS", &idx)
- || argv_find(argv, argc, "no-advertise", &idx)
- || argv_find(argv, argc, "no-export", &idx)) {
- if (argv_find(argv, argc, "exact_match", &idx))
+ if (argv_find(argv, argc, "local-AS", &idx_community_type)
+ || argv_find(argv, argc, "no-advertise", &idx_community_type)
+ || argv_find(argv, argc, "no-export", &idx_community_type)
+ || argv_find(argv, argc, "graceful-shutdown", &idx_community_type)
+ || argv_find(argv, argc, "AA:NN", &idx_community_type)) {
+
+ if (argv_find(argv, argc, "exact-match", &idx))
exact_match = 1;
- return bgp_show_community(vty, bgp, argc, argv,
+ return bgp_show_community(vty, bgp, argv[idx_community_type]->arg,
exact_match, afi, safi);
}
/* show all communities */
@@ -9170,39 +9245,16 @@ static int bgp_show_route_map(struct vty *vty, struct bgp *bgp,
return bgp_show(vty, bgp, afi, safi, type, rmap, 0);
}
-static int bgp_show_community(struct vty *vty, struct bgp *bgp, int argc,
- struct cmd_token **argv, int exact, afi_t afi,
+static int bgp_show_community(struct vty *vty, struct bgp *bgp,
+ const char *comstr, int exact, afi_t afi,
safi_t safi)
{
struct community *com;
- struct buffer *b;
- int i;
- char *str;
- int first = 0;
int ret = 0;
- b = buffer_new(1024);
- for (i = 0; i < argc; i++) {
- if (first)
- buffer_putc(b, ' ');
- else {
- if (strmatch(argv[i]->text, "unicast")
- || strmatch(argv[i]->text, "multicast"))
- continue;
- first = 1;
- }
-
- buffer_putstr(b, argv[i]->arg);
- }
- buffer_putc(b, '\0');
-
- str = buffer_getstr(b);
- buffer_free(b);
-
- com = community_str2com(str);
- XFREE(MTYPE_TMP, str);
+ com = community_str2com(comstr);
if (!com) {
- vty_out(vty, "%% Community malformed: \n");
+ vty_out(vty, "%% Community malformed: %s\n", comstr);
return CMD_WARNING;
}
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 1a1817bad..b9d7957c6 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -423,6 +423,7 @@ extern void bgp_info_restore(struct bgp_node *, struct bgp_info *);
extern int bgp_info_cmp_compatible(struct bgp *, struct bgp_info *,
struct bgp_info *, char *pfx_buf, afi_t afi,
safi_t safi);
+extern void bgp_attr_add_gshut_community(struct attr *attr);
extern void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn,
struct bgp_maxpaths_cfg *mpath_cfg,
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 5a5d2a5d5..dce18a73d 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -3768,6 +3768,11 @@ DEFUN (set_community,
buffer_putstr(b, "no-export");
continue;
}
+ if (strncmp(argv[i]->arg, "graceful-shutdown", strlen(argv[i]->arg))
+ == 0) {
+ buffer_putstr(b, "graceful-shutdown");
+ continue;
+ }
buffer_putstr(b, argv[i]->arg);
}
buffer_putc(b, '\0');
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 0a33fa5ed..1bd6fb8b3 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -691,6 +691,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
aspath = attr.aspath;
+
attr.local_pref = bgp->default_local_pref;
if (afi == AFI_IP)
@@ -749,6 +750,11 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
} else {
if (!CHECK_FLAG(subgrp->sflags,
SUBGRP_STATUS_DEFAULT_ORIGINATE)) {
+
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
+ bgp_attr_add_gshut_community(&attr);
+ }
+
SET_FLAG(subgrp->sflags,
SUBGRP_STATUS_DEFAULT_ORIGINATE);
subgroup_default_update_packet(subgrp, &attr, from);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 2e18a6d44..d9117deaf 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -1804,6 +1804,69 @@ DEFUN (no_bgp_graceful_restart_preserve_fw,
return CMD_SUCCESS;
}
+static void bgp_redistribute_redo(struct bgp *bgp)
+{
+ afi_t afi;
+ int i;
+ struct list *red_list;
+ struct listnode *node;
+ struct bgp_redist *red;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+
+ red_list = bgp->redist[afi][i];
+ if (!red_list)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
+ bgp_redistribute_resend(bgp, afi, i,
+ red->instance);
+ }
+ }
+ }
+}
+
+/* "bgp graceful-shutdown" configuration */
+DEFUN (bgp_graceful_shutdown,
+ bgp_graceful_shutdown_cmd,
+ "bgp graceful-shutdown",
+ BGP_STR
+ "Graceful shutdown parameters\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
+ bgp_flag_set(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN);
+ bgp_static_redo_import_check(bgp);
+ bgp_redistribute_redo(bgp);
+ bgp_clear_star_soft_out(vty, bgp->name);
+ bgp_clear_star_soft_in(vty, bgp->name);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_graceful_shutdown,
+ no_bgp_graceful_shutdown_cmd,
+ "no bgp graceful-shutdown",
+ NO_STR
+ BGP_STR
+ "Graceful shutdown parameters\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
+ bgp_flag_unset(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN);
+ bgp_static_redo_import_check(bgp);
+ bgp_redistribute_redo(bgp);
+ bgp_clear_star_soft_out(vty, bgp->name);
+ bgp_clear_star_soft_in(vty, bgp->name);
+ }
+
+ return CMD_SUCCESS;
+}
+
/* "bgp fast-external-failover" configuration. */
DEFUN (bgp_fast_external_failover,
bgp_fast_external_failover_cmd,
@@ -10459,6 +10522,7 @@ DEFUN (bgp_redistribute_ipv4,
vty_out(vty, "%% Invalid route type\n");
return CMD_WARNING_CONFIG_FAILED;
}
+
bgp_redist_add(bgp, AFI_IP, type, 0);
return bgp_redistribute_set(bgp, AFI_IP, type, 0);
}
@@ -11335,6 +11399,10 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &bgp_graceful_restart_preserve_fw_cmd);
install_element(BGP_NODE, &no_bgp_graceful_restart_preserve_fw_cmd);
+ /* "bgp graceful-shutdown" commands */
+ install_element(BGP_NODE, &bgp_graceful_shutdown_cmd);
+ install_element(BGP_NODE, &no_bgp_graceful_shutdown_cmd);
+
/* "bgp fast-external-failover" commands */
install_element(BGP_NODE, &bgp_fast_external_failover_cmd);
install_element(BGP_NODE, &no_bgp_fast_external_failover_cmd);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 9d7c38c87..258d650d2 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -7190,6 +7190,10 @@ int bgp_config_write(struct vty *vty)
if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_RESTART))
vty_out(vty, " bgp graceful-restart\n");
+ /* BGP graceful-shutdown */
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+ vty_out(vty, " bgp graceful-shutdown\n");
+
/* BGP graceful-restart Preserve State F bit. */
if (bgp_flag_check(bgp, BGP_FLAG_GR_PRESERVE_FWD))
vty_out(vty,
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index f6e7b2277..da30ecd96 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -303,6 +303,7 @@ struct bgp {
#define BGP_FLAG_FORCE_STATIC_PROCESS (1 << 18)
#define BGP_FLAG_SHOW_HOSTNAME (1 << 19)
#define BGP_FLAG_GR_PRESERVE_FWD (1 << 20)
+#define BGP_FLAG_GRACEFUL_SHUTDOWN (1 << 21)
/* BGP Per AF flags */
u_int16_t af_flags[AFI_MAX][SAFI_MAX];
@@ -1091,6 +1092,10 @@ struct bgp_nlri {
/* BGP default local preference. */
#define BGP_DEFAULT_LOCAL_PREF 100
+/* BGP local-preference to send when 'bgp graceful-shutdown'
+ * is configured */
+#define BGP_GSHUT_LOCAL_PREF 0
+
/* BGP default subgroup packet queue max . */
#define BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX 40