GRTAGS
GPATH
compile_commands.json
+.ccls-cache
.dirstamp
refix
+.vscode
# end
AM_CPPFLAGS = \
-I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/lib \
- -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/lib
+ -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/lib \
+ $(LUA_INCLUDE) \
+ # end
AM_LDFLAGS = \
-export-dynamic \
$(AC_LDFLAGS) \
* If the interface or VRF doesn't exist, then we must register
* the session but delay its start.
*/
- if (bs->key.ifname[0]) {
- ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
- if (ifp == NULL) {
- log_error(
- "session-enable: specified interface doesn't exists.");
- return 0;
- }
-
- vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (bs->key.vrfname[0]) {
+ vrf = vrf_lookup_by_name(bs->key.vrfname);
if (vrf == NULL) {
log_error(
"session-enable: specified VRF doesn't exists.");
}
}
- if (bs->key.vrfname[0]) {
- vrf = vrf_lookup_by_name(bs->key.vrfname);
- if (vrf == NULL) {
+ if (bs->key.ifname[0]) {
+ if (vrf)
+ ifp = if_lookup_by_name(bs->key.ifname, vrf->vrf_id);
+ else
+ ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
+ if (ifp == NULL) {
log_error(
- "session-enable: specified VRF doesn't exists.");
+ "session-enable: specified interface doesn't exists.");
return 0;
}
+ if (bs->key.ifname[0] && !vrf) {
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (vrf == NULL) {
+ log_error(
+ "session-enable: specified VRF doesn't exists.");
+ return 0;
+ }
+ }
}
/* Assign interface/VRF pointers. */
/* Sanity check: don't leak open sockets. */
if (bs->sock != -1) {
- zlog_debug("session-enable: previous socket open");
+ log_debug("session-enable: previous socket open");
close(bs->sock);
bs->sock = -1;
}
ptm_bfd_echo_xmt_TO(bfd);
}
-void ptm_bfd_ses_up(struct bfd_session *bfd)
+void ptm_bfd_sess_up(struct bfd_session *bfd)
{
int old_state = bfd->ses_state;
}
}
-void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag)
+void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)
{
int old_state = bfd->ses_state;
switch (bs->ses_state) {
case PTM_BFD_INIT:
case PTM_BFD_UP:
- ptm_bfd_ses_dn(bs, BD_CONTROL_EXPIRED);
+ ptm_bfd_sess_dn(bs, BD_CONTROL_EXPIRED);
bfd_recvtimer_update(bs);
break;
switch (bs->ses_state) {
case PTM_BFD_INIT:
case PTM_BFD_UP:
- ptm_bfd_ses_dn(bs, BD_ECHO_FAILED);
+ ptm_bfd_sess_dn(bs, BD_ECHO_FAILED);
break;
}
return bfd;
}
-int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc)
+int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc)
{
struct bfd_session *bs;
* Remote peer told us his path is up, lets turn
* activate the session.
*/
- ptm_bfd_ses_up(bs);
+ ptm_bfd_sess_up(bs);
break;
default:
case PTM_BFD_INIT:
case PTM_BFD_UP:
/* We agreed on the settings and the path is up. */
- ptm_bfd_ses_up(bs);
+ ptm_bfd_sess_up(bs);
break;
default:
case PTM_BFD_ADM_DOWN:
case PTM_BFD_DOWN:
/* Peer lost or asked to shutdown connection. */
- ptm_bfd_ses_dn(bs, BD_NEIGHBOR_DOWN);
+ ptm_bfd_sess_dn(bs, BD_NEIGHBOR_DOWN);
break;
case PTM_BFD_INIT:
if (bso->bso_isinterface)
strlcpy(bso->bso_entryname, bs->key.ifname,
sizeof(bso->bso_entryname));
- else
- strlcpy(bso->bso_entryname, bs->key.vrfname,
- sizeof(bso->bso_entryname));
-
/* Handle socket binding failures caused by missing local addresses. */
if (bs->sock == -1) {
bso->bso_isaddress = true;
static struct hash *bfd_id_hash;
static struct hash *bfd_key_hash;
-static unsigned int bfd_id_hash_do(void *p);
-static unsigned int bfd_key_hash_do(void *p);
+static unsigned int bfd_id_hash_do(const void *p);
+static unsigned int bfd_key_hash_do(const void *p);
static void _bfd_free(struct hash_bucket *hb,
void *arg __attribute__((__unused__)));
/* BFD hash for our discriminator. */
-static unsigned int bfd_id_hash_do(void *p)
+static unsigned int bfd_id_hash_do(const void *p)
{
- struct bfd_session *bs = p;
+ const struct bfd_session *bs = p;
return jhash_1word(bs->discrs.my_discr, 0);
}
}
/* BFD hash for single hop. */
-static unsigned int bfd_key_hash_do(void *p)
+static unsigned int bfd_key_hash_do(const void *p)
{
- struct bfd_session *bs = p;
+ const struct bfd_session *bs = p;
return jhash(&bs->key, sizeof(bs->key), 0);
}
return hash_lookup(bfd_id_hash, &bs);
}
+struct bfd_key_walk_partial_lookup {
+ struct bfd_session *given;
+ struct bfd_session *result;
+};
+
+/* ignore some parameters */
+static int bfd_key_lookup_ignore_partial_walker(struct hash_bucket *b, void *data)
+{
+ struct bfd_key_walk_partial_lookup *ctx =
+ (struct bfd_key_walk_partial_lookup *)data;
+ struct bfd_session *given = ctx->given;
+ struct bfd_session *parsed = b->data;
+
+ if (given->key.family != parsed->key.family)
+ return HASHWALK_CONTINUE;
+ if (given->key.mhop != parsed->key.mhop)
+ return HASHWALK_CONTINUE;
+ if (memcmp(&given->key.peer, &parsed->key.peer, sizeof(struct in6_addr)))
+ return HASHWALK_CONTINUE;
+ if (memcmp(given->key.vrfname, parsed->key.vrfname, MAXNAMELEN))
+ return HASHWALK_CONTINUE;
+ ctx->result = parsed;
+ /* ignore localaddr or interface */
+ return HASHWALK_ABORT;
+}
+
struct bfd_session *bfd_key_lookup(struct bfd_key key)
{
struct bfd_session bs, *bsp;
+ struct bfd_key_walk_partial_lookup ctx;
+ char peer_buf[INET6_ADDRSTRLEN];
bs.key = key;
bsp = hash_lookup(bfd_key_hash, &bs);
+ if (bsp)
+ return bsp;
+ inet_ntop(bs.key.family, &bs.key.peer, peer_buf,
+ sizeof(peer_buf));
/* Handle cases where local-address is optional. */
- if (bsp == NULL && bs.key.family == AF_INET) {
+ if (bs.key.family == AF_INET) {
memset(&bs.key.local, 0, sizeof(bs.key.local));
bsp = hash_lookup(bfd_key_hash, &bs);
+ if (bsp) {
+ char addr_buf[INET6_ADDRSTRLEN];
+
+ inet_ntop(bs.key.family, &key.local, addr_buf,
+ sizeof(addr_buf));
+ log_debug(" peer %s found, but loc-addr %s ignored",
+ peer_buf, addr_buf);
+ return bsp;
+ }
}
- /* Handle cases where ifname is optional. */
bs.key = key;
- if (bsp == NULL && bs.key.ifname[0]) {
+ /* Handle cases where ifname is optional. */
+ if (bs.key.ifname[0]) {
memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
bsp = hash_lookup(bfd_key_hash, &bs);
+ if (bsp) {
+ log_debug(" peer %s found, but ifp %s ignored",
+ peer_buf, key.ifname);
+ return bsp;
+ }
+ }
- /* Handle cases where local-address and ifname are optional. */
- if (bsp == NULL && bs.key.family == AF_INET) {
- memset(&bs.key.local, 0, sizeof(bs.key.local));
- bsp = hash_lookup(bfd_key_hash, &bs);
+ /* Handle cases where local-address and ifname are optional. */
+ if (bs.key.family == AF_INET) {
+ memset(&bs.key.local, 0, sizeof(bs.key.local));
+ bsp = hash_lookup(bfd_key_hash, &bs);
+ if (bsp) {
+ char addr_buf[INET6_ADDRSTRLEN];
+
+ inet_ntop(bs.key.family, &bs.key.local, addr_buf,
+ sizeof(addr_buf));
+ log_debug(" peer %s found, but ifp %s"
+ " and loc-addr %s ignored",
+ peer_buf, key.ifname,
+ addr_buf);
+ return bsp;
}
}
+ bs.key = key;
+ /* Handle case where a context more complex ctx is present.
+ * input has no iface nor local-address, but a context may
+ * exist
+ */
+ ctx.result = NULL;
+ ctx.given = &bs;
+ hash_walk(bfd_key_hash,
+ &bfd_key_lookup_ignore_partial_walker,
+ &ctx);
+ /* change key */
+ if (ctx.result) {
+ bsp = ctx.result;
+ log_debug(" peer %s found, but ifp"
+ " and/or loc-addr params ignored");
+ }
return bsp;
}
hash_free(bfd_id_hash);
hash_free(bfd_key_hash);
}
+
+static int bfd_vrf_new(struct vrf *vrf)
+{
+ log_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
+ return 0;
+}
+
+static int bfd_vrf_delete(struct vrf *vrf)
+{
+ log_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id);
+ return 0;
+}
+
+static int bfd_vrf_enable(struct vrf *vrf)
+{
+ struct bfd_vrf_global *bvrf;
+
+ /* a different name */
+ if (!vrf->info) {
+ bvrf = XCALLOC(MTYPE_BFDD_VRF, sizeof(struct bfd_vrf_global));
+ bvrf->vrf = vrf;
+ vrf->info = (void *)bvrf;
+ } else
+ bvrf = vrf->info;
+ log_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id);
+
+ /* create sockets if needed */
+ if (!bvrf->bg_shop)
+ bvrf->bg_shop = bp_udp_shop(vrf->vrf_id);
+ if (!bvrf->bg_mhop)
+ bvrf->bg_mhop = bp_udp_mhop(vrf->vrf_id);
+ if (!bvrf->bg_shop6)
+ bvrf->bg_shop6 = bp_udp6_shop(vrf->vrf_id);
+ if (!bvrf->bg_mhop6)
+ bvrf->bg_mhop6 = bp_udp6_mhop(vrf->vrf_id);
+ if (!bvrf->bg_echo)
+ bvrf->bg_echo = bp_echo_socket(vrf->vrf_id);
+ if (!bvrf->bg_echov6)
+ bvrf->bg_echov6 = bp_echov6_socket(vrf->vrf_id);
+
+ /* Add descriptors to the event loop. */
+ if (!bvrf->bg_ev[0])
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop,
+ &bvrf->bg_ev[0]);
+ if (!bvrf->bg_ev[1])
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop,
+ &bvrf->bg_ev[1]);
+ if (!bvrf->bg_ev[2])
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6,
+ &bvrf->bg_ev[2]);
+ if (!bvrf->bg_ev[3])
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6,
+ &bvrf->bg_ev[3]);
+ if (!bvrf->bg_ev[4])
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo,
+ &bvrf->bg_ev[4]);
+ if (!bvrf->bg_ev[5])
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6,
+ &bvrf->bg_ev[5]);
+
+ if (vrf->vrf_id != VRF_DEFAULT) {
+ bfdd_zclient_register(vrf->vrf_id);
+ bfdd_sessions_enable_vrf(vrf);
+ }
+ return 0;
+}
+
+static int bfd_vrf_disable(struct vrf *vrf)
+{
+ struct bfd_vrf_global *bvrf;
+
+ if (!vrf->info)
+ return 0;
+ bvrf = vrf->info;
+
+ if (vrf->vrf_id != VRF_DEFAULT) {
+ bfdd_sessions_disable_vrf(vrf);
+ bfdd_zclient_unregister(vrf->vrf_id);
+ }
+
+ log_debug("VRF disable %s id %d", vrf->name, vrf->vrf_id);
+ /* Close all descriptors. */
+ socket_close(&bvrf->bg_echo);
+ socket_close(&bvrf->bg_shop);
+ socket_close(&bvrf->bg_mhop);
+ socket_close(&bvrf->bg_shop6);
+ socket_close(&bvrf->bg_mhop6);
+
+ /* free context */
+ XFREE(MTYPE_BFDD_VRF, bvrf);
+ vrf->info = NULL;
+
+ return 0;
+}
+
+void bfd_vrf_init(void)
+{
+ vrf_init(bfd_vrf_new, bfd_vrf_enable, bfd_vrf_disable,
+ bfd_vrf_delete, NULL);
+}
+
+void bfd_vrf_terminate(void)
+{
+ vrf_terminate();
+}
+
+struct bfd_vrf_global *bfd_vrf_look_by_session(struct bfd_session *bfd)
+{
+ struct vrf *vrf;
+
+ if (!vrf_is_backend_netns()) {
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ if (vrf)
+ return (struct bfd_vrf_global *)vrf->info;
+ return NULL;
+ }
+ if (!bfd)
+ return NULL;
+ if (!bfd->vrf)
+ return NULL;
+ return bfd->vrf->info;
+}
DECLARE_MTYPE(BFDD_CONTROL);
DECLARE_MTYPE(BFDD_SESSION_OBSERVER);
DECLARE_MTYPE(BFDD_NOTIFICATION);
+DECLARE_MTYPE(BFDD_VRF);
struct bfd_timers {
uint32_t desired_min_tx;
*
* Daemon specific code.
*/
-struct bfd_global {
+struct bfd_vrf_global {
int bg_shop;
int bg_mhop;
int bg_shop6;
int bg_mhop6;
int bg_echo;
int bg_echov6;
+ struct vrf *vrf;
+
struct thread *bg_ev[6];
+};
+struct bfd_global {
int bg_csock;
struct thread *bg_csockev;
struct bcslist bg_bcslist;
struct pllist bg_pllist;
struct obslist bg_obslist;
+
+ struct zebra_privs_t bfdd_privs;
};
extern struct bfd_global bglobal;
extern struct bfd_diag_str_list diag_list[];
int bp_set_tos(int sd, uint8_t value);
int bp_bind_dev(int sd, const char *dev);
-int bp_udp_shop(void);
-int bp_udp_mhop(void);
-int bp_udp6_shop(void);
-int bp_udp6_mhop(void);
+int bp_udp_shop(vrf_id_t vrf_id);
+int bp_udp_mhop(vrf_id_t vrf_id);
+int bp_udp6_shop(vrf_id_t vrf_id);
+int bp_udp6_mhop(vrf_id_t vrf_id);
int bp_peer_socket(const struct bfd_session *bs);
int bp_peer_socketv6(const struct bfd_session *bs);
-int bp_echo_socket(void);
-int bp_echov6_socket(void);
+int bp_echo_socket(vrf_id_t vrf_id);
+int bp_echov6_socket(vrf_id_t vrf_id);
void ptm_bfd_snd(struct bfd_session *bfd, int fbit);
void ptm_bfd_echo_snd(struct bfd_session *bfd);
int bfd_session_enable(struct bfd_session *bs);
void bfd_session_disable(struct bfd_session *bs);
struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc);
-int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc);
-void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag);
-void ptm_bfd_ses_up(struct bfd_session *bfd);
+int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc);
+void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag);
+void ptm_bfd_sess_up(struct bfd_session *bfd);
void ptm_bfd_echo_stop(struct bfd_session *bfd);
void ptm_bfd_echo_start(struct bfd_session *bfd);
void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit);
/* BFD hash data structures interface */
void bfd_initialize(void);
void bfd_shutdown(void);
+void bfd_vrf_init(void);
+void bfd_vrf_terminate(void);
+struct bfd_vrf_global *bfd_vrf_look_by_session(struct bfd_session *bfd);
struct bfd_session *bfd_id_lookup(uint32_t id);
struct bfd_session *bfd_key_lookup(struct bfd_key key);
*/
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv);
void bfdd_zclient_stop(void);
+void bfdd_zclient_unregister(vrf_id_t vrf_id);
+void bfdd_zclient_register(vrf_id_t vrf_id);
+void bfdd_sessions_enable_vrf(struct vrf *vrf);
+void bfdd_sessions_disable_vrf(struct vrf *vrf);
int ptm_bfd_notify(struct bfd_session *bs);
#include "bfd.h"
-
/*
* Prototypes
*/
-static int ptm_bfd_process_echo_pkt(int s);
+static int ptm_bfd_process_echo_pkt(struct bfd_vrf_global *bvrf, int s);
int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
size_t datalen);
-static void bfd_sd_reschedule(int sd);
+static void bfd_sd_reschedule(struct bfd_vrf_global *bvrf, int sd);
ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
ifindex_t *ifindex, struct sockaddr_any *local,
struct sockaddr_any *peer);
struct sockaddr_any *peer);
int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen,
struct sockaddr *to, socklen_t tolen);
-int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr);
+int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
+ uint8_t *ttl, uint32_t *my_discr);
/* socket related prototypes */
static void bp_set_ipopts(int sd);
struct bfd_echo_pkt bep;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
+ struct bfd_vrf_global *bvrf = bfd_vrf_look_by_session(bfd);
+ if (!bvrf)
+ return;
if (!BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE);
bep.my_discr = htonl(bfd->discrs.my_discr);
if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
- sd = bglobal.bg_echov6;
+ sd = bvrf->bg_echov6;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
memcpy(&sin6.sin6_addr, &bfd->key.peer, sizeof(sin6.sin6_addr));
sa = (struct sockaddr *)&sin6;
salen = sizeof(sin6);
} else {
- sd = bglobal.bg_echo;
+ sd = bvrf->bg_echo;
memset(&sin6, 0, sizeof(sin6));
sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, &bfd->key.peer, sizeof(sin.sin_addr));
bfd->stats.tx_echo_pkt++;
}
-static int ptm_bfd_process_echo_pkt(int s)
+static int ptm_bfd_process_echo_pkt(struct bfd_vrf_global *bvrf, int s)
{
struct bfd_session *bfd;
uint32_t my_discr = 0;
uint8_t ttl = 0;
/* Receive and parse echo packet. */
- if (bp_bfd_echo_in(s, &ttl, &my_discr) == -1)
+ if (bp_bfd_echo_in(bvrf, s, &ttl, &my_discr) == -1)
return 0;
/* Your discriminator not zero - use it to find session */
return mlen;
}
-static void bfd_sd_reschedule(int sd)
+static void bfd_sd_reschedule(struct bfd_vrf_global *bvrf, int sd)
{
- if (sd == bglobal.bg_shop) {
- THREAD_OFF(bglobal.bg_ev[0]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop,
- &bglobal.bg_ev[0]);
- } else if (sd == bglobal.bg_mhop) {
- THREAD_OFF(bglobal.bg_ev[1]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop,
- &bglobal.bg_ev[1]);
- } else if (sd == bglobal.bg_shop6) {
- THREAD_OFF(bglobal.bg_ev[2]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop6,
- &bglobal.bg_ev[2]);
- } else if (sd == bglobal.bg_mhop6) {
- THREAD_OFF(bglobal.bg_ev[3]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop6,
- &bglobal.bg_ev[3]);
- } else if (sd == bglobal.bg_echo) {
- THREAD_OFF(bglobal.bg_ev[4]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echo,
- &bglobal.bg_ev[4]);
- } else if (sd == bglobal.bg_echov6) {
- THREAD_OFF(bglobal.bg_ev[5]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echov6,
- &bglobal.bg_ev[5]);
+ if (sd == bvrf->bg_shop) {
+ THREAD_OFF(bvrf->bg_ev[0]);
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop,
+ &bvrf->bg_ev[0]);
+ } else if (sd == bvrf->bg_mhop) {
+ THREAD_OFF(bvrf->bg_ev[1]);
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop,
+ &bvrf->bg_ev[1]);
+ } else if (sd == bvrf->bg_shop6) {
+ THREAD_OFF(bvrf->bg_ev[2]);
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6,
+ &bvrf->bg_ev[2]);
+ } else if (sd == bvrf->bg_mhop6) {
+ THREAD_OFF(bvrf->bg_ev[3]);
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6,
+ &bvrf->bg_ev[3]);
+ } else if (sd == bvrf->bg_echo) {
+ THREAD_OFF(bvrf->bg_ev[4]);
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo,
+ &bvrf->bg_ev[4]);
+ } else if (sd == bvrf->bg_echov6) {
+ THREAD_OFF(bvrf->bg_ev[5]);
+ thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6,
+ &bvrf->bg_ev[5]);
}
}
ifindex_t ifindex = IFINDEX_INTERNAL;
struct sockaddr_any local, peer;
uint8_t msgbuf[1516];
+ struct bfd_vrf_global *bvrf = THREAD_ARG(t);
+ if (bvrf)
+ vrfid = bvrf->vrf->vrf_id;
/* Schedule next read. */
- bfd_sd_reschedule(sd);
+ bfd_sd_reschedule(bvrf, sd);
/* Handle echo packets. */
- if (sd == bglobal.bg_echo || sd == bglobal.bg_echov6) {
- ptm_bfd_process_echo_pkt(sd);
+ if (sd == bvrf->bg_echo || sd == bvrf->bg_echov6) {
+ ptm_bfd_process_echo_pkt(bvrf, sd);
return 0;
}
/* Handle control packets. */
is_mhop = false;
- if (sd == bglobal.bg_shop || sd == bglobal.bg_mhop) {
- is_mhop = sd == bglobal.bg_mhop;
+ if (sd == bvrf->bg_shop || sd == bvrf->bg_mhop) {
+ is_mhop = sd == bvrf->bg_mhop;
mlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), &ttl, &ifindex,
&local, &peer);
- } else if (sd == bglobal.bg_shop6 || sd == bglobal.bg_mhop6) {
- is_mhop = sd == bglobal.bg_mhop6;
+ } else if (sd == bvrf->bg_shop6 || sd == bvrf->bg_mhop6) {
+ is_mhop = sd == bvrf->bg_mhop6;
mlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), &ttl, &ifindex,
&local, &peer);
}
*
* Returns -1 on error or loopback or 0 on success.
*/
-int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr)
+int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd,
+ uint8_t *ttl, uint32_t *my_discr)
{
struct bfd_echo_pkt *bep;
ssize_t rlen;
vrf_id_t vrfid = VRF_DEFAULT;
uint8_t msgbuf[1516];
- if (sd == bglobal.bg_echo)
+ if (sd == bvrf->bg_echo)
rlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), ttl, &ifindex,
&local, &peer);
else
if (*ttl == BFD_TTL_VAL) {
bp_udp_send(sd, *ttl - 1, msgbuf, rlen,
(struct sockaddr *)&peer,
- (sd == bglobal.bg_echo) ? sizeof(peer.sa_sin)
+ (sd == bvrf->bg_echo) ? sizeof(peer.sa_sin)
: sizeof(peer.sa_sin6));
return -1;
}
log_fatal("bind-ip: bind: %s", strerror(errno));
}
-int bp_udp_shop(void)
+int bp_udp_shop(vrf_id_t vrf_id)
{
int sd;
- sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
+ }
if (sd == -1)
log_fatal("udp-shop: socket: %s", strerror(errno));
bp_set_ipopts(sd);
bp_bind_ip(sd, BFD_DEFDESTPORT);
-
return sd;
}
-int bp_udp_mhop(void)
+int bp_udp_mhop(vrf_id_t vrf_id)
{
int sd;
- sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
+ }
if (sd == -1)
log_fatal("udp-mhop: socket: %s", strerror(errno));
int sd, pcount;
struct sockaddr_in sin;
static int srcPort = BFD_SRCPORTINIT;
+ const char *device_to_bind = NULL;
+
+ if (bs->key.ifname[0])
+ device_to_bind = (const char *)bs->key.ifname;
+ else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
+ && bs->key.vrfname[0])
+ device_to_bind = (const char *)bs->key.vrfname;
- sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC,
+ bs->vrf->vrf_id, device_to_bind);
+ }
if (sd == -1) {
log_error("ipv4-new: failed to create socket: %s",
strerror(errno));
return -1;
}
- if (bs->key.ifname[0]) {
- if (bp_bind_dev(sd, bs->key.ifname) != 0) {
- close(sd);
- return -1;
- }
- } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
- && bs->key.vrfname[0]) {
- if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
- close(sd);
- return -1;
- }
- }
-
/* Find an available source port in the proper range */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
int sd, pcount;
struct sockaddr_in6 sin6;
static int srcPort = BFD_SRCPORTINIT;
+ const char *device_to_bind = NULL;
- sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
+ if (bs->key.ifname[0])
+ device_to_bind = (const char *)bs->key.ifname;
+ else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
+ && bs->key.vrfname[0])
+ device_to_bind = (const char *)bs->key.vrfname;
+
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC,
+ bs->vrf->vrf_id, device_to_bind);
+ }
if (sd == -1) {
log_error("ipv6-new: failed to create socket: %s",
strerror(errno));
if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
sin6.sin6_scope_id = bs->ifp->ifindex;
- if (bs->key.ifname[0]) {
- if (bp_bind_dev(sd, bs->key.ifname) != 0) {
- close(sd);
- return -1;
- }
- } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
- && bs->key.vrfname[0]) {
- if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
- close(sd);
- return -1;
- }
- }
-
pcount = 0;
do {
if ((++pcount) > (BFD_SRCPORTMAX - BFD_SRCPORTINIT)) {
log_fatal("bind-ipv6: bind: %s", strerror(errno));
}
-int bp_udp6_shop(void)
+int bp_udp6_shop(vrf_id_t vrf_id)
{
int sd;
- sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
+ }
if (sd == -1)
log_fatal("udp6-shop: socket: %s", strerror(errno));
return sd;
}
-int bp_udp6_mhop(void)
+int bp_udp6_mhop(vrf_id_t vrf_id)
{
int sd;
- sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
+ }
if (sd == -1)
log_fatal("udp6-mhop: socket: %s", strerror(errno));
return sd;
}
-int bp_echo_socket(void)
+int bp_echo_socket(vrf_id_t vrf_id)
{
int s;
- s = socket(AF_INET, SOCK_DGRAM, 0);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ s = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
+ }
if (s == -1)
log_fatal("echo-socket: socket: %s", strerror(errno));
return s;
}
-int bp_echov6_socket(void)
+int bp_echov6_socket(vrf_id_t vrf_id)
{
int s;
- s = socket(AF_INET6, SOCK_DGRAM, 0);
+ frr_elevate_privs(&bglobal.bfdd_privs) {
+ s = vrf_socket(AF_INET6, SOCK_DGRAM, 0, vrf_id, NULL);
+ }
if (s == -1)
log_fatal("echov6-socket: socket: %s", strerror(errno));
DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory");
DEFINE_MTYPE(BFDD, BFDD_SESSION_OBSERVER, "Session observer");
DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data");
+DEFINE_MTYPE(BFDD, BFDD_VRF, "BFD VRF");
/* Master of threads. */
struct thread_master *master;
/* BFDd privileges */
-static zebra_capabilities_t _caps_p[] = {ZCAP_BIND};
-
-struct zebra_privs_t bfdd_privs = {
-#if defined(FRR_USER) && defined(FRR_GROUP)
- .user = FRR_USER,
- .group = FRR_GROUP,
-#endif
-#if defined(VTY_GROUP)
- .vty_group = VTY_GROUP,
-#endif
- .caps_p = _caps_p,
- .cap_num_p = array_size(_caps_p),
- .cap_num_i = 0,
-};
+static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_SYS_ADMIN, ZCAP_NET_RAW};
void socket_close(int *s)
{
/* Shutdown and free all protocol related memory. */
bfd_shutdown();
- /* Close all descriptors. */
- socket_close(&bglobal.bg_echo);
- socket_close(&bglobal.bg_shop);
- socket_close(&bglobal.bg_mhop);
- socket_close(&bglobal.bg_shop6);
- socket_close(&bglobal.bg_mhop6);
+ bfd_vrf_terminate();
/* Terminate and free() FRR related memory. */
frr_fini();
FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617,
.proghelp = "Implementation of the BFD protocol.",
.signals = bfd_signals, .n_signals = array_size(bfd_signals),
- .privs = &bfdd_privs)
+ .privs = &bglobal.bfdd_privs)
#define OPTION_CTLSOCK 1001
static struct option longopts[] = {
static void bg_init(void)
{
+ struct zebra_privs_t bfdd_privs = {
+#if defined(FRR_USER) && defined(FRR_GROUP)
+ .user = FRR_USER,
+ .group = FRR_GROUP,
+#endif
+#if defined(VTY_GROUP)
+ .vty_group = VTY_GROUP,
+#endif
+ .caps_p = _caps_p,
+ .cap_num_p = array_size(_caps_p),
+ .cap_num_i = 0,
+ };
+
TAILQ_INIT(&bglobal.bg_bcslist);
TAILQ_INIT(&bglobal.bg_obslist);
- bglobal.bg_shop = bp_udp_shop();
- bglobal.bg_mhop = bp_udp_mhop();
- bglobal.bg_shop6 = bp_udp6_shop();
- bglobal.bg_mhop6 = bp_udp6_mhop();
- bglobal.bg_echo = bp_echo_socket();
- bglobal.bg_echov6 = bp_echov6_socket();
+ memcpy(&bglobal.bfdd_privs, &bfdd_privs,
+ sizeof(bfdd_privs));
}
int main(int argc, char *argv[])
const char *ctl_path = BFDD_CONTROL_SOCKET;
int opt;
+ /* Initialize system sockets. */
+ bg_init();
+
frr_preinit(&bfdd_di, argc, argv);
frr_opt_add("", longopts,
" --bfdctl Specify bfdd control socket\n");
/* Initialize logging API. */
log_init(1, BLOG_DEBUG, &bfdd_di);
- /* Initialize system sockets. */
- bg_init();
-
/* Initialize control socket. */
control_init(ctl_path);
/* Initialize BFD data structures. */
bfd_initialize();
+ bfd_vrf_init();
+
/* Initialize zebra connection. */
- bfdd_zclient_init(&bfdd_privs);
-
- /* Add descriptors to the event loop. */
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop,
- &bglobal.bg_ev[0]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop,
- &bglobal.bg_ev[1]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop6,
- &bglobal.bg_ev[2]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop6,
- &bglobal.bg_ev[3]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echo,
- &bglobal.bg_ev[4]);
- thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echov6,
- &bglobal.bg_ev[5]);
+ bfdd_zclient_init(&bglobal.bfdd_privs);
+
thread_add_read(master, control_accept, NULL, bglobal.bg_csock,
&bglobal.bg_csockev);
static struct json_object *_peer_json_header(struct bfd_session *bs);
static void _display_peer_json(struct vty *vty, struct bfd_session *bs);
static void _display_peer(struct vty *vty, struct bfd_session *bs);
-static void _display_all_peers(struct vty *vty, bool use_json);
+static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json);
static void _display_peer_iter(struct hash_bucket *hb, void *arg);
static void _display_peer_json_iter(struct hash_bucket *hb, void *arg);
static void _display_peer_counter(struct vty *vty, struct bfd_session *bs);
static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs);
static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg);
static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg);
-static void _display_peers_counter(struct vty *vty, bool use_json);
+static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json);
static struct bfd_session *
_find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
const char *label, const char *peer_str,
DEFUN_NOSH(
bfd_peer_enter, bfd_peer_enter_cmd,
- "peer <A.B.C.D|X:X::X:X> [{[multihop] local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]",
+ "peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]",
PEER_STR PEER_IPV4_STR PEER_IPV6_STR
MHOP_STR
LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
if (argv_find(argv, argc, "vrf", &idx))
vrfname = argv[idx + 1]->arg;
- if (vrfname && ifname) {
- vty_out(vty, "%% VRF is not mixable with interface\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- if (vrfname && !mhop) {
- vty_out(vty, "%% VRF only applies with multihop.\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
strtosa(peer, &psa);
if (local) {
strtosa(local, &lsa);
return CMD_WARNING_CONFIG_FAILED;
}
- if (ptm_bfd_ses_del(&bpc) != 0) {
+ if (ptm_bfd_sess_del(&bpc) != 0) {
vty_out(vty, "%% Failed to remove peer.\n");
return CMD_WARNING_CONFIG_FAILED;
}
json_object_free(jo);
}
+struct bfd_vrf_tuple {
+ char *vrfname;
+ struct vty *vty;
+ struct json_object *jo;
+};
+
static void _display_peer_iter(struct hash_bucket *hb, void *arg)
{
- struct vty *vty = arg;
+ struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg;
+ struct vty *vty;
struct bfd_session *bs = hb->data;
+ if (!bvt)
+ return;
+ vty = bvt->vty;
+
+ if (bvt->vrfname) {
+ if (!bs->key.vrfname[0] ||
+ !strmatch(bs->key.vrfname, bvt->vrfname))
+ return;
+ }
_display_peer(vty, bs);
}
static void _display_peer_json_iter(struct hash_bucket *hb, void *arg)
{
- struct json_object *jo = arg, *jon = NULL;
+ struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg;
+ struct json_object *jo, *jon = NULL;
struct bfd_session *bs = hb->data;
+ if (!bvt)
+ return;
+ jo = bvt->jo;
+
+ if (bvt->vrfname) {
+ if (!bs->key.vrfname[0] ||
+ !strmatch(bs->key.vrfname, bvt->vrfname))
+ return;
+ }
+
jon = __display_peer_json(bs);
if (jon == NULL) {
log_warning("%s: not enough memory", __func__);
json_object_array_add(jo, jon);
}
-static void _display_all_peers(struct vty *vty, bool use_json)
+static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json)
{
struct json_object *jo;
+ struct bfd_vrf_tuple bvt;
+
+ memset(&bvt, 0, sizeof(bvt));
+ bvt.vrfname = vrfname;
if (!use_json) {
+ bvt.vty = vty;
vty_out(vty, "BFD Peers:\n");
- bfd_id_iterate(_display_peer_iter, vty);
+ bfd_id_iterate(_display_peer_iter, &bvt);
return;
}
jo = json_object_new_array();
- bfd_id_iterate(_display_peer_json_iter, jo);
+ bvt.jo = jo;
+ bfd_id_iterate(_display_peer_json_iter, &bvt);
vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
json_object_free(jo);
static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg)
{
- struct vty *vty = arg;
+ struct bfd_vrf_tuple *bvt = arg;
+ struct vty *vty;
struct bfd_session *bs = hb->data;
+ if (!bvt)
+ return;
+ vty = bvt->vty;
+
+ if (bvt->vrfname) {
+ if (!bs->key.vrfname[0] ||
+ !strmatch(bs->key.vrfname, bvt->vrfname))
+ return;
+ }
+
_display_peer_counter(vty, bs);
}
static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg)
{
- struct json_object *jo = arg, *jon = NULL;
+ struct json_object *jo, *jon = NULL;
struct bfd_session *bs = hb->data;
+ struct bfd_vrf_tuple *bvt = arg;
+
+ if (!bvt)
+ return;
+ jo = bvt->jo;
+
+ if (bvt->vrfname) {
+ if (!bs->key.vrfname[0] ||
+ !strmatch(bs->key.vrfname, bvt->vrfname))
+ return;
+ }
jon = __display_peer_counters_json(bs);
if (jon == NULL) {
json_object_array_add(jo, jon);
}
-static void _display_peers_counter(struct vty *vty, bool use_json)
+static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json)
{
struct json_object *jo;
+ struct bfd_vrf_tuple bvt;
+ memset(&bvt, 0, sizeof(struct bfd_vrf_tuple));
+ bvt.vrfname = vrfname;
if (!use_json) {
+ bvt.vty = vty;
vty_out(vty, "BFD Peers:\n");
- bfd_id_iterate(_display_peer_counter_iter, vty);
+ bfd_id_iterate(_display_peer_counter_iter, &bvt);
return;
}
jo = json_object_new_array();
+ bvt.jo = jo;
bfd_id_iterate(_display_peer_counter_json_iter, jo);
vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
/*
* Show commands.
*/
-DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd peers [json]",
+DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf <NAME>] peers [json]",
SHOW_STR
"Bidirection Forwarding Detection\n"
+ VRF_CMD_HELP_STR
"BFD peers status\n" JSON_STR)
{
- _display_all_peers(vty, use_json(argc, argv));
+ char *vrf_name = NULL;
+ int idx_vrf = 0;
+
+ if (argv_find(argv, argc, "vrf", &idx_vrf))
+ vrf_name = argv[idx_vrf + 1]->arg;
+
+ _display_all_peers(vty, vrf_name, use_json(argc, argv));
return CMD_SUCCESS;
}
DEFPY(bfd_show_peer, bfd_show_peer_cmd,
- "show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]",
+ "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]",
SHOW_STR
"Bidirection Forwarding Detection\n"
+ VRF_CMD_HELP_STR
"BFD peers status\n"
"Peer label\n" PEER_IPV4_STR PEER_IPV6_STR MHOP_STR LOCAL_STR
- LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR VRF_STR
- VRF_NAME_STR JSON_STR)
+ LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR JSON_STR)
{
struct bfd_session *bs;
}
DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd,
- "show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> counters [json]",
+ "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters [json]",
SHOW_STR
"Bidirection Forwarding Detection\n"
+ VRF_CMD_HELP_STR
"BFD peers status\n"
"Peer label\n"
PEER_IPV4_STR
LOCAL_IPV6_STR
INTERFACE_STR
LOCAL_INTF_STR
- VRF_STR
- VRF_NAME_STR
"Show BFD peer counters information\n"
JSON_STR)
{
}
DEFPY(bfd_show_peers_counters, bfd_show_peers_counters_cmd,
- "show bfd peers counters [json]",
+ "show bfd [vrf <NAME>] peers counters [json]",
SHOW_STR
"Bidirection Forwarding Detection\n"
+ VRF_CMD_HELP_STR
"BFD peers status\n"
"Show BFD peer counters information\n"
JSON_STR)
{
- _display_peers_counter(vty, use_json(argc, argv));
+ char *vrf_name = NULL;
+ int idx_vrf = 0;
+
+ if (argv_find(argv, argc, "vrf", &idx_vrf))
+ vrf_name = argv[idx_vrf + 1]->arg;
+
+ _display_peers_counter(vty, vrf_name, use_json(argc, argv));
return CMD_SUCCESS;
}
+++ /dev/null
-/*
- * *BSD specific code
- *
- * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <zebra.h>
-
-#ifdef BFD_BSD
-
-#include <net/if.h>
-#include <net/if_types.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <ifaddrs.h>
-
-#include "bfd.h"
-
-/*
- * Definitions.
- */
-int bp_bind_dev(int sd, const char *dev)
-{
- /*
- * *BSDs don't support `SO_BINDTODEVICE`, instead you must
- * manually specify the main address of the interface or use
- * BPF on the socket descriptor.
- */
- return 0;
-}
-
-#endif /* BFD_BSD */
static int config_del(struct bfd_peer_cfg *bpc,
void *arg __attribute__((unused)))
{
- return ptm_bfd_ses_del(bpc) != 0;
+ return ptm_bfd_sess_del(bpc) != 0;
}
static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg)
+++ /dev/null
-/*
- * Linux specific code
- *
- * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <zebra.h>
-
-#ifdef BFD_LINUX
-
-#include "bfd.h"
-
-
-/*
- * Definitions.
- */
-int bp_bind_dev(int sd __attribute__((__unused__)),
- const char *dev __attribute__((__unused__)))
-{
- /*
- * TODO: implement this differently. It is not possible to
- * SO_BINDTODEVICE after the daemon has dropped its privileges.
- */
-#if 0
- size_t devlen = strlen(dev) + 1;
-
- if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, dev, devlen) == -1) {
- log_warning("%s: setsockopt(SO_BINDTODEVICE, \"%s\"): %s",
- __func__, dev, strerror(errno));
- return -1;
- }
-#endif
-
- return 0;
-}
-
-#endif /* BFD_LINUX */
static int _ptm_msg_address(struct stream *msg, int family, const void *addr);
static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
-static int _ptm_msg_read(struct stream *msg, int command,
+static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
struct bfd_peer_cfg *bpc, struct ptm_client **pc);
static struct ptm_client *pc_lookup(uint32_t pid);
static void pcn_free(struct ptm_client_notification *pcn);
-static void bfdd_dest_register(struct stream *msg);
-static void bfdd_dest_deregister(struct stream *msg);
+static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id);
+static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id);
static void bfdd_client_register(struct stream *msg);
static void bfdd_client_deregister(struct stream *msg);
stream_reset(msg);
/* TODO: VRF handling */
- zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
+ if (bs->vrf)
+ zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, bs->vrf->vrf_id);
+ else
+ zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
/* This header will be handled by `zebra_ptm.c`. */
stream_putl(msg, ZEBRA_INTERFACE_BFD_DEST_UPDATE);
memset(sa, 0, sizeof(*sa));
}
-static int _ptm_msg_read(struct stream *msg, int command,
+static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
struct bfd_peer_cfg *bpc, struct ptm_client **pc)
{
uint32_t pid;
bpc->bpc_localif[ifnamelen] = 0;
}
}
+ if (vrf_id != VRF_DEFAULT) {
+ struct vrf *vrf;
+
+ vrf = vrf_lookup_by_id(vrf_id);
+ if (vrf) {
+ bpc->bpc_has_vrfname = true;
+ strlcpy(bpc->bpc_vrfname, vrf->name, sizeof(bpc->bpc_vrfname));
+ } else {
+ log_error("ptm-read: vrf id %u could not be identified", vrf_id);
+ return -1;
+ }
+ }
/* Sanity check: peer and local address must match IP types. */
if (bpc->bpc_local.sa_sin.sin_family != 0
return -1;
}
-static void bfdd_dest_register(struct stream *msg)
+static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id)
{
struct ptm_client *pc;
struct ptm_client_notification *pcn;
struct bfd_peer_cfg bpc;
/* Read the client context and peer data. */
- if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, &bpc, &pc) == -1)
+ if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, vrf_id, &bpc, &pc) == -1)
return;
DEBUG_PRINTBPC(&bpc);
ptm_bfd_notify(bs);
}
-static void bfdd_dest_deregister(struct stream *msg)
+static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id)
{
struct ptm_client *pc;
struct ptm_client_notification *pcn;
struct bfd_peer_cfg bpc;
/* Read the client context and peer data. */
- if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, &bpc, &pc) == -1)
+ if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, vrf_id, &bpc, &pc) == -1)
return;
DEBUG_PRINTBPC(&bpc);
if (bs->refcount ||
BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG))
return;
- ptm_bfd_ses_del(&bpc);
+ ptm_bfd_sess_del(&bpc);
}
/*
switch (rcmd) {
case ZEBRA_BFD_DEST_REGISTER:
case ZEBRA_BFD_DEST_UPDATE:
- bfdd_dest_register(msg);
+ bfdd_dest_register(msg, vrf_id);
break;
case ZEBRA_BFD_DEST_DEREGISTER:
- bfdd_dest_deregister(msg);
+ bfdd_dest_deregister(msg, vrf_id);
break;
case ZEBRA_BFD_CLIENT_REGISTER:
bfdd_client_register(msg);
{
struct bfd_session_observer *bso;
struct bfd_session *bs;
+ struct vrf *vrf;
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+ bs = bso->bso_bs;
if (bso->bso_isinterface == false)
continue;
-
/* Interface name mismatch. */
- bs = bso->bso_bs;
if (strcmp(ifp->name, bs->key.ifname))
continue;
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (!vrf)
+ continue;
+ if (bs->key.vrfname[0] &&
+ strcmp(vrf->name, bs->key.vrfname))
+ continue;
/* Skip enabled sessions. */
if (bs->sock != -1)
continue;
/* Try to enable it. */
bfd_session_disable(bs);
- TAILQ_INSERT_HEAD(&bglobal.bg_obslist, bso, bso_entry);
+ }
+}
+
+void bfdd_sessions_enable_vrf(struct vrf *vrf)
+{
+ struct bfd_session_observer *bso;
+ struct bfd_session *bs;
+
+ /* it may affect configs without interfaces */
+ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+ bs = bso->bso_bs;
+ if (bs->vrf)
+ continue;
+ if (bs->key.vrfname[0] &&
+ strcmp(vrf->name, bs->key.vrfname))
+ continue;
+ /* need to update the vrf information on
+ * bs so that callbacks are handled
+ */
+ bs->vrf = vrf;
+ /* Skip enabled sessions. */
+ if (bs->sock != -1)
+ continue;
+ /* Try to enable it. */
+ bfd_session_enable(bs);
+ }
+}
+
+void bfdd_sessions_disable_vrf(struct vrf *vrf)
+{
+ struct bfd_session_observer *bso;
+ struct bfd_session *bs;
+
+ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+ if (bso->bso_isinterface)
+ continue;
+ bs = bso->bso_bs;
+ if (bs->key.vrfname[0] &&
+ strcmp(vrf->name, bs->key.vrfname))
+ continue;
+ /* Skip disabled sessions. */
+ if (bs->sock == -1)
+ continue;
+
+ /* Try to enable it. */
+ bfd_session_disable(bs);
}
}
zclient->interface_address_delete = bfdd_interface_address_update;
}
+void bfdd_zclient_register(vrf_id_t vrf_id)
+{
+ if (!zclient || zclient->sock < 0)
+ return;
+ zclient_send_reg_requests(zclient, vrf_id);
+}
+
+void bfdd_zclient_unregister(vrf_id_t vrf_id)
+{
+ if (!zclient || zclient->sock < 0)
+ return;
+ zclient_send_dereg_requests(zclient, vrf_id);
+}
+
void bfdd_zclient_stop(void)
{
zclient_stop(zclient);
bfdd/bfd.c \
bfdd/bfdd_vty.c \
bfdd/bfd_packet.c \
- bfdd/bsd.c \
bfdd/config.c \
bfdd/control.c \
bfdd/event.c \
- bfdd/linux.c \
bfdd/log.c \
bfdd/ptm_adapter.c \
# end
return baa;
}
-unsigned int baa_hash_key(void *p)
+unsigned int baa_hash_key(const void *p)
{
- struct bgp_advertise_attr *baa = (struct bgp_advertise_attr *)p;
+ const struct bgp_advertise_attr *baa = p;
return attrhash_key_make(baa->attr);
}
extern void bgp_sync_init(struct peer *);
extern void bgp_sync_delete(struct peer *);
-extern unsigned int baa_hash_key(void *p);
+extern unsigned int baa_hash_key(const void *p);
extern bool baa_hash_cmp(const void *p1, const void *p2);
extern void bgp_advertise_add(struct bgp_advertise_attr *baa,
struct bgp_advertise *adv);
}
/* Make hash value by raw aspath data. */
-unsigned int aspath_key_make(void *p)
+unsigned int aspath_key_make(const void *p)
{
- struct aspath *aspath = (struct aspath *)p;
+ const struct aspath *aspath = p;
unsigned int key = 0;
if (!aspath->str)
- aspath_str_update(aspath, false);
+ aspath_str_update((struct aspath *)aspath, false);
key = jhash(aspath->str, aspath->str_len, 2334325);
extern void aspath_print_vty(struct vty *, const char *, struct aspath *,
const char *);
extern void aspath_print_all_vty(struct vty *);
-extern unsigned int aspath_key_make(void *);
+extern unsigned int aspath_key_make(const void *);
extern unsigned int aspath_get_first_as(struct aspath *);
extern unsigned int aspath_get_last_as(struct aspath *);
extern int aspath_loop_check(struct aspath *, as_t);
#include "bgp_encap_types.h"
#include "bgp_vnc_types.h"
#endif
-#include "bgp_encap_types.h"
#include "bgp_evpn.h"
#include "bgp_flowspec_private.h"
#include "bgp_mac.h"
return 0;
}
-static unsigned int cluster_hash_key_make(void *p)
+static unsigned int cluster_hash_key_make(const void *p)
{
const struct cluster_list *cluster = p;
}
}
-static unsigned int encap_hash_key_make(void *p)
+static unsigned int encap_hash_key_make(const void *p)
{
const struct bgp_attr_encap_subtlv *encap = p;
}
}
-static unsigned int transit_hash_key_make(void *p)
+static unsigned int transit_hash_key_make(const void *p)
{
const struct transit *transit = p;
return transit_hash->count;
}
-unsigned int attrhash_key_make(void *p)
+unsigned int attrhash_key_make(const void *p)
{
const struct attr *attr = (struct attr *)p;
uint32_t key = 0;
return BGP_ATTR_PARSE_PROCEED;
}
+/*
+ * Check that the nexthop attribute is valid.
+ */
+bgp_attr_parse_ret_t
+bgp_attr_nexthop_valid(struct peer *peer, struct attr *attr)
+{
+ in_addr_t nexthop_h;
+
+ nexthop_h = ntohl(attr->nexthop.s_addr);
+ if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h)
+ || IPV4_CLASS_DE(nexthop_h))
+ && !BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) {
+ char buf[INET_ADDRSTRLEN];
+
+ inet_ntop(AF_INET, &attr->nexthop.s_addr, buf,
+ INET_ADDRSTRLEN);
+ flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s",
+ buf);
+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP);
+ return BGP_ATTR_PARSE_ERROR;
+ }
+
+ return BGP_ATTR_PARSE_PROCEED;
+}
+
/* Nexthop attribute. */
static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args)
{
struct attr *const attr = args->attr;
const bgp_size_t length = args->length;
- in_addr_t nexthop_h, nexthop_n;
-
/* Check nexthop attribute length. */
if (length != 4) {
flog_err(EC_BGP_ATTR_LEN,
args->total);
}
- /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
- attribute must result in a NOTIFICATION message (this is implemented
- below).
- At the same time, semantically incorrect NEXT_HOP is more likely to
- be just
- logged locally (this is implemented somewhere else). The UPDATE
- message
- gets ignored in any of these cases. */
- nexthop_n = stream_get_ipv4(peer->curr);
- nexthop_h = ntohl(nexthop_n);
- if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h)
- || IPV4_CLASS_DE(nexthop_h))
- && !BGP_DEBUG(
- allow_martians,
- ALLOW_MARTIANS)) /* loopbacks may be used in testing */
- {
- char buf[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN);
- flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s", buf);
- return bgp_attr_malformed(
- args, BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, args->total);
- }
-
- attr->nexthop.s_addr = nexthop_n;
+ attr->nexthop.s_addr = stream_get_ipv4(peer->curr);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
return BGP_ATTR_PARSE_PROCEED;
}
+ /* Get the tunnel type from encap extended community */
+ bgp_attr_extcom_tunnel_type(attr,
+ (bgp_encap_types *)&attr->encap_tunneltype);
+
return BGP_ATTR_PARSE_PROCEED;
}
return BGP_ATTR_PARSE_ERROR;
}
+ /*
+ * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect,
+ * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute.
+ * This is implemented below and will result in a NOTIFICATION. If the
+ * NEXT_HOP attribute is semantically incorrect, the error SHOULD be
+ * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION
+ * message SHOULD NOT be sent. This is implemented elsewhere.
+ *
+ * RFC4760: An UPDATE message that carries no NLRI, other than the one
+ * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP
+ * attribute. If such a message contains the NEXT_HOP attribute, the BGP
+ * speaker that receives the message SHOULD ignore this attribute.
+ */
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))
+ && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) {
+ if (bgp_attr_nexthop_valid(peer, attr) < 0) {
+ return BGP_ATTR_PARSE_ERROR;
+ }
+ }
+
/* Check all mandatory well-known attributes are present */
if ((ret = bgp_attr_check(peer, attr)) < 0) {
if (as4_path)
return BGP_ATTR_PARSE_PROCEED;
}
+/*
+ * Extract the tunnel type from extended community
+ */
+void bgp_attr_extcom_tunnel_type(struct attr *attr,
+ bgp_encap_types *tunnel_type)
+{
+ struct ecommunity *ecom;
+ int i;
+ if (!attr)
+ return;
+
+ ecom = attr->ecommunity;
+ if (!ecom || !ecom->size)
+ return;
+
+ for (i = 0; i < ecom->size; i++) {
+ uint8_t *pnt;
+ uint8_t type, sub_type;
+
+ pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
+ type = pnt[0];
+ sub_type = pnt[1];
+ if (!(type == ECOMMUNITY_ENCODE_OPAQUE &&
+ sub_type == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP))
+ continue;
+ *tunnel_type = ((pnt[6] << 8) | pnt[7]);
+ return;
+ }
+
+ return;
+}
+
size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
safi_t safi, struct bpacket_attr_vec_arr *vecarr,
struct attr *attr)
#include "mpls.h"
#include "bgp_attr_evpn.h"
+#include "bgpd/bgp_encap_types.h"
/* Simple bit mapping. */
#define BITMAP_NBBY 8
extern void bgp_dump_routes_attr(struct stream *, struct attr *,
struct prefix *);
extern bool attrhash_cmp(const void *arg1, const void *arg2);
-extern unsigned int attrhash_key_make(void *);
+extern unsigned int attrhash_key_make(const void *);
extern void attr_show_all(struct vty *);
extern unsigned long int attr_count(void);
extern unsigned long int attr_unknown_count(void);
extern void bgp_attr_flush_encap(struct attr *attr);
+extern void bgp_attr_extcom_tunnel_type(struct attr *attr,
+ bgp_encap_types *tunnel_type);
+
/**
* Set of functions to encode MP_REACH_NLRI and MP_UNREACH_NLRI attributes.
* Typical call sequence is to call _start(), followed by multiple _prefix(),
uint32_t, int, uint32_t, struct attr *);
extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt);
+extern bgp_attr_parse_ret_t bgp_attr_nexthop_valid(struct peer *peer,
+ struct attr *attr);
+
static inline int bgp_rmap_nhop_changed(uint32_t out_rmap_flags,
uint32_t in_rmap_flags)
{
static void bgp_bfd_peer_sendmsg(struct peer *peer, int command)
{
struct bfd_info *bfd_info;
- vrf_id_t vrf_id = VRF_DEFAULT;
int multihop;
+ vrf_id_t vrf_id;
bfd_info = (struct bfd_info *)peer->bfd_info;
- if (peer->bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
- vrf_id = peer->bgp->vrf_id;
+ vrf_id = peer->bgp->vrf_id;
if (command == ZEBRA_BFD_DEST_DEREGISTER) {
multihop =
zlog_debug("Zebra: BFD Dest replay request");
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
/* Replay the peer, if BFD is enabled in BGP */
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_clist.h"
-static uint32_t bgp_clist_hash_key_community_list(void *data)
+static uint32_t bgp_clist_hash_key_community_list(const void *data)
{
- struct community_list *cl = data;
+ struct community_list *cl = (struct community_list *) data;
if (cl->name_hash)
return cl->name_hash;
/* Make hash value of community attribute. This function is used by
hash package.*/
-unsigned int community_hash_make(struct community *com)
+unsigned int community_hash_make(const struct community *com)
{
uint32_t *pnt = (uint32_t *)com->val;
void community_init(void)
{
comhash =
- hash_create((unsigned int (*)(void *))community_hash_make,
+ hash_create((unsigned int (*)(const void *))community_hash_make,
(bool (*)(const void *, const void *))community_cmp,
"BGP Community Hash");
}
*/
if (aggregate->community_hash == NULL)
aggregate->community_hash = hash_create(
- (unsigned int (*)(void *))community_hash_make,
+ (unsigned int (*)(const void *))community_hash_make,
(bool (*)(const void *, const void *))community_cmp,
"BGP Aggregator community hash");
extern struct community *community_intern(struct community *);
extern void community_unintern(struct community **);
extern char *community_str(struct community *, bool make_json);
-extern unsigned int community_hash_make(struct community *);
+extern unsigned int community_hash_make(const struct community *);
extern struct community *community_str2com(const char *);
extern int community_match(const struct community *, const struct community *);
extern bool community_cmp(const struct community *c1,
}
/* Utinity function to make hash key. */
-unsigned int ecommunity_hash_make(void *arg)
+unsigned int ecommunity_hash_make(const void *arg)
{
const struct ecommunity *ecom = arg;
int size = ecom->size * ECOMMUNITY_SIZE;
#define _QUAGGA_BGP_ECOMMUNITY_H
#include "bgpd/bgp_route.h"
+#include "bgpd/bgpd.h"
/* High-order octet of the Extended Communities type field. */
#define ECOMMUNITY_ENCODE_AS 0x00
extern struct ecommunity *ecommunity_intern(struct ecommunity *);
extern bool ecommunity_cmp(const void *arg1, const void *arg2);
extern void ecommunity_unintern(struct ecommunity **);
-extern unsigned int ecommunity_hash_make(void *);
+extern unsigned int ecommunity_hash_make(const void *);
extern struct ecommunity *ecommunity_str2com(const char *, int, int);
extern char *ecommunity_ecom2str(struct ecommunity *, int, int);
extern void ecommunity_strfree(char **s);
/*
* Make hash key for ESI.
*/
-static unsigned int esi_hash_keymake(void *p)
+static unsigned int esi_hash_keymake(const void *p)
{
- struct evpnes *pes = p;
+ const struct evpnes *pes = p;
const void *pnt = (void *)pes->esi.val;
return jhash(pnt, ESI_BYTES, 0xa5a5a55a);
/*
* Make vni hash key.
*/
-static unsigned int vni_hash_key_make(void *p)
+static unsigned int vni_hash_key_make(const void *p)
{
- struct bgpevpn *vpn = p;
+ const struct bgpevpn *vpn = p;
return (jhash_1word(vpn->vni, 0));
}
/*
* Make vrf import route target hash key.
*/
-static unsigned int vrf_import_rt_hash_key_make(void *p)
+static unsigned int vrf_import_rt_hash_key_make(const void *p)
{
- struct vrf_irt_node *irt = p;
- char *pnt = irt->rt.val;
+ const struct vrf_irt_node *irt = p;
+ const char *pnt = irt->rt.val;
return jhash(pnt, 8, 0x5abc1234);
}
/*
* Make import route target hash key.
*/
-static unsigned int import_rt_hash_key_make(void *p)
+static unsigned int import_rt_hash_key_make(const void *p)
{
- struct irt_node *irt = p;
- char *pnt = irt->rt.val;
+ const struct irt_node *irt = p;
+ const char *pnt = irt->rt.val;
return jhash(pnt, 8, 0xdeadbeef);
}
rd_header = 1;
tbl_ver = table->version;
- for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm))
+ for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) {
+ if (use_json) {
+ json_array = json_object_new_array();
+ json_prefix_info = json_object_new_object();
+
+ json_object_string_add(json_prefix_info,
+ "prefix", bgp_evpn_route2str(
+ (struct prefix_evpn *)&rm->p, buf,
+ BUFSIZ));
+
+ json_object_int_add(json_prefix_info,
+ "prefixLen", rm->p.prefixlen);
+ }
+
for (pi = bgp_node_get_bgp_path_info(rm); pi;
pi = pi->next) {
total_count++;
if (use_json) {
json_nroute =
json_object_new_object();
- json_prefix_info =
- json_object_new_object();
- json_array =
- json_object_new_array();
if (type == RD_TYPE_AS
|| type == RD_TYPE_AS4)
sprintf(rd_str, "%u:%d",
"rd",
rd_str);
- json_object_string_add(
- json_prefix_info,
- "prefix",
- bgp_evpn_route2str(
- (struct prefix_evpn *)
- &rm->p, buf, BUFSIZ));
-
- json_object_int_add(
- json_prefix_info,
- "prefixLen",
- rm->p.prefixlen);
-
} else {
vty_out(vty,
"Route Distinguisher: ");
}
rd_header = 0;
}
+
if (option == SHOW_DISPLAY_TAGS)
route_vty_out_tag(vty, &rm->p, pi, 0,
SAFI_EVPN,
SAFI_EVPN, json_array);
output_count++;
}
+ if (use_json) {
+ json_object_object_add(json_prefix_info,
+ "paths", json_array);
+ json_object_object_add(json_nroute, buf,
+ json_prefix_info);
+ }
+ }
- if (use_json) {
- json_object_object_add(json_prefix_info, "paths",
- json_array);
- json_object_object_add(json_nroute, buf,
- json_prefix_info);
+ if (use_json)
json_object_object_add(json, rd_str, json_nroute);
- }
}
if (use_json) {
DEFUN(show_ip_bgp_l2vpn_evpn_all_overlay,
show_ip_bgp_l2vpn_evpn_all_overlay_cmd,
- "show [ip] bgp l2vpn evpn all overlay",
+ "show [ip] bgp l2vpn evpn all overlay [json]",
SHOW_STR
IP_STR
BGP_STR
L2VPN_HELP_STR
EVPN_HELP_STR
"Display information about all EVPN NLRIs\n"
- "Display BGP Overlay Information for prefixes\n")
+ "Display BGP Overlay Information for prefixes\n"
+ JSON_STR)
{
return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL,
SHOW_DISPLAY_OVERLAY,
return p1->peer == p2->peer;
}
-static unsigned int peer_hash_key(void *arg)
+static unsigned int peer_hash_key(const void *arg)
{
- struct pkat *pkat = arg;
+ const struct pkat *pkat = arg;
return (uintptr_t)pkat->peer;
}
}
/* Utility function to make hash key. */
-unsigned int lcommunity_hash_make(void *arg)
+unsigned int lcommunity_hash_make(const void *arg)
{
const struct lcommunity *lcom = arg;
int size = lcom_length(lcom);
extern struct lcommunity *lcommunity_intern(struct lcommunity *);
extern bool lcommunity_cmp(const void *arg1, const void *arg2);
extern void lcommunity_unintern(struct lcommunity **);
-extern unsigned int lcommunity_hash_make(void *);
+extern unsigned int lcommunity_hash_make(const void *);
extern struct hash *lcommunity_hash(void);
extern struct lcommunity *lcommunity_str2com(const char *);
extern int lcommunity_match(const struct lcommunity *,
struct list *ifp_list;
};
-static unsigned int bgp_mac_hash_key_make(void *data)
+static unsigned int bgp_mac_hash_key_make(const void *data)
{
- struct bgp_self_mac *bsm = data;
+ const struct bgp_self_mac *bsm = data;
return jhash(&bsm->macaddr, ETH_ALEN, 0xa5a5dead);
}
XFREE(MTYPE_TIP_ADDR, addr);
}
-static unsigned int bgp_tip_hash_key_make(void *p)
+static unsigned int bgp_tip_hash_key_make(const void *p)
{
const struct tip_addr *addr = p;
XFREE(MTYPE_BGP_ADDR, addr);
}
-static unsigned int bgp_address_hash_key_make(void *p)
+static unsigned int bgp_address_hash_key_make(const void *p)
{
const struct bgp_addr *addr = p;
nlris[NLRI_UPDATE].nlri = stream_pnt(s);
nlris[NLRI_UPDATE].length = update_len;
stream_forward_getp(s, update_len);
+
+ if (CHECK_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) {
+ /*
+ * We skipped nexthop attribute validation earlier so
+ * validate the nexthop now.
+ */
+ if (bgp_attr_nexthop_valid(peer, &attr) < 0) {
+ bgp_attr_unintern_sub(&attr);
+ return BGP_Stop;
+ }
+ }
}
if (BGP_DEBUG(update, UPDATE_IN))
return new;
}
-uint32_t bgp_pbr_match_hash_key(void *arg)
+uint32_t bgp_pbr_match_hash_key(const void *arg)
{
- struct bgp_pbr_match *pbm = (struct bgp_pbr_match *)arg;
+ const struct bgp_pbr_match *pbm = arg;
uint32_t key;
key = jhash_1word(pbm->vrf_id, 0x4312abde);
return true;
}
-uint32_t bgp_pbr_rule_hash_key(void *arg)
+uint32_t bgp_pbr_rule_hash_key(const void *arg)
{
- struct bgp_pbr_rule *pbr = (struct bgp_pbr_rule *)arg;
+ const struct bgp_pbr_rule *pbr = arg;
uint32_t key;
key = prefix_hash_key(&pbr->src);
return true;
}
-uint32_t bgp_pbr_match_entry_hash_key(void *arg)
+uint32_t bgp_pbr_match_entry_hash_key(const void *arg)
{
- struct bgp_pbr_match_entry *pbme;
+ const struct bgp_pbr_match_entry *pbme;
uint32_t key;
- pbme = (struct bgp_pbr_match_entry *)arg;
+ pbme = arg;
key = prefix_hash_key(&pbme->src);
key = jhash_1word(prefix_hash_key(&pbme->dst), key);
key = jhash(&pbme->dst_port_min, 2, key);
return true;
}
-uint32_t bgp_pbr_action_hash_key(void *arg)
+uint32_t bgp_pbr_action_hash_key(const void *arg)
{
- struct bgp_pbr_action *pbra;
+ const struct bgp_pbr_action *pbra;
uint32_t key;
- pbra = (struct bgp_pbr_action *)arg;
+ pbra = arg;
key = jhash_1word(pbra->table_id, 0x4312abde);
key = jhash_1word(pbra->fwmark, key);
return key;
extern void bgp_pbr_cleanup(struct bgp *bgp);
extern void bgp_pbr_init(struct bgp *bgp);
-extern uint32_t bgp_pbr_rule_hash_key(void *arg);
+extern uint32_t bgp_pbr_rule_hash_key(const void *arg);
extern bool bgp_pbr_rule_hash_equal(const void *arg1,
const void *arg2);
-extern uint32_t bgp_pbr_action_hash_key(void *arg);
+extern uint32_t bgp_pbr_action_hash_key(const void *arg);
extern bool bgp_pbr_action_hash_equal(const void *arg1,
const void *arg2);
-extern uint32_t bgp_pbr_match_entry_hash_key(void *arg);
+extern uint32_t bgp_pbr_match_entry_hash_key(const void *arg);
extern bool bgp_pbr_match_entry_hash_equal(const void *arg1,
const void *arg2);
-extern uint32_t bgp_pbr_match_hash_key(void *arg);
+extern uint32_t bgp_pbr_match_hash_key(const void *arg);
extern bool bgp_pbr_match_hash_equal(const void *arg1,
const void *arg2);
}
}
- /* RFC 8212 to prevent route leaks.
- * This specification intends to improve this situation by requiring the
- * explicit configuration of both BGP Import and Export Policies for any
- * External BGP (EBGP) session such as customers, peers, or
- * confederation boundaries for all enabled address families. Through
- * codification of the aforementioned requirement, operators will
- * benefit from consistent behavior across different BGP
- * implementations.
- */
- if (peer->bgp->ebgp_requires_policy
- == DEFAULT_EBGP_POLICY_ENABLED)
- if (!bgp_inbound_policy_exists(peer, filter))
- return RMAP_DENY;
-
/* Route map apply. */
if (rmap) {
memset(&rmap_path, 0, sizeof(struct bgp_path_info));
peer->rmap_type = 0;
if (ret == RMAP_DENYMATCH) {
+ if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
+ zlog_debug("%s [Update:SEND] %s is filtered by route-map",
+ peer->host, prefix2str(p, buf, sizeof(buf)));
+
bgp_attr_flush(attr);
return 0;
}
goto filtered;
}
+ /* RFC 8212 to prevent route leaks.
+ * This specification intends to improve this situation by requiring the
+ * explicit configuration of both BGP Import and Export Policies for any
+ * External BGP (EBGP) session such as customers, peers, or
+ * confederation boundaries for all enabled address families. Through
+ * codification of the aforementioned requirement, operators will
+ * benefit from consistent behavior across different BGP
+ * implementations.
+ */
+ if (peer->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED)
+ if (!bgp_inbound_policy_exists(peer,
+ &peer->filter[afi][safi])) {
+ reason = "inbound policy missing";
+ goto filtered;
+ }
+
bgp_attr_dup(&new_attr, attr);
/* Apply incoming route-map.
json_object *json_paths)
{
struct attr *attr;
- char buf[BUFSIZ];
+ char buf[BUFSIZ] = {0};
json_object *json_path = NULL;
-
- if (json_paths)
- json_path = json_object_new_object();
+ json_object *json_nexthop = NULL;
+ json_object *json_overlay = NULL;
if (!path->extra)
return;
+ if (json_paths) {
+ json_path = json_object_new_object();
+ json_overlay = json_object_new_object();
+ json_nexthop = json_object_new_object();
+ }
+
/* short status lead text */
route_vty_short_status_out(vty, path, json_path);
/* print prefix and mask */
if (!display)
- route_vty_out_route(p, vty, NULL);
+ route_vty_out_route(p, vty, json_path);
else
vty_out(vty, "%*s", 17, " ");
switch (af) {
case AF_INET:
- vty_out(vty, "%-16s",
- inet_ntop(af, &attr->mp_nexthop_global_in, buf,
- BUFSIZ));
+ inet_ntop(af, &attr->mp_nexthop_global_in, buf, BUFSIZ);
+ if (!json_path) {
+ vty_out(vty, "%-16s", buf);
+ } else {
+ json_object_string_add(json_nexthop, "ip", buf);
+
+ json_object_string_add(json_nexthop, "afi",
+ "ipv4");
+
+ json_object_object_add(json_path, "nexthop",
+ json_nexthop);
+ }
break;
case AF_INET6:
- vty_out(vty, "%s(%s)",
- inet_ntop(af, &attr->mp_nexthop_global, buf,
- BUFSIZ),
- inet_ntop(af, &attr->mp_nexthop_local, buf1,
- BUFSIZ));
+ inet_ntop(af, &attr->mp_nexthop_global, buf, BUFSIZ);
+ inet_ntop(af, &attr->mp_nexthop_local, buf1, BUFSIZ);
+ if (!json_path) {
+ vty_out(vty, "%s(%s)", buf, buf1);
+ } else {
+ json_object_string_add(json_nexthop,
+ "ipv6Global", buf);
+
+ json_object_string_add(json_nexthop,
+ "ipv6LinkLocal", buf1);
+
+ json_object_string_add(json_nexthop, "afi",
+ "ipv6");
+
+ json_object_object_add(json_path, "nexthop",
+ json_nexthop);
+ }
break;
default:
- vty_out(vty, "?");
+ if (!json_path) {
+ vty_out(vty, "?");
+ } else {
+ json_object_string_add(json_nexthop, "Error",
+ "Unsupported address-family");
+ }
}
char *str = esi2str(&(attr->evpn_overlay.eth_s_id));
- vty_out(vty, "%s", str);
+ if (!json_path)
+ vty_out(vty, "%s", str);
+ else
+ json_object_string_add(json_overlay, "esi", str);
+
XFREE(MTYPE_TMP, str);
if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)p)) {
- vty_out(vty, "/%s",
- inet_ntoa(attr->evpn_overlay.gw_ip.ipv4));
+ inet_ntop(AF_INET, &(attr->evpn_overlay.gw_ip.ipv4),
+ buf, BUFSIZ);
} else if (is_evpn_prefix_ipaddr_v6((struct prefix_evpn *)p)) {
- vty_out(vty, "/%s",
- inet_ntop(AF_INET6,
- &(attr->evpn_overlay.gw_ip.ipv6), buf,
- BUFSIZ));
+ inet_ntop(AF_INET6, &(attr->evpn_overlay.gw_ip.ipv6),
+ buf, BUFSIZ);
}
+
+ if (!json_path)
+ vty_out(vty, "/%s", buf);
+ else
+ json_object_string_add(json_overlay, "gw", buf);
+
if (attr->ecommunity) {
char *mac = NULL;
struct ecommunity_val *routermac = ecommunity_lookup(
if (routermac)
mac = ecom_mac2str((char *)routermac->val);
if (mac) {
- vty_out(vty, "/%s", (char *)mac);
+ if (!json_path) {
+ vty_out(vty, "/%s", (char *)mac);
+ } else {
+ json_object_string_add(json_overlay,
+ "rmac", mac);
+ }
XFREE(MTYPE_TMP, mac);
}
}
- vty_out(vty, "\n");
- }
+ if (!json_path) {
+ vty_out(vty, "\n");
+ } else {
+ json_object_object_add(json_path, "overlay",
+ json_overlay);
+
+ json_object_array_add(json_paths, json_path);
+ }
+ }
}
/* dampening route */
#include "plist.h"
#include "memory.h"
#include "log.h"
-#include "lua.h"
+#include "frrlua.h"
#ifdef HAVE_LIBPCREPOSIX
#include <pcreposix.h>
#else
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
}
-static void bgp_route_map_event(route_map_event_t event, const char *rmap_name)
+static void bgp_route_map_event(const char *rmap_name)
{
if (route_map_mark_updated(rmap_name) == 0)
bgp_route_map_mark_update(rmap_name);
* 16. Local-as should match, if configured.
* )
*/
-static unsigned int updgrp_hash_key_make(void *p)
+static unsigned int updgrp_hash_key_make(const void *p)
{
const struct update_group *updgrp;
const struct peer *peer;
case AFI_L2VPN:
return BGP_EVPN_NODE;
break;
+ case AFI_UNSPEC:
case AFI_MAX:
// We should never be here but to clarify the switch statement..
return BGP_IPV4_NODE;
* afi -> The parsed afi if it was included in the show command, returned here
* safi -> The parsed safi if it was included in the show command, returned here
* bgp -> Pointer to the bgp data structure we need to fill in.
+ * use_json -> json is configured or not
*
* The function returns the correct location in the parse tree for the
* last token found.
else {
*bgp = bgp_lookup_by_name(vrf_name);
if (!*bgp) {
- if (use_json)
- vty_out(vty, "{}\n");
+ if (use_json) {
+ json_object *json = NULL;
+ json = json_object_new_object();
+ json_object_string_add(
+ json, "warning",
+ "View/Vrf is unknown");
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(json,
+ JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
else
vty_out(vty, "View/Vrf %s is unknown\n",
vrf_name);
} else {
*bgp = bgp_get_default();
if (!*bgp) {
- if (use_json)
- vty_out(vty, "{}\n");
+ if (use_json) {
+ json_object *json = NULL;
+ json = json_object_new_object();
+ json_object_string_add(
+ json, "warning",
+ "Default BGP instance not found");
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(json,
+ JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
else
vty_out(vty,
"Default BGP instance not found\n");
vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
vty_out(vty, "if you are using this please migrate to the below command.\n");
vty_out(vty, "'no bgp large-community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:BB:CC>'\n");
- zlog_warn("Deprecated option: 'no ip large-community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:BB:CC>' being used");
+ zlog_warn("Deprecated option: 'no ip large-community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> <LINE|AA:BB:CC>' being used");
}
argv_find(argv, argc, "permit", &idx);
argv_find(argv, argc, "deny", &idx);
bgp_zebra_instance_register(bgp);
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, bgp->vrf_id);
/* tell label pool that zebra is connected */
bgp_lp_event_zebra_up();
return sockunion_cmp(&p1->su, &p2->su);
}
-static unsigned int peer_hash_key_make(void *p)
+static unsigned int peer_hash_key_make(const void *p)
{
- struct peer *peer = p;
+ const struct peer *peer = p;
return sockunion_hash(&peer->su);
}
/* 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;
vnc_zlog_debug_verbose("%s done", __func__);
}
-#if 0 /* superseded */
-static void vnc_routemap_event(route_map_event_t type, /* ignored */
- const char *rmap_name) /* ignored */
-{
- struct listnode *mnode, *mnnode;
- struct bgp *bgp;
-
- vnc_zlog_debug_verbose("%s(event type=%d)", __func__, type);
- if (bm->bgp == NULL) /* may be called during cleanup */
- return;
-
- for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp))
- vnc_routemap_update(bgp, rmap_name);
-
- vnc_zlog_debug_verbose("%s: done", __func__);
-}
-#endif
-
/*-------------------------------------------------------------------------
* nve-group
*-----------------------------------------------------------------------*/
void bgp_rfapi_cfg_init(void)
{
- /* main bgpd code does not use this hook, but vnc does */
- /* superseded by bgp_route_map_process_update_cb() */
- /* bgp_route_map_event_hook_add(vnc_routemap_event); */
-
install_node(&bgp_vnc_defaults_node, NULL);
install_node(&bgp_vnc_nve_group_node, NULL);
install_node(&bgp_vrf_policy_node, NULL);
return ENOENT;
}
-/*
- * Extract the tunnel type from the extended community
- */
-int rfapiGetTunnelType(struct attr *attr, bgp_encap_types *type)
-{
- *type = BGP_ENCAP_TYPE_MPLS; /* default to MPLS */
- if (attr && attr->ecommunity) {
- struct ecommunity *ecom = attr->ecommunity;
- int i;
-
- for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE);
- i += ECOMMUNITY_SIZE) {
- uint8_t *ep;
-
- ep = ecom->val + i;
- if (ep[0] == ECOMMUNITY_ENCODE_OPAQUE
- && ep[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP) {
- *type = (ep[6] << 8) + ep[7];
- return 0;
- }
- }
- }
-
- return ENOENT;
-}
-
-
/*
* Look for UN address in Encap attribute
*/
int rfapiGetVncTunnelUnAddr(struct attr *attr, struct prefix *p)
{
struct bgp_attr_encap_subtlv *pEncap;
- bgp_encap_types tun_type;
+ bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS;/*Default tunnel type*/
- rfapiGetTunnelType(attr, &tun_type);
+ bgp_attr_extcom_tunnel_type(attr, &tun_type);
if (tun_type == BGP_ENCAP_TYPE_MPLS) {
if (!p)
return 0;
}
if (bpi->attr) {
- bgp_encap_types tun_type;
+ bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS; /*Default*/
new->prefix.cost = rfapiRfpCost(bpi->attr);
struct bgp_attr_encap_subtlv *pEncap;
}
}
- rfapiGetTunnelType(bpi->attr, &tun_type);
+ bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type);
if (tun_type == BGP_ENCAP_TYPE_MPLS) {
struct prefix p;
/* MPLS carries UN address in next hop */
extern int rfapiGetVncLifetime(struct attr *attr, uint32_t *lifetime);
-extern int rfapiGetTunnelType(struct attr *attr, bgp_encap_types *type);
-
extern int rfapiGetVncTunnelUnAddr(struct attr *attr, struct prefix *p);
extern int rfapi_reopen(struct rfapi_descriptor *rfd, struct bgp *bgp);
struct prefix pfx_vn;
uint8_t cost;
uint32_t lifetime;
- bgp_encap_types tun_type;
+ bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS;/*Default tunnel type*/
char buf_pfx[BUFSIZ];
char buf_ntop[BUFSIZ];
BUFSIZ));
}
- rfapiGetTunnelType(bpi->attr, &tun_type);
+ bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type);
/*
* VN addr
*/
AC_C_FLAG([-O0])
fi
if test "x${enable_lua}" = "xyes"; then
- AC_CHECK_LIB([lua], [lua_newstate],
- [LIBS="$LIBS -llua"])
- AC_DEFINE([HAVE_LUA], [1], [Lua enabled for development])
+ AX_PROG_LUA([5.3])
+ AX_LUA_HEADERS
+ AX_LUA_LIBS([
+ AC_DEFINE([HAVE_LUA], [1], [Have support for Lua interpreter])
+ LIBS="$LIBS $LUA_LIB"
+ ])
fi
else
if test "x${enable_lua}" = "xyes"; then
sudo modprobe mpls-router mpls-iptunnel
+If the above command returns an error, you may need to install the appropriate
+or latest linux-modules-extra-<kernel-version>-generic package. For example
+``apt-get install linux-modules-extra-`uname -r`-generic``
+
Enable MPLS Forwarding
""""""""""""""""""""""
.. 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);
...
}
py.test -s -v --tb=no
+The above command must be executed from inside the topotests directory.
+
All test\_\* scripts in subdirectories are detected and executed (unless
disabled in ``pytest.ini`` file).
cd test_to_be_run
./test_to_be_run.py
+For example, and assuming you are inside the frr directory:
+
+.. code:: shell
+
+ cd tests/topotests/bgp_l3vpn_to_bgp_vrf
+ ./test_bgp_l3vpn_to_bgp_vrf.py
+
For further options, refer to pytest documentation.
Test will set exit code which can be used with ``git bisect``.
Compiling for GCC AddressSanitizer requires to use ``gcc`` as a linker as well
(instead of ``ld``). Here is a suggest way to compile frr with AddressSanitizer
-for ``stable/3.0`` branch:
+for ``master`` branch:
.. code:: shell
git clone https://github.com/FRRouting/frr.git
cd frr
- git checkout stable/3.0
./bootstrap.sh
export CC=gcc
export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer"
--enable-exampledir=/usr/lib/frr/examples \
--with-moduledir=/usr/lib/frr/modules \
--enable-multipath=0 --enable-rtadv \
- --enable-tcp-zebra --enable-fpm --enable-pimd
+ --enable-tcp-zebra --enable-fpm --enable-pimd \
+ --enable-sharpd
make
sudo make install
# Create symlink for vtysh, so topotest finds it in /usr/lib/frr
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.
peer listener to and the address we should use to send the packets.
This option is mandatory for IPv6.
- `interface` selects which interface we should use. This option
- conflicts with `vrf`.
+ `interface` selects which interface we should use.
`vrf` selects which domain we want to use.
Stops and removes the selected peer.
-.. index:: show bfd peers [json]
-.. clicmd:: show bfd peers [json]
+.. index:: show bfd [vrf NAME] peers [json]
+.. clicmd:: show bfd [vrf NAME] peers [json]
Show all configured BFD peers information and current status.
-.. index:: show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]
-.. clicmd:: show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]
+.. index:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]
+.. clicmd:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]
Show status for a specific BFD peer.
shutdown
!
+ ! configure a peer on an interface from a separate vrf
+ peer 192.168.0.5 interface eth1 vrf vrf2
+ no shutdown
+ !
+
! remove a peer
no peer 192.168.0.3 vrf foo
.. 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
.. index:: router ospf6
.. clicmd:: router ospf6
-.. index:: router-id A.B.C.D
-.. clicmd:: router-id A.B.C.D
+.. index:: ospf6 router-id A.B.C.D
+.. clicmd:: ospf6 router-id A.B.C.D
Set router's Router-ID.
.. 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
If the connection to the FPM goes down for some reason, zebra sends
the FPM a complete copy of the forwarding table(s) when it reconnects.
+.. _zebra-dplane:
+
+Dataplane Commands
+==================
+
+The zebra dataplane subsystem provides a framework for FIB
+programming. Zebra uses the dataplane to program the local kernel as
+it makes changes to objects such as IP routes, MPLS LSPs, and
+interface IP addresses. The dataplane runs in its own pthread, in
+order to off-load work from the main zebra pthread.
+
+
+.. index:: show zebra dplane [detailed]
+.. clicmd:: show zebra dplane [detailed]
+
+ Display statistics about the updates and events passing through the
+ dataplane subsystem.
+
+
+.. index:: show zebra dplane providers
+.. clicmd:: show zebra dplane providers
+
+ Display information about the running dataplane plugins that are
+ providing updates to a FIB. By default, the local kernel plugin is
+ present.
+
+
+.. index:: zebra dplane limit [NUMBER]
+.. clicmd:: zebra dplane limit [NUMBER]
+
+ Configure the limit on the number of pending updates that are
+ waiting to be processed by the dataplane pthread.
+
+
zebra Terminal Mode Commands
============================
hash_clean(f->neighbors_neighbors, neighbor_entry_del_void);
}
-static unsigned neighbor_entry_hash_key(void *np)
+static unsigned neighbor_entry_hash_key(const void *np)
{
- struct neighbor_entry *n = np;
+ const struct neighbor_entry *n = np;
return jhash(n->id, sizeof(n->id), 0x55aa5a5a);
}
static int isis_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
{
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
struct listnode *anode;
struct isis_area *area;
if (orig_zebra_connected)
orig_zebra_connected(zclient);
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
}
static void bfd_debug(struct in_addr *dst, struct in_addr *src,
};
__attribute__((__unused__))
-static unsigned isis_vertex_queue_hash_key(void *vp)
+static unsigned isis_vertex_queue_hash_key(const void *vp)
{
- struct isis_vertex *vertex = vp;
+ const struct isis_vertex *vertex = vp;
if (VTYPE_IP(vertex->type)) {
uint32_t key;
static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
struct stream *stream, struct sbuf *log, void *dest,
- int indent);
+ int indent, bool *unpacked_known_tlvs);
/* Functions related to TLVs 1 Area Addresses */
size_t subtlv_start = stream_get_getp(s);
if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH, subtlv_len, s,
- log, NULL, indent + 4)) {
+ log, NULL, indent + 4, NULL)) {
goto out;
}
if (mtid != ISIS_MT_IPV4_UNICAST)
sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
sbuf_push(buf, 0, "\n");
+
+ if (r->subtlvs) {
+ sbuf_push(buf, indent, " Subtlvs:\n");
+ format_subtlvs(r->subtlvs, buf, indent + 4);
+ }
}
static void free_item_extended_ip_reach(struct isis_item *i)
}
rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
+ bool unpacked_known_tlvs = false;
+
if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IP_REACH, subtlv_len, s,
- log, rv->subtlvs, indent + 4)) {
+ log, rv->subtlvs, indent + 4, &unpacked_known_tlvs)) {
goto out;
}
+ if (!unpacked_known_tlvs) {
+ isis_free_subtlvs(rv->subtlvs);
+ rv->subtlvs = NULL;
+ }
}
append_item(items, (struct isis_item *)rv);
}
rv->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH);
+ bool unpacked_known_tlvs = false;
+
if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH, subtlv_len, s,
- log, rv->subtlvs, indent + 4)) {
+ log, rv->subtlvs, indent + 4, &unpacked_known_tlvs)) {
goto out;
}
+ if (!unpacked_known_tlvs) {
+ isis_free_subtlvs(rv->subtlvs);
+ rv->subtlvs = NULL;
+ }
}
append_item(items, (struct isis_item *)rv);
static int unpack_tlv(enum isis_tlv_context context, size_t avail_len,
struct stream *stream, struct sbuf *log, void *dest,
- int indent)
+ int indent, bool *unpacked_known_tlvs)
{
uint8_t tlv_type, tlv_len;
const struct tlv_ops *ops;
ops = tlv_table[context][tlv_type];
if (ops && ops->unpack) {
+ if (unpacked_known_tlvs)
+ *unpacked_known_tlvs = true;
return ops->unpack(context, tlv_type, tlv_len, stream, log,
dest, indent + 2);
}
static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
struct stream *stream, struct sbuf *log, void *dest,
- int indent)
+ int indent, bool *unpacked_known_tlvs)
{
int rv;
size_t tlv_start, tlv_pos;
while (tlv_pos < avail_len) {
rv = unpack_tlv(context, avail_len - tlv_pos, stream, log, dest,
- indent + 2);
+ indent + 2, unpacked_known_tlvs);
if (rv)
return rv;
result = isis_alloc_tlvs();
rv = unpack_tlvs(ISIS_CONTEXT_LSP, avail_len, stream, &logbuf, result,
- indent);
+ indent, NULL);
*log = sbuf_buf(&logbuf);
*dest = result;
struct isis_tx_queue *queue;
};
-static unsigned tx_queue_hash_key(void *p)
+static unsigned tx_queue_hash_key(const void *p)
{
- struct isis_tx_queue_entry *e = p;
+ const struct isis_tx_queue_entry *e = p;
uint32_t id_key = jhash(e->lsp->hdr.lsp_id,
ISIS_SYS_ID_LEN + 2, 0x55aa5a5a);
* bfd_client_sendmsg - Format and send a client register
* command to Zebra to be forwarded to BFD
*/
-void bfd_client_sendmsg(struct zclient *zclient, int command)
+void bfd_client_sendmsg(struct zclient *zclient, int command,
+ vrf_id_t vrf_id)
{
struct stream *s;
int ret;
s = zclient->obuf;
stream_reset(s);
- zclient_create_header(s, command, VRF_DEFAULT);
+ zclient_create_header(s, command, vrf_id);
stream_putl(s, getpid());
int multihop, int extra_space, bool use_json,
json_object *json_obj);
-extern void bfd_client_sendmsg(struct zclient *zclient, int command);
+extern void bfd_client_sendmsg(struct zclient *zclient, int command,
+ vrf_id_t vrf_id);
extern void bfd_gbl_init(void);
return found;
}
-static unsigned int cmd_hash_key(void *p)
+static unsigned int cmd_hash_key(const void *p)
{
int size = sizeof(p);
/* Configuration from terminal */
DEFUN (config_terminal,
config_terminal_cmd,
- "configure terminal",
+ "configure [terminal]",
"Configuration from vty interface\n"
"Configuration terminal\n")
{
return ret;
}
-static unsigned int distribute_hash_make(void *arg)
+static unsigned int distribute_hash_make(const void *arg)
{
const struct distribute *dist = arg;
return f_a->code == f_b->code;
}
-static inline unsigned int ferr_hash_key(void *a)
+static inline unsigned int ferr_hash_key(const void *a)
{
- struct log_ref *f = a;
+ const struct log_ref *f = a;
return f->code;
}
--- /dev/null
+/*
+ * This file defines the lua interface into
+ * FRRouting.
+ *
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This file is part of FreeRangeRouting (FRR).
+ *
+ * FRR is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with FRR; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <stdio.h>
+
+#include <zebra.h>
+
+#if defined(HAVE_LUA)
+#include "prefix.h"
+#include "frrlua.h"
+#include "log.h"
+
+static int lua_zlog_debug(lua_State *L)
+{
+ int debug_lua = 1;
+ const char *string = lua_tostring(L, 1);
+
+ if (debug_lua)
+ zlog_debug("%s", string);
+
+ return 0;
+}
+
+const char *get_string(lua_State *L, const char *key)
+{
+ const char *str;
+
+ lua_pushstring(L, key);
+ lua_gettable(L, -2);
+
+ str = (const char *)lua_tostring(L, -1);
+ lua_pop(L, 1);
+
+ return str;
+}
+
+int get_integer(lua_State *L, const char *key)
+{
+ int result;
+
+ lua_pushstring(L, key);
+ lua_gettable(L, -2);
+
+ result = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ return result;
+}
+
+static void *lua_alloc(void *ud, void *ptr, size_t osize,
+ size_t nsize)
+{
+ (void)ud; (void)osize; /* not used */
+ if (nsize == 0) {
+ free(ptr);
+ return NULL;
+ } else
+ return realloc(ptr, nsize);
+}
+
+lua_State *lua_initialize(const char *file)
+{
+ int status;
+ lua_State *L = lua_newstate(lua_alloc, NULL);
+
+ zlog_debug("Newstate: %p", L);
+ luaL_openlibs(L);
+ zlog_debug("Opened lib");
+ status = luaL_loadfile(L, file);
+ if (status) {
+ zlog_debug("Failure to open %s %d", file, status);
+ lua_close(L);
+ return NULL;
+ }
+
+ lua_pcall(L, 0, LUA_MULTRET, 0);
+ zlog_debug("Setting global function");
+ lua_pushcfunction(L, lua_zlog_debug);
+ lua_setglobal(L, "zlog_debug");
+
+ return L;
+}
+
+void lua_setup_prefix_table(lua_State *L, const struct prefix *prefix)
+{
+ char buffer[100];
+
+ lua_newtable(L);
+ lua_pushstring(L, prefix2str(prefix, buffer, 100));
+ lua_setfield(L, -2, "route");
+ lua_pushinteger(L, prefix->family);
+ lua_setfield(L, -2, "family");
+ lua_setglobal(L, "prefix");
+}
+
+enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule)
+{
+ int status;
+
+ lua_getglobal(L, rule);
+ status = lua_pcall(L, 0, 1, 0);
+ if (status) {
+ zlog_debug("Executing Failure with function: %s: %d",
+ rule, status);
+ return LUA_RM_FAILURE;
+ }
+
+ status = lua_tonumber(L, -1);
+ return status;
+}
+#endif
--- /dev/null
+/*
+ * This file defines the lua interface into
+ * FRRouting.
+ *
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This file is part of FreeRangeRouting (FRR).
+ *
+ * FRR is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with FRR; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef __LUA_H__
+#define __LUA_H__
+
+#if defined(HAVE_LUA)
+
+#include "lua.h"
+#include "lualib.h"
+#include "lauxlib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * These functions are helper functions that
+ * try to glom some of the lua_XXX functionality
+ * into what we actually need, instead of having
+ * to make multiple calls to set up what
+ * we want
+ */
+enum lua_rm_status {
+ /*
+ * Script function run failure. This will translate into a
+ * deny
+ */
+ LUA_RM_FAILURE = 0,
+ /*
+ * No Match was found for the route map function
+ */
+ LUA_RM_NOMATCH,
+ /*
+ * Match was found but no changes were made to the
+ * incoming data.
+ */
+ LUA_RM_MATCH,
+ /*
+ * Match was found and data was modified, so
+ * figure out what changed
+ */
+ LUA_RM_MATCH_AND_CHANGE,
+};
+
+/*
+ * Open up the lua.scr file and parse
+ * initial global values, if any.
+ */
+lua_State *lua_initialize(const char *file);
+
+void lua_setup_prefix_table(lua_State *L, const struct prefix *prefix);
+
+enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule);
+
+/*
+ * Get particular string/integer information
+ * from a table. It is *assumed* that
+ * the table has already been selected
+ */
+const char *get_string(lua_State *L, const char *key);
+int get_integer(lua_State *L, const char *key);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#endif
vty_init(master);
memory_init();
+ yang_init();
+ nb_init(master, NULL, 0);
vty_stdio(vty_do_exit);
static struct list *_hashes;
struct hash *hash_create_size(unsigned int size,
- unsigned int (*hash_key)(void *),
+ unsigned int (*hash_key)(const void *),
bool (*hash_cmp)(const void *, const void *),
const char *name)
{
return hash;
}
-struct hash *hash_create(unsigned int (*hash_key)(void *),
+struct hash *hash_create(unsigned int (*hash_key)(const void *),
bool (*hash_cmp)(const void *, const void *),
const char *name)
{
unsigned int max_size;
/* Key make function. */
- unsigned int (*hash_key)(void *);
+ unsigned int (*hash_key)(const void *);
/* Data compare function. */
bool (*hash_cmp)(const void *, const void *);
* Returns:
* a new hash table
*/
-extern struct hash *hash_create(unsigned int (*hash_key)(void *),
+extern struct hash *hash_create(unsigned int (*hash_key)(const void *),
bool (*hash_cmp)(const void *, const void *),
const char *name);
* a new hash table
*/
extern struct hash *
-hash_create_size(unsigned int size, unsigned int (*hash_key)(void *),
+hash_create_size(unsigned int size, unsigned int (*hash_key)(const void *),
bool (*hash_cmp)(const void *, const void *),
const char *name);
return ret;
}
-static unsigned int if_rmap_hash_make(void *data)
+static unsigned int if_rmap_hash_make(const void *data)
{
const struct if_rmap *if_rmap = data;
+++ /dev/null
-/*
- * This file defines the lua interface into
- * FRRouting.
- *
- * Copyright (C) 2016 Cumulus Networks, Inc.
- * Donald Sharp
- *
- * This file is part of FreeRangeRouting (FRR).
- *
- * FRR is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2, or (at your option) any later version.
- *
- * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along
- * with FRR; see the file COPYING. If not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-#include <stdio.h>
-
-#include <zebra.h>
-
-#if defined(HAVE_LUA)
-#include "prefix.h"
-#include "lua.h"
-#include "log.h"
-
-static int lua_zlog_debug(lua_State *L)
-{
- int debug_lua = 1;
- const char *string = lua_tostring(L, 1);
-
- if (debug_lua)
- zlog_debug("%s", string);
-
- return 0;
-}
-
-const char *get_string(lua_State *L, const char *key)
-{
- const char *str;
-
- lua_pushstring(L, key);
- lua_gettable(L, -2);
-
- str = (const char *)lua_tostring(L, -1);
- lua_pop(L, 1);
-
- return str;
-}
-
-int get_integer(lua_State *L, const char *key)
-{
- int result;
-
- lua_pushstring(L, key);
- lua_gettable(L, -2);
-
- result = lua_tointeger(L, -1);
- lua_pop(L, 1);
-
- return result;
-}
-
-static void *lua_alloc(void *ud, void *ptr, size_t osize,
- size_t nsize)
-{
- (void)ud; (void)osize; /* not used */
- if (nsize == 0) {
- free(ptr);
- return NULL;
- } else
- return realloc(ptr, nsize);
-}
-
-lua_State *lua_initialize(const char *file)
-{
- int status;
- lua_State *L = lua_newstate(lua_alloc, NULL);
-
- zlog_debug("Newstate: %p", L);
- luaL_openlibs(L);
- zlog_debug("Opened lib");
- status = luaL_loadfile(L, file);
- if (status) {
- zlog_debug("Failure to open %s %d", file, status);
- lua_close(L);
- return NULL;
- }
-
- lua_pcall(L, 0, LUA_MULTRET, 0);
- zlog_debug("Setting global function");
- lua_pushcfunction(L, lua_zlog_debug);
- lua_setglobal(L, "zlog_debug");
-
- return L;
-}
-
-void lua_setup_prefix_table(lua_State *L, const struct prefix *prefix)
-{
- char buffer[100];
-
- lua_newtable(L);
- lua_pushstring(L, prefix2str(prefix, buffer, 100));
- lua_setfield(L, -2, "route");
- lua_pushinteger(L, prefix->family);
- lua_setfield(L, -2, "family");
- lua_setglobal(L, "prefix");
-}
-
-enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule)
-{
- int status;
-
- lua_getglobal(L, rule);
- status = lua_pcall(L, 0, 1, 0);
- if (status) {
- zlog_debug("Executing Failure with function: %s: %d",
- rule, status);
- return LUA_RM_FAILURE;
- }
-
- status = lua_tonumber(L, -1);
- return status;
-}
-#endif
+++ /dev/null
-/*
- * This file defines the lua interface into
- * FRRouting.
- *
- * Copyright (C) 2016 Cumulus Networks, Inc.
- * Donald Sharp
- *
- * This file is part of FreeRangeRouting (FRR).
- *
- * FRR is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2, or (at your option) any later version.
- *
- * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along
- * with FRR; see the file COPYING. If not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-#ifndef __LUA_H__
-#define __LUA_H__
-
-#if defined(HAVE_LUA)
-
-#include <lua.h>
-#include <lualib.h>
-#include <lauxlib.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * These functions are helper functions that
- * try to glom some of the lua_XXX functionality
- * into what we actually need, instead of having
- * to make multiple calls to set up what
- * we want
- */
-enum lua_rm_status {
- /*
- * Script function run failure. This will translate into a
- * deny
- */
- LUA_RM_FAILURE = 0,
- /*
- * No Match was found for the route map function
- */
- LUA_RM_NOMATCH,
- /*
- * Match was found but no changes were made to the
- * incoming data.
- */
- LUA_RM_MATCH,
- /*
- * Match was found and data was modified, so
- * figure out what changed
- */
- LUA_RM_MATCH_AND_CHANGE,
-};
-
-/*
- * Open up the lua.scr file and parse
- * initial global values, if any.
- */
-lua_State *lua_initialize(const char *file);
-
-void lua_setup_prefix_table(lua_State *L, const struct prefix *prefix);
-
-enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule);
-
-/*
- * Get particular string/integer information
- * from a table. It is *assumed* that
- * the table has already been selected
- */
-const char *get_string(lua_State *L, const char *key);
-int get_integer(lua_State *L, const char *key);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-#endif
return strmatch(c1->xpath, c2->xpath);
}
-static unsigned int running_config_entry_key_make(void *value)
+static unsigned int running_config_entry_key_make(const void *value)
{
return string_hash_make(value);
}
}
/* Finds the node with the same key as elm */
-void *_rb_find(const struct rb_type *t, struct rbt_tree *rbt, const void *key)
+void *_rb_find(const struct rb_type *t, const struct rbt_tree *rbt,
+ const void *key)
{
struct rb_entry *tmp = RBH_ROOT(rbt);
void *node;
}
/* Finds the first node greater than or equal to the search key */
-void *_rb_nfind(const struct rb_type *t, struct rbt_tree *rbt, const void *key)
+void *_rb_nfind(const struct rb_type *t, const struct rbt_tree *rbt,
+ const void *key)
{
struct rb_entry *tmp = RBH_ROOT(rbt);
void *node;
return (rbe == NULL ? NULL : rb_e2n(t, rbe));
}
-void *_rb_root(const struct rb_type *t, struct rbt_tree *rbt)
+void *_rb_root(const struct rb_type *t, const struct rbt_tree *rbt)
{
struct rb_entry *rbe = RBH_ROOT(rbt);
return (rbe == NULL ? rbe : rb_e2n(t, rbe));
}
-void *_rb_min(const struct rb_type *t, struct rbt_tree *rbt)
+void *_rb_min(const struct rb_type *t, const struct rbt_tree *rbt)
{
struct rb_entry *rbe = RBH_ROOT(rbt);
struct rb_entry *parent = NULL;
return (parent == NULL ? NULL : rb_e2n(t, parent));
}
-void *_rb_max(const struct rb_type *t, struct rbt_tree *rbt)
+void *_rb_max(const struct rb_type *t, const struct rbt_tree *rbt)
{
struct rb_entry *rbe = RBH_ROOT(rbt);
struct rb_entry *parent = NULL;
rbt->rbt_root = NULL;
}
-static inline int _rb_empty(struct rbt_tree *rbt)
+static inline int _rb_empty(const struct rbt_tree *rbt)
{
return (rbt->rbt_root == NULL);
}
void *_rb_insert(const struct rb_type *, struct rbt_tree *, void *);
void *_rb_remove(const struct rb_type *, struct rbt_tree *, void *);
-void *_rb_find(const struct rb_type *, struct rbt_tree *, const void *);
-void *_rb_nfind(const struct rb_type *, struct rbt_tree *, const void *);
-void *_rb_root(const struct rb_type *, struct rbt_tree *);
-void *_rb_min(const struct rb_type *, struct rbt_tree *);
-void *_rb_max(const struct rb_type *, struct rbt_tree *);
+void *_rb_find(const struct rb_type *, const struct rbt_tree *, const void *);
+void *_rb_nfind(const struct rb_type *, const struct rbt_tree *, const void *);
+void *_rb_root(const struct rb_type *, const struct rbt_tree *);
+void *_rb_min(const struct rb_type *, const struct rbt_tree *);
+void *_rb_max(const struct rb_type *, const struct rbt_tree *);
void *_rb_next(const struct rb_type *, void *);
void *_rb_prev(const struct rb_type *, void *);
void *_rb_left(const struct rb_type *, void *);
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_INSERT(struct _name *head, struct _type *elm) \
{ \
- return (struct _type *)_rb_insert( \
- _name##_RB_TYPE, &head->rbh_root, elm); \
+ return (struct _type *)_rb_insert(_name##_RB_TYPE, \
+ &head->rbh_root, elm); \
} \
\
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_REMOVE(struct _name *head, struct _type *elm) \
{ \
- return (struct _type *)_rb_remove( \
- _name##_RB_TYPE, &head->rbh_root, elm); \
+ return (struct _type *)_rb_remove(_name##_RB_TYPE, \
+ &head->rbh_root, elm); \
} \
\
__attribute__((__unused__)) static inline struct _type \
- *_name##_RB_FIND(struct _name *head, const struct _type *key) \
+ *_name##_RB_FIND(const struct _name *head, \
+ const struct _type *key) \
{ \
- return (struct _type *)_rb_find( \
- _name##_RB_TYPE, &head->rbh_root, key); \
+ return (struct _type *)_rb_find(_name##_RB_TYPE, \
+ &head->rbh_root, key); \
} \
\
__attribute__((__unused__)) static inline struct _type \
- *_name##_RB_NFIND(struct _name *head, const struct _type *key) \
+ *_name##_RB_NFIND(const struct _name *head, \
+ const struct _type *key) \
{ \
- return (struct _type *)_rb_nfind( \
- _name##_RB_TYPE, &head->rbh_root, key); \
+ return (struct _type *)_rb_nfind(_name##_RB_TYPE, \
+ &head->rbh_root, key); \
} \
\
__attribute__((__unused__)) static inline struct _type \
- *_name##_RB_ROOT(struct _name *head) \
+ *_name##_RB_ROOT(const struct _name *head) \
{ \
- return (struct _type *)_rb_root( \
- _name##_RB_TYPE, &head->rbh_root); \
+ return (struct _type *)_rb_root(_name##_RB_TYPE, \
+ &head->rbh_root); \
} \
\
__attribute__((__unused__)) static inline int _name##_RB_EMPTY( \
- struct _name *head) \
+ const struct _name *head) \
{ \
return _rb_empty(&head->rbh_root); \
} \
\
__attribute__((__unused__)) static inline struct _type \
- *_name##_RB_MIN(struct _name *head) \
+ *_name##_RB_MIN(const struct _name *head) \
{ \
- return (struct _type *)_rb_min( \
- _name##_RB_TYPE, &head->rbh_root); \
+ return (struct _type *)_rb_min(_name##_RB_TYPE, \
+ &head->rbh_root); \
} \
\
__attribute__((__unused__)) static inline struct _type \
- *_name##_RB_MAX(struct _name *head) \
+ *_name##_RB_MAX(const struct _name *head) \
{ \
- return (struct _type *)_rb_max( \
- _name##_RB_TYPE, &head->rbh_root); \
+ return (struct _type *)_rb_max(_name##_RB_TYPE, \
+ &head->rbh_root); \
} \
\
__attribute__((__unused__)) static inline struct _type \
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);
void (*add_hook)(const char *);
void (*delete_hook)(const char *);
- void (*event_hook)(route_map_event_t, const char *);
+ void (*event_hook)(const char *);
};
/* Master list of route map. */
static struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL};
struct hash *route_map_master_hash = NULL;
-static unsigned int route_map_hash_key_make(void *p)
+static unsigned int route_map_hash_key_make(const void *p)
{
const struct route_map *map = p;
return string_hash_make(map->name);
/* Hashes maintaining dependency between various sublists used by route maps */
struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
-static unsigned int route_map_dep_hash_make_key(void *p);
+static unsigned int route_map_dep_hash_make_key(const void *p);
static void route_map_clear_all_references(char *rmap_name);
static void route_map_rule_delete(struct route_map_rule_list *,
struct route_map_rule *);
case RMAP_DENY:
return "deny";
break;
- default:
+ case RMAP_ANY:
return "";
break;
}
/* Execute event hook. */
if (route_map_master.event_hook && notify) {
- (*route_map_master.event_hook)(RMAP_EVENT_INDEX_DELETED,
- index->map->name);
+ (*route_map_master.event_hook)(index->map->name);
route_map_notify_dependencies(index->map->name,
RMAP_EVENT_CALL_ADDED);
}
/* Execute event hook. */
if (route_map_master.event_hook) {
- (*route_map_master.event_hook)(RMAP_EVENT_INDEX_ADDED,
- map->name);
+ (*route_map_master.event_hook)(map->name);
route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
}
return index;
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;
}
/* Execute event hook. */
if (route_map_master.event_hook) {
- (*route_map_master.event_hook)(
- replaced ? RMAP_EVENT_MATCH_REPLACED
- : RMAP_EVENT_MATCH_ADDED,
- index->map->name);
+ (*route_map_master.event_hook)(index->map->name);
route_map_notify_dependencies(index->map->name,
RMAP_EVENT_CALL_ADDED);
}
route_map_rule_delete(&index->match_list, rule);
/* Execute event hook. */
if (route_map_master.event_hook) {
- (*route_map_master.event_hook)(
- RMAP_EVENT_MATCH_DELETED,
- index->map->name);
+ (*route_map_master.event_hook)(index->map->name);
route_map_notify_dependencies(
index->map->name,
RMAP_EVENT_CALL_ADDED);
/* Execute event hook. */
if (route_map_master.event_hook) {
- (*route_map_master.event_hook)(replaced
- ? RMAP_EVENT_SET_REPLACED
- : RMAP_EVENT_SET_ADDED,
- index->map->name);
+ (*route_map_master.event_hook)(index->map->name);
route_map_notify_dependencies(index->map->name,
RMAP_EVENT_CALL_ADDED);
}
route_map_rule_delete(&index->set_list, rule);
/* Execute event hook. */
if (route_map_master.event_hook) {
- (*route_map_master.event_hook)(
- RMAP_EVENT_SET_DELETED,
- index->map->name);
+ (*route_map_master.event_hook)(index->map->name);
route_map_notify_dependencies(
index->map->name,
RMAP_EVENT_CALL_ADDED);
route_map_master.delete_hook = func;
}
-void route_map_event_hook(void (*func)(route_map_event_t, const char *))
+void route_map_event_hook(void (*func)(const char *name))
{
route_map_master.event_hook = func;
}
return ((void *)XSTRDUP(MTYPE_ROUTE_MAP_NAME, (const char *)p));
}
-static unsigned int route_map_dep_hash_make_key(void *p)
+static unsigned int route_map_dep_hash_make_key(const void *p)
{
return (string_hash_make((char *)p));
}
dep = NULL;
}
break;
- default:
+ case RMAP_EVENT_SET_ADDED:
+ case RMAP_EVENT_SET_DELETED:
+ case RMAP_EVENT_SET_REPLACED:
+ case RMAP_EVENT_MATCH_ADDED:
+ case RMAP_EVENT_MATCH_DELETED:
+ case RMAP_EVENT_MATCH_REPLACED:
+ case RMAP_EVENT_INDEX_ADDED:
+ case RMAP_EVENT_INDEX_DELETED:
break;
}
break;
case RMAP_EVENT_CALL_ADDED:
case RMAP_EVENT_CALL_DELETED:
+ case RMAP_EVENT_MATCH_ADDED:
+ case RMAP_EVENT_MATCH_DELETED:
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
break;
case RMAP_EVENT_FILTER_ADDED:
case RMAP_EVENT_FILTER_DELETED:
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER];
break;
- default:
+ /*
+ * Should we actually be ignoring these?
+ * I am not sure but at this point in time, let
+ * us get them into this switch and we can peel
+ * them into the appropriate place in the future
+ */
+ case RMAP_EVENT_SET_ADDED:
+ case RMAP_EVENT_SET_DELETED:
+ case RMAP_EVENT_SET_REPLACED:
+ case RMAP_EVENT_MATCH_REPLACED:
+ case RMAP_EVENT_INDEX_ADDED:
+ case RMAP_EVENT_INDEX_DELETED:
upd8_hash = NULL;
break;
}
static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
{
char *rmap_name = (char *)bucket->data;
- route_map_event_t type = (route_map_event_t)(ptrdiff_t)data;
if (rmap_debug)
zlog_debug("%s: Notifying %s of dependency",
__FUNCTION__, rmap_name);
if (route_map_master.event_hook)
- (*route_map_master.event_hook)(type, rmap_name);
+ (*route_map_master.event_hook)(rmap_name);
}
void route_map_upd8_dependency(route_map_event_t type, const char *arg,
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);
extern void route_map_add_hook(void (*func)(const char *));
extern void route_map_delete_hook(void (*func)(const char *));
-extern void route_map_event_hook(void (*func)(route_map_event_t, const char *));
+
+/*
+ * This is the callback for when something has changed about a
+ * route-map. The interested parties can register to receive
+ * this data.
+ *
+ * name - Is the name of the changed route-map
+ */
+extern void route_map_event_hook(void (*func)(const char *name));
extern int route_map_mark_updated(const char *name);
extern void route_map_walk_update_list(void (*update_fn)(char *name));
extern void route_map_upd8_dependency(route_map_event_t type, const char *arg,
#
lib_LTLIBRARIES += lib/libfrr.la
lib_libfrr_la_LDFLAGS = -version-info 0:0:0 -Xlinker -e_libfrr_version
-lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS)
+lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB)
lib_libfrr_la_SOURCES = \
lib/agg_table.c \
lib/distribute.c \
lib/ferr.c \
lib/filter.c \
+ lib/frrlua.c \
lib/frr_pthread.c \
lib/frrstr.c \
lib/getopt.c \
lib/yang_wrappers.c \
lib/zclient.c \
lib/logicalrouter.c \
- lib/lua.c \
# end
nodist_lib_libfrr_la_SOURCES = \
lib/ferr.h \
lib/filter.h \
lib/freebsd-queue.h \
+ lib/frrlua.h \
lib/frr_pthread.h \
lib/frratomic.h \
lib/frrstr.h \
lib/zclient.h \
lib/zebra.h \
lib/logicalrouter.h \
- lib/lua.h \
lib/pbr.h \
# end
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; \
static void thread_free(struct thread_master *master, struct thread *thread);
/* CLI start ---------------------------------------------------------------- */
-static unsigned int cpu_record_hash_key(struct cpu_thread_history *a)
+static unsigned int cpu_record_hash_key(const struct cpu_thread_history *a)
{
int size = sizeof(a->func);
sizeof(struct thread *) * rv->fd_limit);
rv->cpu_record = hash_create_size(
- 8, (unsigned int (*)(void *))cpu_record_hash_key,
+ 8, (unsigned int (*)(const void *))cpu_record_hash_key,
(bool (*)(const void *, const void *))cpu_record_hash_cmp,
"Thread Hash");
#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); \
bool set;
};
-static unsigned int vrf_hash_bitmap_key(void *data)
+static unsigned int vrf_hash_bitmap_key(const void *data)
{
- struct vrf_bit_set *bit = data;
+ const struct vrf_bit_set *bit = data;
return bit->vrf_id;
}
int vrf_bind(vrf_id_t vrf_id, int fd, const char *name)
{
int ret = 0;
+ struct interface *ifp;
if (fd < 0 || name == NULL)
return fd;
- if (vrf_is_backend_netns())
+ /* the device should exist
+ * otherwise we should return
+ * case ifname = vrf in netns mode => return
+ */
+ ifp = if_lookup_by_name(name, vrf_id);
+ if (!ifp)
return fd;
#ifdef SO_BINDTODEVICE
ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name)+1);
}
struct timer_wheel *wheel_init(struct thread_master *master, int period,
- size_t slots, unsigned int (*slot_key)(void *),
+ size_t slots, unsigned int (*slot_key)(const void *),
void (*slot_run)(void *),
const char *run_name)
{
/*
* Key to determine what slot the item belongs in
*/
- unsigned int (*slot_key)(void *);
+ unsigned int (*slot_key)(const void *);
void (*slot_run)(void *);
};
* of running your code.
*/
struct timer_wheel *wheel_init(struct thread_master *master, int period,
- size_t slots, unsigned int (*slot_key)(void *),
- void (*slot_run)(void *),
- const char *run_name);
+ size_t slots,
+ unsigned int (*slot_key)(const void *),
+ void (*slot_run)(void *), const char *run_name);
/*
* Delete the specified timer wheel created
return strmatch(c1->xpath_from_canonical, c2->xpath_from_canonical);
}
-static unsigned int yang_mapping_hash_key(void *value)
+static unsigned int yang_mapping_hash_key(const void *value)
{
return string_hash_make(value);
}
#endif
/* Address family numbers from RFC1700. */
-typedef enum { AFI_IP = 1, AFI_IP6 = 2, AFI_L2VPN = 3, AFI_MAX = 4 } afi_t;
+typedef enum {
+ AFI_UNSPEC = 0,
+ AFI_IP = 1,
+ AFI_IP6 = 2,
+ AFI_L2VPN = 3,
+ AFI_MAX = 4
+} afi_t;
/* Subsequent Address Family Identifier. */
typedef enum {
--- /dev/null
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_lua.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
+# AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
+# AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
+# AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
+#
+# DESCRIPTION
+#
+# Detect a Lua interpreter, optionally specifying a minimum and maximum
+# version number. Set up important Lua paths, such as the directories in
+# which to install scripts and modules (shared libraries).
+#
+# Also detect Lua headers and libraries. The Lua version contained in the
+# header is checked to match the Lua interpreter version exactly. When
+# searching for Lua libraries, the version number is used as a suffix.
+# This is done with the goal of supporting multiple Lua installs (5.1,
+# 5.2, and 5.3 side-by-side).
+#
+# A note on compatibility with previous versions: This file has been
+# mostly rewritten for serial 18. Most developers should be able to use
+# these macros without needing to modify configure.ac. Care has been taken
+# to preserve each macro's behavior, but there are some differences:
+#
+# 1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as
+# AX_PROG_LUA with no arguments.
+#
+# 2) AX_LUA_HEADERS now checks that the version number defined in lua.h
+# matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore
+# unnecessary, so it is deprecated and does not expand to anything.
+#
+# 3) The configure flag --with-lua-suffix no longer exists; the user
+# should instead specify the LUA precious variable on the command line.
+# See the AX_PROG_LUA description for details.
+#
+# Please read the macro descriptions below for more information.
+#
+# This file was inspired by Andrew Dalke's and James Henstridge's
+# python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4
+# (serial 17). Basically, this file is a mash-up of those two files. I
+# like to think it combines the best of the two!
+#
+# AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua
+# paths. Adds precious variable LUA, which may contain the path of the Lua
+# interpreter. If LUA is blank, the user's path is searched for an
+# suitable interpreter.
+#
+# If MINIMUM-VERSION is supplied, then only Lua interpreters with a
+# version number greater or equal to MINIMUM-VERSION will be accepted. If
+# TOO-BIG-VERSION is also supplied, then only Lua interpreters with a
+# version number greater or equal to MINIMUM-VERSION and less than
+# TOO-BIG-VERSION will be accepted.
+#
+# The Lua version number, LUA_VERSION, is found from the interpreter, and
+# substituted. LUA_PLATFORM is also found, but not currently supported (no
+# standard representation).
+#
+# Finally, the macro finds four paths:
+#
+# luadir Directory to install Lua scripts.
+# pkgluadir $luadir/$PACKAGE
+# luaexecdir Directory to install Lua modules.
+# pkgluaexecdir $luaexecdir/$PACKAGE
+#
+# These paths are found based on $prefix, $exec_prefix, Lua's
+# package.path, and package.cpath. The first path of package.path
+# beginning with $prefix is selected as luadir. The first path of
+# package.cpath beginning with $exec_prefix is used as luaexecdir. This
+# should work on all reasonable Lua installations. If a path cannot be
+# determined, a default path is used. Of course, the user can override
+# these later when invoking make.
+#
+# luadir Default: $prefix/share/lua/$LUA_VERSION
+# luaexecdir Default: $exec_prefix/lib/lua/$LUA_VERSION
+#
+# These directories can be used by Automake as install destinations. The
+# variable name minus 'dir' needs to be used as a prefix to the
+# appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES.
+#
+# If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is
+# performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT-
+# FOUND is blank, then it will default to printing an error. To prevent
+# the default behavior, give ':' as an action.
+#
+# AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be
+# expanded before this macro. Adds precious variable LUA_INCLUDE, which
+# may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If
+# LUA_INCLUDE is blank, then this macro will attempt to find suitable
+# flags.
+#
+# LUA_INCLUDE can be used by Automake to compile Lua modules or
+# executables with embedded interpreters. The *_CPPFLAGS variables should
+# be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE).
+#
+# This macro searches for the header lua.h (and others). The search is
+# performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE.
+# If the search is unsuccessful, then some common directories are tried.
+# If the headers are then found, then LUA_INCLUDE is set accordingly.
+#
+# The paths automatically searched are:
+#
+# * /usr/include/luaX.Y
+# * /usr/include/lua/X.Y
+# * /usr/include/luaXY
+# * /usr/local/include/luaX.Y
+# * /usr/local/include/lua-X.Y
+# * /usr/local/include/lua/X.Y
+# * /usr/local/include/luaXY
+#
+# (Where X.Y is the Lua version number, e.g. 5.1.)
+#
+# The Lua version number found in the headers is always checked to match
+# the Lua interpreter's version number. Lua headers with mismatched
+# version numbers are not accepted.
+#
+# If headers are found, then ACTION-IF-FOUND is performed, otherwise
+# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then
+# it will default to printing an error. To prevent the default behavior,
+# set the action to ':'.
+#
+# AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be
+# expanded before this macro. Adds precious variable LUA_LIB, which may
+# contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank,
+# then this macro will attempt to find suitable flags.
+#
+# LUA_LIB can be used by Automake to link Lua modules or executables with
+# embedded interpreters. The *_LIBADD and *_LDADD variables should be used
+# for this purpose, e.g. mymod_LIBADD = $(LUA_LIB).
+#
+# This macro searches for the Lua library. More technically, it searches
+# for a library containing the function lua_load. The search is performed
+# with a combination of LIBS, LIBRARY_PATH, and LUA_LIB.
+#
+# If the search determines that some linker flags are missing, then those
+# flags will be added to LUA_LIB.
+#
+# If libraries are found, then ACTION-IF-FOUND is performed, otherwise
+# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then
+# it will default to printing an error. To prevent the default behavior,
+# set the action to ':'.
+#
+# AX_LUA_READLINE: Search for readline headers and libraries. Requires the
+# AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the
+# Autoconf Archive.
+#
+# If a readline compatible library is found, then ACTION-IF-FOUND is
+# performed, otherwise ACTION-IF-NOT-FOUND is performed.
+#
+# LICENSE
+#
+# Copyright (c) 2015 Reuben Thomas <rrt@sc3d.org>
+# Copyright (c) 2014 Tim Perkins <tprk77@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 39
+
+dnl =========================================================================
+dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION],
+dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl =========================================================================
+AC_DEFUN([AX_PROG_LUA],
+[
+ dnl Check for required tools.
+ AC_REQUIRE([AC_PROG_GREP])
+ AC_REQUIRE([AC_PROG_SED])
+
+ dnl Make LUA a precious variable.
+ AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1])
+
+ dnl Find a Lua interpreter.
+ m4_define_default([_AX_LUA_INTERPRETER_LIST],
+ [lua lua5.3 lua53 lua5.2 lua52 lua5.1 lua51 lua50])
+
+ m4_if([$1], [],
+ [ dnl No version check is needed. Find any Lua interpreter.
+ AS_IF([test "x$LUA" = 'x'],
+ [AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])])
+ ax_display_LUA='lua'
+
+ AS_IF([test "x$LUA" != 'x:'],
+ [ dnl At least check if this is a Lua interpreter.
+ AC_MSG_CHECKING([if $LUA is a Lua interpreter])
+ _AX_LUA_CHK_IS_INTRP([$LUA],
+ [AC_MSG_RESULT([yes])],
+ [ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([not a Lua interpreter])
+ ])
+ ])
+ ],
+ [ dnl A version check is needed.
+ AS_IF([test "x$LUA" != 'x'],
+ [ dnl Check if this is a Lua interpreter.
+ AC_MSG_CHECKING([if $LUA is a Lua interpreter])
+ _AX_LUA_CHK_IS_INTRP([$LUA],
+ [AC_MSG_RESULT([yes])],
+ [ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([not a Lua interpreter])
+ ])
+ dnl Check the version.
+ m4_if([$2], [],
+ [_ax_check_text="whether $LUA version >= $1"],
+ [_ax_check_text="whether $LUA version >= $1, < $2"])
+ AC_MSG_CHECKING([$_ax_check_text])
+ _AX_LUA_CHK_VER([$LUA], [$1], [$2],
+ [AC_MSG_RESULT([yes])],
+ [ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([version is out of range for specified LUA])])
+ ax_display_LUA=$LUA
+ ],
+ [ dnl Try each interpreter until we find one that satisfies VERSION.
+ m4_if([$2], [],
+ [_ax_check_text="for a Lua interpreter with version >= $1"],
+ [_ax_check_text="for a Lua interpreter with version >= $1, < $2"])
+ AC_CACHE_CHECK([$_ax_check_text],
+ [ax_cv_pathless_LUA],
+ [ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do
+ test "x$ax_cv_pathless_LUA" = 'xnone' && break
+ _AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue])
+ _AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break])
+ done
+ ])
+ dnl Set $LUA to the absolute path of $ax_cv_pathless_LUA.
+ AS_IF([test "x$ax_cv_pathless_LUA" = 'xnone'],
+ [LUA=':'],
+ [AC_PATH_PROG([LUA], [$ax_cv_pathless_LUA])])
+ ax_display_LUA=$ax_cv_pathless_LUA
+ ])
+ ])
+
+ AS_IF([test "x$LUA" = 'x:'],
+ [ dnl Run any user-specified action, or abort.
+ m4_default([$4], [AC_MSG_ERROR([cannot find suitable Lua interpreter])])
+ ],
+ [ dnl Query Lua for its version number.
+ AC_CACHE_CHECK([for $ax_display_LUA version],
+ [ax_cv_lua_version],
+ [ dnl Get the interpreter version in X.Y format. This should work for
+ dnl interpreters version 5.0 and beyond.
+ ax_cv_lua_version=[`$LUA -e '
+ -- return a version number in X.Y format
+ local _, _, ver = string.find(_VERSION, "^Lua (%d+%.%d+)")
+ print(ver)'`]
+ ])
+ AS_IF([test "x$ax_cv_lua_version" = 'x'],
+ [AC_MSG_ERROR([invalid Lua version number])])
+ AC_SUBST([LUA_VERSION], [$ax_cv_lua_version])
+ AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | $SED 's|\.||'`])
+
+ dnl The following check is not supported:
+ dnl At times (like when building shared libraries) you may want to know
+ dnl which OS platform Lua thinks this is.
+ AC_CACHE_CHECK([for $ax_display_LUA platform],
+ [ax_cv_lua_platform],
+ [ax_cv_lua_platform=[`$LUA -e 'print("unknown")'`]])
+ AC_SUBST([LUA_PLATFORM], [$ax_cv_lua_platform])
+
+ dnl Use the values of $prefix and $exec_prefix for the corresponding
+ dnl values of LUA_PREFIX and LUA_EXEC_PREFIX. These are made distinct
+ dnl variables so they can be overridden if need be. However, the general
+ dnl consensus is that you shouldn't need this ability.
+ AC_SUBST([LUA_PREFIX], ['${prefix}'])
+ AC_SUBST([LUA_EXEC_PREFIX], ['${exec_prefix}'])
+
+ dnl Lua provides no way to query the script directory, and instead
+ dnl provides LUA_PATH. However, we should be able to make a safe educated
+ dnl guess. If the built-in search path contains a directory which is
+ dnl prefixed by $prefix, then we can store scripts there. The first
+ dnl matching path will be used.
+ AC_CACHE_CHECK([for $ax_display_LUA script directory],
+ [ax_cv_lua_luadir],
+ [ AS_IF([test "x$prefix" = 'xNONE'],
+ [ax_lua_prefix=$ac_default_prefix],
+ [ax_lua_prefix=$prefix])
+
+ dnl Initialize to the default path.
+ ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION"
+
+ dnl Try to find a path with the prefix.
+ _AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_prefix], [script])
+ AS_IF([test "x$ax_lua_prefixed_path" != 'x'],
+ [ dnl Fix the prefix.
+ _ax_strip_prefix=`echo "$ax_lua_prefix" | $SED 's|.|.|g'`
+ ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \
+ $SED "s|^$_ax_strip_prefix|$LUA_PREFIX|"`
+ ])
+ ])
+ AC_SUBST([luadir], [$ax_cv_lua_luadir])
+ AC_SUBST([pkgluadir], [\${luadir}/$PACKAGE])
+
+ dnl Lua provides no way to query the module directory, and instead
+ dnl provides LUA_PATH. However, we should be able to make a safe educated
+ dnl guess. If the built-in search path contains a directory which is
+ dnl prefixed by $exec_prefix, then we can store modules there. The first
+ dnl matching path will be used.
+ AC_CACHE_CHECK([for $ax_display_LUA module directory],
+ [ax_cv_lua_luaexecdir],
+ [ AS_IF([test "x$exec_prefix" = 'xNONE'],
+ [ax_lua_exec_prefix=$ax_lua_prefix],
+ [ax_lua_exec_prefix=$exec_prefix])
+
+ dnl Initialize to the default path.
+ ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION"
+
+ dnl Try to find a path with the prefix.
+ _AX_LUA_FND_PRFX_PTH([$LUA],
+ [$ax_lua_exec_prefix], [module])
+ AS_IF([test "x$ax_lua_prefixed_path" != 'x'],
+ [ dnl Fix the prefix.
+ _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | $SED 's|.|.|g'`
+ ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \
+ $SED "s|^$_ax_strip_prefix|$LUA_EXEC_PREFIX|"`
+ ])
+ ])
+ AC_SUBST([luaexecdir], [$ax_cv_lua_luaexecdir])
+ AC_SUBST([pkgluaexecdir], [\${luaexecdir}/$PACKAGE])
+
+ dnl Run any user specified action.
+ $3
+ ])
+])
+
+dnl AX_WITH_LUA is now the same thing as AX_PROG_LUA.
+AC_DEFUN([AX_WITH_LUA],
+[
+ AC_MSG_WARN([[$0 is deprecated, please use AX_PROG_LUA instead]])
+ AX_PROG_LUA
+])
+
+
+dnl =========================================================================
+dnl _AX_LUA_CHK_IS_INTRP(PROG, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+dnl =========================================================================
+AC_DEFUN([_AX_LUA_CHK_IS_INTRP],
+[
+ dnl A minimal Lua factorial to prove this is an interpreter. This should work
+ dnl for Lua interpreters version 5.0 and beyond.
+ _ax_lua_factorial=[`$1 2>/dev/null -e '
+ -- a simple factorial
+ function fact (n)
+ if n == 0 then
+ return 1
+ else
+ return n * fact(n-1)
+ end
+ end
+ print("fact(5) is " .. fact(5))'`]
+ AS_IF([test "$_ax_lua_factorial" = 'fact(5) is 120'],
+ [$2], [$3])
+])
+
+
+dnl =========================================================================
+dnl _AX_LUA_CHK_VER(PROG, MINIMUM-VERSION, [TOO-BIG-VERSION],
+dnl [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+dnl =========================================================================
+AC_DEFUN([_AX_LUA_CHK_VER],
+[
+ dnl Check that the Lua version is within the bounds. Only the major and minor
+ dnl version numbers are considered. This should work for Lua interpreters
+ dnl version 5.0 and beyond.
+ _ax_lua_good_version=[`$1 -e '
+ -- a script to compare versions
+ function verstr2num(verstr)
+ local _, _, majorver, minorver = string.find(verstr, "^(%d+)%.(%d+)")
+ if majorver and minorver then
+ return tonumber(majorver) * 100 + tonumber(minorver)
+ end
+ end
+ local minver = verstr2num("$2")
+ local _, _, trimver = string.find(_VERSION, "^Lua (.*)")
+ local ver = verstr2num(trimver)
+ local maxver = verstr2num("$3") or 1e9
+ if minver <= ver and ver < maxver then
+ print("yes")
+ else
+ print("no")
+ end'`]
+ AS_IF([test "x$_ax_lua_good_version" = "xyes"],
+ [$4], [$5])
+])
+
+
+dnl =========================================================================
+dnl _AX_LUA_FND_PRFX_PTH(PROG, PREFIX, SCRIPT-OR-MODULE-DIR)
+dnl =========================================================================
+AC_DEFUN([_AX_LUA_FND_PRFX_PTH],
+[
+ dnl Get the script or module directory by querying the Lua interpreter,
+ dnl filtering on the given prefix, and selecting the shallowest path. If no
+ dnl path is found matching the prefix, the result will be an empty string.
+ dnl The third argument determines the type of search, it can be 'script' or
+ dnl 'module'. Supplying 'script' will perform the search with package.path
+ dnl and LUA_PATH, and supplying 'module' will search with package.cpath and
+ dnl LUA_CPATH. This is done for compatibility with Lua 5.0.
+
+ ax_lua_prefixed_path=[`$1 -e '
+ -- get the path based on search type
+ local searchtype = "$3"
+ local paths = ""
+ if searchtype == "script" then
+ paths = (package and package.path) or LUA_PATH
+ elseif searchtype == "module" then
+ paths = (package and package.cpath) or LUA_CPATH
+ end
+ -- search for the prefix
+ local prefix = "'$2'"
+ local minpath = ""
+ local mindepth = 1e9
+ string.gsub(paths, "(@<:@^;@:>@+)",
+ function (path)
+ path = string.gsub(path, "%?.*$", "")
+ path = string.gsub(path, "/@<:@^/@:>@*$", "")
+ if string.find(path, prefix) then
+ local depth = string.len(string.gsub(path, "@<:@^/@:>@", ""))
+ if depth < mindepth then
+ minpath = path
+ mindepth = depth
+ end
+ end
+ end)
+ print(minpath)'`]
+])
+
+
+dnl =========================================================================
+dnl AX_LUA_HEADERS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl =========================================================================
+AC_DEFUN([AX_LUA_HEADERS],
+[
+ dnl Check for LUA_VERSION.
+ AC_MSG_CHECKING([if LUA_VERSION is defined])
+ AS_IF([test "x$LUA_VERSION" != 'x'],
+ [AC_MSG_RESULT([yes])],
+ [ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION])
+ ])
+
+ dnl Make LUA_INCLUDE a precious variable.
+ AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1])
+
+ dnl Some default directories to search.
+ LUA_SHORT_VERSION=`echo "$LUA_VERSION" | $SED 's|\.||'`
+ m4_define_default([_AX_LUA_INCLUDE_LIST],
+ [ /usr/include/lua$LUA_VERSION \
+ /usr/include/lua-$LUA_VERSION \
+ /usr/include/lua/$LUA_VERSION \
+ /usr/include/lua$LUA_SHORT_VERSION \
+ /usr/local/include/lua$LUA_VERSION \
+ /usr/local/include/lua-$LUA_VERSION \
+ /usr/local/include/lua/$LUA_VERSION \
+ /usr/local/include/lua$LUA_SHORT_VERSION \
+ ])
+
+ dnl Try to find the headers.
+ _ax_lua_saved_cppflags=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
+ AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
+ CPPFLAGS=$_ax_lua_saved_cppflags
+
+ dnl Try some other directories if LUA_INCLUDE was not set.
+ AS_IF([test "x$LUA_INCLUDE" = 'x' &&
+ test "x$ac_cv_header_lua_h" != 'xyes'],
+ [ dnl Try some common include paths.
+ for _ax_include_path in _AX_LUA_INCLUDE_LIST; do
+ test ! -d "$_ax_include_path" && continue
+
+ AC_MSG_CHECKING([for Lua headers in])
+ AC_MSG_RESULT([$_ax_include_path])
+
+ AS_UNSET([ac_cv_header_lua_h])
+ AS_UNSET([ac_cv_header_lualib_h])
+ AS_UNSET([ac_cv_header_lauxlib_h])
+ AS_UNSET([ac_cv_header_luaconf_h])
+
+ _ax_lua_saved_cppflags=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS -I$_ax_include_path"
+ AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
+ CPPFLAGS=$_ax_lua_saved_cppflags
+
+ AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'],
+ [ LUA_INCLUDE="-I$_ax_include_path"
+ break
+ ])
+ done
+ ])
+
+ AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'],
+ [ dnl Make a program to print LUA_VERSION defined in the header.
+ dnl TODO It would be really nice if we could do this without compiling a
+ dnl program, then it would work when cross compiling. But I'm not sure how
+ dnl to do this reliably. For now, assume versions match when cross compiling.
+
+ AS_IF([test "x$cross_compiling" != 'xyes'],
+ [ AC_CACHE_CHECK([for Lua header version],
+ [ax_cv_lua_header_version],
+ [ _ax_lua_saved_cppflags=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
+ AC_RUN_IFELSE(
+ [ AC_LANG_SOURCE([[
+#include <lua.h>
+#include <stdlib.h>
+#include <stdio.h>
+int main(int argc, char ** argv)
+{
+ if(argc > 1) printf("%s", LUA_VERSION);
+ exit(EXIT_SUCCESS);
+}
+]])
+ ],
+ [ ax_cv_lua_header_version=`./conftest$EXEEXT p | \
+ $SED -n "s|^Lua \(@<:@0-9@:>@\{1,\}\.@<:@0-9@:>@\{1,\}\).\{0,\}|\1|p"`
+ ],
+ [ax_cv_lua_header_version='unknown'])
+ CPPFLAGS=$_ax_lua_saved_cppflags
+ ])
+
+ dnl Compare this to the previously found LUA_VERSION.
+ AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION])
+ AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"],
+ [ AC_MSG_RESULT([yes])
+ ax_header_version_match='yes'
+ ],
+ [ AC_MSG_RESULT([no])
+ ax_header_version_match='no'
+ ])
+ ],
+ [ AC_MSG_WARN([cross compiling so assuming header version number matches])
+ ax_header_version_match='yes'
+ ])
+ ])
+
+ dnl Was LUA_INCLUDE specified?
+ AS_IF([test "x$ax_header_version_match" != 'xyes' &&
+ test "x$LUA_INCLUDE" != 'x'],
+ [AC_MSG_ERROR([cannot find headers for specified LUA_INCLUDE])])
+
+ dnl Test the final result and run user code.
+ AS_IF([test "x$ax_header_version_match" = 'xyes'], [$1],
+ [m4_default([$2], [AC_MSG_ERROR([cannot find Lua includes])])])
+])
+
+dnl AX_LUA_HEADERS_VERSION no longer exists, use AX_LUA_HEADERS.
+AC_DEFUN([AX_LUA_HEADERS_VERSION],
+[
+ AC_MSG_WARN([[$0 is deprecated, please use AX_LUA_HEADERS instead]])
+])
+
+
+dnl =========================================================================
+dnl AX_LUA_LIBS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl =========================================================================
+AC_DEFUN([AX_LUA_LIBS],
+[
+ dnl TODO Should this macro also check various -L flags?
+
+ dnl Check for LUA_VERSION.
+ AC_MSG_CHECKING([if LUA_VERSION is defined])
+ AS_IF([test "x$LUA_VERSION" != 'x'],
+ [AC_MSG_RESULT([yes])],
+ [ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([cannot check Lua libs without knowing LUA_VERSION])
+ ])
+
+ dnl Make LUA_LIB a precious variable.
+ AC_ARG_VAR([LUA_LIB], [The Lua library, e.g. -llua5.1])
+
+ AS_IF([test "x$LUA_LIB" != 'x'],
+ [ dnl Check that LUA_LIBS works.
+ _ax_lua_saved_libs=$LIBS
+ LIBS="$LIBS $LUA_LIB"
+ AC_SEARCH_LIBS([lua_load], [],
+ [_ax_found_lua_libs='yes'],
+ [_ax_found_lua_libs='no'])
+ LIBS=$_ax_lua_saved_libs
+
+ dnl Check the result.
+ AS_IF([test "x$_ax_found_lua_libs" != 'xyes'],
+ [AC_MSG_ERROR([cannot find libs for specified LUA_LIB])])
+ ],
+ [ dnl First search for extra libs.
+ _ax_lua_extra_libs=''
+
+ _ax_lua_saved_libs=$LIBS
+ LIBS="$LIBS $LUA_LIB"
+ AC_SEARCH_LIBS([exp], [m])
+ AC_SEARCH_LIBS([dlopen], [dl])
+ LIBS=$_ax_lua_saved_libs
+
+ AS_IF([test "x$ac_cv_search_exp" != 'xno' &&
+ test "x$ac_cv_search_exp" != 'xnone required'],
+ [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp"])
+
+ AS_IF([test "x$ac_cv_search_dlopen" != 'xno' &&
+ test "x$ac_cv_search_dlopen" != 'xnone required'],
+ [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen"])
+
+ dnl Try to find the Lua libs.
+ _ax_lua_saved_libs=$LIBS
+ LIBS="$LIBS $LUA_LIB"
+ AC_SEARCH_LIBS([lua_load],
+ [ lua$LUA_VERSION \
+ lua$LUA_SHORT_VERSION \
+ lua-$LUA_VERSION \
+ lua-$LUA_SHORT_VERSION \
+ lua \
+ ],
+ [_ax_found_lua_libs='yes'],
+ [_ax_found_lua_libs='no'],
+ [$_ax_lua_extra_libs])
+ LIBS=$_ax_lua_saved_libs
+
+ AS_IF([test "x$ac_cv_search_lua_load" != 'xno' &&
+ test "x$ac_cv_search_lua_load" != 'xnone required'],
+ [LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs"])
+ ])
+
+ dnl Test the result and run user code.
+ AS_IF([test "x$_ax_found_lua_libs" = 'xyes'], [$1],
+ [m4_default([$2], [AC_MSG_ERROR([cannot find Lua libs])])])
+])
+
+
+dnl =========================================================================
+dnl AX_LUA_READLINE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl =========================================================================
+AC_DEFUN([AX_LUA_READLINE],
+[
+ AX_LIB_READLINE
+ AS_IF([test "x$ac_cv_header_readline_readline_h" != 'x' &&
+ test "x$ac_cv_header_readline_history_h" != 'x'],
+ [ LUA_LIBS_CFLAGS="-DLUA_USE_READLINE $LUA_LIBS_CFLAGS"
+ $1
+ ],
+ [$2])
+])
[NHRP_CACHE_LOCAL] = "local",
};
-static unsigned int nhrp_cache_protocol_key(void *peer_data)
+static unsigned int nhrp_cache_protocol_key(const void *peer_data)
{
- struct nhrp_cache *p = peer_data;
+ const struct nhrp_cache *p = peer_data;
return sockunion_hash(&p->remote_addr);
}
nhrp_peer_unref(p);
}
-static unsigned int nhrp_peer_key(void *peer_data)
+static unsigned int nhrp_peer_key(const void *peer_data)
{
- struct nhrp_peer *p = peer_data;
+ const struct nhrp_peer *p = peer_data;
return sockunion_hash(&p->vc->remote.nbma);
}
static struct hash *nhrp_vc_hash;
static struct list_head childlist_head[512];
-static unsigned int nhrp_vc_key(void *peer_data)
+static unsigned int nhrp_vc_key(const void *peer_data)
{
- struct nhrp_vc *vc = peer_data;
+ const struct nhrp_vc *vc = peer_data;
return jhash_2words(sockunion_hash(&vc->local.nbma),
sockunion_hash(&vc->remote.nbma), 0);
}
#include "hash.h"
#include "nhrpd.h"
-static unsigned int nhrp_reqid_key(void *data)
+static unsigned int nhrp_reqid_key(const void *data)
{
- struct nhrp_reqid *r = data;
+ const struct nhrp_reqid *r = data;
return r->request_id;
}
}
}
-static void ospf6_asbr_routemap_event(route_map_event_t event, const char *name)
+static void ospf6_asbr_routemap_event(const char *name)
{
int type;
zlog_debug("Zebra: BFD Dest replay request");
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
/* Replay the neighbor, if BFD is enabled on the interface*/
FOR_ALL_INTERFACES (vrf, ifp) {
static void ospf6_zebra_connected(struct zclient *zclient)
{
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
zclient_send_reg_requests(zclient, VRF_DEFAULT);
}
}
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
/* Replay the neighbor, if BFD is enabled in OSPF */
for (ALL_LIST_ELEMENTS(om->ospf, node, onode, ospf)) {
}
}
-static void ospf_route_map_event(route_map_event_t event, const char *name)
+static void ospf_route_map_event(const char *name)
{
struct ospf *ospf;
int type;
*/
/* Hash function for Segment Routing entry */
-static unsigned int sr_hash(void *p)
+static unsigned int sr_hash(const void *p)
{
const struct in_addr *rid = p;
static void ospf_zebra_connected(struct zclient *zclient)
{
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
zclient_send_reg_requests(zclient, VRF_DEFAULT);
}
pbr_nh_delete((struct pbr_nexthop_cache **)&b->data);
}
-static uint32_t pbr_nh_hash_key(void *arg)
+static uint32_t pbr_nh_hash_key(const void *arg)
{
uint32_t key;
- struct pbr_nexthop_cache *pbrnc = (struct pbr_nexthop_cache *)arg;
+ const struct pbr_nexthop_cache *pbrnc = arg;
key = nexthop_hash(pbrnc->nexthop);
ifp);
}
-static uint32_t pbr_nhg_hash_key(void *arg)
+static uint32_t pbr_nhg_hash_key(const void *arg)
{
- struct pbr_nexthop_group_cache *nhgc =
- (struct pbr_nexthop_group_cache *)arg;
+ const struct pbr_nexthop_group_cache *nhgc = arg;
return jhash(&nhgc->name, strlen(nhgc->name), 0x52c34a96);
}
pbr_nhg_hash = hash_create_size(
16, pbr_nhg_hash_key, pbr_nhg_hash_equal, "PBR NHG Cache Hash");
pbr_nhrc_hash =
- hash_create_size(16, (unsigned int (*)(void *))nexthop_hash,
+ hash_create_size(16, (unsigned int (*)(const void *))nexthop_hash,
pbr_nhrc_hash_equal, "PBR NH Hash");
pbr_nhg_low_table = PBR_NHT_DEFAULT_LOW_TABLEID;
"%s: Asked to install unsupported route type: L2VPN",
__PRETTY_FUNCTION__);
break;
+ case AFI_UNSPEC:
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: Asked to install unspecified route type",
+ __PRETTY_FUNCTION__);
+ break;
}
}
"%s: Asked to delete unsupported route type: L2VPN",
__PRETTY_FUNCTION__);
break;
+ case AFI_UNSPEC:
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: Asked to delete unspecified route type",
+ __PRETTY_FUNCTION__);
+ break;
}
}
struct vrf *vrf = NULL;
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
FOR_ALL_INTERFACES (vrf, ifp) {
if (ch->upstream->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
mask = PIM_OIF_FLAG_PROTO_IGMP;
- /* SGRpt entry could have empty oil */
- pim_channel_del_oif(ch->upstream->channel_oil, ch->interface,
- mask);
+ /*
+ * A S,G RPT channel can have an empty oil, we also
+ * need to take into account the fact that a ifchannel
+ * might have been suppressing a *,G ifchannel from
+ * being inherited. So let's figure out what
+ * needs to be done here
+ */
+ if (pim_upstream_evaluate_join_desired_interface(
+ ch->upstream, ch, ch->parent))
+ pim_channel_add_oif(ch->upstream->channel_oil,
+ ch->interface, mask);
+ else
+ pim_channel_del_oif(ch->upstream->channel_oil,
+ ch->interface, mask);
/*
* Do we have any S,G's that are inheriting?
* Nuke from on high too.
pim_jp_agg_single_upstream_send(&starup->rpf, starup, true);
}
-unsigned int pim_ifchannel_hash_key(void *arg)
+unsigned int pim_ifchannel_hash_key(const void *arg)
{
- struct pim_ifchannel *ch = (struct pim_ifchannel *)arg;
+ const struct pim_ifchannel *ch = arg;
return jhash_2words(ch->sg.src.s_addr, ch->sg.grp.s_addr, 0);
}
int pim_ifchannel_compare(const struct pim_ifchannel *ch1,
const struct pim_ifchannel *ch2);
-unsigned int pim_ifchannel_hash_key(void *arg);
+unsigned int pim_ifchannel_hash_key(const void *arg);
#endif /* PIM_IFCHANNEL_H */
}
}
-static unsigned int igmp_group_hash_key(void *arg)
+static unsigned int igmp_group_hash_key(const void *arg)
{
- struct igmp_group *group = (struct igmp_group *)arg;
+ const struct igmp_group *group = arg;
return jhash_1word(group->group_addr.s_addr, 0);
}
}
/* sa hash and peer list helpers */
-static unsigned int pim_msdp_sa_hash_key_make(void *p)
+static unsigned int pim_msdp_sa_hash_key_make(const void *p)
{
- struct pim_msdp_sa *sa = p;
+ const struct pim_msdp_sa *sa = p;
return (jhash_2words(sa->sg.src.s_addr, sa->sg.grp.s_addr, 0));
}
}
/* peer hash and peer list helpers */
-static unsigned int pim_msdp_peer_hash_key_make(void *p)
+static unsigned int pim_msdp_peer_hash_key_make(const void *p)
{
- struct pim_msdp_peer *mp = p;
+ const struct pim_msdp_peer *mp = p;
return (jhash_1word(mp->peer.s_addr, 0));
}
return false;
}
-static unsigned int pim_oil_hash_key(void *arg)
+static unsigned int pim_oil_hash_key(const void *arg)
{
- struct channel_oil *oil = (struct channel_oil *)arg;
+ const struct channel_oil *oil = arg;
return jhash_2words(oil->oil.mfcc_mcastgrp.s_addr,
oil->oil.mfcc_origin.s_addr, 0);
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
}
-static void pim_route_map_event(route_map_event_t event, const char *rmap_name)
+static void pim_route_map_event(const char *rmap_name)
{
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
}
return 0;
}
-unsigned int pim_rpf_hash_key(void *arg)
+unsigned int pim_rpf_hash_key(const void *arg)
{
- struct pim_nexthop_cache *r = (struct pim_nexthop_cache *)arg;
+ const struct pim_nexthop_cache *r = arg;
return jhash_1word(r->rpf.rpf_addr.u.prefix4.s_addr, 0);
}
struct pim_upstream;
-unsigned int pim_rpf_hash_key(void *arg);
+unsigned int pim_rpf_hash_key(const void *arg);
bool pim_rpf_equal(const void *arg1, const void *arg2);
bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
"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);
}
}
-unsigned int pim_upstream_hash_key(void *arg)
+unsigned int pim_upstream_hash_key(const void *arg)
{
- struct pim_upstream *up = (struct pim_upstream *)arg;
+ const struct pim_upstream *up = arg;
return jhash_2words(up->sg.src.s_addr, up->sg.grp.s_addr, 0);
}
void pim_upstream_spt_prefix_list_update(struct pim_instance *pim,
struct prefix_list *pl);
-unsigned int pim_upstream_hash_key(void *arg);
+unsigned int pim_upstream_hash_key(const void *arg);
bool pim_upstream_equal(const void *arg1, const void *arg2);
struct pim_upstream *pim_upstream_keep_alive_timer_proc(
struct pim_upstream *up);
}
/************************** vxlan SG cache management ************************/
-static unsigned int pim_vxlan_sg_hash_key_make(void *p)
+static unsigned int pim_vxlan_sg_hash_key_make(const void *p)
{
- struct pim_vxlan_sg *vxlan_sg = p;
+ const struct pim_vxlan_sg *vxlan_sg = p;
return (jhash_2words(vxlan_sg->sg.src.s_addr,
vxlan_sg->sg.grp.s_addr, 0));
static void pim_zebra_connected(struct zclient *zclient)
{
/* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, router->vrf_id);
zclient_send_reg_requests(zclient, router->vrf_id);
}
install_it, up->channel_oil->installed);
}
- pim_channel_del_oif(up->channel_oil, ch->interface,
- PIM_OIF_FLAG_PROTO_PIM);
+ /*
+ * If a channel is being removed, check to see if we still need
+ * to inherit the interface. If so make sure it is added in
+ */
+ if (pim_upstream_evaluate_join_desired_interface(up, ch, ch->parent))
+ pim_channel_add_oif(up->channel_oil, ch->interface,
+ PIM_OIF_FLAG_PROTO_PIM);
+ else
+ pim_channel_del_oif(up->channel_oil, ch->interface,
+ PIM_OIF_FLAG_PROTO_PIM);
if (install_it && !up->channel_oil->installed)
pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
mpls_enabled = cap->mpls_enabled;
}
-static unsigned int static_nht_hash_key(void *data)
+static unsigned int static_nht_hash_key(const void *data)
{
- struct static_nht_data *nhtd = data;
+ const struct static_nht_data *nhtd = data;
unsigned int key = 0;
key = prefix_hash_key(nhtd->nh);
return rv;
}
-static unsigned int log_key(void *data)
+static unsigned int log_key(const void *data)
{
- struct prefix *hash_entry = data;
+ const struct prefix *hash_entry = data;
struct prefix_ipv6 *dst_p = (struct prefix_ipv6 *)&hash_entry[0];
struct prefix_ipv6 *src_p = (struct prefix_ipv6 *)&hash_entry[1];
unsigned int hash = 0;
r1-eth0 is up
- ifindex 2, MTU 1500 bytes, BW XX Mbit <UP,BROADCAST,RUNNING,MULTICAST>
+ ifindex X, MTU 1500 bytes, BW XX Mbit <UP,BROADCAST,RUNNING,MULTICAST>
Internet Address 192.168.0.1/24, Broadcast 192.168.0.255, Area 0.0.0.0
MTU mismatch detection: enabled
Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10
Hello due in XX.XXXs
Neighbor Count is 0, Adjacent neighbor count is 0
r1-eth3 is up
- ifindex 5, MTU 1500 bytes, BW XX Mbit <UP,BROADCAST,RUNNING,MULTICAST>
+ ifindex X, MTU 1500 bytes, BW XX Mbit <UP,BROADCAST,RUNNING,MULTICAST>
Internet Address 192.168.3.1/26, Broadcast 192.168.3.63, Area 0.0.0.0
MTU mismatch detection: enabled
Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10
actual = net['r%s' % i].cmd('vtysh -c "show ip ospf interface" 2> /dev/null').rstrip()
# Mask out Bandwidth portion. They may change..
actual = re.sub(r"BW [0-9]+ Mbit", "BW XX Mbit", actual)
+ actual = re.sub(r"ifindex [0-9]", "ifindex X", actual)
+
# Drop time in next due
actual = re.sub(r"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual)
# Fix 'MTU mismatch detection: enabled' vs 'MTU mismatch detection:enabled' - accept both
--- /dev/null
+bfd
+ peer 192.168.0.2 vrf r1-cust1
+ echo-mode
+ no shutdown
+ !
+!
--- /dev/null
+{
+ "routes": {
+ "10.254.254.2/32": [
+ {
+ "aspath": "102",
+ "prefix": "10.254.254.2",
+ "valid": true,
+ "peerId": "192.168.0.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.0.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.3/32": [
+ {
+ "aspath": "102 103",
+ "prefix": "10.254.254.3",
+ "valid": true,
+ "peerId": "192.168.0.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.0.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.4/32": [
+ {
+ "aspath": "102 104",
+ "prefix": "10.254.254.4",
+ "valid": true,
+ "peerId": "192.168.0.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.0.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ]
+ }
+}
--- /dev/null
+{
+ "ipv4Unicast": {
+ "as": 101,
+ "peers": {
+ "192.168.0.2": {
+ "remoteAs": 102,
+ "state": "Established"
+ }
+ }
+ }
+}
--- /dev/null
+router bgp 101 vrf r1-cust1
+ neighbor 192.168.0.2 remote-as 102
+! neighbor 192.168.0.2 ebgp-multihop 10
+ neighbor 192.168.0.2 bfd
+ address-family ipv4 unicast
+ network 10.254.254.1/32
+ exit-address-family
+!
--- /dev/null
+[
+ {
+ "remote-receive-interval": 1000,
+ "remote-transmit-interval": 500,
+ "peer": "192.168.0.2",
+ "status": "up"
+ }
+]
--- /dev/null
+interface r1-eth0 vrf r1-cust1
+ ip address 192.168.0.1/24
+!
--- /dev/null
+bfd
+ peer 192.168.0.1 vrf r2-cust1
+ receive-interval 1000
+ transmit-interval 500
+ echo-mode
+ no shutdown
+ !
+ peer 192.168.1.1 vrf r2-cust1
+ echo-mode
+ no shutdown
+ !
+!
--- /dev/null
+{
+ "routes": {
+ "10.254.254.1/32": [
+ {
+ "aspath": "101",
+ "prefix": "10.254.254.1",
+ "valid": true,
+ "peerId": "192.168.0.1",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.0.1",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.3/32": [
+ {
+ "aspath": "103",
+ "prefix": "10.254.254.3",
+ "valid": true,
+ "peerId": "192.168.1.1",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.1.1",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.4/32": [
+ {
+ "aspath": "104",
+ "prefix": "10.254.254.4",
+ "valid": true,
+ "peerId": "192.168.2.1",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.2.1",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ]
+ }
+}
--- /dev/null
+{
+ "ipv4Unicast": {
+ "as": 102,
+ "peers": {
+ "192.168.0.1": {
+ "remoteAs": 101,
+ "state": "Established"
+ },
+ "192.168.1.1": {
+ "remoteAs": 103,
+ "state": "Established"
+ },
+ "192.168.2.1": {
+ "remoteAs": 104,
+ "state": "Established"
+ }
+ }
+ }
+}
--- /dev/null
+router bgp 102 vrf r2-cust1
+ neighbor 192.168.0.1 remote-as 101
+ neighbor 192.168.0.1 bfd
+ neighbor 192.168.1.1 remote-as 103
+ neighbor 192.168.1.1 bfd
+ neighbor 192.168.2.1 remote-as 104
+ neighbor 192.168.2.1 bfd
+ address-family ipv4 unicast
+ network 10.254.254.2/32
+ exit-address-family
+!
--- /dev/null
+[
+ {
+ "peer": "192.168.0.1",
+ "status": "up"
+ },
+ {
+ "remote-echo-interval": 100,
+ "peer": "192.168.1.1",
+ "status": "up"
+ },
+ {
+ "remote-transmit-interval": 2000,
+ "remote-receive-interval": 2000,
+ "peer": "192.168.2.1",
+ "status": "up"
+ }
+]
--- /dev/null
+interface r2-eth0 vrf r2-cust1
+ ip address 192.168.0.2/24
+!
+interface r2-eth1 vrf r2-cust1
+ ip address 192.168.1.2/24
+!
+interface r2-eth2 vrf r2-cust1
+ ip address 192.168.2.2/24
+!
--- /dev/null
+bfd
+ peer 192.168.1.2 vrf r3-cust1
+ echo-interval 100
+ echo-mode
+ no shutdown
+ !
+!
--- /dev/null
+{
+ "routes": {
+ "10.254.254.1/32": [
+ {
+ "aspath": "102 101",
+ "prefix": "10.254.254.1",
+ "valid": true,
+ "peerId": "192.168.1.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.1.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.2/32": [
+ {
+ "aspath": "102",
+ "prefix": "10.254.254.2",
+ "valid": true,
+ "peerId": "192.168.1.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.1.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.4/32": [
+ {
+ "aspath": "102 104",
+ "prefix": "10.254.254.4",
+ "valid": true,
+ "peerId": "192.168.1.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.1.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ]
+ }
+}
--- /dev/null
+{
+ "ipv4Unicast": {
+ "as": 103,
+ "peers": {
+ "192.168.1.2": {
+ "remoteAs": 102,
+ "state": "Established"
+ }
+ }
+ }
+}
--- /dev/null
+router bgp 103 vrf r3-cust1
+ neighbor 192.168.1.2 remote-as 102
+ neighbor 192.168.1.2 bfd
+ address-family ipv4 unicast
+ network 10.254.254.3/32
+ exit-address-family
+!
--- /dev/null
+[
+ {
+ "peer": "192.168.1.2",
+ "status": "up"
+ }
+]
--- /dev/null
+interface r3-eth0 vrf r3-cust1
+ ip address 192.168.1.1/24
+!
--- /dev/null
+bfd
+ peer 192.168.2.2 vrf r4-cust1
+ transmit-interval 2000
+ receive-interval 2000
+ no shutdown
+ !
+!
--- /dev/null
+{
+ "routes": {
+ "10.254.254.1/32": [
+ {
+ "aspath": "102 101",
+ "prefix": "10.254.254.1",
+ "valid": true,
+ "peerId": "192.168.2.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.2.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.2/32": [
+ {
+ "aspath": "102",
+ "prefix": "10.254.254.2",
+ "valid": true,
+ "peerId": "192.168.2.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.2.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.3/32": [
+ {
+ "aspath": "102 103",
+ "prefix": "10.254.254.3",
+ "valid": true,
+ "peerId": "192.168.2.2",
+ "prefixLen": 32,
+ "nexthops": [
+ {
+ "ip": "192.168.2.2",
+ "used": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ]
+ }
+}
--- /dev/null
+{
+ "ipv4Unicast": {
+ "as": 104,
+ "peers": {
+ "192.168.2.2": {
+ "remoteAs": 102,
+ "state": "Established"
+ }
+ }
+ }
+}
--- /dev/null
+router bgp 104 vrf r4-cust1
+ neighbor 192.168.2.2 remote-as 102
+ neighbor 192.168.2.2 bfd
+ address-family ipv4 unicast
+ network 10.254.254.4/32
+ exit-address-family
+!
--- /dev/null
+[
+ {
+ "peer": "192.168.2.2",
+ "status": "up"
+ }
+]
--- /dev/null
+interface r4-eth0 vrf r4-cust1
+ ip address 192.168.2.1/24
+!
--- /dev/null
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="bfd-topo1";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r4 [
+ shape=doubleoctagon
+ label="r4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n192.168.0.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n192.168.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw3 [
+ shape=oval,
+ label="sw3\n192.168.2.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- sw1 [label="eth0\n.1"];
+ r2 -- sw1 [label="eth0\n.2"];
+
+ r3 -- sw2 [label="eth0\n.1"];
+ r2 -- sw2 [label="eth1\n.2"];
+
+ r4 -- sw3 [label="eth0\n.1"];
+ r2 -- sw3 [label="eth2\n.2"];
+}
--- /dev/null
+#!/usr/bin/env python
+
+#
+# test_bfd_vrf_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2018 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+# Copyright (c) 2019 by 6WIND
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bfd_vrf_topo1.py: Test the FRR/Quagga BFD daemon.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+class BFDTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 4 routers
+ for routern in range(1, 5):
+ tgen.add_router('r{}'.format(routern))
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+ switch = tgen.add_switch('s2')
+ switch.add_link(tgen.gears['r2'])
+ switch.add_link(tgen.gears['r3'])
+
+ switch = tgen.add_switch('s3')
+ switch.add_link(tgen.gears['r2'])
+ switch.add_link(tgen.gears['r4'])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(BFDTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ # check for zebra capability
+ for rname, router in router_list.iteritems():
+ if router.check_capability(
+ TopoRouter.RD_ZEBRA,
+ '--vrfwnetns'
+ ) == False:
+ return pytest.skip('Skipping BFD Topo1 VRF NETNS feature. VRF NETNS backend not available on FRR')
+
+ if os.system('ip netns list') != 0:
+ return pytest.skip('Skipping BFD Topo1 VRF NETNS Test. NETNS not available on System')
+
+ logger.info('Testing with VRF Namespace support')
+
+ cmds = ['if [ -e /var/run/netns/{0}-cust1 ] ; then ip netns del {0}-cust1 ; fi',
+ 'ip netns add {0}-cust1',
+ 'ip link set dev {0}-eth0 netns {0}-cust1',
+ 'ip netns exec {0}-cust1 ifconfig {0}-eth0 up']
+ cmds2 = ['ip link set dev {0}-eth1 netns {0}-cust1',
+ 'ip netns exec {0}-cust1 ifconfig {0}-eth1 up',
+ 'ip link set dev {0}-eth2 netns {0}-cust1',
+ 'ip netns exec {0}-cust1 ifconfig {0}-eth2 up']
+
+ for rname, router in router_list.iteritems():
+ # create VRF rx-cust1 and link rx-eth0 to rx-cust1
+ for cmd in cmds:
+ output = tgen.net[rname].cmd(cmd.format(rname))
+ if rname == 'r2':
+ for cmd in cmds2:
+ output = tgen.net[rname].cmd(cmd.format(rname))
+
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname)),
+ '--vrfwnetns'
+ )
+ router.load_config(
+ TopoRouter.RD_BFD,
+ os.path.join(CWD, '{}/bfdd.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+ # Verify that we are using the proper version and that the BFD
+ # daemon exists.
+ for router in router_list.values():
+ # Check for Version
+ if router.has_version('<', '5.1'):
+ tgen.set_error('Unsupported FRR version')
+ break
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ # move back rx-eth0 to default VRF
+ # delete rx-vrf
+ cmds = ['ip netns exec {0}-cust1 ip link set {0}-eth0 netns 1',
+ 'ip netns delete {0}-cust1']
+ cmds2 = ['ip netns exec {0}-cust1 ip link set {0}-eth1 netns 1',
+ 'ip netns exec {0}-cust2 ip link set {0}-eth1 netns 1']
+
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ if rname == 'r2':
+ for cmd in cmds2:
+ tgen.net[rname].cmd(cmd.format(rname))
+ for cmd in cmds:
+ tgen.net[rname].cmd(cmd.format(rname))
+ tgen.stop_topology()
+
+def test_bfd_connection():
+ "Assert that the BFD peers can find themselves."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('waiting for bfd peers to go up')
+ for router in tgen.routers().values():
+ json_file = '{}/{}/peers.json'.format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show bfd peers json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+
+def test_bgp_convergence():
+ "Assert that BGP is converging."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('waiting for bgp peers to go up')
+
+ for router in tgen.routers().values():
+ ref_file = '{}/{}/bgp_summary.json'.format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip bgp vrf {}-cust1 summary json'.format(router.name), expected)
+ _, res = topotest.run_and_expect(test_func, None, count=125, wait=1.0)
+ assertmsg = '{}: bgp did not converge'.format(router.name)
+ assert res is None, assertmsg
+
+
+def test_bgp_fast_convergence():
+ "Assert that BGP is converging before setting a link down."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('waiting for bgp peers converge')
+
+ for router in tgen.routers().values():
+ ref_file = '{}/{}/bgp_prefixes.json'.format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip bgp vrf {}-cust1 json'.format(router.name), expected)
+ _, res = topotest.run_and_expect(test_func, None, count=40, wait=0.5)
+ assertmsg = '{}: bgp did not converge'.format(router.name)
+ assert res is None, assertmsg
+
+
+def test_bfd_fast_convergence():
+ """
+ Assert that BFD notices the link down after simulating network
+ failure.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Disable r2-eth0 link
+ router2 = tgen.gears['r2']
+ topotest.interface_set_status(router2, 'r2-eth0', ifaceaction=False, vrf_name='r2-cust1')
+
+ # Wait the minimum time we can before checking that BGP/BFD
+ # converged.
+ logger.info('waiting for BFD converge')
+
+ # Check that BGP converged quickly.
+ for router in tgen.routers().values():
+ json_file = '{}/{}/peers.json'.format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+
+ # Load the same file as previous test, but expect R1 to be down.
+ if router.name == 'r1':
+ for peer in expected:
+ if peer['peer'] == '192.168.0.2':
+ peer['status'] = 'down'
+ else:
+ for peer in expected:
+ if peer['peer'] == '192.168.0.1':
+ peer['status'] = 'down'
+
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show bfd peers json', expected)
+ _, res = topotest.run_and_expect(test_func, None, count=20, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert res is None, assertmsg
+
+
+def test_bgp_fast_reconvergence():
+ "Assert that BGP is converging after setting a link down."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('waiting for BGP re convergence')
+
+ # Check that BGP converged quickly.
+ for router in tgen.routers().values():
+ ref_file = '{}/{}/bgp_prefixes.json'.format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+
+ # Load the same file as previous test, but set networks to None
+ # to test absence.
+ if router.name == 'r1':
+ expected['routes']['10.254.254.2/32'] = None
+ expected['routes']['10.254.254.3/32'] = None
+ expected['routes']['10.254.254.4/32'] = None
+ else:
+ expected['routes']['10.254.254.1/32'] = None
+
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip bgp vrf {}-cust1 json'.format(router.name), expected)
+ _, res = topotest.run_and_expect(
+ test_func,
+ None,
+ count=3,
+ wait=1
+ )
+ assertmsg = '{}: bgp did not converge'.format(router.name)
+ assert res is None, assertmsg
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip('Memory leak test/report is disabled')
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
--- /dev/null
+router bgp 65000
+ bgp ebgp-requires-policy
+ neighbor 192.168.255.2 remote-as 1000
+ neighbor 192.168.255.2 local-as 500
+ address-family ipv4 unicast
+ redistribute connected
+ neighbor 192.168.255.2 route-map outgoing out
+!
+ip prefix-list peer-out permit 172.16.255.254/32
+route-map outgoing permit 10
+ match ip address prefix-list peer-out
+!
--- /dev/null
+!
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
--- /dev/null
+router bgp 1000
+ neighbor 192.168.255.1 remote-as 500
--- /dev/null
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
--- /dev/null
+router bgp 65000
+ bgp ebgp-requires-policy
+ neighbor 192.168.255.2 remote-as 1000
+ neighbor 192.168.255.2 local-as 500
+ address-family ipv4 unicast
+ redistribute connected
--- /dev/null
+!
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r3-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
--- /dev/null
+router bgp 1000
+ neighbor 192.168.255.1 remote-as 500
--- /dev/null
+!
+interface r4-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
--- /dev/null
+#!/usr/bin/env python
+
+#
+# bgp_ebgp_requires_policy.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+bgp_ebgp_requires_policy.py:
+
+Test if eBGP sender without a filter applied to the peer is allowed
+to send advertisements.
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 5):
+ tgen.add_router('r{}'.format(routern))
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+ switch = tgen.add_switch('s2')
+ switch.add_link(tgen.gears['r3'])
+ switch.add_link(tgen.gears['r4'])
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+ )
+
+ tgen.start_router()
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+def test_bgp_remove_private_as():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_converge(router):
+ while True:
+ cmd = "show ip bgp neighbor 192.168.255.1 json"
+ output = json.loads(tgen.gears[router].vtysh_cmd(cmd))
+ if output['192.168.255.1']['bgpState'] == 'Established':
+ time.sleep(3)
+ return True
+
+ def _bgp_ebgp_requires_policy(router):
+ cmd = "show ip bgp 172.16.255.254/32 json"
+ output = json.loads(tgen.gears[router].vtysh_cmd(cmd))
+ if 'prefix' in output:
+ return True
+ return False
+
+ if _bgp_converge('r2'):
+ assert _bgp_ebgp_requires_policy('r2') == True
+
+ if _bgp_converge('r4'):
+ assert _bgp_ebgp_requires_policy('r4') == False
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
network 99.0.0.1/32
network 5.1.0.0/24 route-map rm-nh
network 5.1.1.0/24 route-map rm-nh
+ redistribute sharp route-map sharp-nh
neighbor 192.168.1.1 activate
exit-address-family
!
set extcommunity rt 89:123
set community 0:67
!
+route-map sharp-nh permit 10
+ match ip address al-any
+ set ip next-hop 99.0.0.1
+ set local-preference 200
+ set metric 200
+ set large-community 90:12:34
+ set extcommunity rt 80:987
+ set community 0:65
+!
end
network 99.0.0.2/32
network 5.1.0.0/24 route-map rm-nh
network 5.1.1.0/24 route-map rm-nh
+ redistribute sharp route-map sharp-nh
neighbor 192.168.1.1 activate
exit-address-family
!
set extcommunity rt 89:123
set community 0:67
!
+route-map sharp-nh permit 10
+ match ip address al-any
+ set ip next-hop 99.0.0.2
+ set local-preference 200
+ set metric 200
+ set large-community 78:90:12
+ set extcommunity rt 70:456
+ set community 0:66
+!
end
log commands
log file bgpd.log
-debug bgp vpn label
+#debug bgp vpn label
router bgp 5226
bgp router-id 3.3.3.3
bgp cluster-id 3.3.3.3
log commands
log file bgpd.log debug
-debug bgp vpn label
-debug bgp nht
-debug bgp zebra
+#debug bgp vpn label
+#debug bgp nht
+#debug bgp zebra
router bgp 5226
bgp router-id 4.4.4.4
from lutil import luCommand
from customize import l3mdev_accept
+
l3mdev_rtrs = ['r1', 'r3', 'r4', 'ce4']
for rtr in l3mdev_rtrs:
luCommand(rtr,'sysctl net.ipv4.tcp_l3mdev_accept',' = \d*','none','')
--- /dev/null
+from lutil import luCommand
+ret = luCommand('ce1', 'vtysh -c "show ip route" | grep -c \\ 10\\.\\*/32','(.*)','pass', 'Looking for sharp routes')
+found = luLast()
+if ret != False and found != None:
+ num = int(found.group())
+ luCommand('ce3', 'vtysh -c "show bgp sum"',
+ '.', 'pass', 'See %s sharp routes' % num)
+ if num > 0:
+ wait = num/500
+ luCommand('ce1', 'vtysh -c "sharp remove routes 10.0.0.0 {}"'.format(num),'.','none','Removing {} routes'.format(num))
+ luCommand('ce2', 'vtysh -c "sharp remove routes 10.0.0.0 {}"'.format(num),'.','none','Removing {} routes'.format(num))
+ rtrs = ['ce1', 'ce2', 'ce3']
+ for rtr in rtrs:
+ luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep -c 10\\.\\*/32','^0$', 'wait', 'BGP routes removed', wait)
+ for rtr in rtrs:
+ luCommand(rtr, 'ip route show | grep -c \\^10\\.','^0$', 'wait', 'Linux routes removed', wait)
+ rtrs = ['r1', 'r3', 'r4']
+ for rtr in rtrs:
+ luCommand(rtr, 'ip route show vrf {}-cust1 | grep -c \\^10\\.'.format(rtr),'^0$','wait','VRF route removed',wait)
+#done
--- /dev/null
+from lutil import luCommand
+num = 50000
+b = int(num/(256*256))
+if b > 0:
+ r = num - b * (256*256)
+else:
+ r = num
+c = int(r/256)
+if c > 0:
+ d = r - c * 256 - 1
+else:
+ d = r
+wait = num/1000
+mem = {}
+rtrs = ['ce1', 'ce2', 'ce3', 'r1', 'r2', 'r3', 'r4']
+for rtr in rtrs:
+ mem[rtr] = {'value': 0, 'units': 'unknown'}
+ ret = luCommand(rtr, 'vtysh -c "show memory"', 'bgpd: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*)', 'none', 'collect bgpd memory stats')
+ found = luLast()
+ if ret != False and found != None:
+ mem[rtr] = {'value': int(found.group(1)), 'units': found.group(2)}
+
+luCommand('ce1', 'vtysh -c "sharp data nexthop"', 'sharpd is not running', 'none','check if sharpd running')
+doSharp = True
+found = luLast()
+if ret != False and found != None:
+ if len(found.group()):
+ luCommand('ce1', 'vtysh -c "sharp data nexthop"', 'sharpd is not running', 'pass','sharpd NOT running, skipping test')
+ doSharp = False
+
+if doSharp == True:
+ luCommand('ce1', 'vtysh -c "sharp install routes 10.0.0.0 nexthop 99.0.0.1 {}"'.format(num),'','pass','Adding {} routes'.format(num))
+ luCommand('ce2', 'vtysh -c "sharp install routes 10.0.0.0 nexthop 99.0.0.2 {}"'.format(num),'','pass','Adding {} routes'.format(num))
+ rtrs = ['ce1', 'ce2', 'ce3']
+ for rtr in rtrs:
+ luCommand(rtr, 'vtysh -c "show bgp ipv4 uni 10.{}.{}.{}"'.format(b,c,d), 'Last update:', 'wait', 'RXed last route, 10.{}.{}.{}'.format(b,c,d), wait)
+ luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep -c 10\\.\\*/32', str(num), 'wait', 'See all sharp routes in BGP', wait)
+ luCommand('r1', 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 10.{}.{}.{}"'.format(b,c,d),'99.0.0.1','wait','RXed -> 10.{}.{}.{} from CE1'.format(b,c,d), wait)
+ luCommand('r3', 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 10.{}.{}.{}"'.format(b,c,d),'99.0.0.2','wait','RXed -> 10.{}.{}.{} from CE2'.format(b,c,d), wait)
+ luCommand('r1', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'99.0.0.1','wait','see VPN safi -> 10.{}.{}.{} from CE1'.format(b,c,d))
+ luCommand('r3', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'99.0.0.2','wait','see VPN safi -> 10.{}.{}.{} from CE2'.format(b,c,d))
+ luCommand('r3', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'1.1.1.1','wait','see VPN safi -> 10.{}.{}.{} from CE1'.format(b,c,d))
+ luCommand('r1', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'3.3.3.3','wait','see VPN safi -> 10.{}.{}.{} from CE2'.format(b,c,d))
+ luCommand('r4', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'1.1.1.1','wait','see VPN safi -> 10.{}.{}.{} from CE1'.format(b,c,d))
+ luCommand('r4', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'3.3.3.3','wait','see VPN safi -> 10.{}.{}.{} from CE2'.format(b,c,d))
+ rtrs = ['ce1', 'ce2', 'ce3']
+ for rtr in rtrs:
+ luCommand(rtr, 'ip route get 10.{}.{}.{}'.format(b,c,d),'dev','wait','Route to 10.{}.{}.{} available'.format(b,c,d), wait)
+ luCommand(rtr, 'ip route show | grep -c \\^10\\.', str(num), 'wait', 'See {} linux routes'.format(num), wait)
+
+ rtrs = ['r1', 'r3', 'r4']
+ for rtr in rtrs:
+ luCommand(rtr, 'ip route get vrf {}-cust1 10.{}.{}.{}'.format(rtr,b,c,d),'dev','wait','VRF route available',wait)
+ luCommand(rtr, 'ip route show vrf {}-cust1 | grep -c \\^10\\.'.format(rtr), str(num), 'wait','See {} linux routes'.format(num), wait)
+ rtrs = ['ce1', 'ce2', 'ce3', 'r1', 'r2', 'r3', 'r4']
+ for rtr in rtrs:
+ ret = luCommand(rtr, 'vtysh -c "show memory"', 'bgpd: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*)', 'none', 'collect bgpd memory stats')
+ found = luLast()
+ if ret != False and found != None:
+ val = int(found.group(1))
+ if mem[rtr]['units'] != found.group(2):
+ val *= 1000
+ delta = val - int(mem[rtr]['value'])
+ ave = float(delta)/float(num)
+ luCommand(rtr, 'vtysh -c "show thread cpu"', '.', 'pass', 'BGPd heap: {0} {1} --> {2} {3} ({4} {1}/route)'.format(mem[rtr]['value'], mem[rtr]['units'], found.group(1), found.group(2), round(ave,4)))
+#done
#CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True, iproute2=\'4.9\')'
ltemplateTest('scripts/check_linux_mpls.py', False, CliOnFail, CheckFunc)
+def test_check_scale_up():
+ CliOnFail = None
+ # For debugging, uncomment the next line
+ #CliOnFail = 'tgen.mininet_cli'
+ CheckFunc = 'ltemplateVersionCheck(\'4.1\', iproute2=\'4.9\')'
+ #uncomment next line to start cli *before* script is run
+ #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True, iproute2=\'4.9\')'
+ ltemplateTest('scripts/scale_up.py', False, CliOnFail, CheckFunc)
+
+def test_check_scale_down():
+ CliOnFail = None
+ # For debugging, uncomment the next line
+ #CliOnFail = 'tgen.mininet_cli'
+ CheckFunc = 'ltemplateVersionCheck(\'4.1\', iproute2=\'4.9\')'
+ #uncomment next line to start cli *before* script is run
+ #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True, iproute2=\'4.9\')'
+ ltemplateTest('scripts/scale_down.py', False, CliOnFail, CheckFunc)
+
def SKIP_test_cleanup_all():
CliOnFail = None
# For debugging, uncomment the next line
# For all registred routers, load the zebra configuration file
for rname, router in router_list.iteritems():
- print("Setting up %s" % rname)
- config = os.path.join(self.testdir, '{}/zebra.conf'.format(rname))
- if os.path.exists(config):
- router.load_config(TopoRouter.RD_ZEBRA, config)
- config = os.path.join(self.testdir, '{}/ospfd.conf'.format(rname))
- if os.path.exists(config):
- router.load_config(TopoRouter.RD_OSPF, config)
- config = os.path.join(self.testdir, '{}/ldpd.conf'.format(rname))
- if os.path.exists(config):
- router.load_config(TopoRouter.RD_LDP, config)
- config = os.path.join(self.testdir, '{}/bgpd.conf'.format(rname))
- if os.path.exists(config):
- router.load_config(TopoRouter.RD_BGP, config)
- config = os.path.join(self.testdir, '{}/isisd.conf'.format(rname))
- if os.path.exists(config):
- router.load_config(TopoRouter.RD_ISIS, config)
+ logger.info("Setting up %s" % rname)
+ for rd_val in TopoRouter.RD:
+ config = os.path.join(self.testdir, '{}/{}.conf'.format(rname,TopoRouter.RD[rd_val]))
+ prog = os.path.join(tgen.net[rname].daemondir, TopoRouter.RD[rd_val])
+ if os.path.exists(config):
+ if os.path.exists(prog):
+ router.load_config(rd_val, config)
+ else:
+ logger.warning("{} not found, but have {}.conf file".format(prog, TopoRouter.RD[rd_val]))
# After loading the configurations, this function loads configured daemons.
logger.info('Starting routers')
RD_NHRP = 11
RD_STATIC = 12
RD_BFD = 13
+ RD_SHARP = 14
RD = {
RD_ZEBRA: 'zebra',
RD_RIP: 'ripd',
RD_NHRP: 'nhrpd',
RD_STATIC: 'staticd',
RD_BFD: 'bfdd',
+ RD_SHARP: 'sharpd',
}
def __init__(self, tgen, cls, name, **params):
"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
--- /dev/null
+//
+// Transition hash key signatures to take their argument as const.
+// Does not handle headers or weirdly named hash functions.
+//
+@noconst disable optional_qualifier@
+identifier A;
+identifier func =~ ".*key$|.*key_make$|.*hash_make$|.*hash_keymake$|.*hash_key$|.*hash_key.*";
+@@
+
+- func (void *A)
++ func (const void *A)
+ { ... }
+
+@ depends on noconst disable optional_qualifier @
+identifier noconst.A;
+identifier noconst.func;
+identifier b;
+type T;
+@@
+
+func( ... ) {
+<...
+- T b = A;
++ const T b = A;
+...>
+ }
+
+@ depends on noconst disable optional_qualifier @
+identifier noconst.A;
+identifier noconst.func;
+identifier b;
+type T;
+@@
+
+func(...)
+ {
+<...
+- T b = (T) A;
++ const T b = A;
+...>
+ }
+
+@ depends on noconst disable optional_qualifier @
+identifier noconst.A;
+identifier noconst.func;
+identifier b;
+type T;
+@@
+
+func(...)
+ {
+<...
+- T b;
++ const T b;
+...
+ b = A;
+...>
+ }
+
+@ depends on noconst disable optional_qualifier @
+identifier noconst.A;
+identifier noconst.func;
+identifier b;
+type T;
+@@
+
+func(...)
+ {
+<...
+- T b;
++ const T b;
+...
+- b = (T) A;
++ b = A;
+...>
+ }
$cppadd = $fabricd ? "-DFABRICD=1" : "";
- open (FH, "@CPP@ -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -Ivtysh/@top_builddir@ -Ivtysh/@top_srcdir@ -Ivtysh/@top_srcdir@/lib -Ivtysh/@top_builddir@/lib -Ivtysh/@top_srcdir@/bgpd -Ivtysh/@top_srcdir@/bgpd/rfapi @CPPFLAGS@ $cppadd $file |");
+ open (FH, "@CPP@ -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -Ivtysh/@top_builddir@ -Ivtysh/@top_srcdir@ -Ivtysh/@top_srcdir@/lib -Ivtysh/@top_builddir@/lib -Ivtysh/@top_srcdir@/bgpd -Ivtysh/@top_srcdir@/bgpd/rfapi @LUA_INCLUDE@ @CPPFLAGS@ $cppadd $file |");
local $/; undef $/;
$line = <FH>;
close (FH);
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:
.cap_num_p = array_size(_caps_p),
.cap_num_i = 0};
-unsigned int multipath_num = MULTIPATH_NUM;
-
/* SIGHUP handler. */
static void sighup(void)
{
keep_kernel_mode = 1;
break;
case 'e':
- multipath_num = atoi(optarg);
- if (multipath_num > MULTIPATH_NUM
- || multipath_num <= 0) {
+ zrouter.multipath_num = atoi(optarg);
+ if (zrouter.multipath_num > MULTIPATH_NUM
+ || zrouter.multipath_num <= 0) {
flog_err(
EC_ZEBRA_BAD_MULTIPATH_NUM,
"Multipath Number specified must be less than %d and greater than 0",
newre->mtu = re->mtu;
newre->table = 0;
newre->nexthop_num = 0;
- newre->uptime = time(NULL);
+ newre->uptime = monotime(NULL);
newre->instance = re->table;
route_entry_copy_nexthops(newre, re->ng.nexthop);
#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;
uint32_t dplane_sequence;
};
+#define RIB_SYSTEM_ROUTE(R) RSYSTEM_ROUTE((R)->type)
+
+#define RIB_KERNEL_ROUTE(R) RKERNEL_ROUTE((R)->type)
+
/* meta-queue structure:
* sub-queue 0: connected, kernel
* sub-queue 1: static
/*
* 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);
}
/*
extern "C" {
#endif
-#define RSYSTEM_ROUTE(type) \
- ((type) == ZEBRA_ROUTE_KERNEL || (type) == ZEBRA_ROUTE_CONNECT)
+#define RKERNEL_ROUTE(type) ((type) == ZEBRA_ROUTE_KERNEL)
+
+#define RSYSTEM_ROUTE(type) \
+ ((RKERNEL_ROUTE(type)) || (type) == ZEBRA_ROUTE_CONNECT)
/*
* Update or delete a route, LSP, or pseudowire from the kernel,
re->vrf_id = vrf_id;
re->table = table;
re->nexthop_num = 0;
- re->uptime = time(NULL);
+ re->uptime = monotime(NULL);
re->tag = tag;
for (;;) {
#include "zebra/debug.h"
#include "zebra/rib.h"
#include "zebra/zapi_msg.h"
-#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_router.h"
RTADV_READ
};
-static void rtadv_event(struct zebra_ns *, enum rtadv_event, int);
+static void rtadv_event(struct zebra_vrf *, enum rtadv_event, int);
static int if_join_all_router(int, struct interface *);
static int if_leave_all_router(int, struct interface *);
-static int rtadv_increment_received(struct zebra_ns *zns, ifindex_t *ifindex)
+static int rtadv_get_socket(struct zebra_vrf *zvrf)
+{
+ if (zvrf->rtadv.sock >= 0)
+ return zvrf->rtadv.sock;
+ return zrouter.rtadv_sock;
+}
+
+static int rtadv_increment_received(struct zebra_vrf *zvrf, ifindex_t *ifindex)
{
int ret = -1;
struct interface *iface;
struct zebra_if *zif;
- iface = if_lookup_by_index_per_ns(zns, *ifindex);
+ iface = if_lookup_by_index(*ifindex, zvrf->vrf->vrf_id);
if (iface && iface->info) {
zif = iface->info;
zif->ra_rcvd++;
return ret;
}
-static int rtadv_recv_packet(struct zebra_ns *zns, int sock, uint8_t *buf,
+static int rtadv_recv_packet(struct zebra_vrf *zvrf, int sock, uint8_t *buf,
int buflen, struct sockaddr_in6 *from,
ifindex_t *ifindex, int *hoplimit)
{
}
}
- rtadv_increment_received(zns, ifindex);
+ rtadv_increment_received(zvrf, ifindex);
return ret;
}
static int rtadv_timer(struct thread *thread)
{
- struct zebra_ns *zns = THREAD_ARG(thread);
+ struct zebra_vrf *zvrf = THREAD_ARG(thread);
struct vrf *vrf;
struct interface *ifp;
struct zebra_if *zif;
int period;
- zrouter.rtadv.ra_timer = NULL;
- if (zrouter.rtadv.adv_msec_if_count == 0) {
+ zvrf->rtadv.ra_timer = NULL;
+ if (zvrf->rtadv.adv_msec_if_count == 0) {
period = 1000; /* 1 s */
- rtadv_event(zns, RTADV_TIMER, 1 /* 1 s */);
+ rtadv_event(zvrf, RTADV_TIMER, 1 /* 1 s */);
} else {
period = 10; /* 10 ms */
- rtadv_event(zns, RTADV_TIMER_MSEC, 10 /* 10 ms */);
+ rtadv_event(zvrf, RTADV_TIMER_MSEC, 10 /* 10 ms */);
}
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
"Fast RA Rexmit on interface %s",
ifp->name);
- rtadv_send_packet(zrouter.rtadv.sock,
+ rtadv_send_packet(rtadv_get_socket(zvrf),
ifp);
} else {
zif->rtadv.AdvIntervalTimer -= period;
zif->rtadv
.MaxRtrAdvInterval;
rtadv_send_packet(
- zrouter.rtadv.sock,
- ifp);
+ rtadv_get_socket(zvrf),
+ ifp);
}
}
}
static void rtadv_process_solicit(struct interface *ifp)
{
struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
- struct zebra_ns *zns = zvrf->zns;
- assert(zns);
- rtadv_send_packet(zrouter.rtadv.sock, ifp);
+ assert(zvrf);
+ rtadv_send_packet(rtadv_get_socket(zvrf), ifp);
}
/*
static void rtadv_process_packet(uint8_t *buf, unsigned int len,
ifindex_t ifindex, int hoplimit,
struct sockaddr_in6 *from,
- struct zebra_ns *zns)
+ struct zebra_vrf *zvrf)
{
struct icmp6_hdr *icmph;
struct interface *ifp;
inet_ntop(AF_INET6, &from->sin6_addr, addr_str, INET6_ADDRSTRLEN);
/* Interface search. */
- ifp = if_lookup_by_index_per_ns(zns, ifindex);
+ ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id);
if (ifp == NULL) {
flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
"RA/RS received on unknown IF %u from %s", ifindex,
struct sockaddr_in6 from;
ifindex_t ifindex = 0;
int hoplimit = -1;
- struct zebra_ns *zns = THREAD_ARG(thread);
+ struct zebra_vrf *zvrf = THREAD_ARG(thread);
sock = THREAD_FD(thread);
- zrouter.rtadv.ra_read = NULL;
+ zvrf->rtadv.ra_read = NULL;
/* Register myself. */
- rtadv_event(zns, RTADV_READ, sock);
+ rtadv_event(zvrf, RTADV_READ, sock);
- len = rtadv_recv_packet(zns, sock, buf, sizeof(buf), &from, &ifindex,
+ len = rtadv_recv_packet(zvrf, sock, buf, sizeof(buf), &from, &ifindex,
&hoplimit);
if (len < 0) {
return len;
}
- rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zns);
+ rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zvrf);
return 0;
}
{
struct zebra_if *zif;
struct zebra_vrf *zvrf;
- struct zebra_ns *zns;
zif = ifp->info;
zvrf = vrf_info_lookup(ifp->vrf_id);
- zns = zvrf->zns;
if (status == RA_SUPPRESS) {
/* RA is currently enabled */
if (zif->rtadv.AdvSendAdvertisements) {
zif->rtadv.AdvSendAdvertisements = 0;
zif->rtadv.AdvIntervalTimer = 0;
- zrouter.rtadv.adv_if_count--;
+ zvrf->rtadv.adv_if_count--;
- if_leave_all_router(zrouter.rtadv.sock, ifp);
+ if_leave_all_router(rtadv_get_socket(zvrf), ifp);
- if (zrouter.rtadv.adv_if_count == 0)
- rtadv_event(zns, RTADV_STOP, 0);
+ if (zvrf->rtadv.adv_if_count == 0)
+ rtadv_event(zvrf, RTADV_STOP, 0);
}
} else {
if (!zif->rtadv.AdvSendAdvertisements) {
zif->rtadv.AdvSendAdvertisements = 1;
zif->rtadv.AdvIntervalTimer = 0;
- zrouter.rtadv.adv_if_count++;
+ zvrf->rtadv.adv_if_count++;
if (zif->rtadv.MaxRtrAdvInterval >= 1000) {
/* Enable Fast RA only when RA interval is in
RTADV_NUM_FAST_REXMITS;
}
- if_join_all_router(zrouter.rtadv.sock, ifp);
+ if_join_all_router(rtadv_get_socket(zvrf), ifp);
- if (zrouter.rtadv.adv_if_count == 1)
- rtadv_event(zns, RTADV_START,
- zrouter.rtadv.sock);
+ if (zvrf->rtadv.adv_if_count == 1)
+ rtadv_event(zvrf, RTADV_START,
+ rtadv_get_socket(zvrf));
}
}
}
zebra_route_string(client->proto), ra_interval);
/* Locate interface and check VRF match. */
- ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), ifindex);
+ ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id);
if (!ifp) {
flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
"%u: IF %u RA %s client %s - interface unknown",
VTY_DECLVAR_CONTEXT(interface, ifp);
unsigned interval;
struct zebra_if *zif = ifp->info;
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup(ifp->vrf_id);
interval = strtoul(argv[idx_number]->arg, NULL, 10);
if ((zif->rtadv.AdvDefaultLifetime != -1
}
if (zif->rtadv.MaxRtrAdvInterval % 1000)
- zrouter.rtadv.adv_msec_if_count--;
+ zvrf->rtadv.adv_msec_if_count--;
if (interval % 1000)
- zrouter.rtadv.adv_msec_if_count++;
+ zvrf->rtadv.adv_msec_if_count++;
SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
zif->rtadv.MaxRtrAdvInterval = interval;
VTY_DECLVAR_CONTEXT(interface, ifp);
unsigned interval;
struct zebra_if *zif = ifp->info;
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup(ifp->vrf_id);
interval = strtoul(argv[idx_number]->arg, NULL, 10);
if ((zif->rtadv.AdvDefaultLifetime != -1
}
if (zif->rtadv.MaxRtrAdvInterval % 1000)
- zrouter.rtadv.adv_msec_if_count--;
+ zvrf->rtadv.adv_msec_if_count--;
/* convert to milliseconds */
interval = interval * 1000;
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct zebra_if *zif = ifp->info;
+ struct zebra_vrf *zvrf = NULL;
+
+ zvrf = vrf_info_lookup(ifp->vrf_id);
if (zif->rtadv.MaxRtrAdvInterval % 1000)
- zrouter.rtadv.adv_msec_if_count--;
+ zvrf->rtadv.adv_msec_if_count--;
UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
}
-static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
+static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
{
- struct rtadv *rtadv = &zrouter.rtadv;
+ struct rtadv *rtadv = &zvrf->rtadv;
switch (event) {
case RTADV_START:
- thread_add_read(zrouter.master, rtadv_read, zns, val,
+ thread_add_read(zrouter.master, rtadv_read, zvrf, val,
&rtadv->ra_read);
- thread_add_event(zrouter.master, rtadv_timer, zns, 0,
+ thread_add_event(zrouter.master, rtadv_timer, zvrf, 0,
&rtadv->ra_timer);
break;
case RTADV_STOP:
}
break;
case RTADV_TIMER:
- thread_add_timer(zrouter.master, rtadv_timer, zns, val,
+ thread_add_timer(zrouter.master, rtadv_timer, zvrf, val,
&rtadv->ra_timer);
break;
case RTADV_TIMER_MSEC:
- thread_add_timer_msec(zrouter.master, rtadv_timer, zns, val,
+ thread_add_timer_msec(zrouter.master, rtadv_timer, zvrf, val,
&rtadv->ra_timer);
break;
case RTADV_READ:
- thread_add_read(zrouter.master, rtadv_read, zns, val,
+ thread_add_read(zrouter.master, rtadv_read, zvrf, val,
&rtadv->ra_read);
break;
default:
return;
}
-void rtadv_init(struct zebra_ns *zns)
+void rtadv_init(struct zebra_vrf *zvrf)
{
- zrouter.rtadv.sock = rtadv_make_socket(zns->ns_id);
+ if (vrf_is_backend_netns()) {
+ zvrf->rtadv.sock = rtadv_make_socket(zvrf->zns->ns_id);
+ zrouter.rtadv_sock = -1;
+ } else if (!zrouter.rtadv_sock) {
+ zvrf->rtadv.sock = -1;
+ zrouter.rtadv_sock = rtadv_make_socket(zvrf->zns->ns_id);
+ }
}
-void rtadv_terminate(struct zebra_ns *zns)
+void rtadv_terminate(struct zebra_vrf *zvrf)
{
- rtadv_event(zns, RTADV_STOP, 0);
- if (zrouter.rtadv.sock >= 0) {
- close(zrouter.rtadv.sock);
- zrouter.rtadv.sock = -1;
+ rtadv_event(zvrf, RTADV_STOP, 0);
+ if (zvrf->rtadv.sock >= 0) {
+ close(zvrf->rtadv.sock);
+ zvrf->rtadv.sock = -1;
+ } else if (zrouter.rtadv_sock >= 0) {
+ close(zrouter.rtadv_sock);
+ zrouter.rtadv_sock = -1;
}
-
- zrouter.rtadv.adv_if_count = 0;
- zrouter.rtadv.adv_msec_if_count = 0;
+ zvrf->rtadv.adv_if_count = 0;
+ zvrf->rtadv.adv_msec_if_count = 0;
}
void rtadv_cmd_init(void)
}
#else
-void rtadv_init(struct zebra_ns *zns)
+void rtadv_init(struct zebra_vrf *zvrf)
{
/* Empty.*/;
}
-void rtadv_terminate(struct zebra_ns *zns)
+void rtadv_terminate(struct zebra_vrf *zvrf)
{
/* Empty.*/;
}
RA_SUPPRESS,
} ipv6_nd_suppress_ra_status;
-extern void rtadv_init(struct zebra_ns *);
-extern void rtadv_terminate(struct zebra_ns *);
+extern void rtadv_init(struct zebra_vrf *);
+extern void rtadv_terminate(struct zebra_vrf *);
extern void rtadv_cmd_init(void);
extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS);
extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS);
void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
const unsigned int nexthop_num)
{
- if (nexthop_num > multipath_num) {
+ if (nexthop_num > zrouter.multipath_num) {
char buff[PREFIX2STR_BUFFER];
prefix2str(p, buff, sizeof(buff));
flog_warn(
EC_ZEBRA_MORE_NH_THAN_MULTIPATH,
"%s: Prefix %s has %d nexthops, but we can only use the first %d",
- caller, buff, nexthop_num, multipath_num);
+ caller, buff, nexthop_num, zrouter.multipath_num);
}
}
re->type = api.type;
re->instance = api.instance;
re->flags = api.flags;
- re->uptime = time(NULL);
+ re->uptime = monotime(NULL);
re->vrf_id = vrf_id;
if (api.tableid && vrf_id == VRF_DEFAULT)
re->table = api.tableid;
zclient_create_header(s, ZEBRA_CAPABILITIES, zvrf->vrf->vrf_id);
stream_putl(s, vrf_get_backend());
stream_putc(s, mpls_enabled);
- stream_putl(s, multipath_num);
+ stream_putl(s, zrouter.multipath_num);
stream_putc(s, zebra_mlag_get_role());
stream_putw_at(s, 0, stream_get_endp(s));
else {
atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1,
memory_order_relaxed);
- if (ctx)
- dplane_ctx_free(&ctx);
+ dplane_ctx_free(&ctx);
}
return result;
else {
atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1,
memory_order_relaxed);
- if (ctx)
- dplane_ctx_free(&ctx);
+ dplane_ctx_free(&ctx);
}
return result;
/* Error counter */
atomic_fetch_add_explicit(&zdplane_info.dg_intf_addr_errors,
1, memory_order_relaxed);
- if (ctx)
- dplane_ctx_free(&ctx);
+ dplane_ctx_free(&ctx);
}
return result;
#include "prefix.h"
#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/zebra_dplane.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
ri->metric = &re->metric;
for (ALL_NEXTHOPS(re->ng, nexthop)) {
- if (ri->num_nhs >= multipath_num)
+ if (ri->num_nhs >= zrouter.multipath_num)
break;
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
ri->rtm_type = RTN_BLACKHOLE;
break;
}
- return 1;
}
if ((cmd == RTM_NEWROUTE
uint32_t label_index);
static int fec_del(zebra_fec_t *fec);
-static unsigned int label_hash(void *p);
+static unsigned int label_hash(const void *p);
static bool label_cmp(const void *p1, const void *p2);
static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe,
struct nexthop *nexthop);
/*
* Hash function for label.
*/
-static unsigned int label_hash(void *p)
+static unsigned int label_hash(const void *p)
{
const zebra_ile_t *ile = p;
ifp = if_lookup_by_index_per_ns(
zns,
nexthop->ifindex);
- vty_out(vty, "%15s", ifp->name);
+ if (ifp)
+ vty_out(vty, "%15s", ifp->name);
+ else
+ vty_out(vty, "%15s", "Null");
+
break;
}
case NEXTHOP_TYPE_IPV4:
/*
* Called when VRF becomes inactive, cleans up information but keeps
* the table itself.
- * NOTE: Currently supported only for default VRF.
*/
void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
{
- hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
+ struct zebra_vrf *def_zvrf;
+ afi_t afi;
+
+ if (zvrf_id(zvrf) == VRF_DEFAULT)
+ hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
+ else {
+ /*
+ * For other vrfs, we try to remove associated LSPs; we locate
+ * the LSPs in the default vrf.
+ */
+ def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
+
+ /* At shutdown, the default may be gone already */
+ if (def_zvrf == NULL)
+ return;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ if (zvrf->label[afi] != MPLS_LABEL_NONE)
+ lsp_uninstall(def_zvrf, zvrf->label[afi]);
+ }
+ }
}
/*
#include "zebra/zebra_mpls.h"
#include "zebra/debug.h"
#include "zebra/zebra_errors.h"
+#include "zebra/zebra_router.h"
#include "privs.h"
#include "prefix.h"
if (!nexthop)
continue;
- if (nexthop_num >= multipath_num)
+ if (nexthop_num >= zrouter.multipath_num)
break;
if (((action == RTM_ADD || action == RTM_CHANGE)
#include "lib/prefix.h"
#include "lib/memory.h"
-#include "rtadv.h"
#include "zebra_ns.h"
#include "zebra_vrf.h"
#include "zebra_memory.h"
zns->ns_id = ns_id;
-#if defined(HAVE_RTADV)
- rtadv_init(zns);
-#endif
-
kernel_init(zns);
interface_list(zns);
route_read(zns);
static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete)
{
route_table_finish(zns->if_table);
-#if defined(HAVE_RTADV)
- rtadv_terminate(zns);
-#endif
kernel_terminate(zns, complete);
XFREE(MTYPE_TMP, rule);
}
-uint32_t zebra_pbr_rules_hash_key(void *arg)
+uint32_t zebra_pbr_rules_hash_key(const void *arg)
{
- struct zebra_pbr_rule *rule;
+ const struct zebra_pbr_rule *rule;
uint32_t key;
- rule = (struct zebra_pbr_rule *)arg;
+ rule = arg;
key = jhash_3words(rule->rule.seq, rule->rule.priority,
rule->rule.action.table,
prefix_hash_key(&rule->rule.filter.src_ip));
XFREE(MTYPE_TMP, ipset);
}
-uint32_t zebra_pbr_ipset_hash_key(void *arg)
+uint32_t zebra_pbr_ipset_hash_key(const void *arg)
{
- struct zebra_pbr_ipset *ipset = (struct zebra_pbr_ipset *)arg;
+ const struct zebra_pbr_ipset *ipset = arg;
uint32_t *pnt = (uint32_t *)&ipset->ipset_name;
uint32_t key = jhash_1word(ipset->vrf_id, 0x63ab42de);
XFREE(MTYPE_TMP, ipset);
}
-uint32_t zebra_pbr_ipset_entry_hash_key(void *arg)
+uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg)
{
- struct zebra_pbr_ipset_entry *ipset;
+ const struct zebra_pbr_ipset_entry *ipset;
uint32_t key;
- ipset = (struct zebra_pbr_ipset_entry *)arg;
+ ipset = arg;
key = prefix_hash_key(&ipset->src);
key = jhash_1word(ipset->unique, key);
key = jhash_1word(prefix_hash_key(&ipset->dst), key);
XFREE(MTYPE_TMP, iptable);
}
-uint32_t zebra_pbr_iptable_hash_key(void *arg)
+uint32_t zebra_pbr_iptable_hash_key(const void *arg)
{
- struct zebra_pbr_iptable *iptable = (struct zebra_pbr_iptable *)arg;
+ const struct zebra_pbr_iptable *iptable = arg;
uint32_t *pnt = (uint32_t *)&(iptable->ipset_name);
uint32_t key;
extern int kernel_pbr_rule_del(struct zebra_pbr_rule *rule);
extern void zebra_pbr_rules_free(void *arg);
-extern uint32_t zebra_pbr_rules_hash_key(void *arg);
+extern uint32_t zebra_pbr_rules_hash_key(const void *arg);
extern bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2);
/* has operates on 32bit pointer
#define ZEBRA_IPSET_NAME_HASH_SIZE (ZEBRA_IPSET_NAME_SIZE / 4)
extern void zebra_pbr_ipset_free(void *arg);
-extern uint32_t zebra_pbr_ipset_hash_key(void *arg);
+extern uint32_t zebra_pbr_ipset_hash_key(const void *arg);
extern bool zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2);
extern void zebra_pbr_ipset_entry_free(void *arg);
-extern uint32_t zebra_pbr_ipset_entry_hash_key(void *arg);
+extern uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg);
extern bool zebra_pbr_ipset_entry_hash_equal(const void *arg1,
const void *arg2);
extern void zebra_pbr_iptable_free(void *arg);
-extern uint32_t zebra_pbr_iptable_hash_key(void *arg);
+extern uint32_t zebra_pbr_iptable_hash_key(const void *arg);
extern bool zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2);
extern void zebra_pbr_init(void);
static void zebra_ptm_send_bfdd(struct stream *msg);
static void zebra_ptm_send_clients(struct stream *msg);
static int _zebra_ptm_bfd_client_deregister(struct zserv *zs);
-static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
- uint32_t command);
+static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
+ struct stream *msg, uint32_t command);
/*
/*
* Message handling.
*/
-static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
- uint32_t command)
+static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
+ struct stream *msg, uint32_t command)
{
struct stream *msgc;
size_t zmsglen, zhdrlen;
* one callback at the `bfdd` side, however the real command
* number will be included right after the zebra header.
*/
- zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, 0);
+ zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, zvrf->vrf->vrf_id);
stream_putl(msgc, command);
/* Update the data pointers. */
zlog_debug("bfd_dst_register msg from client %s: length=%d",
zebra_route_string(client->proto), hdr->length);
- _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REGISTER);
+ _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REGISTER);
}
void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
zebra_route_string(client->proto), hdr->length);
- _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_DEREGISTER);
+ _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_DEREGISTER);
}
void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
zlog_debug("bfd_client_register msg from client %s: length=%d",
zebra_route_string(client->proto), hdr->length);
- _zebra_ptm_reroute(client, msg, ZEBRA_BFD_CLIENT_REGISTER);
+ _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_CLIENT_REGISTER);
}
void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS)
* special treatment.
*/
if (client->proto != ZEBRA_ROUTE_BFD) {
- _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REPLAY);
+ _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REPLAY);
return;
}
return NULL;
}
-#define RIB_SYSTEM_ROUTE(R) \
- ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
-
-#define RIB_KERNEL_ROUTE(R) \
- ((R)->type == ZEBRA_ROUTE_KERNEL)
-
/* This function verifies reachability of one given nexthop, which can be
* numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
* in nexthop->flags field. The nexthop->ifindex will be updated
* decision point.
*/
new_active = nexthop_active_check(rn, re, nexthop);
- if (new_active && re->nexthop_active_num >= multipath_num) {
+ if (new_active
+ && re->nexthop_active_num >= zrouter.multipath_num) {
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
new_active = 0;
}
*/
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;
re->table = table_id;
re->vrf_id = vrf_id;
re->nexthop_num = 0;
- re->uptime = time(NULL);
+ re->uptime = monotime(NULL);
re->tag = tag;
/* Add nexthop. */
}
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;
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
}
-static void zebra_route_map_event(route_map_event_t event,
- const char *rmap_name)
+static void zebra_route_map_event(const char *rmap_name)
{
if (route_map_mark_updated(rmap_name) == 0)
zebra_route_map_mark_update(rmap_name);
#include "zebra_vxlan.h"
#include "zebra_mlag.h"
-struct zebra_router zrouter;
+struct zebra_router zrouter = {
+ .multipath_num = MULTIPATH_NUM,
+};
static inline int
zebra_router_table_entry_compare(const struct zebra_router_table *e1,
struct hash *iptable_hash;
-#if defined(HAVE_RTADV)
- struct rtadv rtadv;
-#endif /* HAVE_RTADV */
+ /* used if vrf backend is not network namespace */
+ int rtadv_sock;
/* A sequence number used for tracking routes */
_Atomic uint32_t sequence_num;
* The EVPN instance, if any
*/
struct zebra_vrf *evpn_vrf;
+
+ uint32_t multipath_num;
};
extern struct zebra_router zrouter;
#include "vty.h"
#include "zebra/zebra_router.h"
+#include "zebra/rtadv.h"
#include "zebra/debug.h"
#include "zebra/zapi_msg.h"
#include "zebra/rib.h"
zvrf->zns = zebra_ns_lookup((ns_id_t)vrf->vrf_id);
else
zvrf->zns = zebra_ns_lookup(NS_DEFAULT);
+#if defined(HAVE_RTADV)
+ rtadv_init(zvrf);
+#endif
+
/* Inform clients that the VRF is now active. This is an
* add for the clients.
*/
/* Stop any VxLAN-EVPN processing. */
zebra_vxlan_vrf_disable(zvrf);
+#if defined(HAVE_RTADV)
+ rtadv_terminate(zvrf);
+#endif
+
/* Inform clients that the VRF is now inactive. This is a
* delete for the clients.
*/
if (node->info) {
rib_dest_t *dest = node->info;
- list_delete(&dest->nht);
+ rnh_list_fini(&dest->nht);
XFREE(MTYPE_RIB_DEST, node->info);
}
}
uint64_t lsp_removals_queued;
uint64_t lsp_installs;
uint64_t lsp_removals;
+
+#if defined(HAVE_RTADV)
+ struct rtadv rtadv;
+#endif /* HAVE_RTADV */
};
#define PROTO_RM_NAME(zvrf, afi, rtype) zvrf->proto_rm[afi][rtype].name
#define NHT_RM_NAME(zvrf, afi, rtype) zvrf->nht_rm[afi][rtype].name
bool supernets_only, int type,
unsigned short ospf_instance_id);
static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
- int mcast);
+ int mcast, bool use_fib);
static void vty_show_ip_route_summary(struct vty *vty,
struct route_table *table);
static void vty_show_ip_route_summary_prefix(struct vty *vty,
re = rib_match_ipv4_multicast(VRF_DEFAULT, addr, &rn);
if (re)
- vty_show_ip_route_detail(vty, rn, 1);
+ vty_show_ip_route_detail(vty, rn, 1, false);
else
vty_out(vty, "%% No match for RPF lookup\n");
/* New RIB. Detailed information for IPv4 route. */
static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
- int mcast)
+ int mcast, bool use_fib)
{
struct route_entry *re;
struct nexthop *nexthop;
char buf[SRCDEST2STR_BUFFER];
struct zebra_vrf *zvrf;
+ rib_dest_t *dest;
+
+ dest = rib_dest_from_rnode(rn);
RNODE_FOREACH_RE (rn, re) {
+ /*
+ * If re not selected for forwarding, skip re
+ * for "show ip/ipv6 fib <prefix>"
+ */
+ if (use_fib && re != dest->selected_fib)
+ continue;
+
const char *mcast_info = "";
if (mcast) {
rib_table_info_t *info = srcdest_rnode_table_info(rn);
time_t uptime;
struct tm *tm;
- uptime = time(NULL);
+ uptime = monotime(NULL);
uptime -= re->uptime;
tm = gmtime(&uptime);
struct tm *tm;
rib_dest_t *dest = rib_dest_from_rnode(rn);
- uptime = time(NULL);
+ uptime = monotime(NULL);
uptime -= re->uptime;
tm = gmtime(&uptime);
}
static void vty_show_ip_route_detail_json(struct vty *vty,
- struct route_node *rn)
+ struct route_node *rn, bool use_fib)
{
json_object *json = NULL;
json_object *json_prefix = NULL;
struct route_entry *re;
char buf[BUFSIZ];
+ rib_dest_t *dest;
+
+ dest = rib_dest_from_rnode(rn);
json = json_object_new_object();
json_prefix = json_object_new_array();
RNODE_FOREACH_RE (rn, re) {
+ /*
+ * If re not selected for forwarding, skip re
+ * for "show ip/ipv6 fib <prefix> json"
+ */
+ if (use_fib && re != dest->selected_fib)
+ continue;
vty_show_ip_route(vty, rn, re, json_prefix);
}
show_route_detail_cmd,
"show\
<\
- ip$ipv4 route [vrf <NAME$vrf_name|all$vrf_all>]\
+ ip$ipv4 <fib$fib|route> [vrf <NAME$vrf_name|all$vrf_all>]\
<\
A.B.C.D$address\
|A.B.C.D/M$prefix\
>\
- |ipv6$ipv6 route [vrf <NAME$vrf_name|all$vrf_all>]\
+ |ipv6$ipv6 <fib$fib|route> [vrf <NAME$vrf_name|all$vrf_all>]\
<\
X:X::X:X$address\
|X:X::X:X/M$prefix\
[json$json]",
SHOW_STR
IP_STR
+ "IPv6 forwarding table\n"
"IP routing table\n"
VRF_FULL_CMD_HELP_STR
"Network in the IP routing table to display\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
IP6_STR
- "IP routing table\n"
+ "IPv6 forwarding table\n"
+ "IPv6 routing table\n"
VRF_FULL_CMD_HELP_STR
"IPv6 Address\n"
"IPv6 prefix\n"
struct route_table *table;
struct prefix p;
struct route_node *rn;
+ bool use_fib = !!fib;
+ rib_dest_t *dest;
+ bool network_found = false;
if (address_str)
prefix_str = address_str;
continue;
}
+ dest = rib_dest_from_rnode(rn);
+ if (use_fib && !dest->selected_fib) {
+ route_unlock_node(rn);
+ continue;
+ }
+
+ network_found = true;
if (json)
- vty_show_ip_route_detail_json(vty, rn);
+ vty_show_ip_route_detail_json(vty, rn,
+ use_fib);
else
- vty_show_ip_route_detail(vty, rn, 0);
+ vty_show_ip_route_detail(vty, rn, 0, use_fib);
route_unlock_node(rn);
}
+
+ if (!network_found) {
+ if (json)
+ vty_out(vty, "{}\n");
+ else {
+ if (use_fib)
+ vty_out(vty,
+ "%% Network not in FIB\n");
+ else
+ vty_out(vty,
+ "%% Network not in RIB\n");
+ }
+ return CMD_WARNING;
+ }
} else {
vrf_id_t vrf_id = VRF_DEFAULT;
return CMD_SUCCESS;
rn = route_node_match(table, &p);
- if (!rn) {
- vty_out(vty, "%% Network not in table\n");
- return CMD_WARNING;
- }
- if (!address_str && rn->p.prefixlen != p.prefixlen) {
- vty_out(vty, "%% Network not in table\n");
- route_unlock_node(rn);
+ if (rn)
+ dest = rib_dest_from_rnode(rn);
+
+ if (!rn || (!address_str && rn->p.prefixlen != p.prefixlen) ||
+ (use_fib && dest && !dest->selected_fib)) {
+ if (json)
+ vty_out(vty, "{}\n");
+ else {
+ if (use_fib)
+ vty_out(vty,
+ "%% Network not in FIB\n");
+ else
+ vty_out(vty,
+ "%% Network not in table\n");
+ }
+ if (rn)
+ route_unlock_node(rn);
return CMD_WARNING;
}
if (json)
- vty_show_ip_route_detail_json(vty, rn);
+ vty_show_ip_route_detail_json(vty, rn, use_fib);
else
- vty_show_ip_route_detail(vty, rn, 0);
+ vty_show_ip_route_detail(vty, rn, 0, use_fib);
route_unlock_node(rn);
}
static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
struct ipaddr *ip, uint8_t flags,
uint32_t seq, int state, uint16_t cmd);
-static unsigned int neigh_hash_keymake(void *p);
+static unsigned int neigh_hash_keymake(const void *p);
static void *zvni_neigh_alloc(void *p);
static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
struct ethaddr *mac);
static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni);
static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni);
-static unsigned int mac_hash_keymake(void *p);
+static unsigned int mac_hash_keymake(const void *p);
static bool mac_cmp(const void *p1, const void *p2);
static void *zvni_mac_alloc(void *p);
static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr);
static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac);
static void zvni_install_mac_hash(struct hash_bucket *bucket, void *ctxt);
-static unsigned int vni_hash_keymake(void *p);
+static unsigned int vni_hash_keymake(const void *p);
static void *zvni_alloc(void *p);
static zebra_vni_t *zvni_lookup(vni_t vni);
static zebra_vni_t *zvni_add(vni_t vni);
bool do_dad,
bool *is_dup_detect,
bool is_local);
-static unsigned int zebra_vxlan_sg_hash_key_make(void *p);
+static unsigned int zebra_vxlan_sg_hash_key_make(const void *p);
static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2);
static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf,
struct in_addr sip, struct in_addr mcast_grp);
/*
* Make hash key for neighbors.
*/
-static unsigned int neigh_hash_keymake(void *p)
+static unsigned int neigh_hash_keymake(const void *p)
{
- zebra_neigh_t *n = p;
- struct ipaddr *ip = &n->ip;
+ const zebra_neigh_t *n = p;
+ const struct ipaddr *ip = &n->ip;
if (IS_IPADDR_V4(ip))
return jhash_1word(ip->ipaddr_v4.s_addr, 0);
/*
* Make hash key for MAC.
*/
-static unsigned int mac_hash_keymake(void *p)
+static unsigned int mac_hash_keymake(const void *p)
{
- zebra_mac_t *pmac = p;
+ const zebra_mac_t *pmac = p;
const void *pnt = (void *)pmac->macaddr.octet;
return jhash(pnt, ETH_ALEN, 0xa5a5a55a);
/*
* Hash function for VNI.
*/
-static unsigned int vni_hash_keymake(void *p)
+static unsigned int vni_hash_keymake(const void *p)
{
const zebra_vni_t *zvni = p;
/*
* Hash function for L3 VNI.
*/
-static unsigned int l3vni_hash_keymake(void *p)
+static unsigned int l3vni_hash_keymake(const void *p)
{
const zebra_l3vni_t *zl3vni = p;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Add/update remote MAC %s intf %s(%u) VNI %u - del local",
+ "Add/update remote MAC %s intf %s(%u) VNI %u flags 0x%x - del local",
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
- ifp->ifindex, vni);
+ ifp->ifindex, vni, mac->flags);
/* Remove MAC from BGP. */
zvni_mac_send_del_to_client(zvni->vni, macaddr);
zvni_mac_del(zvni, mac);
} else {
UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
}
return -1;
}
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
- ifp->ifindex, vid, zvni->vni);
-
/* If entry doesn't exist, nothing to do. */
mac = zvni_mac_lookup(zvni, macaddr);
if (!mac)
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
return 0;
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u flags 0x%x",
+ prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
+ ifp->ifindex, vid, zvni->vni, mac->flags);
+
/* Update all the neigh entries associated with this mac */
zvni_process_neigh_on_local_mac_del(zvni, mac);
zvni_mac_del(zvni, mac);
} else {
UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
}
return zserv_send_message(client, s);
}
-static unsigned int zebra_vxlan_sg_hash_key_make(void *p)
+static unsigned int zebra_vxlan_sg_hash_key_make(const void *p)
{
- zebra_vxlan_sg_t *vxlan_sg = p;
+ const zebra_vxlan_sg_t *vxlan_sg = p;
return (jhash_2words(vxlan_sg->sg.src.s_addr,
vxlan_sg->sg.grp.s_addr, 0));
DECLARE_HOOK(zserv_client_connect, (struct zserv *client), (client));
DECLARE_KOOH(zserv_client_close, (struct zserv *client), (client));
-extern unsigned int multipath_num;
-
/*
* Initialize Zebra API server.
*