GRTAGS
GPATH
compile_commands.json
+.ccls-cache
.dirstamp
refix
/* Set configuration on peer. */
filter = &peer->filter[afi][safi];
- if (filter->map[direct].name)
+ if (filter->map[direct].name) {
+ /* If the neighbor is configured with the same route-map
+ * again then, ignore the duplicate configuration.
+ */
+ if (strcmp(filter->map[direct].name, name) == 0)
+ return 0;
+
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
+ }
route_map_counter_decrement(filter->map[direct].map);
filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->map[direct].map = route_map;
.. code-block:: c
+ #include <typesafe.h>
+
PREDECL_XXX(Z)
struct item {
int otherdata;
The following iteration macros work across all data structures:
-.. c:function:: for_each(Z, head, item)
+.. c:function:: for_each(Z, &head, item)
Equivalent to:
.. code-block:: c
- for (item = Z_first(head); item; item = Z_next(head, item))
+ for (item = Z_first(&head); item; item = Z_next(&head, item))
Note that this will fail if the list is modified while being iterated
over.
-.. c:function:: for_each_safe(Z, head, item)
+.. c:function:: for_each_safe(Z, &head, item)
Same as the previous, but the next element is pre-loaded into a "hidden"
variable (named ``Z_safe``.) Equivalent to:
.. code-block:: c
- for (item = Z_first(head); item; item = next) {
- next = Z_next_safe(head, item);
+ for (item = Z_first(&head); item; item = next) {
+ next = Z_next_safe(&head, item);
...
}
tables is resized while iterating. This will cause items to be
skipped or iterated over twice.
-.. c:function:: for_each_from(Z, head, item, from)
+.. c:function:: for_each_from(Z, &head, item, from)
Iterates over the list, starting at item ``from``. This variant is "safe"
as in the previous macro. Equivalent to:
.. code-block:: c
for (item = from; item; item = from) {
- from = Z_next_safe(head, item);
+ from = Z_next_safe(&head, item);
...
}
Write current configuration to configuration file.
-.. index:: configure terminal
-.. clicmd:: configure terminal
+.. index:: configure [terminal]
+.. clicmd:: configure [terminal]
Change to configuration mode. This command is the first step to
configuration.
.. index:: [no] neighbor PEER maximum-prefix NUMBER
.. clicmd:: [no] neighbor PEER maximum-prefix NUMBER
-.. index:: [no] neighbor PEER local-as AS-NUMBER no-prepend
-.. clicmd:: [no] neighbor PEER local-as AS-NUMBER no-prepend
-
-.. index:: [no] neighbor PEER local-as AS-NUMBER no-prepend replace-as
-.. clicmd:: [no] neighbor PEER local-as AS-NUMBER no-prepend replace-as
-
-.. index:: [no] neighbor PEER local-as AS-NUMBER
-.. clicmd:: [no] neighbor PEER local-as AS-NUMBER
+ Sets a maximum number of prefixes we can receive from a given peer. If this
+ number is exceeded, the BGP session will be destroyed.
+
+ In practice, it is generally preferable to use a prefix-list to limit what
+ prefixes are received from the peer instead of using this knob. Tearing down
+ the BGP session when a limit is exceeded is far more destructive than merely
+ rejecting undesired prefixes. The prefix-list method is also much more
+ granular and offers much smarter matching criterion than number of received
+ prefixes, making it more suited to implementing policy.
+
+.. index:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as]
+.. clicmd:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as]
Specify an alternate AS for this BGP process when interacting with the
specified peer. With no modifiers, the specified local-as is prepended to
.. code-block:: frr
# case with VRF
- configure terminal
+ configure
vrf r1-cust1
ip route 10.0.0.0/24 10.0.0.2
exit-vrf
/* Configuration from terminal */
DEFUN (config_terminal,
config_terminal_cmd,
- "configure terminal",
+ "configure [terminal]",
"Configuration from vty interface\n"
"Configuration terminal\n")
{
return ptr;
}
-unsigned prefix_hash_key(void *pp)
+unsigned prefix_hash_key(const void *pp)
{
struct prefix copy;
extern int prefix_str2mac(const char *str, struct ethaddr *mac);
extern char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size);
-extern unsigned prefix_hash_key(void *pp);
+extern unsigned prefix_hash_key(const void *pp);
extern int str_to_esi(const char *str, esi_t *esi);
extern char *esi_to_str(const esi_t *esi, char *buf, int size);
for (rule = index->match_list.head; rule; rule = next) {
next = rule->next;
if (rule->cmd == cmd) {
+ /* If the configured route-map match rule is exactly
+ * the same as the existing configuration then,
+ * ignore the duplicate configuration.
+ */
+ if (strcmp(match_arg, rule->rule_str) == 0) {
+ if (cmd->func_free)
+ (*cmd->func_free)(compile);
+ return RMAP_COMPILE_SUCCESS;
+ }
+
route_map_rule_delete(&index->match_list, rule);
replaced = 1;
}
assert(index);
+ /* If "call" is invoked with the same route-map name as
+ * the one previously configured then, ignore the duplicate
+ * configuration.
+ */
+ if (index->nextrm && (strcmp(index->nextrm, rmap) == 0))
+ return CMD_SUCCESS;
+
if (index->nextrm) {
route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
index->nextrm, index->map->name);
static void route_table_free(struct route_table *);
-static bool route_table_hash_cmp(const void *a, const void *b)
+static int route_table_hash_cmp(const void *a, const void *b)
{
const struct prefix *pa = a, *pb = b;
- return prefix_cmp(pa, pb) == 0;
+ return prefix_cmp(pa, pb);
}
+DECLARE_HASH(rn_hash_node, struct route_node, nodehash, route_table_hash_cmp,
+ prefix_hash_key)
/*
* route_table_init_with_delegate
*/
rt = XCALLOC(MTYPE_ROUTE_TABLE, sizeof(struct route_table));
rt->delegate = delegate;
- rt->hash = hash_create(prefix_hash_key, route_table_hash_cmp,
- "route table hash");
+ rn_hash_node_init(&rt->hash);
return rt;
}
static struct route_node *route_node_set(struct route_table *table,
const struct prefix *prefix)
{
- struct route_node *node, *inserted;
+ struct route_node *node;
node = route_node_new(table);
prefix_copy(&node->p, prefix);
node->table = table;
- inserted = hash_get(node->table->hash, node, hash_alloc_intern);
- assert(inserted == node);
+ rn_hash_node_add(&node->table->hash, node);
return node;
}
if (rt == NULL)
return;
- hash_clean(rt->hash, NULL);
- hash_free(rt->hash);
-
node = rt->top;
/* Bulk deletion of nodes remaining in this table. This function is not
tmp_node->table->count--;
tmp_node->lock = 0; /* to cause assert if unlocked after this */
+ rn_hash_node_del(&rt->hash, tmp_node);
route_node_free(rt, tmp_node);
if (node != NULL) {
assert(rt->count == 0);
+ rn_hash_node_fini(&rt->hash);
XFREE(MTYPE_ROUTE_TABLE, rt);
return;
}
prefix_copy(&p, pu.p);
apply_mask(&p);
- node = hash_get(table->hash, (void *)&p, NULL);
+ node = rn_hash_node_find(&table->hash, (void *)&p);
return (node && node->info) ? route_lock_node(node) : NULL;
}
prefix_copy(&p, pu.p);
apply_mask(&p);
- node = hash_get(table->hash, (void *)&p, NULL);
+ node = rn_hash_node_find(&table->hash, (void *)&p);
return node ? route_lock_node(node) : NULL;
}
struct route_node *new;
struct route_node *node;
struct route_node *match;
- struct route_node *inserted;
uint16_t prefixlen = p->prefixlen;
const uint8_t *prefix = &p->u.prefix;
apply_mask((struct prefix *)p);
- node = hash_get(table->hash, (void *)p, NULL);
+ node = rn_hash_node_find(&table->hash, (void *)p);
if (node && node->info)
return route_lock_node(node);
new->p.family = p->family;
new->table = table;
set_link(new, node);
- inserted = hash_get(node->table->hash, new, hash_alloc_intern);
- assert(inserted == new);
+ rn_hash_node_add(&table->hash, new);
if (match)
set_link(match, new);
node->table->count--;
- hash_release(node->table->hash, node);
+ rn_hash_node_del(&node->table->hash, node);
/* WARNING: FRAGILE CODE!
* route_node_free may have the side effect of free'ing the entire
#include "memory.h"
#include "hash.h"
#include "prefix.h"
+#include "typesafe.h"
#ifdef __cplusplus
extern "C" {
route_table_destroy_node_func_t destroy_node;
};
+PREDECL_HASH(rn_hash_node)
+
/* Routing table top structure. */
struct route_table {
struct route_node *top;
- struct hash *hash;
+ struct rn_hash_node_head hash;
/*
* Delegate that performs certain functions for this table.
/* Lock of this radix */ \
unsigned int table_rdonly(lock); \
\
+ struct rn_hash_node_item nodehash; \
/* Each node of route. */ \
void *info; \
#define DECLARE_SORTLIST_UNIQ(prefix, type, field, cmpfn) \
_DECLARE_SORTLIST(prefix, type, field, cmpfn, cmpfn) \
\
-macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
+macro_inline type *prefix ## _find(const struct prefix##_head *h, const type *item) \
{ \
struct ssort_item *sitem = h->sh.first; \
int cmpval = 0; \
*np = &item->field.hi; \
return NULL; \
} \
-macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
+macro_inline type *prefix ## _find(const struct prefix##_head *h, const type *item) \
{ \
if (!h->hh.tabshift) \
return NULL; \
return cmpfn(container_of(a, type, field.si), \
container_of(b, type, field.si)); \
} \
-macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
+macro_inline type *prefix ## _find(const struct prefix##_head *h, const type *item) \
{ \
struct sskip_item *sitem = typesafe_skiplist_find(&h->sh, \
&item->field.si, &prefix ## __cmp); \
"kat expired on %s[%s]; remove stream reference",
up->sg_str, pim->vrf->name);
PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
- up = pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
- } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
+
+ /* Return if upstream entry got deleted.*/
+ if (!pim_upstream_del(pim, up, __PRETTY_FUNCTION__))
+ return NULL;
+ }
+ /* upstream reference would have been added to track the local
+ * membership if it is LHR. We have to clear it when KAT expires.
+ * Otherwise would result in stale entry with uncleared ref count.
+ */
+ if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
struct pim_upstream *parent = up->parent;
PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
"Please, only use 32 bit atomics.\n" . $herecurr);
}
+# check for use of strcpy()
+ if ($line =~ /\bstrcpy\s*\(.*\)/) {
+ ERROR("STRCPY",
+ "strcpy() is error-prone; please use strlcpy()" . $herecurr);
+ }
+
+# check for use of strncpy()
+ if ($line =~ /\bstrncpy\s*\(.*\)/) {
+ WARN("STRNCPY",
+ "strncpy() is error-prone; please use strlcpy() if possible, or memcpy()" . $herecurr);
+ }
+
+# check for use of strcat()
+ if ($line =~ /\bstrcat\s*\(.*\)/) {
+ ERROR("STRCAT",
+ "strcat() is error-prone; please use strlcat() if possible" . $herecurr);
+ }
+
+# check for use of strncat()
+ if ($line =~ /\bstrncat\s*\(.*\)/) {
+ WARN("STRNCAT",
+ "strncat() is error-prone; please use strlcat() if possible" . $herecurr);
+ }
+
+# check for use of bzero()
+ if ($line =~ /\bbzero\s*\(.*\)/) {
+ ERROR("BZERO",
+ "bzero() is deprecated; use memset()" . $herecurr);
+ }
}
# If we have no input at all, then there is nothing to report on
vtysh_execute("exit");
} else if (tried) {
vtysh_execute("end");
- vtysh_execute("configure terminal");
+ vtysh_execute("configure");
}
}
/*
if (pager && strncmp(line, "exit", 4))
vty_open_pager(vty);
- if (!strcmp(cmd->string, "configure terminal")) {
+ if (!strcmp(cmd->string, "configure")) {
for (i = 0; i < array_size(vtysh_client); i++) {
cmd_stat = vtysh_client_execute(
&vtysh_client[i], line);
vty->node = CONFIG_NODE;
vtysh_execute_no_pager("enable");
- vtysh_execute_no_pager("configure terminal");
+ vtysh_execute_no_pager("configure");
vty_buf_copy = XCALLOC(MTYPE_VTYSH_CMD, VTY_BUFSIZ);
while (fgets(vty->buf, VTY_BUFSIZ, confp)) {
}
DEFUNSH(VTYSH_REALLYALL, vtysh_config_terminal, vtysh_config_terminal_cmd,
- "configure terminal",
+ "configure [terminal]",
"Configuration from vty interface\n"
"Configuration terminal\n")
{
case BFD_NODE:
case RPKI_NODE:
vtysh_execute("end");
- vtysh_execute("configure terminal");
+ vtysh_execute("configure");
vty->node = CONFIG_NODE;
break;
case BGP_VPNV4_NODE:
#include "zebra.h"
#include "hook.h"
+#include "typesafe.h"
#include "linklist.h"
#include "prefix.h"
#include "table.h"
extern "C" {
#endif
+typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t;
+
+PREDECL_LIST(rnh_list)
+
+/* Nexthop structure. */
+struct rnh {
+ uint8_t flags;
+
+#define ZEBRA_NHT_CONNECTED 0x1
+#define ZEBRA_NHT_DELETED 0x2
+#define ZEBRA_NHT_EXACT_MATCH 0x4
+
+ /* VRF identifier. */
+ vrf_id_t vrf_id;
+
+ afi_t afi;
+
+ rnh_type_t type;
+
+ uint32_t seqno;
+
+ struct route_entry *state;
+ struct prefix resolved_route;
+ struct list *client_list;
+
+ /* pseudowires dependent on this nh */
+ struct list *zebra_pseudowire_list;
+
+ struct route_node *node;
+
+ /*
+ * if this has been filtered for the client
+ */
+ int filtered[ZEBRA_ROUTE_MAX];
+
+ struct rnh_list_item rnh_list_item;
+};
+
#define DISTANCE_INFINITY 255
#define ZEBRA_KERNEL_TABLE_MAX 252 /* support for no more than this rt tables */
+PREDECL_LIST(re_list)
+
struct route_entry {
/* Link list. */
- struct route_entry *next;
- struct route_entry *prev;
+ struct re_list_item next;
/* Nexthop structure */
struct nexthop_group ng;
/*
* Doubly-linked list of routes for this prefix.
*/
- struct route_entry *routes;
+ struct re_list_head routes;
struct route_entry *selected_fib;
* the data plane we will run evaluate_rnh
* on these prefixes.
*/
- struct list *nht;
+ struct rnh_list_head nht;
/*
* Linkage to put dest on the FPM processing queue.
} rib_dest_t;
+DECLARE_LIST(rnh_list, struct rnh, rnh_list_item);
+DECLARE_LIST(re_list, struct route_entry, next);
+
#define RIB_ROUTE_QUEUED(x) (1 << (x))
// If MQ_SIZE is modified this value needs to be updated.
#define RIB_ROUTE_ANY_QUEUED 0x1F
* Macro to iterate over each route for a destination (prefix).
*/
#define RE_DEST_FOREACH_ROUTE(dest, re) \
- for ((re) = (dest) ? (dest)->routes : NULL; (re); (re) = (re)->next)
+ for ((re) = (dest) ? re_list_first(&((dest)->routes)) : NULL; (re); \
+ (re) = re_list_next(&((dest)->routes), (re)))
/*
* Same as above, but allows the current node to be unlinked.
*/
#define RE_DEST_FOREACH_ROUTE_SAFE(dest, re, next) \
- for ((re) = (dest) ? (dest)->routes : NULL; \
- (re) && ((next) = (re)->next, 1); (re) = (next))
+ for ((re) = (dest) ? re_list_first(&((dest)->routes)) : NULL; \
+ (re) && ((next) = re_list_next(&((dest)->routes), (re)), 1); \
+ (re) = (next))
#define RNODE_FOREACH_RE(rn, re) \
RE_DEST_FOREACH_ROUTE (rib_dest_from_rnode(rn), re)
if (!dest)
return NULL;
- return dest->routes;
+ return re_list_first(&dest->routes);
}
/*
*/
static int rib_can_delete_dest(rib_dest_t *dest)
{
- if (dest->routes) {
+ if (re_list_first(&dest->routes)) {
return 0;
}
void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq)
{
rib_dest_t *dest = rib_dest_from_rnode(rn);
- struct listnode *node, *nnode;
struct rnh *rnh;
/*
* nht resolution and as such we need to call the
* nexthop tracking evaluation code
*/
- for (ALL_LIST_ELEMENTS(dest->nht, node, nnode, rnh)) {
+ for_each (rnh_list, &dest->nht, rnh) {
struct zebra_vrf *zvrf =
zebra_vrf_lookup_by_id(rnh->vrf_id);
struct prefix *p = &rnh->node->p;
zebra_rib_evaluate_rn_nexthops(rn, zebra_router_get_next_sequence());
dest->rnode = NULL;
- list_delete(&dest->nht);
+ rnh_list_fini(&dest->nht);
XFREE(MTYPE_RIB_DEST, dest);
rn->info = NULL;
rib_dest_t *dest;
dest = XCALLOC(MTYPE_RIB_DEST, sizeof(rib_dest_t));
- dest->nht = list_new();
+ rnh_list_init(&dest->nht);
route_lock_node(rn); /* rn route table reference */
rn->info = dest;
dest->rnode = rn;
/* Add RE to head of the route node. */
static void rib_link(struct route_node *rn, struct route_entry *re, int process)
{
- struct route_entry *head;
rib_dest_t *dest;
afi_t afi;
const char *rmap_name;
dest = zebra_rib_create_dest(rn);
}
- head = dest->routes;
- if (head) {
- head->prev = re;
- }
- re->next = head;
- dest->routes = re;
+ re_list_add_head(&dest->routes, re);
afi = (rn->p.family == AF_INET)
? AFI_IP
dest = rib_dest_from_rnode(rn);
- if (re->next)
- re->next->prev = re->prev;
-
- if (re->prev)
- re->prev->next = re->next;
- else {
- dest->routes = re->next;
- }
+ re_list_del(&dest->routes, re);
if (dest->selected_fib == re)
dest->selected_fib = NULL;
}
dest = rib_dest_from_rnode(rn);
- listnode_delete(dest->nht, rnh);
+ rnh_list_del(&dest->nht, rnh);
route_unlock_node(rn);
}
}
dest = rib_dest_from_rnode(rn);
- listnode_add(dest->nht, rnh);
+ rnh_list_add_tail(&dest->nht, rnh);
route_unlock_node(rn);
}
route_unlock_node(rern);
dest = rib_dest_from_rnode(rern);
- listnode_delete(dest->nht, rnh);
+ rnh_list_del(&dest->nht, rnh);
}
}
free_state(rnh->vrf_id, rnh->state, rnh->node);
extern "C" {
#endif
-typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t;
-
-/* Nexthop structure. */
-struct rnh {
- uint8_t flags;
-
-#define ZEBRA_NHT_CONNECTED 0x1
-#define ZEBRA_NHT_DELETED 0x2
-#define ZEBRA_NHT_EXACT_MATCH 0x4
-
- /* VRF identifier. */
- vrf_id_t vrf_id;
-
- afi_t afi;
-
- rnh_type_t type;
-
- uint32_t seqno;
-
- struct route_entry *state;
- struct prefix resolved_route;
- struct list *client_list;
-
- /* pseudowires dependent on this nh */
- struct list *zebra_pseudowire_list;
-
- struct route_node *node;
-
- /*
- * if this has been filtered for the client
- */
- int filtered[ZEBRA_ROUTE_MAX];
-};
-
extern int zebra_rnh_ip_default_route;
extern int zebra_rnh_ipv6_default_route;
if (node->info) {
rib_dest_t *dest = node->info;
- list_delete(&dest->nht);
+ rnh_list_fini(&dest->nht);
XFREE(MTYPE_RIB_DEST, node->info);
}
}