Merge pull request #5169 from ton31337/feature/sequence_numbers_for_community_lists

bgpd: Use sequence numbers for community lists
This commit is contained in:
Quentin Young 2020-02-04 11:56:29 -05:00 committed by GitHub
commit 0445dc7d4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 294 additions and 80 deletions

View File

@ -37,6 +37,37 @@
#include "bgpd/bgp_regex.h" #include "bgpd/bgp_regex.h"
#include "bgpd/bgp_clist.h" #include "bgpd/bgp_clist.h"
/* Calculate new sequential number. */
static int64_t bgp_clist_new_seq_get(struct community_list *list)
{
int64_t maxseq;
int64_t newseq;
struct community_entry *entry;
maxseq = newseq = 0;
for (entry = list->head; entry; entry = entry->next) {
if (maxseq < entry->seq)
maxseq = entry->seq;
}
newseq = ((maxseq / 5) * 5) + 5;
return (newseq > UINT_MAX) ? UINT_MAX : newseq;
}
/* Return community-list entry which has same seq number. */
static struct community_entry *bgp_clist_seq_check(struct community_list *list,
int64_t seq)
{
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next)
if (entry->seq == seq)
return entry;
return NULL;
}
static uint32_t bgp_clist_hash_key_community_list(const void *data) static uint32_t bgp_clist_hash_key_community_list(const void *data)
{ {
struct community_list *cl = (struct community_list *) data; struct community_list *cl = (struct community_list *) data;
@ -285,20 +316,6 @@ static int community_list_empty_p(struct community_list *list)
return (list->head == NULL && list->tail == NULL) ? 1 : 0; return (list->head == NULL && list->tail == NULL) ? 1 : 0;
} }
/* Add community-list entry to the list. */
static void community_list_entry_add(struct community_list *list,
struct community_entry *entry)
{
entry->next = NULL;
entry->prev = list->tail;
if (list->tail)
list->tail->next = entry;
else
list->head = entry;
list->tail = entry;
}
/* Delete community-list entry from the list. */ /* Delete community-list entry from the list. */
static void community_list_entry_delete(struct community_list_master *cm, static void community_list_entry_delete(struct community_list_master *cm,
struct community_list *list, struct community_list *list,
@ -320,6 +337,57 @@ static void community_list_entry_delete(struct community_list_master *cm,
community_list_delete(cm, list); community_list_delete(cm, list);
} }
/* Add community-list entry to the list. */
static void community_list_entry_add(struct community_list *list,
struct community_entry *entry,
struct community_list_handler *ch,
int master)
{
struct community_list_master *cm = NULL;
struct community_entry *replace;
struct community_entry *point;
cm = community_list_master_lookup(ch, master);
/* Automatic assignment of seq no. */
if (entry->seq == COMMUNITY_SEQ_NUMBER_AUTO)
entry->seq = bgp_clist_new_seq_get(list);
if (list->tail && entry->seq > list->tail->seq)
point = NULL;
else {
replace = bgp_clist_seq_check(list, entry->seq);
if (replace)
community_list_entry_delete(cm, list, entry);
/* Check insert point. */
for (point = list->head; point; point = point->next)
if (point->seq >= entry->seq)
break;
}
/* In case of this is the first element of the list. */
entry->next = point;
if (point) {
if (point->prev)
point->prev->next = entry;
else
list->head = entry;
entry->prev = point->prev;
point->prev = entry;
} else {
if (list->tail)
list->tail->next = entry;
else
list->head = entry;
entry->prev = list->tail;
list->tail = entry;
}
}
/* Lookup community-list entry from the list. */ /* Lookup community-list entry from the list. */
static struct community_entry * static struct community_entry *
community_list_entry_lookup(struct community_list *list, const void *arg, community_list_entry_lookup(struct community_list *list, const void *arg,
@ -878,12 +946,16 @@ static int community_list_dup_check(struct community_list *list,
/* Set community-list. */ /* Set community-list. */
int community_list_set(struct community_list_handler *ch, const char *name, int community_list_set(struct community_list_handler *ch, const char *name,
const char *str, int direct, int style) const char *str, const char *seq, int direct, int style)
{ {
struct community_entry *entry = NULL; struct community_entry *entry = NULL;
struct community_list *list; struct community_list *list;
struct community *com = NULL; struct community *com = NULL;
regex_t *regex = NULL; regex_t *regex = NULL;
int64_t seqnum = COMMUNITY_SEQ_NUMBER_AUTO;
if (seq)
seqnum = (int64_t)atol(seq);
/* Get community list. */ /* Get community list. */
list = community_list_get(ch, name, COMMUNITY_LIST_MASTER); list = community_list_get(ch, name, COMMUNITY_LIST_MASTER);
@ -919,6 +991,7 @@ int community_list_set(struct community_list_handler *ch, const char *name,
entry->any = (str ? 0 : 1); entry->any = (str ? 0 : 1);
entry->u.com = com; entry->u.com = com;
entry->reg = regex; entry->reg = regex;
entry->seq = seqnum;
entry->config = entry->config =
(regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL); (regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
@ -926,7 +999,8 @@ int community_list_set(struct community_list_handler *ch, const char *name,
if (community_list_dup_check(list, entry)) if (community_list_dup_check(list, entry))
community_entry_free(entry); community_entry_free(entry);
else { else {
community_list_entry_add(list, entry); community_list_entry_add(list, entry, ch,
COMMUNITY_LIST_MASTER);
route_map_notify_dependencies(name, RMAP_EVENT_CLIST_ADDED); route_map_notify_dependencies(name, RMAP_EVENT_CLIST_ADDED);
} }
@ -935,7 +1009,8 @@ int community_list_set(struct community_list_handler *ch, const char *name,
/* Unset community-list */ /* Unset community-list */
int community_list_unset(struct community_list_handler *ch, const char *name, int community_list_unset(struct community_list_handler *ch, const char *name,
const char *str, int direct, int style) const char *str, const char *seq, int direct,
int style)
{ {
struct community_list_master *cm = NULL; struct community_list_master *cm = NULL;
struct community_entry *entry = NULL; struct community_entry *entry = NULL;
@ -1057,12 +1132,16 @@ static int lcommunity_list_valid(const char *community)
/* Set lcommunity-list. */ /* Set lcommunity-list. */
int lcommunity_list_set(struct community_list_handler *ch, const char *name, int lcommunity_list_set(struct community_list_handler *ch, const char *name,
const char *str, int direct, int style) const char *str, const char *seq, int direct, int style)
{ {
struct community_entry *entry = NULL; struct community_entry *entry = NULL;
struct community_list *list; struct community_list *list;
struct lcommunity *lcom = NULL; struct lcommunity *lcom = NULL;
regex_t *regex = NULL; regex_t *regex = NULL;
int64_t seqnum = COMMUNITY_SEQ_NUMBER_AUTO;
if (seq)
seqnum = (int64_t)atol(seq);
/* Get community list. */ /* Get community list. */
list = community_list_get(ch, name, LARGE_COMMUNITY_LIST_MASTER); list = community_list_get(ch, name, LARGE_COMMUNITY_LIST_MASTER);
@ -1101,6 +1180,7 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
entry->any = (str ? 0 : 1); entry->any = (str ? 0 : 1);
entry->u.lcom = lcom; entry->u.lcom = lcom;
entry->reg = regex; entry->reg = regex;
entry->seq = seqnum;
entry->config = entry->config =
(regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL); (regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
@ -1108,7 +1188,8 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
if (community_list_dup_check(list, entry)) if (community_list_dup_check(list, entry))
community_entry_free(entry); community_entry_free(entry);
else { else {
community_list_entry_add(list, entry); community_list_entry_add(list, entry, ch,
LARGE_COMMUNITY_LIST_MASTER);
route_map_notify_dependencies(name, RMAP_EVENT_LLIST_ADDED); route_map_notify_dependencies(name, RMAP_EVENT_LLIST_ADDED);
} }
@ -1118,7 +1199,8 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
/* Unset community-list. When str is NULL, delete all of /* Unset community-list. When str is NULL, delete all of
community-list entry belongs to the specified name. */ community-list entry belongs to the specified name. */
int lcommunity_list_unset(struct community_list_handler *ch, const char *name, int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
const char *str, int direct, int style) const char *str, const char *seq, int direct,
int style)
{ {
struct community_list_master *cm = NULL; struct community_list_master *cm = NULL;
struct community_entry *entry = NULL; struct community_entry *entry = NULL;
@ -1168,12 +1250,17 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
/* Set extcommunity-list. */ /* Set extcommunity-list. */
int extcommunity_list_set(struct community_list_handler *ch, const char *name, int extcommunity_list_set(struct community_list_handler *ch, const char *name,
const char *str, int direct, int style) const char *str, const char *seq, int direct,
int style)
{ {
struct community_entry *entry = NULL; struct community_entry *entry = NULL;
struct community_list *list; struct community_list *list;
struct ecommunity *ecom = NULL; struct ecommunity *ecom = NULL;
regex_t *regex = NULL; regex_t *regex = NULL;
int64_t seqnum = COMMUNITY_SEQ_NUMBER_AUTO;
if (seq)
seqnum = (int64_t)atol(seq);
if (str == NULL) if (str == NULL)
return COMMUNITY_LIST_ERR_MALFORMED_VAL; return COMMUNITY_LIST_ERR_MALFORMED_VAL;
@ -1220,12 +1307,14 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
entry->u.ecom = ecom; entry->u.ecom = ecom;
entry->reg = regex; entry->reg = regex;
entry->seq = seqnum;
/* Do not put duplicated community entry. */ /* Do not put duplicated community entry. */
if (community_list_dup_check(list, entry)) if (community_list_dup_check(list, entry))
community_entry_free(entry); community_entry_free(entry);
else { else {
community_list_entry_add(list, entry); community_list_entry_add(list, entry, ch,
EXTCOMMUNITY_LIST_MASTER);
route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_ADDED); route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_ADDED);
} }
@ -1238,7 +1327,8 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
* specified name. * specified name.
*/ */
int extcommunity_list_unset(struct community_list_handler *ch, const char *name, int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
const char *str, int direct, int style) const char *str, const char *seq, int direct,
int style)
{ {
struct community_list_master *cm = NULL; struct community_list_master *cm = NULL;
struct community_entry *entry = NULL; struct community_entry *entry = NULL;

View File

@ -36,6 +36,8 @@
#define COMMUNITY_LIST_STRING 0 #define COMMUNITY_LIST_STRING 0
#define COMMUNITY_LIST_NUMBER 1 #define COMMUNITY_LIST_NUMBER 1
#define COMMUNITY_SEQ_NUMBER_AUTO -1
/* Community-list entry types. */ /* Community-list entry types. */
#define COMMUNITY_LIST_STANDARD 0 /* Standard community-list. */ #define COMMUNITY_LIST_STANDARD 0 /* Standard community-list. */
#define COMMUNITY_LIST_EXPANDED 1 /* Expanded community-list. */ #define COMMUNITY_LIST_EXPANDED 1 /* Expanded community-list. */
@ -81,6 +83,9 @@ struct community_entry {
/* Any match. */ /* Any match. */
uint8_t any; uint8_t any;
/* Sequence number. */
int64_t seq;
/* Community structure. */ /* Community structure. */
union { union {
struct community *com; struct community *com;
@ -135,23 +140,23 @@ extern struct community_list_handler *community_list_init(void);
extern void community_list_terminate(struct community_list_handler *); extern void community_list_terminate(struct community_list_handler *);
extern int community_list_set(struct community_list_handler *ch, extern int community_list_set(struct community_list_handler *ch,
const char *name, const char *str, int direct, const char *name, const char *str,
int style); const char *seq, int direct, int style);
extern int community_list_unset(struct community_list_handler *ch, extern int community_list_unset(struct community_list_handler *ch,
const char *name, const char *str, int direct, const char *name, const char *str,
int style); const char *seq, int direct, int style);
extern int extcommunity_list_set(struct community_list_handler *ch, extern int extcommunity_list_set(struct community_list_handler *ch,
const char *name, const char *str, int direct, const char *name, const char *str,
int style); const char *seq, int direct, int style);
extern int extcommunity_list_unset(struct community_list_handler *ch, extern int extcommunity_list_unset(struct community_list_handler *ch,
const char *name, const char *str, const char *name, const char *str,
int direct, int style); const char *seq, int direct, int style);
extern int lcommunity_list_set(struct community_list_handler *ch, extern int lcommunity_list_set(struct community_list_handler *ch,
const char *name, const char *str, int direct, const char *name, const char *str,
int style); const char *seq, int direct, int style);
extern int lcommunity_list_unset(struct community_list_handler *ch, extern int lcommunity_list_unset(struct community_list_handler *ch,
const char *name, const char *str, int direct, const char *name, const char *str,
int style); const char *seq, int direct, int style);
extern struct community_list_master * extern struct community_list_master *
community_list_master_lookup(struct community_list_handler *, int); community_list_master_lookup(struct community_list_handler *, int);

View File

@ -16706,21 +16706,29 @@ static void community_list_perror(struct vty *vty, int ret)
/*community-list standard */ /*community-list standard */
DEFUN (community_list_standard, DEFUN (community_list_standard,
bgp_community_list_standard_cmd, bgp_community_list_standard_cmd,
"bgp community-list <(1-99)|standard WORD> <deny|permit> AA:NN...", "bgp community-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
BGP_STR BGP_STR
COMMUNITY_LIST_STR COMMUNITY_LIST_STR
"Community list number (standard)\n" "Community list number (standard)\n"
"Add an standard community-list entry\n" "Add an standard community-list entry\n"
"Community list name\n" "Community list name\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify community to reject\n" "Specify community to reject\n"
"Specify community to accept\n" "Specify community to accept\n"
COMMUNITY_VAL_STR) COMMUNITY_VAL_STR)
{ {
char *cl_name_or_number = NULL; char *cl_name_or_number = NULL;
char *seq = NULL;
int direct = 0; int direct = 0;
int style = COMMUNITY_LIST_STANDARD; int style = COMMUNITY_LIST_STANDARD;
int idx = 0; int idx = 0;
argv_find(argv, argc, "(1-4294967295)", &idx);
if (idx)
seq = argv[idx]->arg;
idx = 0;
argv_find(argv, argc, "(1-99)", &idx); argv_find(argv, argc, "(1-99)", &idx);
argv_find(argv, argc, "WORD", &idx); argv_find(argv, argc, "WORD", &idx);
cl_name_or_number = argv[idx]->arg; cl_name_or_number = argv[idx]->arg;
@ -16729,8 +16737,8 @@ DEFUN (community_list_standard,
argv_find(argv, argc, "AA:NN", &idx); argv_find(argv, argc, "AA:NN", &idx);
char *str = argv_concat(argv, argc, idx); char *str = argv_concat(argv, argc, idx);
int ret = community_list_set(bgp_clist, cl_name_or_number, str, direct, int ret = community_list_set(bgp_clist, cl_name_or_number, str, seq,
style); direct, style);
XFREE(MTYPE_TMP, str); XFREE(MTYPE_TMP, str);
@ -16745,13 +16753,15 @@ DEFUN (community_list_standard,
DEFUN (no_community_list_standard_all, DEFUN (no_community_list_standard_all,
no_bgp_community_list_standard_all_cmd, no_bgp_community_list_standard_all_cmd,
"no bgp community-list <(1-99)|standard WORD> <deny|permit> AA:NN...", "no bgp community-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
NO_STR NO_STR
BGP_STR BGP_STR
COMMUNITY_LIST_STR COMMUNITY_LIST_STR
"Community list number (standard)\n" "Community list number (standard)\n"
"Add an standard community-list entry\n" "Add an standard community-list entry\n"
"Community list name\n" "Community list name\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify community to reject\n" "Specify community to reject\n"
"Specify community to accept\n" "Specify community to accept\n"
COMMUNITY_VAL_STR) COMMUNITY_VAL_STR)
@ -16760,9 +16770,14 @@ DEFUN (no_community_list_standard_all,
char *str = NULL; char *str = NULL;
int direct = 0; int direct = 0;
int style = COMMUNITY_LIST_STANDARD; int style = COMMUNITY_LIST_STANDARD;
char *seq = NULL;
int idx = 0; int idx = 0;
argv_find(argv, argc, "(1-4294967295)", &idx);
if (idx)
seq = argv[idx]->arg;
idx = 0;
argv_find(argv, argc, "permit", &idx); argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx); argv_find(argv, argc, "deny", &idx);
@ -16781,7 +16796,7 @@ DEFUN (no_community_list_standard_all,
argv_find(argv, argc, "WORD", &idx); argv_find(argv, argc, "WORD", &idx);
cl_name_or_number = argv[idx]->arg; cl_name_or_number = argv[idx]->arg;
int ret = community_list_unset(bgp_clist, cl_name_or_number, str, int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq,
direct, style); direct, style);
XFREE(MTYPE_TMP, str); XFREE(MTYPE_TMP, str);
@ -16804,22 +16819,30 @@ ALIAS(no_community_list_standard_all, no_bgp_community_list_standard_all_list_cm
/*community-list expanded */ /*community-list expanded */
DEFUN (community_list_expanded_all, DEFUN (community_list_expanded_all,
bgp_community_list_expanded_all_cmd, bgp_community_list_expanded_all_cmd,
"bgp community-list <(100-500)|expanded WORD> <deny|permit> AA:NN...", "bgp community-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
BGP_STR BGP_STR
COMMUNITY_LIST_STR COMMUNITY_LIST_STR
"Community list number (expanded)\n" "Community list number (expanded)\n"
"Add an expanded community-list entry\n" "Add an expanded community-list entry\n"
"Community list name\n" "Community list name\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify community to reject\n" "Specify community to reject\n"
"Specify community to accept\n" "Specify community to accept\n"
COMMUNITY_VAL_STR) COMMUNITY_VAL_STR)
{ {
char *cl_name_or_number = NULL; char *cl_name_or_number = NULL;
char *seq = NULL;
int direct = 0; int direct = 0;
int style = COMMUNITY_LIST_EXPANDED; int style = COMMUNITY_LIST_EXPANDED;
int idx = 0; int idx = 0;
argv_find(argv, argc, "(1-4294967295)", &idx);
if (idx)
seq = argv[idx]->arg;
idx = 0;
argv_find(argv, argc, "(100-500)", &idx); argv_find(argv, argc, "(100-500)", &idx);
argv_find(argv, argc, "WORD", &idx); argv_find(argv, argc, "WORD", &idx);
cl_name_or_number = argv[idx]->arg; cl_name_or_number = argv[idx]->arg;
@ -16828,8 +16851,8 @@ DEFUN (community_list_expanded_all,
argv_find(argv, argc, "AA:NN", &idx); argv_find(argv, argc, "AA:NN", &idx);
char *str = argv_concat(argv, argc, idx); char *str = argv_concat(argv, argc, idx);
int ret = community_list_set(bgp_clist, cl_name_or_number, str, direct, int ret = community_list_set(bgp_clist, cl_name_or_number, str, seq,
style); direct, style);
XFREE(MTYPE_TMP, str); XFREE(MTYPE_TMP, str);
@ -16844,24 +16867,31 @@ DEFUN (community_list_expanded_all,
DEFUN (no_community_list_expanded_all, DEFUN (no_community_list_expanded_all,
no_bgp_community_list_expanded_all_cmd, no_bgp_community_list_expanded_all_cmd,
"no bgp community-list <(100-500)|expanded WORD> <deny|permit> AA:NN...", "no bgp community-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
NO_STR NO_STR
BGP_STR BGP_STR
COMMUNITY_LIST_STR COMMUNITY_LIST_STR
"Community list number (expanded)\n" "Community list number (expanded)\n"
"Add an expanded community-list entry\n" "Add an expanded community-list entry\n"
"Community list name\n" "Community list name\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify community to reject\n" "Specify community to reject\n"
"Specify community to accept\n" "Specify community to accept\n"
COMMUNITY_VAL_STR) COMMUNITY_VAL_STR)
{ {
char *cl_name_or_number = NULL; char *cl_name_or_number = NULL;
char *seq = NULL;
char *str = NULL; char *str = NULL;
int direct = 0; int direct = 0;
int style = COMMUNITY_LIST_EXPANDED; int style = COMMUNITY_LIST_EXPANDED;
int idx = 0; int idx = 0;
argv_find(argv, argc, "(1-4294967295)", &idx);
if (idx)
seq = argv[idx]->arg;
idx = 0;
argv_find(argv, argc, "permit", &idx); argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx); argv_find(argv, argc, "deny", &idx);
@ -16880,7 +16910,7 @@ DEFUN (no_community_list_expanded_all,
argv_find(argv, argc, "WORD", &idx); argv_find(argv, argc, "WORD", &idx);
cl_name_or_number = argv[idx]->arg; cl_name_or_number = argv[idx]->arg;
int ret = community_list_unset(bgp_clist, cl_name_or_number, str, int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq,
direct, style); direct, style);
XFREE(MTYPE_TMP, str); XFREE(MTYPE_TMP, str);
@ -17007,7 +17037,13 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc,
char *str; char *str;
int idx = 0; int idx = 0;
char *cl_name; char *cl_name;
char *seq = NULL;
argv_find(argv, argc, "(1-4294967295)", &idx);
if (idx)
seq = argv[idx]->arg;
idx = 0;
direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
: COMMUNITY_DENY; : COMMUNITY_DENY;
@ -17031,7 +17067,7 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc,
else else
str = NULL; str = NULL;
ret = lcommunity_list_set(bgp_clist, cl_name, str, direct, style); ret = lcommunity_list_set(bgp_clist, cl_name, str, seq, direct, style);
/* Free temporary community list string allocated by /* Free temporary community list string allocated by
argv_concat(). */ argv_concat(). */
@ -17051,7 +17087,13 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc,
int direct = 0; int direct = 0;
char *str = NULL; char *str = NULL;
int idx = 0; int idx = 0;
char *seq = NULL;
argv_find(argv, argc, "(1-4294967295)", &idx);
if (idx)
seq = argv[idx]->arg;
idx = 0;
argv_find(argv, argc, "permit", &idx); argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx); argv_find(argv, argc, "deny", &idx);
@ -17075,7 +17117,7 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc,
argv_find(argv, argc, "WORD", &idx); argv_find(argv, argc, "WORD", &idx);
/* Unset community list. */ /* Unset community list. */
ret = lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, direct, ret = lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, seq, direct,
style); style);
/* Free temporary community list string allocated by /* Free temporary community list string allocated by
@ -17096,10 +17138,12 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc,
DEFUN (lcommunity_list_standard, DEFUN (lcommunity_list_standard,
bgp_lcommunity_list_standard_cmd, bgp_lcommunity_list_standard_cmd,
"bgp large-community-list (1-99) <deny|permit> AA:BB:CC...", "bgp large-community-list (1-99) [seq (1-4294967295)] <deny|permit> AA:BB:CC...",
BGP_STR BGP_STR
LCOMMUNITY_LIST_STR LCOMMUNITY_LIST_STR
"Large Community list number (standard)\n" "Large Community list number (standard)\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify large community to reject\n" "Specify large community to reject\n"
"Specify large community to accept\n" "Specify large community to accept\n"
LCOMMUNITY_VAL_STR) LCOMMUNITY_VAL_STR)
@ -17110,10 +17154,12 @@ DEFUN (lcommunity_list_standard,
DEFUN (lcommunity_list_expanded, DEFUN (lcommunity_list_expanded,
bgp_lcommunity_list_expanded_cmd, bgp_lcommunity_list_expanded_cmd,
"bgp large-community-list (100-500) <deny|permit> LINE...", "bgp large-community-list (100-500) [seq (1-4294967295)] <deny|permit> LINE...",
BGP_STR BGP_STR
LCOMMUNITY_LIST_STR LCOMMUNITY_LIST_STR
"Large Community list number (expanded)\n" "Large Community list number (expanded)\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify large community to reject\n" "Specify large community to reject\n"
"Specify large community to accept\n" "Specify large community to accept\n"
"An ordered list as a regular-expression\n") "An ordered list as a regular-expression\n")
@ -17124,11 +17170,13 @@ DEFUN (lcommunity_list_expanded,
DEFUN (lcommunity_list_name_standard, DEFUN (lcommunity_list_name_standard,
bgp_lcommunity_list_name_standard_cmd, bgp_lcommunity_list_name_standard_cmd,
"bgp large-community-list standard WORD <deny|permit> AA:BB:CC...", "bgp large-community-list standard WORD [seq (1-4294967295)] <deny|permit> AA:BB:CC...",
BGP_STR BGP_STR
LCOMMUNITY_LIST_STR LCOMMUNITY_LIST_STR
"Specify standard large-community-list\n" "Specify standard large-community-list\n"
"Large Community list name\n" "Large Community list name\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify large community to reject\n" "Specify large community to reject\n"
"Specify large community to accept\n" "Specify large community to accept\n"
LCOMMUNITY_VAL_STR) LCOMMUNITY_VAL_STR)
@ -17139,11 +17187,13 @@ DEFUN (lcommunity_list_name_standard,
DEFUN (lcommunity_list_name_expanded, DEFUN (lcommunity_list_name_expanded,
bgp_lcommunity_list_name_expanded_cmd, bgp_lcommunity_list_name_expanded_cmd,
"bgp large-community-list expanded WORD <deny|permit> LINE...", "bgp large-community-list expanded WORD [seq (1-4294967295)] <deny|permit> LINE...",
BGP_STR BGP_STR
LCOMMUNITY_LIST_STR LCOMMUNITY_LIST_STR
"Specify expanded large-community-list\n" "Specify expanded large-community-list\n"
"Large Community list name\n" "Large Community list name\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify large community to reject\n" "Specify large community to reject\n"
"Specify large community to accept\n" "Specify large community to accept\n"
"An ordered list as a regular-expression\n") "An ordered list as a regular-expression\n")
@ -17152,8 +17202,8 @@ DEFUN (lcommunity_list_name_expanded,
LARGE_COMMUNITY_LIST_EXPANDED, 1); LARGE_COMMUNITY_LIST_EXPANDED, 1);
} }
DEFUN (no_lcommunity_list_standard_all, DEFUN (no_lcommunity_list_all,
no_bgp_lcommunity_list_standard_all_cmd, no_bgp_lcommunity_list_all_cmd,
"no bgp large-community-list <(1-99)|(100-500)|WORD>", "no bgp large-community-list <(1-99)|(100-500)|WORD>",
NO_STR NO_STR
BGP_STR BGP_STR
@ -17166,6 +17216,19 @@ DEFUN (no_lcommunity_list_standard_all,
LARGE_COMMUNITY_LIST_STANDARD); LARGE_COMMUNITY_LIST_STANDARD);
} }
DEFUN (no_lcommunity_list_name_standard_all,
no_bgp_lcommunity_list_name_standard_all_cmd,
"no bgp large-community-list standard WORD",
NO_STR
BGP_STR
LCOMMUNITY_LIST_STR
"Specify standard large-community-list\n"
"Large Community list name\n")
{
return lcommunity_list_unset_vty(vty, argc, argv,
LARGE_COMMUNITY_LIST_STANDARD);
}
DEFUN (no_lcommunity_list_name_expanded_all, DEFUN (no_lcommunity_list_name_expanded_all,
no_bgp_lcommunity_list_name_expanded_all_cmd, no_bgp_lcommunity_list_name_expanded_all_cmd,
"no bgp large-community-list expanded WORD", "no bgp large-community-list expanded WORD",
@ -17181,11 +17244,13 @@ DEFUN (no_lcommunity_list_name_expanded_all,
DEFUN (no_lcommunity_list_standard, DEFUN (no_lcommunity_list_standard,
no_bgp_lcommunity_list_standard_cmd, no_bgp_lcommunity_list_standard_cmd,
"no bgp large-community-list (1-99) <deny|permit> AA:AA:NN...", "no bgp large-community-list (1-99) [seq (1-4294967295)] <deny|permit> AA:AA:NN...",
NO_STR NO_STR
BGP_STR BGP_STR
LCOMMUNITY_LIST_STR LCOMMUNITY_LIST_STR
"Large Community list number (standard)\n" "Large Community list number (standard)\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify large community to reject\n" "Specify large community to reject\n"
"Specify large community to accept\n" "Specify large community to accept\n"
LCOMMUNITY_VAL_STR) LCOMMUNITY_VAL_STR)
@ -17196,11 +17261,13 @@ DEFUN (no_lcommunity_list_standard,
DEFUN (no_lcommunity_list_expanded, DEFUN (no_lcommunity_list_expanded,
no_bgp_lcommunity_list_expanded_cmd, no_bgp_lcommunity_list_expanded_cmd,
"no bgp large-community-list (100-500) <deny|permit> LINE...", "no bgp large-community-list (100-500) [seq (1-4294967295)] <deny|permit> LINE...",
NO_STR NO_STR
BGP_STR BGP_STR
LCOMMUNITY_LIST_STR LCOMMUNITY_LIST_STR
"Large Community list number (expanded)\n" "Large Community list number (expanded)\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify large community to reject\n" "Specify large community to reject\n"
"Specify large community to accept\n" "Specify large community to accept\n"
"An ordered list as a regular-expression\n") "An ordered list as a regular-expression\n")
@ -17211,12 +17278,14 @@ DEFUN (no_lcommunity_list_expanded,
DEFUN (no_lcommunity_list_name_standard, DEFUN (no_lcommunity_list_name_standard,
no_bgp_lcommunity_list_name_standard_cmd, no_bgp_lcommunity_list_name_standard_cmd,
"no bgp large-community-list standard WORD <deny|permit> AA:AA:NN...", "no bgp large-community-list standard WORD [seq (1-4294967295)] <deny|permit> AA:AA:NN...",
NO_STR NO_STR
BGP_STR BGP_STR
LCOMMUNITY_LIST_STR LCOMMUNITY_LIST_STR
"Specify standard large-community-list\n" "Specify standard large-community-list\n"
"Large Community list name\n" "Large Community list name\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify large community to reject\n" "Specify large community to reject\n"
"Specify large community to accept\n" "Specify large community to accept\n"
LCOMMUNITY_VAL_STR) LCOMMUNITY_VAL_STR)
@ -17227,12 +17296,14 @@ DEFUN (no_lcommunity_list_name_standard,
DEFUN (no_lcommunity_list_name_expanded, DEFUN (no_lcommunity_list_name_expanded,
no_bgp_lcommunity_list_name_expanded_cmd, no_bgp_lcommunity_list_name_expanded_cmd,
"no bgp large-community-list expanded WORD <deny|permit> LINE...", "no bgp large-community-list expanded WORD [seq (1-4294967295)] <deny|permit> LINE...",
NO_STR NO_STR
BGP_STR BGP_STR
LCOMMUNITY_LIST_STR LCOMMUNITY_LIST_STR
"Specify expanded large-community-list\n" "Specify expanded large-community-list\n"
"Large community list name\n" "Large community list name\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify large community to reject\n" "Specify large community to reject\n"
"Specify large community to accept\n" "Specify large community to accept\n"
"An ordered list as a regular-expression\n") "An ordered list as a regular-expression\n")
@ -17327,12 +17398,14 @@ DEFUN (show_lcommunity_list_arg,
DEFUN (extcommunity_list_standard, DEFUN (extcommunity_list_standard,
bgp_extcommunity_list_standard_cmd, bgp_extcommunity_list_standard_cmd,
"bgp extcommunity-list <(1-99)|standard WORD> <deny|permit> AA:NN...", "bgp extcommunity-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
BGP_STR BGP_STR
EXTCOMMUNITY_LIST_STR EXTCOMMUNITY_LIST_STR
"Extended Community list number (standard)\n" "Extended Community list number (standard)\n"
"Specify standard extcommunity-list\n" "Specify standard extcommunity-list\n"
"Community list name\n" "Community list name\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify community to reject\n" "Specify community to reject\n"
"Specify community to accept\n" "Specify community to accept\n"
EXTCOMMUNITY_VAL_STR) EXTCOMMUNITY_VAL_STR)
@ -17340,18 +17413,24 @@ DEFUN (extcommunity_list_standard,
int style = EXTCOMMUNITY_LIST_STANDARD; int style = EXTCOMMUNITY_LIST_STANDARD;
int direct = 0; int direct = 0;
char *cl_number_or_name = NULL; char *cl_number_or_name = NULL;
char *seq = NULL;
int idx = 0; int idx = 0;
argv_find(argv, argc, "(1-99)", &idx); argv_find(argv, argc, "(1-99)", &idx);
argv_find(argv, argc, "WORD", &idx); argv_find(argv, argc, "WORD", &idx);
cl_number_or_name = argv[idx]->arg; cl_number_or_name = argv[idx]->arg;
argv_find(argv, argc, "(1-4294967295)", &idx);
if (idx)
seq = argv[idx]->arg;
direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
: COMMUNITY_DENY; : COMMUNITY_DENY;
argv_find(argv, argc, "AA:NN", &idx); argv_find(argv, argc, "AA:NN", &idx);
char *str = argv_concat(argv, argc, idx); char *str = argv_concat(argv, argc, idx);
int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str, int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str, seq,
direct, style); direct, style);
XFREE(MTYPE_TMP, str); XFREE(MTYPE_TMP, str);
@ -17366,12 +17445,14 @@ DEFUN (extcommunity_list_standard,
DEFUN (extcommunity_list_name_expanded, DEFUN (extcommunity_list_name_expanded,
bgp_extcommunity_list_name_expanded_cmd, bgp_extcommunity_list_name_expanded_cmd,
"bgp extcommunity-list <(100-500)|expanded WORD> <deny|permit> LINE...", "bgp extcommunity-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> LINE...",
BGP_STR BGP_STR
EXTCOMMUNITY_LIST_STR EXTCOMMUNITY_LIST_STR
"Extended Community list number (expanded)\n" "Extended Community list number (expanded)\n"
"Specify expanded extcommunity-list\n" "Specify expanded extcommunity-list\n"
"Extended Community list name\n" "Extended Community list name\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify community to reject\n" "Specify community to reject\n"
"Specify community to accept\n" "Specify community to accept\n"
"An ordered list as a regular-expression\n") "An ordered list as a regular-expression\n")
@ -17379,17 +17460,23 @@ DEFUN (extcommunity_list_name_expanded,
int style = EXTCOMMUNITY_LIST_EXPANDED; int style = EXTCOMMUNITY_LIST_EXPANDED;
int direct = 0; int direct = 0;
char *cl_number_or_name = NULL; char *cl_number_or_name = NULL;
char *seq = NULL;
int idx = 0; int idx = 0;
argv_find(argv, argc, "(100-500)", &idx); argv_find(argv, argc, "(100-500)", &idx);
argv_find(argv, argc, "WORD", &idx); argv_find(argv, argc, "WORD", &idx);
cl_number_or_name = argv[idx]->arg; cl_number_or_name = argv[idx]->arg;
argv_find(argv, argc, "(1-4294967295)", &idx);
if (idx)
seq = argv[idx]->arg;
direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
: COMMUNITY_DENY; : COMMUNITY_DENY;
argv_find(argv, argc, "LINE", &idx); argv_find(argv, argc, "LINE", &idx);
char *str = argv_concat(argv, argc, idx); char *str = argv_concat(argv, argc, idx);
int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str, int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str, seq,
direct, style); direct, style);
XFREE(MTYPE_TMP, str); XFREE(MTYPE_TMP, str);
@ -17404,13 +17491,15 @@ DEFUN (extcommunity_list_name_expanded,
DEFUN (no_extcommunity_list_standard_all, DEFUN (no_extcommunity_list_standard_all,
no_bgp_extcommunity_list_standard_all_cmd, no_bgp_extcommunity_list_standard_all_cmd,
"no bgp extcommunity-list <(1-99)|standard WORD> <deny|permit> AA:NN...", "no bgp extcommunity-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
NO_STR NO_STR
BGP_STR BGP_STR
EXTCOMMUNITY_LIST_STR EXTCOMMUNITY_LIST_STR
"Extended Community list number (standard)\n" "Extended Community list number (standard)\n"
"Specify standard extcommunity-list\n" "Specify standard extcommunity-list\n"
"Community list name\n" "Community list name\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify community to reject\n" "Specify community to reject\n"
"Specify community to accept\n" "Specify community to accept\n"
EXTCOMMUNITY_VAL_STR) EXTCOMMUNITY_VAL_STR)
@ -17419,11 +17508,16 @@ DEFUN (no_extcommunity_list_standard_all,
int direct = 0; int direct = 0;
char *cl_number_or_name = NULL; char *cl_number_or_name = NULL;
char *str = NULL; char *str = NULL;
char *seq = NULL;
int idx = 0; int idx = 0;
argv_find(argv, argc, "(1-4294967295)", &idx);
if (idx)
seq = argv[idx]->arg;
idx = 0;
argv_find(argv, argc, "permit", &idx); argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx); argv_find(argv, argc, "deny", &idx);
if (idx) { if (idx) {
direct = argv_find(argv, argc, "permit", &idx) direct = argv_find(argv, argc, "permit", &idx)
? COMMUNITY_PERMIT ? COMMUNITY_PERMIT
@ -17440,7 +17534,7 @@ DEFUN (no_extcommunity_list_standard_all,
cl_number_or_name = argv[idx]->arg; cl_number_or_name = argv[idx]->arg;
int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str, int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
direct, style); seq, direct, style);
XFREE(MTYPE_TMP, str); XFREE(MTYPE_TMP, str);
@ -17462,13 +17556,15 @@ ALIAS(no_extcommunity_list_standard_all,
DEFUN (no_extcommunity_list_expanded_all, DEFUN (no_extcommunity_list_expanded_all,
no_bgp_extcommunity_list_expanded_all_cmd, no_bgp_extcommunity_list_expanded_all_cmd,
"no bgp extcommunity-list <(100-500)|expanded WORD> <deny|permit> LINE...", "no bgp extcommunity-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> LINE...",
NO_STR NO_STR
BGP_STR BGP_STR
EXTCOMMUNITY_LIST_STR EXTCOMMUNITY_LIST_STR
"Extended Community list number (expanded)\n" "Extended Community list number (expanded)\n"
"Specify expanded extcommunity-list\n" "Specify expanded extcommunity-list\n"
"Extended Community list name\n" "Extended Community list name\n"
"Sequence number of an entry\n"
"Sequence number\n"
"Specify community to reject\n" "Specify community to reject\n"
"Specify community to accept\n" "Specify community to accept\n"
"An ordered list as a regular-expression\n") "An ordered list as a regular-expression\n")
@ -17477,8 +17573,14 @@ DEFUN (no_extcommunity_list_expanded_all,
int direct = 0; int direct = 0;
char *cl_number_or_name = NULL; char *cl_number_or_name = NULL;
char *str = NULL; char *str = NULL;
char *seq = NULL;
int idx = 0; int idx = 0;
argv_find(argv, argc, "(1-4294967295)", &idx);
if (idx)
seq = argv[idx]->arg;
idx = 0;
argv_find(argv, argc, "permit", &idx); argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx); argv_find(argv, argc, "deny", &idx);
@ -17498,7 +17600,7 @@ DEFUN (no_extcommunity_list_expanded_all,
cl_number_or_name = argv[idx]->arg; cl_number_or_name = argv[idx]->arg;
int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str, int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
direct, style); seq, direct, style);
XFREE(MTYPE_TMP, str); XFREE(MTYPE_TMP, str);
@ -17609,18 +17711,22 @@ static int community_list_config_write(struct vty *vty)
for (list = cm->num.head; list; list = list->next) for (list = cm->num.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next) { for (entry = list->head; entry; entry = entry->next) {
vty_out(vty, "bgp community-list %s %s %s\n", list->name, vty_out(vty,
"bgp community-list %s seq %" PRId64 " %s %s\n",
list->name, entry->seq,
community_direct_str(entry->direct), community_direct_str(entry->direct),
community_list_config_str(entry)); community_list_config_str(entry));
write++; write++;
} }
for (list = cm->str.head; list; list = list->next) for (list = cm->str.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next) { for (entry = list->head; entry; entry = entry->next) {
vty_out(vty, "bgp community-list %s %s %s %s\n", vty_out(vty,
"bgp community-list %s %s seq %" PRId64 " %s %s\n",
entry->style == COMMUNITY_LIST_STANDARD entry->style == COMMUNITY_LIST_STANDARD
? "standard" ? "standard"
: "expanded", : "expanded",
list->name, community_direct_str(entry->direct), list->name, entry->seq,
community_direct_str(entry->direct),
community_list_config_str(entry)); community_list_config_str(entry));
write++; write++;
} }
@ -17630,18 +17736,23 @@ static int community_list_config_write(struct vty *vty)
for (list = cm->num.head; list; list = list->next) for (list = cm->num.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next) { for (entry = list->head; entry; entry = entry->next) {
vty_out(vty, "bgp extcommunity-list %s %s %s\n", vty_out(vty,
list->name, community_direct_str(entry->direct), "bgp extcommunity-list %s seq %" PRId64 " %s %s\n",
list->name, entry->seq,
community_direct_str(entry->direct),
community_list_config_str(entry)); community_list_config_str(entry));
write++; write++;
} }
for (list = cm->str.head; list; list = list->next) for (list = cm->str.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next) { for (entry = list->head; entry; entry = entry->next) {
vty_out(vty, "bgp extcommunity-list %s %s %s %s\n", vty_out(vty,
"bgp extcommunity-list %s %s seq %" PRId64
" %s %s\n",
entry->style == EXTCOMMUNITY_LIST_STANDARD entry->style == EXTCOMMUNITY_LIST_STANDARD
? "standard" ? "standard"
: "expanded", : "expanded",
list->name, community_direct_str(entry->direct), list->name, entry->seq,
community_direct_str(entry->direct),
community_list_config_str(entry)); community_list_config_str(entry));
write++; write++;
} }
@ -17653,18 +17764,24 @@ static int community_list_config_write(struct vty *vty)
for (list = cm->num.head; list; list = list->next) for (list = cm->num.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next) { for (entry = list->head; entry; entry = entry->next) {
vty_out(vty, "bgp large-community-list %s %s %s\n", vty_out(vty,
list->name, community_direct_str(entry->direct), "bgp large-community-list %s seq %" PRId64
" %s %s\n",
list->name, entry->seq,
community_direct_str(entry->direct),
community_list_config_str(entry)); community_list_config_str(entry));
write++; write++;
} }
for (list = cm->str.head; list; list = list->next) for (list = cm->str.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next) { for (entry = list->head; entry; entry = entry->next) {
vty_out(vty, "bgp large-community-list %s %s %s %s\n", vty_out(vty,
"bgp large-community-list %s %s seq %" PRId64
" %s %s\n",
entry->style == LARGE_COMMUNITY_LIST_STANDARD entry->style == LARGE_COMMUNITY_LIST_STANDARD
? "standard" ? "standard"
: "expanded", : "expanded",
list->name, community_direct_str(entry->direct), list->name, entry->seq, community_direct_str(entry->direct),
community_list_config_str(entry)); community_list_config_str(entry));
write++; write++;
} }
@ -17707,7 +17824,9 @@ static void community_list_vty(void)
install_element(CONFIG_NODE, &bgp_lcommunity_list_expanded_cmd); install_element(CONFIG_NODE, &bgp_lcommunity_list_expanded_cmd);
install_element(CONFIG_NODE, &bgp_lcommunity_list_name_standard_cmd); install_element(CONFIG_NODE, &bgp_lcommunity_list_name_standard_cmd);
install_element(CONFIG_NODE, &bgp_lcommunity_list_name_expanded_cmd); install_element(CONFIG_NODE, &bgp_lcommunity_list_name_expanded_cmd);
install_element(CONFIG_NODE, &no_bgp_lcommunity_list_standard_all_cmd); install_element(CONFIG_NODE, &no_bgp_lcommunity_list_all_cmd);
install_element(CONFIG_NODE,
&no_bgp_lcommunity_list_name_standard_all_cmd);
install_element(CONFIG_NODE, install_element(CONFIG_NODE,
&no_bgp_lcommunity_list_name_expanded_all_cmd); &no_bgp_lcommunity_list_name_expanded_all_cmd);
install_element(CONFIG_NODE, &no_bgp_lcommunity_list_standard_cmd); install_element(CONFIG_NODE, &no_bgp_lcommunity_list_standard_cmd);