diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-01-26 16:38:07 +0100 |
---|---|---|
committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-01-26 16:38:07 +0100 |
commit | 7f12cb2b659196bd818b3d5ddd1929d83dc85069 (patch) | |
tree | f07849247b6b51088eacc182d91f8fe346a3bf69 /bgpd/bgp_routemap.c | |
parent | bgpd: Remove redundant warning message (diff) | |
parent | Merge branch 'frr/pull/118' (diff) | |
download | frr-7f12cb2b659196bd818b3d5ddd1929d83dc85069.tar.xz frr-7f12cb2b659196bd818b3d5ddd1929d83dc85069.zip |
Merge remote-tracking branch 'origin/master' into bgpafisafi
Diffstat (limited to 'bgpd/bgp_routemap.c')
-rw-r--r-- | bgpd/bgp_routemap.c | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 373a8e5d9..8f2486314 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -52,6 +52,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_filter.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_debug.h" @@ -84,6 +85,8 @@ o Cisco route-map as-path tag : Not yet automatic-tag : (This will not be implemented by bgpd) community : Done + large-community : Done + large-comm-list : Done comm-list : Not yet dampning : Not yet default : (This will not be implemented by bgpd) @@ -847,6 +850,78 @@ struct route_map_rule_cmd route_match_community_cmd = route_match_community_free }; +/* Match function for lcommunity match. */ +static route_map_result_t +route_match_lcommunity (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct community_list *list; + struct bgp_info *bgp_info; + struct rmap_community *rcom; + + if (type == RMAP_BGP) + { + bgp_info = object; + rcom = rule; + + list = community_list_lookup (bgp_clist, rcom->name, + LARGE_COMMUNITY_LIST_MASTER); + if (! list) + return RMAP_NOMATCH; + + if (bgp_info->attr->extra && + lcommunity_list_match (bgp_info->attr->extra->lcommunity, list)) + return RMAP_MATCH; + + } + return RMAP_NOMATCH; +} + +/* Compile function for community match. */ +static void * +route_match_lcommunity_compile (const char *arg) +{ + struct rmap_community *rcom; + int len; + char *p; + + rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community)); + + p = strchr (arg, ' '); + if (p) + { + len = p - arg; + rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); + memcpy (rcom->name, arg, len); + } + else + { + rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); + rcom->exact = 0; + } + return rcom; +} + +/* Compile function for community match. */ +static void +route_match_lcommunity_free (void *rule) +{ + struct rmap_community *rcom = rule; + + XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name); + XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom); +} + +/* Route map commands for community matching. */ +struct route_map_rule_cmd route_match_lcommunity_cmd = +{ + "large-community", + route_match_lcommunity, + route_match_lcommunity_compile, + route_match_lcommunity_free +}; + + /* Match function for extcommunity match. */ static route_map_result_t route_match_ecommunity (void *rule, struct prefix *prefix, @@ -1544,6 +1619,224 @@ struct route_map_rule_cmd route_set_community_cmd = route_set_community_free, }; +/* `set community COMMUNITY' */ +struct rmap_lcom_set +{ + struct lcommunity *lcom; + int additive; + int none; +}; + + +/* For lcommunity set mechanism. */ +static route_map_result_t +route_set_lcommunity (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct rmap_lcom_set *rcs; + struct bgp_info *binfo; + struct attr *attr; + struct lcommunity *new = NULL; + struct lcommunity *old; + struct lcommunity *merge; + + if (type == RMAP_BGP) + { + rcs = rule; + binfo = object; + attr = binfo->attr; + old = (attr->extra) ? attr->extra->lcommunity : NULL; + + /* "none" case. */ + if (rcs->none) + { + attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)); + if (attr->extra) + attr->extra->lcommunity = NULL; + + /* See the longer comment down below. */ + if (old && old->refcnt == 0) + lcommunity_free(&old); + return RMAP_OKAY; + } + + if (rcs->additive && old) + { + merge = lcommunity_merge (lcommunity_dup (old), rcs->lcom); + + /* HACK: if the old large-community is not intern'd, + * we should free it here, or all reference to it may be lost. + * Really need to cleanup attribute caching sometime. + */ + if (old->refcnt == 0) + lcommunity_free (&old); + new = lcommunity_uniq_sort (merge); + lcommunity_free (&merge); + } + else + new = lcommunity_dup (rcs->lcom); + + /* will be intern()'d or attr_flush()'d by bgp_update_main() */ + (bgp_attr_extra_get (attr))->lcommunity = new; + + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); + } + + return RMAP_OKAY; +} + +/* Compile function for set community. */ +static void * +route_set_lcommunity_compile (const char *arg) +{ + struct rmap_lcom_set *rcs; + struct lcommunity *lcom = NULL; + char *sp; + int additive = 0; + int none = 0; + + if (strcmp (arg, "none") == 0) + none = 1; + else + { + sp = strstr (arg, "additive"); + + if (sp && sp > arg) + { + /* "additive" keyworkd is included. */ + additive = 1; + *(sp - 1) = '\0'; + } + + lcom = lcommunity_str2com (arg); + + if (additive) + *(sp - 1) = ' '; + + if (! lcom) + return NULL; + } + + rcs = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set)); + rcs->lcom = lcom; + rcs->additive = additive; + rcs->none = none; + + return rcs; +} + +/* Free function for set lcommunity. */ +static void +route_set_lcommunity_free (void *rule) +{ + struct rmap_lcom_set *rcs = rule; + + if (rcs->lcom) { + lcommunity_free (&rcs->lcom); + } + XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_lcommunity_cmd = +{ + "large-community", + route_set_lcommunity, + route_set_lcommunity_compile, + route_set_lcommunity_free, +}; + +/* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */ + +/* For large community set mechanism. */ +static route_map_result_t +route_set_lcommunity_delete (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct community_list *list; + struct lcommunity *merge; + struct lcommunity *new; + struct lcommunity *old; + struct bgp_info *binfo; + + if (type == RMAP_BGP) + { + if (! rule) + return RMAP_OKAY; + + binfo = object; + list = community_list_lookup (bgp_clist, rule, + LARGE_COMMUNITY_LIST_MASTER); + old = ((binfo->attr->extra) ? binfo->attr->extra->lcommunity : NULL); + + if (list && old) + { + merge = lcommunity_list_match_delete (lcommunity_dup (old), list); + new = lcommunity_uniq_sort (merge); + lcommunity_free (&merge); + + /* HACK: if the old community is not intern'd, + * we should free it here, or all reference to it may be lost. + * Really need to cleanup attribute caching sometime. + */ + if (old->refcnt == 0) + lcommunity_free (&old); + + if (new->size == 0) + { + binfo->attr->extra->lcommunity = NULL; + binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); + lcommunity_free (&new); + } + else + { + binfo->attr->extra->lcommunity = new; + binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); + } + } + } + + return RMAP_OKAY; +} + +/* Compile function for set lcommunity. */ +static void * +route_set_lcommunity_delete_compile (const char *arg) +{ + char *p; + char *str; + int len; + + p = strchr (arg, ' '); + if (p) + { + len = p - arg; + str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); + memcpy (str, arg, len); + } + else + str = NULL; + + return str; +} + +/* Free function for set lcommunity. */ +static void +route_set_lcommunity_delete_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set lcommunity rule structure. */ +struct route_map_rule_cmd route_set_lcommunity_delete_cmd = +{ + "large-comm-list", + route_set_lcommunity_delete, + route_set_lcommunity_delete_compile, + route_set_lcommunity_delete_free, +}; + + /* `set comm-list (<1-99>|<100-500>|WORD) delete' */ /* For community set mechanism. */ @@ -3164,7 +3457,32 @@ DEFUN (no_match_community, RMAP_EVENT_CLIST_DELETED); } +DEFUN (match_lcommunity, + match_lcommunity_cmd, + "match large-community [<(1-99)|(100-500)|WORD>]", + MATCH_STR + "Match BGP large community list\n" + "Large Community-list number (standard)\n" + "Large Community-list number (expanded)\n" + "Large Community-list name\n") +{ + return bgp_route_match_add (vty, "large-community", argv[2]->arg, + RMAP_EVENT_LLIST_ADDED); +} +DEFUN (no_match_lcommunity, + no_match_lcommunity_cmd, + "no match large-community [<(1-99)|(100-500)|WORD>]", + NO_STR + MATCH_STR + "Match BGP large community list\n" + "Large Community-list number (standard)\n" + "Large Community-list number (expanded)\n" + "Large Community-list name\n") +{ + return bgp_route_match_delete (vty, "large-community", NULL, + RMAP_EVENT_LLIST_DELETED); +} DEFUN (match_ecommunity, match_ecommunity_cmd, @@ -3597,6 +3915,95 @@ DEFUN (no_set_community_delete, "comm-list", NULL); } +DEFUN (set_lcommunity, + set_lcommunity_cmd, + "set large-community AA:BB:CC...", + SET_STR + "BGP large community attribute\n" + "Large Community number in aa:bb:cc format or additive\n") +{ + int ret; + char *str; + + str = argv_concat (argv, argc, 2); + ret = generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), "large-community", str); + XFREE (MTYPE_TMP, str); + + return ret; +} + +DEFUN (set_lcommunity_none, + set_lcommunity_none_cmd, + "set large-community none", + SET_STR + "BGP large community attribute\n" + "No large community attribute\n") +{ + return generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), + "large-community", "none"); +} + +DEFUN (no_set_lcommunity, + no_set_lcommunity_cmd, + "no set large-community none", + NO_STR + SET_STR + "BGP large community attribute\n" + "No community attribute\n") +{ + return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index), + "large-community", NULL); +} + +DEFUN (no_set_lcommunity1, + no_set_lcommunity1_cmd, + "no set large-community AA:BB:CC...", + NO_STR + SET_STR + "BGP large community attribute\n" + "Large community in AA:BB:CC... format or additive\n") +{ + return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index), + "large-community", NULL); +} + +DEFUN (set_lcommunity_delete, + set_lcommunity_delete_cmd, + "set large-comm-list <(1-99)|(100-500)|WORD> delete", + SET_STR + "set BGP large community list (for deletion)\n" + "Large Community-list number (standard)\n" + "Large Communitly-list number (expanded)\n" + "Large Community-list name\n" + "Delete matching large communities\n") +{ + char *str; + + str = XCALLOC (MTYPE_TMP, strlen (argv[2]->arg) + strlen (" delete") + 1); + strcpy (str, argv[2]->arg); + strcpy (str + strlen (argv[2]->arg), " delete"); + + generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), + "large-comm-list", str); + + XFREE (MTYPE_TMP, str); + return CMD_SUCCESS; +} + +DEFUN (no_set_lcommunity_delete, + no_set_lcommunity_delete_cmd, + "no set large-comm-list <(1-99|(100-500)|WORD)> [delete]", + NO_STR + SET_STR + "set BGP large community list (for deletion)\n" + "Large Community-list number (standard)\n" + "Large Communitly-list number (expanded)\n" + "Large Community-list name\n" + "Delete matching large communities\n") +{ + return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index), + "large-comm-list", NULL); +} DEFUN (set_ecommunity_rt, set_ecommunity_rt_cmd, @@ -4139,6 +4546,7 @@ bgp_route_map_init (void) route_map_install_match (&route_match_ip_route_source_prefix_list_cmd); route_map_install_match (&route_match_aspath_cmd); route_map_install_match (&route_match_community_cmd); + route_map_install_match (&route_match_lcommunity_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); @@ -4158,6 +4566,8 @@ bgp_route_map_init (void) route_map_install_set (&route_set_aggregator_as_cmd); route_map_install_set (&route_set_community_cmd); route_map_install_set (&route_set_community_delete_cmd); + route_map_install_set (&route_set_lcommunity_cmd); + route_map_install_set (&route_set_lcommunity_delete_cmd); route_map_install_set (&route_set_vpnv4_nexthop_cmd); route_map_install_set (&route_set_vpnv6_nexthop_cmd); route_map_install_set (&route_set_originator_id_cmd); @@ -4180,6 +4590,8 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &match_community_cmd); install_element (RMAP_NODE, &match_community_exact_cmd); install_element (RMAP_NODE, &no_match_community_cmd); + install_element (RMAP_NODE, &match_lcommunity_cmd); + install_element (RMAP_NODE, &no_match_lcommunity_cmd); install_element (RMAP_NODE, &match_ecommunity_cmd); install_element (RMAP_NODE, &no_match_ecommunity_cmd); install_element (RMAP_NODE, &match_origin_cmd); @@ -4209,6 +4621,12 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &no_set_community_cmd); install_element (RMAP_NODE, &set_community_delete_cmd); install_element (RMAP_NODE, &no_set_community_delete_cmd); + install_element (RMAP_NODE, &set_lcommunity_cmd); + install_element (RMAP_NODE, &set_lcommunity_none_cmd); + install_element (RMAP_NODE, &no_set_lcommunity_cmd); + install_element (RMAP_NODE, &no_set_lcommunity1_cmd); + install_element (RMAP_NODE, &set_lcommunity_delete_cmd); + install_element (RMAP_NODE, &no_set_lcommunity_delete_cmd); install_element (RMAP_NODE, &set_ecommunity_rt_cmd); install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd); install_element (RMAP_NODE, &set_ecommunity_soo_cmd); |