mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-06-14 01:38:24 +00:00
Merge remote-tracking 'frr/master' into SR-Routing
This commit is contained in:
commit
dab8b7a81c
@ -57,3 +57,5 @@ ForEachMacros:
|
||||
- SUBGRP_FOREACH_ADJ_SAFE
|
||||
- AF_FOREACH
|
||||
- FOREACH_AFI_SAFI
|
||||
# ospfd
|
||||
- LSDB_LOOP
|
||||
|
12
README
12
README
@ -1,12 +1,14 @@
|
||||
FRRouting is free software that manages various IPv4 and IPv6 routing
|
||||
protocols.
|
||||
FRRouting is free software that implements and manages various IPv4 and IPv6
|
||||
routing protocols.
|
||||
|
||||
Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1,
|
||||
RIPv2, RIPng, PIM-SM/MSDP and LDP as well as very early support for IS-IS,
|
||||
EIGRP and NHRP.
|
||||
Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, RIPng,
|
||||
IS-IS, PIM-SM/MSDP, LDP and Babel as well as very early support for EIGRP and
|
||||
NHRP.
|
||||
|
||||
See the file REPORTING-BUGS to report bugs.
|
||||
|
||||
See COMMUNITY.md for information on contributing.
|
||||
|
||||
Free RRRouting is free software. See the file COPYING for copying conditions.
|
||||
|
||||
Public email discussion can be found at https://lists.frrouting.org/listinfo
|
||||
|
@ -166,6 +166,7 @@ zebra_route(int add, int family, const unsigned char *pref, unsigned short plen,
|
||||
api.type = ZEBRA_ROUTE_BABEL;
|
||||
api.safi = SAFI_UNICAST;
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.prefix = quagga_prefix;
|
||||
|
||||
if(metric >= KERNEL_INFINITY) {
|
||||
|
@ -246,8 +246,6 @@ void bgp_sync_init(struct peer *peer)
|
||||
BGP_ADV_FIFO_INIT(&sync->withdraw);
|
||||
BGP_ADV_FIFO_INIT(&sync->withdraw_low);
|
||||
peer->sync[afi][safi] = sync;
|
||||
peer->hash[afi][safi] = hash_create(baa_hash_key, baa_hash_cmp,
|
||||
"BGP Sync Hash");
|
||||
}
|
||||
}
|
||||
|
||||
@ -260,9 +258,5 @@ void bgp_sync_delete(struct peer *peer)
|
||||
if (peer->sync[afi][safi])
|
||||
XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]);
|
||||
peer->sync[afi][safi] = NULL;
|
||||
|
||||
if (peer->hash[afi][safi])
|
||||
hash_free(peer->hash[afi][safi]);
|
||||
peer->hash[afi][safi] = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -302,13 +302,13 @@ static int bgp_bfd_dest_update(int command, struct zclient *zclient,
|
||||
prefix2str(&dp, buf[0], sizeof(buf[0]));
|
||||
if (ifp) {
|
||||
zlog_debug(
|
||||
"Zebra: vrf %d interface %s bfd destination %s %s",
|
||||
"Zebra: vrf %u interface %s bfd destination %s %s",
|
||||
vrf_id, ifp->name, buf[0],
|
||||
bfd_get_status_str(status));
|
||||
} else {
|
||||
prefix2str(&sp, buf[1], sizeof(buf[1]));
|
||||
zlog_debug(
|
||||
"Zebra: vrf %d source %s bfd destination %s %s",
|
||||
"Zebra: vrf %u source %s bfd destination %s %s",
|
||||
vrf_id, buf[1], buf[0],
|
||||
bfd_get_status_str(status));
|
||||
}
|
||||
|
125
bgpd/bgp_io.c
125
bgpd/bgp_io.c
@ -51,74 +51,13 @@ static bool validate_header(struct peer *);
|
||||
#define BGP_IO_TRANS_ERR (1 << 0) // EAGAIN or similar occurred
|
||||
#define BGP_IO_FATAL_ERR (1 << 1) // some kind of fatal TCP error
|
||||
|
||||
/* Start and stop routines for I/O pthread + control variables
|
||||
* ------------------------------------------------------------------------ */
|
||||
_Atomic bool bgp_io_thread_run;
|
||||
_Atomic bool bgp_io_thread_started;
|
||||
|
||||
void bgp_io_init()
|
||||
{
|
||||
bgp_io_thread_run = false;
|
||||
bgp_io_thread_started = false;
|
||||
}
|
||||
|
||||
/* Unused callback for thread_add_read() */
|
||||
static int bgp_io_dummy(struct thread *thread) { return 0; }
|
||||
|
||||
void *bgp_io_start(void *arg)
|
||||
{
|
||||
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
|
||||
fpt->master->owner = pthread_self();
|
||||
|
||||
// fd so we can sleep in poll()
|
||||
int sleeper[2];
|
||||
pipe(sleeper);
|
||||
thread_add_read(fpt->master, &bgp_io_dummy, NULL, sleeper[0], NULL);
|
||||
|
||||
// we definitely don't want to handle signals
|
||||
fpt->master->handle_signals = false;
|
||||
|
||||
struct thread task;
|
||||
|
||||
atomic_store_explicit(&bgp_io_thread_run, true, memory_order_seq_cst);
|
||||
atomic_store_explicit(&bgp_io_thread_started, true,
|
||||
memory_order_seq_cst);
|
||||
|
||||
while (bgp_io_thread_run) {
|
||||
if (thread_fetch(fpt->master, &task)) {
|
||||
thread_call(&task);
|
||||
}
|
||||
}
|
||||
|
||||
close(sleeper[1]);
|
||||
close(sleeper[0]);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int bgp_io_finish(struct thread *thread)
|
||||
{
|
||||
atomic_store_explicit(&bgp_io_thread_run, false, memory_order_seq_cst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bgp_io_stop(void **result, struct frr_pthread *fpt)
|
||||
{
|
||||
thread_add_event(fpt->master, &bgp_io_finish, NULL, 0, NULL);
|
||||
pthread_join(fpt->thread, result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Extern API -------------------------------------------------------------- */
|
||||
void bgp_io_running(void)
|
||||
{
|
||||
while (!atomic_load_explicit(&bgp_io_thread_started,
|
||||
memory_order_seq_cst))
|
||||
frr_pthread_yield();
|
||||
}
|
||||
/* Thread external API ----------------------------------------------------- */
|
||||
|
||||
void bgp_writes_on(struct peer *peer)
|
||||
{
|
||||
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
|
||||
assert(fpt->running);
|
||||
|
||||
assert(peer->status != Deleted);
|
||||
assert(peer->obuf);
|
||||
assert(peer->ibuf);
|
||||
@ -127,8 +66,6 @@ void bgp_writes_on(struct peer *peer)
|
||||
assert(!peer->t_connect_check_w);
|
||||
assert(peer->fd);
|
||||
|
||||
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
|
||||
|
||||
thread_add_write(fpt->master, bgp_process_writes, peer, peer->fd,
|
||||
&peer->t_write);
|
||||
SET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON);
|
||||
@ -137,6 +74,7 @@ void bgp_writes_on(struct peer *peer)
|
||||
void bgp_writes_off(struct peer *peer)
|
||||
{
|
||||
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
|
||||
assert(fpt->running);
|
||||
|
||||
thread_cancel_async(fpt->master, &peer->t_write, NULL);
|
||||
THREAD_OFF(peer->t_generate_updgrp_packets);
|
||||
@ -146,6 +84,9 @@ void bgp_writes_off(struct peer *peer)
|
||||
|
||||
void bgp_reads_on(struct peer *peer)
|
||||
{
|
||||
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
|
||||
assert(fpt->running);
|
||||
|
||||
assert(peer->status != Deleted);
|
||||
assert(peer->ibuf);
|
||||
assert(peer->fd);
|
||||
@ -155,8 +96,6 @@ void bgp_reads_on(struct peer *peer)
|
||||
assert(!peer->t_connect_check_w);
|
||||
assert(peer->fd);
|
||||
|
||||
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
|
||||
|
||||
thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
|
||||
&peer->t_read);
|
||||
|
||||
@ -166,6 +105,7 @@ void bgp_reads_on(struct peer *peer)
|
||||
void bgp_reads_off(struct peer *peer)
|
||||
{
|
||||
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
|
||||
assert(fpt->running);
|
||||
|
||||
thread_cancel_async(fpt->master, &peer->t_read, NULL);
|
||||
THREAD_OFF(peer->t_process_packet);
|
||||
@ -173,9 +113,9 @@ void bgp_reads_off(struct peer *peer)
|
||||
UNSET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON);
|
||||
}
|
||||
|
||||
/* Internal functions ------------------------------------------------------- */
|
||||
/* Thread internal functions ----------------------------------------------- */
|
||||
|
||||
/**
|
||||
/*
|
||||
* Called from I/O pthread when a file descriptor has become ready for writing.
|
||||
*/
|
||||
static int bgp_process_writes(struct thread *thread)
|
||||
@ -198,11 +138,13 @@ static int bgp_process_writes(struct thread *thread)
|
||||
}
|
||||
pthread_mutex_unlock(&peer->io_mtx);
|
||||
|
||||
if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) { /* no problem */
|
||||
/* no problem */
|
||||
if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) {
|
||||
}
|
||||
|
||||
/* problem */
|
||||
if (CHECK_FLAG(status, BGP_IO_FATAL_ERR)) {
|
||||
reschedule = false; /* problem */
|
||||
reschedule = false;
|
||||
fatal = true;
|
||||
}
|
||||
|
||||
@ -217,7 +159,7 @@ static int bgp_process_writes(struct thread *thread)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Called from I/O pthread when a file descriptor has become ready for reading,
|
||||
* or has hung up.
|
||||
*
|
||||
@ -288,8 +230,10 @@ static int bgp_process_reads(struct thread *thread)
|
||||
/* if this fails we are seriously screwed */
|
||||
assert(pktsize <= BGP_MAX_PACKET_SIZE);
|
||||
|
||||
/* If we have that much data, chuck it into its own
|
||||
* stream and append to input queue for processing. */
|
||||
/*
|
||||
* If we have that much data, chuck it into its own
|
||||
* stream and append to input queue for processing.
|
||||
*/
|
||||
if (ringbuf_remain(ibw) >= pktsize) {
|
||||
struct stream *pkt = stream_new(pktsize);
|
||||
assert(ringbuf_get(ibw, pktbuf, pktsize) == pktsize);
|
||||
@ -323,7 +267,7 @@ static int bgp_process_reads(struct thread *thread)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Flush peer output buffer.
|
||||
*
|
||||
* This function pops packets off of peer->obuf and writes them to peer->fd.
|
||||
@ -342,15 +286,10 @@ static uint16_t bgp_write(struct peer *peer)
|
||||
int num;
|
||||
int update_last_write = 0;
|
||||
unsigned int count = 0;
|
||||
uint32_t oc;
|
||||
uint32_t uo;
|
||||
uint32_t uo = 0;
|
||||
uint16_t status = 0;
|
||||
uint32_t wpkt_quanta_old;
|
||||
|
||||
// save current # updates sent
|
||||
oc = atomic_load_explicit(&peer->update_out, memory_order_relaxed);
|
||||
|
||||
// cache current write quanta
|
||||
wpkt_quanta_old =
|
||||
atomic_load_explicit(&peer->bgp->wpkt_quanta, memory_order_relaxed);
|
||||
|
||||
@ -369,7 +308,7 @@ static uint16_t bgp_write(struct peer *peer)
|
||||
}
|
||||
|
||||
goto done;
|
||||
} else if (num != writenum) // incomplete write
|
||||
} else if (num != writenum)
|
||||
stream_forward_getp(s, num);
|
||||
|
||||
} while (num != writenum);
|
||||
@ -386,6 +325,7 @@ static uint16_t bgp_write(struct peer *peer)
|
||||
case BGP_MSG_UPDATE:
|
||||
atomic_fetch_add_explicit(&peer->update_out, 1,
|
||||
memory_order_relaxed);
|
||||
uo++;
|
||||
break;
|
||||
case BGP_MSG_NOTIFY:
|
||||
atomic_fetch_add_explicit(&peer->notify_out, 1,
|
||||
@ -397,8 +337,10 @@ static uint16_t bgp_write(struct peer *peer)
|
||||
if (peer->v_start >= (60 * 2))
|
||||
peer->v_start = (60 * 2);
|
||||
|
||||
/* Handle Graceful Restart case where the state changes
|
||||
* to Connect instead of Idle */
|
||||
/*
|
||||
* Handle Graceful Restart case where the state changes
|
||||
* to Connect instead of Idle.
|
||||
*/
|
||||
BGP_EVENT_ADD(peer, BGP_Stop);
|
||||
goto done;
|
||||
|
||||
@ -424,9 +366,12 @@ static uint16_t bgp_write(struct peer *peer)
|
||||
}
|
||||
|
||||
done : {
|
||||
/* Update last_update if UPDATEs were written. */
|
||||
uo = atomic_load_explicit(&peer->update_out, memory_order_relaxed);
|
||||
if (uo > oc)
|
||||
/*
|
||||
* Update last_update if UPDATEs were written.
|
||||
* Note: that these are only updated at end,
|
||||
* not per message (i.e., per loop)
|
||||
*/
|
||||
if (uo)
|
||||
atomic_store_explicit(&peer->last_update, bgp_clock(),
|
||||
memory_order_relaxed);
|
||||
|
||||
@ -439,7 +384,7 @@ done : {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads a chunk of data from peer->fd into peer->ibuf_work.
|
||||
*
|
||||
* @return status flag (see top-of-file)
|
||||
|
@ -28,24 +28,6 @@
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "frr_pthread.h"
|
||||
|
||||
/**
|
||||
* Initializes data structures and flags for the write thread.
|
||||
*
|
||||
* This function should be called from the main thread before
|
||||
* bgp_writes_start() is invoked.
|
||||
*/
|
||||
extern void bgp_io_init(void);
|
||||
|
||||
/**
|
||||
* Ensure that the BGP IO thread is actually up and running
|
||||
*
|
||||
* This function must be called immediately after the thread
|
||||
* has been created for running. This is because we want
|
||||
* to make sure that the io thread is ready before other
|
||||
* threads start attempting to use it.
|
||||
*/
|
||||
extern void bgp_io_running(void);
|
||||
|
||||
/**
|
||||
* Start function for write thread.
|
||||
*
|
||||
|
@ -36,14 +36,14 @@
|
||||
#include "bgpd/bgp_keepalives.h"
|
||||
/* clang-format on */
|
||||
|
||||
/**
|
||||
/*
|
||||
* Peer KeepAlive Timer.
|
||||
* Associates a peer with the time of its last keepalive.
|
||||
*/
|
||||
struct pkat {
|
||||
// the peer to send keepalives to
|
||||
/* the peer to send keepalives to */
|
||||
struct peer *peer;
|
||||
// absolute time of last keepalive sent
|
||||
/* absolute time of last keepalive sent */
|
||||
struct timeval last;
|
||||
};
|
||||
|
||||
@ -52,9 +52,6 @@ static pthread_mutex_t *peerhash_mtx;
|
||||
static pthread_cond_t *peerhash_cond;
|
||||
static struct hash *peerhash;
|
||||
|
||||
/* Thread control flag. */
|
||||
bool bgp_keepalives_thread_run = false;
|
||||
|
||||
static struct pkat *pkat_new(struct peer *peer)
|
||||
{
|
||||
struct pkat *pkat = XMALLOC(MTYPE_TMP, sizeof(struct pkat));
|
||||
@ -100,10 +97,10 @@ static void peer_process(struct hash_backet *hb, void *arg)
|
||||
|
||||
static struct timeval tolerance = {0, 100000};
|
||||
|
||||
// calculate elapsed time since last keepalive
|
||||
/* calculate elapsed time since last keepalive */
|
||||
monotime_since(&pkat->last, &elapsed);
|
||||
|
||||
// calculate difference between elapsed time and configured time
|
||||
/* calculate difference between elapsed time and configured time */
|
||||
ka.tv_sec = pkat->peer->v_keepalive;
|
||||
timersub(&ka, &elapsed, &diff);
|
||||
|
||||
@ -118,10 +115,10 @@ static void peer_process(struct hash_backet *hb, void *arg)
|
||||
bgp_keepalive_send(pkat->peer);
|
||||
monotime(&pkat->last);
|
||||
memset(&elapsed, 0x00, sizeof(struct timeval));
|
||||
diff = ka; // time until next keepalive == peer keepalive time
|
||||
diff = ka;
|
||||
}
|
||||
|
||||
// if calculated next update for this peer < current delay, use it
|
||||
/* if calculated next update for this peer < current delay, use it */
|
||||
if (next_update->tv_sec <= 0 || timercmp(&diff, next_update, <))
|
||||
*next_update = diff;
|
||||
}
|
||||
@ -139,29 +136,9 @@ static unsigned int peer_hash_key(void *arg)
|
||||
return (uintptr_t)pkat->peer;
|
||||
}
|
||||
|
||||
void bgp_keepalives_init()
|
||||
{
|
||||
peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t));
|
||||
peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t));
|
||||
|
||||
// initialize mutex
|
||||
pthread_mutex_init(peerhash_mtx, NULL);
|
||||
|
||||
// use monotonic clock with condition variable
|
||||
pthread_condattr_t attrs;
|
||||
pthread_condattr_init(&attrs);
|
||||
pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
|
||||
pthread_cond_init(peerhash_cond, &attrs);
|
||||
pthread_condattr_destroy(&attrs);
|
||||
|
||||
// initialize peer hashtable
|
||||
peerhash = hash_create_size(2048, peer_hash_key, peer_hash_cmp, NULL);
|
||||
}
|
||||
|
||||
/* Cleanup handler / deinitializer. */
|
||||
static void bgp_keepalives_finish(void *arg)
|
||||
{
|
||||
bgp_keepalives_thread_run = false;
|
||||
|
||||
if (peerhash) {
|
||||
hash_clean(peerhash, pkat_del);
|
||||
hash_free(peerhash);
|
||||
@ -177,32 +154,50 @@ static void bgp_keepalives_finish(void *arg)
|
||||
XFREE(MTYPE_TMP, peerhash_cond);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Entry function for peer keepalive generation pthread.
|
||||
*
|
||||
* bgp_keepalives_init() must be called prior to this.
|
||||
*/
|
||||
void *bgp_keepalives_start(void *arg)
|
||||
{
|
||||
struct frr_pthread *fpt = arg;
|
||||
fpt->master->owner = pthread_self();
|
||||
|
||||
struct timeval currtime = {0, 0};
|
||||
struct timeval aftertime = {0, 0};
|
||||
struct timeval next_update = {0, 0};
|
||||
struct timespec next_update_ts = {0, 0};
|
||||
|
||||
peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t));
|
||||
peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t));
|
||||
|
||||
/* initialize mutex */
|
||||
pthread_mutex_init(peerhash_mtx, NULL);
|
||||
|
||||
/* use monotonic clock with condition variable */
|
||||
pthread_condattr_t attrs;
|
||||
pthread_condattr_init(&attrs);
|
||||
pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
|
||||
pthread_cond_init(peerhash_cond, &attrs);
|
||||
pthread_condattr_destroy(&attrs);
|
||||
|
||||
/* initialize peer hashtable */
|
||||
peerhash = hash_create_size(2048, peer_hash_key, peer_hash_cmp, NULL);
|
||||
pthread_mutex_lock(peerhash_mtx);
|
||||
|
||||
// register cleanup handler
|
||||
/* register cleanup handler */
|
||||
pthread_cleanup_push(&bgp_keepalives_finish, NULL);
|
||||
|
||||
bgp_keepalives_thread_run = true;
|
||||
/* notify anybody waiting on us that we are done starting up */
|
||||
frr_pthread_notify_running(fpt);
|
||||
|
||||
while (bgp_keepalives_thread_run) {
|
||||
while (atomic_load_explicit(&fpt->running, memory_order_relaxed)) {
|
||||
if (peerhash->count > 0)
|
||||
pthread_cond_timedwait(peerhash_cond, peerhash_mtx,
|
||||
&next_update_ts);
|
||||
else
|
||||
while (peerhash->count == 0
|
||||
&& bgp_keepalives_thread_run)
|
||||
&& atomic_load_explicit(&fpt->running,
|
||||
memory_order_relaxed))
|
||||
pthread_cond_wait(peerhash_cond, peerhash_mtx);
|
||||
|
||||
monotime(&currtime);
|
||||
@ -219,7 +214,7 @@ void *bgp_keepalives_start(void *arg)
|
||||
TIMEVAL_TO_TIMESPEC(&next_update, &next_update_ts);
|
||||
}
|
||||
|
||||
// clean up
|
||||
/* clean up */
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return NULL;
|
||||
@ -229,6 +224,12 @@ void *bgp_keepalives_start(void *arg)
|
||||
|
||||
void bgp_keepalives_on(struct peer *peer)
|
||||
{
|
||||
if (CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON))
|
||||
return;
|
||||
|
||||
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_KEEPALIVES);
|
||||
assert(fpt->running);
|
||||
|
||||
/* placeholder bucket data to use for fast key lookups */
|
||||
static struct pkat holder = {0};
|
||||
|
||||
@ -253,6 +254,12 @@ void bgp_keepalives_on(struct peer *peer)
|
||||
|
||||
void bgp_keepalives_off(struct peer *peer)
|
||||
{
|
||||
if (!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON))
|
||||
return;
|
||||
|
||||
struct frr_pthread *fpt = frr_pthread_get(PTHREAD_KEEPALIVES);
|
||||
assert(fpt->running);
|
||||
|
||||
/* placeholder bucket data to use for fast key lookups */
|
||||
static struct pkat holder = {0};
|
||||
|
||||
@ -283,10 +290,13 @@ void bgp_keepalives_wake()
|
||||
pthread_mutex_unlock(peerhash_mtx);
|
||||
}
|
||||
|
||||
int bgp_keepalives_stop(void **result, struct frr_pthread *fpt)
|
||||
int bgp_keepalives_stop(struct frr_pthread *fpt, void **result)
|
||||
{
|
||||
bgp_keepalives_thread_run = false;
|
||||
assert(fpt->running);
|
||||
|
||||
atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
|
||||
bgp_keepalives_wake();
|
||||
|
||||
pthread_join(fpt->thread, result);
|
||||
return 0;
|
||||
}
|
||||
|
@ -88,6 +88,6 @@ extern void bgp_keepalives_wake(void);
|
||||
/**
|
||||
* Stops the thread and blocks until it terminates.
|
||||
*/
|
||||
int bgp_keepalives_stop(void **result, struct frr_pthread *fpt);
|
||||
int bgp_keepalives_stop(struct frr_pthread *fpt, void **result);
|
||||
|
||||
#endif /* _FRR_BGP_KEEPALIVES_H */
|
||||
|
@ -232,7 +232,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
|
||||
static int bgp_vrf_new(struct vrf *vrf)
|
||||
{
|
||||
if (BGP_DEBUG(zebra, ZEBRA))
|
||||
zlog_debug("VRF Created: %s(%d)", vrf->name, vrf->vrf_id);
|
||||
zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -240,7 +240,7 @@ static int bgp_vrf_new(struct vrf *vrf)
|
||||
static int bgp_vrf_delete(struct vrf *vrf)
|
||||
{
|
||||
if (BGP_DEBUG(zebra, ZEBRA))
|
||||
zlog_debug("VRF Deletion: %s(%d)", vrf->name, vrf->vrf_id);
|
||||
zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -251,7 +251,7 @@ static int bgp_vrf_enable(struct vrf *vrf)
|
||||
vrf_id_t old_vrf_id;
|
||||
|
||||
if (BGP_DEBUG(zebra, ZEBRA))
|
||||
zlog_debug("VRF enable add %s id %d", vrf->name, vrf->vrf_id);
|
||||
zlog_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id);
|
||||
|
||||
bgp = bgp_lookup_by_name(vrf->name);
|
||||
if (bgp) {
|
||||
|
@ -336,7 +336,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
|
||||
bgp = bgp_lookup_by_vrf_id(vrf_id);
|
||||
if (!bgp) {
|
||||
zlog_err(
|
||||
"parse nexthop update: instance not found for vrf_id %d",
|
||||
"parse nexthop update: instance not found for vrf_id %u",
|
||||
vrf_id);
|
||||
return;
|
||||
}
|
||||
@ -389,7 +389,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
|
||||
char buf[PREFIX2STR_BUFFER];
|
||||
prefix2str(&p, buf, sizeof(buf));
|
||||
zlog_debug(
|
||||
"%d: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
|
||||
"%u: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
|
||||
vrf_id, buf, metric, bnc->metric, nexthop_num,
|
||||
bnc->nexthop_num, bnc->flags);
|
||||
}
|
||||
@ -572,12 +572,11 @@ static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p)
|
||||
*/
|
||||
static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
|
||||
{
|
||||
struct stream *s;
|
||||
struct prefix *p;
|
||||
bool exact_match = false;
|
||||
int ret;
|
||||
|
||||
/* Check socket. */
|
||||
if (!zclient || zclient->sock < 0)
|
||||
if (!zclient)
|
||||
return;
|
||||
|
||||
/* Don't try to register if Zebra doesn't know of this instance. */
|
||||
@ -585,32 +584,14 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
|
||||
return;
|
||||
|
||||
p = &(bnc->node->p);
|
||||
s = zclient->obuf;
|
||||
stream_reset(s);
|
||||
zclient_create_header(s, command, bnc->bgp->vrf_id);
|
||||
if ((command == ZEBRA_NEXTHOP_REGISTER ||
|
||||
command == ZEBRA_IMPORT_ROUTE_REGISTER) &&
|
||||
(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)
|
||||
|| CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)))
|
||||
stream_putc(s, 1);
|
||||
else
|
||||
stream_putc(s, 0);
|
||||
exact_match = true;
|
||||
|
||||
stream_putw(s, PREFIX_FAMILY(p));
|
||||
stream_putc(s, p->prefixlen);
|
||||
switch (PREFIX_FAMILY(p)) {
|
||||
case AF_INET:
|
||||
stream_put_in_addr(s, &p->u.prefix4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
stream_put(s, &(p->u.prefix6), 16);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
ret = zclient_send_message(zclient);
|
||||
ret = zclient_send_rnh(zclient, command, p,
|
||||
exact_match, bnc->bgp->vrf_id);
|
||||
/* TBD: handle the failure */
|
||||
if (ret < 0)
|
||||
zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
|
||||
|
@ -545,19 +545,26 @@ void bgp_open_send(struct peer *peer)
|
||||
bgp_writes_on(peer);
|
||||
}
|
||||
|
||||
/* This is only for sending NOTIFICATION message to neighbor. */
|
||||
/*
|
||||
* Writes NOTIFICATION message directly to a peer socket without waiting for
|
||||
* the I/O thread.
|
||||
*
|
||||
* There must be exactly one stream on the peer->obuf FIFO, and the data within
|
||||
* this stream must match the format of a BGP NOTIFICATION message.
|
||||
* Transmission is best-effort.
|
||||
*
|
||||
* @requires peer->io_mtx
|
||||
* @param peer
|
||||
* @return 0
|
||||
*/
|
||||
static int bgp_write_notify(struct peer *peer)
|
||||
{
|
||||
int ret, val;
|
||||
u_char type;
|
||||
struct stream *s;
|
||||
|
||||
pthread_mutex_lock(&peer->io_mtx);
|
||||
{
|
||||
/* There should be at least one packet. */
|
||||
s = stream_fifo_pop(peer->obuf);
|
||||
}
|
||||
pthread_mutex_unlock(&peer->io_mtx);
|
||||
/* There should be at least one packet. */
|
||||
s = stream_fifo_pop(peer->obuf);
|
||||
|
||||
if (!s)
|
||||
return 0;
|
||||
@ -622,6 +629,14 @@ static int bgp_write_notify(struct peer *peer)
|
||||
* This function attempts to write the packet from the thread it is called
|
||||
* from, to ensure the packet gets out ASAP.
|
||||
*
|
||||
* This function may be called from multiple threads. Since the function
|
||||
* modifies I/O buffer(s) in the peer, these are locked for the duration of the
|
||||
* call to prevent tampering from other threads.
|
||||
*
|
||||
* Delivery of the NOTIFICATION is attempted once and is best-effort. After
|
||||
* return, the peer structure *must* be reset; no assumptions about session
|
||||
* state are valid.
|
||||
*
|
||||
* @param peer
|
||||
* @param code BGP error code
|
||||
* @param sub_code BGP error subcode
|
||||
@ -634,6 +649,10 @@ void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code,
|
||||
struct stream *s;
|
||||
int length;
|
||||
|
||||
/* Lock I/O mutex to prevent other threads from pushing packets */
|
||||
pthread_mutex_lock(&peer->io_mtx);
|
||||
/* ============================================== */
|
||||
|
||||
/* Allocate new stream. */
|
||||
s = stream_new(BGP_MAX_PACKET_SIZE);
|
||||
|
||||
@ -651,20 +670,8 @@ void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code,
|
||||
/* Set BGP packet length. */
|
||||
length = bgp_packet_set_size(s);
|
||||
|
||||
/*
|
||||
* Turn off keepalive generation for peer. This is necessary because
|
||||
* otherwise between the time we wipe the output buffer and the time we
|
||||
* push the NOTIFY onto it, the KA generation thread could have pushed
|
||||
* a KEEPALIVE in the middle.
|
||||
*/
|
||||
bgp_keepalives_off(peer);
|
||||
|
||||
/* wipe output buffer */
|
||||
pthread_mutex_lock(&peer->io_mtx);
|
||||
{
|
||||
stream_fifo_clean(peer->obuf);
|
||||
}
|
||||
pthread_mutex_unlock(&peer->io_mtx);
|
||||
stream_fifo_clean(peer->obuf);
|
||||
|
||||
/*
|
||||
* If possible, store last packet for debugging purposes. This check is
|
||||
@ -728,9 +735,12 @@ void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code,
|
||||
peer->last_reset = PEER_DOWN_NOTIFY_SEND;
|
||||
|
||||
/* Add packet to peer's output queue */
|
||||
bgp_packet_add(peer, s);
|
||||
stream_fifo_push(peer->obuf, s);
|
||||
|
||||
bgp_write_notify(peer);
|
||||
|
||||
/* ============================================== */
|
||||
pthread_mutex_unlock(&peer->io_mtx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2719,7 +2719,9 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
|
||||
/* AS path local-as loop check. */
|
||||
if (peer->change_local_as) {
|
||||
if (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
|
||||
if (peer->allowas_in[afi][safi])
|
||||
aspath_loop_count = peer->allowas_in[afi][safi];
|
||||
else if (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
|
||||
aspath_loop_count = 1;
|
||||
|
||||
if (aspath_loop_check(attr->aspath, peer->change_local_as)
|
||||
@ -7857,7 +7859,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
|
||||
vty_out(vty,
|
||||
"{\n \"vrfId\": %d,\n \"vrfName\": \"%s\",\n \"tableVersion\": %" PRId64
|
||||
",\n \"routerId\": \"%s\",\n \"routes\": { ",
|
||||
bgp->vrf_id == VRF_UNKNOWN ? -1 : bgp->vrf_id,
|
||||
bgp->vrf_id == VRF_UNKNOWN ? -1 : (int)bgp->vrf_id,
|
||||
bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT ? "Default"
|
||||
: bgp->name,
|
||||
table->version, inet_ntoa(bgp->router_id));
|
||||
@ -8125,6 +8127,9 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
|
||||
struct bgp_node *rn, *next;
|
||||
unsigned long output_cum = 0;
|
||||
unsigned long total_cum = 0;
|
||||
bool show_msg;
|
||||
|
||||
show_msg = (!use_json && type == bgp_show_type_normal);
|
||||
|
||||
for (rn = bgp_table_top(table); rn; rn = next) {
|
||||
next = bgp_route_next(rn);
|
||||
@ -8140,8 +8145,19 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
|
||||
output_arg, use_json,
|
||||
rd, next == NULL,
|
||||
&output_cum, &total_cum);
|
||||
if (next == NULL)
|
||||
show_msg = false;
|
||||
}
|
||||
}
|
||||
if (show_msg) {
|
||||
if (output_cum == 0)
|
||||
vty_out(vty, "No BGP prefixes displayed, %ld exist\n",
|
||||
total_cum);
|
||||
else
|
||||
vty_out(vty,
|
||||
"\nDisplayed %ld routes and %ld total paths\n",
|
||||
output_cum, total_cum);
|
||||
}
|
||||
if (use_json)
|
||||
vty_out(vty, " } }");
|
||||
return CMD_SUCCESS;
|
||||
@ -10902,7 +10918,7 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
|
||||
&bgp_static->gatewayIp.u.prefix, buf2,
|
||||
sizeof(buf2));
|
||||
vty_out(vty,
|
||||
" network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s\n",
|
||||
" network %s rd %s ethtag %u label %u esi %s gwip %s routermac %s\n",
|
||||
buf, rdbuf, p->u.prefix_evpn.eth_tag,
|
||||
decode_label(&bgp_static->label), esi, buf2,
|
||||
macrouter);
|
||||
|
@ -2692,6 +2692,19 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
|
||||
return bgp_vty_return(vty, ret);
|
||||
}
|
||||
|
||||
DEFUN (bgp_default_shutdown,
|
||||
bgp_default_shutdown_cmd,
|
||||
"[no] bgp default shutdown",
|
||||
NO_STR
|
||||
BGP_STR
|
||||
"Configure BGP defaults\n"
|
||||
"Do not automatically activate peers upon configuration\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||
bgp->autoshutdown = !strmatch(argv[0]->text, "no");
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (neighbor_remote_as,
|
||||
neighbor_remote_as_cmd,
|
||||
"neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <(1-4294967295)|internal|external>",
|
||||
@ -3238,7 +3251,6 @@ DEFUN (no_neighbor_password,
|
||||
return bgp_vty_return(vty, ret);
|
||||
}
|
||||
|
||||
|
||||
DEFUN (neighbor_activate,
|
||||
neighbor_activate_cmd,
|
||||
"neighbor <A.B.C.D|X:X::X:X|WORD> activate",
|
||||
@ -6490,7 +6502,6 @@ DEFUN (show_bgp_vrfs,
|
||||
struct listnode *node, *nnode;
|
||||
int peers_cfg, peers_estb;
|
||||
json_object *json_vrf = NULL;
|
||||
int vrf_id_ui;
|
||||
|
||||
/* Skip Views. */
|
||||
if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
|
||||
@ -6524,8 +6535,10 @@ DEFUN (show_bgp_vrfs,
|
||||
type = "VRF";
|
||||
}
|
||||
|
||||
vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN) ? -1 : bgp->vrf_id;
|
||||
|
||||
if (uj) {
|
||||
int64_t vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN) ? -1 :
|
||||
(int64_t)bgp->vrf_id;
|
||||
json_object_string_add(json_vrf, "type", type);
|
||||
json_object_int_add(json_vrf, "vrfId", vrf_id_ui);
|
||||
json_object_string_add(json_vrf, "routerId",
|
||||
@ -6543,7 +6556,9 @@ DEFUN (show_bgp_vrfs,
|
||||
} else
|
||||
vty_out(vty,
|
||||
"%4s %-5d %-16s %9u %10u %-37s %-10u %-15s\n",
|
||||
type, vrf_id_ui, inet_ntoa(bgp->router_id),
|
||||
type, bgp->vrf_id == VRF_UNKNOWN ?
|
||||
-1 : (int)bgp->vrf_id,
|
||||
inet_ntoa(bgp->router_id),
|
||||
peers_cfg, peers_estb, name, bgp->l3vni,
|
||||
prefix_mac2str(&bgp->rmac, buf, sizeof(buf)));
|
||||
}
|
||||
@ -6863,10 +6878,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
|
||||
if (!count) {
|
||||
unsigned long ents;
|
||||
char memstrbuf[MTYPE_MEMSTR_LEN];
|
||||
int vrf_id_ui;
|
||||
int64_t vrf_id_ui;
|
||||
|
||||
vrf_id_ui =
|
||||
(bgp->vrf_id == VRF_UNKNOWN) ? -1 : bgp->vrf_id;
|
||||
(bgp->vrf_id == VRF_UNKNOWN) ? -1 :
|
||||
(int64_t)bgp->vrf_id;
|
||||
|
||||
/* Usage summary and header */
|
||||
if (use_json) {
|
||||
@ -6885,7 +6901,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
|
||||
vty_out(vty,
|
||||
"BGP router identifier %s, local AS number %u vrf-id %d",
|
||||
inet_ntoa(bgp->router_id), bgp->as,
|
||||
vrf_id_ui);
|
||||
bgp->vrf_id == VRF_UNKNOWN ? -1 :
|
||||
(int)bgp->vrf_id);
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
@ -9853,7 +9870,6 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
|
||||
}
|
||||
|
||||
if (use_json) {
|
||||
bgp_show_bestpath_json(bgp, json);
|
||||
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
@ -9887,8 +9903,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
|
||||
|
||||
json_object_int_add(json, "vrfId",
|
||||
(bgp->vrf_id == VRF_UNKNOWN)
|
||||
? -1
|
||||
: bgp->vrf_id);
|
||||
? -1 : (int64_t) bgp->vrf_id);
|
||||
json_object_string_add(
|
||||
json, "vrfName",
|
||||
(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
|
||||
@ -11578,6 +11593,9 @@ void bgp_vty_init(void)
|
||||
install_element(BGP_NODE, &bgp_listen_range_cmd);
|
||||
install_element(BGP_NODE, &no_bgp_listen_range_cmd);
|
||||
|
||||
/* "neighbors auto-shutdown" command */
|
||||
install_element(BGP_NODE, &bgp_default_shutdown_cmd);
|
||||
|
||||
/* "neighbor remote-as" commands. */
|
||||
install_element(BGP_NODE, &neighbor_remote_as_cmd);
|
||||
install_element(BGP_NODE, &neighbor_interface_config_cmd);
|
||||
|
@ -1001,6 +1001,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
|
||||
memset(&api, 0, sizeof(api));
|
||||
memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr));
|
||||
api.vrf_id = bgp->vrf_id;
|
||||
api.nh_vrf_id = bgp->vrf_id;
|
||||
api.type = ZEBRA_ROUTE_BGP;
|
||||
api.safi = safi;
|
||||
api.prefix = *p;
|
||||
@ -1253,6 +1254,7 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
|
||||
memset(&api, 0, sizeof(api));
|
||||
memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr));
|
||||
api.vrf_id = peer->bgp->vrf_id;
|
||||
api.nh_vrf_id = peer->bgp->vrf_id;
|
||||
api.type = ZEBRA_ROUTE_BGP;
|
||||
api.safi = safi;
|
||||
api.prefix = *p;
|
||||
|
76
bgpd/bgpd.c
76
bgpd/bgpd.c
@ -866,8 +866,7 @@ static void peer_af_flag_reset(struct peer *peer, afi_t afi, safi_t safi)
|
||||
/* peer global config reset */
|
||||
static void peer_global_config_reset(struct peer *peer)
|
||||
{
|
||||
|
||||
int v6only;
|
||||
int saved_flags = 0;
|
||||
|
||||
peer->change_local_as = 0;
|
||||
peer->ttl = (peer_sort(peer) == BGP_PEER_IBGP ? MAXTTL : 1);
|
||||
@ -885,13 +884,11 @@ static void peer_global_config_reset(struct peer *peer)
|
||||
else
|
||||
peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
|
||||
|
||||
/* This is a per-peer specific flag and so we must preserve it */
|
||||
v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
|
||||
|
||||
/* These are per-peer specific flags and so we must preserve them */
|
||||
saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
|
||||
saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN);
|
||||
peer->flags = 0;
|
||||
|
||||
if (v6only)
|
||||
SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
|
||||
SET_FLAG(peer->flags, saved_flags);
|
||||
|
||||
peer->config = 0;
|
||||
peer->holdtime = 0;
|
||||
@ -1498,8 +1495,11 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
|
||||
peer_af_create(peer, afi, safi);
|
||||
}
|
||||
|
||||
/* auto shutdown if configured */
|
||||
if (bgp->autoshutdown)
|
||||
peer_flag_set(peer, PEER_FLAG_SHUTDOWN);
|
||||
/* Set up peer's events and timers. */
|
||||
if (!active && peer_active(peer))
|
||||
else if (!active && peer_active(peer))
|
||||
bgp_timer_set(peer);
|
||||
|
||||
return peer;
|
||||
@ -2340,7 +2340,7 @@ static void peer_group2peer_config_copy(struct peer_group *group,
|
||||
struct peer *peer)
|
||||
{
|
||||
struct peer *conf;
|
||||
int v6only;
|
||||
int saved_flags = 0;
|
||||
|
||||
conf = group->conf;
|
||||
|
||||
@ -2358,14 +2358,11 @@ static void peer_group2peer_config_copy(struct peer_group *group,
|
||||
/* GTSM hops */
|
||||
peer->gtsm_hops = conf->gtsm_hops;
|
||||
|
||||
/* this flag is per-neighbor and so has to be preserved */
|
||||
v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
|
||||
|
||||
/* peer flags apply */
|
||||
/* These are per-peer specific flags and so we must preserve them */
|
||||
saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
|
||||
saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN);
|
||||
peer->flags = conf->flags;
|
||||
|
||||
if (v6only)
|
||||
SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
|
||||
SET_FLAG(peer->flags, saved_flags);
|
||||
|
||||
/* peer config apply */
|
||||
peer->config = conf->config;
|
||||
@ -7152,6 +7149,10 @@ int bgp_config_write(struct vty *vty)
|
||||
vty_out(vty, " bgp default subgroup-pkt-queue-max %u\n",
|
||||
bgp->default_subgroup_pkt_queue_max);
|
||||
|
||||
/* BGP default autoshutdown neighbors */
|
||||
if (bgp->autoshutdown)
|
||||
vty_out(vty, " bgp default auto-shutdown\n");
|
||||
|
||||
/* BGP client-to-client reflection. */
|
||||
if (bgp_flag_check(bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT))
|
||||
vty_out(vty, " no bgp client-to-client reflection\n");
|
||||
@ -7469,32 +7470,33 @@ static void bgp_pthreads_init()
|
||||
{
|
||||
frr_pthread_init();
|
||||
|
||||
frr_pthread_new("BGP i/o thread", PTHREAD_IO, bgp_io_start,
|
||||
bgp_io_stop);
|
||||
frr_pthread_new("BGP keepalives thread", PTHREAD_KEEPALIVES,
|
||||
bgp_keepalives_start, bgp_keepalives_stop);
|
||||
|
||||
/* pre-run initialization */
|
||||
bgp_keepalives_init();
|
||||
bgp_io_init();
|
||||
struct frr_pthread_attr io = {
|
||||
.id = PTHREAD_IO,
|
||||
.start = frr_pthread_attr_default.start,
|
||||
.stop = frr_pthread_attr_default.stop,
|
||||
.name = "BGP I/O thread",
|
||||
};
|
||||
struct frr_pthread_attr ka = {
|
||||
.id = PTHREAD_KEEPALIVES,
|
||||
.start = bgp_keepalives_start,
|
||||
.stop = bgp_keepalives_stop,
|
||||
.name = "BGP Keepalives thread",
|
||||
};
|
||||
frr_pthread_new(&io);
|
||||
frr_pthread_new(&ka);
|
||||
}
|
||||
|
||||
void bgp_pthreads_run()
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
|
||||
struct frr_pthread *io = frr_pthread_get(PTHREAD_IO);
|
||||
struct frr_pthread *ka = frr_pthread_get(PTHREAD_KEEPALIVES);
|
||||
|
||||
/*
|
||||
* Please ensure that the io thread is running
|
||||
* by calling bgp_io_running. The BGP threads
|
||||
* depend on it being running when we start
|
||||
* looking for it.
|
||||
*/
|
||||
frr_pthread_run(PTHREAD_IO, &attr, NULL);
|
||||
bgp_io_running();
|
||||
frr_pthread_run(io, NULL);
|
||||
frr_pthread_run(ka, NULL);
|
||||
|
||||
frr_pthread_run(PTHREAD_KEEPALIVES, &attr, NULL);
|
||||
/* Wait until threads are ready. */
|
||||
frr_pthread_wait_running(io);
|
||||
frr_pthread_wait_running(ka);
|
||||
}
|
||||
|
||||
void bgp_pthreads_finish()
|
||||
|
@ -390,6 +390,9 @@ struct bgp {
|
||||
/* Actual coalesce time */
|
||||
uint32_t coalesce_time;
|
||||
|
||||
/* Auto-shutdown new peers */
|
||||
bool autoshutdown;
|
||||
|
||||
u_int32_t addpath_tx_id;
|
||||
int addpath_tx_used[AFI_MAX][SAFI_MAX];
|
||||
|
||||
@ -916,9 +919,6 @@ struct peer {
|
||||
/* Send prefix count. */
|
||||
unsigned long scount[AFI_MAX][SAFI_MAX];
|
||||
|
||||
/* Announcement attribute hash. */
|
||||
struct hash *hash[AFI_MAX][SAFI_MAX];
|
||||
|
||||
/* Notify data. */
|
||||
struct bgp_notify notify;
|
||||
|
||||
|
@ -913,7 +913,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
|
||||
* aspath: points to interned hash from aspath hash table
|
||||
*/
|
||||
|
||||
red = bgp_redist_lookup(bgp, afi, type, VRF_DEFAULT);
|
||||
red = bgp_redist_lookup(bgp, afi, type, 0);
|
||||
|
||||
if (red && red->redist_metric_flag) {
|
||||
attr.med = red->redist_metric;
|
||||
|
@ -385,6 +385,8 @@ static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count,
|
||||
struct zapi_route api;
|
||||
struct zapi_nexthop *api_nh;
|
||||
int i;
|
||||
struct in_addr **nhp_ary4 = nhp_ary;
|
||||
struct in6_addr **nhp_ary6 = nhp_ary;
|
||||
|
||||
if (!nhp_count) {
|
||||
vnc_zlog_debug_verbose("%s: empty nexthop list, skipping",
|
||||
@ -394,6 +396,7 @@ static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count,
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_VNC;
|
||||
api.safi = SAFI_UNICAST;
|
||||
api.prefix = *p;
|
||||
@ -402,20 +405,16 @@ static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count,
|
||||
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
|
||||
api.nexthop_num = MIN(nhp_count, multipath_num);
|
||||
for (i = 0; i < api.nexthop_num; i++) {
|
||||
struct in_addr *nhp_ary4;
|
||||
struct in6_addr *nhp_ary6;
|
||||
|
||||
api_nh = &api.nexthops[i];
|
||||
switch (p->family) {
|
||||
case AF_INET:
|
||||
nhp_ary4 = nhp_ary;
|
||||
memcpy(&api_nh->gate.ipv4, &nhp_ary4[i],
|
||||
memcpy(&api_nh->gate.ipv4, nhp_ary4[i],
|
||||
sizeof(api_nh->gate.ipv4));
|
||||
api_nh->type = NEXTHOP_TYPE_IPV4;
|
||||
break;
|
||||
case AF_INET6:
|
||||
nhp_ary6 = nhp_ary;
|
||||
memcpy(&api_nh->gate.ipv6, &nhp_ary6[i],
|
||||
memcpy(&api_nh->gate.ipv6, nhp_ary6[i],
|
||||
sizeof(api_nh->gate.ipv6));
|
||||
api_nh->type = NEXTHOP_TYPE_IPV6;
|
||||
break;
|
||||
|
@ -823,22 +823,15 @@ Network Layer protocols. BGP supports multiple Address Family
|
||||
Identifier (AFI), namely IPv4 and IPv6. Support is also provided for
|
||||
multiple sets of per-AFI information via Subsequent Address Family
|
||||
Identifiers (SAFI). In addition to unicast information, VPN information
|
||||
@cite{RFC4364} and @cite{RFC4659}, and Encapsulation information
|
||||
@cite{RFC4364} and @cite{RFC4659}, and Encapsulation attribute
|
||||
@cite{RFC5512} is supported.
|
||||
|
||||
@deffn {Command} {show ip bgp vpnv4 all} {}
|
||||
@deffnx {Command} {show ipv6 bgp vpn all} {}
|
||||
@deffn {Command} {show ip bgp ipv4 vpn} {}
|
||||
@deffnx {Command} {show ipv6 bgp ipv6 vpn} {}
|
||||
Print active IPV4 or IPV6 routes advertised via the VPN SAFI.
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {show ip bgp encap all} {}
|
||||
@deffnx {Command} {show ipv6 bgp encap all} {}
|
||||
Print active IPV4 or IPV6 routes advertised via the Encapsulation SAFI.
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {show bgp ipv4 encap summary} {}
|
||||
@deffnx {Command} {show bgp ipv4 vpn summary} {}
|
||||
@deffnx {Command} {show bgp ipv6 encap summary} {}
|
||||
@deffn {Command} {show bgp ipv4 vpn summary} {}
|
||||
@deffnx {Command} {show bgp ipv6 vpn summary} {}
|
||||
Print a summary of neighbor connections for the specified AFI/SAFI combination.
|
||||
@end deffn
|
||||
|
@ -373,36 +373,37 @@ log file /var/log/zebra.log
|
||||
!
|
||||
interface eth0
|
||||
ip address 10.2.2.2/24
|
||||
mpls-te on
|
||||
mpls-te link metric 10
|
||||
mpls-te link max-bw 1.25e+06
|
||||
mpls-te link max-rsv-bw 1.25e+06
|
||||
mpls-te link unrsv-bw 0 1.25e+06
|
||||
mpls-te link unrsv-bw 1 1.25e+06
|
||||
mpls-te link unrsv-bw 2 1.25e+06
|
||||
mpls-te link unrsv-bw 3 1.25e+06
|
||||
mpls-te link unrsv-bw 4 1.25e+06
|
||||
mpls-te link unrsv-bw 5 1.25e+06
|
||||
mpls-te link unrsv-bw 6 1.25e+06
|
||||
mpls-te link unrsv-bw 7 1.25e+06
|
||||
mpls-te link rsc-clsclr 0xab
|
||||
link-params
|
||||
enable
|
||||
metric 100
|
||||
max-bw 1.25e+07
|
||||
max-rsv-bw 1.25e+06
|
||||
unrsv-bw 0 1.25e+06
|
||||
unrsv-bw 1 1.25e+06
|
||||
unrsv-bw 2 1.25e+06
|
||||
unrsv-bw 3 1.25e+06
|
||||
unrsv-bw 4 1.25e+06
|
||||
unrsv-bw 5 1.25e+06
|
||||
unrsv-bw 6 1.25e+06
|
||||
unrsv-bw 7 1.25e+06
|
||||
admin-grp 0xab
|
||||
!
|
||||
interface eth1
|
||||
ip address 10.1.1.1/24
|
||||
mpls-te on
|
||||
mpls-te link metric 10
|
||||
mpls-te link max-bw 1.25e+06
|
||||
mpls-te link max-rsv-bw 1.25e+06
|
||||
mpls-te link unrsv-bw 0 1.25e+06
|
||||
mpls-te link unrsv-bw 1 1.25e+06
|
||||
mpls-te link unrsv-bw 2 1.25e+06
|
||||
mpls-te link unrsv-bw 3 1.25e+06
|
||||
mpls-te link unrsv-bw 4 1.25e+06
|
||||
mpls-te link unrsv-bw 5 1.25e+06
|
||||
mpls-te link unrsv-bw 6 1.25e+06
|
||||
mpls-te link unrsv-bw 7 1.25e+06
|
||||
mpls-te link rsc-clsclr 0xab
|
||||
mpls-te neighbor 10.1.1.2 as 65000
|
||||
link-params
|
||||
enable
|
||||
metric 100
|
||||
max-bw 1.25e+07
|
||||
max-rsv-bw 1.25e+06
|
||||
unrsv-bw 0 1.25e+06
|
||||
unrsv-bw 1 1.25e+06
|
||||
unrsv-bw 2 1.25e+06
|
||||
unrsv-bw 3 1.25e+06
|
||||
unrsv-bw 4 1.25e+06
|
||||
unrsv-bw 5 1.25e+06
|
||||
unrsv-bw 6 1.25e+06
|
||||
unrsv-bw 7 1.25e+06
|
||||
neighbor 10.1.1.2 as 65000
|
||||
@end group
|
||||
@end example
|
||||
|
||||
|
@ -884,36 +884,37 @@ log file /var/log/zebra.log
|
||||
!
|
||||
interface eth0
|
||||
ip address 198.168.1.1/24
|
||||
mpls-te on
|
||||
mpls-te link metric 10
|
||||
mpls-te link max-bw 1.25e+06
|
||||
mpls-te link max-rsv-bw 1.25e+06
|
||||
mpls-te link unrsv-bw 0 1.25e+06
|
||||
mpls-te link unrsv-bw 1 1.25e+06
|
||||
mpls-te link unrsv-bw 2 1.25e+06
|
||||
mpls-te link unrsv-bw 3 1.25e+06
|
||||
mpls-te link unrsv-bw 4 1.25e+06
|
||||
mpls-te link unrsv-bw 5 1.25e+06
|
||||
mpls-te link unrsv-bw 6 1.25e+06
|
||||
mpls-te link unrsv-bw 7 1.25e+06
|
||||
mpls-te link rsc-clsclr 0xab
|
||||
link-params
|
||||
enable
|
||||
admin-grp 0xa1
|
||||
metric 100
|
||||
max-bw 1.25e+07
|
||||
max-rsv-bw 1.25e+06
|
||||
unrsv-bw 0 1.25e+06
|
||||
unrsv-bw 1 1.25e+06
|
||||
unrsv-bw 2 1.25e+06
|
||||
unrsv-bw 3 1.25e+06
|
||||
unrsv-bw 4 1.25e+06
|
||||
unrsv-bw 5 1.25e+06
|
||||
unrsv-bw 6 1.25e+06
|
||||
unrsv-bw 7 1.25e+06
|
||||
!
|
||||
interface eth1
|
||||
ip address 192.168.2.1/24
|
||||
mpls-te on
|
||||
mpls-te link metric 10
|
||||
mpls-te link max-bw 1.25e+06
|
||||
mpls-te link max-rsv-bw 1.25e+06
|
||||
mpls-te link unrsv-bw 0 1.25e+06
|
||||
mpls-te link unrsv-bw 1 1.25e+06
|
||||
mpls-te link unrsv-bw 2 1.25e+06
|
||||
mpls-te link unrsv-bw 3 1.25e+06
|
||||
mpls-te link unrsv-bw 4 1.25e+06
|
||||
mpls-te link unrsv-bw 5 1.25e+06
|
||||
mpls-te link unrsv-bw 6 1.25e+06
|
||||
mpls-te link unrsv-bw 7 1.25e+06
|
||||
mpls-te link rsc-clsclr 0xab
|
||||
mpls-te neighbor 192.168.2.2 as 65000
|
||||
link-params
|
||||
enable
|
||||
metric 10
|
||||
max-bw 1.25e+07
|
||||
max-rsv-bw 1.25e+06
|
||||
unrsv-bw 0 1.25e+06
|
||||
unrsv-bw 1 1.25e+06
|
||||
unrsv-bw 2 1.25e+06
|
||||
unrsv-bw 3 1.25e+06
|
||||
unrsv-bw 4 1.25e+06
|
||||
unrsv-bw 5 1.25e+06
|
||||
unrsv-bw 6 1.25e+06
|
||||
unrsv-bw 7 1.25e+06
|
||||
neighbor 192.168.2.2 as 65000
|
||||
@end group
|
||||
@end example
|
||||
|
||||
|
43
doc/vnc.texi
43
doc/vnc.texi
@ -22,8 +22,8 @@ BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VN
|
||||
information between NVAs. BGP based IP VPN support is defined in
|
||||
@cite{RFC4364, BGP/MPLS IP Virtual Private Networks (VPNs)}, and
|
||||
@cite{RFC4659, BGP-MPLS IP Virtual Private Network (VPN) Extension for
|
||||
IPv6 VPN }. Both the Encapsulation Subsequent Address Family Identifier
|
||||
(SAFI) and the Tunnel Encapsulation Attribute, @cite{RFC5512, The BGP
|
||||
IPv6 VPN }. Encapsulation information is provided via
|
||||
the Tunnel Encapsulation Attribute, @cite{RFC5512, The BGP
|
||||
Encapsulation Subsequent Address Family Identifier (SAFI) and the BGP
|
||||
Tunnel Encapsulation Attribute}, are supported.
|
||||
|
||||
@ -83,12 +83,10 @@ operating within a VN.
|
||||
@node General VNC Configuration
|
||||
@subsection General VNC Configuration
|
||||
|
||||
@deffn {VNC} {vnc advertise-un-method encap-safi|encap-attr} {}
|
||||
Advertise NVE underlay-network IP addresses using the encapsulation SAFI
|
||||
(@code{encap-safi}) or the UN address sub-TLV of the Tunnel Encapsulation attribute
|
||||
(@code{encap-attr}). When @code{encap-safi} is used, neighbors under
|
||||
@code{address-family encap} and/or @code{address-family encapv6} must be
|
||||
configured. The default is @code{encap-attr}.
|
||||
@deffn {VNC} {vnc advertise-un-method encap-attr} {}
|
||||
Advertise NVE underlay-network IP addresses using
|
||||
the UN address sub-TLV of the Tunnel Encapsulation attribute
|
||||
(@code{encap-attr}). The default is @code{encap-attr}.
|
||||
@end deffn
|
||||
|
||||
@node RFP Related Configuration
|
||||
@ -356,8 +354,7 @@ by receiving NVAs.
|
||||
The second form, @code{rt import} specifies an @var{import rt-list},
|
||||
which is a filter for incoming routes.
|
||||
In order to be made available to NVEs in the group,
|
||||
incoming BGP VPN and @w{ENCAP} @w{SAFI} (when @code{vnc
|
||||
advertise-un-method encap-safi} is set) routes must have
|
||||
incoming BGP VPN @w{SAFI} routes must have
|
||||
RT lists that have at least one route target in common with the
|
||||
group's @var{import rt-list}.
|
||||
|
||||
@ -1010,7 +1007,7 @@ router bgp 64512
|
||||
neighbor 192.168.1.101 remote-as 64512
|
||||
neighbor 192.168.1.102 remote-as 64512
|
||||
|
||||
address-family vpnv4
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.101 activate
|
||||
neighbor 192.168.1.102 activate
|
||||
exit-address-family
|
||||
@ -1043,7 +1040,7 @@ router bgp 64512
|
||||
neighbor 192.168.1.100 remote-as 64512
|
||||
neighbor 192.168.1.102 remote-as 64512
|
||||
|
||||
address-family vpnv4
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.100 activate
|
||||
neighbor 192.168.1.102 activate
|
||||
exit-address-family
|
||||
@ -1066,7 +1063,7 @@ router bgp 64512
|
||||
neighbor 192.168.1.101 remote-as 64512
|
||||
neighbor 192.168.1.102 remote-as 64512
|
||||
|
||||
address-family vpnv4
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.100 activate
|
||||
neighbor 192.168.1.101 activate
|
||||
exit-address-family
|
||||
@ -1131,7 +1128,7 @@ router bgp 64512
|
||||
neighbor 172.16.2.2 route-reflector-client
|
||||
exit-address-family
|
||||
!
|
||||
address-family vpnv4 unicast
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.102 activate
|
||||
neighbor 192.168.1.103 activate
|
||||
neighbor 192.168.1.104 activate
|
||||
@ -1161,7 +1158,7 @@ router bgp 64512
|
||||
no neighbor 192.168.1.103 activate
|
||||
exit-address-family
|
||||
!
|
||||
address-family vpnv4 unicast
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.101 activate
|
||||
neighbor 192.168.1.102 activate
|
||||
neighbor 192.168.1.103 activate
|
||||
@ -1250,7 +1247,7 @@ router bgp 64512
|
||||
neighbor 192.168.1.102 route-reflector-client
|
||||
exit-address-family
|
||||
|
||||
address-family vpnv4
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.101 activate
|
||||
neighbor 192.168.1.102 activate
|
||||
|
||||
@ -1269,7 +1266,7 @@ router bgp 64512
|
||||
|
||||
neighbor 192.168.1.100 remote-as 64512
|
||||
|
||||
address-family vpnv4
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.100 activate
|
||||
exit-address-family
|
||||
|
||||
@ -1290,7 +1287,7 @@ router bgp 64512
|
||||
|
||||
neighbor 192.168.1.100 remote-as 64512
|
||||
|
||||
address-family vpnv4
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.100 activate
|
||||
exit-address-family
|
||||
|
||||
@ -1381,7 +1378,7 @@ router bgp 64512
|
||||
|
||||
neighbor 192.168.1.100 remote-as 64512
|
||||
|
||||
address-family vpnv4
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.100 activate
|
||||
exit-address-family
|
||||
|
||||
@ -1402,7 +1399,7 @@ router bgp 64512
|
||||
|
||||
neighbor 192.168.1.100 remote-as 64512
|
||||
|
||||
address-family vpnv4
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.100 activate
|
||||
exit-address-family
|
||||
|
||||
@ -1450,7 +1447,7 @@ router bgp 64512
|
||||
neighbor 192.168.1.102 description iBGP-client-192-168-1-102
|
||||
neighbor 192.168.1.102 route-reflector-client
|
||||
|
||||
address-family vpnv4
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.101 activate
|
||||
neighbor 192.168.1.102 activate
|
||||
neighbor 192.168.1.104 activate
|
||||
@ -1470,7 +1467,7 @@ router bgp 64512
|
||||
neighbor 192.168.1.100 remote-as 64512
|
||||
neighbor 192.168.1.104 remote-as 64512
|
||||
|
||||
address-family vpnv4
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.100 activate
|
||||
neighbor 192.168.1.104 activate
|
||||
exit-address-family
|
||||
@ -1493,7 +1490,7 @@ router bgp 64512
|
||||
neighbor 192.168.1.100 remote-as 64512
|
||||
neighbor 192.168.1.104 remote-as 64512
|
||||
|
||||
address-family vpnv4
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.1.100 activate
|
||||
neighbor 192.168.1.104 activate
|
||||
exit-address-family
|
||||
|
@ -366,6 +366,7 @@ void eigrp_zebra_route_add(struct prefix *p, struct list *successors)
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_EIGRP;
|
||||
api.safi = SAFI_UNICAST;
|
||||
memcpy(&api.prefix, p, sizeof(*p));
|
||||
@ -407,6 +408,7 @@ void eigrp_zebra_route_delete(struct prefix *p)
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_EIGRP;
|
||||
api.safi = SAFI_UNICAST;
|
||||
memcpy(&api.prefix, p, sizeof(*p));
|
||||
|
@ -261,6 +261,7 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_ISIS;
|
||||
api.safi = SAFI_UNICAST;
|
||||
api.prefix = *prefix;
|
||||
@ -329,6 +330,7 @@ static void isis_zebra_route_del_route(struct prefix *prefix,
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_ISIS;
|
||||
api.safi = SAFI_UNICAST;
|
||||
api.prefix = *prefix;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Utilities and interfaces for managing POSIX threads
|
||||
* Utilities and interfaces for managing POSIX threads within FRR.
|
||||
* Copyright (C) 2017 Cumulus Networks
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -25,78 +25,99 @@
|
||||
#include "memory.h"
|
||||
#include "hash.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
|
||||
DEFINE_MTYPE(LIB, FRR_PTHREAD, "FRR POSIX Thread");
|
||||
DEFINE_MTYPE(LIB, PTHREAD_PRIM, "POSIX synchronization primitives");
|
||||
|
||||
/* id for next created pthread */
|
||||
static unsigned int next_id = 0;
|
||||
|
||||
/* Hash table of all frr_pthreads along with synchronization primitive(s) and
|
||||
* hash table callbacks.
|
||||
* ------------------------------------------------------------------------ */
|
||||
static struct hash *pthread_table;
|
||||
static pthread_mutex_t pthread_table_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
/* default frr_pthread start/stop routine prototypes */
|
||||
static void *fpt_run(void *arg);
|
||||
static int fpt_halt(struct frr_pthread *fpt, void **res);
|
||||
|
||||
/* pthread_table->hash_cmp */
|
||||
static int pthread_table_hash_cmp(const void *value1, const void *value2)
|
||||
/* default frr_pthread attributes */
|
||||
struct frr_pthread_attr frr_pthread_attr_default = {
|
||||
.id = 0,
|
||||
.start = fpt_run,
|
||||
.stop = fpt_halt,
|
||||
.name = "Anonymous",
|
||||
};
|
||||
|
||||
/* hash table to keep track of all frr_pthreads */
|
||||
static struct hash *frr_pthread_hash;
|
||||
static pthread_mutex_t frr_pthread_hash_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* frr_pthread_hash->hash_cmp */
|
||||
static int frr_pthread_hash_cmp(const void *value1, const void *value2)
|
||||
{
|
||||
const struct frr_pthread *tq1 = value1;
|
||||
const struct frr_pthread *tq2 = value2;
|
||||
|
||||
return (tq1->id == tq2->id);
|
||||
return (tq1->attr.id == tq2->attr.id);
|
||||
}
|
||||
|
||||
/* pthread_table->hash_key */
|
||||
static unsigned int pthread_table_hash_key(void *value)
|
||||
/* frr_pthread_hash->hash_key */
|
||||
static unsigned int frr_pthread_hash_key(void *value)
|
||||
{
|
||||
return ((struct frr_pthread *)value)->id;
|
||||
return ((struct frr_pthread *)value)->attr.id;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
void frr_pthread_init()
|
||||
{
|
||||
pthread_mutex_lock(&pthread_table_mtx);
|
||||
pthread_mutex_lock(&frr_pthread_hash_mtx);
|
||||
{
|
||||
pthread_table = hash_create(pthread_table_hash_key,
|
||||
pthread_table_hash_cmp, NULL);
|
||||
frr_pthread_hash = hash_create(frr_pthread_hash_key,
|
||||
frr_pthread_hash_cmp, NULL);
|
||||
}
|
||||
pthread_mutex_unlock(&pthread_table_mtx);
|
||||
pthread_mutex_unlock(&frr_pthread_hash_mtx);
|
||||
}
|
||||
|
||||
void frr_pthread_finish()
|
||||
{
|
||||
pthread_mutex_lock(&pthread_table_mtx);
|
||||
pthread_mutex_lock(&frr_pthread_hash_mtx);
|
||||
{
|
||||
hash_clean(pthread_table,
|
||||
hash_clean(frr_pthread_hash,
|
||||
(void (*)(void *))frr_pthread_destroy);
|
||||
hash_free(pthread_table);
|
||||
hash_free(frr_pthread_hash);
|
||||
}
|
||||
pthread_mutex_unlock(&pthread_table_mtx);
|
||||
pthread_mutex_unlock(&frr_pthread_hash_mtx);
|
||||
}
|
||||
|
||||
struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
|
||||
void *(*start_routine)(void *),
|
||||
int (*stop_routine)(void **,
|
||||
struct frr_pthread *))
|
||||
struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr)
|
||||
{
|
||||
static struct frr_pthread holder = {0};
|
||||
struct frr_pthread *fpt = NULL;
|
||||
|
||||
pthread_mutex_lock(&pthread_table_mtx);
|
||||
attr = attr ? attr : &frr_pthread_attr_default;
|
||||
|
||||
pthread_mutex_lock(&frr_pthread_hash_mtx);
|
||||
{
|
||||
holder.id = id;
|
||||
holder.attr.id = attr->id;
|
||||
|
||||
if (!hash_lookup(pthread_table, &holder)) {
|
||||
struct frr_pthread *fpt = XCALLOC(
|
||||
MTYPE_FRR_PTHREAD, sizeof(struct frr_pthread));
|
||||
fpt->id = id;
|
||||
fpt->master = thread_master_create(name);
|
||||
fpt->start_routine = start_routine;
|
||||
fpt->stop_routine = stop_routine;
|
||||
fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
|
||||
if (!hash_lookup(frr_pthread_hash, &holder)) {
|
||||
fpt = XCALLOC(MTYPE_FRR_PTHREAD,
|
||||
sizeof(struct frr_pthread));
|
||||
/* create new thread master */
|
||||
fpt->master = thread_master_create(attr->name);
|
||||
/* set attributes */
|
||||
fpt->attr = *attr;
|
||||
if (attr == &frr_pthread_attr_default)
|
||||
fpt->attr.id = frr_pthread_get_id();
|
||||
/* initialize startup synchronization primitives */
|
||||
fpt->running_cond_mtx = XCALLOC(
|
||||
MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t));
|
||||
fpt->running_cond = XCALLOC(MTYPE_PTHREAD_PRIM,
|
||||
sizeof(pthread_cond_t));
|
||||
pthread_mutex_init(fpt->running_cond_mtx, NULL);
|
||||
pthread_cond_init(fpt->running_cond, NULL);
|
||||
|
||||
hash_get(pthread_table, fpt, hash_alloc_intern);
|
||||
/* insert into global thread hash */
|
||||
hash_get(frr_pthread_hash, fpt, hash_alloc_intern);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&pthread_table_mtx);
|
||||
pthread_mutex_unlock(&frr_pthread_hash_mtx);
|
||||
|
||||
return fpt;
|
||||
}
|
||||
@ -104,7 +125,11 @@ struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
|
||||
void frr_pthread_destroy(struct frr_pthread *fpt)
|
||||
{
|
||||
thread_master_free(fpt->master);
|
||||
XFREE(MTYPE_FRR_PTHREAD, fpt->name);
|
||||
|
||||
pthread_mutex_destroy(fpt->running_cond_mtx);
|
||||
pthread_cond_destroy(fpt->running_cond);
|
||||
XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond_mtx);
|
||||
XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond);
|
||||
XFREE(MTYPE_FRR_PTHREAD, fpt);
|
||||
}
|
||||
|
||||
@ -113,74 +138,82 @@ struct frr_pthread *frr_pthread_get(unsigned int id)
|
||||
static struct frr_pthread holder = {0};
|
||||
struct frr_pthread *fpt;
|
||||
|
||||
pthread_mutex_lock(&pthread_table_mtx);
|
||||
pthread_mutex_lock(&frr_pthread_hash_mtx);
|
||||
{
|
||||
holder.id = id;
|
||||
fpt = hash_lookup(pthread_table, &holder);
|
||||
holder.attr.id = id;
|
||||
fpt = hash_lookup(frr_pthread_hash, &holder);
|
||||
}
|
||||
pthread_mutex_unlock(&pthread_table_mtx);
|
||||
pthread_mutex_unlock(&frr_pthread_hash_mtx);
|
||||
|
||||
return fpt;
|
||||
}
|
||||
|
||||
int frr_pthread_run(unsigned int id, const pthread_attr_t *attr, void *arg)
|
||||
int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr)
|
||||
{
|
||||
struct frr_pthread *fpt = frr_pthread_get(id);
|
||||
int ret;
|
||||
|
||||
if (!fpt)
|
||||
return -1;
|
||||
ret = pthread_create(&fpt->thread, attr, fpt->attr.start, fpt);
|
||||
|
||||
ret = pthread_create(&fpt->thread, attr, fpt->start_routine, arg);
|
||||
|
||||
/* Per pthread_create(3), the contents of fpt->thread are undefined if
|
||||
* pthread_create() did not succeed. Reset this value to zero. */
|
||||
/*
|
||||
* Per pthread_create(3), the contents of fpt->thread are undefined if
|
||||
* pthread_create() did not succeed. Reset this value to zero.
|
||||
*/
|
||||
if (ret < 0)
|
||||
memset(&fpt->thread, 0x00, sizeof(fpt->thread));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the stop routine for the frr_pthread and resets any relevant fields.
|
||||
*
|
||||
* @param fpt - the frr_pthread to stop
|
||||
* @param result - pointer to result pointer
|
||||
* @return the return code from the stop routine
|
||||
*/
|
||||
static int frr_pthread_stop_actual(struct frr_pthread *fpt, void **result)
|
||||
void frr_pthread_wait_running(struct frr_pthread *fpt)
|
||||
{
|
||||
int ret = (*fpt->stop_routine)(result, fpt);
|
||||
pthread_mutex_lock(fpt->running_cond_mtx);
|
||||
{
|
||||
while (!fpt->running)
|
||||
pthread_cond_wait(fpt->running_cond,
|
||||
fpt->running_cond_mtx);
|
||||
}
|
||||
pthread_mutex_unlock(fpt->running_cond_mtx);
|
||||
}
|
||||
|
||||
void frr_pthread_notify_running(struct frr_pthread *fpt)
|
||||
{
|
||||
pthread_mutex_lock(fpt->running_cond_mtx);
|
||||
{
|
||||
fpt->running = true;
|
||||
pthread_cond_signal(fpt->running_cond);
|
||||
}
|
||||
pthread_mutex_unlock(fpt->running_cond_mtx);
|
||||
}
|
||||
|
||||
int frr_pthread_stop(struct frr_pthread *fpt, void **result)
|
||||
{
|
||||
int ret = (*fpt->attr.stop)(fpt, result);
|
||||
memset(&fpt->thread, 0x00, sizeof(fpt->thread));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int frr_pthread_stop(unsigned int id, void **result)
|
||||
{
|
||||
struct frr_pthread *fpt = frr_pthread_get(id);
|
||||
return frr_pthread_stop_actual(fpt, result);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Callback for hash_iterate to stop all frr_pthread's.
|
||||
*/
|
||||
static void frr_pthread_stop_all_iter(struct hash_backet *hb, void *arg)
|
||||
{
|
||||
struct frr_pthread *fpt = hb->data;
|
||||
frr_pthread_stop_actual(fpt, NULL);
|
||||
frr_pthread_stop(fpt, NULL);
|
||||
}
|
||||
|
||||
void frr_pthread_stop_all()
|
||||
{
|
||||
pthread_mutex_lock(&pthread_table_mtx);
|
||||
pthread_mutex_lock(&frr_pthread_hash_mtx);
|
||||
{
|
||||
hash_iterate(pthread_table, frr_pthread_stop_all_iter, NULL);
|
||||
hash_iterate(frr_pthread_hash, frr_pthread_stop_all_iter, NULL);
|
||||
}
|
||||
pthread_mutex_unlock(&pthread_table_mtx);
|
||||
pthread_mutex_unlock(&frr_pthread_hash_mtx);
|
||||
}
|
||||
|
||||
unsigned int frr_pthread_get_id()
|
||||
{
|
||||
/* just a sanity check, this should never happen */
|
||||
assert(next_id <= INT_MAX - 1);
|
||||
return next_id++;
|
||||
}
|
||||
|
||||
@ -188,3 +221,60 @@ void frr_pthread_yield(void)
|
||||
{
|
||||
(void)sched_yield();
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* Default Event Loop
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* dummy task for sleeper pipe */
|
||||
static int fpt_dummy(struct thread *thread)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* poison pill task to end event loop */
|
||||
static int fpt_finish(struct thread *thread)
|
||||
{
|
||||
struct frr_pthread *fpt = THREAD_ARG(thread);
|
||||
atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* stop function, called from other threads to halt this one */
|
||||
static int fpt_halt(struct frr_pthread *fpt, void **res)
|
||||
{
|
||||
thread_add_event(fpt->master, &fpt_finish, fpt, 0, NULL);
|
||||
pthread_join(fpt->thread, res);
|
||||
fpt = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* entry pthread function & main event loop */
|
||||
static void *fpt_run(void *arg)
|
||||
{
|
||||
struct frr_pthread *fpt = arg;
|
||||
fpt->master->owner = pthread_self();
|
||||
|
||||
int sleeper[2];
|
||||
pipe(sleeper);
|
||||
thread_add_read(fpt->master, &fpt_dummy, NULL, sleeper[0], NULL);
|
||||
|
||||
fpt->master->handle_signals = false;
|
||||
|
||||
frr_pthread_notify_running(fpt);
|
||||
|
||||
struct thread task;
|
||||
while (atomic_load_explicit(&fpt->running, memory_order_relaxed)) {
|
||||
if (thread_fetch(fpt->master, &task)) {
|
||||
thread_call(&task);
|
||||
}
|
||||
}
|
||||
|
||||
close(sleeper[1]);
|
||||
close(sleeper[0]);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Utilities and interfaces for managing POSIX threads
|
||||
* Utilities and interfaces for managing POSIX threads within FRR.
|
||||
* Copyright (C) 2017 Cumulus Networks
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -21,36 +21,73 @@
|
||||
#define _FRR_PTHREAD_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include "frratomic.h"
|
||||
#include "memory.h"
|
||||
#include "thread.h"
|
||||
|
||||
DECLARE_MTYPE(FRR_PTHREAD);
|
||||
DECLARE_MTYPE(PTHREAD_PRIM);
|
||||
|
||||
struct frr_pthread;
|
||||
struct frr_pthread_attr;
|
||||
|
||||
struct frr_pthread_attr {
|
||||
int id;
|
||||
void *(*start)(void *);
|
||||
int (*stop)(struct frr_pthread *, void **);
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct frr_pthread {
|
||||
|
||||
/* pthread id */
|
||||
pthread_t thread;
|
||||
|
||||
/* frr thread identifier */
|
||||
unsigned int id;
|
||||
|
||||
/* thread master for this pthread's thread.c event loop */
|
||||
struct thread_master *master;
|
||||
|
||||
/* start routine */
|
||||
void *(*start_routine)(void *);
|
||||
/* caller-specified data; start & stop funcs, name, id */
|
||||
struct frr_pthread_attr attr;
|
||||
|
||||
/* stop routine */
|
||||
int (*stop_routine)(void **, struct frr_pthread *);
|
||||
/*
|
||||
* Notification mechanism for allowing pthreads to notify their parents
|
||||
* when they are ready to do work. This mechanism has two associated
|
||||
* functions:
|
||||
*
|
||||
* - frr_pthread_wait_running()
|
||||
* This function should be called by the spawning thread after
|
||||
* frr_pthread_run(). It safely waits until the spawned thread
|
||||
* indicates that is ready to do work by posting to the condition
|
||||
* variable.
|
||||
*
|
||||
* - frr_pthread_notify_running()
|
||||
* This function should be called by the spawned thread when it is
|
||||
* ready to do work. It will wake up any threads waiting on the
|
||||
* previously described condition.
|
||||
*/
|
||||
pthread_cond_t *running_cond;
|
||||
pthread_mutex_t *running_cond_mtx;
|
||||
_Atomic bool running;
|
||||
|
||||
/* the (hopefully descriptive) name of this thread */
|
||||
char *name;
|
||||
/*
|
||||
* Fake thread-specific storage. No constraints on usage. Helpful when
|
||||
* creating reentrant pthread implementations. Can be used to pass
|
||||
* argument to pthread entry function.
|
||||
*/
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* Initializes this module.
|
||||
extern struct frr_pthread_attr frr_pthread_attr_default;
|
||||
|
||||
/*
|
||||
* Initializes this module.
|
||||
*
|
||||
* Must be called before using any of the other functions.
|
||||
*/
|
||||
void frr_pthread_init(void);
|
||||
|
||||
/* Uninitializes this module.
|
||||
/*
|
||||
* Uninitializes this module.
|
||||
*
|
||||
* Destroys all registered frr_pthread's and internal data structures.
|
||||
*
|
||||
@ -59,34 +96,23 @@ void frr_pthread_init(void);
|
||||
*/
|
||||
void frr_pthread_finish(void);
|
||||
|
||||
/* Creates a new frr_pthread.
|
||||
/*
|
||||
* Creates a new frr_pthread with the given attributes.
|
||||
*
|
||||
* If the provided ID is already assigned to an existing frr_pthread, the
|
||||
* return value will be NULL.
|
||||
*
|
||||
* @param name - the name of the thread. Doesn't have to be unique, but it
|
||||
* probably should be. This value is copied and may be safely free'd upon
|
||||
* return.
|
||||
*
|
||||
* @param id - the integral ID of the thread. MUST be unique. The caller may
|
||||
* use this id to retrieve the thread.
|
||||
*
|
||||
* @param start_routine - start routine for the pthread, will be passed to
|
||||
* pthread_create (see those docs for details)
|
||||
*
|
||||
* @param stop_routine - stop routine for the pthread, called to terminate the
|
||||
* thread. This function should gracefully stop the pthread and clean up any
|
||||
* thread-specific resources. The passed pointer is used to return a data
|
||||
* result.
|
||||
* The 'attr' argument should be filled out with the desired attributes,
|
||||
* including ID, start and stop functions and the desired name. Alternatively,
|
||||
* if attr is NULL, the default attributes will be used. The pthread will be
|
||||
* set up to run a basic threadmaster loop and the name will be "Anonymous".
|
||||
* Scheduling tasks onto the threadmaster in the 'master' field of the returned
|
||||
* frr_pthread will cause them to run on that pthread.
|
||||
*
|
||||
* @param attr - the thread attributes
|
||||
* @return the created frr_pthread upon success, or NULL upon failure
|
||||
*/
|
||||
struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
|
||||
void *(*start_routine)(void *),
|
||||
int (*stop_routine)(void **,
|
||||
struct frr_pthread *));
|
||||
struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr);
|
||||
|
||||
/* Destroys an frr_pthread.
|
||||
/*
|
||||
* Destroys an frr_pthread.
|
||||
*
|
||||
* Assumes that the associated pthread, if any, has already terminated.
|
||||
*
|
||||
@ -94,38 +120,66 @@ struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
|
||||
*/
|
||||
void frr_pthread_destroy(struct frr_pthread *fpt);
|
||||
|
||||
/* Gets an existing frr_pthread by its id.
|
||||
/*
|
||||
* Gets an existing frr_pthread by its id.
|
||||
*
|
||||
* @return frr_thread associated with the provided id, or NULL on error
|
||||
*/
|
||||
struct frr_pthread *frr_pthread_get(unsigned int id);
|
||||
|
||||
/* Creates a new pthread and binds it to a frr_pthread.
|
||||
/*
|
||||
* Creates a new pthread and binds it to a frr_pthread.
|
||||
*
|
||||
* This function is a wrapper for pthread_create. The first parameter is the
|
||||
* frr_pthread to bind the created pthread to. All subsequent arguments are
|
||||
* passed unmodified to pthread_create().
|
||||
* passed unmodified to pthread_create(). The frr_pthread * provided will be
|
||||
* used as the argument to the pthread entry function. If it is necessary to
|
||||
* pass additional data, the 'data' field in the frr_pthread may be used.
|
||||
*
|
||||
* This function returns the same code as pthread_create(). If the value is
|
||||
* zero, the provided frr_pthread is bound to a running POSIX thread. If the
|
||||
* value is less than zero, the provided frr_pthread is guaranteed to be a
|
||||
* clean instance that may be susbsequently passed to frr_pthread_run().
|
||||
*
|
||||
* @param id - frr_pthread to bind the created pthread to
|
||||
* @param fpt - frr_pthread * to run
|
||||
* @param attr - see pthread_create(3)
|
||||
* @param arg - see pthread_create(3)
|
||||
*
|
||||
* @return see pthread_create(3)
|
||||
*/
|
||||
int frr_pthread_run(unsigned int id, const pthread_attr_t *attr, void *arg);
|
||||
int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr);
|
||||
|
||||
/* Stops an frr_pthread with a result.
|
||||
/*
|
||||
* Waits until the specified pthread has finished setting up and is ready to
|
||||
* begin work.
|
||||
*
|
||||
* @param id - frr_pthread to stop
|
||||
* If the pthread's code makes use of the startup synchronization mechanism,
|
||||
* this function should be called before attempting to use the functionality
|
||||
* exposed by the pthread. It waits until the 'running' condition is satisfied
|
||||
* (see struct definition of frr_pthread).
|
||||
*
|
||||
* @param fpt - the frr_pthread * to wait on
|
||||
*/
|
||||
void frr_pthread_wait_running(struct frr_pthread *fpt);
|
||||
|
||||
/*
|
||||
* Notifies other pthreads that the calling thread has finished setting up and
|
||||
* is ready to begin work.
|
||||
*
|
||||
* This will allow any other pthreads waiting in 'frr_pthread_wait_running' to
|
||||
* proceed.
|
||||
*
|
||||
* @param fpt - the frr_pthread * that has finished setting up
|
||||
*/
|
||||
void frr_pthread_notify_running(struct frr_pthread *fpt);
|
||||
|
||||
/*
|
||||
* Stops a frr_pthread with a result.
|
||||
*
|
||||
* @param fpt - frr_pthread * to stop
|
||||
* @param result - where to store the thread's result, if any. May be NULL if a
|
||||
* result is not needed.
|
||||
*/
|
||||
int frr_pthread_stop(unsigned int id, void **result);
|
||||
int frr_pthread_stop(struct frr_pthread *fpt, void **result);
|
||||
|
||||
/* Stops all frr_pthread's. */
|
||||
void frr_pthread_stop_all(void);
|
||||
@ -133,7 +187,8 @@ void frr_pthread_stop_all(void);
|
||||
/* Yields the current thread of execution */
|
||||
void frr_pthread_yield(void);
|
||||
|
||||
/* Returns a unique identifier for use with frr_pthread_new().
|
||||
/*
|
||||
* Returns a unique identifier for use with frr_pthread_new().
|
||||
*
|
||||
* Internally, this is an integer that increments after each call to this
|
||||
* function. Because the number of pthreads created should never exceed INT_MAX
|
||||
|
15
lib/if.c
15
lib/if.c
@ -210,6 +210,9 @@ void if_delete(struct interface *ifp)
|
||||
|
||||
if_link_params_free(ifp);
|
||||
|
||||
if (ifp->desc)
|
||||
XFREE(MTYPE_TMP, ifp->desc);
|
||||
|
||||
XFREE(MTYPE_IF, ifp);
|
||||
}
|
||||
|
||||
@ -219,6 +222,18 @@ struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id)
|
||||
struct vrf *vrf;
|
||||
struct interface if_tmp;
|
||||
|
||||
if (vrf_id == VRF_UNKNOWN) {
|
||||
struct interface *ifp;
|
||||
|
||||
RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) {
|
||||
ifp = if_lookup_by_index(ifindex, vrf->vrf_id);
|
||||
if (ifp)
|
||||
return ifp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vrf = vrf_lookup_by_id(vrf_id);
|
||||
if (!vrf)
|
||||
return NULL;
|
||||
|
7
lib/if.h
7
lib/if.h
@ -452,6 +452,13 @@ struct nbr_connected {
|
||||
/* Prototypes. */
|
||||
extern int if_cmp_name_func(char *, char *);
|
||||
|
||||
/*
|
||||
* Passing in VRF_UNKNOWN is a valid thing to do, unless we
|
||||
* are creating a new interface.
|
||||
*
|
||||
* This is useful for vrf route-leaking. So more than anything
|
||||
* else think before you use VRF_UNKNOWN
|
||||
*/
|
||||
extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id);
|
||||
extern struct interface *if_create(const char *name, vrf_id_t vrf_id);
|
||||
extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id);
|
||||
|
@ -89,6 +89,12 @@ typedef unsigned int mpls_lse_t;
|
||||
/* MPLS label value as a 32-bit (mostly we only care about the label value). */
|
||||
typedef unsigned int mpls_label_t;
|
||||
|
||||
struct mpls_label_stack {
|
||||
uint8_t num_labels;
|
||||
uint8_t reserved[3];
|
||||
mpls_label_t label[0]; /* 1 or more labels */
|
||||
};
|
||||
|
||||
/* The MPLS explicit-null label is 0 which means when you memset a mpls_label_t
|
||||
* to zero you have set that variable to explicit-null which was probably not
|
||||
* your intent. The work-around is to use one bit to indicate if the
|
||||
|
@ -124,7 +124,7 @@ const char *nexthop_type_to_str(enum nexthop_types_t nh_type)
|
||||
*/
|
||||
int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2)
|
||||
{
|
||||
struct nexthop_label *nhl1, *nhl2;
|
||||
struct mpls_label_stack *nhl1, *nhl2;
|
||||
|
||||
nhl1 = nh1->nh_label;
|
||||
nhl2 = nh2->nh_label;
|
||||
@ -210,12 +210,12 @@ void nexthops_free(struct nexthop *nexthop)
|
||||
void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
|
||||
u_int8_t num_labels, mpls_label_t *label)
|
||||
{
|
||||
struct nexthop_label *nh_label;
|
||||
struct mpls_label_stack *nh_label;
|
||||
int i;
|
||||
|
||||
nexthop->nh_label_type = type;
|
||||
nh_label = XCALLOC(MTYPE_NH_LABEL,
|
||||
sizeof(struct nexthop_label)
|
||||
sizeof(struct mpls_label_stack)
|
||||
+ num_labels * sizeof(mpls_label_t));
|
||||
nh_label->num_labels = num_labels;
|
||||
for (i = 0; i < num_labels; i++)
|
||||
|
@ -55,13 +55,6 @@ enum blackhole_type {
|
||||
((type) == NEXTHOP_TYPE_IFINDEX || (type) == NEXTHOP_TYPE_BLACKHOLE) \
|
||||
? (type) : ((type) | 1)
|
||||
|
||||
/* Nexthop label structure. */
|
||||
struct nexthop_label {
|
||||
u_int8_t num_labels;
|
||||
u_int8_t reserved[3];
|
||||
mpls_label_t label[0]; /* 1 or more labels. */
|
||||
};
|
||||
|
||||
/* Nexthop structure. */
|
||||
struct nexthop {
|
||||
struct nexthop *next;
|
||||
@ -107,7 +100,7 @@ struct nexthop {
|
||||
enum lsp_types_t nh_label_type;
|
||||
|
||||
/* Label(s) associated with this nexthop. */
|
||||
struct nexthop_label *nh_label;
|
||||
struct mpls_label_stack *nh_label;
|
||||
};
|
||||
|
||||
/* The following for loop allows to iterate over the nexthop
|
||||
|
5
lib/ns.h
5
lib/ns.h
@ -25,10 +25,11 @@
|
||||
#include "openbsd-tree.h"
|
||||
#include "linklist.h"
|
||||
|
||||
typedef u_int16_t ns_id_t;
|
||||
typedef u_int32_t ns_id_t;
|
||||
|
||||
/* The default NS ID */
|
||||
/* the default NS ID */
|
||||
#define NS_DEFAULT 0
|
||||
#define NS_UNKNOWN UINT32_MAX
|
||||
|
||||
/* Default netns directory (Linux) */
|
||||
#define NS_RUN_DIR "/var/run/netns"
|
||||
|
14
lib/thread.c
14
lib/thread.c
@ -919,6 +919,8 @@ struct thread *funcname_thread_add_event(struct thread_master *m,
|
||||
*/
|
||||
static void thread_cancel_rw(struct thread_master *master, int fd, short state)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
/* Cancel POLLHUP too just in case some bozo set it */
|
||||
state |= POLLHUP;
|
||||
|
||||
@ -926,8 +928,18 @@ static void thread_cancel_rw(struct thread_master *master, int fd, short state)
|
||||
nfds_t i;
|
||||
|
||||
for (i = 0; i < master->handler.pfdcount; i++)
|
||||
if (master->handler.pfds[i].fd == fd)
|
||||
if (master->handler.pfds[i].fd == fd) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
zlog_debug(
|
||||
"[!] Received cancellation request for nonexistent rw job");
|
||||
zlog_debug("[!] threadmaster: %s | fd: %d",
|
||||
master->name ? master->name : "", fd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* NOT out event. */
|
||||
master->handler.pfds[i].events &= ~(state);
|
||||
|
@ -94,7 +94,7 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
|
||||
int new = 0;
|
||||
|
||||
if (debug_vrf)
|
||||
zlog_debug("VRF_GET: %s(%d)", name, vrf_id);
|
||||
zlog_debug("VRF_GET: %s(%u)", name, vrf_id);
|
||||
|
||||
/* Nothing to see, move along here */
|
||||
if (!name && vrf_id == VRF_UNKNOWN)
|
||||
@ -267,8 +267,8 @@ void *vrf_info_lookup(vrf_id_t vrf_id)
|
||||
* VRF bit-map
|
||||
*/
|
||||
|
||||
#define VRF_BITMAP_NUM_OF_GROUPS 8
|
||||
#define VRF_BITMAP_NUM_OF_BITS_IN_GROUP (UINT16_MAX / VRF_BITMAP_NUM_OF_GROUPS)
|
||||
#define VRF_BITMAP_NUM_OF_GROUPS 1024
|
||||
#define VRF_BITMAP_NUM_OF_BITS_IN_GROUP (UINT32_MAX / VRF_BITMAP_NUM_OF_GROUPS)
|
||||
#define VRF_BITMAP_NUM_OF_BYTES_IN_GROUP \
|
||||
(VRF_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */
|
||||
|
||||
@ -355,7 +355,7 @@ static void vrf_autocomplete(vector comps, struct cmd_token *token)
|
||||
struct vrf *vrf = NULL;
|
||||
|
||||
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
||||
if (vrf->vrf_id != 0)
|
||||
if (vrf->vrf_id != VRF_DEFAULT)
|
||||
vector_set(comps, XSTRDUP(MTYPE_COMPLETION, vrf->name));
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,7 @@
|
||||
|
||||
/* The default VRF ID */
|
||||
#define VRF_DEFAULT 0
|
||||
#define VRF_UNKNOWN UINT16_MAX
|
||||
#define VRF_ALL UINT16_MAX - 1
|
||||
#define VRF_UNKNOWN UINT32_MAX
|
||||
|
||||
/* Pending: May need to refine this. */
|
||||
#ifndef IFLA_VRF_MAX
|
||||
|
126
lib/zclient.c
126
lib/zclient.c
@ -291,7 +291,7 @@ void zclient_create_header(struct stream *s, uint16_t command, vrf_id_t vrf_id)
|
||||
stream_putw(s, ZEBRA_HEADER_SIZE);
|
||||
stream_putc(s, ZEBRA_HEADER_MARKER);
|
||||
stream_putc(s, ZSERV_VERSION);
|
||||
stream_putw(s, vrf_id);
|
||||
stream_putl(s, vrf_id);
|
||||
stream_putw(s, command);
|
||||
}
|
||||
|
||||
@ -306,7 +306,7 @@ int zclient_read_header(struct stream *s, int sock, u_int16_t *size,
|
||||
*size -= ZEBRA_HEADER_SIZE;
|
||||
STREAM_GETC(s, *marker);
|
||||
STREAM_GETC(s, *version);
|
||||
STREAM_GETW(s, *vrf_id);
|
||||
STREAM_GETL(s, *vrf_id);
|
||||
STREAM_GETW(s, *cmd);
|
||||
|
||||
if (*version != ZSERV_VERSION || *marker != ZEBRA_HEADER_MARKER) {
|
||||
@ -389,25 +389,28 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
|
||||
vrf_id);
|
||||
|
||||
/* Flush all redistribute request. */
|
||||
if (vrf_id == VRF_DEFAULT)
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
||||
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
|
||||
if (zclient->mi_redist[afi][i].enabled) {
|
||||
struct listnode *node;
|
||||
u_short *id;
|
||||
if (vrf_id == VRF_DEFAULT) {
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
|
||||
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
|
||||
if (!zclient->mi_redist[afi][i].enabled)
|
||||
continue;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(
|
||||
zclient->mi_redist[afi][i]
|
||||
.instances,
|
||||
node, id))
|
||||
if (!(i == zclient->redist_default
|
||||
&& *id == zclient->instance))
|
||||
zebra_redistribute_send(
|
||||
ZEBRA_REDISTRIBUTE_ADD,
|
||||
zclient, afi, i,
|
||||
*id,
|
||||
VRF_DEFAULT);
|
||||
}
|
||||
struct listnode *node;
|
||||
u_short *id;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(
|
||||
zclient->mi_redist[afi][i]
|
||||
.instances, node, id))
|
||||
if (!(i == zclient->redist_default
|
||||
&& *id == zclient->instance))
|
||||
zebra_redistribute_send(
|
||||
ZEBRA_REDISTRIBUTE_ADD,
|
||||
zclient, afi, i,
|
||||
*id,
|
||||
VRF_DEFAULT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Flush all redistribute request. */
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
||||
@ -447,29 +450,32 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id)
|
||||
|
||||
/* Set unwanted redistribute route. */
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
||||
vrf_bitmap_set(zclient->redist[afi][zclient->redist_default],
|
||||
vrf_id);
|
||||
vrf_bitmap_unset(zclient->redist[afi][zclient->redist_default],
|
||||
vrf_id);
|
||||
|
||||
/* Flush all redistribute request. */
|
||||
if (vrf_id == VRF_DEFAULT)
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
||||
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
|
||||
if (zclient->mi_redist[afi][i].enabled) {
|
||||
struct listnode *node;
|
||||
u_short *id;
|
||||
if (vrf_id == VRF_DEFAULT) {
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
|
||||
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
|
||||
if (!zclient->mi_redist[afi][i].enabled)
|
||||
continue;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(
|
||||
zclient->mi_redist[afi][i]
|
||||
.instances,
|
||||
node, id))
|
||||
if (!(i == zclient->redist_default
|
||||
&& *id == zclient->instance))
|
||||
zebra_redistribute_send(
|
||||
ZEBRA_REDISTRIBUTE_DELETE,
|
||||
zclient, afi, i,
|
||||
*id,
|
||||
VRF_DEFAULT);
|
||||
}
|
||||
struct listnode *node;
|
||||
u_short *id;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(
|
||||
zclient->mi_redist[afi][i]
|
||||
.instances, node, id))
|
||||
if (!(i == zclient->redist_default
|
||||
&& *id == zclient->instance))
|
||||
zebra_redistribute_send(
|
||||
ZEBRA_REDISTRIBUTE_DELETE,
|
||||
zclient, afi, i,
|
||||
*id,
|
||||
VRF_DEFAULT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Flush all redistribute request. */
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
||||
@ -608,6 +614,33 @@ static int zclient_connect(struct thread *t)
|
||||
return zclient_start(zclient);
|
||||
}
|
||||
|
||||
int zclient_send_rnh(struct zclient *zclient, int command, struct prefix *p,
|
||||
bool exact_match, vrf_id_t vrf_id)
|
||||
{
|
||||
struct stream *s;
|
||||
|
||||
s = zclient->obuf;
|
||||
stream_reset(s);
|
||||
zclient_create_header(s, command, vrf_id);
|
||||
stream_putc(s, (exact_match) ? 1 : 0);
|
||||
|
||||
stream_putw(s, PREFIX_FAMILY(p));
|
||||
stream_putc(s, p->prefixlen);
|
||||
switch (PREFIX_FAMILY(p)) {
|
||||
case AF_INET:
|
||||
stream_put_in_addr(s, &p->u.prefix4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
stream_put(s, &(p->u.prefix6), 16);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
return zclient_send_message(zclient);
|
||||
}
|
||||
|
||||
/*
|
||||
* "xdr_encode"-like interface that allows daemon (client) to send
|
||||
* a message to zebra server for a route that needs to be
|
||||
@ -942,6 +975,8 @@ int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api)
|
||||
}
|
||||
|
||||
stream_putw(s, api->nexthop_num);
|
||||
if (api->nexthop_num)
|
||||
stream_putw(s, api->nh_vrf_id);
|
||||
|
||||
for (i = 0; i < api->nexthop_num; i++) {
|
||||
api_nh = &api->nexthops[i];
|
||||
@ -1091,6 +1126,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (api->nexthop_num)
|
||||
STREAM_GETW(s, api->nh_vrf_id);
|
||||
|
||||
for (i = 0; i < api->nexthop_num; i++) {
|
||||
api_nh = &api->nexthops[i];
|
||||
|
||||
@ -1677,7 +1715,7 @@ struct interface *zebra_interface_vrf_update_read(struct stream *s,
|
||||
{
|
||||
unsigned int ifindex;
|
||||
struct interface *ifp;
|
||||
vrf_id_t new_id = VRF_DEFAULT;
|
||||
vrf_id_t new_id;
|
||||
|
||||
/* Get interface index. */
|
||||
ifindex = stream_getl(s);
|
||||
@ -2043,7 +2081,7 @@ static int zclient_read(struct thread *thread)
|
||||
length = stream_getw(zclient->ibuf);
|
||||
marker = stream_getc(zclient->ibuf);
|
||||
version = stream_getc(zclient->ibuf);
|
||||
vrf_id = stream_getw(zclient->ibuf);
|
||||
vrf_id = stream_getl(zclient->ibuf);
|
||||
command = stream_getw(zclient->ibuf);
|
||||
|
||||
if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) {
|
||||
@ -2346,9 +2384,9 @@ void zclient_interface_set_master(struct zclient *client,
|
||||
|
||||
zclient_create_header(s, ZEBRA_INTERFACE_SET_MASTER, master->vrf_id);
|
||||
|
||||
stream_putw(s, master->vrf_id);
|
||||
stream_putl(s, master->vrf_id);
|
||||
stream_putl(s, master->ifindex);
|
||||
stream_putw(s, slave->vrf_id);
|
||||
stream_putl(s, slave->vrf_id);
|
||||
stream_putl(s, slave->ifindex);
|
||||
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
@ -40,7 +40,7 @@
|
||||
#define ZEBRA_MAX_PACKET_SIZ 4096
|
||||
|
||||
/* Zebra header size. */
|
||||
#define ZEBRA_HEADER_SIZE 8
|
||||
#define ZEBRA_HEADER_SIZE 10
|
||||
|
||||
/* special socket path name to use TCP
|
||||
* @ is used as first character because that's abstract socket names on Linux
|
||||
@ -227,7 +227,7 @@ struct zserv_header {
|
||||
* always set to 255 in new zserv.
|
||||
*/
|
||||
uint8_t version;
|
||||
#define ZSERV_VERSION 4
|
||||
#define ZSERV_VERSION 5
|
||||
vrf_id_t vrf_id;
|
||||
uint16_t command;
|
||||
};
|
||||
@ -281,6 +281,7 @@ struct zapi_route {
|
||||
u_int32_t mtu;
|
||||
|
||||
vrf_id_t vrf_id;
|
||||
vrf_id_t nh_vrf_id;
|
||||
|
||||
struct ethaddr rmac;
|
||||
};
|
||||
@ -420,6 +421,11 @@ extern struct interface *zebra_interface_vrf_update_read(struct stream *s,
|
||||
vrf_id_t *new_vrf_id);
|
||||
extern void zebra_interface_if_set_value(struct stream *, struct interface *);
|
||||
extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid);
|
||||
|
||||
#if CONFDATE > 20180823
|
||||
CPP_NOTICE("zapi_ipv4_route, zapi_ipv6_route, zapi_ipv4_route_ipv6_nexthop as well as the zapi_ipv4 and zapi_ipv6 data structures should be removed now");
|
||||
#endif
|
||||
|
||||
extern int zapi_ipv4_route(u_char, struct zclient *, struct prefix_ipv4 *,
|
||||
struct zapi_ipv4 *) __attribute__((deprecated));
|
||||
|
||||
@ -478,6 +484,9 @@ extern int zapi_ipv4_route_ipv6_nexthop(u_char, struct zclient *,
|
||||
struct zapi_ipv6 *)
|
||||
__attribute__((deprecated));
|
||||
extern int zclient_route_send(u_char, struct zclient *, struct zapi_route *);
|
||||
extern int zclient_send_rnh(struct zclient *zclient, int command,
|
||||
struct prefix *p, bool exact_match,
|
||||
vrf_id_t vrf_id);
|
||||
extern int zapi_route_encode(u_char, struct stream *, struct zapi_route *);
|
||||
extern int zapi_route_decode(struct stream *, struct zapi_route *);
|
||||
bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
|
||||
|
@ -486,7 +486,7 @@ typedef u_int16_t zebra_size_t;
|
||||
typedef u_int16_t zebra_command_t;
|
||||
|
||||
/* VRF ID type. */
|
||||
typedef u_int16_t vrf_id_t;
|
||||
typedef uint32_t vrf_id_t;
|
||||
|
||||
typedef uint32_t route_tag_t;
|
||||
#define ROUTE_TAG_MAX UINT32_MAX
|
||||
|
@ -95,6 +95,8 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.type = ZEBRA_ROUTE_NHRP;
|
||||
api.safi = SAFI_UNICAST;
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.prefix = *p;
|
||||
|
||||
switch (type) {
|
||||
|
@ -901,6 +901,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
|
||||
|
||||
ospf6_route_copy_nexthops(route, abr_entry);
|
||||
|
||||
|
||||
/* (7) If the routes are identical, copy the next hops over to existing
|
||||
route. ospf6's route table implementation will otherwise string both
|
||||
routes, but keep the older one as the best route since the routes
|
||||
@ -910,6 +911,12 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
|
||||
|
||||
if (old && (ospf6_route_cmp(route, old) == 0)) {
|
||||
ospf6_route_merge_nexthops(old, route);
|
||||
|
||||
if (is_debug)
|
||||
zlog_debug("%s: Update route: %s nh count %u",
|
||||
__PRETTY_FUNCTION__,
|
||||
buf, listcount(route->nh_list));
|
||||
|
||||
/* Update RIB/FIB */
|
||||
if (table->hook_add)
|
||||
(*table->hook_add)(old);
|
||||
@ -918,7 +925,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
|
||||
ospf6_route_delete(route);
|
||||
} else {
|
||||
if (is_debug)
|
||||
zlog_debug("Install route: %s", buf);
|
||||
zlog_debug("Install route: %s nh count %u",
|
||||
buf, listcount(route->nh_list));
|
||||
/* ospf6_ia_add_nw_route (table, &prefix, route); */
|
||||
ospf6_route_add(route, table);
|
||||
}
|
||||
|
@ -117,7 +117,9 @@ static void ospf6_area_lsdb_hook_remove(struct ospf6_lsa *lsa)
|
||||
|
||||
static void ospf6_area_route_hook_add(struct ospf6_route *route)
|
||||
{
|
||||
struct ospf6_route *copy = ospf6_route_copy(route);
|
||||
struct ospf6_route *copy;
|
||||
|
||||
copy = ospf6_route_copy(route);
|
||||
ospf6_route_add(copy, ospf6->route_table);
|
||||
}
|
||||
|
||||
@ -219,6 +221,7 @@ struct ospf6_area *ospf6_area_create(u_int32_t area_id, struct ospf6 *o, int df)
|
||||
oa->lsdb->hook_add = ospf6_area_lsdb_hook_add;
|
||||
oa->lsdb->hook_remove = ospf6_area_lsdb_hook_remove;
|
||||
oa->lsdb_self = ospf6_lsdb_create(oa);
|
||||
oa->temp_router_lsa_lsdb = ospf6_lsdb_create(oa);
|
||||
|
||||
oa->spf_table = OSPF6_ROUTE_TABLE_CREATE(AREA, SPF_RESULTS);
|
||||
oa->spf_table->scope = oa;
|
||||
@ -277,6 +280,7 @@ void ospf6_area_delete(struct ospf6_area *oa)
|
||||
|
||||
ospf6_lsdb_delete(oa->lsdb);
|
||||
ospf6_lsdb_delete(oa->lsdb_self);
|
||||
ospf6_lsdb_delete(oa->temp_router_lsa_lsdb);
|
||||
|
||||
ospf6_spf_table_finish(oa->spf_table);
|
||||
ospf6_route_table_delete(oa->spf_table);
|
||||
|
@ -55,6 +55,7 @@ struct ospf6_area {
|
||||
|
||||
struct ospf6_lsdb *lsdb;
|
||||
struct ospf6_lsdb *lsdb_self;
|
||||
struct ospf6_lsdb *temp_router_lsa_lsdb;
|
||||
|
||||
struct ospf6_route_table *spf_table;
|
||||
struct ospf6_route_table *route_table;
|
||||
|
@ -173,11 +173,136 @@ static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
|
||||
return ntohl(network_order);
|
||||
}
|
||||
|
||||
void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
|
||||
struct ospf6_route *route)
|
||||
{
|
||||
struct ospf6_route *old_route;
|
||||
struct ospf6_path *ecmp_path, *o_path = NULL;
|
||||
struct listnode *anode;
|
||||
struct listnode *nnode, *rnode, *rnext;
|
||||
struct ospf6_nexthop *nh, *rnh;
|
||||
char buf[PREFIX2STR_BUFFER];
|
||||
bool route_found = false;
|
||||
|
||||
for (old_route = old; old_route; old_route = old_route->next) {
|
||||
if (ospf6_route_is_same(old_route, route) &&
|
||||
(old_route->path.type == route->path.type) &&
|
||||
(old_route->path.cost == route->path.cost) &&
|
||||
(old_route->path.u.cost_e2 == route->path.u.cost_e2)) {
|
||||
|
||||
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||
prefix2str(&old_route->prefix, buf,
|
||||
sizeof(buf));
|
||||
zlog_debug("%s: old route %s path cost %u [%u]",
|
||||
__PRETTY_FUNCTION__, buf,
|
||||
old_route->path.cost,
|
||||
ospf6_route_is_same(old_route,
|
||||
route));
|
||||
}
|
||||
route_found = true;
|
||||
/* check if this path exists already in
|
||||
* route->paths list, if so, replace nh_list
|
||||
* from asbr_entry.
|
||||
*/
|
||||
for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
|
||||
o_path)) {
|
||||
if ((o_path->origin.id == route->path.origin.id)
|
||||
&& (o_path->origin.adv_router ==
|
||||
route->path.origin.adv_router))
|
||||
break;
|
||||
}
|
||||
/* If path is not found in old_route paths's list,
|
||||
* add a new path to route paths list and merge
|
||||
* nexthops in route->path->nh_list.
|
||||
* Otherwise replace existing path's nh_list.
|
||||
*/
|
||||
if (o_path == NULL) {
|
||||
ecmp_path = ospf6_path_dup(&route->path);
|
||||
|
||||
/* Add a nh_list to new ecmp path */
|
||||
ospf6_copy_nexthops(ecmp_path->nh_list,
|
||||
route->nh_list);
|
||||
/* Merge nexthop to existing route's nh_list */
|
||||
ospf6_route_merge_nexthops(old_route, route);
|
||||
|
||||
/* Update RIB/FIB */
|
||||
if (ospf6->route_table->hook_add)
|
||||
(*ospf6->route_table->hook_add)
|
||||
(old_route);
|
||||
|
||||
/* Add the new path to route's path list */
|
||||
listnode_add_sort(old_route->paths, ecmp_path);
|
||||
|
||||
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||
prefix2str(&route->prefix, buf,
|
||||
sizeof(buf));
|
||||
zlog_debug("%s: route %s another path added with nh %u, Paths %u",
|
||||
__PRETTY_FUNCTION__, buf,
|
||||
listcount(ecmp_path->nh_list),
|
||||
old_route->paths ?
|
||||
listcount(old_route->paths)
|
||||
: 0);
|
||||
}
|
||||
} else {
|
||||
for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
|
||||
nnode, nh)) {
|
||||
for (ALL_LIST_ELEMENTS(
|
||||
old_route->nh_list,
|
||||
rnode, rnext, rnh)) {
|
||||
if (!ospf6_nexthop_is_same(rnh,
|
||||
nh))
|
||||
continue;
|
||||
|
||||
listnode_delete(
|
||||
old_route->nh_list,
|
||||
rnh);
|
||||
ospf6_nexthop_delete(rnh);
|
||||
}
|
||||
}
|
||||
list_delete_all_node(o_path->nh_list);
|
||||
ospf6_copy_nexthops(o_path->nh_list,
|
||||
route->nh_list);
|
||||
|
||||
/* Merge nexthop to existing route's nh_list */
|
||||
ospf6_route_merge_nexthops(old_route,
|
||||
route);
|
||||
|
||||
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||
prefix2str(&route->prefix,
|
||||
buf, sizeof(buf));
|
||||
zlog_debug("%s: existing route %s with effective nh count %u",
|
||||
__PRETTY_FUNCTION__, buf,
|
||||
old_route->nh_list ?
|
||||
listcount(old_route->nh_list)
|
||||
: 0);
|
||||
}
|
||||
|
||||
/* Update RIB/FIB */
|
||||
if (ospf6->route_table->hook_add)
|
||||
(*ospf6->route_table->hook_add)
|
||||
(old_route);
|
||||
|
||||
}
|
||||
/* Delete the new route its info added to existing
|
||||
* route.
|
||||
*/
|
||||
ospf6_route_delete(route);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!route_found) {
|
||||
/* Add new route to existing node in ospf6 route table. */
|
||||
ospf6_route_add(route, ospf6->route_table);
|
||||
}
|
||||
}
|
||||
|
||||
void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
|
||||
{
|
||||
struct ospf6_as_external_lsa *external;
|
||||
struct prefix asbr_id;
|
||||
struct ospf6_route *asbr_entry, *route;
|
||||
struct ospf6_route *asbr_entry, *route, *old;
|
||||
struct ospf6_path *path;
|
||||
char buf[PREFIX2STR_BUFFER];
|
||||
|
||||
external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
|
||||
@ -245,12 +370,34 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
|
||||
|
||||
ospf6_route_copy_nexthops(route, asbr_entry);
|
||||
|
||||
path = ospf6_path_dup(&route->path);
|
||||
ospf6_copy_nexthops(path->nh_list, asbr_entry->nh_list);
|
||||
listnode_add_sort(route->paths, path);
|
||||
|
||||
|
||||
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||
prefix2str(&route->prefix, buf, sizeof(buf));
|
||||
zlog_debug("AS-External route add: %s", buf);
|
||||
zlog_debug("%s: AS-External %u route add %s cost %u(%u) nh %u",
|
||||
__PRETTY_FUNCTION__,
|
||||
(route->path.type == OSPF6_PATH_TYPE_EXTERNAL1)
|
||||
? 1 : 2, buf, route->path.cost,
|
||||
route->path.u.cost_e2,
|
||||
listcount(route->nh_list));
|
||||
}
|
||||
|
||||
old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
|
||||
if (!old) {
|
||||
/* Add the new route to ospf6 instance route table. */
|
||||
ospf6_route_add(route, ospf6->route_table);
|
||||
} else {
|
||||
/* RFC 2328 16.4 (6)
|
||||
* ECMP: Keep new equal preference path in current
|
||||
* route's path list, update zebra with new effective
|
||||
* list along with addition of ECMP path.
|
||||
*/
|
||||
ospf6_asbr_update_route_ecmp_path(old, route);
|
||||
}
|
||||
|
||||
ospf6_route_add(route, ospf6->route_table);
|
||||
}
|
||||
|
||||
void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
|
||||
@ -291,16 +438,126 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
|
||||
nroute = ospf6_route_next(route);
|
||||
if (route->type != OSPF6_DEST_TYPE_NETWORK)
|
||||
continue;
|
||||
if (route->path.origin.type != lsa->header->type)
|
||||
continue;
|
||||
if (route->path.origin.id != lsa->header->id)
|
||||
continue;
|
||||
if (route->path.origin.adv_router != lsa->header->adv_router)
|
||||
|
||||
/* Route has multiple ECMP paths remove,
|
||||
* matching path and update effective route's nh list.
|
||||
*/
|
||||
if (listcount(route->paths) > 1) {
|
||||
struct listnode *anode, *anext;
|
||||
struct listnode *nnode, *rnode, *rnext;
|
||||
struct ospf6_nexthop *nh, *rnh;
|
||||
struct ospf6_path *o_path;
|
||||
bool nh_updated = false;
|
||||
|
||||
/* Iterate all paths of route to find maching with LSA
|
||||
* remove from route path list. If route->path is same,
|
||||
* replace from paths list.
|
||||
*/
|
||||
for (ALL_LIST_ELEMENTS(route->paths, anode, anext,
|
||||
o_path)) {
|
||||
if (o_path->origin.type != lsa->header->type)
|
||||
continue;
|
||||
if (o_path->origin.id != lsa->header->id)
|
||||
continue;
|
||||
if (o_path->origin.adv_router !=
|
||||
lsa->header->adv_router)
|
||||
continue;
|
||||
|
||||
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||
prefix2str(&prefix, buf, sizeof(buf));
|
||||
zlog_debug(
|
||||
"%s: route %s path found with nh %u",
|
||||
__PRETTY_FUNCTION__, buf,
|
||||
listcount(o_path->nh_list));
|
||||
}
|
||||
|
||||
/* Remove found path's nh_list from
|
||||
* the route's nh_list.
|
||||
*/
|
||||
for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
|
||||
nnode, nh)) {
|
||||
for (ALL_LIST_ELEMENTS(route->nh_list,
|
||||
rnode, rnext, rnh)) {
|
||||
if (!ospf6_nexthop_is_same(rnh,
|
||||
nh))
|
||||
continue;
|
||||
listnode_delete(route->nh_list,
|
||||
rnh);
|
||||
ospf6_nexthop_delete(rnh);
|
||||
}
|
||||
}
|
||||
/* Delete the path from route's path list */
|
||||
listnode_delete(route->paths, o_path);
|
||||
ospf6_path_free(o_path);
|
||||
nh_updated = true;
|
||||
}
|
||||
|
||||
if (nh_updated) {
|
||||
/* Iterate all paths and merge nexthop,
|
||||
* unlesss any of the nexthop similar to
|
||||
* ones deleted as part of path deletion.
|
||||
*/
|
||||
|
||||
for (ALL_LIST_ELEMENTS(route->paths, anode,
|
||||
anext, o_path)) {
|
||||
ospf6_merge_nexthops(route->nh_list,
|
||||
o_path->nh_list);
|
||||
}
|
||||
|
||||
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||
prefix2str(&route->prefix, buf,
|
||||
sizeof(buf));
|
||||
zlog_debug("%s: AS-External %u route %s update paths %u nh %u"
|
||||
, __PRETTY_FUNCTION__,
|
||||
(route->path.type ==
|
||||
OSPF6_PATH_TYPE_EXTERNAL1)
|
||||
? 1 : 2, buf,
|
||||
listcount(route->paths),
|
||||
listcount(route->nh_list));
|
||||
}
|
||||
|
||||
/* Update RIB/FIB w/ effective nh_list */
|
||||
if (ospf6->route_table->hook_add)
|
||||
(*ospf6->route_table->hook_add)(route);
|
||||
|
||||
/* route's path is similar to lsa header,
|
||||
* replace route's path with route's
|
||||
* paths list head.
|
||||
*/
|
||||
if (route->path.origin.id == lsa->header->id &&
|
||||
route->path.origin.adv_router ==
|
||||
lsa->header->adv_router) {
|
||||
struct ospf6_path *h_path;
|
||||
|
||||
h_path = (struct ospf6_path *)
|
||||
listgetdata(listhead(route->paths));
|
||||
route->path.origin.type =
|
||||
h_path->origin.type;
|
||||
route->path.origin.id =
|
||||
h_path->origin.id;
|
||||
route->path.origin.adv_router =
|
||||
h_path->origin.adv_router;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
} else {
|
||||
if (route->path.origin.type != lsa->header->type)
|
||||
continue;
|
||||
if (route->path.origin.id != lsa->header->id)
|
||||
continue;
|
||||
if (route->path.origin.adv_router !=
|
||||
lsa->header->adv_router)
|
||||
continue;
|
||||
}
|
||||
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||
prefix2str(&route->prefix, buf, sizeof(buf));
|
||||
zlog_debug("AS-External route remove: %s", buf);
|
||||
zlog_debug("%s: AS-External %u route remove %s cost %u(%u) nh %u",
|
||||
__PRETTY_FUNCTION__,
|
||||
route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
|
||||
? 1 : 2, buf, route->path.cost,
|
||||
route->path.u.cost_e2,
|
||||
listcount(route->nh_list));
|
||||
}
|
||||
ospf6_route_remove(route, ospf6->route_table);
|
||||
}
|
||||
|
@ -93,5 +93,7 @@ extern void ospf6_asbr_send_externals_to_area(struct ospf6_area *);
|
||||
|
||||
extern int config_write_ospf6_debug_asbr(struct vty *vty);
|
||||
extern void install_element_ospf6_debug_asbr(void);
|
||||
extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
|
||||
struct ospf6_route *route);
|
||||
|
||||
#endif /* OSPF6_ASBR_H */
|
||||
|
@ -1008,6 +1008,103 @@ DEFUN (show_ipv6_ospf6_interface,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int ospf6_interface_show_traffic(struct vty *vty,
|
||||
uint32_t vrf_id,
|
||||
struct interface *intf_ifp,
|
||||
int display_once)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct vrf *vrf = NULL;
|
||||
struct ospf6_interface *oi = NULL;
|
||||
|
||||
vrf = vrf_lookup_by_id(vrf_id);
|
||||
|
||||
if (!display_once) {
|
||||
vty_out(vty, "\n");
|
||||
vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s\n",
|
||||
"Interface", " HELLO", " DB-Desc", " LS-Req",
|
||||
" LS-Update", " LS-Ack");
|
||||
vty_out(vty, "%-10s%-18s%-18s%-17s%-17s%-17s\n", "",
|
||||
" Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx");
|
||||
vty_out(vty,
|
||||
"--------------------------------------------------------------------------------------------\n");
|
||||
}
|
||||
|
||||
if (intf_ifp == NULL) {
|
||||
FOR_ALL_INTERFACES (vrf, ifp) {
|
||||
if (ifp->info)
|
||||
oi = (struct ospf6_interface *)ifp->info;
|
||||
else
|
||||
continue;
|
||||
|
||||
vty_out(vty,
|
||||
"%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n",
|
||||
oi->interface->name, oi->hello_in,
|
||||
oi->hello_out,
|
||||
oi->db_desc_in, oi->db_desc_out,
|
||||
oi->ls_req_in, oi->ls_req_out,
|
||||
oi->ls_upd_in, oi->ls_upd_out,
|
||||
oi->ls_ack_in, oi->ls_ack_out);
|
||||
}
|
||||
} else {
|
||||
oi = intf_ifp->info;
|
||||
if (oi == NULL)
|
||||
return CMD_WARNING;
|
||||
|
||||
vty_out(vty,
|
||||
"%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n",
|
||||
oi->interface->name, oi->hello_in,
|
||||
oi->hello_out,
|
||||
oi->db_desc_in, oi->db_desc_out,
|
||||
oi->ls_req_in, oi->ls_req_out,
|
||||
oi->ls_upd_in, oi->ls_upd_out,
|
||||
oi->ls_ack_in, oi->ls_ack_out);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* show interface */
|
||||
DEFUN (show_ipv6_ospf6_interface_traffic,
|
||||
show_ipv6_ospf6_interface_traffic_cmd,
|
||||
"show ipv6 ospf6 interface traffic [IFNAME]",
|
||||
SHOW_STR
|
||||
IP6_STR
|
||||
OSPF6_STR
|
||||
INTERFACE_STR
|
||||
"Protocol Packet counters\n"
|
||||
IFNAME_STR)
|
||||
{
|
||||
int idx_ifname = 0;
|
||||
int display_once = 0;
|
||||
char *intf_name = NULL;
|
||||
struct interface *ifp = NULL;
|
||||
|
||||
if (argv_find(argv, argc, "IFNAME", &idx_ifname)) {
|
||||
intf_name = argv[idx_ifname]->arg;
|
||||
ifp = if_lookup_by_name(intf_name, VRF_DEFAULT);
|
||||
if (ifp == NULL) {
|
||||
vty_out(vty,
|
||||
"No such Interface: %s\n",
|
||||
intf_name);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (ifp->info == NULL) {
|
||||
vty_out(vty,
|
||||
" OSPF not enabled on this interface %s\n",
|
||||
intf_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ospf6_interface_show_traffic(vty, VRF_DEFAULT, ifp,
|
||||
display_once);
|
||||
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DEFUN (show_ipv6_ospf6_interface_ifname_prefix,
|
||||
show_ipv6_ospf6_interface_ifname_prefix_cmd,
|
||||
"show ipv6 ospf6 interface IFNAME prefix [<X:X::X:X|X:X::X:X/M>] [<match|detail>]",
|
||||
@ -1841,6 +1938,8 @@ void ospf6_interface_init(void)
|
||||
install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
|
||||
install_element(VIEW_NODE,
|
||||
&show_ipv6_ospf6_interface_ifname_prefix_cmd);
|
||||
install_element(VIEW_NODE,
|
||||
&show_ipv6_ospf6_interface_traffic_cmd);
|
||||
|
||||
install_element(INTERFACE_NODE, &ipv6_ospf6_cost_cmd);
|
||||
install_element(INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd);
|
||||
|
@ -117,6 +117,19 @@ struct ospf6_interface {
|
||||
/* BFD information */
|
||||
void *bfd_info;
|
||||
|
||||
/* Statistics Fields */
|
||||
u_int32_t hello_in;
|
||||
u_int32_t hello_out;
|
||||
u_int32_t db_desc_in;
|
||||
u_int32_t db_desc_out;
|
||||
u_int32_t ls_req_in;
|
||||
u_int32_t ls_req_out;
|
||||
u_int32_t ls_upd_in;
|
||||
u_int32_t ls_upd_out;
|
||||
u_int32_t ls_ack_in;
|
||||
u_int32_t ls_ack_out;
|
||||
u_int32_t discarded;
|
||||
|
||||
QOBJ_FIELDS
|
||||
};
|
||||
DECLARE_QOBJ_TYPE(ospf6_interface)
|
||||
|
@ -1404,7 +1404,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
|
||||
|
||||
if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
|
||||
prefix2str(&route->prefix, buf, sizeof(buf));
|
||||
zlog_debug(" route %s add", buf);
|
||||
zlog_debug(" route %s add with nh count %u", buf,
|
||||
listcount(route->nh_list));
|
||||
}
|
||||
|
||||
ospf6_route_add(route, oa->route_table);
|
||||
|
@ -191,7 +191,7 @@ int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2)
|
||||
|
||||
/* ospf6 age functions */
|
||||
/* calculate birth */
|
||||
static void ospf6_lsa_age_set(struct ospf6_lsa *lsa)
|
||||
void ospf6_lsa_age_set(struct ospf6_lsa *lsa)
|
||||
{
|
||||
struct timeval now;
|
||||
|
||||
|
@ -252,5 +252,6 @@ extern void ospf6_lsa_terminate(void);
|
||||
|
||||
extern int config_write_ospf6_debug_lsa(struct vty *vty);
|
||||
extern void install_element_ospf6_debug_lsa(void);
|
||||
extern void ospf6_lsa_age_set(struct ospf6_lsa *lsa);
|
||||
|
||||
#endif /* OSPF6_LSA_H */
|
||||
|
@ -41,4 +41,5 @@ DEFINE_MTYPE(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex")
|
||||
DEFINE_MTYPE(OSPF6D, OSPF6_SPFTREE, "OSPF6 SPF tree")
|
||||
DEFINE_MTYPE(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop")
|
||||
DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info")
|
||||
DEFINE_MTYPE(OSPF6D, OSPF6_PATH, "OSPF6 Path")
|
||||
DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other")
|
||||
|
@ -40,6 +40,7 @@ DECLARE_MTYPE(OSPF6_VERTEX)
|
||||
DECLARE_MTYPE(OSPF6_SPFTREE)
|
||||
DECLARE_MTYPE(OSPF6_NEXTHOP)
|
||||
DECLARE_MTYPE(OSPF6_EXTERNAL_INFO)
|
||||
DECLARE_MTYPE(OSPF6_PATH)
|
||||
DECLARE_MTYPE(OSPF6_OTHER)
|
||||
|
||||
#endif /* _QUAGGA_OSPF6_MEMORY_H */
|
||||
|
@ -321,6 +321,8 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
|
||||
backupseen++;
|
||||
}
|
||||
|
||||
oi->hello_in++;
|
||||
|
||||
/* Execute neighbor events */
|
||||
thread_execute(master, hello_received, on, 0);
|
||||
if (twoway)
|
||||
@ -776,6 +778,8 @@ static void ospf6_dbdesc_recv(struct in6_addr *src, struct in6_addr *dst,
|
||||
dbdesc->reserved2 = 0;
|
||||
}
|
||||
|
||||
oi->db_desc_in++;
|
||||
|
||||
if (ntohl(oh->router_id) < ntohl(ospf6->router_id))
|
||||
ospf6_dbdesc_recv_master(oh, on);
|
||||
else if (ntohl(ospf6->router_id) < ntohl(oh->router_id))
|
||||
@ -811,6 +815,8 @@ static void ospf6_lsreq_recv(struct in6_addr *src, struct in6_addr *dst,
|
||||
return;
|
||||
}
|
||||
|
||||
oi->ls_req_in++;
|
||||
|
||||
/* Process each request */
|
||||
for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
|
||||
p + sizeof(struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END(oh);
|
||||
@ -1370,6 +1376,8 @@ static void ospf6_lsupdate_recv(struct in6_addr *src, struct in6_addr *dst,
|
||||
lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
|
||||
+ sizeof(struct ospf6_header));
|
||||
|
||||
oi->ls_upd_in++;
|
||||
|
||||
/* Process LSAs */
|
||||
for (p = (char *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
|
||||
p < OSPF6_MESSAGE_END(oh)
|
||||
@ -1407,6 +1415,8 @@ static void ospf6_lsack_recv(struct in6_addr *src, struct in6_addr *dst,
|
||||
return;
|
||||
}
|
||||
|
||||
oi->ls_ack_in++;
|
||||
|
||||
for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
|
||||
p + sizeof(struct ospf6_lsa_header) <= OSPF6_MESSAGE_END(oh);
|
||||
p += sizeof(struct ospf6_lsa_header)) {
|
||||
@ -1777,6 +1787,8 @@ int ospf6_hello_send(struct thread *thread)
|
||||
oh->type = OSPF6_MESSAGE_TYPE_HELLO;
|
||||
oh->length = htons(p - sendbuf);
|
||||
|
||||
oi->hello_out++;
|
||||
|
||||
ospf6_send(oi->linklocal_addr, &allspfrouters6, oi, oh);
|
||||
return 0;
|
||||
}
|
||||
@ -1852,6 +1864,8 @@ int ospf6_dbdesc_send(struct thread *thread)
|
||||
else
|
||||
dst = &on->linklocal_addr;
|
||||
|
||||
on->ospf6_if->db_desc_out++;
|
||||
|
||||
ospf6_send(on->ospf6_if->linklocal_addr, dst, on->ospf6_if, oh);
|
||||
|
||||
return 0;
|
||||
@ -1955,6 +1969,8 @@ int ospf6_lsreq_send(struct thread *thread)
|
||||
oh->type = OSPF6_MESSAGE_TYPE_LSREQ;
|
||||
oh->length = htons(p - sendbuf);
|
||||
|
||||
on->ospf6_if->ls_req_out++;
|
||||
|
||||
if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
|
||||
ospf6_send(on->ospf6_if->linklocal_addr, &allspfrouters6,
|
||||
on->ospf6_if, oh);
|
||||
@ -1979,6 +1995,8 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on,
|
||||
{
|
||||
|
||||
if (on) {
|
||||
on->ospf6_if->ls_upd_out++;
|
||||
|
||||
if ((on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) ||
|
||||
(on->ospf6_if->state == OSPF6_INTERFACE_DR) ||
|
||||
(on->ospf6_if->state == OSPF6_INTERFACE_BDR)) {
|
||||
@ -1989,6 +2007,9 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on,
|
||||
&on->linklocal_addr, on->ospf6_if, oh);
|
||||
}
|
||||
} else if (oi) {
|
||||
|
||||
oi->ls_upd_out++;
|
||||
|
||||
if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT) ||
|
||||
(oi->state == OSPF6_INTERFACE_DR) ||
|
||||
(oi->state == OSPF6_INTERFACE_BDR)) {
|
||||
@ -2185,8 +2206,11 @@ int ospf6_lsupdate_send_interface(struct thread *thread)
|
||||
lsupdate->lsa_number = htonl(lsa_cnt);
|
||||
|
||||
ospf6_send_lsupdate(NULL, oi, oh);
|
||||
zlog_debug("%s: LSUpdate length %d",
|
||||
__PRETTY_FUNCTION__, ntohs(oh->length));
|
||||
if (IS_OSPF6_DEBUG_MESSAGE(
|
||||
OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
|
||||
zlog_debug("%s: LSUpdate length %d",
|
||||
__PRETTY_FUNCTION__,
|
||||
ntohs(oh->length));
|
||||
|
||||
memset(sendbuf, 0, iobuflen);
|
||||
oh = (struct ospf6_header *)sendbuf;
|
||||
@ -2263,6 +2287,8 @@ int ospf6_lsack_send_neighbor(struct thread *thread)
|
||||
oh->type = OSPF6_MESSAGE_TYPE_LSACK;
|
||||
oh->length = htons(p - sendbuf);
|
||||
|
||||
on->ospf6_if->ls_ack_out++;
|
||||
|
||||
ospf6_send(on->ospf6_if->linklocal_addr,
|
||||
&on->linklocal_addr,
|
||||
on->ospf6_if, oh);
|
||||
@ -2288,6 +2314,8 @@ int ospf6_lsack_send_neighbor(struct thread *thread)
|
||||
oh->type = OSPF6_MESSAGE_TYPE_LSACK;
|
||||
oh->length = htons(p - sendbuf);
|
||||
|
||||
on->ospf6_if->ls_ack_out++;
|
||||
|
||||
ospf6_send(on->ospf6_if->linklocal_addr, &on->linklocal_addr,
|
||||
on->ospf6_if, oh);
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ void ospf6_copy_nexthops(struct list *dst, struct list *src)
|
||||
if (ospf6_nexthop_is_set(nh)) {
|
||||
nh_new = ospf6_nexthop_create();
|
||||
ospf6_nexthop_copy(nh_new, nh);
|
||||
listnode_add(dst, nh_new);
|
||||
listnode_add_sort(dst, nh_new);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -231,7 +231,7 @@ void ospf6_merge_nexthops(struct list *dst, struct list *src)
|
||||
if (!ospf6_route_find_nexthop(dst, nh)) {
|
||||
nh_new = ospf6_nexthop_create();
|
||||
ospf6_nexthop_copy(nh_new, nh);
|
||||
listnode_add(dst, nh_new);
|
||||
listnode_add_sort(dst, nh_new);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -338,7 +338,7 @@ int ospf6_route_get_first_nh_index(struct ospf6_route *route)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
|
||||
int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
|
||||
{
|
||||
if (a->ifindex < b->ifindex)
|
||||
return -1;
|
||||
@ -351,6 +351,36 @@ static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ospf6_path_cmp(struct ospf6_path *a, struct ospf6_path *b)
|
||||
{
|
||||
if (a->origin.adv_router < b->origin.adv_router)
|
||||
return -1;
|
||||
else if (a->origin.adv_router > b->origin.adv_router)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ospf6_path_free(struct ospf6_path *op)
|
||||
{
|
||||
if (op->nh_list)
|
||||
list_delete_and_null(&op->nh_list);
|
||||
XFREE(MTYPE_OSPF6_PATH, op);
|
||||
}
|
||||
|
||||
struct ospf6_path *ospf6_path_dup(struct ospf6_path *path)
|
||||
{
|
||||
struct ospf6_path *new;
|
||||
|
||||
new = XCALLOC(MTYPE_OSPF6_PATH, sizeof(struct ospf6_path));
|
||||
memcpy(new, path, sizeof(struct ospf6_path));
|
||||
new->nh_list = list_new();
|
||||
new->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
|
||||
new->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
struct ospf6_route *ospf6_route_create(void)
|
||||
{
|
||||
struct ospf6_route *route;
|
||||
@ -358,6 +388,9 @@ struct ospf6_route *ospf6_route_create(void)
|
||||
route->nh_list = list_new();
|
||||
route->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
|
||||
route->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
|
||||
route->paths = list_new();
|
||||
route->paths->cmp = (int (*)(void *, void *))ospf6_path_cmp;
|
||||
route->paths->del = (void (*)(void *))ospf6_path_free;
|
||||
return route;
|
||||
}
|
||||
|
||||
@ -366,6 +399,8 @@ void ospf6_route_delete(struct ospf6_route *route)
|
||||
if (route) {
|
||||
if (route->nh_list)
|
||||
list_delete_and_null(&route->nh_list);
|
||||
if (route->paths)
|
||||
list_delete_and_null(&route->paths);
|
||||
XFREE(MTYPE_OSPF6_ROUTE, route);
|
||||
}
|
||||
}
|
||||
@ -464,7 +499,13 @@ ospf6_route_lookup_identical(struct ospf6_route *route,
|
||||
|
||||
for (target = ospf6_route_lookup(&route->prefix, table); target;
|
||||
target = target->next) {
|
||||
if (ospf6_route_is_identical(target, route))
|
||||
if (target->type == route->type &&
|
||||
(memcmp(&target->prefix, &route->prefix,
|
||||
sizeof(struct prefix)) == 0) &&
|
||||
target->path.type == route->path.type &&
|
||||
target->path.cost == route->path.cost &&
|
||||
target->path.u.cost_e2 == route->path.u.cost_e2 &&
|
||||
ospf6_route_cmp_nexthops(target, route) == 0)
|
||||
return target;
|
||||
}
|
||||
return NULL;
|
||||
@ -1083,6 +1124,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route)
|
||||
vty_out(vty, "Metric: %d (%d)\n", route->path.cost,
|
||||
route->path.u.cost_e2);
|
||||
|
||||
vty_out(vty, "Paths count: %u\n", route->paths->count);
|
||||
vty_out(vty, "Nexthop count: %u\n", route->nh_list->count);
|
||||
/* Nexthops */
|
||||
vty_out(vty, "Nexthop:\n");
|
||||
|
@ -96,6 +96,9 @@ struct ospf6_path {
|
||||
u_int32_t cost_config;
|
||||
} u;
|
||||
u_int32_t tag;
|
||||
|
||||
/* nh list for this path */
|
||||
struct list *nh_list;
|
||||
};
|
||||
|
||||
#define OSPF6_PATH_TYPE_NONE 0
|
||||
@ -149,6 +152,9 @@ struct ospf6_route {
|
||||
/* path */
|
||||
struct ospf6_path path;
|
||||
|
||||
/* List of Paths. */
|
||||
struct list *paths;
|
||||
|
||||
/* nexthop */
|
||||
struct list *nh_list;
|
||||
};
|
||||
@ -256,6 +262,7 @@ extern void ospf6_linkstate_prefix2str(struct prefix *prefix, char *buf,
|
||||
int size);
|
||||
|
||||
extern struct ospf6_nexthop *ospf6_nexthop_create(void);
|
||||
extern int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b);
|
||||
extern void ospf6_nexthop_delete(struct ospf6_nexthop *nh);
|
||||
extern void ospf6_clear_nexthops(struct list *nh_list);
|
||||
extern int ospf6_num_nexthops(struct list *nh_list);
|
||||
@ -331,5 +338,7 @@ extern int config_write_ospf6_debug_route(struct vty *vty);
|
||||
extern void install_element_ospf6_debug_route(void);
|
||||
extern void ospf6_route_init(void);
|
||||
extern void ospf6_clean(void);
|
||||
extern void ospf6_path_free(struct ospf6_path *op);
|
||||
extern struct ospf6_path *ospf6_path_dup(struct ospf6_path *path);
|
||||
|
||||
#endif /* OSPF6_ROUTE_H */
|
||||
|
@ -145,6 +145,7 @@ static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa)
|
||||
v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END(lsa->header) + 3);
|
||||
|
||||
v->nh_list = list_new();
|
||||
v->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
|
||||
v->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
|
||||
|
||||
v->parent = NULL;
|
||||
@ -162,21 +163,20 @@ static void ospf6_vertex_delete(struct ospf6_vertex *v)
|
||||
}
|
||||
|
||||
static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc,
|
||||
struct ospf6_vertex *v,
|
||||
uint32_t link_id)
|
||||
struct ospf6_vertex *v)
|
||||
{
|
||||
struct ospf6_lsa *lsa;
|
||||
struct ospf6_lsa *lsa = NULL;
|
||||
u_int16_t type = 0;
|
||||
u_int32_t id = 0, adv_router = 0;
|
||||
|
||||
if (VERTEX_IS_TYPE(NETWORK, v)) {
|
||||
type = htons(OSPF6_LSTYPE_ROUTER);
|
||||
id = link_id;
|
||||
id = htonl(0);
|
||||
adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc);
|
||||
} else {
|
||||
if (ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc)) {
|
||||
type = htons(OSPF6_LSTYPE_ROUTER);
|
||||
id = link_id;
|
||||
id = htonl(0);
|
||||
adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc);
|
||||
} else if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, lsdesc)) {
|
||||
type = htons(OSPF6_LSTYPE_NETWORK);
|
||||
@ -185,19 +185,22 @@ static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc,
|
||||
}
|
||||
}
|
||||
|
||||
lsa = ospf6_lsdb_lookup(type, id, adv_router, v->area->lsdb);
|
||||
|
||||
if (type == htons(OSPF6_LSTYPE_NETWORK))
|
||||
lsa = ospf6_lsdb_lookup(type, id, adv_router, v->area->lsdb);
|
||||
else
|
||||
lsa = ospf6_create_single_router_lsa(v->area, v->area->lsdb,
|
||||
adv_router);
|
||||
if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
|
||||
char ibuf[16], abuf[16];
|
||||
inet_ntop(AF_INET, &id, ibuf, sizeof(ibuf));
|
||||
inet_ntop(AF_INET, &adv_router, abuf, sizeof(abuf));
|
||||
if (lsa)
|
||||
zlog_debug(" Link to: %s , V %s id %u", lsa->name,
|
||||
v->name, link_id);
|
||||
zlog_debug(" Link to: %s len %u, V %s", lsa->name,
|
||||
ntohs(lsa->header->length), v->name);
|
||||
else
|
||||
zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s id %u",
|
||||
zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s",
|
||||
ospf6_lstype_name(type), ibuf, abuf,
|
||||
v->name, link_id);
|
||||
v->name);
|
||||
}
|
||||
|
||||
return lsa;
|
||||
@ -460,17 +463,14 @@ void ospf6_spf_calculation(u_int32_t router_id,
|
||||
struct ospf6_vertex *root, *v, *w;
|
||||
int size;
|
||||
caddr_t lsdesc;
|
||||
struct ospf6_lsa *lsa, *self_rtr_lsa = NULL, *rtr_lsa = NULL;
|
||||
const struct route_node *end = NULL;
|
||||
struct ospf6_lsa *lsa;
|
||||
struct in6_addr address;
|
||||
struct ospf6_lsdb *lsdb = NULL;
|
||||
|
||||
ospf6_spf_table_finish(result_table);
|
||||
|
||||
/* Install the calculating router itself as the root of the SPF tree */
|
||||
/* construct root vertex */
|
||||
lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_ROUTER), htonl(0), router_id,
|
||||
oa->lsdb_self);
|
||||
lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
|
||||
if (lsa == NULL) {
|
||||
if (IS_OSPF6_DEBUG_SPF(PROCESS))
|
||||
zlog_debug("%s: No router LSA for area %s\n", __func__,
|
||||
@ -478,8 +478,6 @@ void ospf6_spf_calculation(u_int32_t router_id,
|
||||
return;
|
||||
}
|
||||
|
||||
self_rtr_lsa = lsa;
|
||||
|
||||
/* initialize */
|
||||
candidate_list = pqueue_create();
|
||||
candidate_list->cmp = ospf6_vertex_cmp;
|
||||
@ -509,139 +507,63 @@ void ospf6_spf_calculation(u_int32_t router_id,
|
||||
&& ospf6_router_is_stub_router(v->lsa)))
|
||||
continue;
|
||||
|
||||
if (VERTEX_IS_TYPE(ROUTER, v)) {
|
||||
/* First fetch root Router LSAs from lsdb_self */
|
||||
if (v->lsa == self_rtr_lsa)
|
||||
lsdb = oa->lsdb_self;
|
||||
else
|
||||
lsdb = v->area->lsdb;
|
||||
/* For each LS description in the just-added vertex V's LSA */
|
||||
size = (VERTEX_IS_TYPE(ROUTER, v)
|
||||
? sizeof(struct ospf6_router_lsdesc)
|
||||
: sizeof(struct ospf6_network_lsdesc));
|
||||
for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4;
|
||||
lsdesc + size <= OSPF6_LSA_END(v->lsa->header);
|
||||
lsdesc += size) {
|
||||
lsa = ospf6_lsdesc_lsa(lsdesc, v);
|
||||
if (lsa == NULL)
|
||||
continue;
|
||||
|
||||
/* Iterating multiple ROUTER LSAs from same adv router
|
||||
* with different Link State ID */
|
||||
end = ospf6_lsdb_head(lsdb, 2,
|
||||
htons(OSPF6_LSTYPE_ROUTER),
|
||||
v->lsa->header->adv_router,
|
||||
&rtr_lsa);
|
||||
while (rtr_lsa) {
|
||||
if (IS_OSPF6_DEBUG_SPF(PROCESS))
|
||||
zlog_debug("%s: Next LSA %s to process"
|
||||
,__PRETTY_FUNCTION__,
|
||||
rtr_lsa->name);
|
||||
size = sizeof(struct ospf6_router_lsdesc);
|
||||
/* For each LS description in the just-added vertex V's LSA */
|
||||
for (lsdesc = OSPF6_LSA_HEADER_END(
|
||||
rtr_lsa->header) + 4;
|
||||
lsdesc + size <= OSPF6_LSA_END(
|
||||
rtr_lsa->header);
|
||||
lsdesc += size) {
|
||||
lsa = ospf6_lsdesc_lsa(lsdesc, v,
|
||||
rtr_lsa->header->id);
|
||||
if (lsa == NULL)
|
||||
continue;
|
||||
if (OSPF6_LSA_IS_MAXAGE(lsa))
|
||||
continue;
|
||||
|
||||
if (OSPF6_LSA_IS_MAXAGE(lsa))
|
||||
continue;
|
||||
if (!ospf6_lsdesc_backlink(lsa, lsdesc, v))
|
||||
continue;
|
||||
|
||||
if (!ospf6_lsdesc_backlink(lsa,
|
||||
lsdesc, v))
|
||||
continue;
|
||||
|
||||
w = ospf6_vertex_create(lsa);
|
||||
w->area = oa;
|
||||
w->parent = v;
|
||||
w->link_id = rtr_lsa->header->id;
|
||||
|
||||
if (VERTEX_IS_TYPE(ROUTER, v)) {
|
||||
w->cost = v->cost
|
||||
+ ROUTER_LSDESC_GET_METRIC(lsdesc);
|
||||
w->hops =
|
||||
v->hops
|
||||
+ (VERTEX_IS_TYPE(NETWORK, w)
|
||||
? 0 : 1);
|
||||
} else /* NETWORK */ {
|
||||
w->cost = v->cost;
|
||||
w->hops = v->hops + 1;
|
||||
}
|
||||
|
||||
/* nexthop calculation */
|
||||
if (w->hops == 0)
|
||||
ospf6_add_nexthop(w->nh_list,
|
||||
ROUTER_LSDESC_GET_IFID(lsdesc)
|
||||
, NULL);
|
||||
else if (w->hops == 1 && v->hops == 0)
|
||||
ospf6_nexthop_calc(w, v, lsdesc);
|
||||
else {
|
||||
ospf6_copy_nexthops(w->nh_list,
|
||||
v->nh_list);
|
||||
}
|
||||
|
||||
/* add new candidate to the candidate_list */
|
||||
if (IS_OSPF6_DEBUG_SPF(PROCESS))
|
||||
zlog_debug(
|
||||
" New candidate: %s hops %d cost %d",
|
||||
w->name, w->hops,
|
||||
w->cost);
|
||||
pqueue_enqueue(w, candidate_list);
|
||||
}
|
||||
/* Fetch next Link state ID Router LSA */
|
||||
rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
|
||||
}
|
||||
} else {
|
||||
/* For each LS description in the just-added vertex V's LSA */
|
||||
size = (VERTEX_IS_TYPE(ROUTER, v)
|
||||
? sizeof(struct ospf6_router_lsdesc)
|
||||
: sizeof(struct ospf6_network_lsdesc));
|
||||
for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4;
|
||||
lsdesc + size <= OSPF6_LSA_END(v->lsa->header);
|
||||
lsdesc += size) {
|
||||
lsa = ospf6_lsdesc_lsa(lsdesc, v, v->link_id);
|
||||
if (lsa == NULL)
|
||||
continue;
|
||||
|
||||
if (OSPF6_LSA_IS_MAXAGE(lsa))
|
||||
continue;
|
||||
|
||||
if (!ospf6_lsdesc_backlink(lsa, lsdesc, v))
|
||||
continue;
|
||||
|
||||
w = ospf6_vertex_create(lsa);
|
||||
w->area = oa;
|
||||
w->parent = v;
|
||||
if (VERTEX_IS_TYPE(ROUTER, v)) {
|
||||
w->cost = v->cost
|
||||
w = ospf6_vertex_create(lsa);
|
||||
w->area = oa;
|
||||
w->parent = v;
|
||||
if (VERTEX_IS_TYPE(ROUTER, v)) {
|
||||
w->cost = v->cost
|
||||
+ ROUTER_LSDESC_GET_METRIC(lsdesc);
|
||||
w->hops =
|
||||
v->hops
|
||||
+ (VERTEX_IS_TYPE(NETWORK, w) ?
|
||||
0 : 1);
|
||||
} else /* NETWORK */ {
|
||||
w->cost = v->cost;
|
||||
w->hops = v->hops + 1;
|
||||
}
|
||||
w->hops =
|
||||
v->hops
|
||||
+ (VERTEX_IS_TYPE(NETWORK, w) ? 0 : 1);
|
||||
} else {
|
||||
/* NETWORK */
|
||||
w->cost = v->cost;
|
||||
w->hops = v->hops + 1;
|
||||
}
|
||||
|
||||
/* nexthop calculation */
|
||||
if (w->hops == 0)
|
||||
ospf6_add_nexthop(w->nh_list,
|
||||
/* nexthop calculation */
|
||||
if (w->hops == 0)
|
||||
ospf6_add_nexthop(
|
||||
w->nh_list,
|
||||
ROUTER_LSDESC_GET_IFID(lsdesc), NULL);
|
||||
else if (w->hops == 1 && v->hops == 0)
|
||||
ospf6_nexthop_calc(w, v, lsdesc);
|
||||
else {
|
||||
ospf6_copy_nexthops(w->nh_list,
|
||||
v->nh_list);
|
||||
}
|
||||
else if (w->hops == 1 && v->hops == 0)
|
||||
ospf6_nexthop_calc(w, v, lsdesc);
|
||||
else
|
||||
ospf6_copy_nexthops(w->nh_list, v->nh_list);
|
||||
|
||||
/* add new candidate to the candidate_list */
|
||||
if (IS_OSPF6_DEBUG_SPF(PROCESS))
|
||||
zlog_debug(
|
||||
|
||||
/* add new candidate to the candidate_list */
|
||||
if (IS_OSPF6_DEBUG_SPF(PROCESS))
|
||||
zlog_debug(
|
||||
" New candidate: %s hops %d cost %d",
|
||||
w->name, w->hops, w->cost);
|
||||
pqueue_enqueue(w, candidate_list);
|
||||
}
|
||||
pqueue_enqueue(w, candidate_list);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pqueue_delete(candidate_list);
|
||||
|
||||
ospf6_remove_temp_router_lsa(oa);
|
||||
|
||||
oa->spf_calculation++;
|
||||
}
|
||||
|
||||
@ -1028,3 +950,153 @@ void ospf6_spf_init(void)
|
||||
install_element(OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
|
||||
install_element(OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);
|
||||
}
|
||||
|
||||
/* Create Aggregated Large Router-LSA from multiple Link-State IDs
|
||||
* RFC 5340 A 4.3:
|
||||
* When more than one router-LSA is received from a single router,
|
||||
* the links are processed as if concatenated into a single LSA.*/
|
||||
struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area,
|
||||
struct ospf6_lsdb *lsdb,
|
||||
uint32_t adv_router)
|
||||
{
|
||||
struct ospf6_lsa *lsa = NULL;
|
||||
struct ospf6_lsa *rtr_lsa = NULL;
|
||||
struct ospf6_lsa_header *lsa_header = NULL;
|
||||
uint8_t *new_header = NULL;
|
||||
const struct route_node *end = NULL;
|
||||
uint16_t lsa_length, total_lsa_length = 0, num_lsa = 0;
|
||||
u_int16_t type = 0;
|
||||
char ifbuf[16];
|
||||
uint32_t interface_id;
|
||||
caddr_t lsd;
|
||||
|
||||
lsa_length = sizeof(struct ospf6_lsa_header) +
|
||||
sizeof(struct ospf6_router_lsa);
|
||||
total_lsa_length = lsa_length;
|
||||
type = htons(OSPF6_LSTYPE_ROUTER);
|
||||
|
||||
/* First check Aggregated LSA formed earlier in Cache */
|
||||
lsa = ospf6_lsdb_lookup(type, htonl(0), adv_router,
|
||||
area->temp_router_lsa_lsdb);
|
||||
if (lsa)
|
||||
return lsa;
|
||||
|
||||
inet_ntop(AF_INET, &adv_router, ifbuf, sizeof(ifbuf));
|
||||
|
||||
/* Determine total LSA length from all link state ids */
|
||||
end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa);
|
||||
while (rtr_lsa) {
|
||||
lsa = rtr_lsa;
|
||||
if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) {
|
||||
rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
|
||||
continue;
|
||||
}
|
||||
lsa_header = (struct ospf6_lsa_header *) rtr_lsa->header;
|
||||
total_lsa_length += (ntohs(lsa_header->length)
|
||||
- lsa_length);
|
||||
num_lsa++;
|
||||
rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
|
||||
}
|
||||
if (IS_OSPF6_DEBUG_SPF(PROCESS))
|
||||
zlog_debug("%s: adv_router %s num_lsa %u to convert.",
|
||||
__PRETTY_FUNCTION__, ifbuf, num_lsa);
|
||||
if (num_lsa == 1)
|
||||
return lsa;
|
||||
|
||||
if (num_lsa == 0) {
|
||||
if (IS_OSPF6_DEBUG_SPF(PROCESS))
|
||||
zlog_debug("%s: adv_router %s not found in LSDB.",
|
||||
__PRETTY_FUNCTION__, ifbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate memory for this LSA */
|
||||
new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, total_lsa_length);
|
||||
if (!new_header)
|
||||
return NULL;
|
||||
|
||||
/* LSA information structure */
|
||||
lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA,
|
||||
sizeof(struct ospf6_lsa));
|
||||
if (!lsa) {
|
||||
free(new_header);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lsa->header = (struct ospf6_lsa_header *)new_header;
|
||||
|
||||
lsa->lsdb = area->temp_router_lsa_lsdb;
|
||||
|
||||
/* Fill Larger LSA Payload */
|
||||
end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa);
|
||||
if (rtr_lsa) {
|
||||
if (!OSPF6_LSA_IS_MAXAGE(rtr_lsa)) {
|
||||
/* Append first Link State ID LSA */
|
||||
lsa_header = (struct ospf6_lsa_header *)rtr_lsa->header;
|
||||
memcpy(new_header, lsa_header,
|
||||
ntohs(lsa_header->length));
|
||||
/* Assign new lsa length as aggregated length. */
|
||||
((struct ospf6_lsa_header *)new_header)->length =
|
||||
htons(total_lsa_length);
|
||||
new_header += ntohs(lsa_header->length);
|
||||
num_lsa--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print LSA Name */
|
||||
ospf6_lsa_printbuf(lsa, lsa->name, sizeof(lsa->name));
|
||||
|
||||
rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
|
||||
while (rtr_lsa) {
|
||||
if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) {
|
||||
rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
|
||||
lsd = OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4;
|
||||
interface_id = ROUTER_LSDESC_GET_IFID(lsd);
|
||||
inet_ntop(AF_INET, &interface_id, ifbuf, sizeof(ifbuf));
|
||||
zlog_debug("%s: Next Router LSA %s to aggreat with len %u interface_id %s",
|
||||
__PRETTY_FUNCTION__, rtr_lsa->name,
|
||||
ntohs(lsa_header->length), ifbuf);
|
||||
}
|
||||
|
||||
/* Append Next Link State ID LSA */
|
||||
lsa_header = (struct ospf6_lsa_header *) rtr_lsa->header;
|
||||
memcpy(new_header, (OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4),
|
||||
(ntohs(lsa_header->length) - lsa_length));
|
||||
new_header += (ntohs(lsa_header->length) - lsa_length);
|
||||
num_lsa--;
|
||||
|
||||
rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
|
||||
}
|
||||
|
||||
/* Calculate birth of this lsa */
|
||||
ospf6_lsa_age_set(lsa);
|
||||
|
||||
/* Store Aggregated LSA into area temp lsdb */
|
||||
ospf6_lsdb_add(lsa, area->temp_router_lsa_lsdb);
|
||||
|
||||
if (IS_OSPF6_DEBUG_SPF(PROCESS))
|
||||
zlog_debug("%s: LSA %s id %u type 0%x len %u num_lsa %u",
|
||||
__PRETTY_FUNCTION__, lsa->name,
|
||||
ntohl(lsa->header->id), ntohs(lsa->header->type),
|
||||
ntohs(lsa->header->length), num_lsa);
|
||||
|
||||
return lsa;
|
||||
}
|
||||
|
||||
void ospf6_remove_temp_router_lsa(struct ospf6_area *area)
|
||||
{
|
||||
struct ospf6_lsa *lsa = NULL;
|
||||
|
||||
for (ALL_LSDB(area->temp_router_lsa_lsdb, lsa)) {
|
||||
if (IS_OSPF6_DEBUG_SPF(PROCESS))
|
||||
zlog_debug("%s Remove LSA %s lsa->lock %u lsdb count %u",
|
||||
__PRETTY_FUNCTION__,
|
||||
lsa->name, lsa->lock,
|
||||
area->temp_router_lsa_lsdb->count);
|
||||
ospf6_lsdb_remove(lsa, area->temp_router_lsa_lsdb);
|
||||
}
|
||||
}
|
||||
|
@ -149,5 +149,9 @@ extern int config_write_ospf6_debug_spf(struct vty *vty);
|
||||
extern void install_element_ospf6_debug_spf(void);
|
||||
extern void ospf6_spf_init(void);
|
||||
extern void ospf6_spf_reason_string(unsigned int reason, char *buf, int size);
|
||||
extern struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area,
|
||||
struct ospf6_lsdb *lsdb,
|
||||
uint32_t adv_router);
|
||||
extern void ospf6_remove_temp_router_lsa(struct ospf6_area *area);
|
||||
|
||||
#endif /* OSPF6_SPF_H */
|
||||
|
@ -95,6 +95,13 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route)
|
||||
|
||||
static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
|
||||
{
|
||||
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||
char buf[PREFIX2STR_BUFFER];
|
||||
|
||||
prefix2str(&route->prefix, buf, sizeof(buf));
|
||||
zlog_debug("%s: brouter %s add with nh count %u",
|
||||
__PRETTY_FUNCTION__, buf, listcount(route->nh_list));
|
||||
}
|
||||
ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
|
||||
ospf6_asbr_lsentry_add(route);
|
||||
ospf6_abr_originate_summary(route);
|
||||
@ -102,6 +109,13 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
|
||||
|
||||
static void ospf6_top_brouter_hook_remove(struct ospf6_route *route)
|
||||
{
|
||||
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
|
||||
char buf[PREFIX2STR_BUFFER];
|
||||
|
||||
prefix2str(&route->prefix, buf, sizeof(buf));
|
||||
zlog_debug("%s: brouter %s del with nh count %u",
|
||||
__PRETTY_FUNCTION__, buf, listcount(route->nh_list));
|
||||
}
|
||||
route->flag |= OSPF6_ROUTE_REMOVE;
|
||||
ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
|
||||
ospf6_asbr_lsentry_remove(route);
|
||||
|
@ -337,6 +337,7 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request)
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_OSPF6;
|
||||
api.safi = SAFI_UNICAST;
|
||||
api.prefix = *dest;
|
||||
@ -387,6 +388,7 @@ void ospf6_zebra_add_discard(struct ospf6_route *request)
|
||||
if (!CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_OSPF6;
|
||||
api.safi = SAFI_UNICAST;
|
||||
api.prefix = *dest;
|
||||
@ -420,6 +422,7 @@ void ospf6_zebra_delete_discard(struct ospf6_route *request)
|
||||
if (CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_OSPF6;
|
||||
api.safi = SAFI_UNICAST;
|
||||
api.prefix = *dest;
|
||||
|
@ -360,6 +360,49 @@ DEFUN (show_ipv6_ospf6_database_router,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_HIDDEN (show_ipv6_ospf6_database_aggr_router,
|
||||
show_ipv6_ospf6_database_aggr_router_cmd,
|
||||
"show ipv6 ospf6 database aggr adv-router A.B.C.D",
|
||||
SHOW_STR
|
||||
IPV6_STR
|
||||
OSPF6_STR
|
||||
"Display Link state database\n"
|
||||
"Aggregated Router LSA\n"
|
||||
"Search by Advertising Router\n"
|
||||
"Specify Advertising Router as IPv4 address notation\n")
|
||||
{
|
||||
int level = OSPF6_LSDB_SHOW_LEVEL_DETAIL;
|
||||
uint16_t type = htons(OSPF6_LSTYPE_ROUTER);
|
||||
int idx_ipv4 = 6;
|
||||
struct listnode *i;
|
||||
struct ospf6 *o = ospf6;
|
||||
struct ospf6_area *oa;
|
||||
struct ospf6_lsdb *lsdb;
|
||||
uint32_t adv_router = 0;
|
||||
|
||||
inet_pton(AF_INET, argv[idx_ipv4]->arg, &adv_router);
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(o->area_list, i, oa)) {
|
||||
if (adv_router == o->router_id)
|
||||
lsdb = oa->lsdb_self;
|
||||
else
|
||||
lsdb = oa->lsdb;
|
||||
if (ospf6_create_single_router_lsa(oa, lsdb,
|
||||
adv_router) == NULL) {
|
||||
vty_out(vty, "Adv router is not found in LSDB.");
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
ospf6_lsdb_show(vty, level, &type, NULL, NULL,
|
||||
oa->temp_router_lsa_lsdb);
|
||||
/* Remove the temp cache */
|
||||
ospf6_remove_temp_router_lsa(oa);
|
||||
}
|
||||
|
||||
vty_out(vty, "\n");
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_ipv6_ospf6_database_type_id,
|
||||
show_ipv6_ospf6_database_type_id_cmd,
|
||||
"show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> linkstate-id A.B.C.D [<detail|dump|internal>]",
|
||||
@ -1219,6 +1262,7 @@ void ospf6_init(void)
|
||||
install_element(
|
||||
VIEW_NODE,
|
||||
&show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd);
|
||||
install_element(VIEW_NODE, &show_ipv6_ospf6_database_aggr_router_cmd);
|
||||
|
||||
/* Make ospf protocol socket. */
|
||||
ospf6_serv_sock();
|
||||
|
@ -327,8 +327,7 @@ static int ospf_abr_nssa_am_elected(struct ospf_area *area)
|
||||
struct router_lsa *rlsa;
|
||||
struct in_addr *best = NULL;
|
||||
|
||||
LSDB_LOOP(ROUTER_LSDB(area), rn, lsa)
|
||||
{
|
||||
LSDB_LOOP (ROUTER_LSDB(area), rn, lsa) {
|
||||
/* sanity checks */
|
||||
if (!lsa || (lsa->data->type != OSPF_ROUTER_LSA)
|
||||
|| IS_LSA_SELF(lsa))
|
||||
@ -978,7 +977,7 @@ static void ospf_abr_process_nssa_translates(struct ospf *ospf)
|
||||
inet_ntoa(area->area_id));
|
||||
|
||||
LSDB_LOOP(NSSA_LSDB(area), rn, lsa)
|
||||
ospf_abr_translate_nssa(area, lsa);
|
||||
ospf_abr_translate_nssa(area, lsa);
|
||||
}
|
||||
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
@ -1325,14 +1324,14 @@ ospf_abr_unapprove_translates(struct ospf *ospf) /* For NSSA Translations */
|
||||
and we would want to flush any residuals anyway */
|
||||
|
||||
LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
|
||||
if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) {
|
||||
UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED);
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
zlog_debug(
|
||||
"ospf_abr_unapprove_translates(): "
|
||||
"approved unset on link id %s",
|
||||
inet_ntoa(lsa->data->id));
|
||||
}
|
||||
if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) {
|
||||
UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED);
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
zlog_debug(
|
||||
"ospf_abr_unapprove_translates(): "
|
||||
"approved unset on link id %s",
|
||||
inet_ntoa(lsa->data->id));
|
||||
}
|
||||
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
zlog_debug("ospf_abr_unapprove_translates(): Stop");
|
||||
@ -1355,24 +1354,24 @@ static void ospf_abr_unapprove_summaries(struct ospf *ospf)
|
||||
"considering area %s",
|
||||
inet_ntoa(area->area_id));
|
||||
LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
|
||||
if (ospf_lsa_is_self_originated(ospf, lsa)) {
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug(
|
||||
"ospf_abr_unapprove_summaries(): "
|
||||
"approved unset on summary link id %s",
|
||||
inet_ntoa(lsa->data->id));
|
||||
UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED);
|
||||
}
|
||||
if (ospf_lsa_is_self_originated(ospf, lsa)) {
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug(
|
||||
"ospf_abr_unapprove_summaries(): "
|
||||
"approved unset on summary link id %s",
|
||||
inet_ntoa(lsa->data->id));
|
||||
UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED);
|
||||
}
|
||||
|
||||
LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
|
||||
if (ospf_lsa_is_self_originated(ospf, lsa)) {
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug(
|
||||
"ospf_abr_unapprove_summaries(): "
|
||||
"approved unset on asbr-summary link id %s",
|
||||
inet_ntoa(lsa->data->id));
|
||||
UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED);
|
||||
}
|
||||
if (ospf_lsa_is_self_originated(ospf, lsa)) {
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug(
|
||||
"ospf_abr_unapprove_summaries(): "
|
||||
"approved unset on asbr-summary link id %s",
|
||||
inet_ntoa(lsa->data->id));
|
||||
UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED);
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
@ -1633,7 +1632,7 @@ static void ospf_abr_remove_unapproved_translates(struct ospf *ospf)
|
||||
zlog_debug("ospf_abr_remove_unapproved_translates(): Start");
|
||||
|
||||
LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
|
||||
ospf_abr_remove_unapproved_translates_apply(ospf, lsa);
|
||||
ospf_abr_remove_unapproved_translates_apply(ospf, lsa);
|
||||
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
zlog_debug("ospf_abr_remove_unapproved_translates(): Stop");
|
||||
@ -1657,14 +1656,14 @@ static void ospf_abr_remove_unapproved_summaries(struct ospf *ospf)
|
||||
inet_ntoa(area->area_id));
|
||||
|
||||
LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
|
||||
if (ospf_lsa_is_self_originated(ospf, lsa))
|
||||
if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED))
|
||||
ospf_lsa_flush_area(lsa, area);
|
||||
if (ospf_lsa_is_self_originated(ospf, lsa))
|
||||
if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED))
|
||||
ospf_lsa_flush_area(lsa, area);
|
||||
|
||||
LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
|
||||
if (ospf_lsa_is_self_originated(ospf, lsa))
|
||||
if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED))
|
||||
ospf_lsa_flush_area(lsa, area);
|
||||
if (ospf_lsa_is_self_originated(ospf, lsa))
|
||||
if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED))
|
||||
ospf_lsa_flush_area(lsa, area);
|
||||
}
|
||||
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
|
@ -1313,22 +1313,28 @@ int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver *apiserv,
|
||||
/* Check msg type. */
|
||||
if (mask & Power2[OSPF_ROUTER_LSA])
|
||||
LSDB_LOOP(ROUTER_LSDB(area), rn, lsa)
|
||||
apiserver_sync_callback(lsa, (void *)¶m, seqnum);
|
||||
apiserver_sync_callback(
|
||||
lsa, (void *)¶m, seqnum);
|
||||
if (mask & Power2[OSPF_NETWORK_LSA])
|
||||
LSDB_LOOP(NETWORK_LSDB(area), rn, lsa)
|
||||
apiserver_sync_callback(lsa, (void *)¶m, seqnum);
|
||||
apiserver_sync_callback(
|
||||
lsa, (void *)¶m, seqnum);
|
||||
if (mask & Power2[OSPF_SUMMARY_LSA])
|
||||
LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
|
||||
apiserver_sync_callback(lsa, (void *)¶m, seqnum);
|
||||
apiserver_sync_callback(
|
||||
lsa, (void *)¶m, seqnum);
|
||||
if (mask & Power2[OSPF_ASBR_SUMMARY_LSA])
|
||||
LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
|
||||
apiserver_sync_callback(lsa, (void *)¶m, seqnum);
|
||||
apiserver_sync_callback(
|
||||
lsa, (void *)¶m, seqnum);
|
||||
if (mask & Power2[OSPF_OPAQUE_LINK_LSA])
|
||||
LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
|
||||
apiserver_sync_callback(lsa, (void *)¶m, seqnum);
|
||||
apiserver_sync_callback(
|
||||
lsa, (void *)¶m, seqnum);
|
||||
if (mask & Power2[OSPF_OPAQUE_AREA_LSA])
|
||||
LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
|
||||
apiserver_sync_callback(lsa, (void *)¶m, seqnum);
|
||||
apiserver_sync_callback(
|
||||
lsa, (void *)¶m, seqnum);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1336,14 +1342,16 @@ int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver *apiserv,
|
||||
if (ospf->lsdb) {
|
||||
if (mask & Power2[OSPF_AS_EXTERNAL_LSA])
|
||||
LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
|
||||
apiserver_sync_callback(lsa, (void *)¶m, seqnum);
|
||||
apiserver_sync_callback(lsa, (void *)¶m,
|
||||
seqnum);
|
||||
}
|
||||
|
||||
/* For AS-external opaque LSAs */
|
||||
if (ospf->lsdb) {
|
||||
if (mask & Power2[OSPF_OPAQUE_AS_LSA])
|
||||
LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa)
|
||||
apiserver_sync_callback(lsa, (void *)¶m, seqnum);
|
||||
apiserver_sync_callback(lsa, (void *)¶m,
|
||||
seqnum);
|
||||
}
|
||||
|
||||
/* Send a reply back to client with return code */
|
||||
@ -1945,16 +1953,19 @@ void ospf_apiserver_flush_opaque_lsa(struct ospf_apiserver *apiserv,
|
||||
case OSPF_OPAQUE_LINK_LSA:
|
||||
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area))
|
||||
LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
|
||||
apiserver_flush_opaque_type_callback(lsa, (void *)¶m, 0);
|
||||
apiserver_flush_opaque_type_callback(
|
||||
lsa, (void *)¶m, 0);
|
||||
break;
|
||||
case OSPF_OPAQUE_AREA_LSA:
|
||||
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area))
|
||||
LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
|
||||
apiserver_flush_opaque_type_callback(lsa, (void *)¶m, 0);
|
||||
apiserver_flush_opaque_type_callback(
|
||||
lsa, (void *)¶m, 0);
|
||||
break;
|
||||
case OSPF_OPAQUE_AS_LSA:
|
||||
LSDB_LOOP(OPAQUE_LINK_LSDB(ospf), rn, lsa)
|
||||
apiserver_flush_opaque_type_callback(lsa, (void *)¶m, 0);
|
||||
apiserver_flush_opaque_type_callback(lsa,
|
||||
(void *)¶m, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -649,7 +649,7 @@ static int ospf_ase_calculate_timer(struct thread *t)
|
||||
|
||||
/* Calculate external route for each AS-external-LSA */
|
||||
LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
|
||||
ospf_ase_calculate_route(ospf, lsa);
|
||||
ospf_ase_calculate_route(ospf, lsa);
|
||||
|
||||
/* This version simple adds to the table all NSSA areas */
|
||||
if (ospf->anyNSSA)
|
||||
@ -661,11 +661,12 @@ static int ospf_ase_calculate_timer(struct thread *t)
|
||||
|
||||
if (area->external_routing == OSPF_AREA_NSSA)
|
||||
LSDB_LOOP(NSSA_LSDB(area), rn, lsa)
|
||||
ospf_ase_calculate_route(ospf, lsa);
|
||||
ospf_ase_calculate_route(ospf,
|
||||
lsa);
|
||||
}
|
||||
/* kevinm: And add the NSSA routes in ospf_top */
|
||||
LSDB_LOOP(NSSA_LSDB(ospf), rn, lsa)
|
||||
ospf_ase_calculate_route(ospf, lsa);
|
||||
ospf_ase_calculate_route(ospf, lsa);
|
||||
|
||||
/* Compare old and new external routing table and install the
|
||||
difference info zebra/kernel */
|
||||
|
@ -283,7 +283,7 @@ static void ospf_examine_summaries(struct ospf_area *area,
|
||||
struct route_node *rn;
|
||||
|
||||
LSDB_LOOP(lsdb_rt, rn, lsa)
|
||||
process_summary_lsa(area, rt, rtrs, lsa);
|
||||
process_summary_lsa(area, rt, rtrs, lsa);
|
||||
}
|
||||
|
||||
int ospf_area_is_transit(struct ospf_area *area)
|
||||
@ -583,7 +583,7 @@ static void ospf_examine_transit_summaries(struct ospf_area *area,
|
||||
struct route_node *rn;
|
||||
|
||||
LSDB_LOOP(lsdb_rt, rn, lsa)
|
||||
process_transit_summary_lsa(area, rt, rtrs, lsa);
|
||||
process_transit_summary_lsa(area, rt, rtrs, lsa);
|
||||
}
|
||||
|
||||
void ospf_ia_routing(struct ospf *ospf, struct route_table *rt,
|
||||
|
@ -51,6 +51,28 @@ DEFINE_QOBJ_TYPE(ospf_interface)
|
||||
DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd))
|
||||
DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd))
|
||||
|
||||
int ospf_interface_neighbor_count(struct ospf_interface *oi)
|
||||
{
|
||||
int count = 0;
|
||||
struct route_node *rn;
|
||||
struct ospf_neighbor *nbr = NULL;
|
||||
|
||||
for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
|
||||
nbr = rn->info;
|
||||
if (nbr) {
|
||||
/* Do not show myself. */
|
||||
if (nbr == oi->nbr_self)
|
||||
continue;
|
||||
/* Down state is not shown. */
|
||||
if (nbr->state == NSM_Down)
|
||||
continue;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int ospf_if_get_output_cost(struct ospf_interface *oi)
|
||||
{
|
||||
/* If all else fails, use default OSPF cost */
|
||||
|
@ -314,8 +314,8 @@ extern struct crypt_key *ospf_crypt_key_lookup(struct list *, u_char);
|
||||
extern struct crypt_key *ospf_crypt_key_new(void);
|
||||
extern void ospf_crypt_key_add(struct list *, struct crypt_key *);
|
||||
extern int ospf_crypt_key_delete(struct list *, u_char);
|
||||
|
||||
extern u_char ospf_default_iftype(struct interface *ifp);
|
||||
extern int ospf_interface_neighbor_count(struct ospf_interface *oi);
|
||||
|
||||
/* Set all multicast memberships appropriately based on the type and
|
||||
state of the interface. */
|
||||
|
@ -1872,8 +1872,7 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf,
|
||||
if (area->external_routing != OSPF_AREA_NSSA && !type7)
|
||||
continue;
|
||||
|
||||
LSDB_LOOP(NSSA_LSDB(area), rn, lsa)
|
||||
{
|
||||
LSDB_LOOP (NSSA_LSDB(area), rn, lsa) {
|
||||
if (lsa->data->id.s_addr
|
||||
== type5->data->id.s_addr) {
|
||||
type7 = lsa;
|
||||
@ -3007,27 +3006,27 @@ int ospf_lsa_maxage_walker(struct thread *thread)
|
||||
|
||||
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
|
||||
LSDB_LOOP(ROUTER_LSDB(area), rn, lsa)
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
LSDB_LOOP(NETWORK_LSDB(area), rn, lsa)
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
LSDB_LOOP(NSSA_LSDB(area), rn, lsa)
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
}
|
||||
|
||||
/* for AS-external-LSAs. */
|
||||
if (ospf->lsdb) {
|
||||
LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa)
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
ospf_lsa_maxage_walker_remover(ospf, lsa);
|
||||
}
|
||||
|
||||
OSPF_TIMER_ON(ospf->t_maxage_walker, ospf_lsa_maxage_walker,
|
||||
@ -3350,20 +3349,20 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf)
|
||||
}
|
||||
|
||||
LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
}
|
||||
|
||||
if (need_to_flush_ase) {
|
||||
LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa)
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -280,37 +280,37 @@ static int nsm_negotiation_done(struct ospf_neighbor *nbr)
|
||||
ospf_proactively_arp(nbr);
|
||||
|
||||
LSDB_LOOP(ROUTER_LSDB(area), rn, lsa)
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
LSDB_LOOP(NETWORK_LSDB(area), rn, lsa)
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
|
||||
/* Process only if the neighbor is opaque capable. */
|
||||
if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)) {
|
||||
LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(nbr->options, OSPF_OPTION_NP)) {
|
||||
LSDB_LOOP(NSSA_LSDB(area), rn, lsa)
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
}
|
||||
|
||||
if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
|
||||
&& area->external_routing == OSPF_AREA_DEFAULT)
|
||||
LSDB_LOOP(EXTERNAL_LSDB(nbr->oi->ospf), rn, lsa)
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
|
||||
if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)
|
||||
&& (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
|
||||
&& area->external_routing == OSPF_AREA_DEFAULT))
|
||||
LSDB_LOOP(OPAQUE_AS_LSDB(nbr->oi->ospf), rn, lsa)
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
ospf_db_summary_add(nbr, lsa);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -607,30 +607,6 @@ static void free_opaque_info_per_type(void *val)
|
||||
ospf_opaque_lsa_flush_schedule(lsa);
|
||||
}
|
||||
|
||||
/* Remove "oipt" from its owner's self-originated LSA list. */
|
||||
switch (oipt->lsa_type) {
|
||||
case OSPF_OPAQUE_LINK_LSA: {
|
||||
struct ospf_interface *oi =
|
||||
(struct ospf_interface *)(oipt->owner);
|
||||
listnode_delete(oi->opaque_lsa_self, oipt);
|
||||
break;
|
||||
}
|
||||
case OSPF_OPAQUE_AREA_LSA: {
|
||||
struct ospf_area *area = (struct ospf_area *)(oipt->owner);
|
||||
listnode_delete(area->opaque_lsa_self, oipt);
|
||||
break;
|
||||
}
|
||||
case OSPF_OPAQUE_AS_LSA: {
|
||||
struct ospf *top = (struct ospf *)(oipt->owner);
|
||||
listnode_delete(top->opaque_lsa_self, oipt);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
zlog_warn("free_opaque_info_per_type: Unexpected LSA-type(%u)",
|
||||
oipt->lsa_type);
|
||||
break; /* This case may not exist. */
|
||||
}
|
||||
|
||||
OSPF_TIMER_OFF(oipt->t_opaque_lsa_self);
|
||||
list_delete_and_null(&oipt->id_list);
|
||||
XFREE(MTYPE_OPAQUE_INFO_PER_TYPE, oipt);
|
||||
|
100
ospfd/ospf_vty.c
100
ospfd/ospf_vty.c
@ -218,7 +218,7 @@ DEFUN_NOSH (router_ospf,
|
||||
if (ospf->vrf_id != VRF_UNKNOWN)
|
||||
ospf->oi_running = 1;
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("Config command 'router ospf %d' received, vrf %s id %d oi_running %u",
|
||||
zlog_debug("Config command 'router ospf %d' received, vrf %s id %u oi_running %u",
|
||||
instance, ospf->name ? ospf->name : "NIL",
|
||||
ospf->vrf_id, ospf->oi_running);
|
||||
VTY_PUSH_CONTEXT(OSPF_NODE, ospf);
|
||||
@ -3693,14 +3693,15 @@ static int show_ip_ospf_interface_common(struct vty *vty, struct ospf *ospf,
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
|
||||
json_object *json_vrf = NULL;
|
||||
json_object *json_interface_sub = NULL;
|
||||
json_object *json_vrf = NULL, *json_intf_array = NULL;
|
||||
json_object *json_interface_sub = NULL, *json_interface = NULL;
|
||||
|
||||
if (use_json) {
|
||||
if (use_vrf)
|
||||
json_vrf = json_object_new_object();
|
||||
else
|
||||
json_vrf = json;
|
||||
json_intf_array = json_object_new_array();
|
||||
}
|
||||
|
||||
if (ospf->instance) {
|
||||
@ -3714,21 +3715,29 @@ static int show_ip_ospf_interface_common(struct vty *vty, struct ospf *ospf,
|
||||
ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf);
|
||||
|
||||
if (intf_name == NULL) {
|
||||
if (use_json)
|
||||
json_object_object_add(json_vrf, "interfaces",
|
||||
json_intf_array);
|
||||
/* Show All Interfaces.*/
|
||||
FOR_ALL_INTERFACES (vrf, ifp) {
|
||||
if (ospf_oi_count(ifp)) {
|
||||
if (use_json)
|
||||
if (use_json) {
|
||||
json_interface =
|
||||
json_object_new_object();
|
||||
json_interface_sub =
|
||||
json_object_new_object();
|
||||
|
||||
}
|
||||
show_ip_ospf_interface_sub(vty, ospf, ifp,
|
||||
json_interface_sub,
|
||||
use_json);
|
||||
|
||||
if (use_json)
|
||||
if (use_json) {
|
||||
json_object_array_add(json_intf_array,
|
||||
json_interface);
|
||||
json_object_object_add(
|
||||
json_vrf, ifp->name,
|
||||
json_interface, ifp->name,
|
||||
json_interface_sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -3741,15 +3750,23 @@ static int show_ip_ospf_interface_common(struct vty *vty, struct ospf *ospf,
|
||||
else
|
||||
vty_out(vty, "No such interface name\n");
|
||||
} else {
|
||||
if (use_json)
|
||||
if (use_json) {
|
||||
json_interface_sub = json_object_new_object();
|
||||
json_interface = json_object_new_object();
|
||||
json_object_object_add(json_vrf, "interfaces",
|
||||
json_intf_array);
|
||||
}
|
||||
|
||||
show_ip_ospf_interface_sub(
|
||||
vty, ospf, ifp, json_interface_sub, use_json);
|
||||
|
||||
if (use_json)
|
||||
json_object_object_add(json_vrf, ifp->name,
|
||||
if (use_json) {
|
||||
json_object_array_add(json_intf_array,
|
||||
json_interface);
|
||||
json_object_object_add(json_interface,
|
||||
ifp->name,
|
||||
json_interface_sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4283,13 +4300,15 @@ static int show_ip_ospf_neighbor_common(struct vty *vty, struct ospf *ospf,
|
||||
{
|
||||
struct ospf_interface *oi;
|
||||
struct listnode *node;
|
||||
json_object *json_vrf = NULL;
|
||||
json_object *json_vrf = NULL, *json_nbr_array = NULL;
|
||||
json_object *json_nbr_sub = NULL;
|
||||
|
||||
if (use_json) {
|
||||
if (use_vrf)
|
||||
json_vrf = json_object_new_object();
|
||||
else
|
||||
json_vrf = json;
|
||||
json_nbr_array = json_object_new_array();
|
||||
}
|
||||
|
||||
if (ospf->instance) {
|
||||
@ -4303,9 +4322,19 @@ static int show_ip_ospf_neighbor_common(struct vty *vty, struct ospf *ospf,
|
||||
ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf);
|
||||
if (!use_json)
|
||||
show_ip_ospf_neighbour_header(vty);
|
||||
else
|
||||
json_object_object_add(json_vrf, "neighbors",
|
||||
json_nbr_array);
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi))
|
||||
show_ip_ospf_neighbor_sub(vty, oi, json_vrf, use_json);
|
||||
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
|
||||
if (ospf_interface_neighbor_count(oi) == 0)
|
||||
continue;
|
||||
if (use_json) {
|
||||
json_nbr_sub = json_object_new_object();
|
||||
json_object_array_add(json_nbr_array, json_nbr_sub);
|
||||
}
|
||||
show_ip_ospf_neighbor_sub(vty, oi, json_nbr_sub, use_json);
|
||||
}
|
||||
|
||||
if (use_json) {
|
||||
if (use_vrf) {
|
||||
@ -4681,7 +4710,6 @@ static int show_ip_ospf_neighbor_int_common(struct vty *vty, struct ospf *ospf,
|
||||
|
||||
ospf_show_vrf_name(ospf, vty, json, use_vrf);
|
||||
|
||||
/*ifp = if_lookup_by_name(argv[arg_base]->arg, ospf->vrf_id);*/
|
||||
ifp = if_lookup_by_name_all_vrf(argv[arg_base]->arg);
|
||||
if (!ifp) {
|
||||
if (use_json)
|
||||
@ -6167,7 +6195,7 @@ static void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf,
|
||||
show_database_header[type]);
|
||||
|
||||
LSDB_LOOP(AREA_LSDB(area, type), rn, lsa)
|
||||
show_lsa_summary(vty, lsa, self);
|
||||
show_lsa_summary(vty, lsa, self);
|
||||
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
@ -6189,7 +6217,7 @@ static void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf,
|
||||
vty_out(vty, "%s\n", show_database_header[type]);
|
||||
|
||||
LSDB_LOOP(AS_LSDB(ospf, type), rn, lsa)
|
||||
show_lsa_summary(vty, lsa, self);
|
||||
show_lsa_summary(vty, lsa, self);
|
||||
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
@ -8099,7 +8127,7 @@ DEFUN (no_ip_ospf_area,
|
||||
|
||||
DEFUN (ospf_redistribute_source,
|
||||
ospf_redistribute_source_cmd,
|
||||
"redistribute " FRR_REDIST_STR_OSPFD " [<metric (0-16777214)|metric-type (1-2)|route-map WORD>]",
|
||||
"redistribute " FRR_REDIST_STR_OSPFD " [{metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
|
||||
REDIST_STR
|
||||
FRR_REDIST_HELP_STR_OSPFD
|
||||
"Metric for redistributed routes\n"
|
||||
@ -8132,13 +8160,15 @@ DEFUN (ospf_redistribute_source,
|
||||
if (!str2metric(argv[idx]->arg, &metric))
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
idx = 1;
|
||||
/* Get metric type. */
|
||||
else if (argv_find(argv, argc, "(1-2)", &idx)) {
|
||||
if (argv_find(argv, argc, "(1-2)", &idx)) {
|
||||
if (!str2metric_type(argv[idx]->arg, &type))
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
idx = 1;
|
||||
/* Get route-map */
|
||||
else if (argv_find(argv, argc, "WORD", &idx)) {
|
||||
if (argv_find(argv, argc, "WORD", &idx)) {
|
||||
ospf_routemap_set(red, argv[idx]->arg);
|
||||
} else
|
||||
ospf_routemap_unset(red);
|
||||
@ -8148,7 +8178,7 @@ DEFUN (ospf_redistribute_source,
|
||||
|
||||
DEFUN (no_ospf_redistribute_source,
|
||||
no_ospf_redistribute_source_cmd,
|
||||
"no redistribute " FRR_REDIST_STR_OSPFD " [<metric (0-16777214)|metric-type (1-2)|route-map WORD>]",
|
||||
"no redistribute " FRR_REDIST_STR_OSPFD " [{metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
|
||||
NO_STR
|
||||
REDIST_STR
|
||||
FRR_REDIST_HELP_STR_OSPFD
|
||||
@ -8338,7 +8368,7 @@ DEFUN (no_ospf_distribute_list_out,
|
||||
/* Default information originate. */
|
||||
DEFUN (ospf_default_information_originate,
|
||||
ospf_default_information_originate_cmd,
|
||||
"default-information originate [<always|metric (0-16777214)|metric-type (1-2)|route-map WORD>]",
|
||||
"default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
|
||||
"Control distribution of default information\n"
|
||||
"Distribute a default route\n"
|
||||
"Always advertise default route\n"
|
||||
@ -8361,18 +8391,21 @@ DEFUN (ospf_default_information_originate,
|
||||
/* Check whether "always" was specified */
|
||||
if (argv_find(argv, argc, "always", &idx))
|
||||
default_originate = DEFAULT_ORIGINATE_ALWAYS;
|
||||
idx = 1;
|
||||
/* Get metric value */
|
||||
else if (argv_find(argv, argc, "(0-16777214)", &idx)) {
|
||||
if (argv_find(argv, argc, "(0-16777214)", &idx)) {
|
||||
if (!str2metric(argv[idx]->arg, &metric))
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
idx = 1;
|
||||
/* Get metric type. */
|
||||
else if (argv_find(argv, argc, "(1-2)", &idx)) {
|
||||
if (argv_find(argv, argc, "(1-2)", &idx)) {
|
||||
if (!str2metric_type(argv[idx]->arg, &type))
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
idx = 1;
|
||||
/* Get route-map */
|
||||
else if (argv_find(argv, argc, "WORD", &idx))
|
||||
if (argv_find(argv, argc, "WORD", &idx))
|
||||
ospf_routemap_set(red, argv[idx]->arg);
|
||||
else
|
||||
ospf_routemap_unset(red);
|
||||
@ -8383,7 +8416,7 @@ DEFUN (ospf_default_information_originate,
|
||||
|
||||
DEFUN (no_ospf_default_information_originate,
|
||||
no_ospf_default_information_originate_cmd,
|
||||
"no default-information originate [<always|metric (0-16777214)|metric-type (1-2)|route-map WORD>]",
|
||||
"no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
|
||||
NO_STR
|
||||
"Control distribution of default information\n"
|
||||
"Distribute a default route\n"
|
||||
@ -9496,9 +9529,9 @@ DEFUN (show_ip_ospf_route,
|
||||
}
|
||||
|
||||
if (uj) {
|
||||
/* Keep Non-pretty format */
|
||||
vty_out(vty, "%s\n",
|
||||
json_object_to_json_string_ext(json,
|
||||
JSON_C_TO_STRING_PRETTY));
|
||||
json_object_to_json_string(json));
|
||||
json_object_free(json);
|
||||
}
|
||||
|
||||
@ -9522,9 +9555,9 @@ DEFUN (show_ip_ospf_route,
|
||||
|
||||
if (ospf) {
|
||||
ret = show_ip_ospf_route_common(vty, ospf, json, use_vrf);
|
||||
/* Keep Non-pretty format */
|
||||
if (uj)
|
||||
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
vty_out(vty, "%s\n", json_object_to_json_string(json));
|
||||
}
|
||||
|
||||
if (uj)
|
||||
@ -9583,7 +9616,7 @@ DEFUN (show_ip_ospf_vrfs,
|
||||
for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
|
||||
json_object *json_vrf = NULL;
|
||||
const char *name = NULL;
|
||||
int vrf_id_ui = 0;
|
||||
int64_t vrf_id_ui = 0;
|
||||
|
||||
count++;
|
||||
|
||||
@ -9597,7 +9630,8 @@ DEFUN (show_ip_ospf_vrfs,
|
||||
else
|
||||
name = ospf->name;
|
||||
|
||||
vrf_id_ui = (ospf->vrf_id == VRF_UNKNOWN) ? -1 : ospf->vrf_id;
|
||||
vrf_id_ui = (ospf->vrf_id == VRF_UNKNOWN) ? -1 :
|
||||
(int64_t) ospf->vrf_id;
|
||||
|
||||
if (uj) {
|
||||
json_object_int_add(json_vrf, "vrfId", vrf_id_ui);
|
||||
@ -10202,8 +10236,12 @@ static int config_write_ospf_distribute(struct vty *vty, struct ospf *ospf)
|
||||
if (red->dmetric.value >= 0)
|
||||
vty_out(vty, " metric %d",
|
||||
red->dmetric.value);
|
||||
|
||||
if (red->dmetric.type == EXTERNAL_METRIC_TYPE_1)
|
||||
vty_out(vty, " metric-type 1");
|
||||
else if (red->dmetric.type ==
|
||||
EXTERNAL_METRIC_TYPE_2)
|
||||
vty_out(vty, " metric-type 2");
|
||||
|
||||
if (ROUTEMAP_NAME(red))
|
||||
vty_out(vty, " route-map %s",
|
||||
|
@ -389,6 +389,7 @@ void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *p,
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = ospf->vrf_id;
|
||||
api.nh_vrf_id = ospf->vrf_id;
|
||||
api.type = ZEBRA_ROUTE_OSPF;
|
||||
api.instance = ospf->instance;
|
||||
api.safi = SAFI_UNICAST;
|
||||
@ -466,6 +467,7 @@ void ospf_zebra_delete(struct ospf *ospf, struct prefix_ipv4 *p,
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = ospf->vrf_id;
|
||||
api.nh_vrf_id = ospf->vrf_id;
|
||||
api.type = ZEBRA_ROUTE_OSPF;
|
||||
api.instance = ospf->instance;
|
||||
api.safi = SAFI_UNICAST;
|
||||
@ -487,6 +489,7 @@ void ospf_zebra_add_discard(struct ospf *ospf, struct prefix_ipv4 *p)
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = ospf->vrf_id;
|
||||
api.nh_vrf_id = ospf->vrf_id;
|
||||
api.type = ZEBRA_ROUTE_OSPF;
|
||||
api.instance = ospf->instance;
|
||||
api.safi = SAFI_UNICAST;
|
||||
@ -506,6 +509,7 @@ void ospf_zebra_delete_discard(struct ospf *ospf, struct prefix_ipv4 *p)
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = ospf->vrf_id;
|
||||
api.nh_vrf_id = ospf->vrf_id;
|
||||
api.type = ZEBRA_ROUTE_OSPF;
|
||||
api.instance = ospf->instance;
|
||||
api.safi = SAFI_UNICAST;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "log.h"
|
||||
#include "sockunion.h" /* for inet_aton () */
|
||||
#include "zclient.h"
|
||||
#include "routemap.h"
|
||||
#include "plist.h"
|
||||
#include "sockopt.h"
|
||||
#include "bfd.h"
|
||||
@ -159,8 +160,8 @@ void ospf_router_id_update(struct ospf *ospf)
|
||||
struct ospf_lsa *lsa;
|
||||
|
||||
LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
|
||||
if (IS_LSA_SELF(lsa))
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
if (IS_LSA_SELF(lsa))
|
||||
ospf_lsa_flush_schedule(ospf, lsa);
|
||||
}
|
||||
|
||||
ospf->router_id = router_id;
|
||||
@ -183,8 +184,7 @@ void ospf_router_id_update(struct ospf *ospf)
|
||||
struct route_node *rn;
|
||||
struct ospf_lsa *lsa;
|
||||
|
||||
LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
|
||||
{
|
||||
LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa) {
|
||||
/* AdvRouter and Router ID is the same. */
|
||||
if (IPV4_ADDR_SAME(&lsa->data->adv_router,
|
||||
&ospf->router_id)) {
|
||||
@ -241,7 +241,7 @@ static struct ospf *ospf_new(u_short instance, const char *name)
|
||||
new->name = XSTRDUP(MTYPE_OSPF_TOP, name);
|
||||
vrf = vrf_lookup_by_name(new->name);
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s: Create new ospf instance with vrf_name %s vrf_id %d",
|
||||
zlog_debug("%s: Create new ospf instance with vrf_name %s vrf_id %u",
|
||||
__PRETTY_FUNCTION__, name, new->vrf_id);
|
||||
if (vrf)
|
||||
ospf_vrf_link(new, vrf);
|
||||
@ -555,6 +555,20 @@ void ospf_terminate(void)
|
||||
for (ALL_LIST_ELEMENTS(om->ospf, node, nnode, ospf))
|
||||
ospf_finish(ospf);
|
||||
|
||||
/* Cleanup route maps */
|
||||
route_map_add_hook(NULL);
|
||||
route_map_delete_hook(NULL);
|
||||
route_map_event_hook(NULL);
|
||||
route_map_finish();
|
||||
|
||||
/* reverse prefix_list_init */
|
||||
prefix_list_add_hook(NULL);
|
||||
prefix_list_delete_hook(NULL);
|
||||
prefix_list_reset();
|
||||
|
||||
/* Cleanup vrf info */
|
||||
ospf_vrf_terminate();
|
||||
|
||||
/* Deliberately go back up, hopefully to thread scheduler, as
|
||||
* One or more ospf_finish()'s may have deferred shutdown to a timer
|
||||
* thread
|
||||
@ -693,9 +707,9 @@ static void ospf_finish_final(struct ospf *ospf)
|
||||
stream_free(ospf->ibuf);
|
||||
|
||||
LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa)
|
||||
ospf_discard_from_db(ospf, ospf->lsdb, lsa);
|
||||
ospf_discard_from_db(ospf, ospf->lsdb, lsa);
|
||||
LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
|
||||
ospf_discard_from_db(ospf, ospf->lsdb, lsa);
|
||||
ospf_discard_from_db(ospf, ospf->lsdb, lsa);
|
||||
|
||||
ospf_lsdb_delete_all(ospf->lsdb);
|
||||
ospf_lsdb_free(ospf->lsdb);
|
||||
@ -832,22 +846,21 @@ static void ospf_area_free(struct ospf_area *area)
|
||||
|
||||
/* Free LSDBs. */
|
||||
LSDB_LOOP(ROUTER_LSDB(area), rn, lsa)
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
LSDB_LOOP(NETWORK_LSDB(area), rn, lsa)
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
|
||||
LSDB_LOOP(NSSA_LSDB(area), rn, lsa)
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
|
||||
|
||||
ospf_opaque_type10_lsa_term(area);
|
||||
ospf_lsdb_delete_all(area->lsdb);
|
||||
ospf_lsdb_free(area->lsdb);
|
||||
|
||||
@ -2016,7 +2029,7 @@ void ospf_vrf_unlink(struct ospf *ospf, struct vrf *vrf)
|
||||
static int ospf_vrf_new(struct vrf *vrf)
|
||||
{
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s: VRF Created: %s(%d)", __PRETTY_FUNCTION__,
|
||||
zlog_debug("%s: VRF Created: %s(%u)", __PRETTY_FUNCTION__,
|
||||
vrf->name, vrf->vrf_id);
|
||||
|
||||
return 0;
|
||||
@ -2026,7 +2039,7 @@ static int ospf_vrf_new(struct vrf *vrf)
|
||||
static int ospf_vrf_delete(struct vrf *vrf)
|
||||
{
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s: VRF Deletion: %s(%d)", __PRETTY_FUNCTION__,
|
||||
zlog_debug("%s: VRF Deletion: %s(%u)", __PRETTY_FUNCTION__,
|
||||
vrf->name, vrf->vrf_id);
|
||||
|
||||
return 0;
|
||||
@ -2039,7 +2052,7 @@ static int ospf_vrf_enable(struct vrf *vrf)
|
||||
vrf_id_t old_vrf_id = VRF_DEFAULT;
|
||||
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s: VRF %s id %d enabled",
|
||||
zlog_debug("%s: VRF %s id %u enabled",
|
||||
__PRETTY_FUNCTION__, vrf->name, vrf->vrf_id);
|
||||
|
||||
ospf = ospf_lookup_by_name(vrf->name);
|
||||
@ -2048,7 +2061,7 @@ static int ospf_vrf_enable(struct vrf *vrf)
|
||||
/* We have instance configured, link to VRF and make it "up". */
|
||||
ospf_vrf_link(ospf, vrf);
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s: ospf linked to vrf %s vrf_id %d (old id %d)",
|
||||
zlog_debug("%s: ospf linked to vrf %s vrf_id %u (old id %u)",
|
||||
__PRETTY_FUNCTION__, vrf->name, ospf->vrf_id,
|
||||
old_vrf_id);
|
||||
|
||||
|
@ -136,7 +136,7 @@ static int pim_vrf_new(struct vrf *vrf)
|
||||
{
|
||||
struct pim_instance *pim = pim_instance_init(vrf);
|
||||
|
||||
zlog_debug("VRF Created: %s(%d)", vrf->name, vrf->vrf_id);
|
||||
zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
|
||||
if (pim == NULL) {
|
||||
zlog_err("%s %s: pim class init failure ", __FILE__,
|
||||
__PRETTY_FUNCTION__);
|
||||
@ -159,7 +159,7 @@ static int pim_vrf_delete(struct vrf *vrf)
|
||||
{
|
||||
struct pim_instance *pim = vrf->info;
|
||||
|
||||
zlog_debug("VRF Deletion: %s(%d)", vrf->name, vrf->vrf_id);
|
||||
zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id);
|
||||
|
||||
pim_ssmpingd_destroy(pim);
|
||||
pim_instance_terminate(pim);
|
||||
|
@ -47,40 +47,14 @@
|
||||
void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
|
||||
struct pim_nexthop_cache *pnc, int command)
|
||||
{
|
||||
struct stream *s;
|
||||
struct prefix *p;
|
||||
int ret;
|
||||
|
||||
/* Check socket. */
|
||||
if (!zclient || zclient->sock < 0)
|
||||
return;
|
||||
|
||||
p = &(pnc->rpf.rpf_addr);
|
||||
s = zclient->obuf;
|
||||
stream_reset(s);
|
||||
zclient_create_header(s, command, pim->vrf_id);
|
||||
/* get update for all routes for a prefix */
|
||||
stream_putc(s, 0);
|
||||
|
||||
stream_putw(s, PREFIX_FAMILY(p));
|
||||
stream_putc(s, p->prefixlen);
|
||||
switch (PREFIX_FAMILY(p)) {
|
||||
case AF_INET:
|
||||
stream_put_in_addr(s, &p->u.prefix4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
stream_put(s, &(p->u.prefix6), 16);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
ret = zclient_send_message(zclient);
|
||||
ret = zclient_send_rnh(zclient, command, p, false, pim->vrf_id);
|
||||
if (ret < 0)
|
||||
zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
|
||||
|
||||
|
||||
if (PIM_DEBUG_PIM_NHT) {
|
||||
char buf[PREFIX2STR_BUFFER];
|
||||
prefix2str(p, buf, sizeof(buf));
|
||||
@ -811,7 +785,7 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
|
||||
char buf[PREFIX2STR_BUFFER];
|
||||
prefix2str(&p, buf, sizeof(buf));
|
||||
zlog_debug(
|
||||
"%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%d up %ld rp %d",
|
||||
"%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
|
||||
__PRETTY_FUNCTION__, buf, pim->vrf->name, nexthop_num,
|
||||
pnc->nexthop_num, vrf_id, pnc->upstream_hash->count,
|
||||
listcount(pnc->rp_list));
|
||||
|
@ -80,7 +80,7 @@ static int pim_zebra_if_add(int command, struct zclient *zclient,
|
||||
|
||||
if (PIM_DEBUG_ZEBRA) {
|
||||
zlog_debug(
|
||||
"%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d",
|
||||
"%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
|
||||
__PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id,
|
||||
(long)ifp->flags, ifp->metric, ifp->mtu,
|
||||
if_is_operative(ifp));
|
||||
@ -130,7 +130,7 @@ static int pim_zebra_if_del(int command, struct zclient *zclient,
|
||||
|
||||
if (PIM_DEBUG_ZEBRA) {
|
||||
zlog_debug(
|
||||
"%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d",
|
||||
"%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
|
||||
__PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id,
|
||||
(long)ifp->flags, ifp->metric, ifp->mtu,
|
||||
if_is_operative(ifp));
|
||||
@ -158,7 +158,7 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient,
|
||||
|
||||
if (PIM_DEBUG_ZEBRA) {
|
||||
zlog_debug(
|
||||
"%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d",
|
||||
"%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
|
||||
__PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id,
|
||||
(long)ifp->flags, ifp->metric, ifp->mtu,
|
||||
if_is_operative(ifp));
|
||||
@ -213,7 +213,7 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient,
|
||||
|
||||
if (PIM_DEBUG_ZEBRA) {
|
||||
zlog_debug(
|
||||
"%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d",
|
||||
"%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
|
||||
__PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id,
|
||||
(long)ifp->flags, ifp->metric, ifp->mtu,
|
||||
if_is_operative(ifp));
|
||||
@ -293,7 +293,7 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
|
||||
if (PIM_DEBUG_ZEBRA) {
|
||||
char buf[BUFSIZ];
|
||||
prefix2str(p, buf, BUFSIZ);
|
||||
zlog_debug("%s: %s(%d) connected IP address %s flags %u %s",
|
||||
zlog_debug("%s: %s(%u) connected IP address %s flags %u %s",
|
||||
__PRETTY_FUNCTION__, c->ifp->name, vrf_id, buf,
|
||||
c->flags, CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
|
||||
? "secondary"
|
||||
@ -372,7 +372,7 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
|
||||
char buf[BUFSIZ];
|
||||
prefix2str(p, buf, BUFSIZ);
|
||||
zlog_debug(
|
||||
"%s: %s(%d) disconnected IP address %s flags %u %s",
|
||||
"%s: %s(%u) disconnected IP address %s flags %u %s",
|
||||
__PRETTY_FUNCTION__, c->ifp->name, vrf_id, buf,
|
||||
c->flags,
|
||||
CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
|
||||
@ -765,8 +765,6 @@ void pim_zebra_init(void)
|
||||
zlog_info("zclient_init cleared redistribution request");
|
||||
}
|
||||
|
||||
zassert(zclient->redist_default == ZEBRA_ROUTE_PIM);
|
||||
|
||||
/* Request all redistribution */
|
||||
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
|
||||
if (i == zclient->redist_default)
|
||||
|
@ -22,7 +22,7 @@
|
||||
%{!?with_multipath: %global with_multipath 256 }
|
||||
%{!?frr_user: %global frr_user frr }
|
||||
%{!?vty_group: %global vty_group frrvty }
|
||||
%{!?with_fpm: %global with_fpm 0 }
|
||||
%{!?with_fpm: %global with_fpm 1 }
|
||||
%{!?with_watchfrr: %global with_watchfrr 1 }
|
||||
%{!?with_bgp_vnc: %global with_bgp_vnc 0 }
|
||||
%{!?with_pimd: %global with_pimd 1 }
|
||||
@ -554,6 +554,9 @@ rm -rf %{buildroot}
|
||||
%{_libdir}/lib*.so.0
|
||||
%attr(755,root,root) %{_libdir}/lib*.so.0.*
|
||||
%endif
|
||||
%if %{with_fpm}
|
||||
%attr(755,root,root) %{_libdir}/frr/modules/zebra_fpm.so
|
||||
%endif
|
||||
%attr(755,root,root) %{_libdir}/frr/modules/zebra_irdp.so
|
||||
%{_bindir}/*
|
||||
%config(noreplace) /etc/frr/[!v]*.conf*
|
||||
|
@ -48,6 +48,7 @@ static void rip_zebra_ipv4_send(struct route_node *rp, u_char cmd)
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_RIP;
|
||||
api.safi = SAFI_UNICAST;
|
||||
|
||||
|
@ -48,6 +48,7 @@ static void ripng_zebra_ipv6_send(struct route_node *rp, u_char cmd)
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_RIPNG;
|
||||
api.safi = SAFI_UNICAST;
|
||||
api.prefix = rp->p;
|
||||
|
@ -159,6 +159,7 @@ void route_add(struct prefix *p, struct nexthop *nh)
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_SHARP;
|
||||
api.safi = SAFI_UNICAST;
|
||||
memcpy(&api.prefix, p, sizeof(*p));
|
||||
@ -180,6 +181,7 @@ void route_delete(struct prefix *p)
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.nh_vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_SHARP;
|
||||
api.safi = SAFI_UNICAST;
|
||||
memcpy(&api.prefix, p, sizeof(*p));
|
||||
|
@ -25,8 +25,9 @@
|
||||
#include "privs.h"
|
||||
#include "queue.h"
|
||||
#include "filter.h"
|
||||
#include "frr_pthread.h"
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgpd.c"
|
||||
#include "bgpd/bgp_aspath.h"
|
||||
#include "bgpd/bgp_attr.h"
|
||||
#include "bgpd/bgp_packet.h"
|
||||
@ -1272,6 +1273,9 @@ static int handle_attr_test(struct aspath_tests *t)
|
||||
struct aspath *asp;
|
||||
size_t datalen;
|
||||
|
||||
bgp_pthreads_init();
|
||||
frr_pthread_get(PTHREAD_KEEPALIVES)->running = true;
|
||||
|
||||
asp = make_aspath(t->segment->asdata, t->segment->len, 0);
|
||||
|
||||
peer.curr = stream_new(BGP_MAX_PACKET_SIZE);
|
||||
|
@ -27,8 +27,9 @@
|
||||
#include "memory.h"
|
||||
#include "queue.h"
|
||||
#include "filter.h"
|
||||
#include "frr_pthread.h"
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgpd.c"
|
||||
#include "bgpd/bgp_open.h"
|
||||
#include "bgpd/bgp_debug.h"
|
||||
#include "bgpd/bgp_packet.h"
|
||||
@ -915,6 +916,9 @@ int main(void)
|
||||
vrf_init(NULL, NULL, NULL, NULL);
|
||||
bgp_option_set(BGP_OPT_NO_LISTEN);
|
||||
|
||||
bgp_pthreads_init();
|
||||
frr_pthread_get(PTHREAD_KEEPALIVES)->running = true;
|
||||
|
||||
if (fileno(stdout) >= 0)
|
||||
tty = isatty(fileno(stdout));
|
||||
|
||||
|
@ -434,7 +434,14 @@ end
|
||||
new_ctx = False
|
||||
log.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys)
|
||||
|
||||
elif "vni " in line:
|
||||
# The 'vni' keyword under 'router bgp X/address-family l2vpn evpn' creates
|
||||
# a sub-context but the 'vni' keyword in other places (such as 'vrf BLUE')
|
||||
# does not.
|
||||
elif ("vni " in line and
|
||||
len(ctx_keys) == 2 and
|
||||
ctx_keys[0].startswith('router bgp') and
|
||||
ctx_keys[1] == 'address-family l2vpn evpn'):
|
||||
|
||||
main_ctx_key = []
|
||||
|
||||
# Save old context first
|
||||
|
165
vtysh/vtysh.c
165
vtysh/vtysh.c
@ -46,6 +46,9 @@
|
||||
|
||||
DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy")
|
||||
|
||||
/* Destination for vtysh output */
|
||||
FILE *outputfile;
|
||||
|
||||
/* Struct VTY. */
|
||||
struct vty *vty;
|
||||
|
||||
@ -138,16 +141,25 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
|
||||
|
||||
bufvalid += nread;
|
||||
|
||||
end = memmem(buf, bufvalid - buf, terminator,
|
||||
sizeof(terminator));
|
||||
if (end + sizeof(terminator) + 1 > bufvalid)
|
||||
if (bufvalid - buf >= 4)
|
||||
end = memmem(bufvalid - 4, 4, terminator,
|
||||
sizeof(terminator));
|
||||
|
||||
if (end && end + sizeof(terminator) + 1 > bufvalid)
|
||||
/* found \0\0\0 but return code hasn't been read yet */
|
||||
end = NULL;
|
||||
if (end)
|
||||
ret = end[sizeof(terminator)];
|
||||
|
||||
while (bufvalid > buf && (end > buf || !end)) {
|
||||
size_t textlen = (end ? end : bufvalid) - buf;
|
||||
/*
|
||||
* calculate # bytes we have, up to & not including the
|
||||
* terminator if present
|
||||
*/
|
||||
size_t textlen = (end ? end : bufvalid) - buf;
|
||||
|
||||
/* feed line processing callback if present */
|
||||
while (callback && bufvalid > buf && (end > buf || !end)) {
|
||||
textlen = (end ? end : bufvalid) - buf;
|
||||
char *eol = memchr(buf, '\n', textlen);
|
||||
if (eol)
|
||||
/* line break */
|
||||
@ -165,8 +177,7 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
|
||||
/* continue reading */
|
||||
break;
|
||||
|
||||
/* eol is at a line end now, either \n => \0 or \0\0\0
|
||||
*/
|
||||
/* eol is at line end now, either \n => \0 or \0\0\0 */
|
||||
assert(eol && eol <= bufvalid);
|
||||
|
||||
if (fp) {
|
||||
@ -186,6 +197,14 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
|
||||
end -= eol - buf;
|
||||
}
|
||||
|
||||
/* else if no callback, dump raw */
|
||||
if (!callback) {
|
||||
if (fp)
|
||||
fwrite(buf, 1, textlen, fp);
|
||||
memmove(buf, buf + textlen, bufvalid - buf - textlen);
|
||||
bufvalid -= textlen;
|
||||
}
|
||||
|
||||
if (bufvalid == buf + bufsz) {
|
||||
char *new;
|
||||
bufsz *= 2;
|
||||
@ -375,21 +394,21 @@ static int vtysh_execute_func(const char *line, int pager)
|
||||
fprintf(stdout, "%% Command incomplete.\n");
|
||||
break;
|
||||
case CMD_SUCCESS_DAEMON: {
|
||||
/* FIXME: Don't open pager for exit commands. popen() causes
|
||||
* problems
|
||||
* if exited from vtysh at all. This hack shouldn't cause any
|
||||
* problem
|
||||
* but is really ugly. */
|
||||
if (pager && vtysh_pager_name
|
||||
/*
|
||||
* FIXME: Don't open pager for exit commands. popen() causes
|
||||
* problems if exited from vtysh at all. This hack shouldn't
|
||||
* cause any problem but is really ugly.
|
||||
*/
|
||||
fp = outputfile;
|
||||
if (pager && vtysh_pager_name && outputfile == stdout
|
||||
&& (strncmp(line, "exit", 4) != 0)) {
|
||||
fp = popen(vtysh_pager_name, "w");
|
||||
if (fp == NULL) {
|
||||
perror("popen failed for pager");
|
||||
fp = stdout;
|
||||
fp = outputfile;
|
||||
} else
|
||||
closepager = 1;
|
||||
} else
|
||||
fp = stdout;
|
||||
}
|
||||
|
||||
if (!strcmp(cmd->string, "configure terminal")) {
|
||||
for (i = 0; i < array_size(vtysh_client); i++) {
|
||||
@ -405,7 +424,7 @@ static int vtysh_execute_func(const char *line, int pager)
|
||||
|
||||
if (vline == NULL) {
|
||||
if (pager && vtysh_pager_name && fp
|
||||
&& closepager) {
|
||||
&& fp != outputfile && closepager) {
|
||||
if (pclose(fp) == -1) {
|
||||
perror("pclose failed for pager");
|
||||
}
|
||||
@ -455,7 +474,7 @@ static int vtysh_execute_func(const char *line, int pager)
|
||||
(*cmd->func)(cmd, vty, 0, NULL);
|
||||
}
|
||||
}
|
||||
if (pager && vtysh_pager_name && fp && closepager) {
|
||||
if (pager && vtysh_pager_name && fp && closepager && fp != outputfile) {
|
||||
if (pclose(fp) == -1) {
|
||||
perror("pclose failed for pager");
|
||||
}
|
||||
@ -537,19 +556,19 @@ int vtysh_mark_file(const char *filename)
|
||||
switch (vty->node) {
|
||||
case LDP_IPV4_IFACE_NODE:
|
||||
if (strncmp(vty_buf_copy, " ", 3)) {
|
||||
fprintf(stdout, " end\n");
|
||||
fprintf(outputfile, " end\n");
|
||||
vty->node = LDP_IPV4_NODE;
|
||||
}
|
||||
break;
|
||||
case LDP_IPV6_IFACE_NODE:
|
||||
if (strncmp(vty_buf_copy, " ", 3)) {
|
||||
fprintf(stdout, " end\n");
|
||||
fprintf(outputfile, " end\n");
|
||||
vty->node = LDP_IPV6_NODE;
|
||||
}
|
||||
break;
|
||||
case LDP_PSEUDOWIRE_NODE:
|
||||
if (strncmp(vty_buf_copy, " ", 2)) {
|
||||
fprintf(stdout, " end\n");
|
||||
fprintf(outputfile, " end\n");
|
||||
vty->node = LDP_L2VPN_NODE;
|
||||
}
|
||||
break;
|
||||
@ -558,7 +577,7 @@ int vtysh_mark_file(const char *filename)
|
||||
}
|
||||
|
||||
if (vty_buf_trimmed[0] == '!' || vty_buf_trimmed[0] == '#') {
|
||||
fprintf(stdout, "%s", vty->buf);
|
||||
fprintf(outputfile, "%s", vty->buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -566,7 +585,7 @@ int vtysh_mark_file(const char *filename)
|
||||
vline = cmd_make_strvec(vty->buf);
|
||||
|
||||
if (vline == NULL) {
|
||||
fprintf(stdout, "%s", vty->buf);
|
||||
fprintf(outputfile, "%s", vty->buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -609,15 +628,15 @@ int vtysh_mark_file(const char *filename)
|
||||
|| prev_node == BGP_IPV6M_NODE
|
||||
|| prev_node == BGP_EVPN_NODE)
|
||||
&& (tried == 1)) {
|
||||
fprintf(stdout, "exit-address-family\n");
|
||||
fprintf(outputfile, "exit-address-family\n");
|
||||
} else if ((prev_node == BGP_EVPN_VNI_NODE)
|
||||
&& (tried == 1)) {
|
||||
fprintf(stdout, "exit-vni\n");
|
||||
fprintf(outputfile, "exit-vni\n");
|
||||
} else if ((prev_node == KEYCHAIN_KEY_NODE)
|
||||
&& (tried == 1)) {
|
||||
fprintf(stdout, "exit\n");
|
||||
fprintf(outputfile, "exit\n");
|
||||
} else if (tried) {
|
||||
fprintf(stdout, "end\n");
|
||||
fprintf(outputfile, "end\n");
|
||||
}
|
||||
}
|
||||
/* If command didn't succeed in any node, continue with return
|
||||
@ -667,12 +686,12 @@ int vtysh_mark_file(const char *filename)
|
||||
u_int i;
|
||||
int cmd_stat = CMD_SUCCESS;
|
||||
|
||||
fprintf(stdout, "%s", vty->buf);
|
||||
fprintf(outputfile, "%s", vty->buf);
|
||||
for (i = 0; i < array_size(vtysh_client); i++) {
|
||||
if (cmd->daemon & vtysh_client[i].flag) {
|
||||
cmd_stat = vtysh_client_execute(
|
||||
&vtysh_client[i], vty->buf,
|
||||
stdout);
|
||||
outputfile);
|
||||
if (cmd_stat != CMD_SUCCESS)
|
||||
break;
|
||||
}
|
||||
@ -686,7 +705,7 @@ int vtysh_mark_file(const char *filename)
|
||||
}
|
||||
}
|
||||
/* This is the end */
|
||||
fprintf(stdout, "\nend\n");
|
||||
fprintf(outputfile, "\nend\n");
|
||||
vty_close(vty);
|
||||
XFREE(MTYPE_VTYSH_CMD, vty_buf_copy);
|
||||
|
||||
@ -749,7 +768,7 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp)
|
||||
if (cmd->daemon & vtysh_client[i].flag) {
|
||||
cmd_stat = vtysh_client_execute(
|
||||
&vtysh_client[i], vty->buf,
|
||||
stdout);
|
||||
outputfile);
|
||||
/*
|
||||
* CMD_WARNING - Can mean that the
|
||||
* command was
|
||||
@ -1854,7 +1873,7 @@ DEFUN (vtysh_show_thread,
|
||||
fprintf(stdout, "Thread statistics for %s:\n",
|
||||
vtysh_client[i].name);
|
||||
ret = vtysh_client_execute(&vtysh_client[i], line,
|
||||
stdout);
|
||||
outputfile);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
return ret;
|
||||
@ -1875,7 +1894,7 @@ DEFUN (vtysh_show_work_queues,
|
||||
fprintf(stdout, "Work queue statistics for %s:\n",
|
||||
vtysh_client[i].name);
|
||||
ret = vtysh_client_execute(&vtysh_client[i], line,
|
||||
stdout);
|
||||
outputfile);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
@ -1905,7 +1924,7 @@ DEFUN (vtysh_show_work_queues_daemon,
|
||||
}
|
||||
|
||||
ret = vtysh_client_execute(&vtysh_client[i], "show work-queues\n",
|
||||
stdout);
|
||||
outputfile);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1932,9 +1951,9 @@ static int show_per_daemon(const char *line, const char *headline)
|
||||
|
||||
for (i = 0; i < array_size(vtysh_client); i++)
|
||||
if (vtysh_client[i].fd >= 0) {
|
||||
fprintf(stdout, headline, vtysh_client[i].name);
|
||||
fprintf(outputfile, headline, vtysh_client[i].name);
|
||||
ret = vtysh_client_execute(&vtysh_client[i], line,
|
||||
stdout);
|
||||
outputfile);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
@ -2226,20 +2245,19 @@ DEFUN (vtysh_write_terminal,
|
||||
{
|
||||
u_int i;
|
||||
char line[] = "do write terminal\n";
|
||||
FILE *fp = NULL;
|
||||
FILE *fp = outputfile;
|
||||
|
||||
if (vtysh_pager_name) {
|
||||
if (fp == stdout && vtysh_pager_name) {
|
||||
fp = popen(vtysh_pager_name, "w");
|
||||
if (fp == NULL) {
|
||||
perror("popen");
|
||||
exit(1);
|
||||
}
|
||||
} else
|
||||
fp = stdout;
|
||||
}
|
||||
|
||||
vty_out(vty, "Building configuration...\n");
|
||||
vty_out(vty, "\nCurrent configuration:\n");
|
||||
vty_out(vty, "!\n");
|
||||
fprintf(outputfile, "Building configuration...\n");
|
||||
fprintf(outputfile, "\nCurrent configuration:\n");
|
||||
fprintf(outputfile, "!\n");
|
||||
|
||||
for (i = 0; i < array_size(vtysh_client); i++)
|
||||
if ((argc < 3)
|
||||
@ -2251,7 +2269,7 @@ DEFUN (vtysh_write_terminal,
|
||||
|
||||
vtysh_config_dump(fp);
|
||||
|
||||
if (vtysh_pager_name && fp) {
|
||||
if (vtysh_pager_name && fp && fp != outputfile) {
|
||||
fflush(fp);
|
||||
if (pclose(fp) == -1) {
|
||||
perror("pclose");
|
||||
@ -2260,7 +2278,7 @@ DEFUN (vtysh_write_terminal,
|
||||
fp = NULL;
|
||||
}
|
||||
|
||||
vty_out(vty, "end\n");
|
||||
fprintf(outputfile, "end\n");
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -2429,7 +2447,7 @@ DEFUN (vtysh_write_memory,
|
||||
char line[] = "do write memory\n";
|
||||
u_int i;
|
||||
|
||||
fprintf(stdout,
|
||||
fprintf(outputfile,
|
||||
"Note: this version of vtysh never writes vtysh.conf\n");
|
||||
|
||||
/* If integrated frr.conf explicitely set. */
|
||||
@ -2441,7 +2459,7 @@ DEFUN (vtysh_write_memory,
|
||||
if (i < array_size(vtysh_client) && vtysh_client[i].fd != -1)
|
||||
ret = vtysh_client_execute(&vtysh_client[i],
|
||||
"do write integrated",
|
||||
stdout);
|
||||
outputfile);
|
||||
|
||||
if (ret != CMD_SUCCESS) {
|
||||
printf("\nWarning: attempting direct configuration write without "
|
||||
@ -2452,10 +2470,10 @@ DEFUN (vtysh_write_memory,
|
||||
return ret;
|
||||
}
|
||||
|
||||
fprintf(stdout, "Building Configuration...\n");
|
||||
fprintf(outputfile, "Building Configuration...\n");
|
||||
|
||||
for (i = 0; i < array_size(vtysh_client); i++)
|
||||
ret = vtysh_client_execute(&vtysh_client[i], line, stdout);
|
||||
ret = vtysh_client_execute(&vtysh_client[i], line, outputfile);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2484,7 +2502,7 @@ DEFUN (vtysh_terminal_length,
|
||||
|
||||
lines = strtol(argv[idx_number]->arg, &endptr, 10);
|
||||
if (lines < 0 || lines > 512 || *endptr != '\0') {
|
||||
vty_out(vty, "length is malformed\n");
|
||||
fprintf(outputfile, "length is malformed\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
@ -2527,8 +2545,8 @@ DEFUN (vtysh_show_daemons,
|
||||
|
||||
for (i = 0; i < array_size(vtysh_client); i++)
|
||||
if (vtysh_client[i].fd >= 0)
|
||||
vty_out(vty, " %s", vtysh_client[i].name);
|
||||
vty_out(vty, "\n");
|
||||
fprintf(outputfile, " %s", vtysh_client[i].name);
|
||||
fprintf(outputfile, "\n");
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@ -2703,6 +2721,38 @@ DEFUN (config_list,
|
||||
return cmd_list_cmds(vty, argc == 2);
|
||||
}
|
||||
|
||||
DEFUN (vtysh_output_file,
|
||||
vtysh_output_file_cmd,
|
||||
"output file FILE",
|
||||
"Direct vtysh output to file\n"
|
||||
"Direct vtysh output to file\n"
|
||||
"Path to dump output to\n")
|
||||
{
|
||||
const char *path = argv[argc - 1]->arg;
|
||||
outputfile = fopen(path, "a");
|
||||
if (!outputfile) {
|
||||
fprintf(stdout, "Failed to open file '%s': %s\n", path,
|
||||
safe_strerror(errno));
|
||||
outputfile = stdout;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (no_vtysh_output_file,
|
||||
no_vtysh_output_file_cmd,
|
||||
"no output file [FILE]",
|
||||
NO_STR
|
||||
"Direct vtysh output to file\n"
|
||||
"Direct vtysh output to file\n"
|
||||
"Path to dump output to\n")
|
||||
{
|
||||
if (outputfile != stdout) {
|
||||
fclose(outputfile);
|
||||
outputfile = stdout;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(find,
|
||||
find_cmd,
|
||||
"find COMMAND...",
|
||||
@ -2736,6 +2786,8 @@ static void vtysh_install_default(enum node_type node)
|
||||
{
|
||||
install_element(node, &config_list_cmd);
|
||||
install_element(node, &find_cmd);
|
||||
install_element(node, &vtysh_output_file_cmd);
|
||||
install_element(node, &no_vtysh_output_file_cmd);
|
||||
}
|
||||
|
||||
/* Making connection to protocol daemon. */
|
||||
@ -2964,6 +3016,12 @@ static const struct cmd_variable_handler vtysh_var_handler[] = {
|
||||
.completions = vtysh_autocomplete},
|
||||
{.completions = NULL}};
|
||||
|
||||
void vtysh_uninit()
|
||||
{
|
||||
if (outputfile != stdout)
|
||||
fclose(outputfile);
|
||||
}
|
||||
|
||||
void vtysh_init_vty(void)
|
||||
{
|
||||
/* Make vty structure. */
|
||||
@ -2971,6 +3029,9 @@ void vtysh_init_vty(void)
|
||||
vty->type = VTY_SHELL;
|
||||
vty->node = VIEW_NODE;
|
||||
|
||||
/* set default output */
|
||||
outputfile = stdout;
|
||||
|
||||
/* Initialize commands. */
|
||||
cmd_init(0);
|
||||
cmd_variable_handler_register(vtysh_var_handler);
|
||||
|
@ -63,6 +63,7 @@ extern char frr_config[];
|
||||
extern char vtydir[];
|
||||
|
||||
void vtysh_init_vty(void);
|
||||
void vtysh_uninit(void);
|
||||
void vtysh_init_cmd(void);
|
||||
extern int vtysh_connect_all(const char *optional_daemon_name);
|
||||
void vtysh_readline_init(void);
|
||||
|
@ -644,6 +644,8 @@ int main(int argc, char **argv, char **env)
|
||||
while (vtysh_rl_gets())
|
||||
vtysh_execute(line_read);
|
||||
|
||||
vtysh_uninit();
|
||||
|
||||
history_truncate_file(history_file, 1000);
|
||||
printf("\n");
|
||||
|
||||
|
@ -238,10 +238,12 @@ void connected_up(struct interface *ifp, struct connected *ifc)
|
||||
break;
|
||||
}
|
||||
|
||||
rib_add(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0,
|
||||
rib_add(afi, SAFI_UNICAST, ifp->vrf_id, ifp->vrf_id,
|
||||
ZEBRA_ROUTE_CONNECT, 0, 0,
|
||||
&p, NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0);
|
||||
|
||||
rib_add(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0,
|
||||
rib_add(afi, SAFI_MULTICAST, ifp->vrf_id, ifp->vrf_id,
|
||||
ZEBRA_ROUTE_CONNECT, 0, 0,
|
||||
&p, NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
|
||||
|
@ -387,6 +387,11 @@ static int get_iflink_speed(const char *ifname)
|
||||
return (ecmd.speed_hi << 16) | ecmd.speed;
|
||||
}
|
||||
|
||||
uint32_t kernel_get_speed(struct interface *ifp)
|
||||
{
|
||||
return get_iflink_speed(ifp->name);
|
||||
}
|
||||
|
||||
static int netlink_extract_bridge_info(struct rtattr *link_data,
|
||||
struct zebra_l2info_bridge *bridge_info)
|
||||
{
|
||||
|
@ -57,8 +57,29 @@ DEFINE_HOOK(zebra_if_extra_info, (struct vty *vty, struct interface *ifp),
|
||||
DEFINE_HOOK(zebra_if_config_wr, (struct vty *vty, struct interface *ifp),
|
||||
(vty, ifp))
|
||||
|
||||
|
||||
static void if_down_del_nbr_connected(struct interface *ifp);
|
||||
|
||||
static int if_zebra_speed_update(struct thread *thread)
|
||||
{
|
||||
struct interface *ifp = THREAD_ARG(thread);
|
||||
struct zebra_if *zif = ifp->info;
|
||||
uint32_t new_speed;
|
||||
|
||||
zif->speed_update = NULL;
|
||||
|
||||
new_speed = kernel_get_speed(ifp);
|
||||
if (new_speed != ifp->speed) {
|
||||
zlog_info("%s: %s old speed: %u new speed: %u",
|
||||
__PRETTY_FUNCTION__, ifp->name,
|
||||
ifp->speed, new_speed);
|
||||
ifp->speed = new_speed;
|
||||
if_add_update(ifp);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void zebra_if_node_destroy(route_table_delegate_t *delegate,
|
||||
struct route_table *table,
|
||||
struct route_node *node)
|
||||
@ -119,6 +140,16 @@ static int if_zebra_new_hook(struct interface *ifp)
|
||||
route_table_init_with_delegate(&zebra_if_table_delegate);
|
||||
|
||||
ifp->info = zebra_if;
|
||||
|
||||
/*
|
||||
* Some platforms are telling us that the interface is
|
||||
* up and ready to go. When we check the speed we
|
||||
* sometimes get the wrong value. Wait a couple
|
||||
* of seconds and ask again. Hopefully it's all settled
|
||||
* down upon startup.
|
||||
*/
|
||||
thread_add_timer(zebrad.master, if_zebra_speed_update,
|
||||
ifp, 15, &zebra_if->speed_update);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -141,6 +172,8 @@ static int if_zebra_delete_hook(struct interface *ifp)
|
||||
list_delete_and_null(&rtadv->AdvPrefixList);
|
||||
#endif /* HAVE_RTADV */
|
||||
|
||||
THREAD_OFF(zebra_if->speed_update);
|
||||
|
||||
XFREE(MTYPE_TMP, zebra_if);
|
||||
}
|
||||
|
||||
@ -735,7 +768,8 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id)
|
||||
zebra_interface_vrf_update_add(ifp, old_vrf_id);
|
||||
|
||||
/* Install connected routes (in new VRF). */
|
||||
if_install_connected(ifp);
|
||||
if (if_is_operative(ifp))
|
||||
if_install_connected(ifp);
|
||||
|
||||
static_ifindex_update(ifp, true);
|
||||
|
||||
|
@ -273,6 +273,8 @@ struct zebra_if {
|
||||
/* Link fields - for sub-interfaces. */
|
||||
ifindex_t link_ifindex;
|
||||
struct interface *link;
|
||||
|
||||
struct thread *speed_update;
|
||||
};
|
||||
|
||||
DECLARE_HOOK(zebra_if_extra_info, (struct vty *vty, struct interface *ifp),
|
||||
|
@ -1048,7 +1048,7 @@ void rtm_read(struct rt_msghdr *rtm)
|
||||
|
||||
if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
|
||||
|| rtm->rtm_type == RTM_CHANGE)
|
||||
rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
|
||||
rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, VRF_DEFAULT,
|
||||
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
|
||||
&nh, 0, 0, 0, 0, 0);
|
||||
else
|
||||
@ -1096,7 +1096,7 @@ void rtm_read(struct rt_msghdr *rtm)
|
||||
|
||||
if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
|
||||
|| rtm->rtm_type == RTM_CHANGE)
|
||||
rib_add(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
|
||||
rib_add(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, VRF_DEFAULT,
|
||||
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
|
||||
&nh, 0, 0, 0, 0, 0);
|
||||
else
|
||||
|
@ -121,7 +121,7 @@ static int reply_error(int cmd, struct zserv *zserv, vrf_id_t vrf_id)
|
||||
s = zserv->obuf;
|
||||
stream_reset(s);
|
||||
|
||||
zserv_create_header(s, cmd, vrf_id);
|
||||
zclient_create_header(s, cmd, vrf_id);
|
||||
|
||||
/* result */
|
||||
stream_putc(s, 1);
|
||||
|
17
zebra/main.c
17
zebra/main.c
@ -300,6 +300,13 @@ int main(int argc, char **argv)
|
||||
zebra_if_init();
|
||||
zebra_debug_init();
|
||||
router_id_cmd_init();
|
||||
|
||||
/*
|
||||
* Initialize NS( and implicitly the VRF module), and make kernel
|
||||
* routing socket. */
|
||||
zebra_ns_init();
|
||||
|
||||
zebra_vty_init();
|
||||
access_list_init();
|
||||
prefix_list_init();
|
||||
#if defined(HAVE_RTADV)
|
||||
@ -317,16 +324,6 @@ int main(int argc, char **argv)
|
||||
/* For debug purpose. */
|
||||
/* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
|
||||
|
||||
/* Initialize NS( and implicitly the VRF module), and make kernel
|
||||
* routing socket. */
|
||||
zebra_ns_init();
|
||||
|
||||
/*
|
||||
* Initialize show/config command after the vrf initialization is
|
||||
* complete
|
||||
*/
|
||||
zebra_vty_init();
|
||||
|
||||
#if defined(HANDLE_ZAPI_FUZZING)
|
||||
if (fuzzing) {
|
||||
zserv_read_file(fuzzing);
|
||||
|
@ -59,6 +59,7 @@ struct route_entry {
|
||||
|
||||
/* VRF identifier. */
|
||||
vrf_id_t vrf_id;
|
||||
vrf_id_t nh_vrf_id;
|
||||
|
||||
/* Which routing table */
|
||||
uint32_t table;
|
||||
@ -293,8 +294,8 @@ extern void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re);
|
||||
/* NOTE:
|
||||
* All rib_add function will not just add prefix into RIB, but
|
||||
* also implicitly withdraw equal prefix of same type. */
|
||||
extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
|
||||
u_short instance, int flags, struct prefix *p,
|
||||
extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, vrf_id_t nh_vrf_id,
|
||||
int type, u_short instance, int flags, struct prefix *p,
|
||||
struct prefix_ipv6 *src_p, const struct nexthop *nh,
|
||||
u_int32_t table_id, u_int32_t metric, u_int32_t mtu,
|
||||
uint8_t distance, route_tag_t tag);
|
||||
@ -439,6 +440,8 @@ DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason),
|
||||
|
||||
|
||||
extern void zebra_vty_init(void);
|
||||
extern int static_config(struct vty *vty, struct zebra_vrf *zvrf,
|
||||
afi_t afi, safi_t safi, const char *cmd);
|
||||
extern pid_t pid;
|
||||
|
||||
#endif /*_ZEBRA_RIB_H */
|
||||
|
@ -60,15 +60,17 @@ enum southbound_results {
|
||||
* semantics so we will end up with a delete than
|
||||
* a re-add.
|
||||
*/
|
||||
extern void kernel_route_rib(struct prefix *p, struct prefix *src_p,
|
||||
struct route_entry *old, struct route_entry *new);
|
||||
extern void kernel_route_rib(struct route_node *rn, struct prefix *p,
|
||||
struct prefix *src_p, struct route_entry *old,
|
||||
struct route_entry *new);
|
||||
|
||||
/*
|
||||
* So route install/failure may not be immediately known
|
||||
* so let's separate it out and allow the result to
|
||||
* be passed back up.
|
||||
*/
|
||||
extern void kernel_route_rib_pass_fail(struct prefix *p,
|
||||
extern void kernel_route_rib_pass_fail(struct route_node *rn,
|
||||
struct prefix *p,
|
||||
struct route_entry *re,
|
||||
enum southbound_results res);
|
||||
|
||||
@ -98,6 +100,7 @@ extern void kernel_lsp_pass_fail(zebra_lsp_t *lsp,
|
||||
|
||||
extern int mpls_kernel_init(void);
|
||||
|
||||
extern uint32_t kernel_get_speed(struct interface *ifp);
|
||||
extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute);
|
||||
extern int kernel_add_vtep(vni_t vni, struct interface *ifp,
|
||||
struct in_addr *vtep_ip);
|
||||
|
@ -403,6 +403,9 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
|
||||
afi = AFI_IP6;
|
||||
|
||||
if (h->nlmsg_type == RTM_NEWROUTE) {
|
||||
struct interface *ifp;
|
||||
vrf_id_t nh_vrf_id = vrf_id;
|
||||
|
||||
if (!tb[RTA_MULTIPATH]) {
|
||||
struct nexthop nh;
|
||||
size_t sz = (afi == AFI_IP) ? 4 : 16;
|
||||
@ -434,7 +437,14 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
|
||||
if (gate)
|
||||
memcpy(&nh.gate, gate, sz);
|
||||
|
||||
rib_add(afi, SAFI_UNICAST, vrf_id, proto,
|
||||
if (index) {
|
||||
ifp = if_lookup_by_index(index,
|
||||
VRF_UNKNOWN);
|
||||
if (ifp)
|
||||
nh_vrf_id = ifp->vrf_id;
|
||||
}
|
||||
|
||||
rib_add(afi, SAFI_UNICAST, vrf_id, nh_vrf_id, proto,
|
||||
0, flags, &p, NULL, &nh, table, metric,
|
||||
mtu, distance, tag);
|
||||
} else {
|
||||
@ -453,6 +463,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
|
||||
re->metric = metric;
|
||||
re->mtu = mtu;
|
||||
re->vrf_id = vrf_id;
|
||||
re->nh_vrf_id = vrf_id;
|
||||
re->table = table;
|
||||
re->nexthop_num = 0;
|
||||
re->uptime = time(NULL);
|
||||
@ -464,6 +475,18 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
|
||||
break;
|
||||
|
||||
index = rtnh->rtnh_ifindex;
|
||||
if (index) {
|
||||
/*
|
||||
* Yes we are looking this up
|
||||
* for every nexthop and just
|
||||
* using the last one looked
|
||||
* up right now
|
||||
*/
|
||||
ifp = if_lookup_by_index(index,
|
||||
VRF_UNKNOWN);
|
||||
if (ifp)
|
||||
re->nh_vrf_id = ifp->vrf_id;
|
||||
}
|
||||
gate = 0;
|
||||
if (rtnh->rtnh_len > sizeof(*rtnh)) {
|
||||
memset(tb, 0, sizeof(tb));
|
||||
@ -803,7 +826,7 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
|
||||
struct rtmsg *rtmsg,
|
||||
size_t req_size, int cmd)
|
||||
{
|
||||
struct nexthop_label *nh_label;
|
||||
struct mpls_label_stack *nh_label;
|
||||
mpls_lse_t out_lse[MPLS_MAX_LABELS];
|
||||
char label_buf[256];
|
||||
|
||||
@ -940,10 +963,17 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
|
||||
routedesc, inet6_ntoa(nexthop->gate.ipv6),
|
||||
label_buf, nexthop->ifindex);
|
||||
}
|
||||
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
||||
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
|
||||
|
||||
/*
|
||||
* We have the ifindex so we should always send it
|
||||
* This is especially useful if we are doing route
|
||||
* leaking.
|
||||
*/
|
||||
if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)
|
||||
addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex);
|
||||
|
||||
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
||||
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
|
||||
if (cmd == RTM_NEWROUTE) {
|
||||
if (nexthop->rmap_src.ipv4.s_addr)
|
||||
addattr_l(nlmsg, req_size, RTA_PREFSRC,
|
||||
@ -961,8 +991,6 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
|
||||
}
|
||||
|
||||
if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
|
||||
addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex);
|
||||
|
||||
if (cmd == RTM_NEWROUTE) {
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
|
||||
addattr_l(nlmsg, req_size, RTA_PREFSRC,
|
||||
@ -1003,7 +1031,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
|
||||
struct rtmsg *rtmsg,
|
||||
union g_addr **src)
|
||||
{
|
||||
struct nexthop_label *nh_label;
|
||||
struct mpls_label_stack *nh_label;
|
||||
mpls_lse_t out_lse[MPLS_MAX_LABELS];
|
||||
char label_buf[256];
|
||||
|
||||
@ -1141,11 +1169,18 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
|
||||
routedesc, inet6_ntoa(nexthop->gate.ipv6),
|
||||
label_buf, nexthop->ifindex);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have figured out the ifindex so we should always send it
|
||||
* This is especially useful if we are doing route
|
||||
* leaking.
|
||||
*/
|
||||
if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)
|
||||
rtnh->rtnh_ifindex = nexthop->ifindex;
|
||||
|
||||
/* ifindex */
|
||||
if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
|
||||
|| nexthop->type == NEXTHOP_TYPE_IFINDEX) {
|
||||
rtnh->rtnh_ifindex = nexthop->ifindex;
|
||||
|
||||
if (nexthop->rmap_src.ipv4.s_addr)
|
||||
*src = &nexthop->rmap_src;
|
||||
else if (nexthop->src.ipv4.s_addr)
|
||||
@ -1157,8 +1192,6 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
|
||||
"nexthop via if %u",
|
||||
routedesc, nexthop->ifindex);
|
||||
} else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
|
||||
rtnh->rtnh_ifindex = nexthop->ifindex;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug(
|
||||
"netlink_route_multipath() (%s): "
|
||||
@ -1609,8 +1642,9 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
|
||||
return suc;
|
||||
}
|
||||
|
||||
void kernel_route_rib(struct prefix *p, struct prefix *src_p,
|
||||
struct route_entry *old, struct route_entry *new)
|
||||
void kernel_route_rib(struct route_node *rn, struct prefix *p,
|
||||
struct prefix *src_p, struct route_entry *old,
|
||||
struct route_entry *new)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@ -1639,7 +1673,7 @@ void kernel_route_rib(struct prefix *p, struct prefix *src_p,
|
||||
ret = netlink_route_multipath(RTM_NEWROUTE, p,
|
||||
src_p, new, 0);
|
||||
}
|
||||
kernel_route_rib_pass_fail(p, new,
|
||||
kernel_route_rib_pass_fail(rn, p, new,
|
||||
(!ret) ?
|
||||
SOUTHBOUND_INSTALL_SUCCESS :
|
||||
SOUTHBOUND_INSTALL_FAILURE);
|
||||
@ -1649,7 +1683,7 @@ void kernel_route_rib(struct prefix *p, struct prefix *src_p,
|
||||
if (old) {
|
||||
ret = netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0);
|
||||
|
||||
kernel_route_rib_pass_fail(p, old,
|
||||
kernel_route_rib_pass_fail(rn, p, old,
|
||||
(!ret) ?
|
||||
SOUTHBOUND_DELETE_SUCCESS :
|
||||
SOUTHBOUND_DELETE_FAILURE);
|
||||
|
@ -67,7 +67,7 @@ static int sin_masklen(struct in_addr mask)
|
||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
static int kernel_rtm_add_labels(struct nexthop_label *nh_label,
|
||||
static int kernel_rtm_add_labels(struct mpls_label_stack *nh_label,
|
||||
struct sockaddr_mpls *smpls)
|
||||
{
|
||||
if (nh_label->num_labels > 1) {
|
||||
@ -387,8 +387,9 @@ static int kernel_rtm(int cmd, struct prefix *p, struct route_entry *re)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kernel_route_rib(struct prefix *p, struct prefix *src_p,
|
||||
struct route_entry *old, struct route_entry *new)
|
||||
void kernel_route_rib(struct route_node *rn, struct prefix *p,
|
||||
struct prefix *src_p, struct route_entry *old,
|
||||
struct route_entry *new)
|
||||
{
|
||||
int route = 0;
|
||||
|
||||
@ -410,12 +411,12 @@ void kernel_route_rib(struct prefix *p, struct prefix *src_p,
|
||||
zlog_err("Can't lower privileges");
|
||||
|
||||
if (new) {
|
||||
kernel_route_rib_pass_fail(p, new,
|
||||
kernel_route_rib_pass_fail(rn, p, new,
|
||||
(!route) ?
|
||||
SOUTHBOUND_INSTALL_SUCCESS :
|
||||
SOUTHBOUND_INSTALL_FAILURE);
|
||||
} else {
|
||||
kernel_route_rib_pass_fail(p, old,
|
||||
kernel_route_rib_pass_fail(rn, p, old,
|
||||
(!route) ?
|
||||
SOUTHBOUND_DELETE_SUCCESS :
|
||||
SOUTHBOUND_DELETE_FAILURE);
|
||||
@ -473,4 +474,9 @@ extern int kernel_interface_set_master(struct interface *master,
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t kernel_get_speed(struct interface *ifp)
|
||||
{
|
||||
return ifp->speed;
|
||||
}
|
||||
|
||||
#endif /* !HAVE_NETLINK */
|
||||
|
@ -97,8 +97,9 @@ static void handle_route_entry(mib2_ipRouteEntry_t *routeEntry)
|
||||
nh.type = NEXTHOP_TYPE_IPV4;
|
||||
nh.gate.ipv4.s_addr = routeEntry->ipRouteNextHop;
|
||||
|
||||
rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0,
|
||||
zebra_flags, &prefix, NULL, &nh, 0, 0, 0, 0, 0);
|
||||
rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, VRF_DEFAULT,
|
||||
ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &prefix, NULL,
|
||||
&nh, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void route_read(struct zebra_ns *zns)
|
||||
|
@ -713,7 +713,15 @@ static int zfpm_read_cb(struct thread *thread)
|
||||
nbyte = stream_read_try(ibuf, zfpm_g->sock,
|
||||
FPM_MSG_HDR_LEN - already);
|
||||
if (nbyte == 0 || nbyte == -1) {
|
||||
zfpm_connection_down("closed socket in read");
|
||||
if (nbyte == -1) {
|
||||
char buffer[1024];
|
||||
|
||||
sprintf(buffer, "closed socket in read(%d): %s",
|
||||
errno, safe_strerror(errno));
|
||||
zfpm_connection_down(buffer);
|
||||
}
|
||||
else
|
||||
zfpm_connection_down("closed socket in read");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -743,7 +751,15 @@ static int zfpm_read_cb(struct thread *thread)
|
||||
nbyte = stream_read_try(ibuf, zfpm_g->sock, msg_len - already);
|
||||
|
||||
if (nbyte == 0 || nbyte == -1) {
|
||||
zfpm_connection_down("failed to read message");
|
||||
if (nbyte == -1) {
|
||||
char buffer[1024];
|
||||
|
||||
sprintf(buffer, "failed to read message(%d) %s",
|
||||
errno, safe_strerror(errno));
|
||||
zfpm_connection_down(buffer);
|
||||
}
|
||||
else
|
||||
zfpm_connection_down("failed to read message");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
|
||||
ifindex_t ifindex, mpls_label_t out_label);
|
||||
static int nhlfe_del(zebra_nhlfe_t *snhlfe);
|
||||
static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe,
|
||||
struct nexthop_label *nh_label);
|
||||
struct mpls_label_stack *nh_label);
|
||||
static int mpls_lsp_uninstall_all(struct hash *lsp_table, zebra_lsp_t *lsp,
|
||||
enum lsp_types_t type);
|
||||
static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
|
||||
@ -457,7 +457,7 @@ static int fec_send(zebra_fec_t *fec, struct zserv *client)
|
||||
s = client->obuf;
|
||||
stream_reset(s);
|
||||
|
||||
zserv_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
|
||||
zclient_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
|
||||
|
||||
stream_putw(s, rn->p.family);
|
||||
stream_put_prefix(s, &rn->p);
|
||||
@ -1217,7 +1217,7 @@ static int nhlfe_del(zebra_nhlfe_t *nhlfe)
|
||||
* Update label for NHLFE entry.
|
||||
*/
|
||||
static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe,
|
||||
struct nexthop_label *nh_label)
|
||||
struct mpls_label_stack *nh_label)
|
||||
{
|
||||
nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ stream_failure:
|
||||
|
||||
stream_reset(s);
|
||||
|
||||
zserv_create_header(s, ZEBRA_IPMR_ROUTE_STATS, zvrf_id(zvrf));
|
||||
zclient_create_header(s, ZEBRA_IPMR_ROUTE_STATS, zvrf_id(zvrf));
|
||||
stream_put_in_addr(s, &mroute.sg.src);
|
||||
stream_put_in_addr(s, &mroute.sg.grp);
|
||||
stream_put(s, &mroute.lastused, sizeof(mroute.lastused));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user