diff options
114 files changed, 2683 insertions, 1215 deletions
diff --git a/.clang-format b/.clang-format index 21fe9d7c5..cc5a95baf 100644 --- a/.clang-format +++ b/.clang-format @@ -57,3 +57,5 @@ ForEachMacros: - SUBGRP_FOREACH_ADJ_SAFE - AF_FOREACH - FOREACH_AFI_SAFI + # ospfd + - LSDB_LOOP @@ -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 diff --git a/babeld/kernel.c b/babeld/kernel.c index 8c4fc953e..6b673c487 100644 --- a/babeld/kernel.c +++ b/babeld/kernel.c @@ -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) { diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index 840cc3575..29b6ca6bf 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -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; } } diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 2e277bfa5..ce46b21f0 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -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)); } diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index 5ab14d5cd..59b2d1cda 100644 --- a/bgpd/bgp_io.c +++ b/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; +/* Thread external API ----------------------------------------------------- */ -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) +void bgp_writes_on(struct peer *peer) { 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(); -} + assert(fpt->running); -void bgp_writes_on(struct peer *peer) -{ 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) diff --git a/bgpd/bgp_io.h b/bgpd/bgp_io.h index 73587366d..14a12d370 100644 --- a/bgpd/bgp_io.h +++ b/bgpd/bgp_io.h @@ -29,24 +29,6 @@ #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. * * @param arg - unused diff --git a/bgpd/bgp_keepalives.c b/bgpd/bgp_keepalives.c index afa280a79..5a48c7013 100644 --- a/bgpd/bgp_keepalives.c +++ b/bgpd/bgp_keepalives.c @@ -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; } diff --git a/bgpd/bgp_keepalives.h b/bgpd/bgp_keepalives.h index 1fbd035b9..d1cb7d246 100644 --- a/bgpd/bgp_keepalives.h +++ b/bgpd/bgp_keepalives.h @@ -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 */ diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index a720d31a7..0508f4846 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -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) { diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 625d4f844..a963838f5 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -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); - - 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)); + exact_match = true; - 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"); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index eed5fdc65..0ce2466f5 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -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); } /* diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index c691233c5..fdc7f22ae 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -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); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index cff5c1b2e..38bc45728 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -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); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 30e3c6f31..de170fdd0 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -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; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 5356cfd2f..19f0c8cab 100644 --- a/bgpd/bgpd.c +++ b/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() diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 8e843eb65..c4ac4b0ad 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -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; diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 1e3c5a035..95666143a 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -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; diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c index f8b38468f..92d7e6fc7 100644 --- a/bgpd/rfapi/vnc_zebra.c +++ b/bgpd/rfapi/vnc_zebra.c @@ -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; diff --git a/doc/bgpd.texi b/doc/bgpd.texi index d62c3a751..83483f569 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -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 diff --git a/doc/isisd.texi b/doc/isisd.texi index bbc289675..404698d80 100644 --- a/doc/isisd.texi +++ b/doc/isisd.texi @@ -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 diff --git a/doc/ospfd.texi b/doc/ospfd.texi index 9feba08b2..33341d2be 100644 --- a/doc/ospfd.texi +++ b/doc/ospfd.texi @@ -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 diff --git a/doc/vnc.texi b/doc/vnc.texi index c44519a9f..6193d3c90 100644 --- a/doc/vnc.texi +++ b/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 diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index 00438f2f4..f18d39d57 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -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)); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 573b81591..0512a18a2 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -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; diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index 19dfbaf54..72b47ae5c 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -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; - - 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); - - hash_get(pthread_table, fpt, hash_alloc_intern); + holder.attr.id = attr->id; + + 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); + + /* 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->start_routine, arg); + ret = pthread_create(&fpt->thread, attr, fpt->attr.start, fpt); - /* 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); - memset(&fpt->thread, 0x00, sizeof(fpt->thread)); - return ret; + 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); } -int frr_pthread_stop(unsigned int id, void **result) +void frr_pthread_notify_running(struct frr_pthread *fpt) { - struct frr_pthread *fpt = frr_pthread_get(id); - return frr_pthread_stop_actual(fpt, result); + 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; +} + +/* * 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; +} diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h index f6000340a..2cc50196a 100644 --- a/lib/frr_pthread.h +++ b/lib/frr_pthread.h @@ -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 *); - - /* stop routine */ - int (*stop_routine)(void **, struct frr_pthread *); - - /* the (hopefully descriptive) name of this thread */ - char *name; + /* caller-specified data; start & stop funcs, name, id */ + struct frr_pthread_attr attr; + + /* + * 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; + + /* + * 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. - * - * 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) +/* + * Creates a new frr_pthread with the given attributes. * - * @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 @@ -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; @@ -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); diff --git a/lib/mpls.h b/lib/mpls.h index 9d103e669..95882c26e 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -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 diff --git a/lib/nexthop.c b/lib/nexthop.c index f6b2c9788..f531f2730 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -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++) diff --git a/lib/nexthop.h b/lib/nexthop.h index a727f3705..753e66643 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -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 @@ -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" diff --git a/lib/thread.c b/lib/thread.c index d26db8855..9d64663d9 100644 --- a/lib/thread.c +++ b/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 diff --git a/lib/zclient.c b/lib/zclient.c index 4177ce1a7..d3717d0cd 100644 --- a/lib/zclient.c +++ b/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; - - 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); - } + 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; + + 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; - - 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); - } + 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; + + 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)); diff --git a/lib/zclient.h b/lib/zclient.h index cc34fd9d2..df9e5f438 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -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, diff --git a/lib/zebra.h b/lib/zebra.h index 1eb0c5625..b9a795d16 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -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 diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 2612d8e04..2f084f842 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -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) { diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index d270b9547..884761149 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -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); } diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index bd5e2bd1d..ed624c6ae 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -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); diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index d212d9238..b7cd9b4b0 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -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; diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 5fbf2dafa..745b87b89 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -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); } diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index 73053452e..7f4665ac2 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -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 */ diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 98f93b06e..fc6c46c7e 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -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); diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 384413236..b67d9a9f2 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -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) diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index b1d940952..77653ea33 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -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); diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 82f75b153..cca4616c1 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -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; diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 3536d33d1..db446a328 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -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 */ diff --git a/ospf6d/ospf6_memory.c b/ospf6d/ospf6_memory.c index 56c232d6d..1c3523b43 100644 --- a/ospf6d/ospf6_memory.c +++ b/ospf6d/ospf6_memory.c @@ -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") diff --git a/ospf6d/ospf6_memory.h b/ospf6d/ospf6_memory.h index fe72ee366..548af5e32 100644 --- a/ospf6d/ospf6_memory.h +++ b/ospf6d/ospf6_memory.h @@ -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 */ diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 1307b374a..d76438ea5 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -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); } diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 281757222..735b28a69 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -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"); diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index 9eacadbdb..b759828c3 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -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 */ diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 340d90159..17ce1771e 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -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; - - /* 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_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 + /* 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; + + 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 + 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, + 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( + 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); - } + 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); + } +} diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h index dbb88d12b..f294b8d34 100644 --- a/ospf6d/ospf6_spf.h +++ b/ospf6d/ospf6_spf.h @@ -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 */ diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index e0844765d..5d1144335 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -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); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index cc87c499e..2a419ddfc 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -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; diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index d28d9dd06..bbc1cc18f 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -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(); diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index f7aa94ad1..ea94bab6b 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -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) diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 8c1ad5ff0..9ebaeffa6 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -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; diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index 368987a2b..d2af97483 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -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 */ diff --git a/ospfd/ospf_ia.c b/ospfd/ospf_ia.c index c65d8b874..e570f3337 100644 --- a/ospfd/ospf_ia.c +++ b/ospfd/ospf_ia.c @@ -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, diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index e8700e7eb..c8f758525 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -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 */ diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 829a3f429..ab02444f7 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -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. */ diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index a2961992d..0f1dd63df 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -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); } /* diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index c87001294..54d5dd5d1 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -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; } diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 78d82f8a6..986c202d8 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -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); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 0541bfeee..c923a6f35 100644 --- a/ospfd/ospf_vty.c +++ b/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", diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 66be29dbb..58e8a921d 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -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; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index b60cdb352..e53599462 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -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); diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 1fccbaeaf..8da610a3a 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -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); diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index e2984e1d1..ccef79672 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -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)); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 689e9a744..2970dcee5 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -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) diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 4e05f7828..20b96bb76 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -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* diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 041635e15..52a5d93c4 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -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; diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 18a8d14f0..ea069d877 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -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; diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 4a5ae13c4..25bb512a8 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -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)); diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index 56808bc8a..9e5cb7fe5 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -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); diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index a5092708e..3d5518f3b 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -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)); diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 2c651ffbd..0b7e80962 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -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 diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 76343ded6..097f39fcf 100644 --- a/vtysh/vtysh.c +++ b/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); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index c584d7a90..ab1318209 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -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); diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 57042f8e6..a4985c423 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -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"); diff --git a/zebra/connected.c b/zebra/connected.c index 7b949c504..d34fd9021 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -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) { diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index f73506bf9..14905b738 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -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) { diff --git a/zebra/interface.c b/zebra/interface.c index 18588ee52..07570e64b 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -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); diff --git a/zebra/interface.h b/zebra/interface.h index 61c3359f3..e13721448 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -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), diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 9fd7bb1c2..ba028ed09 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -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 diff --git a/zebra/label_manager.c b/zebra/label_manager.c index f38206d8e..ace13eda7 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -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); diff --git a/zebra/main.c b/zebra/main.c index e26c8e3d6..19b16936d 100644 --- a/zebra/main.c +++ b/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); diff --git a/zebra/rib.h b/zebra/rib.h index c7e83480c..664afd01b 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -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 */ diff --git a/zebra/rt.h b/zebra/rt.h index 7f5bb4dd3..54d45b889 100644 --- a/zebra/rt.h +++ b/zebra/rt.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); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a77814668..20cc292e1 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -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); diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 0d1a80e73..6d4af1203 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -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 */ diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 69e45f9a6..ba45f54ad 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -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) diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 0d0a2cb3b..a6e0882ff 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -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; } diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 4c6fb002d..61051ba87 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -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]; } diff --git a/zebra/zebra_mroute.c b/zebra/zebra_mroute.c index 519c120a6..e9cd19ebe 100644 --- a/zebra/zebra_mroute.c +++ b/zebra/zebra_mroute.c @@ -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)); diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 5ede948e0..b3b9c6d18 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -81,7 +81,7 @@ int zebra_ns_init(void) zebra_vrf_init(); - zebra_ns_enable(0, (void **)&dzns); + zebra_ns_enable(NS_DEFAULT, (void **)&dzns); return 0; } diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 0c340d8d5..5d90b9be6 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -57,9 +57,6 @@ struct zebra_ns { #endif /* HAVE_RTADV */ }; -#define NS_DEFAULT 0 -#define NS_UNKNOWN UINT16_MAX - struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id); int zebra_ns_init(void); diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 769d2f566..7f5fd472f 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -432,7 +432,7 @@ static void if_bfd_session_update(struct interface *ifp, struct prefix *dp, } else { zlog_debug( "MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d " - "with src %s/%d and vrf %d %s event", + "with src %s/%d and vrf %u %s event", inet_ntop(dp->family, &dp->u.prefix, buf[0], INET6_ADDRSTRLEN), dp->prefixlen, @@ -816,6 +816,8 @@ int zebra_ptm_bfd_dst_register(struct zserv *client, u_short length, ptm_cb.out_data); zebra_ptm_send_message(ptm_cb.out_data, data_len); + return 0; + stream_failure: ptm_lib_cleanup_msg(ptm_hdl, out_ctxt); return 0; @@ -946,6 +948,8 @@ int zebra_ptm_bfd_dst_deregister(struct zserv *client, u_short length, zebra_ptm_send_message(ptm_cb.out_data, data_len); + return 0; + stream_failure: ptm_lib_cleanup_msg(ptm_hdl, out_ctxt); return 0; @@ -957,7 +961,7 @@ int zebra_ptm_bfd_client_register(struct zserv *client, { struct stream *s; unsigned int pid; - void *out_ctxt; + void *out_ctxt = NULL; char tmp_buf[64]; int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF; @@ -999,7 +1003,12 @@ int zebra_ptm_bfd_client_register(struct zserv *client, SET_FLAG(ptm_cb.client_flags[client->proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG); + + return 0; + stream_failure: + if (out_ctxt) + ptm_lib_cleanup_msg(ptm_hdl, out_ctxt); return 0; } diff --git a/zebra/zebra_ptm_redistribute.c b/zebra/zebra_ptm_redistribute.c index 1378ea186..8fddd400c 100644 --- a/zebra/zebra_ptm_redistribute.c +++ b/zebra/zebra_ptm_redistribute.c @@ -41,7 +41,7 @@ static int zsend_interface_bfd_update(int cmd, struct zserv *client, s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, vrf_id); + zclient_create_header(s, cmd, vrf_id); if (ifp) stream_putl(s, ifp->ifindex); else @@ -96,8 +96,7 @@ static int zsend_bfd_peer_replay(int cmd, struct zserv *client) s = client->obuf; stream_reset(s); - zserv_create_header( - s, cmd, VRF_DEFAULT); // Pending: adjust when multi-vrf bfd work + zclient_create_header(s, cmd, VRF_DEFAULT); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 41e14459b..c200e2dbb 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -256,7 +256,7 @@ struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re, if (src) nexthop->src.ipv4 = *src; nexthop->ifindex = ifindex; - ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id); + ifp = if_lookup_by_index(nexthop->ifindex, re->nh_vrf_id); /*Pending: need to think if null ifp here is ok during bootup? There was a crash because ifp here was coming to be NULL */ if (ifp) @@ -372,6 +372,12 @@ static void nexthop_set_resolved(afi_t afi, struct nexthop *newhop, break; } + /* Copy labels of the resolved route */ + if (newhop->nh_label) + nexthop_add_labels(resolved_hop, newhop->nh_label_type, + newhop->nh_label->num_labels, + &newhop->nh_label->label[0]); + resolved_hop->rparent = nexthop; nexthop_add(&nexthop->resolved, resolved_hop); } @@ -397,7 +403,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (set) { UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE); - zebra_deregister_rnh_static_nexthops(re->vrf_id, + zebra_deregister_rnh_static_nexthops(re->nh_vrf_id, nexthop->resolved, top); nexthops_free(nexthop->resolved); nexthop->resolved = NULL; @@ -416,7 +422,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, * address in the routing table. */ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) { - ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id); + ifp = if_lookup_by_index(nexthop->ifindex, re->nh_vrf_id); if (ifp && connected_is_unnumbered(ifp)) { if (if_is_operative(ifp)) return 1; @@ -444,7 +450,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, break; } /* Lookup table. */ - table = zebra_vrf_table(afi, SAFI_UNICAST, re->vrf_id); + table = zebra_vrf_table(afi, SAFI_UNICAST, re->nh_vrf_id); if (!table) return 0; @@ -832,7 +838,7 @@ static unsigned nexthop_active_check(struct route_node *rn, family = 0; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: - ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id); + ifp = if_lookup_by_index(nexthop->ifindex, re->nh_vrf_id); if (ifp && if_is_operative(ifp)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else @@ -860,7 +866,8 @@ static unsigned nexthop_active_check(struct route_node *rn, if (rn->p.family != AF_INET) family = AFI_IP6; if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) { - ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id); + ifp = if_lookup_by_index(nexthop->ifindex, + re->nh_vrf_id); if (ifp && if_is_operative(ifp)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else @@ -903,7 +910,7 @@ static unsigned nexthop_active_check(struct route_node *rn, memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr)); /* It'll get set if required inside */ - ret = zebra_route_map_check(family, re->type, p, nexthop, re->vrf_id, + ret = zebra_route_map_check(family, re->type, p, nexthop, re->nh_vrf_id, re->tag); if (ret == RMAP_DENYMATCH) { if (IS_ZEBRA_DEBUG_RIB) { @@ -911,7 +918,8 @@ static unsigned nexthop_active_check(struct route_node *rn, zlog_debug( "%u:%s: Filtering out with NH out %s due to route map", re->vrf_id, buf, - ifindex2ifname(nexthop->ifindex, re->vrf_id)); + ifindex2ifname(nexthop->ifindex, + re->nh_vrf_id)); } UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); } @@ -990,14 +998,19 @@ int zebra_rib_labeled_unicast(struct route_entry *re) return 1; } -void kernel_route_rib_pass_fail(struct prefix *p, struct route_entry *re, +void kernel_route_rib_pass_fail(struct route_node *rn, struct prefix *p, + struct route_entry *re, enum southbound_results res) { struct nexthop *nexthop; char buf[PREFIX_STRLEN]; + rib_dest_t *dest; + + dest = rib_dest_from_rnode(rn); switch (res) { case SOUTHBOUND_INSTALL_SUCCESS: + dest->selected_fib = re; for (ALL_NEXTHOPS(re->nexthop, nexthop)) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; @@ -1011,16 +1024,37 @@ void kernel_route_rib_pass_fail(struct prefix *p, struct route_entry *re, p, ZAPI_ROUTE_INSTALLED); break; case SOUTHBOUND_INSTALL_FAILURE: + /* + * I am not sure this is the right thing to do here + * but the code always set selected_fib before + * this assignment was moved here. + */ + dest->selected_fib = re; + zsend_route_notify_owner(re->type, re->instance, re->vrf_id, p, ZAPI_ROUTE_FAIL_INSTALL); zlog_warn("%u:%s: Route install failed", re->vrf_id, prefix2str(p, buf, sizeof(buf))); break; case SOUTHBOUND_DELETE_SUCCESS: + /* + * The case where selected_fib is not re is + * when we have received a system route + * that is overriding our installed route + * as such we should leave the selected_fib + * pointer alone + */ + if (dest->selected_fib == re) + dest->selected_fib = NULL; for (ALL_NEXTHOPS(re->nexthop, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); break; case SOUTHBOUND_DELETE_FAILURE: + /* + * Should we set this to NULL if the + * delete fails? + */ + dest->selected_fib = NULL; zlog_warn("%u:%s: Route Deletion failure", re->vrf_id, prefix2str(p, buf, sizeof(buf))); break; @@ -1075,7 +1109,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, * the kernel. */ hook_call(rib_update, rn, "installing in kernel"); - kernel_route_rib(p, src_p, old, re); + kernel_route_rib(rn, p, src_p, old, re); zvrf->installs++; return; @@ -1102,7 +1136,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) * the kernel. */ hook_call(rib_update, rn, "uninstalling from kernel"); - kernel_route_rib(p, src_p, re, NULL); + kernel_route_rib(rn, p, src_p, re, NULL); zvrf->removals++; return; @@ -1124,8 +1158,6 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re) /* If labeled-unicast route, uninstall transit LSP. */ if (zebra_rib_labeled_unicast(re)) zebra_mpls_lsp_uninstall(info->zvrf, rn, re); - - dest->selected_fib = NULL; } if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) { @@ -1210,7 +1242,6 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, return; } - dest->selected_fib = new; if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rn, buf, sizeof(buf)); @@ -1224,6 +1255,8 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (!RIB_SYSTEM_ROUTE(new)) rib_install_kernel(rn, new, NULL); + else + dest->selected_fib = new; UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); } @@ -1248,8 +1281,17 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); - - dest->selected_fib = NULL; + else { + /* + * We are setting this to NULL here + * because that is what we traditionally + * have been doing. I am not positive + * that this is the right thing to do + * but let's leave the code alone + * for the RIB_SYSTEM_ROUTE case + */ + dest->selected_fib = NULL; + } /* Update nexthop for route, reset changed flag. */ nexthop_active_update(rn, old, 1); @@ -1263,7 +1305,6 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, { struct nexthop *nexthop = NULL; int nh_active = 0; - int installed = 1; rib_dest_t *dest = rib_dest_from_rnode(rn); /* @@ -1313,11 +1354,23 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, zebra_mpls_lsp_install(zvrf, rn, new); rib_install_kernel(rn, new, old); + } else { + /* + * We do not need to install the + * selected route because it + * is already isntalled by + * the system( ie not us ) + * so just mark it as winning + * we do need to ensure that + * if we uninstall a route + * from ourselves we don't + * over write this pointer + */ + dest->selected_fib = NULL; } - /* If install succeeded or system route, cleanup flags * for prior route. */ - if (installed && new != old) { + if (new != old) { if (RIB_SYSTEM_ROUTE(new)) { if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); @@ -1328,10 +1381,6 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, NEXTHOP_FLAG_FIB); } } - - /* Update for redistribution. */ - if (installed) - dest->selected_fib = new; } /* @@ -1339,7 +1388,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, * failed, we * may need to uninstall and delete for redistribution. */ - if (!nh_active || !installed) { + if (!nh_active) { if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rn, buf, sizeof(buf)); @@ -1366,7 +1415,8 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); - dest->selected_fib = NULL; + else + dest->selected_fib = NULL; } } else { /* @@ -1379,12 +1429,12 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, * to add routes. */ if (!RIB_SYSTEM_ROUTE(new)) { - int in_fib = 0; + bool in_fib = false; for (ALL_NEXTHOPS(new->nexthop, nexthop)) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) { - in_fib = 1; + in_fib = true; break; } if (!in_fib) @@ -2431,6 +2481,11 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, UNSET_FLAG(rtnh->flags, NEXTHOP_FLAG_FIB); + /* + * This is a non FRR route + * as such we should mark + * it as deleted + */ dest->selected_fib = NULL; } else { /* This means someone else, other than Zebra, @@ -2496,9 +2551,10 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, } -int rib_add(afi_t afi, safi_t safi, vrf_id_t 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, +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) { struct route_entry *re; @@ -2514,6 +2570,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, re->mtu = mtu; re->table = table_id; re->vrf_id = vrf_id; + re->nh_vrf_id = nh_vrf_id; re->nexthop_num = 0; re->uptime = time(NULL); re->tag = tag; diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 33d0b3a64..8983bdee0 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -951,6 +951,8 @@ static void copy_state(struct rnh *rnh, struct route_entry *re, state->type = re->type; state->distance = re->distance; state->metric = re->metric; + state->vrf_id = re->vrf_id; + state->nh_vrf_id = re->vrf_id; route_entry_copy_nexthops(state, re->nexthop); rnh->state = state; @@ -1000,7 +1002,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, vrf_id); + zclient_create_header(s, cmd, vrf_id); stream_putw(s, rn->p.family); switch (rn->p.family) { diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 61af60b5d..4c619e578 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -1193,7 +1193,7 @@ static void *route_set_src_compile(const char *arg) union g_addr src, *psrc; if ((inet_pton(AF_INET6, arg, &src.ipv6) == 1) - || (src.ipv4.s_addr && (inet_pton(AF_INET, arg, &src.ipv4) == 1))) { + || (inet_pton(AF_INET, arg, &src.ipv4) == 1)) { psrc = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(union g_addr)); *psrc = src; return psrc; @@ -1329,7 +1329,7 @@ route_map_result_t zebra_nht_route_map_check(int family, int client_proto, struct nh_rmap_obj nh_obj; nh_obj.nexthop = nexthop; - nh_obj.vrf_id = re->vrf_id; + nh_obj.vrf_id = re->nh_vrf_id; nh_obj.source_protocol = re->type; nh_obj.metric = re->metric; nh_obj.tag = re->tag; diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index 751ea08a3..2e8ab11b0 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -91,7 +91,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.family = AF_INET; nh_p.prefixlen = IPV4_MAX_BITLEN; nh_p.u.prefix4 = si->addr.ipv4; - zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); + zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); break; case STATIC_IPV4_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv4_ifindex_add( @@ -111,7 +111,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.family = AF_INET6; nh_p.prefixlen = IPV6_MAX_BITLEN; nh_p.u.prefix6 = si->addr.ipv6; - zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); + zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); break; case STATIC_IPV6_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv6_ifindex_add( @@ -141,7 +141,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, */ if (si->type == STATIC_IPV4_GATEWAY || si->type == STATIC_IPV6_GATEWAY) - zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, + zebra_evaluate_rnh(si->nh_vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p); else rib_queue_add(rn); @@ -155,8 +155,9 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, re->metric = 0; re->mtu = 0; re->vrf_id = si->vrf_id; + re->nh_vrf_id = si->nh_vrf_id; re->table = - si->vrf_id + (si->vrf_id != VRF_DEFAULT) ? (zebra_vrf_lookup_by_id(si->vrf_id))->table_id : zebrad.rtm_table_default; re->nexthop_num = 0; @@ -169,7 +170,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.family = AF_INET; nh_p.prefixlen = IPV4_MAX_BITLEN; nh_p.u.prefix4 = si->addr.ipv4; - zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); + zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); break; case STATIC_IPV4_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv4_ifindex_add( @@ -189,7 +190,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.family = AF_INET6; nh_p.prefixlen = IPV6_MAX_BITLEN; nh_p.u.prefix6 = si->addr.ipv6; - zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); + zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); break; case STATIC_IPV6_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv6_ifindex_add( @@ -221,7 +222,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, if (si->type == STATIC_IPV4_GATEWAY || si->type == STATIC_IPV6_GATEWAY) { rib_addnode(rn, re, 0); - zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, + zebra_evaluate_rnh(si->nh_vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p); } else rib_addnode(rn, re, 1); @@ -378,6 +379,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, struct prefix_ipv6 *src_p, union g_addr *gate, const char *ifname, enum static_blackhole_type bh_type, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, + struct zebra_vrf *nh_zvrf, struct static_nh_label *snh_label) { struct route_node *rn; @@ -439,6 +441,8 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, si->bh_type = bh_type; si->tag = tag; si->vrf_id = zvrf_id(zvrf); + si->nh_vrf_id = zvrf_id(nh_zvrf); + if (ifname) strlcpy(si->ifname, ifname, sizeof(si->ifname)); si->ifindex = IFINDEX_INTERNAL; @@ -493,7 +497,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, else { struct interface *ifp; - ifp = if_lookup_by_name(ifname, zvrf_id(zvrf)); + ifp = if_lookup_by_name(ifname, zvrf_id(nh_zvrf)); if (ifp && ifp->ifindex != IFINDEX_INTERNAL) { si->ifindex = ifp->ifindex; static_install_route(afi, safi, p, src_p, si); diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h index 68fe73b0a..234e3e403 100644 --- a/zebra/zebra_static.h +++ b/zebra/zebra_static.h @@ -54,6 +54,7 @@ struct static_route { /* VRF identifier. */ vrf_id_t vrf_id; + vrf_id_t nh_vrf_id; /* Administrative distance. */ u_char distance; @@ -89,6 +90,7 @@ extern int static_add_route(afi_t, safi_t safi, u_char type, struct prefix *p, const char *ifname, enum static_blackhole_type bh_type, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, + struct zebra_vrf *nh_zvrf, struct static_nh_label *snh_label); extern int static_delete_route(afi_t, safi_t safi, u_char type, diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 1ae9eac61..246a7e7e4 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -456,6 +456,7 @@ struct route_table *zebra_vrf_other_route_table(afi_t afi, u_int32_t table_id, info->afi = afi; info->safi = SAFI_UNICAST; table->info = info; + table->cleanup = zebra_rtable_node_cleanup; zvrf->other_table[afi][table_id] = table; } @@ -476,12 +477,18 @@ static int vrf_config_write(struct vty *vty) if (!zvrf) continue; - if (strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) { + if (vrf->vrf_id != VRF_DEFAULT) vty_out(vty, "vrf %s\n", zvrf_name(zvrf)); - if (zvrf->l3vni) - vty_out(vty, " vni %u\n", zvrf->l3vni); + + static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route"); + static_config(vty, zvrf, AFI_IP, SAFI_MULTICAST, "ip mroute"); + static_config(vty, zvrf, AFI_IP6, SAFI_UNICAST, "ipv6 route"); + + if (vrf->vrf_id != VRF_DEFAULT && zvrf->l3vni) + vty_out(vty, " vni %u\n", zvrf->l3vni); + + if (vrf->vrf_id != VRF_DEFAULT) vty_out(vty, "!\n"); - } } return 0; } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 82b0157ad..f0be86222 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -78,13 +78,16 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, #define CMD_VNI_RANGE "(1-16777215)" /* General function for static route. */ -static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, - const char *negate, const char *dest_str, - const char *mask_str, const char *src_str, - const char *gate_str, const char *ifname, - const char *flag_str, const char *tag_str, - const char *distance_str, const char *vrf_id_str, - const char *label_str) +static int zebra_static_route_leak(struct vty *vty, + struct zebra_vrf *zvrf, + struct zebra_vrf *nh_zvrf, + afi_t afi, safi_t safi, + const char *negate, const char *dest_str, + const char *mask_str, const char *src_str, + const char *gate_str, const char *ifname, + const char *flag_str, const char *tag_str, + const char *distance_str, + const char *label_str) { int ret; u_char distance; @@ -95,7 +98,6 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, struct in_addr mask; enum static_blackhole_type bh_type = 0; route_tag_t tag = 0; - struct zebra_vrf *zvrf; u_char type; struct static_nh_label snh_label; @@ -145,14 +147,6 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, if (tag_str) tag = strtoul(tag_str, NULL, 10); - /* VRF id */ - zvrf = zebra_vrf_lookup_by_name(vrf_id_str); - - if (!zvrf) { - vty_out(vty, "%% vrf %s is not defined\n", vrf_id_str); - return CMD_WARNING_CONFIG_FAILED; - } - /* Labels */ memset(&snh_label, 0, sizeof(struct static_nh_label)); if (label_str) { @@ -239,7 +233,8 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, if (!negate) static_add_route(afi, safi, type, &p, src_p, gatep, ifname, - bh_type, tag, distance, zvrf, &snh_label); + bh_type, tag, distance, zvrf, nh_zvrf, + &snh_label); else static_delete_route(afi, safi, type, &p, src_p, gatep, ifname, tag, distance, zvrf, &snh_label); @@ -247,6 +242,31 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, return CMD_SUCCESS; } +static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, + const char *negate, const char *dest_str, + const char *mask_str, const char *src_str, + const char *gate_str, const char *ifname, + const char *flag_str, const char *tag_str, + const char *distance_str, const char *vrf_id_str, + const char *label_str) +{ + struct zebra_vrf *zvrf; + + /* VRF id */ + zvrf = zebra_vrf_lookup_by_name(vrf_id_str); + + if (!zvrf) { + vty_out(vty, "%% vrf %s is not defined\n", vrf_id_str); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, zvrf, afi, safi, + negate, dest_str, mask_str, src_str, + gate_str, ifname, flag_str, tag_str, + distance_str, label_str); +} + + /* Static unicast routes for multicast RPF lookup. */ DEFPY (ip_mroute_dist, ip_mroute_dist_cmd, @@ -387,6 +407,37 @@ DEFPY(ip_route_blackhole, tag_str, distance_str, vrf, label); } +DEFPY(ip_route_blackhole_vrf, + ip_route_blackhole_vrf_cmd, + "[no] ip route\ + <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \ + <reject|blackhole>$flag \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + }]", + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + MPLS_LABEL_HELPSTR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct zebra_vrf *zvrf = vrf->info; + + return zebra_static_route_leak(vty, zvrf, zvrf, + AFI_IP, SAFI_UNICAST, no, prefix, + mask_str, NULL, NULL, NULL, flag, + tag_str, distance_str, label); +} + DEFPY(ip_route_address_interface, ip_route_address_interface_cmd, "[no] ip route\ @@ -398,6 +449,7 @@ DEFPY(ip_route_address_interface, |(1-255)$distance \ |vrf NAME \ |label WORD \ + |nexthop-vrf NAME \ }]", NO_STR IP_STR "Establish static routes\n" @@ -411,16 +463,89 @@ DEFPY(ip_route_address_interface, "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR) + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) { + struct zebra_vrf *zvrf; + struct zebra_vrf *nh_zvrf; + const char *flag = NULL; if (ifname && !strncasecmp(ifname, "Null0", 5)) { flag = "Null0"; ifname = NULL; } - return zebra_static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix, - mask_str, NULL, gate_str, ifname, flag, - tag_str, distance_str, vrf, label); + + zvrf = zebra_vrf_lookup_by_name(vrf); + if (!zvrf) { + vty_out(vty, "%% vrf %s is not defined\n", + vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nexthop_vrf) + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + else + nh_zvrf = zvrf; + + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP, SAFI_UNICAST, no, prefix, + mask_str, NULL, gate_str, ifname, flag, + tag_str, distance_str, label); +} + +DEFPY(ip_route_address_interface_vrf, + ip_route_address_interface_vrf_cmd, + "[no] ip route\ + <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \ + A.B.C.D$gate \ + INTERFACE$ifname \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |nexthop-vrf NAME \ + }]", + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name. Specify 'Null0' (case-insensitive) for a \ + null route.\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + const char *flag = NULL; + struct zebra_vrf *zvrf = vrf->info; + struct zebra_vrf *nh_zvrf; + + if (ifname && !strncasecmp(ifname, "Null0", 5)) { + flag = "Null0"; + ifname = NULL; + } + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP, SAFI_UNICAST, no, prefix, + mask_str, NULL, gate_str, ifname, flag, + tag_str, distance_str, label); } DEFPY(ip_route, @@ -433,6 +558,7 @@ DEFPY(ip_route, |(1-255)$distance \ |vrf NAME \ |label WORD \ + |nexthop-vrf NAME \ }]", NO_STR IP_STR "Establish static routes\n" @@ -445,16 +571,88 @@ DEFPY(ip_route, "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR) + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) { + struct zebra_vrf *zvrf; + struct zebra_vrf *nh_zvrf; const char *flag = NULL; + if (ifname && !strncasecmp(ifname, "Null0", 5)) { flag = "Null0"; ifname = NULL; } - return zebra_static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix, - mask_str, NULL, gate_str, ifname, flag, - tag_str, distance_str, vrf, label); + + zvrf = zebra_vrf_lookup_by_name(vrf); + if (!zvrf) { + vty_out(vty, "%% vrf %s is not defined\n", + vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nexthop_vrf) + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + else + nh_zvrf = zvrf; + + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP, SAFI_UNICAST, no, prefix, + mask_str, NULL, gate_str, ifname, flag, + tag_str, distance_str, label); +} + +DEFPY(ip_route_vrf, + ip_route_vrf_cmd, + "[no] ip route\ + <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \ + <A.B.C.D$gate|INTERFACE$ifname> \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |nexthop-vrf NAME \ + }]", + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct zebra_vrf *zvrf = vrf->info; + struct zebra_vrf *nh_zvrf; + + const char *flag = NULL; + if (ifname && !strncasecmp(ifname, "Null0", 5)) { + flag = "Null0"; + ifname = NULL; + } + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP, SAFI_UNICAST, no, prefix, + mask_str, NULL, gate_str, ifname, flag, + tag_str, distance_str, label); } /* New RIB. Detailed information for IPv4 route. */ @@ -539,7 +737,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, if (nexthop->ifindex) vty_out(vty, ", via %s", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: @@ -549,12 +747,12 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, if (nexthop->ifindex) vty_out(vty, ", via %s", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); break; case NEXTHOP_TYPE_IFINDEX: vty_out(vty, " directly connected, %s", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); break; case NEXTHOP_TYPE_BLACKHOLE: vty_out(vty, " unreachable"); @@ -576,6 +774,14 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, default: break; } + + if (re->vrf_id != re->nh_vrf_id) { + struct vrf *vrf = + vrf_lookup_by_id(re->nh_vrf_id); + + vty_out(vty, "(vrf %s)", vrf->name); + } + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) vty_out(vty, " (duplicate nexthop removed)"); @@ -715,7 +921,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_string_add( json_nexthop, "interfaceName", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); } break; case NEXTHOP_TYPE_IPV6: @@ -734,7 +940,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_string_add( json_nexthop, "interfaceName", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); } break; @@ -747,7 +953,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_string_add( json_nexthop, "interfaceName", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); break; case NEXTHOP_TYPE_BLACKHOLE: json_object_boolean_true_add(json_nexthop, @@ -774,6 +980,14 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, break; } + if (re->nh_vrf_id != re->vrf_id) { + struct vrf *vrf = + vrf_lookup_by_id(re->nh_vrf_id); + + json_object_string_add(json_nexthop, + "vrf", + vrf->name); + } if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) json_object_boolean_true_add(json_nexthop, "duplicate"); @@ -881,7 +1095,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (nexthop->ifindex) vty_out(vty, ", %s", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: @@ -891,12 +1105,13 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (nexthop->ifindex) vty_out(vty, ", %s", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); break; case NEXTHOP_TYPE_IFINDEX: vty_out(vty, " is directly connected, %s", - ifindex2ifname(nexthop->ifindex, re->vrf_id)); + ifindex2ifname(nexthop->ifindex, + re->nh_vrf_id)); break; case NEXTHOP_TYPE_BLACKHOLE: vty_out(vty, " unreachable"); @@ -917,6 +1132,14 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, default: break; } + + if (re->nh_vrf_id != re->vrf_id) { + struct vrf *vrf = + vrf_lookup_by_id(re->nh_vrf_id); + + vty_out(vty, "(vrf %s)", vrf->name); + } + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) vty_out(vty, " inactive"); @@ -1181,7 +1404,7 @@ DEFUN (ip_nht_default_route, return CMD_SUCCESS; zebra_rnh_ip_default_route = 1; - zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(VRF_DEFAULT, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1197,7 +1420,7 @@ DEFUN (no_ip_nht_default_route, return CMD_SUCCESS; zebra_rnh_ip_default_route = 0; - zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(VRF_DEFAULT, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1212,7 +1435,7 @@ DEFUN (ipv6_nht_default_route, return CMD_SUCCESS; zebra_rnh_ipv6_default_route = 1; - zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(VRF_DEFAULT, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1228,7 +1451,7 @@ DEFUN (no_ipv6_nht_default_route, return CMD_SUCCESS; zebra_rnh_ipv6_default_route = 0; - zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(VRF_DEFAULT, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1603,97 +1826,98 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, } /* Write static route configuration. */ -static int static_config(struct vty *vty, afi_t afi, safi_t safi, - const char *cmd) +int static_config(struct vty *vty, struct zebra_vrf *zvrf, + afi_t afi, safi_t safi, const char *cmd) { + char spacing[100]; struct route_node *rn; struct static_route *si; struct route_table *stable; - struct vrf *vrf; - struct zebra_vrf *zvrf; char buf[SRCDEST2STR_BUFFER]; int write = 0; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - if (!(zvrf = vrf->info)) - continue; - if ((stable = zvrf->stable[afi][safi]) == NULL) - continue; + if ((stable = zvrf->stable[afi][safi]) == NULL) + return write; - for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) - for (si = rn->info; si; si = si->next) { - vty_out(vty, "%s %s", cmd, - srcdest_rnode2str(rn, buf, sizeof buf)); + sprintf(spacing, "%s%s", + (zvrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ", + cmd); - switch (si->type) { - case STATIC_IPV4_GATEWAY: - vty_out(vty, " %s", - inet_ntoa(si->addr.ipv4)); - break; - case STATIC_IPV6_GATEWAY: - vty_out(vty, " %s", - inet_ntop(AF_INET6, - &si->addr.ipv6, buf, - sizeof buf)); - break; - case STATIC_IFNAME: - vty_out(vty, " %s", si->ifname); - break; - case STATIC_BLACKHOLE: - switch (si->bh_type) { - case STATIC_BLACKHOLE_DROP: - vty_out(vty, " blackhole"); - break; - case STATIC_BLACKHOLE_NULL: - vty_out(vty, " Null0"); - break; - case STATIC_BLACKHOLE_REJECT: - vty_out(vty, " reject"); - break; - } + for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) + for (si = rn->info; si; si = si->next) { + vty_out(vty, "%s %s", spacing, + srcdest_rnode2str(rn, buf, sizeof buf)); + + switch (si->type) { + case STATIC_IPV4_GATEWAY: + vty_out(vty, " %s", + inet_ntoa(si->addr.ipv4)); + break; + case STATIC_IPV6_GATEWAY: + vty_out(vty, " %s", + inet_ntop(AF_INET6, + &si->addr.ipv6, buf, + sizeof buf)); + break; + case STATIC_IFNAME: + vty_out(vty, " %s", si->ifname); + break; + case STATIC_BLACKHOLE: + switch (si->bh_type) { + case STATIC_BLACKHOLE_DROP: + vty_out(vty, " blackhole"); break; - case STATIC_IPV4_GATEWAY_IFNAME: - vty_out(vty, " %s %s", - inet_ntop(AF_INET, - &si->addr.ipv4, buf, - sizeof buf), - si->ifname); + case STATIC_BLACKHOLE_NULL: + vty_out(vty, " Null0"); break; - case STATIC_IPV6_GATEWAY_IFNAME: - vty_out(vty, " %s %s", - inet_ntop(AF_INET6, - &si->addr.ipv6, buf, - sizeof buf), - si->ifname); + case STATIC_BLACKHOLE_REJECT: + vty_out(vty, " reject"); break; } + break; + case STATIC_IPV4_GATEWAY_IFNAME: + vty_out(vty, " %s %s", + inet_ntop(AF_INET, + &si->addr.ipv4, buf, + sizeof buf), + si->ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + vty_out(vty, " %s %s", + inet_ntop(AF_INET6, + &si->addr.ipv6, buf, + sizeof buf), + si->ifname); + break; + } - if (si->tag) - vty_out(vty, " tag %" ROUTE_TAG_PRI, - si->tag); + if (si->tag) + vty_out(vty, " tag %" ROUTE_TAG_PRI, + si->tag); - if (si->distance - != ZEBRA_STATIC_DISTANCE_DEFAULT) - vty_out(vty, " %d", si->distance); + if (si->distance + != ZEBRA_STATIC_DISTANCE_DEFAULT) + vty_out(vty, " %d", si->distance); - if (si->vrf_id != VRF_DEFAULT) - vty_out(vty, " vrf %s", - zvrf_name(zvrf)); + if (si->nh_vrf_id != si->vrf_id) { + struct vrf *vrf; + + vrf = vrf_lookup_by_id(si->nh_vrf_id); + vty_out(vty, " nexthop-vrf %s", + (vrf) ? vrf->name : "Unknown"); + } - /* Label information */ - if (si->snh_label.num_labels) - vty_out(vty, " label %s", - mpls_label2str( - si->snh_label - .num_labels, - si->snh_label.label, - buf, sizeof buf, 0)); + /* Label information */ + if (si->snh_label.num_labels) + vty_out(vty, " label %s", + mpls_label2str(si->snh_label.num_labels, + si->snh_label.label, + buf, sizeof buf, 0)); - vty_out(vty, "\n"); + vty_out(vty, "\n"); - write = 1; - } - } + write = 1; + } return write; } @@ -1727,6 +1951,38 @@ DEFPY(ipv6_route_blackhole, tag_str, distance_str, vrf, label); } +DEFPY(ipv6_route_blackhole_vrf, + ipv6_route_blackhole_vrf_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + <Null0|reject|blackhole>$flag \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + }]", + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "Null interface\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + MPLS_LABEL_HELPSTR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct zebra_vrf *zvrf = vrf->info; + + return zebra_static_route_leak(vty, zvrf, zvrf, + AFI_IP6, SAFI_UNICAST, no, prefix_str, + NULL, from_str, NULL, NULL, flag, + tag_str, distance_str, label); +} + DEFPY(ipv6_route_address_interface, ipv6_route_address_interface_cmd, "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ @@ -1737,6 +1993,7 @@ DEFPY(ipv6_route_address_interface, |(1-255)$distance \ |vrf NAME \ |label WORD \ + |nexthop-vrf NAME \ }]", NO_STR IPV6_STR @@ -1750,11 +2007,72 @@ DEFPY(ipv6_route_address_interface, "Tag value\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR) + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) { - return zebra_static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str, - NULL, from_str, gate_str, ifname, NULL, - tag_str, distance_str, vrf, label); + struct zebra_vrf *zvrf; + struct zebra_vrf *nh_zvrf; + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + zvrf = zebra_vrf_lookup_by_name(vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP6, SAFI_UNICAST, no, prefix_str, + NULL, from_str, gate_str, ifname, NULL, + tag_str, distance_str, label); +} + +DEFPY(ipv6_route_address_interface_vrf, + ipv6_route_address_interface_vrf_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + X:X::X:X$gate \ + INTERFACE$ifname \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |nexthop-vrf NAME \ + }]", + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct zebra_vrf *zvrf = vrf->info; + struct zebra_vrf *nh_zvrf; + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP6, SAFI_UNICAST, no, prefix_str, + NULL, from_str, gate_str, ifname, NULL, + tag_str, distance_str, label); } DEFPY(ipv6_route, @@ -1766,6 +2084,7 @@ DEFPY(ipv6_route, |(1-255)$distance \ |vrf NAME \ |label WORD \ + |nexthop-vrf NAME \ }]", NO_STR IPV6_STR @@ -1779,11 +2098,71 @@ DEFPY(ipv6_route, "Tag value\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR) + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) { - return zebra_static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str, - NULL, from_str, gate_str, ifname, NULL, - tag_str, distance_str, vrf, label); + struct zebra_vrf *zvrf; + struct zebra_vrf *nh_zvrf; + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + zvrf = zebra_vrf_lookup_by_name(vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP6, SAFI_UNICAST, no, prefix_str, + NULL, from_str, gate_str, ifname, NULL, + tag_str, distance_str, label); +} + +DEFPY(ipv6_route_vrf, + ipv6_route_vrf_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + <X:X::X:X$gate|INTERFACE$ifname> \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |nexthop-vrf NAME \ + }]", + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct zebra_vrf *zvrf = vrf->info; + struct zebra_vrf *nh_zvrf; + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP6, SAFI_UNICAST, no, prefix_str, + NULL, from_str, gate_str, ifname, NULL, + tag_str, distance_str, label); } /* @@ -1890,7 +2269,7 @@ DEFUN (show_vrf, RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { if (!(zvrf = vrf->info)) continue; - if (!zvrf_id(zvrf)) + if (zvrf_id(zvrf) == VRF_DEFAULT) continue; vty_out(vty, "vrf %s ", zvrf_name(zvrf)); @@ -2419,11 +2798,8 @@ static int zebra_ip_config(struct vty *vty) { int write = 0; - write += static_config(vty, AFI_IP, SAFI_UNICAST, "ip route"); - write += static_config(vty, AFI_IP, SAFI_MULTICAST, "ip mroute"); - write += static_config(vty, AFI_IP6, SAFI_UNICAST, "ipv6 route"); - write += zebra_import_table_config(vty); + return write; } @@ -2859,8 +3235,11 @@ void zebra_vty_init(void) install_element(CONFIG_NODE, &ip_multicast_mode_cmd); install_element(CONFIG_NODE, &no_ip_multicast_mode_cmd); install_element(CONFIG_NODE, &ip_route_blackhole_cmd); + install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd); install_element(CONFIG_NODE, &ip_route_address_interface_cmd); + install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd); install_element(CONFIG_NODE, &ip_route_cmd); + install_element(VRF_NODE, &ip_route_vrf_cmd); install_element(CONFIG_NODE, &ip_zebra_import_table_distance_cmd); install_element(CONFIG_NODE, &no_ip_zebra_import_table_cmd); install_element(CONFIG_NODE, &zebra_workqueue_timer_cmd); @@ -2882,8 +3261,11 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_ip_rpf_addr_cmd); install_element(CONFIG_NODE, &ipv6_route_blackhole_cmd); + install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd); install_element(CONFIG_NODE, &ipv6_route_address_interface_cmd); + install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd); install_element(CONFIG_NODE, &ipv6_route_cmd); + install_element(VRF_NODE, &ipv6_route_vrf_cmd); install_element(CONFIG_NODE, &ip_nht_default_route_cmd); install_element(CONFIG_NODE, &no_ip_nht_default_route_cmd); install_element(CONFIG_NODE, &ipv6_nht_default_route_cmd); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 0ef180236..1690079f6 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1166,7 +1166,7 @@ static int zvni_macip_send_msg_to_client(vni_t vni, s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, VRF_DEFAULT); + zclient_create_header(s, cmd, VRF_DEFAULT); stream_putl(s, vni); stream_put(s, macaddr->octet, ETH_ALEN); if (ip) { @@ -2531,7 +2531,7 @@ static int zvni_send_add_to_client(zebra_vni_t *zvni) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT); + zclient_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT); stream_putl(s, zvni->vni); stream_put_in_addr(s, &zvni->local_vtep_ip); stream_put(s, &zvni->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */ @@ -2565,7 +2565,7 @@ static int zvni_send_del_to_client(vni_t vni) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_VNI_DEL, VRF_DEFAULT); + zclient_create_header(s, ZEBRA_VNI_DEL, VRF_DEFAULT); stream_putl(s, vni); /* Write packet size. */ @@ -3550,7 +3550,7 @@ static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_L3VNI_ADD, + zclient_create_header(s, ZEBRA_L3VNI_ADD, zl3vni_vrf_id(zl3vni)); stream_putl(s, zl3vni->vni); stream_put(s, &rmac, sizeof(struct ethaddr)); @@ -3586,7 +3586,7 @@ static int zl3vni_send_del_to_client(zebra_l3vni_t *zl3vni) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_L3VNI_DEL, + zclient_create_header(s, ZEBRA_L3VNI_DEL, zl3vni_vrf_id(zl3vni)); stream_putl(s, zl3vni->vni); diff --git a/zebra/zserv.c b/zebra/zserv.c index 7eded89f6..3ee2bb59e 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -149,16 +149,6 @@ int zebra_server_send_message(struct zserv *client) return 0; } -void zserv_create_header(struct stream *s, uint16_t cmd, vrf_id_t vrf_id) -{ - /* length placeholder, caller can update */ - stream_putw(s, ZEBRA_HEADER_SIZE); - stream_putc(s, ZEBRA_HEADER_MARKER); - stream_putc(s, ZSERV_VERSION); - stream_putw(s, vrf_id); - stream_putw(s, cmd); -} - static void zserv_encode_interface(struct stream *s, struct interface *ifp) { /* Interface information. */ @@ -221,7 +211,7 @@ int zsend_interface_add(struct zserv *client, struct interface *ifp) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); zserv_encode_interface(s, ifp); client->ifadd_cnt++; @@ -236,7 +226,7 @@ int zsend_interface_delete(struct zserv *client, struct interface *ifp) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); zserv_encode_interface(s, ifp); client->ifdel_cnt++; @@ -250,7 +240,7 @@ int zsend_vrf_add(struct zserv *client, struct zebra_vrf *zvrf) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_VRF_ADD, zvrf_id(zvrf)); + zclient_create_header(s, ZEBRA_VRF_ADD, zvrf_id(zvrf)); zserv_encode_vrf(s, zvrf); client->vrfadd_cnt++; @@ -265,7 +255,7 @@ int zsend_vrf_delete(struct zserv *client, struct zebra_vrf *zvrf) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_VRF_DELETE, zvrf_id(zvrf)); + zclient_create_header(s, ZEBRA_VRF_DELETE, zvrf_id(zvrf)); zserv_encode_vrf(s, zvrf); client->vrfdel_cnt++; @@ -285,7 +275,7 @@ int zsend_interface_link_params(struct zserv *client, struct interface *ifp) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id); /* Add Interface Index */ stream_putl(s, ifp->ifindex); @@ -348,7 +338,7 @@ int zsend_interface_address(int cmd, struct zserv *client, s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, ifp->vrf_id); + zclient_create_header(s, cmd, ifp->vrf_id); stream_putl(s, ifp->ifindex); /* Interface address flag. */ @@ -393,7 +383,7 @@ static int zsend_interface_nbr_address(int cmd, struct zserv *client, s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, ifp->vrf_id); + zclient_create_header(s, cmd, ifp->vrf_id); stream_putl(s, ifp->ifindex); /* Prefix information. */ @@ -504,11 +494,11 @@ int zsend_interface_vrf_update(struct zserv *client, struct interface *ifp, s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf_id); /* Fill in the ifIndex of the interface and its new VRF (id) */ stream_putl(s, ifp->ifindex); - stream_putw(s, vrf_id); + stream_putl(s, vrf_id); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -581,7 +571,7 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp) s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, ifp->vrf_id); + zclient_create_header(s, cmd, ifp->vrf_id); zserv_encode_interface(s, ifp); if (cmd == ZEBRA_INTERFACE_UP) @@ -602,6 +592,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p, memset(&api, 0, sizeof(api)); api.vrf_id = re->vrf_id; + api.nh_vrf_id = re->nh_vrf_id; api.type = re->type; api.instance = re->instance; api.flags = re->flags; @@ -957,7 +948,7 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, stream_reset(s); /* Fill in result. */ - zserv_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, zvrf_id(zvrf)); + zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, zvrf_id(zvrf)); stream_put_in_addr(s, &addr); if (re) { @@ -1009,7 +1000,7 @@ int zsend_route_notify_owner(u_char proto, u_short instance, s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, vrf_id); + zclient_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, vrf_id); stream_put(s, ¬e, sizeof(note)); @@ -1039,7 +1030,7 @@ int zsend_router_id_update(struct zserv *client, struct prefix *p, stream_reset(s); /* Message type. */ - zserv_create_header(s, ZEBRA_ROUTER_ID_UPDATE, vrf_id); + zclient_create_header(s, ZEBRA_ROUTER_ID_UPDATE, vrf_id); /* Prefix information. */ stream_putc(s, p->family); @@ -1063,7 +1054,7 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id); + zclient_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id); stream_write(s, pw->ifname, IF_NAMESIZE); stream_putl(s, pw->ifindex); stream_putl(s, pw->status); @@ -1146,6 +1137,7 @@ static int zread_route_add(struct zserv *client, u_short length, re->flags = api.flags; re->uptime = time(NULL); re->vrf_id = vrf_id; + re->nh_vrf_id = api.nh_vrf_id; re->table = zvrf->table_id; if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { @@ -1372,6 +1364,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, /* VRF ID */ re->vrf_id = zvrf_id(zvrf); + re->nh_vrf_id = zvrf_id(zvrf); /* Nexthop parse. */ if (CHECK_FLAG(message, ZAPI_MESSAGE_NEXTHOP)) { @@ -1581,6 +1574,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, /* VRF ID */ re->vrf_id = zvrf_id(zvrf); + re->nh_vrf_id = zvrf_id(zvrf); /* We need to give nh-addr, nh-ifindex with the same next-hop object * to the re to ensure that IPv6 multipathing works; need to coalesce @@ -1866,6 +1860,8 @@ static int zread_ipv6_add(struct zserv *client, u_short length, /* VRF ID */ re->vrf_id = zvrf_id(zvrf); + re->nh_vrf_id = zvrf_id(zvrf); + re->table = zvrf->table_id; ret = rib_add_multipath(AFI_IP6, safi, &p, src_pp, re); @@ -2089,7 +2085,7 @@ static int zsend_label_manager_connect_response(struct zserv *client, s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id); + zclient_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id); /* result */ stream_putc(s, result); @@ -2151,7 +2147,7 @@ static int zsend_assign_label_chunk_response(struct zserv *client, s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id); + zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id); if (lmc) { /* keep */ @@ -2472,11 +2468,11 @@ static int zread_interface_set_master(struct zserv *client, int ifindex; vrf_id_t vrf_id; - STREAM_GETW(s, vrf_id); + STREAM_GETL(s, vrf_id); STREAM_GETL(s, ifindex); master = if_lookup_by_index(ifindex, vrf_id); - STREAM_GETW(s, vrf_id); + STREAM_GETL(s, vrf_id); STREAM_GETL(s, ifindex); slave = if_lookup_by_index(ifindex, vrf_id); @@ -2714,7 +2710,7 @@ static int zebra_client_read(struct thread *thread) STREAM_GETW(client->ibuf, length); STREAM_GETC(client->ibuf, marker); STREAM_GETC(client->ibuf, version); - STREAM_GETW(client->ibuf, vrf_id); + STREAM_GETL(client->ibuf, vrf_id); STREAM_GETW(client->ibuf, command); if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { diff --git a/zebra/zserv.h b/zebra/zserv.h index 63db9d9eb..4b3b0041b 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -177,8 +177,6 @@ extern int zsend_route_notify_owner(u_char proto, u_short instance, vrf_id_t vrf_id, struct prefix *p, enum zapi_route_notify_owner note); -extern void zserv_create_header(struct stream *s, uint16_t cmd, - vrf_id_t vrf_id); extern void zserv_nexthop_num_warn(const char *, const struct prefix *, const unsigned int); extern int zebra_server_send_message(struct zserv *client); |