diff options
539 files changed, 14716 insertions, 6387 deletions
diff --git a/.gitignore b/.gitignore index 05fcd6ce4..bf6df9ad6 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ /aclocal.m4 /libtool /libtool.orig +/changelog-auto /Makefile /Makefile.in diff --git a/Makefile.am b/Makefile.am index c56a551aa..6e3c2a418 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,8 @@ AUTOMAKE_OPTIONS = subdir-objects 1.12 ACLOCAL_AMFLAGS = -I m4 AM_CFLAGS = \ + $(LIBYANG_CFLAGS) \ + $(SQLITE3_CFLAGS) \ $(UNWIND_CFLAGS) \ $(SAN_FLAGS) \ $(WERROR) \ @@ -17,7 +19,6 @@ AM_LDFLAGS = \ $(SAN_FLAGS) \ # end DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE) -LIBCAP = @LIBCAP@ AR_FLAGS = @AR_FLAGS@ ARFLAGS = @ARFLAGS@ @@ -123,7 +124,6 @@ include watchfrr/subdir.am include qpb/subdir.am include fpm/subdir.am include tools/subdir.am -include debianpkg/subdir.am include solaris/subdir.am include bgpd/subdir.am @@ -169,6 +169,8 @@ EXTRA_DIST += \ m4/README.txt \ m4/libtool-whole-archive.patch \ config.version \ + changelog-auto \ + changelog-auto.in \ \ python/clidef.py \ python/clippy/__init__.py \ @@ -226,8 +228,8 @@ noinst_HEADERS += defaults.h clean-local: clean-python .PHONY: clean-python clean-python: - find -name __pycache__ -o -name .pytest_cache | xargs rm -rf - find -name "*.pyc" -o -name "*_clippy.c" | xargs rm -f + find . -name __pycache__ -o -name .pytest_cache | xargs rm -rf + find . -name "*.pyc" -o -name "*_clippy.c" | xargs rm -f redistclean: $(MAKE) distclean CONFIG_CLEAN_FILES="$(filter-out $(EXTRA_DIST), $(CONFIG_CLEAN_FILES))" @@ -18,6 +18,8 @@ FRR currently supports the following protocols: * LDP * BFD * Babel +* PBR +* OpenFabric * EIGRP (alpha) * NHRP (alpha) diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index a8698bfce..79242f5b8 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -1262,7 +1262,7 @@ DEFUN (show_babel_parameters, } void -babel_if_init () +babel_if_init(void) { /* initialize interface list */ hook_register_prio(if_add, 0, babel_if_new_hook); diff --git a/babeld/babeld.c b/babeld/babeld.c index 702c1fbab..39451b435 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -307,7 +307,7 @@ babel_initial_noise(void) /* Delete all the added babel routes, make babeld only speak to zebra. */ static void -babel_clean_routing_process() +babel_clean_routing_process(void) { flush_all_routes(); babel_interface_close_all(); diff --git a/babeld/message.c b/babeld/message.c index f85a08ac3..794b6e997 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -1430,7 +1430,7 @@ send_wildcard_retraction(struct interface *ifp) } void -update_myseqno() +update_myseqno(void) { myseqno = seqno_plus(myseqno, 1); } diff --git a/babeld/neighbour.c b/babeld/neighbour.c index 83f05bb5c..d962a0961 100644 --- a/babeld/neighbour.c +++ b/babeld/neighbour.c @@ -234,7 +234,7 @@ neighbour_txcost(struct neighbour *neigh) } unsigned -check_neighbours() +check_neighbours(void) { struct neighbour *neigh; int changed, rc; diff --git a/babeld/resend.c b/babeld/resend.c index 8949075f6..f08897fbd 100644 --- a/babeld/resend.c +++ b/babeld/resend.c @@ -238,7 +238,7 @@ satisfy_request(const unsigned char *prefix, unsigned char plen, } void -expire_resend() +expire_resend(void) { struct resend *current, *previous; int recompute = 0; @@ -267,7 +267,7 @@ expire_resend() } void -recompute_resend_time() +recompute_resend_time(void) { struct resend *request; struct timeval resend = {0, 0}; @@ -286,7 +286,7 @@ recompute_resend_time() } void -do_resend() +do_resend(void) { struct resend *resend; diff --git a/babeld/route.c b/babeld/route.c index 76f038cda..ab104aa2b 100644 --- a/babeld/route.c +++ b/babeld/route.c @@ -248,7 +248,7 @@ flush_route(struct babel_route *route) } void -flush_all_routes() +flush_all_routes(void) { int i; diff --git a/babeld/source.c b/babeld/source.c index ed165b41b..2c303b624 100644 --- a/babeld/source.c +++ b/babeld/source.c @@ -135,7 +135,7 @@ update_source(struct source *src, } void -expire_sources() +expire_sources(void) { struct source *src; diff --git a/babeld/subdir.am b/babeld/subdir.am index e1f2cb0a0..7081c730a 100644 --- a/babeld/subdir.am +++ b/babeld/subdir.am @@ -51,4 +51,4 @@ noinst_HEADERS += \ # end babeld_babeld_SOURCES = babeld/babel_main.c -babeld_babeld_LDADD = babeld/libbabel.a lib/libfrr.la @LIBCAP@ +babeld_babeld_LDADD = babeld/libbabel.a lib/libfrr.la $(LIBCAP) diff --git a/babeld/util.c b/babeld/util.c index 880cda2fc..c6606e4f0 100644 --- a/babeld/util.c +++ b/babeld/util.c @@ -441,7 +441,7 @@ uchar_to_in6addr(struct in6_addr *dest, const unsigned char *src) } int -daemonise() +daemonise(void) { int rc; diff --git a/babeld/xroute.c b/babeld/xroute.c index 88e9479e4..61ea5a1ac 100644 --- a/babeld/xroute.c +++ b/babeld/xroute.c @@ -169,7 +169,7 @@ add_xroute(unsigned char prefix[16], unsigned char plen, /* Returns an overestimate of the number of xroutes. */ int -xroutes_estimate() +xroutes_estimate(void) { return numxroutes; } diff --git a/bfdd/Makefile b/bfdd/Makefile new file mode 100644 index 000000000..dfe78232c --- /dev/null +++ b/bfdd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. bfdd/bfdd +%: ALWAYS + @$(MAKE) -s -C .. bfdd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/bfdd/bfd.c b/bfdd/bfd.c index df263a91c..afd5d814a 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -36,23 +36,80 @@ DEFINE_QOBJ_TYPE(bfd_session); /* * Prototypes */ +static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc); + static uint32_t ptm_bfd_gen_ID(void); static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd); static void bfd_session_free(struct bfd_session *bs); -static struct bfd_session *bfd_session_new(int sd); +static struct bfd_session *bfd_session_new(void); static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa, uint32_t ldisc); static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc); static const char *get_diag_str(int diag); +static void bs_admin_down_handler(struct bfd_session *bs, int nstate); +static void bs_down_handler(struct bfd_session *bs, int nstate); +static void bs_init_handler(struct bfd_session *bs, int nstate); +static void bs_up_handler(struct bfd_session *bs, int nstate); + /* * Functions */ +static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc) +{ + struct bfd_session_observer *bso; + struct bfd_session *bs = NULL; + bool is_shop, is_ipv4; + + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + bs = bso->bso_bs; + + is_shop = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH); + is_ipv4 = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6); + /* Quick checks first. */ + if (is_shop != (!bpc->bpc_mhop)) + continue; + if (is_ipv4 != bpc->bpc_ipv4) + continue; + + /* + * Slow lookup without hash because we don't have all + * information yet. + */ + if (is_shop) { + if (strcmp(bs->ifname, bpc->bpc_localif)) + continue; + if (memcmp(&bs->shop.peer, &bpc->bpc_peer, + sizeof(bs->shop.peer))) + continue; + + break; + } + + if (strcmp(bs->vrfname, bpc->bpc_vrfname)) + continue; + if (memcmp(&bs->mhop.peer, &bpc->bpc_peer, + sizeof(bs->mhop.peer))) + continue; + if (memcmp(&bs->mhop.local, &bpc->bpc_local, + sizeof(bs->mhop.local))) + continue; + + break; + } + if (bso == NULL) + bs = NULL; + + return bs; +} + struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) { struct bfd_session *bs; struct peer_label *pl; + struct interface *ifp; + struct vrf *vrf; struct bfd_mhop_key mhop; struct bfd_shop_key shop; @@ -70,29 +127,190 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) memset(&mhop, 0, sizeof(mhop)); mhop.peer = bpc->bpc_peer; mhop.local = bpc->bpc_local; - if (bpc->bpc_has_vrfname) - strlcpy(mhop.vrf_name, bpc->bpc_vrfname, - sizeof(mhop.vrf_name)); + if (bpc->bpc_has_vrfname) { + vrf = vrf_lookup_by_name(bpc->bpc_vrfname); + if (vrf == NULL) + return NULL; + + mhop.vrfid = vrf->vrf_id; + } bs = bfd_mhop_lookup(mhop); } else { memset(&shop, 0, sizeof(shop)); shop.peer = bpc->bpc_peer; - if (bpc->bpc_has_localif) - strlcpy(shop.port_name, bpc->bpc_localif, - sizeof(shop.port_name)); + if (bpc->bpc_has_localif) { + ifp = if_lookup_by_name_all_vrf(bpc->bpc_localif); + if (ifp == NULL) + return NULL; + + shop.ifindex = ifp->ifindex; + } bs = bfd_shop_lookup(shop); } - return bs; + if (bs != NULL) + return bs; + + /* Search for entries that are incomplete. */ + return bs_peer_waiting_find(bpc); +} + +/* + * Starts a disabled BFD session. + * + * A session is disabled when the specified interface/VRF doesn't exist + * yet. It might happen on FRR boot or with virtual interfaces. + */ +int bfd_session_enable(struct bfd_session *bs) +{ + struct sockaddr_in6 *sin6; + struct interface *ifp = NULL; + struct vrf *vrf = NULL; + int psock; + + /* + * If the interface or VRF doesn't exist, then we must register + * the session but delay its start. + */ + if (bs->ifname[0] != 0) { + ifp = if_lookup_by_name_all_vrf(bs->ifname); + if (ifp == NULL) { + log_error( + "session-enable: specified interface doesn't exists."); + return 0; + } + + vrf = vrf_lookup_by_id(ifp->vrf_id); + if (vrf == NULL) { + log_error("session-enable: specified VRF doesn't exists."); + return 0; + } + } + + if (bs->vrfname[0] != 0) { + vrf = vrf_lookup_by_name(bs->vrfname); + if (vrf == NULL) { + log_error("session-enable: specified VRF doesn't exists."); + return 0; + } + } + + /* Assign interface/VRF pointers. */ + bs->vrf = vrf; + if (bs->vrf == NULL) + bs->vrf = vrf_lookup_by_id(VRF_DEFAULT); + + if (bs->ifname[0] != 0 && + BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) + bs->ifp = ifp; + + /* Set the IPv6 scope id for link-local addresses. */ + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) { + sin6 = &bs->mhop.peer.sa_sin6; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + sin6->sin6_scope_id = bs->ifp != NULL + ? bs->ifp->ifindex + : IFINDEX_INTERNAL; + + sin6 = &bs->mhop.local.sa_sin6; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + sin6->sin6_scope_id = bs->ifp != NULL + ? bs->ifp->ifindex + : IFINDEX_INTERNAL; + + bs->local_ip.sa_sin6 = *sin6; + bs->local_address.sa_sin6 = *sin6; + } + + /* + * Get socket for transmitting control packets. Note that if we + * could use the destination port (3784) for the source + * port we wouldn't need a socket per session. + */ + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) { + psock = bp_peer_socket(bs); + if (psock == -1) + return -1; + } else { + psock = bp_peer_socketv6(bs); + if (psock == -1) + return -1; + } + + /* + * We've got a valid socket, lets start the timers and the + * protocol. + */ + bs->sock = psock; + bfd_recvtimer_update(bs); + ptm_bfd_start_xmt_timer(bs, false); + + /* Registrate session into data structures. */ + bs->discrs.my_discr = ptm_bfd_gen_ID(); + bfd_id_insert(bs); + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { + if (vrf != NULL) + bs->mhop.vrfid = vrf->vrf_id; + else + bs->mhop.vrfid = VRF_DEFAULT; + + bfd_mhop_insert(bs); + } else { + if (ifp != NULL) + bs->shop.ifindex = ifp->ifindex; + else + bs->shop.ifindex = IFINDEX_INTERNAL; + + bfd_shop_insert(bs); + } + + return 0; +} + +/* + * Disabled a running BFD session. + * + * A session is disabled when the specified interface/VRF gets removed + * (e.g. virtual interfaces). + */ +void bfd_session_disable(struct bfd_session *bs) +{ + /* Free up socket resources. */ + if (bs->sock != -1) { + close(bs->sock); + bs->sock = -1; + } + + /* Disable all timers. */ + bfd_recvtimer_delete(bs); + bfd_echo_recvtimer_delete(bs); + bfd_xmttimer_delete(bs); + bfd_echo_xmttimer_delete(bs); + + /* Unregister session from hashes to avoid unwanted activation. */ + bfd_id_delete(bs->discrs.my_discr); + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) + bfd_mhop_delete(bs->mhop); + else + bfd_shop_delete(bs->shop); } static uint32_t ptm_bfd_gen_ID(void) { - static uint32_t sessionID = 1; + uint32_t session_id; + + /* + * RFC 5880, Section 6.8.1. recommends that we should generate + * random session identification numbers. + */ + do { + session_id = ((random() << 16) & 0xFFFF0000) + | (random() & 0x0000FFFF); + } while (session_id == 0 || bfd_id_lookup(session_id) != NULL); - return (sessionID++); + return session_id; } void ptm_bfd_start_xmt_timer(struct bfd_session *bfd, bool is_echo) @@ -137,7 +355,7 @@ void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit) ptm_bfd_start_xmt_timer(bfd, false); } -void ptm_bfd_echo_stop(struct bfd_session *bfd, int polling) +void ptm_bfd_echo_stop(struct bfd_session *bfd) { bfd->echo_xmt_TO = 0; bfd->echo_detect_TO = 0; @@ -145,13 +363,6 @@ void ptm_bfd_echo_stop(struct bfd_session *bfd, int polling) bfd_echo_xmttimer_delete(bfd); bfd_echo_recvtimer_delete(bfd); - - if (polling) { - bfd->polling = polling; - bfd->new_timers.desired_min_tx = bfd->up_min_tx; - bfd->new_timers.required_min_rx = bfd->timers.required_min_rx; - ptm_bfd_snd(bfd, 0); - } } void ptm_bfd_echo_start(struct bfd_session *bfd) @@ -159,11 +370,6 @@ void ptm_bfd_echo_start(struct bfd_session *bfd) bfd->echo_detect_TO = (bfd->remote_detect_mult * bfd->echo_xmt_TO); if (bfd->echo_detect_TO > 0) ptm_bfd_echo_xmt_TO(bfd); - - bfd->polling = 1; - bfd->new_timers.desired_min_tx = bfd->up_min_tx; - bfd->new_timers.required_min_rx = bfd->timers.required_min_rx; - ptm_bfd_snd(bfd, 0); } void ptm_bfd_ses_up(struct bfd_session *bfd) @@ -172,17 +378,13 @@ void ptm_bfd_ses_up(struct bfd_session *bfd) bfd->local_diag = 0; bfd->ses_state = PTM_BFD_UP; - bfd->polling = 1; monotime(&bfd->uptime); - /* If the peer is capable to receiving Echo pkts */ - if (bfd->echo_xmt_TO && !BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MH)) { - ptm_bfd_echo_start(bfd); - } else { - bfd->new_timers.desired_min_tx = bfd->up_min_tx; - bfd->new_timers.required_min_rx = bfd->timers.required_min_rx; - ptm_bfd_snd(bfd, 0); - } + /* Connection is up, lets negotiate timers. */ + bfd_set_polling(bfd); + + /* Start sending control packets with poll bit immediately. */ + ptm_bfd_snd(bfd, 0); control_notify(bfd); @@ -207,13 +409,16 @@ void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag) ptm_bfd_snd(bfd, 0); + /* Slow down the control packets, the connection is down. */ + bs_set_slow_timers(bfd); + /* only signal clients when going from up->down state */ if (old_state == PTM_BFD_UP) control_notify(bfd); /* Stop echo packet transmission if they are active */ if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) - ptm_bfd_echo_stop(bfd, 0); + ptm_bfd_echo_stop(bfd); if (old_state != bfd->ses_state) { bfd->stats.session_down++; @@ -224,25 +429,6 @@ void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag) } } -static int ptm_bfd_get_vrf_name(char *port_name, char *vrf_name) -{ - struct bfd_iface *iface; - struct bfd_vrf *vrf; - - if ((port_name == NULL) || (vrf_name == NULL)) - return -1; - - iface = bfd_iface_lookup(port_name); - if (iface) { - vrf = bfd_vrf_lookup(iface->vrf_id); - if (vrf) { - strlcpy(vrf_name, vrf->name, sizeof(vrf->name)); - return 0; - } - } - return -1; -} - static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa, uint32_t ldisc) { @@ -269,15 +455,15 @@ static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa, return NULL; } -struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, char *port_name, +struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, struct sockaddr_any *peer, struct sockaddr_any *local, - char *vrf_name, bool is_mhop) + ifindex_t ifindex, vrf_id_t vrfid, + bool is_mhop) { struct bfd_session *l_bfd = NULL; struct bfd_mhop_key mhop; struct bfd_shop_key shop; - char vrf_buf[MAXNAMELEN]; /* Find our session using the ID signaled by the remote end. */ if (cp->discrs.remote_discr) @@ -288,22 +474,13 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, char *port_name, memset(&mhop, 0, sizeof(mhop)); mhop.peer = *peer; mhop.local = *local; - if (vrf_name && vrf_name[0]) { - strlcpy(mhop.vrf_name, vrf_name, sizeof(mhop.vrf_name)); - } else if (port_name && port_name[0]) { - memset(vrf_buf, 0, sizeof(vrf_buf)); - if (ptm_bfd_get_vrf_name(port_name, vrf_buf) != -1) - strlcpy(mhop.vrf_name, vrf_buf, - sizeof(mhop.vrf_name)); - } + mhop.vrfid = vrfid; l_bfd = bfd_mhop_lookup(mhop); } else { memset(&shop, 0, sizeof(shop)); shop.peer = *peer; - if (port_name && port_name[0]) - strlcpy(shop.port_name, port_name, - sizeof(shop.port_name)); + shop.ifindex = ifindex; l_bfd = bfd_shop_lookup(shop); } @@ -369,7 +546,7 @@ int bfd_echo_recvtimer_cb(struct thread *t) return 0; } -static struct bfd_session *bfd_session_new(int sd) +static struct bfd_session *bfd_session_new(void) { struct bfd_session *bs; @@ -379,13 +556,21 @@ static struct bfd_session *bfd_session_new(int sd) QOBJ_REG(bs, bfd_session); - bs->up_min_tx = BFD_DEFDESIREDMINTX; + bs->timers.desired_min_tx = BFD_DEFDESIREDMINTX; bs->timers.required_min_rx = BFD_DEFREQUIREDMINRX; bs->timers.required_min_echo = BFD_DEF_REQ_MIN_ECHO; bs->detect_mult = BFD_DEFDETECTMULT; bs->mh_ttl = BFD_DEF_MHOP_TTL; + bs->ses_state = PTM_BFD_DOWN; + + /* Initiate connection with slow timers. */ + bs_set_slow_timers(bs); - bs->sock = sd; + /* Initiate remote settings as well. */ + bs->remote_timers = bs->cur_timers; + bs->remote_detect_mult = BFD_DEFDETECTMULT; + + bs->sock = -1; monotime(&bs->uptime); bs->downtime = bs->uptime; @@ -434,22 +619,21 @@ static void _bfd_session_update(struct bfd_session *bs, goto skip_echo; BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO); - ptm_bfd_echo_start(bs); /* Activate/update echo receive timeout timer. */ - bfd_echo_recvtimer_update(bs); + bs_echo_timer_handler(bs); } else { /* Check if echo mode is already disabled. */ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) goto skip_echo; BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO); - ptm_bfd_echo_stop(bs, 0); + ptm_bfd_echo_stop(bs); } skip_echo: if (bpc->bpc_has_txinterval) - bs->up_min_tx = bpc->bpc_txinterval * 1000; + bs->timers.desired_min_tx = bpc->bpc_txinterval * 1000; if (bpc->bpc_has_recvinterval) bs->timers.required_min_rx = bpc->bpc_recvinterval * 1000; @@ -480,7 +664,9 @@ skip_echo: bs->ses_state = PTM_BFD_ADM_DOWN; control_notify(bs); - ptm_bfd_snd(bs, 0); + /* Don't try to send packets with a disabled session. */ + if (bs->sock != -1) + ptm_bfd_snd(bs, 0); } else { /* Check if already working. */ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) @@ -495,10 +681,6 @@ skip_echo: /* Enable all timers. */ bfd_recvtimer_update(bs); bfd_xmttimer_update(bs, bs->xmt_TO); - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) { - bfd_echo_recvtimer_update(bs); - bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO); - } } } @@ -517,19 +699,19 @@ static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) static void bfd_session_free(struct bfd_session *bs) { - if (bs->sock != -1) - close(bs->sock); + struct bfd_session_observer *bso; - bfd_recvtimer_delete(bs); - bfd_echo_recvtimer_delete(bs); - bfd_xmttimer_delete(bs); - bfd_echo_xmttimer_delete(bs); + bfd_session_disable(bs); - bfd_id_delete(bs->discrs.my_discr); - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) - bfd_mhop_delete(bs->mhop); - else - bfd_shop_delete(bs->shop); + /* Remove observer if any. */ + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + if (bso->bso_bs != bs) + continue; + + break; + } + if (bso != NULL) + bs_observer_del(bso); pl_free(bs->pl); @@ -540,8 +722,6 @@ static void bfd_session_free(struct bfd_session *bs) struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc) { struct bfd_session *bfd, *l_bfd; - struct interface *ifp = NULL; - int psock; /* check to see if this needs a new session */ l_bfd = bs_peer_find(bpc); @@ -553,105 +733,51 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc) return NULL; } - /* - * No session found, we have to allocate a new one. - * - * First a few critical checks: - * - * * Check that the specified interface exists. - * * Attempt to create the UDP socket (might fail if we exceed - * our limits). - */ - if (bpc->bpc_has_localif) { - ifp = if_lookup_by_name(bpc->bpc_localif, VRF_DEFAULT); - if (ifp == NULL) { - log_error( - "session-new: specified interface doesn't exists."); - return NULL; - } - } - - /* - * Get socket for transmitting control packets. Note that if we - * could use the destination port (3784) for the source - * port we wouldn't need a socket per session. - */ - if (bpc->bpc_ipv4) { - psock = bp_peer_socket(bpc); - if (psock == -1) - return NULL; - } else { - psock = bp_peer_socketv6(bpc); - if (psock == -1) - return NULL; - } - - /* Get memory */ - bfd = bfd_session_new(psock); + /* Get BFD session storage with its defaults. */ + bfd = bfd_session_new(); if (bfd == NULL) { log_error("session-new: allocation failed"); return NULL; } - if (bpc->bpc_has_localif && !bpc->bpc_mhop) - bfd->ifp = ifp; - - if (bpc->bpc_ipv4 == false) { - BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6); - - /* Set the IPv6 scope id for link-local addresses. */ - if (IN6_IS_ADDR_LINKLOCAL(&bpc->bpc_local.sa_sin6.sin6_addr)) - bpc->bpc_local.sa_sin6.sin6_scope_id = - bfd->ifp != NULL ? bfd->ifp->ifindex - : IFINDEX_INTERNAL; - if (IN6_IS_ADDR_LINKLOCAL(&bpc->bpc_peer.sa_sin6.sin6_addr)) - bpc->bpc_peer.sa_sin6.sin6_scope_id = - bfd->ifp != NULL ? bfd->ifp->ifindex - : IFINDEX_INTERNAL; - } + /* + * Store interface/VRF name in case we need to delay session + * start. See `bfd_session_enable` for more information. + */ + if (bpc->bpc_has_localif) + strlcpy(bfd->ifname, bpc->bpc_localif, sizeof(bfd->ifname)); - /* Initialize the session */ - bfd->ses_state = PTM_BFD_DOWN; - bfd->discrs.my_discr = ptm_bfd_gen_ID(); - bfd->discrs.remote_discr = 0; - bfd->local_ip = bpc->bpc_local; - bfd->local_address = bpc->bpc_local; - bfd->timers.desired_min_tx = bfd->up_min_tx; - bfd->detect_TO = (bfd->detect_mult * BFD_DEF_SLOWTX); + if (bpc->bpc_has_vrfname) + strlcpy(bfd->vrfname, bpc->bpc_vrfname, sizeof(bfd->vrfname)); - /* Use detect_TO first for slow detection, then use recvtimer_update. */ - bfd_recvtimer_update(bfd); + /* Add observer if we have moving parts. */ + if (bfd->ifname[0] || bfd->vrfname[0]) + bs_observer_add(bfd); - bfd_id_insert(bfd); + /* Copy remaining data. */ + if (bpc->bpc_ipv4 == false) + BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6); if (bpc->bpc_mhop) { BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH); bfd->mhop.peer = bpc->bpc_peer; bfd->mhop.local = bpc->bpc_local; - if (bpc->bpc_has_vrfname) - strlcpy(bfd->mhop.vrf_name, bpc->bpc_vrfname, - sizeof(bfd->mhop.vrf_name)); - - bfd_mhop_insert(bfd); } else { bfd->shop.peer = bpc->bpc_peer; - if (bpc->bpc_has_localif) - strlcpy(bfd->shop.port_name, bpc->bpc_localif, - sizeof(bfd->shop.port_name)); - - bfd_shop_insert(bfd); } - /* - * XXX: session update triggers echo start, so we must have our - * discriminator ID set first. - */ - _bfd_session_update(bfd, bpc); + bfd->local_ip = bpc->bpc_local; + bfd->local_address = bpc->bpc_local; - /* Start transmitting with slow interval until peer responds */ - bfd->xmt_TO = BFD_DEF_SLOWTX; + /* Try to enable session and schedule for packet receive/send. */ + if (bfd_session_enable(bfd) == -1) { + /* Unrecoverable failure, remove the session/peer. */ + bfd_session_free(bfd); + return NULL; + } - ptm_bfd_xmt_TO(bfd, 0); + /* Apply other configurations. */ + _bfd_session_update(bfd, bpc); log_info("session-new: %s", bs_to_string(bfd)); @@ -688,12 +814,268 @@ int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc) void bfd_set_polling(struct bfd_session *bs) { - bs->new_timers.desired_min_tx = bs->up_min_tx; - bs->new_timers.required_min_rx = bs->timers.required_min_rx; - bs->new_timers.required_min_echo = bs->timers.required_min_echo; + /* + * Start polling procedure: the only timers that require polling + * to change value without losing connection are: + * + * - Desired minimum transmission interval; + * - Required minimum receive interval; + * + * RFC 5880, Section 6.8.3. + */ bs->polling = 1; } +/* + * bs_<state>_handler() functions implement the BFD state machine + * transition mechanism. `<state>` is the current session state and + * the parameter `nstate` is the peer new state. + */ +static void bs_admin_down_handler(struct bfd_session *bs + __attribute__((__unused__)), + int nstate __attribute__((__unused__))) +{ + /* + * We are administratively down, there is no state machine + * handling. + */ +} + +static void bs_down_handler(struct bfd_session *bs, int nstate) +{ + switch (nstate) { + case PTM_BFD_ADM_DOWN: + /* + * Remote peer doesn't want to talk, so lets keep the + * connection down. + */ + case PTM_BFD_UP: + /* Peer can't be up yet, wait it go to 'init' or 'down'. */ + break; + + case PTM_BFD_DOWN: + /* + * Remote peer agreed that the path is down, lets try to + * bring it up. + */ + bs->ses_state = PTM_BFD_INIT; + break; + + case PTM_BFD_INIT: + /* + * Remote peer told us his path is up, lets turn + * activate the session. + */ + ptm_bfd_ses_up(bs); + break; + + default: + log_debug("state-change: unhandled neighbor state: %d", nstate); + break; + } +} + +static void bs_init_handler(struct bfd_session *bs, int nstate) +{ + switch (nstate) { + case PTM_BFD_ADM_DOWN: + /* + * Remote peer doesn't want to talk, so lets make the + * connection down. + */ + bs->ses_state = PTM_BFD_DOWN; + break; + + case PTM_BFD_DOWN: + /* Remote peer hasn't moved to first stage yet. */ + break; + + case PTM_BFD_INIT: + case PTM_BFD_UP: + /* We agreed on the settings and the path is up. */ + ptm_bfd_ses_up(bs); + break; + + default: + log_debug("state-change: unhandled neighbor state: %d", nstate); + break; + } +} + +static void bs_up_handler(struct bfd_session *bs, int nstate) +{ + switch (nstate) { + case PTM_BFD_ADM_DOWN: + case PTM_BFD_DOWN: + /* Peer lost or asked to shutdown connection. */ + ptm_bfd_ses_dn(bs, BD_NEIGHBOR_DOWN); + break; + + case PTM_BFD_INIT: + case PTM_BFD_UP: + /* Path is up and working. */ + break; + + default: + log_debug("state-change: unhandled neighbor state: %d", nstate); + break; + } +} + +void bs_state_handler(struct bfd_session *bs, int nstate) +{ + switch (bs->ses_state) { + case PTM_BFD_ADM_DOWN: + bs_admin_down_handler(bs, nstate); + break; + case PTM_BFD_DOWN: + bs_down_handler(bs, nstate); + break; + case PTM_BFD_INIT: + bs_init_handler(bs, nstate); + break; + case PTM_BFD_UP: + bs_up_handler(bs, nstate); + break; + + default: + log_debug("state-change: [%s] is in invalid state: %d", + bs_to_string(bs), nstate); + break; + } +} + +/* + * Handles echo timer manipulation after updating timer. + */ +void bs_echo_timer_handler(struct bfd_session *bs) +{ + uint32_t old_timer; + + /* + * Before doing any echo handling, check if it is possible to + * use it. + * + * - Check for `echo-mode` configuration. + * - Check that we are not using multi hop (RFC 5883, + * Section 3). + * - Check that we are already at the up state. + */ + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO) == 0 + || BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) + || bs->ses_state != PTM_BFD_UP) + return; + + /* Remote peer asked to stop echo. */ + if (bs->remote_timers.required_min_echo == 0) { + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) + ptm_bfd_echo_stop(bs); + + return; + } + + /* + * Calculate the echo transmission timer: we must not send + * echo packets faster than the minimum required time + * announced by the remote system. + * + * RFC 5880, Section 6.8.9. + */ + old_timer = bs->echo_xmt_TO; + if (bs->remote_timers.required_min_echo > bs->timers.required_min_echo) + bs->echo_xmt_TO = bs->remote_timers.required_min_echo; + else + bs->echo_xmt_TO = bs->timers.required_min_echo; + + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO_ACTIVE) == 0 + || old_timer != bs->echo_xmt_TO) + ptm_bfd_echo_start(bs); +} + +/* + * RFC 5880 Section 6.5. + * + * When a BFD control packet with the final bit is received, we must + * update the session parameters. + */ +void bs_final_handler(struct bfd_session *bs) +{ + /* Start using our new timers. */ + bs->cur_timers.desired_min_tx = bs->timers.desired_min_tx; + bs->cur_timers.required_min_rx = bs->timers.required_min_rx; + + /* + * TODO: demand mode. See RFC 5880 Section 6.1. + * + * When using demand mode we must disable the detection timer + * for lost control packets. + */ + if (bs->demand_mode) { + /* Notify watchers about changed timers. */ + control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); + return; + } + + /* + * Calculate detection time based on new timers. + * + * Transmission calculation: + * We must respect the RequiredMinRxInterval from the remote + * system: if our desired transmission timer is more than the + * minimum receive rate, then we must lower it to at least the + * minimum receive interval. + * + * RFC 5880, Section 6.8.3. + */ + if (bs->timers.desired_min_tx > bs->remote_timers.required_min_rx) + bs->xmt_TO = bs->remote_timers.required_min_rx; + else + bs->xmt_TO = bs->timers.desired_min_tx; + + /* Apply new transmission timer immediately. */ + ptm_bfd_start_xmt_timer(bs, false); + + /* + * Detection timeout calculation: + * The minimum detection timeout is the remote detection + * multipler (number of packets to be missed) times the agreed + * transmission interval. + * + * RFC 5880, Section 6.8.4. + * + * TODO: support sending/counting more packets inside detection + * timeout. + */ + if (bs->remote_timers.required_min_rx > bs->timers.desired_min_tx) + bs->detect_TO = bs->remote_detect_mult + * bs->remote_timers.required_min_rx; + else + bs->detect_TO = bs->remote_detect_mult + * bs->timers.desired_min_tx; + + /* Apply new receive timer immediately. */ + bfd_recvtimer_update(bs); + + /* Notify watchers about changed timers. */ + control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); +} + +void bs_set_slow_timers(struct bfd_session *bs) +{ + /* + * BFD connection must use slow timers before going up or after + * losing connectivity to avoid wasting bandwidth. + * + * RFC 5880, Section 6.8.3. + */ + bs->cur_timers.desired_min_tx = BFD_DEF_SLOWTX; + bs->cur_timers.required_min_rx = BFD_DEF_SLOWTX; + bs->cur_timers.required_min_echo = 0; + + /* Set the appropriated timeouts for slow connection. */ + bs->detect_TO = (BFD_DEFDETECTMULT * BFD_DEF_SLOWTX); + bs->xmt_TO = BFD_DEF_SLOWTX; +} /* * Helper functions. @@ -851,9 +1233,9 @@ const char *bs_to_string(struct bfd_session *bs) " peer:%s local:%s", satostr(&bs->mhop.peer), satostr(&bs->mhop.local)); - if (bs->mhop.vrf_name[0]) - snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s", - bs->mhop.vrf_name); + if (bs->mhop.vrfid != VRF_DEFAULT) + snprintf(buf + pos, sizeof(buf) - pos, " vrf:%u", + bs->mhop.vrfid); } else { pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s", satostr(&bs->shop.peer)); @@ -863,14 +1245,39 @@ const char *bs_to_string(struct bfd_session *bs) " local:%s", satostr(&bs->local_address)); - if (bs->shop.port_name[0]) - snprintf(buf + pos, sizeof(buf) - pos, " interface:%s", - bs->shop.port_name); + if (bs->shop.ifindex) + snprintf(buf + pos, sizeof(buf) - pos, " ifindex:%u", + bs->shop.ifindex); } return buf; } +int bs_observer_add(struct bfd_session *bs) +{ + struct bfd_session_observer *bso; + + bso = XMALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso)); + bso->bso_bs = bs; + bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH); + if (bso->bso_isinterface) + strlcpy(bso->bso_entryname, bs->ifname, + sizeof(bso->bso_entryname)); + else + strlcpy(bso->bso_entryname, bs->vrfname, + sizeof(bso->bso_entryname)); + + TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry); + + return 0; +} + +void bs_observer_del(struct bfd_session_observer *bso) +{ + TAILQ_REMOVE(&bglobal.bg_obslist, bso, bso_entry); + XFREE(MTYPE_BFDD_SESSION_OBSERVER, bso); +} + /* * BFD hash data structures to find sessions. @@ -878,24 +1285,17 @@ const char *bs_to_string(struct bfd_session *bs) static struct hash *bfd_id_hash; static struct hash *bfd_shop_hash; static struct hash *bfd_mhop_hash; -static struct hash *bfd_vrf_hash; -static struct hash *bfd_iface_hash; static unsigned int bfd_id_hash_do(void *p); static unsigned int bfd_shop_hash_do(void *p); static unsigned int bfd_mhop_hash_do(void *p); -static unsigned int bfd_vrf_hash_do(void *p); -static unsigned int bfd_iface_hash_do(void *p); static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop); static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop); static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop); -static int _iface_key(struct bfd_iface *iface, const char *ifname); -static void _bfd_free(struct hash_backet *hb, +static void _bfd_free(struct hash_bucket *hb, void *arg __attribute__((__unused__))); -static void _vrf_free(void *arg); -static void _iface_free(void *arg); /* BFD hash for our discriminator. */ static unsigned int bfd_id_hash_do(void *p) @@ -942,36 +1342,6 @@ static bool bfd_mhop_hash_cmp(const void *n1, const void *n2) return memcmp(&bs1->mhop, &bs2->mhop, sizeof(bs1->mhop)) == 0; } -/* BFD hash for VRFs. */ -static unsigned int bfd_vrf_hash_do(void *p) -{ - struct bfd_vrf *vrf = p; - - return jhash_1word(vrf->vrf_id, 0); -} - -static bool bfd_vrf_hash_cmp(const void *n1, const void *n2) -{ - const struct bfd_vrf *v1 = n1, *v2 = n2; - - return v1->vrf_id == v2->vrf_id; -} - -/* BFD hash for interfaces. */ -static unsigned int bfd_iface_hash_do(void *p) -{ - struct bfd_iface *iface = p; - - return string_hash_make(iface->ifname); -} - -static bool bfd_iface_hash_cmp(const void *n1, const void *n2) -{ - const struct bfd_iface *i1 = n1, *i2 = n2; - - return strcmp(i1->ifname, i2->ifname) == 0; -} - /* Helper functions */ static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop) { @@ -991,7 +1361,7 @@ static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop) static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop) { _shop_key(bs, shop); - memset(bs->shop.port_name, 0, sizeof(bs->shop.port_name)); + bs->shop.ifindex = IFINDEX_INTERNAL; } static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop) @@ -1011,17 +1381,6 @@ static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop) } } -static int _iface_key(struct bfd_iface *iface, const char *ifname) -{ - size_t slen = sizeof(iface->ifname); - - memset(iface->ifname, 0, slen); - if (strlcpy(iface->ifname, ifname, slen) >= slen) - return -1; - - return 0; -} - /* * Hash public interface / exported functions. */ @@ -1043,7 +1402,7 @@ struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop) _shop_key(&bs, &shop); bsp = hash_lookup(bfd_shop_hash, &bs); - if (bsp == NULL && bs.shop.port_name[0] != 0) { + if (bsp == NULL && bs.shop.ifindex != 0) { /* * Since the local interface spec is optional, try * searching the key without it as well. @@ -1064,25 +1423,6 @@ struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop) return hash_lookup(bfd_mhop_hash, &bs); } -struct bfd_vrf *bfd_vrf_lookup(int vrf_id) -{ - struct bfd_vrf vrf; - - vrf.vrf_id = vrf_id; - - return hash_lookup(bfd_vrf_hash, &vrf); -} - -struct bfd_iface *bfd_iface_lookup(const char *ifname) -{ - struct bfd_iface iface; - - if (_iface_key(&iface, ifname) != 0) - return NULL; - - return hash_lookup(bfd_iface_hash, &iface); -} - /* * Delete functions. * @@ -1108,7 +1448,7 @@ struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop) _shop_key(&bs, &shop); bsp = hash_release(bfd_shop_hash, &bs); - if (bsp == NULL && shop.port_name[0] != 0) { + if (bsp == NULL && shop.ifindex != 0) { /* * Since the local interface spec is optional, try * searching the key without it as well. @@ -1129,25 +1469,6 @@ struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop) return hash_release(bfd_mhop_hash, &bs); } -struct bfd_vrf *bfd_vrf_delete(int vrf_id) -{ - struct bfd_vrf vrf; - - vrf.vrf_id = vrf_id; - - return hash_release(bfd_vrf_hash, &vrf); -} - -struct bfd_iface *bfd_iface_delete(const char *ifname) -{ - struct bfd_iface iface; - - if (_iface_key(&iface, ifname) != 0) - return NULL; - - return hash_release(bfd_iface_hash, &iface); -} - /* Iteration functions. */ void bfd_id_iterate(hash_iter_func hif, void *arg) { @@ -1164,16 +1485,6 @@ void bfd_mhop_iterate(hash_iter_func hif, void *arg) hash_iterate(bfd_mhop_hash, hif, arg); } -void bfd_vrf_iterate(hash_iter_func hif, void *arg) -{ - hash_iterate(bfd_vrf_hash, hif, arg); -} - -void bfd_iface_iterate(hash_iter_func hif, void *arg) -{ - hash_iterate(bfd_iface_hash, hif, arg); -} - /* * Insert functions. * @@ -1195,16 +1506,6 @@ bool bfd_mhop_insert(struct bfd_session *bs) return (hash_get(bfd_mhop_hash, bs, hash_alloc_intern) == bs); } -bool bfd_vrf_insert(struct bfd_vrf *vrf) -{ - return (hash_get(bfd_vrf_hash, vrf, hash_alloc_intern) == vrf); -} - -bool bfd_iface_insert(struct bfd_iface *iface) -{ - return (hash_get(bfd_iface_hash, iface, hash_alloc_intern) == iface); -} - void bfd_initialize(void) { bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp, @@ -1213,13 +1514,9 @@ void bfd_initialize(void) "BFD single hop hash"); bfd_mhop_hash = hash_create(bfd_mhop_hash_do, bfd_mhop_hash_cmp, "BFD multihop hop hash"); - bfd_vrf_hash = - hash_create(bfd_vrf_hash_do, bfd_vrf_hash_cmp, "BFD VRF hash"); - bfd_iface_hash = hash_create(bfd_iface_hash_do, bfd_iface_hash_cmp, - "BFD interface hash"); } -static void _bfd_free(struct hash_backet *hb, +static void _bfd_free(struct hash_bucket *hb, void *arg __attribute__((__unused__))) { struct bfd_session *bs = hb->data; @@ -1227,20 +1524,6 @@ static void _bfd_free(struct hash_backet *hb, bfd_session_free(bs); } -static void _vrf_free(void *arg) -{ - struct bfd_vrf *vrf = arg; - - XFREE(MTYPE_BFDD_CONFIG, vrf); -} - -static void _iface_free(void *arg) -{ - struct bfd_iface *iface = arg; - - XFREE(MTYPE_BFDD_CONFIG, iface); -} - void bfd_shutdown(void) { /* @@ -1254,14 +1537,8 @@ void bfd_shutdown(void) assert(bfd_shop_hash->count == 0); assert(bfd_mhop_hash->count == 0); - /* Clean the VRF and interface hashes. */ - hash_clean(bfd_vrf_hash, _vrf_free); - hash_clean(bfd_iface_hash, _iface_free); - /* Now free the hashes themselves. */ hash_free(bfd_id_hash); hash_free(bfd_shop_hash); hash_free(bfd_mhop_hash); - hash_free(bfd_vrf_hash); - hash_free(bfd_iface_hash); } diff --git a/bfdd/bfd.h b/bfdd/bfd.h index a3e5ad144..7451ca82a 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -35,8 +35,6 @@ #include "bfdctl.h" -#define ETHERNET_ADDRESS_LENGTH 6 - #ifdef BFD_DEBUG #define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY) #else @@ -48,6 +46,7 @@ DECLARE_MTYPE(BFDD_TMP); DECLARE_MTYPE(BFDD_CONFIG); DECLARE_MTYPE(BFDD_LABEL); DECLARE_MTYPE(BFDD_CONTROL); +DECLARE_MTYPE(BFDD_SESSION_OBSERVER); DECLARE_MTYPE(BFDD_NOTIFICATION); struct bfd_timers { @@ -176,13 +175,13 @@ enum bfd_session_flags { /* BFD session hash keys */ struct bfd_shop_key { struct sockaddr_any peer; - char port_name[MAXNAMELEN + 1]; + ifindex_t ifindex; }; struct bfd_mhop_key { struct sockaddr_any peer; struct sockaddr_any local; - char vrf_name[MAXNAMELEN + 1]; + vrf_id_t vrfid; }; struct bfd_session_stats { @@ -214,8 +213,7 @@ struct bfd_session { /* Timers */ struct bfd_timers timers; - struct bfd_timers new_timers; - uint32_t up_min_tx; + struct bfd_timers cur_timers; uint64_t detect_TO; struct thread *echo_recvtimer_ev; struct thread *recvtimer_ev; @@ -239,8 +237,9 @@ struct bfd_session { struct sockaddr_any local_address; struct sockaddr_any local_ip; struct interface *ifp; - uint8_t local_mac[ETHERNET_ADDRESS_LENGTH]; - uint8_t peer_mac[ETHERNET_ADDRESS_LENGTH]; + struct vrf *vrf; + char ifname[MAXNAMELEN]; + char vrfname[MAXNAMELEN]; /* BFD session flags */ enum bfd_session_flags flags; @@ -279,15 +278,14 @@ struct bfd_state_str_list { int type; }; -struct bfd_vrf { - int vrf_id; - char name[MAXNAMELEN + 1]; -} bfd_vrf; +struct bfd_session_observer { + struct bfd_session *bso_bs; + bool bso_isinterface; + char bso_entryname[MAXNAMELEN]; -struct bfd_iface { - int vrf_id; - char ifname[MAXNAMELEN + 1]; -} bfd_iface; + TAILQ_ENTRY(bfd_session_observer) bso_entry; +}; +TAILQ_HEAD(obslist, bfd_session_observer); /* States defined per 4.1 */ @@ -299,15 +297,12 @@ struct bfd_iface { /* Various constants */ /* Retrieved from ptm_timer.h from Cumulus PTM sources. */ -#define MSEC_PER_SEC 1000L -#define NSEC_PER_MSEC 1000000L - #define BFD_DEF_DEMAND 0 #define BFD_DEFDETECTMULT 3 -#define BFD_DEFDESIREDMINTX (300 * MSEC_PER_SEC) -#define BFD_DEFREQUIREDMINRX (300 * MSEC_PER_SEC) -#define BFD_DEF_REQ_MIN_ECHO (50 * MSEC_PER_SEC) -#define BFD_DEF_SLOWTX (2000 * MSEC_PER_SEC) +#define BFD_DEFDESIREDMINTX (300 * 1000) /* microseconds. */ +#define BFD_DEFREQUIREDMINRX (300 * 1000) /* microseconds. */ +#define BFD_DEF_REQ_MIN_ECHO (50 * 1000) /* microseconds. */ +#define BFD_DEF_SLOWTX (1000 * 1000) /* microseconds. */ #define BFD_DEF_MHOP_TTL 5 #define BFD_PKT_LEN 24 /* Length of control packet */ #define BFD_TTL_VAL 255 @@ -321,8 +316,6 @@ struct bfd_iface { #define BFD_DEFDESTPORT 3784 #define BFD_DEF_ECHO_PORT 3785 #define BFD_DEF_MHOP_DEST_PORT 4784 -#define BFD_CMD_STRING_LEN (MAXNAMELEN + 50) -#define BFD_BUFFER_LEN (BFD_CMD_STRING_LEN + MAXNAMELEN + 1) /* * control.c @@ -402,6 +395,8 @@ struct bfd_global { struct bcslist bg_bcslist; struct pllist bg_pllist; + + struct obslist bg_obslist; }; extern struct bfd_global bglobal; extern struct bfd_diag_str_list diag_list[]; @@ -470,8 +465,8 @@ int bp_udp_shop(void); int bp_udp_mhop(void); int bp_udp6_shop(void); int bp_udp6_mhop(void); -int bp_peer_socket(struct bfd_peer_cfg *bpc); -int bp_peer_socketv6(struct bfd_peer_cfg *bpc); +int bp_peer_socket(const struct bfd_session *bs); +int bp_peer_socketv6(const struct bfd_session *bs); int bp_echo_socket(void); int bp_echov6_socket(void); @@ -509,28 +504,38 @@ void bfd_echo_xmttimer_assign(struct bfd_session *bs, bfd_ev_cb cb); * * BFD protocol specific code. */ +int bfd_session_enable(struct bfd_session *bs); +void bfd_session_disable(struct bfd_session *bs); struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc); int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc); void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag); void ptm_bfd_ses_up(struct bfd_session *bfd); -void ptm_bfd_echo_stop(struct bfd_session *bfd, int polling); +void ptm_bfd_echo_stop(struct bfd_session *bfd); void ptm_bfd_echo_start(struct bfd_session *bfd); void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit); void ptm_bfd_start_xmt_timer(struct bfd_session *bfd, bool is_echo); -struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, char *port_name, +struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, struct sockaddr_any *peer, struct sockaddr_any *local, - char *vrf_name, bool is_mhop); + ifindex_t ifindex, vrf_id_t vrfid, + bool is_mhop); struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc); int bfd_session_update_label(struct bfd_session *bs, const char *nlabel); void bfd_set_polling(struct bfd_session *bs); +void bs_state_handler(struct bfd_session *bs, int nstate); +void bs_echo_timer_handler(struct bfd_session *bs); +void bs_final_handler(struct bfd_session *bs); +void bs_set_slow_timers(struct bfd_session *bs); const char *satostr(struct sockaddr_any *sa); const char *diag2str(uint8_t diag); int strtosa(const char *addr, struct sockaddr_any *sa); void integer2timestr(uint64_t time, char *buf, size_t buflen); const char *bs_to_string(struct bfd_session *bs); +int bs_observer_add(struct bfd_session *bs); +void bs_observer_del(struct bfd_session_observer *bso); + /* BFD hash data structures interface */ void bfd_initialize(void); void bfd_shutdown(void); @@ -552,7 +557,7 @@ bool bfd_mhop_insert(struct bfd_session *bs); bool bfd_vrf_insert(struct bfd_vrf *vrf); bool bfd_iface_insert(struct bfd_iface *iface); -typedef void (*hash_iter_func)(struct hash_backet *hb, void *arg); +typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg); void bfd_id_iterate(hash_iter_func hif, void *arg); void bfd_shop_iterate(hash_iter_func hif, void *arg); void bfd_mhop_iterate(hash_iter_func hif, void *arg); diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 9cfd7e866..45c5f5dbd 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -47,12 +47,10 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data, static void bfd_sd_reschedule(int sd); ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, - char *port, size_t portlen, char *vrfname, - size_t vrfnamelen, struct sockaddr_any *local, + ifindex_t *ifindex, struct sockaddr_any *local, struct sockaddr_any *peer); ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, - char *port, size_t portlen, char *vrfname, - size_t vrfnamelen, struct sockaddr_any *local, + ifindex_t *ifindex, struct sockaddr_any *local, struct sockaddr_any *peer); int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen, struct sockaddr *to, socklen_t tolen); @@ -213,20 +211,36 @@ void ptm_bfd_snd(struct bfd_session *bfd, int fbit) cp.flags = 0; BFD_SETSTATE(cp.flags, bfd->ses_state); BFD_SETDEMANDBIT(cp.flags, BFD_DEF_DEMAND); - BFD_SETPBIT(cp.flags, bfd->polling); + + /* + * Polling and Final can't be set at the same time. + * + * RFC 5880, Section 6.5. + */ BFD_SETFBIT(cp.flags, fbit); + if (fbit == 0) + BFD_SETPBIT(cp.flags, bfd->polling); + cp.detect_mult = bfd->detect_mult; cp.len = BFD_PKT_LEN; cp.discrs.my_discr = htonl(bfd->discrs.my_discr); cp.discrs.remote_discr = htonl(bfd->discrs.remote_discr); if (bfd->polling) { cp.timers.desired_min_tx = - htonl(bfd->new_timers.desired_min_tx); + htonl(bfd->timers.desired_min_tx); cp.timers.required_min_rx = - htonl(bfd->new_timers.required_min_rx); + htonl(bfd->timers.required_min_rx); } else { - cp.timers.desired_min_tx = htonl(bfd->timers.desired_min_tx); - cp.timers.required_min_rx = htonl(bfd->timers.required_min_rx); + /* + * We can only announce current setting on poll, this + * avoids timing mismatch with our peer and give it + * the oportunity to learn. See `bs_final_handler` for + * more information. + */ + cp.timers.desired_min_tx = + htonl(bfd->cur_timers.desired_min_tx); + cp.timers.required_min_rx = + htonl(bfd->cur_timers.required_min_rx); } cp.timers.required_min_echo = htonl(bfd->timers.required_min_echo); @@ -237,21 +251,16 @@ void ptm_bfd_snd(struct bfd_session *bfd, int fbit) } ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, - char *port, size_t portlen, char *vrfname, - size_t vrfnamelen, struct sockaddr_any *local, + ifindex_t *ifindex, struct sockaddr_any *local, struct sockaddr_any *peer) { - struct interface *ifp; struct cmsghdr *cm; - int ifindex; ssize_t mlen; struct sockaddr_in msgaddr; struct msghdr msghdr; struct iovec iov[1]; uint8_t cmsgbuf[255]; - port[0] = '\0'; - /* Prepare the recvmsg params. */ iov[0].iov_base = msgbuf; iov[0].iov_len = msgbuflen; @@ -309,13 +318,7 @@ ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, local->sa_sin.sin_len = sizeof(local->sa_sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ - ifp = if_lookup_by_index(pi->ipi_ifindex, VRF_DEFAULT); - if (ifp == NULL) - break; - - if (strlcpy(port, ifp->name, portlen) >= portlen) - log_debug( - "ipv4-recv: interface name truncated"); + *ifindex = pi->ipi_ifindex; break; } #endif /* BFD_LINUX */ @@ -350,31 +353,18 @@ ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, } /* OS agnostic way of getting interface name. */ - if (port[0] == 0) { - ifindex = getsockopt_ifindex(AF_INET, &msghdr); - if (ifindex <= 0) - return mlen; - - ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); - if (ifp == NULL) - return mlen; - - if (strlcpy(port, ifp->name, portlen) >= portlen) - log_debug("ipv4-recv: interface name truncated"); - } + if (*ifindex == IFINDEX_INTERNAL) + *ifindex = getsockopt_ifindex(AF_INET, &msghdr); return mlen; } ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, - char *port, size_t portlen, char *vrfname, - size_t vrfnamelen, struct sockaddr_any *local, + ifindex_t *ifindex, struct sockaddr_any *local, struct sockaddr_any *peer) { - struct interface *ifp; struct cmsghdr *cm; struct in6_pktinfo *pi6 = NULL; - int ifindex = 0; ssize_t mlen; uint32_t ttlval; struct sockaddr_in6 msgaddr6; @@ -429,24 +419,16 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, local->sa_sin6.sin6_len = sizeof(local->sa_sin6); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ - ifindex = pi6->ipi6_ifindex; - ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); - if (ifp == NULL) - break; - - if (strlcpy(port, ifp->name, portlen) - >= portlen) - log_debug( - "ipv6-recv: interface name truncated"); + *ifindex = pi6->ipi6_ifindex; } } } /* Set scope ID for link local addresses. */ if (IN6_IS_ADDR_LINKLOCAL(&peer->sa_sin6.sin6_addr)) - peer->sa_sin6.sin6_scope_id = ifindex; + peer->sa_sin6.sin6_scope_id = *ifindex; if (IN6_IS_ADDR_LINKLOCAL(&local->sa_sin6.sin6_addr)) - local->sa_sin6.sin6_scope_id = ifindex; + local->sa_sin6.sin6_scope_id = *ifindex; return mlen; } @@ -481,8 +463,8 @@ static void bfd_sd_reschedule(int sd) } static void cp_debug(bool mhop, struct sockaddr_any *peer, - struct sockaddr_any *local, const char *port, - const char *vrf, const char *fmt, ...) + struct sockaddr_any *local, ifindex_t ifindex, + vrf_id_t vrfid, const char *fmt, ...) { char buf[512], peerstr[128], localstr[128], portstr[64], vrfstr[64]; va_list vl; @@ -498,13 +480,13 @@ static void cp_debug(bool mhop, struct sockaddr_any *peer, else localstr[0] = 0; - if (port[0]) - snprintf(portstr, sizeof(portstr), " port:%s", port); + if (ifindex != IFINDEX_INTERNAL) + snprintf(portstr, sizeof(portstr), " port:%u", ifindex); else portstr[0] = 0; - if (vrf[0]) - snprintf(vrfstr, sizeof(vrfstr), " vrf:%s", port); + if (vrfid != VRF_DEFAULT) + snprintf(vrfstr, sizeof(vrfstr), " vrf:%u", vrfid); else vrfstr[0] = 0; @@ -523,10 +505,10 @@ int bfd_recv_cb(struct thread *t) struct bfd_pkt *cp; bool is_mhop; ssize_t mlen = 0; - uint32_t oldEchoXmt_TO, oldXmtTime; - uint8_t ttl; + uint8_t ttl = 0; + vrf_id_t vrfid = VRF_DEFAULT; + ifindex_t ifindex = IFINDEX_INTERNAL; struct sockaddr_any local, peer; - char port[MAXNAMELEN + 1], vrfname[MAXNAMELEN + 1]; uint8_t msgbuf[1516]; /* Schedule next read. */ @@ -539,8 +521,6 @@ int bfd_recv_cb(struct thread *t) } /* Sanitize input/output. */ - memset(port, 0, sizeof(port)); - memset(vrfname, 0, sizeof(vrfname)); memset(&local, 0, sizeof(local)); memset(&peer, 0, sizeof(peer)); @@ -548,26 +528,24 @@ int bfd_recv_cb(struct thread *t) is_mhop = false; if (sd == bglobal.bg_shop || sd == bglobal.bg_mhop) { is_mhop = sd == bglobal.bg_mhop; - mlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), &ttl, port, - sizeof(port), vrfname, sizeof(vrfname), + mlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), &ttl, &ifindex, &local, &peer); } else if (sd == bglobal.bg_shop6 || sd == bglobal.bg_mhop6) { is_mhop = sd == bglobal.bg_mhop6; - mlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), &ttl, port, - sizeof(port), vrfname, sizeof(vrfname), + mlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), &ttl, &ifindex, &local, &peer); } /* Implement RFC 5880 6.8.6 */ if (mlen < BFD_PKT_LEN) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "too small (%ld bytes)", mlen); return 0; } /* Validate packet TTL. */ if ((is_mhop == false) && (ttl != BFD_TTL_VAL)) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "invalid TTL: %d expected %d", ttl, BFD_TTL_VAL); return 0; } @@ -581,32 +559,32 @@ int bfd_recv_cb(struct thread *t) */ cp = (struct bfd_pkt *)(msgbuf); if (BFD_GETVER(cp->diag) != BFD_VERSION) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "bad version %d", BFD_GETVER(cp->diag)); return 0; } if (cp->detect_mult == 0) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "detect multiplier set to zero"); return 0; } if ((cp->len < BFD_PKT_LEN) || (cp->len > mlen)) { - cp_debug(is_mhop, &peer, &local, port, vrfname, "too small"); + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "too small"); return 0; } if (cp->discrs.my_discr == 0) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "'my discriminator' is zero"); return 0; } /* Find the session that this packet belongs. */ - bfd = ptm_bfd_sess_find(cp, port, &peer, &local, vrfname, is_mhop); + bfd = ptm_bfd_sess_find(cp, &peer, &local, ifindex, vrfid, is_mhop); if (bfd == NULL) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "no session found"); return 0; } @@ -619,7 +597,7 @@ int bfd_recv_cb(struct thread *t) */ if (is_mhop) { if ((BFD_TTL_VAL - bfd->mh_ttl) > BFD_TTL_VAL) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "exceeded max hop count (expected %d, got %d)", bfd->mh_ttl, BFD_TTL_VAL); return 0; @@ -633,137 +611,57 @@ int bfd_recv_cb(struct thread *t) * packet came in. */ if (bfd->ifp == NULL) - bfd->ifp = if_lookup_by_name(port, VRF_DEFAULT); + bfd->ifp = if_lookup_by_index(ifindex, vrfid); /* Log remote discriminator changes. */ if ((bfd->discrs.remote_discr != 0) && (bfd->discrs.remote_discr != ntohl(cp->discrs.my_discr))) - cp_debug(is_mhop, &peer, &local, port, vrfname, - "remote discriminator mismatch (expected %d, got %d)", + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, + "remote discriminator mismatch (expected %u, got %u)", bfd->discrs.remote_discr, ntohl(cp->discrs.my_discr)); bfd->discrs.remote_discr = ntohl(cp->discrs.my_discr); - /* If received the Final bit, the new values should take effect */ - if (bfd->polling && BFD_GETFBIT(cp->flags)) { - bfd->timers.desired_min_tx = bfd->new_timers.desired_min_tx; - bfd->timers.required_min_rx = bfd->new_timers.required_min_rx; - bfd->new_timers.desired_min_tx = 0; - bfd->new_timers.required_min_rx = 0; - bfd->polling = 0; - } - - if (!bfd->demand_mode) { - /* Compute detect time */ - bfd->detect_TO = cp->detect_mult - * ((bfd->timers.required_min_rx - > ntohl(cp->timers.desired_min_tx)) - ? bfd->timers.required_min_rx - : ntohl(cp->timers.desired_min_tx)); - bfd->remote_detect_mult = cp->detect_mult; - } else - cp_debug(is_mhop, &peer, &local, port, vrfname, - "unsupported demand mode"); - /* Save remote diagnostics before state switch. */ bfd->remote_diag = cp->diag & BFD_DIAGMASK; - /* State switch from section 6.8.6 */ - if (BFD_GETSTATE(cp->flags) == PTM_BFD_ADM_DOWN) { - if (bfd->ses_state != PTM_BFD_DOWN) - ptm_bfd_ses_dn(bfd, BD_NEIGHBOR_DOWN); - } else { - switch (bfd->ses_state) { - case (PTM_BFD_DOWN): - if (BFD_GETSTATE(cp->flags) == PTM_BFD_INIT) - ptm_bfd_ses_up(bfd); - else if (BFD_GETSTATE(cp->flags) == PTM_BFD_DOWN) - bfd->ses_state = PTM_BFD_INIT; - break; - case (PTM_BFD_INIT): - if (BFD_GETSTATE(cp->flags) == PTM_BFD_INIT - || BFD_GETSTATE(cp->flags) == PTM_BFD_UP) - ptm_bfd_ses_up(bfd); - break; - case (PTM_BFD_UP): - if (BFD_GETSTATE(cp->flags) == PTM_BFD_DOWN) - ptm_bfd_ses_dn(bfd, BD_NEIGHBOR_DOWN); - break; - } - } + /* Update remote timers settings. */ + bfd->remote_timers.desired_min_tx = ntohl(cp->timers.desired_min_tx); + bfd->remote_timers.required_min_rx = ntohl(cp->timers.required_min_rx); + bfd->remote_timers.required_min_echo = + ntohl(cp->timers.required_min_echo); + bfd->remote_detect_mult = cp->detect_mult; - /* - * Handle echo packet status: - * - Start echo packets if configured and permitted - * (required_min_echo > 0); - * - Stop echo packets if not allowed (required_min_echo == 0); - * - Recalculate echo packet interval; - */ - if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO)) { - if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) { - if (!ntohl(cp->timers.required_min_echo)) { - ptm_bfd_echo_stop(bfd, 1); - } else { - oldEchoXmt_TO = bfd->echo_xmt_TO; - bfd->echo_xmt_TO = - bfd->timers.required_min_echo; - if (ntohl(cp->timers.required_min_echo) - > bfd->echo_xmt_TO) - bfd->echo_xmt_TO = ntohl( - cp->timers.required_min_echo); - if (oldEchoXmt_TO != bfd->echo_xmt_TO) - ptm_bfd_echo_start(bfd); - } - } else if (ntohl(cp->timers.required_min_echo)) { - bfd->echo_xmt_TO = bfd->timers.required_min_echo; - if (ntohl(cp->timers.required_min_echo) - > bfd->echo_xmt_TO) - bfd->echo_xmt_TO = - ntohl(cp->timers.required_min_echo); - ptm_bfd_echo_start(bfd); - } - } - - if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) { - bfd->echo_xmt_TO = bfd->timers.required_min_echo; - if (ntohl(cp->timers.required_min_echo) > bfd->echo_xmt_TO) - bfd->echo_xmt_TO = ntohl(cp->timers.required_min_echo); - } + /* State switch from section 6.2. */ + bs_state_handler(bfd, BFD_GETSTATE(cp->flags)); - /* Calculate new transmit time */ - oldXmtTime = bfd->xmt_TO; - bfd->xmt_TO = - (bfd->timers.desired_min_tx > ntohl(cp->timers.required_min_rx)) - ? bfd->timers.desired_min_tx - : ntohl(cp->timers.required_min_rx); + /* RFC 5880, Section 6.5: handle POLL/FINAL negotiation sequence. */ + if (bfd->polling && BFD_GETFBIT(cp->flags)) { + /* Disable pooling. */ + bfd->polling = 0; - /* If transmit time has changed, and too much time until next xmt, - * restart - */ - if (BFD_GETPBIT(cp->flags)) { - ptm_bfd_xmt_TO(bfd, 1); - } else if (oldXmtTime != bfd->xmt_TO) { - /* XXX add some skid to this as well */ - ptm_bfd_start_xmt_timer(bfd, false); + /* Handle poll finalization. */ + bs_final_handler(bfd); + } else { + /* Received a packet, lets update the receive timer. */ + bfd_recvtimer_update(bfd); } - /* Restart detection timer (packet received) */ - if (!bfd->demand_mode) - bfd_recvtimer_update(bfd); + /* Handle echo timers changes. */ + bs_echo_timer_handler(bfd); /* - * Save the timers and state sent by the remote end - * for debugging and statistics. + * We've received a packet with the POLL bit set, we must send + * a control packet back with the FINAL bit set. + * + * RFC 5880, Section 6.5. */ - if (BFD_GETFBIT(cp->flags)) { - bfd->remote_timers.desired_min_tx = - ntohl(cp->timers.desired_min_tx); - bfd->remote_timers.required_min_rx = - ntohl(cp->timers.required_min_rx); - bfd->remote_timers.required_min_echo = - ntohl(cp->timers.required_min_echo); - - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bfd); + if (BFD_GETPBIT(cp->flags)) { + /* We are finalizing a poll negotiation. */ + bs_final_handler(bfd); + + /* Send the control packet with the final bit immediately. */ + ptm_bfd_snd(bfd, 1); } return 0; @@ -781,21 +679,20 @@ int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr) struct bfd_echo_pkt *bep; ssize_t rlen; struct sockaddr_any local, peer; - char port[MAXNAMELEN + 1], vrfname[MAXNAMELEN + 1]; + ifindex_t ifindex = IFINDEX_INTERNAL; + vrf_id_t vrfid = VRF_DEFAULT; uint8_t msgbuf[1516]; if (sd == bglobal.bg_echo) - rlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), ttl, port, - sizeof(port), vrfname, sizeof(vrfname), + rlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), ttl, &ifindex, &local, &peer); else - rlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), ttl, port, - sizeof(port), vrfname, sizeof(vrfname), + rlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), ttl, &ifindex, &local, &peer); /* Short packet, better not risk reading it. */ if (rlen < (ssize_t)sizeof(*bep)) { - cp_debug(false, &peer, &local, port, vrfname, + cp_debug(false, &peer, &local, ifindex, vrfid, "small echo packet"); return -1; } @@ -813,7 +710,7 @@ int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr) bep = (struct bfd_echo_pkt *)msgbuf; *my_discr = ntohl(bep->my_discr); if (*my_discr == 0) { - cp_debug(false, &peer, &local, port, vrfname, + cp_debug(false, &peer, &local, ifindex, vrfid, "invalid echo packet discriminator (zero)"); return -1; } @@ -995,7 +892,7 @@ int bp_udp_mhop(void) return sd; } -int bp_peer_socket(struct bfd_peer_cfg *bpc) +int bp_peer_socket(const struct bfd_session *bs) { int sd, pcount; struct sockaddr_in sin; @@ -1020,28 +917,26 @@ int bp_peer_socket(struct bfd_peer_cfg *bpc) return -1; } - if (bpc->bpc_has_localif) { - if (bp_bind_dev(sd, bpc->bpc_localif) != 0) { + if (bs->shop.ifindex != IFINDEX_INTERNAL) { + if (bp_bind_dev(sd, bs->ifp->name) != 0) { close(sd); return -1; } - } else if (bpc->bpc_mhop && bpc->bpc_has_vrfname) { - if (bp_bind_dev(sd, bpc->bpc_vrfname) != 0) { + } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) && + bs->mhop.vrfid != VRF_DEFAULT) { + if (bp_bind_dev(sd, bs->vrf->name) != 0) { close(sd); return -1; } } /* Find an available source port in the proper range */ - memset(&sin, 0, sizeof(sin)); - sin = bpc->bpc_local.sa_sin; + sin = bs->local_ip.sa_sin; sin.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin.sin_len = sizeof(sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ - if (bpc->bpc_mhop) - sin.sin_addr = bpc->bpc_local.sa_sin.sin_addr; - else + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) sin.sin_addr.s_addr = INADDR_ANY; pcount = 0; @@ -1066,9 +961,8 @@ int bp_peer_socket(struct bfd_peer_cfg *bpc) * IPv6 sockets */ -int bp_peer_socketv6(struct bfd_peer_cfg *bpc) +int bp_peer_socketv6(const struct bfd_session *bs) { - struct interface *ifp; int sd, pcount; struct sockaddr_in6 sin6; static int srcPort = BFD_SRCPORTINIT; @@ -1093,25 +987,20 @@ int bp_peer_socketv6(struct bfd_peer_cfg *bpc) } /* Find an available source port in the proper range */ - memset(&sin6, 0, sizeof(sin6)); + sin6 = bs->local_ip.sa_sin6; sin6.sin6_family = AF_INET6; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin6.sin6_len = sizeof(sin6); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ - sin6 = bpc->bpc_local.sa_sin6; - if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) { - ifp = if_lookup_by_name(bpc->bpc_localif, VRF_DEFAULT); - sin6.sin6_scope_id = - (ifp != NULL) ? ifp->ifindex : IFINDEX_INTERNAL; - } - if (bpc->bpc_has_localif) { - if (bp_bind_dev(sd, bpc->bpc_localif) != 0) { + if (bs->shop.ifindex != IFINDEX_INTERNAL) { + if (bp_bind_dev(sd, bs->ifp->name) != 0) { close(sd); return -1; } - } else if (bpc->bpc_mhop && bpc->bpc_has_vrfname) { - if (bp_bind_dev(sd, bpc->bpc_vrfname) != 0) { + } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) && + bs->mhop.vrfid != VRF_DEFAULT) { + if (bp_bind_dev(sd, bs->vrf->name) != 0) { close(sd); return -1; } diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index 250f8d21c..6023b5e4f 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -32,6 +32,7 @@ DEFINE_MTYPE(BFDD, BFDD_TMP, "short-lived temporary memory"); DEFINE_MTYPE(BFDD, BFDD_CONFIG, "long-lived configuration memory"); DEFINE_MTYPE(BFDD, BFDD_LABEL, "long-lived label memory"); DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory"); +DEFINE_MTYPE(BFDD, BFDD_SESSION_OBSERVER, "Session observer"); DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data"); /* Master of threads. */ @@ -153,6 +154,7 @@ struct bfd_state_str_list state_list[] = { static void bg_init(void) { TAILQ_INIT(&bglobal.bg_bcslist); + TAILQ_INIT(&bglobal.bg_obslist); bglobal.bg_shop = bp_udp_shop(); bglobal.bg_mhop = bp_udp_mhop(); diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 8f8fff6b1..0041f9cc2 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -51,7 +51,8 @@ */ static int bfdd_write_config(struct vty *vty); static int bfdd_peer_write_config(struct vty *vty); -static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg); +static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs); +static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg); static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop, const struct sockaddr_any *peer, const struct sockaddr_any *local, @@ -64,13 +65,13 @@ static struct json_object *_peer_json_header(struct bfd_session *bs); static void _display_peer_json(struct vty *vty, struct bfd_session *bs); static void _display_peer(struct vty *vty, struct bfd_session *bs); static void _display_all_peers(struct vty *vty, bool use_json); -static void _display_peer_iter(struct hash_backet *hb, void *arg); -static void _display_peer_json_iter(struct hash_backet *hb, void *arg); +static void _display_peer_iter(struct hash_bucket *hb, void *arg); +static void _display_peer_json_iter(struct hash_bucket *hb, void *arg); static void _display_peer_counter(struct vty *vty, struct bfd_session *bs); static struct json_object *__display_peer_counters_json(struct bfd_session *bs); static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs); -static void _display_peer_counter_iter(struct hash_backet *hb, void *arg); -static void _display_peer_counter_json_iter(struct hash_backet *hb, void *arg); +static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg); +static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg); static void _display_peers_counter(struct vty *vty, bool use_json); static struct bfd_session * _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, @@ -130,6 +131,10 @@ DEFUN_NOSH( vty_out(vty, "%% VRF is not mixable with interface\n"); return CMD_WARNING_CONFIG_FAILED; } + if (vrfname && !mhop) { + vty_out(vty, "%% VRF only applies with multihop.\n"); + return CMD_WARNING_CONFIG_FAILED; + } strtosa(peer, &psa); if (local) { @@ -171,7 +176,6 @@ DEFPY(bfd_peer_detectmultiplier, bfd_peer_detectmultiplier_cmd, return CMD_SUCCESS; bs->detect_mult = multiplier; - bfd_set_polling(bs); return CMD_SUCCESS; } @@ -201,10 +205,10 @@ DEFPY(bfd_peer_txinterval, bfd_peer_txinterval_cmd, struct bfd_session *bs; bs = VTY_GET_CONTEXT(bfd_session); - if (bs->up_min_tx == (uint32_t)(interval * 1000)) + if (bs->timers.desired_min_tx == (uint32_t)(interval * 1000)) return CMD_SUCCESS; - bs->up_min_tx = interval * 1000; + bs->timers.desired_min_tx = interval * 1000; bfd_set_polling(bs); return CMD_SUCCESS; @@ -222,7 +226,6 @@ DEFPY(bfd_peer_echointerval, bfd_peer_echointerval_cmd, return CMD_SUCCESS; bs->timers.required_min_echo = interval * 1000; - bfd_set_polling(bs); return CMD_SUCCESS; } @@ -283,17 +286,15 @@ DEFPY(bfd_peer_echo, bfd_peer_echo_cmd, "[no] echo-mode", return CMD_SUCCESS; BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO); - ptm_bfd_echo_stop(bs, 0); + ptm_bfd_echo_stop(bs); } else { if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) return CMD_SUCCESS; BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO); /* Apply setting immediately. */ - if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) { - ptm_bfd_echo_start(bs); - bfd_echo_recvtimer_update(bs); - } + if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) + bs_echo_timer_handler(bs); } return CMD_SUCCESS; @@ -372,16 +373,16 @@ static void _display_peer_header(struct vty *vty, struct bfd_session *bs) vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer)); vty_out(vty, " multihop"); vty_out(vty, " local-address %s", satostr(&bs->mhop.local)); - if (bs->mhop.vrf_name[0]) - vty_out(vty, " vrf %s", bs->mhop.vrf_name); + if (bs->vrfname[0]) + vty_out(vty, " vrf %s", bs->vrfname); vty_out(vty, "\n"); } else { vty_out(vty, "\tpeer %s", satostr(&bs->shop.peer)); if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) vty_out(vty, " local-address %s", satostr(&bs->local_address)); - if (bs->shop.port_name[0]) - vty_out(vty, " interface %s", bs->shop.port_name); + if (bs->ifname[0]) + vty_out(vty, " interface %s", bs->ifname); vty_out(vty, "\n"); } @@ -433,20 +434,10 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs) vty_out(vty, "\t\tLocal timers:\n"); vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n", bs->timers.required_min_rx / 1000); - vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms", + vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n", bs->timers.desired_min_tx / 1000); - if (bs->up_min_tx != bs->timers.desired_min_tx) - vty_out(vty, " (configured %" PRIu32 "ms)\n", - bs->up_min_tx / 1000); - else - vty_out(vty, "\n"); - - vty_out(vty, "\t\t\tEcho transmission interval: "); - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) - vty_out(vty, "%" PRIu32 "ms\n", - bs->timers.required_min_echo / 1000); - else - vty_out(vty, "disabled\n"); + vty_out(vty, "\t\t\tEcho transmission interval: %" PRIu32 "ms\n", + bs->timers.required_min_echo / 1000); vty_out(vty, "\t\tRemote timers:\n"); vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n", @@ -467,17 +458,16 @@ static struct json_object *_peer_json_header(struct bfd_session *bs) json_object_boolean_true_add(jo, "multihop"); json_object_string_add(jo, "peer", satostr(&bs->mhop.peer)); json_object_string_add(jo, "local", satostr(&bs->mhop.local)); - if (bs->mhop.vrf_name[0]) - json_object_string_add(jo, "vrf", bs->mhop.vrf_name); + if (bs->vrfname[0]) + json_object_string_add(jo, "vrf", bs->vrfname); } else { json_object_boolean_false_add(jo, "multihop"); json_object_string_add(jo, "peer", satostr(&bs->shop.peer)); if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) json_object_string_add(jo, "local", satostr(&bs->local_address)); - if (bs->shop.port_name[0]) - json_object_string_add(jo, "interface", - bs->shop.port_name); + if (bs->ifname[0]) + json_object_string_add(jo, "interface", bs->ifname); } if (bs->pl) @@ -548,7 +538,7 @@ static void _display_peer_json(struct vty *vty, struct bfd_session *bs) json_object_free(jo); } -static void _display_peer_iter(struct hash_backet *hb, void *arg) +static void _display_peer_iter(struct hash_bucket *hb, void *arg) { struct vty *vty = arg; struct bfd_session *bs = hb->data; @@ -556,7 +546,7 @@ static void _display_peer_iter(struct hash_backet *hb, void *arg) _display_peer(vty, bs); } -static void _display_peer_json_iter(struct hash_backet *hb, void *arg) +static void _display_peer_json_iter(struct hash_bucket *hb, void *arg) { struct json_object *jo = arg, *jon = NULL; struct bfd_session *bs = hb->data; @@ -631,7 +621,7 @@ static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs) json_object_free(jo); } -static void _display_peer_counter_iter(struct hash_backet *hb, void *arg) +static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg) { struct vty *vty = arg; struct bfd_session *bs = hb->data; @@ -639,7 +629,7 @@ static void _display_peer_counter_iter(struct hash_backet *hb, void *arg) _display_peer_counter(vty, bs); } -static void _display_peer_counter_json_iter(struct hash_backet *hb, void *arg) +static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg) { struct json_object *jo = arg, *jon = NULL; struct bfd_session *bs = hb->data; @@ -924,36 +914,36 @@ static int bfdd_write_config(struct vty *vty) return 0; } -static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg) +static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs) { - struct vty *vty = arg; - struct bfd_session *bs = hb->data; - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { vty_out(vty, " peer %s", satostr(&bs->mhop.peer)); vty_out(vty, " multihop"); vty_out(vty, " local-address %s", satostr(&bs->mhop.local)); - if (bs->mhop.vrf_name[0]) - vty_out(vty, " vrf %s", bs->mhop.vrf_name); + if (bs->vrfname[0]) + vty_out(vty, " vrf %s", bs->vrfname); vty_out(vty, "\n"); } else { vty_out(vty, " peer %s", satostr(&bs->shop.peer)); if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) vty_out(vty, " local-address %s", satostr(&bs->local_address)); - if (bs->shop.port_name[0]) - vty_out(vty, " interface %s", bs->shop.port_name); + if (bs->ifname[0]) + vty_out(vty, " interface %s", bs->ifname); vty_out(vty, "\n"); } + if (bs->sock == -1) + vty_out(vty, " ! vrf or interface doesn't exist\n"); + if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER) vty_out(vty, " detect-multiplier %d\n", bs->detect_mult); if (bs->timers.required_min_rx != (BPC_DEF_RECEIVEINTERVAL * 1000)) vty_out(vty, " receive-interval %" PRIu32 "\n", bs->timers.required_min_rx / 1000); - if (bs->up_min_tx != (BPC_DEF_TRANSMITINTERVAL * 1000)) + if (bs->timers.desired_min_tx != (BPC_DEF_TRANSMITINTERVAL * 1000)) vty_out(vty, " transmit-interval %" PRIu32 "\n", - bs->up_min_tx / 1000); + bs->timers.desired_min_tx / 1000); if (bs->timers.required_min_echo != (BPC_DEF_ECHOINTERVAL * 1000)) vty_out(vty, " echo-interval %" PRIu32 "\n", bs->timers.required_min_echo / 1000); @@ -968,9 +958,39 @@ static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg) vty_out(vty, " !\n"); } +DEFUN_NOSH(show_debugging_bfd, + show_debugging_bfd_cmd, + "show debugging [bfd]", + SHOW_STR + DEBUG_STR + "BFD daemon\n") +{ + vty_out(vty, "BFD debugging status:\n"); + + return CMD_SUCCESS; +} + +static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg) +{ + struct vty *vty = arg; + struct bfd_session *bs = hb->data; + + _bfdd_peer_write_config(vty, bs); +} + static int bfdd_peer_write_config(struct vty *vty) { - bfd_id_iterate(_bfdd_peer_write_config, vty); + struct bfd_session_observer *bso; + + bfd_id_iterate(_bfdd_peer_write_config_iter, vty); + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + /* Only print disabled sessions here. */ + if (bso->bso_bs->sock != -1) + continue; + + _bfdd_peer_write_config(vty, bso->bso_bs); + } + return 1; } @@ -993,6 +1013,7 @@ void bfdd_vty_init(void) install_element(ENABLE_NODE, &bfd_show_peers_cmd); install_element(ENABLE_NODE, &bfd_show_peer_cmd); install_element(CONFIG_NODE, &bfd_enter_cmd); + install_element(ENABLE_NODE, &show_debugging_bfd_cmd); /* Install BFD node and commands. */ install_node(&bfd_node, bfdd_write_config); diff --git a/bfdd/config.c b/bfdd/config.c index 06089780c..d1342eff1 100644 --- a/bfdd/config.c +++ b/bfdd/config.c @@ -314,16 +314,16 @@ static int parse_peer_label_config(struct json_object *jo, if (bpc->bpc_mhop) { bpc->bpc_peer = pl->pl_bs->mhop.peer; bpc->bpc_local = pl->pl_bs->mhop.local; - if (pl->pl_bs->mhop.vrf_name[0]) { + if (pl->pl_bs->mhop.vrfid != VRF_DEFAULT) { bpc->bpc_has_vrfname = true; - strlcpy(bpc->bpc_vrfname, pl->pl_bs->mhop.vrf_name, + strlcpy(bpc->bpc_vrfname, pl->pl_bs->vrf->name, sizeof(bpc->bpc_vrfname)); } } else { bpc->bpc_peer = pl->pl_bs->shop.peer; - if (pl->pl_bs->shop.port_name[0]) { + if (pl->pl_bs->ifname[0]) { bpc->bpc_has_localif = true; - strlcpy(bpc->bpc_localif, pl->pl_bs->shop.port_name, + strlcpy(bpc->bpc_localif, pl->pl_bs->ifname, sizeof(bpc->bpc_localif)); } } @@ -471,7 +471,8 @@ char *config_notify_config(const char *op, struct bfd_session *bs) json_object_int_add(resp, "detect-multiplier", bs->detect_mult); json_object_int_add(resp, "receive-interval", bs->timers.required_min_rx / 1000); - json_object_int_add(resp, "transmit-interval", bs->up_min_tx / 1000); + json_object_int_add(resp, "transmit-interval", + bs->timers.desired_min_tx / 1000); json_object_int_add(resp, "echo-interval", bs->timers.required_min_echo / 1000); @@ -530,9 +531,8 @@ static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs) satostr(&bs->mhop.peer)); json_object_string_add(jo, "local-address", satostr(&bs->mhop.local)); - if (strlen(bs->mhop.vrf_name) > 0) - json_object_string_add(jo, "vrf-name", - bs->mhop.vrf_name); + if (bs->vrfname[0]) + json_object_string_add(jo, "vrf-name", bs->vrfname); } else { json_object_boolean_false_add(jo, "multihop"); json_object_string_add(jo, "peer-address", @@ -540,9 +540,9 @@ static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs) if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) json_object_string_add(jo, "local-address", satostr(&bs->local_address)); - if (strlen(bs->shop.port_name) > 0) + if (bs->ifname[0]) json_object_string_add(jo, "local-interface", - bs->shop.port_name); + bs->ifname); } if (bs->pl) diff --git a/bfdd/control.c b/bfdd/control.c index 554a5a8d8..40f4f4d3b 100644 --- a/bfdd/control.c +++ b/bfdd/control.c @@ -65,7 +65,7 @@ static void control_handle_notify_add(struct bfd_control_socket *bcs, struct bfd_control_msg *bcm); static void control_handle_notify_del(struct bfd_control_socket *bcs, struct bfd_control_msg *bcm); -static void _control_handle_notify(struct hash_backet *hb, void *arg); +static void _control_handle_notify(struct hash_bucket *hb, void *arg); static void control_handle_notify(struct bfd_control_socket *bcs, struct bfd_control_msg *bcm); static void control_response(struct bfd_control_socket *bcs, uint16_t id, @@ -630,7 +630,7 @@ static struct bfd_session *_notify_find_peer(struct bfd_peer_cfg *bpc) return bs_peer_find(bpc); } -static void _control_handle_notify(struct hash_backet *hb, void *arg) +static void _control_handle_notify(struct hash_bucket *hb, void *arg) { struct bfd_control_socket *bcs = arg; struct bfd_session *bs = hb->data; diff --git a/bfdd/event.c b/bfdd/event.c index 3f48921af..5ba54c2b0 100644 --- a/bfdd/event.c +++ b/bfdd/event.c @@ -43,7 +43,8 @@ void bfd_recvtimer_update(struct bfd_session *bs) bfd_recvtimer_delete(bs); /* Don't add event if peer is deactivated. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) || + bs->sock == -1) return; tv_normalize(&tv); @@ -63,7 +64,8 @@ void bfd_echo_recvtimer_update(struct bfd_session *bs) bfd_echo_recvtimer_delete(bs); /* Don't add event if peer is deactivated. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) || + bs->sock == -1) return; tv_normalize(&tv); @@ -83,7 +85,8 @@ void bfd_xmttimer_update(struct bfd_session *bs, uint64_t jitter) bfd_xmttimer_delete(bs); /* Don't add event if peer is deactivated. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) || + bs->sock == -1) return; tv_normalize(&tv); @@ -102,7 +105,8 @@ void bfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter) bfd_echo_xmttimer_delete(bs); /* Don't add event if peer is deactivated. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) || + bs->sock == -1) return; tv_normalize(&tv); diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index a57167376..3f1512d8e 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -597,23 +597,96 @@ static void bfdd_zebra_connected(struct zclient *zc) zclient_send_message(zclient); } -static int bfdd_interface_update(int cmd, struct zclient *zc, uint16_t len, +static void bfdd_sessions_enable_interface(struct interface *ifp) +{ + struct bfd_session_observer *bso; + struct bfd_session *bs; + + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + if (bso->bso_isinterface == false) + continue; + + /* Interface name mismatch. */ + bs = bso->bso_bs; + if (strcmp(ifp->name, bs->ifname)) + continue; + /* Skip enabled sessions. */ + if (bs->sock != -1) + continue; + + /* Try to enable it. */ + bfd_session_enable(bs); + } +} + +static void bfdd_sessions_disable_interface(struct interface *ifp) +{ + struct bfd_session_observer *bso; + struct bfd_session *bs; + + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + if (bso->bso_isinterface == false) + continue; + + /* Interface name mismatch. */ + bs = bso->bso_bs; + if (strcmp(ifp->name, bs->ifname)) + continue; + /* Skip disabled sessions. */ + if (bs->sock == -1) + continue; + + /* Try to enable it. */ + bfd_session_disable(bs); + + TAILQ_INSERT_HEAD(&bglobal.bg_obslist, bso, bso_entry); + } +} + +static int bfdd_interface_update(int cmd, struct zclient *zc, + uint16_t len __attribute__((__unused__)), vrf_id_t vrfid) { + struct interface *ifp; + /* * `zebra_interface_add_read` will handle the interface creation * on `lib/if.c`. We'll use that data structure instead of * rolling our own. */ if (cmd == ZEBRA_INTERFACE_ADD) { - zebra_interface_add_read(zc->ibuf, vrfid); + ifp = zebra_interface_add_read(zc->ibuf, vrfid); + if (ifp == NULL) + return 0; + + bfdd_sessions_enable_interface(ifp); return 0; } /* Update interface information. */ - zebra_interface_state_read(zc->ibuf, vrfid); + ifp = zebra_interface_state_read(zc->ibuf, vrfid); + if (ifp == NULL) + return 0; + + bfdd_sessions_disable_interface(ifp); - /* TODO: stop all sessions using this interface. */ + return 0; +} + +static int bfdd_interface_vrf_update(int command __attribute__((__unused__)), + struct zclient *zclient, + zebra_size_t length + __attribute__((__unused__)), + vrf_id_t vrfid) +{ + struct interface *ifp; + vrf_id_t nvrfid; + + ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrfid, &nvrfid); + if (ifp == NULL) + return 0; + + if_update_to_new_vrf(ifp, nvrfid); return 0; } @@ -637,6 +710,9 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv) /* Learn interfaces from zebra instead of the OS. */ zclient->interface_add = bfdd_interface_update; zclient->interface_delete = bfdd_interface_update; + + /* Learn about interface VRF. */ + zclient->interface_vrf_update = bfdd_interface_vrf_update; } void bfdd_zclient_stop(void) diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c index 55a86f99f..c7fd1ba0e 100644 --- a/bgpd/bgp_addpath.c +++ b/bgpd/bgp_addpath.c @@ -175,6 +175,28 @@ int bgp_addpath_tx_path(enum bgp_addpath_strat strat, } } +static void bgp_addpath_flush_type_rn(struct bgp *bgp, afi_t afi, safi_t safi, + enum bgp_addpath_strat addpath_type, + struct bgp_node *rn) +{ + struct bgp_path_info *pi; + + idalloc_drain_pool( + bgp->tx_addpath.id_allocators[afi][safi][addpath_type], + &(rn->tx_addpath.free_ids[addpath_type])); + for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { + if (pi->tx_addpath.addpath_tx_id[addpath_type] + != IDALLOC_INVALID) { + idalloc_free( + bgp->tx_addpath + .id_allocators[afi][safi][addpath_type], + pi->tx_addpath.addpath_tx_id[addpath_type]); + pi->tx_addpath.addpath_tx_id[addpath_type] = + IDALLOC_INVALID; + } + } +} + /* * Purge all addpath ID's on a BGP instance associated with the addpath * strategy, and afi/safi combination. This lets us let go of all memory held to @@ -185,26 +207,24 @@ int bgp_addpath_tx_path(enum bgp_addpath_strat strat, static void bgp_addpath_flush_type(struct bgp *bgp, afi_t afi, safi_t safi, enum bgp_addpath_strat addpath_type) { - struct bgp_node *rn; - struct bgp_path_info *pi; + struct bgp_node *rn, *nrn; for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) { - idalloc_drain_pool( - bgp->tx_addpath.id_allocators[afi][safi][addpath_type], - &(rn->tx_addpath.free_ids[addpath_type])); - for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { - if (pi->tx_addpath.addpath_tx_id[addpath_type] - != IDALLOC_INVALID) { - idalloc_free( - bgp->tx_addpath - .id_allocators[afi][safi] - [addpath_type], - pi->tx_addpath - .addpath_tx_id[addpath_type]); - pi->tx_addpath.addpath_tx_id[addpath_type] = - IDALLOC_INVALID; - } + if (safi == SAFI_MPLS_VPN) { + struct bgp_table *table; + + table = bgp_node_get_bgp_table_info(rn); + if (!table) + continue; + + for (nrn = bgp_table_top(table); nrn; + nrn = bgp_route_next(nrn)) + bgp_addpath_flush_type_rn(bgp, afi, safi, + addpath_type, nrn); + } else { + bgp_addpath_flush_type_rn(bgp, afi, safi, addpath_type, + rn); } } @@ -234,8 +254,7 @@ static void bgp_addpath_populate_path(struct id_alloc *allocator, static void bgp_addpath_populate_type(struct bgp *bgp, afi_t afi, safi_t safi, enum bgp_addpath_strat addpath_type) { - struct bgp_node *rn; - struct bgp_path_info *bi; + struct bgp_node *rn, *nrn; char buf[200]; struct id_alloc *allocator; @@ -255,9 +274,29 @@ static void bgp_addpath_populate_type(struct bgp *bgp, afi_t afi, safi_t safi, allocator = bgp->tx_addpath.id_allocators[afi][safi][addpath_type]; for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; - rn = bgp_route_next(rn)) - for (bi = bgp_node_get_bgp_path_info(rn); bi; bi = bi->next) - bgp_addpath_populate_path(allocator, bi, addpath_type); + rn = bgp_route_next(rn)) { + struct bgp_path_info *bi; + + if (safi == SAFI_MPLS_VPN) { + struct bgp_table *table; + + table = bgp_node_get_bgp_table_info(rn); + if (!table) + continue; + + for (nrn = bgp_table_top(table); nrn; + nrn = bgp_route_next(nrn)) + for (bi = bgp_node_get_bgp_path_info(nrn); bi; + bi = bi->next) + bgp_addpath_populate_path(allocator, bi, + addpath_type); + } else { + for (bi = bgp_node_get_bgp_path_info(rn); bi; + bi = bi->next) + bgp_addpath_populate_path(allocator, bi, + addpath_type); + } + } } /* diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 4f756519c..3bd3de031 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -212,6 +212,9 @@ static struct assegment *assegment_append_asns(struct assegment *seg, { as_t *newas; + if (!seg) + return seg; + newas = XREALLOC(MTYPE_AS_SEG_DATA, seg->as, ASSEGMENT_DATA_SIZE(seg->length + num, 1)); @@ -1372,7 +1375,8 @@ static struct aspath *aspath_merge(struct aspath *as1, struct aspath *as2) while (last && last->next) last = last->next; - last->next = as2->segments; + if (last) + last->next = as2->segments; as2->segments = new; aspath_str_update(as2, false); return as2; @@ -1381,39 +1385,45 @@ static struct aspath *aspath_merge(struct aspath *as1, struct aspath *as2) /* Prepend as1 to as2. as2 should be uninterned aspath. */ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) { - struct assegment *seg1; - struct assegment *seg2; + struct assegment *as1segtail; + struct assegment *as2segtail; + struct assegment *as2seghead; if (!as1 || !as2) return NULL; - seg1 = as1->segments; - seg2 = as2->segments; - /* If as2 is empty, only need to dupe as1's chain onto as2 */ - if (seg2 == NULL) { + if (as2->segments == NULL) { as2->segments = assegment_dup_all(as1->segments); aspath_str_update(as2, false); return as2; } /* If as1 is empty AS, no prepending to do. */ - if (seg1 == NULL) + if (as1->segments == NULL) return as2; /* find the tail as1's segment chain. */ - while (seg1 && seg1->next) - seg1 = seg1->next; + as1segtail = as1->segments; + while (as1segtail && as1segtail->next) + as1segtail = as1segtail->next; /* Delete any AS_CONFED_SEQUENCE segment from as2. */ - if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE) + if (as1segtail->type == AS_SEQUENCE + && as2->segments->type == AS_CONFED_SEQUENCE) as2 = aspath_delete_confed_seq(as2); + if (!as2->segments) { + as2->segments = assegment_dup_all(as1->segments); + aspath_str_update(as2, false); + return as2; + } + /* Compare last segment type of as1 and first segment type of as2. */ - if (seg1->type != seg2->type) + if (as1segtail->type != as2->segments->type) return aspath_merge(as1, as2); - if (seg1->type == AS_SEQUENCE) { + if (as1segtail->type == AS_SEQUENCE) { /* We have two chains of segments, as1->segments and seg2, * and we have to attach them together, merging the attaching * segments together into one. @@ -1423,23 +1433,29 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) * 3. attach chain after seg2 */ + /* save as2 head */ + as2seghead = as2->segments; + /* dupe as1 onto as2's head */ - seg1 = as2->segments = assegment_dup_all(as1->segments); + as2segtail = as2->segments = assegment_dup_all(as1->segments); - /* refind the tail of as2, reusing seg1 */ - while (seg1 && seg1->next) - seg1 = seg1->next; + /* refind the tail of as2 */ + while (as2segtail && as2segtail->next) + as2segtail = as2segtail->next; /* merge the old head, seg2, into tail, seg1 */ - seg1 = assegment_append_asns(seg1, seg2->as, seg2->length); + assegment_append_asns(as2segtail, as2seghead->as, + as2seghead->length); - /* bypass the merged seg2, and attach any chain after it to - * chain descending from as2's head + /* + * bypass the merged seg2, and attach any chain after it + * to chain descending from as2's head */ - seg1->next = seg2->next; + if (as2segtail) + as2segtail->next = as2seghead->next; - /* seg2 is now referenceless and useless*/ - assegment_free(seg2); + /* as2->segments is now referenceless and useless */ + assegment_free(as2seghead); /* we've now prepended as1's segment chain to as2, merging * the inbetween AS_SEQUENCE of seg2 in the process @@ -2066,14 +2082,14 @@ void aspath_print_vty(struct vty *vty, const char *format, struct aspath *as, vty_out(vty, "%s", suffix); } -static void aspath_show_all_iterator(struct hash_backet *backet, +static void aspath_show_all_iterator(struct hash_bucket *bucket, struct vty *vty) { struct aspath *as; - as = (struct aspath *)backet->data; + as = (struct aspath *)bucket->data; - vty_out(vty, "[%p:%u] (%ld) ", (void *)backet, backet->key, as->refcnt); + vty_out(vty, "[%p:%u] (%ld) ", (void *)bucket, bucket->key, as->refcnt); vty_out(vty, "%s\n", as->str); } @@ -2081,7 +2097,114 @@ static void aspath_show_all_iterator(struct hash_backet *backet, `show [ip] bgp paths' command. */ void aspath_print_all_vty(struct vty *vty) { - hash_iterate(ashash, (void (*)(struct hash_backet *, + hash_iterate(ashash, (void (*)(struct hash_bucket *, void *))aspath_show_all_iterator, vty); } + +static struct aspath *bgp_aggr_aspath_lookup(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ + return hash_lookup(aggregate->aspath_hash, aspath); +} + +static void *bgp_aggr_aspath_hash_alloc(void *p) +{ + struct aspath *ref = (struct aspath *)p; + struct aspath *aspath = NULL; + + aspath = aspath_dup(ref); + return aspath; +} + +static void bgp_aggr_aspath_prepare(struct hash_backet *hb, void *arg) +{ + struct aspath *asmerge = NULL; + struct aspath *hb_aspath = hb->data; + struct aspath **aggr_aspath = arg; + + if (*aggr_aspath) { + asmerge = aspath_aggregate(*aggr_aspath, hb_aspath); + aspath_free(*aggr_aspath); + *aggr_aspath = asmerge; + } else + *aggr_aspath = aspath_dup(hb_aspath); +} + +void bgp_aggr_aspath_remove(void *arg) +{ + struct aspath *aspath = arg; + + aspath_free(aspath); +} + +void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ + struct aspath *aggr_aspath = NULL; + + if ((aggregate == NULL) || (aspath == NULL)) + return; + + /* Create hash if not already created. + */ + if (aggregate->aspath_hash == NULL) + aggregate->aspath_hash = hash_create( + aspath_key_make, aspath_cmp, + "BGP Aggregator as-path hash"); + + aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath); + if (aggr_aspath == NULL) { + /* Insert as-path into hash. + */ + aggr_aspath = hash_get(aggregate->aspath_hash, aspath, + bgp_aggr_aspath_hash_alloc); + + /* Compute aggregate's as-path. + */ + hash_iterate(aggregate->aspath_hash, + bgp_aggr_aspath_prepare, + &aggregate->aspath); + } + + /* Increment refernce counter. + */ + aggr_aspath->refcnt++; +} + +void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ + struct aspath *aggr_aspath = NULL; + struct aspath *ret_aspath = NULL; + + if ((aggregate == NULL) || (aspath == NULL)) + return; + + if (aggregate->aspath_hash == NULL) + return; + + /* Look-up the aspath in the hash. + */ + aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath); + if (aggr_aspath) { + aggr_aspath->refcnt--; + + if (aggr_aspath->refcnt == 0) { + ret_aspath = hash_release(aggregate->aspath_hash, + aggr_aspath); + aspath_free(ret_aspath); + + /* Remove aggregate's old as-path. + */ + aspath_free(aggregate->aspath); + aggregate->aspath = NULL; + + /* Compute aggregate's as-path. + */ + hash_iterate(aggregate->aspath_hash, + bgp_aggr_aspath_prepare, + &aggregate->aspath); + } + } +} diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 9c9c687a6..be5725c1a 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -22,6 +22,7 @@ #define _QUAGGA_BGP_ASPATH_H #include "lib/json.h" +#include "bgpd/bgp_route.h" /* AS path segment type. */ #define AS_SET 1 @@ -130,4 +131,10 @@ extern unsigned int aspath_has_as4(struct aspath *); /* For SNMP BGP4PATHATTRASPATHSEGMENT, might be useful for debug */ extern uint8_t *aspath_snmp_pathseg(struct aspath *, size_t *); +extern void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, + struct aspath *aspath); +extern void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, + struct aspath *aspath); +extern void bgp_aggr_aspath_remove(void *arg); + #endif /* _QUAGGA_BGP_ASPATH_H */ diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 03f31eddf..e731af754 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -592,9 +592,9 @@ static void attrhash_finish(void) attrhash = NULL; } -static void attr_show_all_iterator(struct hash_backet *backet, struct vty *vty) +static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty) { - struct attr *attr = backet->data; + struct attr *attr = bucket->data; vty_out(vty, "attr[%ld] nexthop %s\n", attr->refcnt, inet_ntoa(attr->nexthop)); @@ -605,7 +605,7 @@ static void attr_show_all_iterator(struct hash_backet *backet, struct vty *vty) void attr_show_all(struct vty *vty) { - hash_iterate(attrhash, (void (*)(struct hash_backet *, + hash_iterate(attrhash, (void (*)(struct hash_bucket *, void *))attr_show_all_iterator, vty); } @@ -2227,11 +2227,12 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args) struct attr *const attr = args->attr; const bgp_size_t length = args->length; uint8_t tnl_type; + int attr_parse_len = 2 + BGP_LABEL_BYTES; /* Verify that the receiver is expecting "ingress replication" as we * can only support that. */ - if (length < 2) { + if (length < attr_parse_len) { flog_err(EC_BGP_ATTR_LEN, "Bad PMSI tunnel attribute length %d", length); return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, @@ -2258,9 +2259,10 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args) attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); attr->pmsi_tnl_type = tnl_type; + stream_get(&attr->label, peer->curr, BGP_LABEL_BYTES); /* Forward read pointer of input stream. */ - stream_forward_getp(peer->curr, length - 2); + stream_forward_getp(peer->curr, length - attr_parse_len); return BGP_ATTR_PARSE_PROCEED; } @@ -3445,7 +3447,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, stream_putc(s, BGP_ATTR_PMSI_TUNNEL); stream_putc(s, 9); // Length stream_putc(s, 0); // Flags - stream_putc(s, PMSI_TNLTYPE_INGR_REPL); // IR (6) + stream_putc(s, attr->pmsi_tnl_type); stream_put(s, &(attr->label), BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI stream_put_ipv4(s, attr->nexthop.s_addr); diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index 614e24ca4..2e28c3095 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -910,3 +910,112 @@ void community_finish(void) hash_free(comhash); comhash = NULL; } + +static struct community *bgp_aggr_community_lookup( + struct bgp_aggregate *aggregate, + struct community *community) +{ + return hash_lookup(aggregate->community_hash, community); +} + +static void *bgp_aggr_communty_hash_alloc(void *p) +{ + struct community *ref = (struct community *)p; + struct community *community = NULL; + + community = community_dup(ref); + return community; +} + +static void bgp_aggr_community_prepare(struct hash_backet *hb, void *arg) +{ + struct community *commerge = NULL; + struct community *hb_community = hb->data; + struct community **aggr_community = arg; + + if (*aggr_community) { + commerge = community_merge(*aggr_community, hb_community); + *aggr_community = community_uniq_sort(commerge); + community_free(&commerge); + } else + *aggr_community = community_dup(hb_community); +} + +void bgp_aggr_community_remove(void *arg) +{ + struct community *community = arg; + + community_free(&community); +} + +void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, + struct community *community) +{ + struct community *aggr_community = NULL; + + if ((aggregate == NULL) || (community == NULL)) + return; + + /* Create hash if not already created. + */ + if (aggregate->community_hash == NULL) + aggregate->community_hash = hash_create( + (unsigned int (*)(void *))community_hash_make, + (bool (*)(const void *, const void *))community_cmp, + "BGP Aggregator community hash"); + + aggr_community = bgp_aggr_community_lookup(aggregate, community); + if (aggr_community == NULL) { + /* Insert community into hash. + */ + aggr_community = hash_get(aggregate->community_hash, community, + bgp_aggr_communty_hash_alloc); + + /* Re-compute aggregate's community. + */ + if (aggregate->community) + community_free(&aggregate->community); + + hash_iterate(aggregate->community_hash, + bgp_aggr_community_prepare, + &aggregate->community); + } + + /* Increment refernce counter. + */ + aggr_community->refcnt++; +} + +void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, + struct community *community) +{ + struct community *aggr_community = NULL; + struct community *ret_comm = NULL; + + if ((aggregate == NULL) || (community == NULL)) + return; + + if (aggregate->community_hash == NULL) + return; + + /* Look-up the community in the hash. + */ + aggr_community = bgp_aggr_community_lookup(aggregate, community); + if (aggr_community) { + aggr_community->refcnt--; + + if (aggr_community->refcnt == 0) { + ret_comm = hash_release(aggregate->community_hash, + aggr_community); + community_free(&ret_comm); + + community_free(&aggregate->community); + + /* Compute aggregate's community. + */ + hash_iterate(aggregate->community_hash, + bgp_aggr_community_prepare, + &aggregate->community); + } + } +} diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h index e1545249d..4ff4d214a 100644 --- a/bgpd/bgp_community.h +++ b/bgpd/bgp_community.h @@ -22,6 +22,7 @@ #define _QUAGGA_BGP_COMMUNITY_H #include "lib/json.h" +#include "bgpd/bgp_route.h" /* Communities attribute. */ struct community { @@ -89,5 +90,10 @@ extern void community_del_val(struct community *, uint32_t *); extern unsigned long community_count(void); extern struct hash *community_hash(void); extern uint32_t community_val_get(struct community *com, int i); +extern void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, + struct community *community); +extern void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, + struct community *community); +extern void bgp_aggr_community_remove(void *arg); #endif /* _QUAGGA_BGP_COMMUNITY_H */ diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index c7fad29cb..f476b1618 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -368,6 +368,8 @@ int bgp_dump_attr(struct attr *attr, char *buf, size_t size) if (!attr) return 0; + buf[0] = '\0'; + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))) snprintf(buf, size, "nexthop %s", inet_ntoa(attr->nexthop)); @@ -2121,67 +2123,6 @@ DEFUN_NOSH (show_debugging_bgp, return CMD_SUCCESS; } -/* return count of number of debug flags set */ -int bgp_debug_count(void) -{ - int ret = 0; - if (BGP_DEBUG(as4, AS4)) - ret++; - - if (BGP_DEBUG(as4, AS4_SEGMENT)) - ret++; - - if (BGP_DEBUG(bestpath, BESTPATH)) - ret++; - - if (BGP_DEBUG(keepalive, KEEPALIVE)) - ret++; - - if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS)) - ret++; - - if (BGP_DEBUG(nht, NHT)) - ret++; - - if (BGP_DEBUG(update_groups, UPDATE_GROUPS)) - ret++; - - if (BGP_DEBUG(update, UPDATE_PREFIX)) - ret++; - - if (BGP_DEBUG(update, UPDATE_IN)) - ret++; - - if (BGP_DEBUG(update, UPDATE_OUT)) - ret++; - - if (BGP_DEBUG(zebra, ZEBRA)) - ret++; - - if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) - ret++; - - if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)) - ret++; - if (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF)) - ret++; - if (BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT)) - ret++; - if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) - ret++; - if (BGP_DEBUG(flowspec, FLOWSPEC)) - ret++; - if (BGP_DEBUG(labelpool, LABELPOOL)) - ret++; - - if (BGP_DEBUG(pbr, PBR)) - ret++; - if (BGP_DEBUG(pbr, PBR_ERROR)) - ret++; - - return ret; -} - static int bgp_config_write_debug(struct vty *vty) { int write = 0; diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index d5d8fbb50..e05da3764 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -168,7 +168,6 @@ extern int bgp_debug_update(struct peer *peer, struct prefix *p, extern int bgp_debug_bestpath(struct prefix *p); extern int bgp_debug_zebra(struct prefix *p); -extern int bgp_debug_count(void); extern const char *bgp_debug_rdpfxpath2str(afi_t, safi_t, struct prefix_rd *, union prefixconstptr, mpls_label_t *, uint32_t, int, uint32_t, char *, diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index ed0900a72..fcfaa388d 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1026,3 +1026,112 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, return -1; return 0; } + +static struct ecommunity *bgp_aggr_ecommunity_lookup( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ + return hash_lookup(aggregate->ecommunity_hash, ecommunity); +} + +static void *bgp_aggr_ecommunty_hash_alloc(void *p) +{ + struct ecommunity *ref = (struct ecommunity *)p; + struct ecommunity *ecommunity = NULL; + + ecommunity = ecommunity_dup(ref); + return ecommunity; +} + +static void bgp_aggr_ecommunity_prepare(struct hash_backet *hb, void *arg) +{ + struct ecommunity *ecommerge = NULL; + struct ecommunity *hb_ecommunity = hb->data; + struct ecommunity **aggr_ecommunity = arg; + + if (*aggr_ecommunity) { + ecommerge = ecommunity_merge(*aggr_ecommunity, hb_ecommunity); + *aggr_ecommunity = ecommunity_uniq_sort(ecommerge); + ecommunity_free(&ecommerge); + } else + *aggr_ecommunity = ecommunity_dup(hb_ecommunity); +} + +void bgp_aggr_ecommunity_remove(void *arg) +{ + struct ecommunity *ecommunity = arg; + + ecommunity_free(&ecommunity); +} + +void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ + struct ecommunity *aggr_ecommunity = NULL; + + if ((aggregate == NULL) || (ecommunity == NULL)) + return; + + /* Create hash if not already created. + */ + if (aggregate->ecommunity_hash == NULL) + aggregate->ecommunity_hash = hash_create( + ecommunity_hash_make, ecommunity_cmp, + "BGP Aggregator ecommunity hash"); + + aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity); + if (aggr_ecommunity == NULL) { + /* Insert ecommunity into hash. + */ + aggr_ecommunity = hash_get(aggregate->ecommunity_hash, + ecommunity, + bgp_aggr_ecommunty_hash_alloc); + + /* Re-compute aggregate's ecommunity. + */ + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); + + hash_iterate(aggregate->ecommunity_hash, + bgp_aggr_ecommunity_prepare, + &aggregate->ecommunity); + } + + /* Increment refernce counter. + */ + aggr_ecommunity->refcnt++; +} + +void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ + struct ecommunity *aggr_ecommunity = NULL; + struct ecommunity *ret_ecomm = NULL; + + if ((aggregate == NULL) || (ecommunity == NULL)) + return; + + if (aggregate->ecommunity_hash == NULL) + return; + + /* Look-up the ecommunity in the hash. + */ + aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity); + if (aggr_ecommunity) { + aggr_ecommunity->refcnt--; + + if (aggr_ecommunity->refcnt == 0) { + ret_ecomm = hash_release(aggregate->ecommunity_hash, + aggr_ecommunity); + ecommunity_free(&ret_ecomm); + + ecommunity_free(&aggregate->ecommunity); + + /* Compute aggregate's ecommunity. + */ + hash_iterate(aggregate->ecommunity_hash, + bgp_aggr_ecommunity_prepare, + &aggregate->ecommunity); + } + } +} diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 519991da5..62b213775 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -21,6 +21,8 @@ #ifndef _QUAGGA_BGP_ECOMMUNITY_H #define _QUAGGA_BGP_ECOMMUNITY_H +#include "bgpd/bgp_route.h" + /* High-order octet of the Extended Communities type field. */ #define ECOMMUNITY_ENCODE_AS 0x00 #define ECOMMUNITY_ENCODE_IP 0x01 @@ -184,4 +186,12 @@ struct bgp_pbr_entry_action; extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, struct bgp_pbr_entry_action *api); +extern void bgp_compute_aggregate_ecommunity( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); +extern void bgp_remove_ecommunity_from_aggregate( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); +extern void bgp_aggr_ecommunity_remove(void *arg); + #endif /* _QUAGGA_BGP_ECOMMUNITY_H */ diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 7f6d34808..4a8fe111b 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -887,17 +887,26 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr) /* Install EVPN route into zebra. */ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, - struct in_addr remote_vtep_ip, uint8_t flags, - uint32_t seq) + struct prefix_evpn *p, struct bgp_path_info *pi) { int ret; + uint8_t flags; - if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip, - 1, flags, seq); - else + if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + flags = 0; + if (pi->attr->sticky) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + if (pi->attr->default_gw) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + if (is_evpn_prefix_ipaddr_v6(p) && + pi->attr->router_flag) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); + ret = bgp_zebra_send_remote_macip( + bgp, vpn, p, pi->attr->nexthop, 1, flags, + mac_mobility_seqnum(pi->attr)); + } else { ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 1); + } return ret; } @@ -1121,11 +1130,9 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, { struct bgp_path_info *old_select, *new_select; struct bgp_path_info_pair old_and_new; - struct prefix_evpn *evp; afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; int ret = 0; - uint8_t flags = 0; /* Compute the best path. */ bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new, @@ -1133,7 +1140,6 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, old_select = old_and_new.old; new_select = old_and_new.new; - evp = (struct prefix_evpn *)&rn->p; /* If the best path hasn't changed - see if there is still something to * update * to zebra RIB. @@ -1144,20 +1150,10 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR) && !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED) && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) { - if (bgp_zebra_has_route_changed(rn, old_select)) { - if (old_select->attr->sticky) - SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); - if (old_select->attr->default_gw) - SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); - if (is_evpn_prefix_ipaddr_v6(evp) && - old_select->attr->router_flag) - SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); - + if (bgp_zebra_has_route_changed(rn, old_select)) ret = evpn_zebra_install( bgp, vpn, (struct prefix_evpn *)&rn->p, - old_select->attr->nexthop, flags, - mac_mobility_seqnum(old_select->attr)); - } + old_select); UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); bgp_zebra_clear_route_change_flags(rn); return ret; @@ -1182,18 +1178,9 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, if (new_select && new_select->type == ZEBRA_ROUTE_BGP && new_select->sub_type == BGP_ROUTE_IMPORTED) { - flags = 0; - if (new_select->attr->sticky) - SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); - if (new_select->attr->default_gw) - SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); - if (is_evpn_prefix_ipaddr_v6(evp) && - new_select->attr->router_flag) - SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); - ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p, - new_select->attr->nexthop, flags, - mac_mobility_seqnum(new_select->attr)); + new_select); + /* If an old best existed and it was a "local" route, the only * reason * it would be supplanted is due to MAC mobility procedures. So, @@ -1698,6 +1685,27 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, return route_change; } +static void evpn_zebra_reinstall_best_route(struct bgp *bgp, + struct bgpevpn *vpn, struct bgp_node *rn) +{ + struct bgp_path_info *tmp_ri; + struct bgp_path_info *curr_select = NULL; + + for (tmp_ri = bgp_node_get_bgp_path_info(rn); + tmp_ri; tmp_ri = tmp_ri->next) { + if (CHECK_FLAG(tmp_ri->flags, BGP_PATH_SELECTED)) { + curr_select = tmp_ri; + break; + } + } + + if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP + && curr_select->sub_type == BGP_ROUTE_IMPORTED) + evpn_zebra_install(bgp, vpn, + (struct prefix_evpn *)&rn->p, + curr_select); +} + /* * If the local route was not selected evict it and tell zebra to re-add * the best remote dest. @@ -1717,9 +1725,6 @@ static void evpn_cleanup_local_non_best_route(struct bgp *bgp, struct bgp_node *rn, struct bgp_path_info *local_pi) { - struct bgp_path_info *tmp_pi; - struct bgp_path_info *curr_select = NULL; - uint8_t flags = 0; char buf[PREFIX_STRLEN]; /* local path was not picked as the winner; kick it out */ @@ -1731,24 +1736,7 @@ static void evpn_cleanup_local_non_best_route(struct bgp *bgp, bgp_path_info_reap(rn, local_pi); /* tell zebra to re-add the best remote path */ - for (tmp_pi = bgp_node_get_bgp_path_info(rn); - tmp_pi; tmp_pi = tmp_pi->next) { - if (CHECK_FLAG(tmp_pi->flags, BGP_PATH_SELECTED)) { - curr_select = tmp_pi; - break; - } - } - if (curr_select && - curr_select->type == ZEBRA_ROUTE_BGP - && curr_select->sub_type == BGP_ROUTE_IMPORTED) { - if (curr_select->attr->sticky) - SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); - if (curr_select->attr->default_gw) - SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); - evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p, - curr_select->attr->nexthop, flags, - mac_mobility_seqnum(curr_select->attr)); - } + evpn_zebra_reinstall_best_route(bgp, vpn, rn); } /* @@ -1781,8 +1769,10 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0; /* PMSI is only needed for type-3 routes */ - if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) + if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) { attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); + attr.pmsi_tnl_type = PMSI_TNLTYPE_INGR_REPL; + } /* router mac is only needed for type-2 routes here. */ if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) @@ -3614,9 +3604,9 @@ static int delete_withdraw_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) * router-id. The routes in the per-VNI table are used to create routes in * the global table and schedule them. */ -static void update_router_id_vni(struct hash_backet *backet, struct bgp *bgp) +static void update_router_id_vni(struct hash_bucket *bucket, struct bgp *bgp) { - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; /* Skip VNIs with configured RD. */ if (is_rd_configured(vpn)) @@ -3632,9 +3622,9 @@ static void update_router_id_vni(struct hash_backet *backet, struct bgp *bgp) * the router-id and is done only on the global route table, the routes * are needed in the per-VNI table to re-advertise with new router id. */ -static void withdraw_router_id_vni(struct hash_backet *backet, struct bgp *bgp) +static void withdraw_router_id_vni(struct hash_bucket *bucket, struct bgp *bgp) { - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; /* Skip VNIs with configured RD. */ if (is_rd_configured(vpn)) @@ -3647,9 +3637,9 @@ static void withdraw_router_id_vni(struct hash_backet *backet, struct bgp *bgp) * Create RT-3 for a VNI and schedule for processing and advertisement. * This is invoked upon flooding mode changing to head-end replication. */ -static void create_advertise_type3(struct hash_backet *backet, void *data) +static void create_advertise_type3(struct hash_bucket *bucket, void *data) { - struct bgpevpn *vpn = backet->data; + struct bgpevpn *vpn = bucket->data; struct bgp *bgp = data; struct prefix_evpn p; @@ -3666,9 +3656,9 @@ static void create_advertise_type3(struct hash_backet *backet, void *data) * Delete RT-3 for a VNI and schedule for processing and withdrawal. * This is invoked upon flooding mode changing to drop BUM packets. */ -static void delete_withdraw_type3(struct hash_backet *backet, void *data) +static void delete_withdraw_type3(struct hash_bucket *bucket, void *data) { - struct bgpevpn *vpn = backet->data; + struct bgpevpn *vpn = bucket->data; struct bgp *bgp = data; struct prefix_evpn p; @@ -4098,9 +4088,9 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, /* * Cleanup specific VNI upon EVPN (advertise-all-vni) being disabled. */ -static void cleanup_vni_on_disable(struct hash_backet *backet, struct bgp *bgp) +static void cleanup_vni_on_disable(struct hash_bucket *bucket, struct bgp *bgp) { - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; /* Remove EVPN routes and schedule for processing. */ delete_routes_for_vni(bgp, vpn); @@ -4114,9 +4104,9 @@ static void cleanup_vni_on_disable(struct hash_backet *backet, struct bgp *bgp) /* * Free a VNI entry; iterator function called during cleanup. */ -static void free_vni_entry(struct hash_backet *backet, struct bgp *bgp) +static void free_vni_entry(struct hash_bucket *bucket, struct bgp *bgp) { - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; delete_all_vni_routes(bgp, vpn); bgp_evpn_free(bgp, vpn); @@ -4185,9 +4175,9 @@ static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf) /* * Handle autort change for a given VNI. */ -static void update_autort_vni(struct hash_backet *backet, struct bgp *bgp) +static void update_autort_vni(struct hash_bucket *bucket, struct bgp *bgp) { - struct bgpevpn *vpn = backet->data; + struct bgpevpn *vpn = bucket->data; if (!is_import_rt_configured(vpn)) { if (is_vni_live(vpn)) @@ -4493,7 +4483,7 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw) * L2-VNIs */ hash_iterate(bgp->vnihash, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))withdraw_router_id_vni, bgp); } else { @@ -4507,7 +4497,7 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw) * new RD */ hash_iterate(bgp->vnihash, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))update_router_id_vni, bgp); } @@ -4519,7 +4509,7 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw) void bgp_evpn_handle_autort_change(struct bgp *bgp) { hash_iterate(bgp->vnihash, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void*))update_autort_vni, bgp); } @@ -5291,7 +5281,7 @@ int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp) if (bgp_nexthop_self(bgp, pi->attr->nexthop)) { - char attr_str[BUFSIZ]; + char attr_str[BUFSIZ] = {0}; char pbuf[PREFIX_STRLEN]; bgp_dump_attr(pi->attr, attr_str, @@ -5324,10 +5314,11 @@ int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp) * Handle del of a local MACIP. */ int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac, - struct ipaddr *ip) + struct ipaddr *ip, int state) { struct bgpevpn *vpn; struct prefix_evpn p; + struct bgp_node *rn; /* Lookup VNI hash - should exist. */ vpn = bgp_evpn_lookup_vni(bgp, vni); @@ -5338,9 +5329,16 @@ int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac, return -1; } - /* Remove EVPN type-2 route and schedule for processing. */ build_evpn_type2_prefix(&p, mac, ip); - delete_evpn_route(bgp, vpn, &p); + if (state == ZEBRA_NEIGH_ACTIVE) { + /* Remove EVPN type-2 route and schedule for processing. */ + delete_evpn_route(bgp, vpn, &p); + } else { + /* Re-instate the current remote best path if any */ + rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p); + if (rn) + evpn_zebra_reinstall_best_route(bgp, vpn, rn); + } return 0; } @@ -5384,10 +5382,10 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, return 0; } -static void link_l2vni_hash_to_l3vni(struct hash_backet *backet, +static void link_l2vni_hash_to_l3vni(struct hash_bucket *bucket, struct bgp *bgp_vrf) { - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; struct bgp *bgp_def = NULL; bgp_def = bgp_get_default(); @@ -5398,7 +5396,8 @@ static void link_l2vni_hash_to_l3vni(struct hash_backet *backet, } int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac, - struct in_addr originator_ip, int filter) + struct in_addr originator_ip, int filter, + ifindex_t svi_ifindex) { struct bgp *bgp_vrf = NULL; /* bgp VRF instance */ struct bgp *bgp_def = NULL; /* default bgp instance */ @@ -5446,14 +5445,11 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac, SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO); } - /* associate with l3vni */ + /* associate the vrf with l3vni and related parameters */ bgp_vrf->l3vni = l3vni; - - /* set the router mac - to be used in mac-ip routes for this vrf */ memcpy(&bgp_vrf->rmac, rmac, sizeof(struct ethaddr)); - - /* set the originator ip */ bgp_vrf->originator_ip = originator_ip; + bgp_vrf->l3vni_svi_ifindex = svi_ifindex; /* set the right filter - are we using l3vni only for prefix routes? */ if (filter) @@ -5473,7 +5469,7 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac, /* link all corresponding l2vnis */ hash_iterate(bgp_def->vnihash, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))link_l2vni_hash_to_l3vni, bgp_vrf); @@ -5806,7 +5802,7 @@ void bgp_evpn_flood_control_change(struct bgp *bgp) */ void bgp_evpn_cleanup_on_disable(struct bgp *bgp) { - hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *, + hash_iterate(bgp->vnihash, (void (*)(struct hash_bucket *, void *))cleanup_vni_on_disable, bgp); } @@ -5818,7 +5814,7 @@ void bgp_evpn_cleanup_on_disable(struct bgp *bgp) void bgp_evpn_cleanup(struct bgp *bgp) { hash_iterate(bgp->vnihash, - (void (*)(struct hash_backet *, void *))free_vni_entry, + (void (*)(struct hash_bucket *, void *))free_vni_entry, bgp); hash_free(bgp->import_rt_hash); diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 8728fdcab..fbf30083e 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -129,13 +129,15 @@ extern int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p, struct bgp_path_info *ri); extern int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp); extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, - struct ethaddr *mac, struct ipaddr *ip); + struct ethaddr *mac, struct ipaddr *ip, + int state); extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, struct ipaddr *ip, uint8_t flags, uint32_t seq); extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id, struct ethaddr *rmac, - struct in_addr originator_ip, int filter); + struct in_addr originator_ip, int filter, + ifindex_t svi_ifindex); extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id); extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni); extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 43b1f05b3..c7f2671b7 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -73,6 +73,9 @@ struct bgpevpn { * advertising subnet for this VNI */ uint8_t advertise_subnet; + /* Flag to indicate if we are advertising the svi mac ip for this VNI*/ + uint8_t advertise_svi_macip; + /* Id for deriving the RD * automatically for this VNI */ uint16_t rd_id; @@ -177,6 +180,10 @@ struct bgp_evpn_info { bool dad_freeze; /* Recovery time */ uint32_t dad_freeze_time; + + /* EVPN enable - advertise svi macip routes */ + int advertise_svi_macip; + }; static inline int is_vrf_rd_configured(struct bgp *bgp_vrf) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 776f8f8ef..8437c4024 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -149,11 +149,11 @@ static void display_vrf_import_rt(struct vty *vty, struct vrf_irt_node *irt, } } -static void show_vrf_import_rt_entry(struct hash_backet *backet, void *args[]) +static void show_vrf_import_rt_entry(struct hash_bucket *bucket, void *args[]) { json_object *json = NULL; struct vty *vty = NULL; - struct vrf_irt_node *irt = (struct vrf_irt_node *)backet->data; + struct vrf_irt_node *irt = (struct vrf_irt_node *)bucket->data; vty = (struct vty *)args[0]; json = (struct json_object *)args[1]; @@ -256,11 +256,11 @@ static void display_import_rt(struct vty *vty, struct irt_node *irt, } } -static void show_import_rt_entry(struct hash_backet *backet, void *args[]) +static void show_import_rt_entry(struct hash_bucket *bucket, void *args[]) { json_object *json = NULL; struct vty *vty = NULL; - struct irt_node *irt = (struct irt_node *)backet->data; + struct irt_node *irt = (struct irt_node *)bucket->data; vty = args[0]; json = args[1]; @@ -489,6 +489,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json) inet_ntoa(vpn->originator_ip)); vty_out(vty, " Advertise-gw-macip : %s\n", vpn->advertise_gw_macip ? "Yes" : "No"); + vty_out(vty, " Advertise-svi-macip : %s\n", + vpn->advertise_svi_macip ? "Yes" : "No"); } if (!json) @@ -707,9 +709,9 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, } } -static void show_vni_routes_hash(struct hash_backet *backet, void *arg) +static void show_vni_routes_hash(struct hash_bucket *bucket, void *arg) { - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; struct vni_walk_ctx *wctx = arg; struct vty *vty = wctx->vty; json_object *json = wctx->json; @@ -833,7 +835,7 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp, } } -static void show_es_entry(struct hash_backet *backet, void *args[]) +static void show_es_entry(struct hash_bucket *bucket, void *args[]) { char buf[ESI_STR_LEN]; char buf1[RD_ADDRSTRLEN]; @@ -843,7 +845,7 @@ static void show_es_entry(struct hash_backet *backet, void *args[]) json_object *json = args[1]; json_object *json_vteps = NULL; struct listnode *node = NULL; - struct evpnes *es = (struct evpnes *)backet->data; + struct evpnes *es = (struct evpnes *)bucket->data; if (json) { json_vteps = json_object_new_array(); @@ -875,14 +877,14 @@ static void show_es_entry(struct hash_backet *backet, void *args[]) } } -static void show_vni_entry(struct hash_backet *backet, void *args[]) +static void show_vni_entry(struct hash_bucket *bucket, void *args[]) { struct vty *vty; json_object *json; json_object *json_vni = NULL; json_object *json_import_rtl = NULL; json_object *json_export_rtl = NULL; - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; char buf1[10]; char buf2[RD_ADDRSTRLEN]; char rt_buf[25]; @@ -1967,7 +1969,7 @@ static void evpn_show_vrf_import_rts(struct vty *vty, struct bgp *bgp_def, args[1] = json; hash_iterate(bgp_def->vrf_import_rt_hash, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))show_vrf_import_rt_entry, args); } @@ -1985,7 +1987,7 @@ static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp, hash_iterate( bgp->import_rt_hash, - (void (*)(struct hash_backet *, void *))show_import_rt_entry, + (void (*)(struct hash_bucket *, void *))show_import_rt_entry, args); } @@ -2006,7 +2008,7 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, wctx.vty = vty; wctx.vtep_ip = vtep_ip; wctx.json = json; - hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *, + hash_iterate(bgp->vnihash, (void (*)(struct hash_bucket *, void *))show_vni_routes_hash, &wctx); } @@ -2550,7 +2552,7 @@ static void evpn_show_all_es(struct vty *vty, struct bgp *bgp, args[0] = vty; args[1] = json; hash_iterate(bgp->esihash, - (void (*)(struct hash_backet *, void *))show_es_entry, + (void (*)(struct hash_bucket *, void *))show_es_entry, args); } @@ -2610,7 +2612,7 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp, args[0] = vty; args[1] = json; hash_iterate(bgp->vnihash, - (void (*)(struct hash_backet *, void *))show_vni_entry, + (void (*)(struct hash_bucket *, void *))show_vni_entry, args); /* print all L3 VNIs */ @@ -2619,6 +2621,33 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp, } /* + * evpn - enable advertisement of svi MAC-IP + */ +static void evpn_set_advertise_svi_macip(struct bgp *bgp, struct bgpevpn *vpn, + uint32_t set) +{ + if (!vpn) { + if (set && bgp->evpn_info->advertise_svi_macip) + return; + else if (!set && !bgp->evpn_info->advertise_svi_macip) + return; + + bgp->evpn_info->advertise_svi_macip = set; + bgp_zebra_advertise_svi_macip(bgp, + bgp->evpn_info->advertise_svi_macip, 0); + } else { + if (set && vpn->advertise_svi_macip) + return; + else if (!set && !vpn->advertise_svi_macip) + return; + + vpn->advertise_svi_macip = set; + bgp_zebra_advertise_svi_macip(bgp, vpn->advertise_svi_macip, + vpn->vni); + } +} + +/* * evpn - enable advertisement of default g/w */ static void evpn_set_advertise_default_gw(struct bgp *bgp, struct bgpevpn *vpn) @@ -2798,6 +2827,9 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn) if (vpn->advertise_gw_macip) vty_out(vty, " advertise-default-gw\n"); + if (vpn->advertise_svi_macip) + vty_out(vty, " advertise-svi-ip\n"); + if (vpn->advertise_subnet) vty_out(vty, " advertise-subnet\n"); @@ -3151,6 +3183,54 @@ DEFPY (no_dup_addr_detection, return CMD_SUCCESS; } +DEFPY(bgp_evpn_advertise_svi_ip, + bgp_evpn_advertise_svi_ip_cmd, + "[no$no] advertise-svi-ip", + NO_STR + "Advertise svi mac-ip routes in EVPN\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + + if (!bgp) + return CMD_WARNING; + + if (bgp->vrf_id != VRF_DEFAULT) { + vty_out(vty, + "This command is only supported under Default VRF\n"); + return CMD_WARNING; + } + + if (no) + evpn_set_advertise_svi_macip(bgp, NULL, 0); + else + evpn_set_advertise_svi_macip(bgp, NULL, 1); + + return CMD_SUCCESS; +} + +DEFPY(bgp_evpn_advertise_svi_ip_vni, + bgp_evpn_advertise_svi_ip_vni_cmd, + "[no$no] advertise-svi-ip", + NO_STR + "Advertise svi mac-ip routes in EVPN for a VNI\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); + + if (!bgp) + return CMD_WARNING; + + if (!vpn) + return CMD_WARNING; + + if (no) + evpn_set_advertise_svi_macip(bgp, vpn, 0); + else + evpn_set_advertise_svi_macip(bgp, vpn, 1); + + return CMD_SUCCESS; +} + DEFUN_HIDDEN (bgp_evpn_advertise_vni_subnet, bgp_evpn_advertise_vni_subnet_cmd, "advertise-subnet", @@ -3260,6 +3340,8 @@ DEFUN (bgp_evpn_advertise_type5, if (bgp_vrf->adv_cmd_rmap[afi][safi].name) { XFREE(MTYPE_ROUTE_MAP_NAME, bgp_vrf->adv_cmd_rmap[afi][safi].name); + route_map_counter_decrement( + bgp_vrf->adv_cmd_rmap[afi][safi].map); bgp_vrf->adv_cmd_rmap[afi][safi].name = NULL; bgp_vrf->adv_cmd_rmap[afi][safi].map = NULL; } @@ -3271,6 +3353,8 @@ DEFUN (bgp_evpn_advertise_type5, XSTRDUP(MTYPE_ROUTE_MAP_NAME, argv[idx_rmap + 1]->arg); bgp_vrf->adv_cmd_rmap[afi][safi].map = route_map_lookup_by_name(argv[idx_rmap + 1]->arg); + route_map_counter_increment( + bgp_vrf->adv_cmd_rmap[afi][safi].map); } /* advertise type-5 routes */ @@ -3409,6 +3493,9 @@ DEFUN(show_bgp_l2vpn_evpn_vni, vty_out(vty, "Advertise Gateway Macip: %s\n", bgp_def->advertise_gw_macip ? "Enabled" : "Disabled"); + vty_out(vty, "Advertise SVI Macip: %s\n", + bgp_def->evpn_info->advertise_svi_macip ? "Enabled" + : "Disabled"); vty_out(vty, "Advertise All VNI flag: %s\n", is_evpn_enabled() ? "Enabled" : "Disabled"); vty_out(vty, "BUM flooding: %s\n", @@ -5071,6 +5158,9 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, if (bgp->advertise_gw_macip) vty_out(vty, " advertise-default-gw\n"); + if (bgp->evpn_info->advertise_svi_macip) + vty_out(vty, " advertise-svi-ip\n"); + if (!bgp->evpn_info->dup_addr_detect) vty_out(vty, " no dup-addr-detection\n"); @@ -5181,6 +5271,7 @@ void bgp_ethernetvpn_init(void) install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_autort_rfc8365_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_default_gw_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd); + install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_svi_ip_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd); @@ -5237,6 +5328,7 @@ void bgp_ethernetvpn_init(void) install_element(BGP_NODE, &no_bgp_evpn_vrf_rd_without_val_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_vrf_rt_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_vrf_rt_cmd); + install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_svi_ip_vni_cmd); install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_default_gw_vni_cmd); install_element(BGP_EVPN_VNI_NODE, diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c index cd5bec626..b9a0d81cc 100644 --- a/bgpd/bgp_flowspec_util.c +++ b/bgpd/bgp_flowspec_util.c @@ -456,8 +456,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, */ if (prefix->family == AF_INET && prefix->u.prefix4.s_addr == 0) - memset(prefix, 0, - sizeof(struct prefix)); + bpem->match_bitmask_iprule |= bitmask; else bpem->match_bitmask |= bitmask; } @@ -580,6 +579,22 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, __func__, type); } } + if (bpem->match_packet_length_num || bpem->match_fragment_num || + bpem->match_tcpflags_num || bpem->match_dscp_num || + bpem->match_packet_length_num || bpem->match_icmp_code_num || + bpem->match_icmp_type_num || bpem->match_port_num || + bpem->match_src_port_num || bpem->match_dst_port_num || + bpem->match_protocol_num || bpem->match_bitmask) + bpem->type = BGP_PBR_IPSET; + else if ((bpem->match_bitmask_iprule & PREFIX_SRC_PRESENT) || + (bpem->match_bitmask_iprule & PREFIX_DST_PRESENT)) + /* the extracted policy rule may not need an + * iptables/ipset filtering. check this may not be + * a standard ip rule : permit any to any ( eg) + */ + bpem->type = BGP_PBR_IPRULE; + else + bpem->type = BGP_PBR_UNDEFINED; return error; } diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index 26f0fffb3..72ee8bb4c 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -333,16 +333,17 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p, struct bgp_path_info_extra *extra = bgp_path_info_extra_get(path); - if (extra->bgp_fs_pbr) { + if (listcount(extra->bgp_fs_pbr) || + listcount(extra->bgp_fs_iprule)) { struct listnode *node; struct bgp_pbr_match_entry *bpme; + struct bgp_pbr_rule *bpr; struct bgp_pbr_match *bpm; bool list_began = false; struct list *list_bpm; list_bpm = list_new(); - if (listcount(extra->bgp_fs_pbr)) - vty_out(vty, "\tinstalled in PBR"); + vty_out(vty, "\tinstalled in PBR"); for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_pbr, node, bpme)) { bpm = bpme->backpointer; @@ -356,6 +357,19 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p, vty_out(vty, ", "); vty_out(vty, "%s", bpm->ipset_name); } + for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_iprule, + node, bpr)) { + if (!bpr->action) + continue; + if (!list_began) { + vty_out(vty, " ("); + list_began = true; + } else + vty_out(vty, ", "); + vty_out(vty, "-ipv4-rule %d action lookup %u-", + bpr->priority, + bpr->action->table_id); + } if (list_began) vty_out(vty, ")"); vty_out(vty, "\n"); diff --git a/bgpd/bgp_keepalives.c b/bgpd/bgp_keepalives.c index 87e3ff249..c2f0baff7 100644 --- a/bgpd/bgp_keepalives.c +++ b/bgpd/bgp_keepalives.c @@ -85,7 +85,7 @@ static void pkat_del(void *pkat) * * @return maximum time to wait until next update (0 if infinity) */ -static void peer_process(struct hash_backet *hb, void *arg) +static void peer_process(struct hash_bucket *hb, void *arg) { struct pkat *pkat = hb->data; @@ -288,7 +288,7 @@ void bgp_keepalives_off(struct peer *peer) pthread_mutex_unlock(peerhash_mtx); } -void bgp_keepalives_wake() +void bgp_keepalives_wake(void) { pthread_mutex_lock(peerhash_mtx); { diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index cfc9af777..1e4589719 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -537,3 +537,112 @@ void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr) i++; } } + +static struct lcommunity *bgp_aggr_lcommunity_lookup( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + return hash_lookup(aggregate->lcommunity_hash, lcommunity); +} + +static void *bgp_aggr_lcommunty_hash_alloc(void *p) +{ + struct lcommunity *ref = (struct lcommunity *)p; + struct lcommunity *lcommunity = NULL; + + lcommunity = lcommunity_dup(ref); + return lcommunity; +} + +static void bgp_aggr_lcommunity_prepare(struct hash_backet *hb, void *arg) +{ + struct lcommunity *lcommerge = NULL; + struct lcommunity *hb_lcommunity = hb->data; + struct lcommunity **aggr_lcommunity = arg; + + if (*aggr_lcommunity) { + lcommerge = lcommunity_merge(*aggr_lcommunity, hb_lcommunity); + *aggr_lcommunity = lcommunity_uniq_sort(lcommerge); + lcommunity_free(&lcommerge); + } else + *aggr_lcommunity = lcommunity_dup(hb_lcommunity); +} + +void bgp_aggr_lcommunity_remove(void *arg) +{ + struct lcommunity *lcommunity = arg; + + lcommunity_free(&lcommunity); +} + +void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + struct lcommunity *aggr_lcommunity = NULL; + + if ((aggregate == NULL) || (lcommunity == NULL)) + return; + + /* Create hash if not already created. + */ + if (aggregate->lcommunity_hash == NULL) + aggregate->lcommunity_hash = hash_create( + lcommunity_hash_make, lcommunity_cmp, + "BGP Aggregator lcommunity hash"); + + aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity); + if (aggr_lcommunity == NULL) { + /* Insert lcommunity into hash. + */ + aggr_lcommunity = hash_get(aggregate->lcommunity_hash, + lcommunity, + bgp_aggr_lcommunty_hash_alloc); + + /* Re-compute aggregate's lcommunity. + */ + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + + hash_iterate(aggregate->lcommunity_hash, + bgp_aggr_lcommunity_prepare, + &aggregate->lcommunity); + } + + /* Increment refernce counter. + */ + aggr_lcommunity->refcnt++; +} + +void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + struct lcommunity *aggr_lcommunity = NULL; + struct lcommunity *ret_lcomm = NULL; + + if ((aggregate == NULL) || (lcommunity == NULL)) + return; + + if (aggregate->lcommunity_hash == NULL) + return; + + /* Look-up the lcommunity in the hash. + */ + aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity); + if (aggr_lcommunity) { + aggr_lcommunity->refcnt--; + + if (aggr_lcommunity->refcnt == 0) { + ret_lcomm = hash_release(aggregate->lcommunity_hash, + aggr_lcommunity); + lcommunity_free(&ret_lcomm); + + lcommunity_free(&aggregate->lcommunity); + + /* Compute aggregate's lcommunity. + */ + hash_iterate(aggregate->lcommunity_hash, + bgp_aggr_lcommunity_prepare, + &aggregate->lcommunity); + } + } +} diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h index 23c777d9f..aa4e8c69f 100644 --- a/bgpd/bgp_lcommunity.h +++ b/bgpd/bgp_lcommunity.h @@ -22,6 +22,7 @@ #define _QUAGGA_BGP_LCOMMUNITY_H #include "lib/json.h" +#include "bgpd/bgp_route.h" /* Large Communities value is twelve octets long. */ #define LCOMMUNITY_SIZE 12 @@ -70,4 +71,13 @@ extern int lcommunity_match(const struct lcommunity *, extern char *lcommunity_str(struct lcommunity *, bool make_json); extern int lcommunity_include(struct lcommunity *lcom, uint8_t *ptr); extern void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr); + +extern void bgp_compute_aggregate_lcommunity( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity); +extern void bgp_remove_lcommunity_from_aggregate( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity); +extern void bgp_aggr_lcommunity_remove(void *arg); + #endif /* _QUAGGA_BGP_LCOMMUNITY_H */ diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c index 24f93e437..4a408df85 100644 --- a/bgpd/bgp_mac.c +++ b/bgpd/bgp_mac.c @@ -106,10 +106,10 @@ struct bgp_mac_find_internal { const char *ifname; }; -static void bgp_mac_find_ifp_internal(struct hash_backet *backet, void *arg) +static void bgp_mac_find_ifp_internal(struct hash_bucket *bucket, void *arg) { struct bgp_mac_find_internal *bmfi = arg; - struct bgp_self_mac *bsm = backet->data; + struct bgp_self_mac *bsm = bucket->data; struct listnode *node; char *name; @@ -331,10 +331,10 @@ bool bgp_mac_entry_exists(struct prefix *p) return true; } -static void bgp_mac_show_mac_entry(struct hash_backet *backet, void *arg) +static void bgp_mac_show_mac_entry(struct hash_bucket *bucket, void *arg) { struct vty *vty = arg; - struct bgp_self_mac *bsm = backet->data; + struct bgp_self_mac *bsm = bucket->data; struct listnode *node; char *name; char buf_mac[ETHER_ADDR_STRLEN]; diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index d0ccdcedf..765170d1a 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1073,9 +1073,13 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ return; } - if (debug) - zlog_debug("%s: updating to vrf %s", __func__, - bgp_vrf->name_pretty); + if (debug) { + char buf_prefix[PREFIX_STRLEN]; + + prefix2str(p, buf_prefix, sizeof(buf_prefix)); + zlog_debug("%s: updating %s to vrf %s", __func__, + buf_prefix, bgp_vrf->name_pretty); + } bgp_attr_dup(&static_attr, path_vpn->attr); /* shallow copy */ @@ -1088,8 +1092,6 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ */ uint8_t nhfamily = NEXTHOP_FAMILY(path_vpn->attr->mp_nexthop_len); - if (nhfamily != AF_UNSPEC) - static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); memset(&nexthop_orig, 0, sizeof(nexthop_orig)); nexthop_orig.family = nhfamily; @@ -1109,6 +1111,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ static_attr.mp_nexthop_len = path_vpn->attr->mp_nexthop_len; } + static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); break; case AF_INET6: /* save */ @@ -1132,6 +1135,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ memset(&info, 0, sizeof(info)); info.peer = bgp_vrf->peer_self; info.attr = &static_attr; + info.extra = path_vpn->extra; /* Used for source-vrf filter */ ret = route_map_apply(bgp_vrf->vpn_policy[afi] .rmap[BGP_VPN_POLICY_DIR_FROMVPN], p, RMAP_BGP, &info); diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index e15b8f4ec..4153da5a6 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -670,8 +670,7 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen, listener->fd = sock; /* this socket needs a change of ns. record bgp back pointer */ - if (bgp->vrf_id != VRF_DEFAULT && vrf_is_mapped_on_netns( - vrf_lookup_by_id(bgp->vrf_id))) + if (bgp->vrf_id != VRF_DEFAULT && vrf_is_backend_netns()) listener->bgp = bgp; memcpy(&listener->su, sa, salen); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 70d3d7b69..de97b73c7 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -184,10 +184,10 @@ struct bgp_addr { struct list *ifp_name_list; }; -static void show_address_entry(struct hash_backet *backet, void *args) +static void show_address_entry(struct hash_bucket *bucket, void *args) { struct vty *vty = (struct vty *)args; - struct bgp_addr *addr = (struct bgp_addr *)backet->data; + struct bgp_addr *addr = (struct bgp_addr *)bucket->data; char *name; struct listnode *node; @@ -204,7 +204,7 @@ static void show_address_entry(struct hash_backet *backet, void *args) void bgp_nexthop_show_address_hash(struct vty *vty, struct bgp *bgp) { hash_iterate(bgp->address_hash, - (void (*)(struct hash_backet *, void *))show_address_entry, + (void (*)(struct hash_bucket *, void *))show_address_entry, vty); } diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 3018124f4..7af5827d0 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -49,7 +49,7 @@ So there is many configurable point. First of all we want set each peer whether we send capability negotiation to the peer or not. - Next, if we send capability to the peer we want to set my capabilty + Next, if we send capability to the peer we want to set my capability inforation at each peer. */ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index 0fc321bdf..8359f59a4 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -49,7 +49,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_DYNAMIC_OLD 66 /* Dynamic Capability, deprecated since 2003 */ #define CAPABILITY_CODE_DYNAMIC 67 /* Dynamic Capability */ #define CAPABILITY_CODE_ADDPATH 69 /* Addpath Capability */ -#define CAPABILITY_CODE_FQDN 73 /* Advertise hostname capabilty */ +#define CAPABILITY_CODE_FQDN 73 /* Advertise hostname capability */ #define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */ #define CAPABILITY_CODE_REFRESH_OLD 128 /* Route Refresh Capability(cisco) */ #define CAPABILITY_CODE_ORF_OLD 130 /* Cooperative Route Filtering Capability(cisco) */ diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index f00215470..4c51db8e1 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -38,6 +38,7 @@ DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry") DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match") DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action") +DEFINE_MTYPE_STATIC(BGPD, PBR_RULE, "PBR rule") DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context") DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value") @@ -66,9 +67,28 @@ struct bgp_pbr_action_unique { struct bgp_pbr_action *bpa_found; }; -static int bgp_pbr_action_walkcb(struct hash_backet *backet, void *arg) +struct bgp_pbr_rule_unique { + uint32_t unique; + struct bgp_pbr_rule *bpr_found; +}; + +static int bgp_pbr_rule_walkcb(struct hash_bucket *bucket, void *arg) { - struct bgp_pbr_action *bpa = (struct bgp_pbr_action *)backet->data; + struct bgp_pbr_rule *bpr = (struct bgp_pbr_rule *)bucket->data; + struct bgp_pbr_rule_unique *bpru = (struct bgp_pbr_rule_unique *) + arg; + uint32_t unique = bpru->unique; + + if (bpr->unique == unique) { + bpru->bpr_found = bpr; + return HASHWALK_ABORT; + } + return HASHWALK_CONTINUE; +} + +static int bgp_pbr_action_walkcb(struct hash_bucket *bucket, void *arg) +{ + struct bgp_pbr_action *bpa = (struct bgp_pbr_action *)bucket->data; struct bgp_pbr_action_unique *bpau = (struct bgp_pbr_action_unique *) arg; uint32_t unique = bpau->unique; @@ -80,10 +100,10 @@ static int bgp_pbr_action_walkcb(struct hash_backet *backet, void *arg) return HASHWALK_CONTINUE; } -static int bgp_pbr_match_entry_walkcb(struct hash_backet *backet, void *arg) +static int bgp_pbr_match_entry_walkcb(struct hash_bucket *bucket, void *arg) { struct bgp_pbr_match_entry *bpme = - (struct bgp_pbr_match_entry *)backet->data; + (struct bgp_pbr_match_entry *)bucket->data; struct bgp_pbr_match_entry_unique *bpmeu = (struct bgp_pbr_match_entry_unique *)arg; uint32_t unique = bpmeu->unique; @@ -100,9 +120,9 @@ struct bgp_pbr_match_ipsetname { struct bgp_pbr_match *bpm_found; }; -static int bgp_pbr_match_pername_walkcb(struct hash_backet *backet, void *arg) +static int bgp_pbr_match_pername_walkcb(struct hash_bucket *bucket, void *arg) { - struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)backet->data; + struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data; struct bgp_pbr_match_ipsetname *bpmi = (struct bgp_pbr_match_ipsetname *)arg; char *ipset_name = bpmi->ipsetname; @@ -115,9 +135,9 @@ static int bgp_pbr_match_pername_walkcb(struct hash_backet *backet, void *arg) return HASHWALK_CONTINUE; } -static int bgp_pbr_match_iptable_walkcb(struct hash_backet *backet, void *arg) +static int bgp_pbr_match_iptable_walkcb(struct hash_bucket *bucket, void *arg) { - struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)backet->data; + struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data; struct bgp_pbr_match_iptable_unique *bpmiu = (struct bgp_pbr_match_iptable_unique *)arg; uint32_t unique = bpmiu->unique; @@ -134,9 +154,9 @@ struct bgp_pbr_match_unique { struct bgp_pbr_match *bpm_found; }; -static int bgp_pbr_match_walkcb(struct hash_backet *backet, void *arg) +static int bgp_pbr_match_walkcb(struct hash_bucket *bucket, void *arg) { - struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)backet->data; + struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data; struct bgp_pbr_match_unique *bpmu = (struct bgp_pbr_match_unique *) arg; uint32_t unique = bpmu->unique; @@ -200,9 +220,11 @@ struct bgp_pbr_val_mask { * so that BGP can create pbr instructions to ZEBRA */ struct bgp_pbr_filter { + uint8_t type; vrf_id_t vrf_id; struct prefix *src; struct prefix *dst; + uint8_t bitmask_iprule; uint8_t protocol; struct bgp_pbr_range_port *pkt_len; struct bgp_pbr_range_port *src_port; @@ -448,6 +470,11 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api) { bool enumerate_icmp = false; + if (api->type == BGP_PBR_UNDEFINED) { + if (BGP_DEBUG(pbr, PBR)) + zlog_debug("BGP: pbr entry undefined. cancel."); + return 0; + } /* because bgp pbr entry may contain unsupported * combinations, a message will be displayed here if * not supported. @@ -612,13 +639,45 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api) " too complex. ignoring."); return 0; } - if (!(api->match_bitmask & PREFIX_SRC_PRESENT) && - !(api->match_bitmask & PREFIX_DST_PRESENT)) { + /* iprule only supports redirect IP */ + if (api->type == BGP_PBR_IPRULE) { + int i; + + for (i = 0; i < api->action_num; i++) { + if (api->actions[i].action == ACTION_TRAFFICRATE && + api->actions[i].u.r.rate == 0) { + if (BGP_DEBUG(pbr, PBR)) { + bgp_pbr_print_policy_route(api); + zlog_debug("BGP: iprule match actions" + " drop not supported"); + } + return 0; + } + if (api->actions[i].action == ACTION_MARKING) { + if (BGP_DEBUG(pbr, PBR)) { + bgp_pbr_print_policy_route(api); + zlog_warn("PBR: iprule set DSCP %u" + " not supported", + api->actions[i].u.marking_dscp); + } + } + if (api->actions[i].action == ACTION_REDIRECT) { + if (BGP_DEBUG(pbr, PBR)) { + bgp_pbr_print_policy_route(api); + zlog_warn("PBR: iprule redirect VRF %u" + " not supported", + api->actions[i].u.redirect_vrf); + } + } + } + + } else if (!(api->match_bitmask & PREFIX_SRC_PRESENT) && + !(api->match_bitmask & PREFIX_DST_PRESENT)) { if (BGP_DEBUG(pbr, PBR)) { bgp_pbr_print_policy_route(api); zlog_debug("BGP: match actions without src" - " or dst address can not operate." - " ignoring."); + " or dst address can not operate." + " ignoring."); } return 0; } @@ -832,6 +891,34 @@ static void *bgp_pbr_match_alloc_intern(void *arg) return new; } +static void bgp_pbr_rule_free(void *arg) +{ + struct bgp_pbr_rule *bpr; + + bpr = (struct bgp_pbr_rule *)arg; + + /* delete iprule */ + if (bpr->installed) { + bgp_send_pbr_rule_action(bpr->action, bpr, false); + bpr->installed = false; + bpr->action->refcnt--; + bpr->action = NULL; + } + XFREE(MTYPE_PBR_RULE, bpr); +} + +static void *bgp_pbr_rule_alloc_intern(void *arg) +{ + struct bgp_pbr_rule *bpr, *new; + + bpr = (struct bgp_pbr_rule *)arg; + + new = XCALLOC(MTYPE_PBR_RULE, sizeof(*new)); + memcpy(new, bpr, sizeof(*bpr)); + + return new; +} + static void bgp_pbr_action_free(void *arg) { struct bgp_pbr_action *bpa; @@ -840,7 +927,7 @@ static void bgp_pbr_action_free(void *arg) if (bpa->refcnt == 0) { if (bpa->installed && bpa->table_id != 0) { - bgp_send_pbr_rule_action(bpa, false); + bgp_send_pbr_rule_action(bpa, NULL, false); bgp_zebra_announce_default(bpa->bgp, &(bpa->nh), AFI_IP, bpa->table_id, @@ -932,6 +1019,44 @@ bool bgp_pbr_match_hash_equal(const void *arg1, const void *arg2) return true; } +uint32_t bgp_pbr_rule_hash_key(void *arg) +{ + struct bgp_pbr_rule *pbr = (struct bgp_pbr_rule *)arg; + uint32_t key; + + key = prefix_hash_key(&pbr->src); + key = jhash_1word(pbr->vrf_id, key); + key = jhash_1word(pbr->flags, key); + return jhash_1word(prefix_hash_key(&pbr->dst), key); +} + +bool bgp_pbr_rule_hash_equal(const void *arg1, const void *arg2) +{ + const struct bgp_pbr_rule *r1, *r2; + + r1 = (const struct bgp_pbr_rule *)arg1; + r2 = (const struct bgp_pbr_rule *)arg2; + + if (r1->vrf_id != r2->vrf_id) + return false; + + if (r1->flags != r2->flags) + return false; + + if (r1->action != r2->action) + return false; + + if ((r1->flags & MATCH_IP_SRC_SET) && + !prefix_same(&r1->src, &r2->src)) + return false; + + if ((r1->flags & MATCH_IP_DST_SET) && + !prefix_same(&r1->dst, &r2->dst)) + return false; + + return true; +} + uint32_t bgp_pbr_match_entry_hash_key(void *arg) { struct bgp_pbr_match_entry *pbme; @@ -1017,6 +1142,20 @@ bool bgp_pbr_action_hash_equal(const void *arg1, const void *arg2) return true; } +struct bgp_pbr_rule *bgp_pbr_rule_lookup(vrf_id_t vrf_id, + uint32_t unique) +{ + struct bgp *bgp = bgp_lookup_by_vrf_id(vrf_id); + struct bgp_pbr_rule_unique bpru; + + if (!bgp || unique == 0) + return NULL; + bpru.unique = unique; + bpru.bpr_found = NULL; + hash_walk(bgp->pbr_rule_hash, bgp_pbr_rule_walkcb, &bpru); + return bpru.bpr_found; +} + struct bgp_pbr_action *bgp_pbr_action_rule_lookup(vrf_id_t vrf_id, uint32_t unique) { @@ -1090,6 +1229,11 @@ void bgp_pbr_cleanup(struct bgp *bgp) hash_free(bgp->pbr_match_hash); bgp->pbr_match_hash = NULL; } + if (bgp->pbr_rule_hash) { + hash_clean(bgp->pbr_rule_hash, bgp_pbr_rule_free); + hash_free(bgp->pbr_rule_hash); + bgp->pbr_rule_hash = NULL; + } if (bgp->pbr_action_hash) { hash_clean(bgp->pbr_action_hash, bgp_pbr_action_free); hash_free(bgp->pbr_action_hash); @@ -1113,6 +1257,11 @@ void bgp_pbr_init(struct bgp *bgp) bgp_pbr_action_hash_equal, "Match Hash Entry"); + bgp->pbr_rule_hash = + hash_create_size(8, bgp_pbr_rule_hash_key, + bgp_pbr_rule_hash_equal, + "Match Rule"); + bgp->bgp_pbr_cfg = XCALLOC(MTYPE_PBR, sizeof(struct bgp_pbr_config)); bgp->bgp_pbr_cfg->pbr_interface_any_ipv4 = true; } @@ -1253,6 +1402,42 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api) zlog_info("%s", return_string); } +static void bgp_pbr_flush_iprule(struct bgp *bgp, struct bgp_pbr_action *bpa, + struct bgp_pbr_rule *bpr) +{ + /* if bpr is null, do nothing + */ + if (bpr == NULL) + return; + if (bpr->installed) { + bgp_send_pbr_rule_action(bpa, bpr, false); + bpr->installed = false; + bpr->action->refcnt--; + bpr->action = NULL; + if (bpr->path) { + struct bgp_path_info *path; + struct bgp_path_info_extra *extra; + + /* unlink path to bpme */ + path = (struct bgp_path_info *)bpr->path; + extra = bgp_path_info_extra_get(path); + listnode_delete(extra->bgp_fs_iprule, bpr); + bpr->path = NULL; + } + } + hash_release(bgp->pbr_rule_hash, bpr); + if (bpa->refcnt == 0) { + if (bpa->installed && bpa->table_id != 0) { + bgp_send_pbr_rule_action(bpa, NULL, false); + bgp_zebra_announce_default(bpa->bgp, &(bpa->nh), + AFI_IP, + bpa->table_id, + false); + bpa->installed = false; + } + } +} + static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa, struct bgp_pbr_match *bpm, struct bgp_pbr_match_entry *bpme) @@ -1270,11 +1455,10 @@ static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa, struct bgp_path_info *path; struct bgp_path_info_extra *extra; - /* unlink bgp_path_info to bpme */ + /* unlink path to bpme */ path = (struct bgp_path_info *)bpme->path; extra = bgp_path_info_extra_get(path); - if (extra->bgp_fs_pbr) - listnode_delete(extra->bgp_fs_pbr, bpme); + listnode_delete(extra->bgp_fs_pbr, bpme); bpme->path = NULL; } } @@ -1300,7 +1484,7 @@ static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa, } if (bpa->refcnt == 0) { if (bpa->installed && bpa->table_id != 0) { - bgp_send_pbr_rule_action(bpa, false); + bgp_send_pbr_rule_action(bpa, NULL, false); bgp_zebra_announce_default(bpa->bgp, &(bpa->nh), AFI_IP, bpa->table_id, @@ -1315,9 +1499,53 @@ struct bgp_pbr_match_entry_remain { struct bgp_pbr_match_entry *bpme_found; }; -static int bgp_pbr_get_remaining_entry(struct hash_backet *backet, void *arg) +struct bgp_pbr_rule_remain { + struct bgp_pbr_rule *bpr_to_match; + struct bgp_pbr_rule *bpr_found; +}; + +static int bgp_pbr_get_same_rule(struct hash_bucket *bucket, void *arg) { - struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)backet->data; + struct bgp_pbr_rule *r1 = (struct bgp_pbr_rule *)bucket->data; + struct bgp_pbr_rule_remain *ctxt = + (struct bgp_pbr_rule_remain *)arg; + struct bgp_pbr_rule *r2; + + r2 = ctxt->bpr_to_match; + + if (r1->vrf_id != r2->vrf_id) + return HASHWALK_CONTINUE; + + if (r1->flags != r2->flags) + return HASHWALK_CONTINUE; + + if ((r1->flags & MATCH_IP_SRC_SET) && + !prefix_same(&r1->src, &r2->src)) + return HASHWALK_CONTINUE; + + if ((r1->flags & MATCH_IP_DST_SET) && + !prefix_same(&r1->dst, &r2->dst)) + return HASHWALK_CONTINUE; + + /* this function is used for two cases: + * - remove an entry upon withdraw request + * (case r2->action is null) + * - replace an old iprule with different action + * (case r2->action is != null) + * the old one is removed after the new one + * this is to avoid disruption in traffic + */ + if (r2->action == NULL || + r1->action != r2->action) { + ctxt->bpr_found = r1; + return HASHWALK_ABORT; + } + return HASHWALK_CONTINUE; +} + +static int bgp_pbr_get_remaining_entry(struct hash_bucket *bucket, void *arg) +{ + struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data; struct bgp_pbr_match_entry_remain *bpmer = (struct bgp_pbr_match_entry_remain *)arg; struct bgp_pbr_match *bpm_temp; @@ -1352,12 +1580,15 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit( { struct bgp_pbr_match temp; struct bgp_pbr_match_entry temp2; + struct bgp_pbr_rule pbr_rule; + struct bgp_pbr_rule *bpr; struct bgp_pbr_match *bpm; struct bgp_pbr_match_entry *bpme; struct bgp_pbr_match_entry_remain bpmer; struct bgp_pbr_range_port *src_port; struct bgp_pbr_range_port *dst_port; struct bgp_pbr_range_port *pkt_len; + struct bgp_pbr_rule_remain bprr; if (!bpf) return; @@ -1374,6 +1605,37 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit( */ memset(&temp2, 0, sizeof(temp2)); memset(&temp, 0, sizeof(temp)); + + if (bpf->type == BGP_PBR_IPRULE) { + memset(&pbr_rule, 0, sizeof(pbr_rule)); + pbr_rule.vrf_id = bpf->vrf_id; + if (bpf->src) { + prefix_copy(&pbr_rule.src, bpf->src); + pbr_rule.flags |= MATCH_IP_SRC_SET; + } + if (bpf->dst) { + prefix_copy(&pbr_rule.dst, bpf->dst); + pbr_rule.flags |= MATCH_IP_DST_SET; + } + bpr = &pbr_rule; + /* A previous entry may already exist + * flush previous entry if necessary + */ + bprr.bpr_to_match = bpr; + bprr.bpr_found = NULL; + hash_walk(bgp->pbr_rule_hash, bgp_pbr_get_same_rule, &bprr); + if (bprr.bpr_found) { + static struct bgp_pbr_rule *local_bpr; + static struct bgp_pbr_action *local_bpa; + + local_bpr = bprr.bpr_found; + local_bpa = local_bpr->action; + bgp_pbr_flush_iprule(bgp, local_bpa, + local_bpr); + } + return; + } + if (bpf->src) { temp.flags |= MATCH_IP_SRC_SET; prefix_copy(&temp2.src, bpf->src); @@ -1732,9 +1994,13 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, struct bgp_pbr_action temp3; struct bgp_pbr_action *bpa = NULL; struct bgp_pbr_match_entry_remain bpmer; + struct bgp_pbr_rule_remain bprr; struct bgp_pbr_range_port *src_port; struct bgp_pbr_range_port *dst_port; struct bgp_pbr_range_port *pkt_len; + struct bgp_pbr_rule pbr_rule; + struct bgp_pbr_rule *bpr; + bool bpr_found = false; bool bpme_found = false; if (!bpf) @@ -1771,7 +2037,69 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, /* 0 value is forbidden */ bpa->install_in_progress = false; } + if (bpf->type == BGP_PBR_IPRULE) { + memset(&pbr_rule, 0, sizeof(pbr_rule)); + pbr_rule.vrf_id = bpf->vrf_id; + pbr_rule.priority = 20; + if (bpf->src) { + pbr_rule.flags |= MATCH_IP_SRC_SET; + prefix_copy(&pbr_rule.src, bpf->src); + } + if (bpf->dst) { + pbr_rule.flags |= MATCH_IP_DST_SET; + prefix_copy(&pbr_rule.dst, bpf->dst); + } + pbr_rule.action = bpa; + bpr = hash_get(bgp->pbr_rule_hash, &pbr_rule, + bgp_pbr_rule_alloc_intern); + if (bpr && bpr->unique == 0) { + bpr->unique = ++bgp_pbr_action_counter_unique; + bpr->installed = false; + bpr->install_in_progress = false; + /* link bgp info to bpr */ + bpr->path = (void *)path; + } else + bpr_found = true; + /* already installed */ + if (bpr_found && bpr) { + struct bgp_path_info_extra *extra = + bgp_path_info_extra_get(path); + + if (extra && listnode_lookup(extra->bgp_fs_iprule, + bpr)) { + if (BGP_DEBUG(pbr, PBR_ERROR)) + zlog_err("%s: entry %p/%p already " + "installed in bgp pbr iprule", + __func__, path, bpr); + return; + } + } + if (!bpa->installed && !bpa->install_in_progress) { + bgp_send_pbr_rule_action(bpa, NULL, true); + bgp_zebra_announce_default(bgp, nh, + AFI_IP, bpa->table_id, true); + } + /* ip rule add */ + if (bpr && !bpr->installed) + bgp_send_pbr_rule_action(bpa, bpr, true); + /* A previous entry may already exist + * flush previous entry if necessary + */ + bprr.bpr_to_match = bpr; + bprr.bpr_found = NULL; + hash_walk(bgp->pbr_rule_hash, bgp_pbr_get_same_rule, &bprr); + if (bprr.bpr_found) { + static struct bgp_pbr_rule *local_bpr; + static struct bgp_pbr_action *local_bpa; + + local_bpr = bprr.bpr_found; + local_bpa = local_bpr->action; + bgp_pbr_flush_iprule(bgp, local_bpa, + local_bpr); + } + return; + } /* then look for bpm */ memset(&temp, 0, sizeof(temp)); temp.vrf_id = bpf->vrf_id; @@ -1885,8 +2213,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, struct bgp_path_info_extra *extra = bgp_path_info_extra_get(path); - if (extra && extra->bgp_fs_pbr && - listnode_lookup(extra->bgp_fs_pbr, bpme)) { + if (extra && listnode_lookup(extra->bgp_fs_pbr, bpme)) { if (BGP_DEBUG(pbr, PBR_ERROR)) zlog_err( "%s: entry %p/%p already installed in bgp pbr", @@ -1906,7 +2233,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, */ /* ip rule add */ if (!bpa->installed && !bpa->install_in_progress) { - bgp_send_pbr_rule_action(bpa, true); + bgp_send_pbr_rule_action(bpa, NULL, true); bgp_zebra_announce_default(bgp, nh, AFI_IP, bpa->table_id, true); } @@ -2048,10 +2375,16 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path, memset(&nh, 0, sizeof(struct nexthop)); memset(&bpf, 0, sizeof(struct bgp_pbr_filter)); memset(&bpof, 0, sizeof(struct bgp_pbr_or_filter)); - if (api->match_bitmask & PREFIX_SRC_PRESENT) + if (api->match_bitmask & PREFIX_SRC_PRESENT || + (api->type == BGP_PBR_IPRULE && + api->match_bitmask_iprule & PREFIX_SRC_PRESENT)) src = &api->src_prefix; - if (api->match_bitmask & PREFIX_DST_PRESENT) + if (api->match_bitmask & PREFIX_DST_PRESENT || + (api->type == BGP_PBR_IPRULE && + api->match_bitmask_iprule & PREFIX_DST_PRESENT)) dst = &api->dst_prefix; + if (api->type == BGP_PBR_IPRULE) + bpf.type = api->type; memset(&nh, 0, sizeof(struct nexthop)); nh.vrf_id = VRF_UNKNOWN; if (api->match_protocol_num) diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h index 45c3c9ea1..f7fddac7f 100644 --- a/bgpd/bgp_pbr.h +++ b/bgpd/bgp_pbr.h @@ -87,12 +87,10 @@ struct bgp_pbr_entry_action { /* BGP Policy Route structure */ struct bgp_pbr_entry_main { +#define BGP_PBR_UNDEFINED 0 +#define BGP_PBR_IPSET 1 +#define BGP_PBR_IPRULE 2 uint8_t type; - uint16_t instance; - - uint32_t flags; - - uint8_t message; /* * This is an enum but we are going to treat it as a uint8_t @@ -103,6 +101,7 @@ struct bgp_pbr_entry_main { #define PREFIX_SRC_PRESENT (1 << 0) #define PREFIX_DST_PRESENT (1 << 1) + uint8_t match_bitmask_iprule; uint8_t match_bitmask; uint8_t match_src_port_num; @@ -137,14 +136,6 @@ struct bgp_pbr_entry_main { uint16_t action_num; struct bgp_pbr_entry_action actions[ACTIONS_MAX_NUM]; - uint8_t distance; - - uint32_t metric; - - route_tag_t tag; - - uint32_t mtu; - vrf_id_t vrf_id; }; @@ -167,6 +158,19 @@ struct bgp_pbr_config { extern struct bgp_pbr_config *bgp_pbr_cfg; +struct bgp_pbr_rule { + uint32_t flags; + struct prefix src; + struct prefix dst; + struct bgp_pbr_action *action; + vrf_id_t vrf_id; + uint32_t unique; + uint32_t priority; + bool installed; + bool install_in_progress; + void *path; +}; + struct bgp_pbr_match { char ipset_name[ZEBRA_IPSET_NAME_SIZE]; @@ -251,6 +255,9 @@ struct bgp_pbr_action { struct bgp *bgp; }; +extern struct bgp_pbr_rule *bgp_pbr_rule_lookup(vrf_id_t vrf_id, + uint32_t unique); + extern struct bgp_pbr_action *bgp_pbr_action_rule_lookup(vrf_id_t vrf_id, uint32_t unique); @@ -266,6 +273,9 @@ extern struct bgp_pbr_match *bgp_pbr_match_iptable_lookup(vrf_id_t vrf_id, extern void bgp_pbr_cleanup(struct bgp *bgp); extern void bgp_pbr_init(struct bgp *bgp); +extern uint32_t bgp_pbr_rule_hash_key(void *arg); +extern bool bgp_pbr_rule_hash_equal(const void *arg1, + const void *arg2); extern uint32_t bgp_pbr_action_hash_key(void *arg); extern bool bgp_pbr_action_hash_equal(const void *arg1, const void *arg2); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 6bce7261a..666254a62 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -175,6 +175,8 @@ static struct bgp_path_info_extra *bgp_path_info_extra_new(void) sizeof(struct bgp_path_info_extra)); new->label[0] = MPLS_INVALID_LABEL; new->num_labels = 0; + new->bgp_fs_pbr = list_new(); + new->bgp_fs_iprule = list_new(); return new; } @@ -218,6 +220,8 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra) if (e->bgp_orig) bgp_unlock(e->bgp_orig); + if ((*extra)->bgp_fs_iprule) + list_delete(&((*extra)->bgp_fs_iprule)); if ((*extra)->bgp_fs_pbr) list_delete(&((*extra)->bgp_fs_pbr)); XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra); @@ -250,8 +254,9 @@ static void bgp_path_info_free(struct bgp_path_info *path) bgp_unlink_nexthop(path); bgp_path_info_extra_free(&path->extra); bgp_path_info_mpath_free(&path->mpath); - bgp_addpath_free_info_data(&path->tx_addpath, - path->net ? &path->net->tx_addpath : NULL); + if (path->net) + bgp_addpath_free_info_data(&path->tx_addpath, + &path->net->tx_addpath); peer_unlock(path->peer); /* bgp_path_info peer reference */ @@ -1220,6 +1225,20 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p, } } + /* RFC 8212 to prevent route leaks. + * This specification intends to improve this situation by requiring the + * explicit configuration of both BGP Import and Export Policies for any + * External BGP (EBGP) session such as customers, peers, or + * confederation boundaries for all enabled address families. Through + * codification of the aforementioned requirement, operators will + * benefit from consistent behavior across different BGP + * implementations. + */ + if (peer->bgp->ebgp_requires_policy + == DEFAULT_EBGP_POLICY_ENABLED) + if (!bgp_inbound_policy_exists(peer, filter)) + return RMAP_DENY; + /* Route map apply. */ if (rmap) { memset(&rmap_path, 0, sizeof(struct bgp_path_info)); @@ -1773,6 +1792,20 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, } } + /* RFC 8212 to prevent route leaks. + * This specification intends to improve this situation by requiring the + * explicit configuration of both BGP Import and Export Policies for any + * External BGP (EBGP) session such as customers, peers, or + * confederation boundaries for all enabled address families. Through + * codification of the aforementioned requirement, operators will + * benefit from consistent behavior across different BGP + * implementations. + */ + if (peer->bgp->ebgp_requires_policy + == DEFAULT_EBGP_POLICY_ENABLED) + if (!bgp_outbound_policy_exists(peer, filter)) + return 0; + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { @@ -2457,6 +2490,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, bgp_evpn_advertise_type5_route( bgp, &rn->p, new_select->attr, afi, safi); + else + bgp_evpn_withdraw_type5_route( + bgp, &rn->p, afi, safi); } else { bgp_evpn_advertise_type5_route(bgp, &rn->p, @@ -3245,9 +3281,11 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, /* Update MPLS label */ if (has_valid_label) { extra = bgp_path_info_extra_get(pi); - memcpy(&extra->label, label, - num_labels * sizeof(mpls_label_t)); - extra->num_labels = num_labels; + if (extra->label != label) { + memcpy(&extra->label, label, + num_labels * sizeof(mpls_label_t)); + extra->num_labels = num_labels; + } if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) bgp_set_valid_label(&extra->label[0]); } @@ -3416,8 +3454,11 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, /* Update MPLS label */ if (has_valid_label) { extra = bgp_path_info_extra_get(new); - memcpy(&extra->label, label, num_labels * sizeof(mpls_label_t)); - extra->num_labels = num_labels; + if (extra->label != label) { + memcpy(&extra->label, label, + num_labels * sizeof(mpls_label_t)); + extra->num_labels = num_labels; + } if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) bgp_set_valid_label(&extra->label[0]); } @@ -4152,6 +4193,26 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) } } +int bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) +{ + if (peer->sort == BGP_PEER_EBGP + && (ROUTE_MAP_OUT_NAME(filter) || PREFIX_LIST_OUT_NAME(filter) + || FILTER_LIST_OUT_NAME(filter) + || DISTRIBUTE_OUT_NAME(filter))) + return 1; + return 0; +} + +int bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter) +{ + if (peer->sort == BGP_PEER_EBGP + && (ROUTE_MAP_IN_NAME(filter) || PREFIX_LIST_IN_NAME(filter) + || FILTER_LIST_IN_NAME(filter) + || DISTRIBUTE_IN_NAME(filter))) + return 1; + return 0; +} + static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table, safi_t safi) { @@ -4409,6 +4470,8 @@ static void bgp_static_free(struct bgp_static *bgp_static) { if (bgp_static->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); + route_map_counter_decrement(bgp_static->rmap.map); + if (bgp_static->eth_s_id) XFREE(MTYPE_ATTR, bgp_static->eth_s_id); XFREE(MTYPE_BGP_STATIC, bgp_static); @@ -4973,14 +5036,20 @@ static int bgp_static_set(struct vty *vty, const char *negate, if (bgp_static->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); + route_map_counter_decrement( + bgp_static->rmap.map); bgp_static->rmap.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); bgp_static->rmap.map = route_map_lookup_by_name(rmap); + route_map_counter_increment( + bgp_static->rmap.map); } else { if (bgp_static->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); + route_map_counter_decrement( + bgp_static->rmap.map); bgp_static->rmap.name = NULL; bgp_static->rmap.map = NULL; bgp_static->valid = 0; @@ -4999,10 +5068,14 @@ static int bgp_static_set(struct vty *vty, const char *negate, if (bgp_static->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); + route_map_counter_decrement( + bgp_static->rmap.map); bgp_static->rmap.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); bgp_static->rmap.map = route_map_lookup_by_name(rmap); + route_map_counter_increment( + bgp_static->rmap.map); } bgp_node_set_bgp_static_info(rn, bgp_static); } @@ -5081,6 +5154,9 @@ void bgp_static_delete(struct bgp *bgp) bgp_static = bgp_node_get_bgp_static_info( rm); + if (!bgp_static) + continue; + bgp_static_withdraw_safi( bgp, &rm->p, AFI_IP, safi, (struct prefix_rd *)&rn->p); @@ -5257,8 +5333,6 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty, if (!bgp_node_has_bgp_path_info_data(prn)) bgp_node_set_bgp_table_info(prn, bgp_table_init(bgp, afi, safi)); - else - bgp_unlock_node(prn); table = bgp_node_get_bgp_table_info(prn); rn = bgp_node_get(table, &p); @@ -5280,10 +5354,12 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty, if (bgp_static->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); + route_map_counter_decrement(bgp_static->rmap.map); bgp_static->rmap.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_str); bgp_static->rmap.map = route_map_lookup_by_name(rmap_str); + route_map_counter_increment(bgp_static->rmap.map); } if (safi == SAFI_EVPN) { @@ -5386,11 +5462,14 @@ static int bgp_table_map_set(struct vty *vty, afi_t afi, safi_t safi, if (rmap_name) { if (rmap->name) XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); + route_map_counter_decrement(rmap->map); rmap->name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name); rmap->map = route_map_lookup_by_name(rmap_name); + route_map_counter_increment(rmap->map); } else { if (rmap->name) XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); + route_map_counter_decrement(rmap->map); rmap->name = NULL; rmap->map = NULL; } @@ -5410,6 +5489,7 @@ static int bgp_table_map_unset(struct vty *vty, afi_t afi, safi_t safi, rmap = &bgp->table_map[afi][safi]; if (rmap->name) XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); + route_map_counter_decrement(rmap->map); rmap->name = NULL; rmap->map = NULL; @@ -5504,33 +5584,6 @@ DEFPY(ipv6_bgp_network, label_index ? (uint32_t)label_index : BGP_INVALID_LABEL_INDEX); } -/* Aggreagete address: - - advertise-map Set condition to advertise attribute - as-set Generate AS set path information - attribute-map Set attributes of aggregate - route-map Set parameters of aggregate - summary-only Filter more specific routes from updates - suppress-map Conditionally filter more specific routes from updates - <cr> - */ -struct bgp_aggregate { - /* Summary-only flag. */ - uint8_t summary_only; - - /* AS set generation. */ - uint8_t as_set; - - /* Route-map for aggregated route. */ - struct route_map *map; - - /* Suppress-count. */ - unsigned long count; - - /* SAFI configuration. */ - safi_t safi; -}; - static struct bgp_aggregate *bgp_aggregate_new(void) { return XCALLOC(MTYPE_BGP_AGGREGATE, sizeof(struct bgp_aggregate)); @@ -5656,8 +5709,7 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, /* Update an aggregate as routes are added/removed from the BGP table */ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, - struct bgp_path_info *pinew, afi_t afi, - safi_t safi, struct bgp_path_info *del, + afi_t afi, safi_t safi, struct bgp_aggregate *aggregate) { struct bgp_table *table; @@ -5665,13 +5717,9 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, struct bgp_node *rn; uint8_t origin; struct aspath *aspath = NULL; - struct aspath *asmerge = NULL; struct community *community = NULL; - struct community *commerge = NULL; struct ecommunity *ecommunity = NULL; - struct ecommunity *ecommerge = NULL; struct lcommunity *lcommunity = NULL; - struct lcommunity *lcommerge = NULL; struct bgp_path_info *pi; unsigned long match = 0; uint8_t atomic_aggregate = 0; @@ -5700,9 +5748,6 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, if (BGP_PATH_HOLDDOWN(pi)) continue; - if (del && pi == del) - continue; - if (pi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) atomic_aggregate = 1; @@ -5733,8 +5778,18 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, * route MUST have the ORIGIN attribute with the value * EGP. */ - if (origin < pi->attr->origin) - origin = pi->attr->origin; + switch (pi->attr->origin) { + case BGP_ORIGIN_INCOMPLETE: + aggregate->incomplete_origin_count++; + break; + case BGP_ORIGIN_EGP: + aggregate->egp_origin_count++; + break; + default: + /*Do nothing. + */ + break; + } if (!aggregate->as_set) continue; @@ -5743,130 +5798,68 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, * as-set aggregate route generate origin, as path, * and community aggregation. */ - if (aspath) { - asmerge = aspath_aggregate(aspath, - pi->attr->aspath); - aspath_free(aspath); - aspath = asmerge; - } else - aspath = aspath_dup(pi->attr->aspath); - - if (pi->attr->community) { - if (community) { - commerge = community_merge( - community, pi->attr->community); - community = - community_uniq_sort(commerge); - community_free(&commerge); - } else - community = community_dup( - pi->attr->community); - } - - if (pi->attr->ecommunity) { - if (ecommunity) { - ecommerge = ecommunity_merge( - ecommunity, - pi->attr->ecommunity); - ecommunity = - ecommunity_uniq_sort(ecommerge); - ecommunity_free(&ecommerge); - } else - ecommunity = ecommunity_dup( - pi->attr->ecommunity); - } - - if (pi->attr->lcommunity) { - if (lcommunity) { - lcommerge = lcommunity_merge( - lcommunity, - pi->attr->lcommunity); - lcommunity = - lcommunity_uniq_sort(lcommerge); - lcommunity_free(&lcommerge); - } else - lcommunity = lcommunity_dup( - pi->attr->lcommunity); - } + /* Compute aggregate route's as-path. + */ + bgp_compute_aggregate_aspath(aggregate, + pi->attr->aspath); + + /* Compute aggregate route's community. + */ + if (pi->attr->community) + bgp_compute_aggregate_community( + aggregate, + pi->attr->community); + + /* Compute aggregate route's extended community. + */ + if (pi->attr->ecommunity) + bgp_compute_aggregate_ecommunity( + aggregate, + pi->attr->ecommunity); + + /* Compute aggregate route's large community. + */ + if (pi->attr->lcommunity) + bgp_compute_aggregate_lcommunity( + aggregate, + pi->attr->lcommunity); } if (match) bgp_process(bgp, rn, afi, safi); } bgp_unlock_node(top); - if (pinew) { - aggregate->count++; - if (aggregate->summary_only) - (bgp_path_info_extra_get(pinew))->suppress++; + if (aggregate->incomplete_origin_count > 0) + origin = BGP_ORIGIN_INCOMPLETE; + else if (aggregate->egp_origin_count > 0) + origin = BGP_ORIGIN_EGP; - if (origin < pinew->attr->origin) - origin = pinew->attr->origin; + if (aggregate->as_set) { + if (aggregate->aspath) + /* Retrieve aggregate route's as-path. + */ + aspath = aspath_dup(aggregate->aspath); - if (aggregate->as_set) { - if (aspath) { - asmerge = aspath_aggregate(aspath, - pinew->attr->aspath); - aspath_free(aspath); - aspath = asmerge; - } else - aspath = aspath_dup(pinew->attr->aspath); + if (aggregate->community) + /* Retrieve aggregate route's community. + */ + community = community_dup(aggregate->community); - if (pinew->attr->community) { - if (community) { - commerge = community_merge( - community, - pinew->attr->community); - community = - community_uniq_sort(commerge); - community_free(&commerge); - } else - community = community_dup( - pinew->attr->community); - } + if (aggregate->ecommunity) + /* Retrieve aggregate route's ecommunity. + */ + ecommunity = ecommunity_dup(aggregate->ecommunity); - if (pinew->attr->ecommunity) { - if (ecommunity) { - ecommerge = ecommunity_merge( - ecommunity, - pinew->attr->ecommunity); - ecommunity = - ecommunity_uniq_sort(ecommerge); - ecommunity_free(&ecommerge); - } else - ecommunity = ecommunity_dup( - pinew->attr->ecommunity); - } - - if (pinew->attr->lcommunity) { - if (lcommunity) { - lcommerge = lcommunity_merge( - lcommunity, - pinew->attr->lcommunity); - lcommunity = - lcommunity_uniq_sort(lcommerge); - lcommunity_free(&lcommerge); - } else - lcommunity = lcommunity_dup( - pinew->attr->lcommunity); - } - } + if (aggregate->lcommunity) + /* Retrieve aggregate route's lcommunity. + */ + lcommunity = lcommunity_dup(aggregate->lcommunity); } bgp_aggregate_install(bgp, afi, safi, p, origin, aspath, community, ecommunity, lcommunity, atomic_aggregate, aggregate); - - if (aggregate->count == 0) { - if (aspath) - aspath_free(aspath); - if (community) - community_free(&community); - if (ecommunity) - ecommunity_free(&ecommunity); - if (lcommunity) - lcommunity_free(&lcommunity); - } } static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, @@ -5905,6 +5898,41 @@ static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, } } aggregate->count--; + + if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE) + aggregate->incomplete_origin_count--; + else if (pi->attr->origin == BGP_ORIGIN_EGP) + aggregate->egp_origin_count--; + + if (aggregate->as_set) { + /* Remove as-path from aggregate. + */ + bgp_remove_aspath_from_aggregate( + aggregate, + pi->attr->aspath); + + if (pi->attr->community) + /* Remove community from aggregate. + */ + bgp_remove_community_from_aggregate( + aggregate, + pi->attr->community); + + if (pi->attr->ecommunity) + /* Remove ecommunity from aggregate. + */ + bgp_remove_ecommunity_from_aggregate( + aggregate, + pi->attr->ecommunity); + + if (pi->attr->lcommunity) + /* Remove lcommunity from aggregate. + */ + bgp_remove_lcommunity_from_aggregate( + aggregate, + pi->attr->lcommunity); + } + } /* If this node was suppressed, process the change. */ @@ -5914,6 +5942,210 @@ static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, bgp_unlock_node(top); } +static void bgp_add_route_to_aggregate(struct bgp *bgp, struct prefix *aggr_p, + struct bgp_path_info *pinew, afi_t afi, + safi_t safi, + struct bgp_aggregate *aggregate) +{ + uint8_t origin; + struct aspath *aspath = NULL; + uint8_t atomic_aggregate = 0; + struct community *community = NULL; + struct ecommunity *ecommunity = NULL; + struct lcommunity *lcommunity = NULL; + + /* ORIGIN attribute: If at least one route among routes that are + * aggregated has ORIGIN with the value INCOMPLETE, then the + * aggregated route must have the ORIGIN attribute with the value + * INCOMPLETE. Otherwise, if at least one route among routes that + * are aggregated has ORIGIN with the value EGP, then the aggregated + * route must have the origin attribute with the value EGP. In all + * other case the value of the ORIGIN attribute of the aggregated + * route is INTERNAL. + */ + origin = BGP_ORIGIN_IGP; + + aggregate->count++; + + if (aggregate->summary_only) + (bgp_path_info_extra_get(pinew))->suppress++; + + switch (pinew->attr->origin) { + case BGP_ORIGIN_INCOMPLETE: + aggregate->incomplete_origin_count++; + break; + case BGP_ORIGIN_EGP: + aggregate->egp_origin_count++; + break; + default: + /* Do nothing. + */ + break; + } + + if (aggregate->incomplete_origin_count > 0) + origin = BGP_ORIGIN_INCOMPLETE; + else if (aggregate->egp_origin_count > 0) + origin = BGP_ORIGIN_EGP; + + if (aggregate->as_set) { + /* Compute aggregate route's as-path. + */ + bgp_compute_aggregate_aspath(aggregate, + pinew->attr->aspath); + + /* Compute aggregate route's community. + */ + if (pinew->attr->community) + bgp_compute_aggregate_community( + aggregate, + pinew->attr->community); + + /* Compute aggregate route's extended community. + */ + if (pinew->attr->ecommunity) + bgp_compute_aggregate_ecommunity( + aggregate, + pinew->attr->ecommunity); + + /* Compute aggregate route's large community. + */ + if (pinew->attr->lcommunity) + bgp_compute_aggregate_lcommunity( + aggregate, + pinew->attr->lcommunity); + + /* Retrieve aggregate route's as-path. + */ + if (aggregate->aspath) + aspath = aspath_dup(aggregate->aspath); + + /* Retrieve aggregate route's community. + */ + if (aggregate->community) + community = community_dup(aggregate->community); + + /* Retrieve aggregate route's ecommunity. + */ + if (aggregate->ecommunity) + ecommunity = ecommunity_dup(aggregate->ecommunity); + + /* Retrieve aggregate route's lcommunity. + */ + if (aggregate->lcommunity) + lcommunity = lcommunity_dup(aggregate->lcommunity); + } + + bgp_aggregate_install(bgp, afi, safi, aggr_p, origin, + aspath, community, ecommunity, + lcommunity, atomic_aggregate, aggregate); +} + +static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, + safi_t safi, + struct bgp_path_info *pi, + struct bgp_aggregate *aggregate, + struct prefix *aggr_p) +{ + uint8_t origin; + struct aspath *aspath = NULL; + uint8_t atomic_aggregate = 0; + struct community *community = NULL; + struct ecommunity *ecommunity = NULL; + struct lcommunity *lcommunity = NULL; + unsigned long match = 0; + + if (BGP_PATH_HOLDDOWN(pi)) + return; + + if (pi->sub_type == BGP_ROUTE_AGGREGATE) + return; + + if (aggregate->summary_only + && pi->extra + && pi->extra->suppress > 0) { + pi->extra->suppress--; + + if (pi->extra->suppress == 0) { + bgp_path_info_set_flag(pi->net, pi, + BGP_PATH_ATTR_CHANGED); + match++; + } + } + + if (aggregate->count > 0) + aggregate->count--; + + if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE) + aggregate->incomplete_origin_count--; + else if (pi->attr->origin == BGP_ORIGIN_EGP) + aggregate->egp_origin_count--; + + if (aggregate->as_set) { + /* Remove as-path from aggregate. + */ + bgp_remove_aspath_from_aggregate(aggregate, + pi->attr->aspath); + + if (pi->attr->community) + /* Remove community from aggregate. + */ + bgp_remove_community_from_aggregate( + aggregate, + pi->attr->community); + + if (pi->attr->ecommunity) + /* Remove ecommunity from aggregate. + */ + bgp_remove_ecommunity_from_aggregate( + aggregate, + pi->attr->ecommunity); + + if (pi->attr->lcommunity) + /* Remove lcommunity from aggregate. + */ + bgp_remove_lcommunity_from_aggregate( + aggregate, + pi->attr->lcommunity); + } + + /* If this node was suppressed, process the change. */ + if (match) + bgp_process(bgp, pi->net, afi, safi); + + origin = BGP_ORIGIN_IGP; + if (aggregate->incomplete_origin_count > 0) + origin = BGP_ORIGIN_INCOMPLETE; + else if (aggregate->egp_origin_count > 0) + origin = BGP_ORIGIN_EGP; + + if (aggregate->as_set) { + /* Retrieve aggregate route's as-path. + */ + if (aggregate->aspath) + aspath = aspath_dup(aggregate->aspath); + + /* Retrieve aggregate route's community. + */ + if (aggregate->community) + community = community_dup(aggregate->community); + + /* Retrieve aggregate route's ecommunity. + */ + if (aggregate->ecommunity) + ecommunity = ecommunity_dup(aggregate->ecommunity); + + /* Retrieve aggregate route's lcommunity. + */ + if (aggregate->lcommunity) + lcommunity = lcommunity_dup(aggregate->lcommunity); + } + + bgp_aggregate_install(bgp, afi, safi, aggr_p, origin, + aspath, community, ecommunity, + lcommunity, atomic_aggregate, aggregate); +} + void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p, struct bgp_path_info *pi, afi_t afi, safi_t safi) { @@ -5940,9 +6172,8 @@ void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p, for (rn = child; rn; rn = bgp_node_parent_nolock(rn)) { aggregate = bgp_node_get_bgp_aggregate_info(rn); if (aggregate != NULL && rn->p.prefixlen < p->prefixlen) { - bgp_aggregate_delete(bgp, &rn->p, afi, safi, aggregate); - bgp_aggregate_route(bgp, &rn->p, pi, afi, safi, NULL, - aggregate); + bgp_add_route_to_aggregate(bgp, &rn->p, pi, afi, + safi, aggregate); } } bgp_unlock_node(child); @@ -5971,9 +6202,8 @@ void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p, for (rn = child; rn; rn = bgp_node_parent_nolock(rn)) { aggregate = bgp_node_get_bgp_aggregate_info(rn); if (aggregate != NULL && rn->p.prefixlen < p->prefixlen) { - bgp_aggregate_delete(bgp, &rn->p, afi, safi, aggregate); - bgp_aggregate_route(bgp, &rn->p, NULL, afi, safi, del, - aggregate); + bgp_remove_route_from_aggregate(bgp, afi, safi, + del, aggregate, &rn->p); } } bgp_unlock_node(child); @@ -6015,6 +6245,59 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str, /* Unlock aggregate address configuration. */ bgp_node_set_bgp_aggregate_info(rn, NULL); + + if (aggregate->community) + community_free(&aggregate->community); + + if (aggregate->community_hash) { + /* Delete all communities in the hash. + */ + hash_clean(aggregate->community_hash, + bgp_aggr_community_remove); + /* Free up the community_hash. + */ + hash_free(aggregate->community_hash); + } + + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); + + if (aggregate->ecommunity_hash) { + /* Delete all ecommunities in the hash. + */ + hash_clean(aggregate->ecommunity_hash, + bgp_aggr_ecommunity_remove); + /* Free up the ecommunity_hash. + */ + hash_free(aggregate->ecommunity_hash); + } + + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + + if (aggregate->lcommunity_hash) { + /* Delete all lcommunities in the hash. + */ + hash_clean(aggregate->lcommunity_hash, + bgp_aggr_lcommunity_remove); + /* Free up the lcommunity_hash. + */ + hash_free(aggregate->lcommunity_hash); + } + + if (aggregate->aspath) + aspath_free(aggregate->aspath); + + if (aggregate->aspath_hash) { + /* Delete all as-paths in the hash. + */ + hash_clean(aggregate->aspath_hash, + bgp_aggr_aspath_remove); + /* Free up the aspath_hash. + */ + hash_free(aggregate->aspath_hash); + } + bgp_aggregate_free(aggregate); bgp_unlock_node(rn); bgp_unlock_node(rn); @@ -6068,7 +6351,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, bgp_node_set_bgp_aggregate_info(rn, aggregate); /* Aggregate address insert into BGP routing table. */ - bgp_aggregate_route(bgp, &p, NULL, afi, safi, NULL, aggregate); + bgp_aggregate_route(bgp, &p, afi, safi, aggregate); return CMD_SUCCESS; } @@ -8378,11 +8661,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, json_pmsi = json_object_new_object(); json_object_string_add(json_pmsi, "tunnelType", str); + json_object_int_add(json_pmsi, + "label", + label2vni(&attr->label)); json_object_object_add(json_path, "pmsi", json_pmsi); } else - vty_out(vty, " PMSI Tunnel Type: %s\n", - str); + vty_out(vty, + " PMSI Tunnel Type: %s, label: %d\n", + str, label2vni(&attr->label)); } } @@ -11615,10 +11902,10 @@ DEFUN (clear_ip_bgp_dampening_address_mask, NULL, 0); } -static void show_bgp_peerhash_entry(struct hash_backet *backet, void *arg) +static void show_bgp_peerhash_entry(struct hash_bucket *bucket, void *arg) { struct vty *vty = arg; - struct peer *peer = backet->data; + struct peer *peer = bucket->data; char buf[SU_ADDRSTRLEN]; vty_out(vty, "\tPeer: %s %s\n", peer->host, diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 0b3a203af..04a3c85f2 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -147,8 +147,10 @@ struct bgp_path_info_extra { * Set nexthop_orig.family to 0 if not valid. */ struct prefix nexthop_orig; - /* presence of FS pbr entry */ + /* presence of FS pbr firewall based entry */ struct list *bgp_fs_pbr; + /* presence of FS pbr iprule based entry */ + struct list *bgp_fs_iprule; }; struct bgp_path_info { @@ -270,6 +272,71 @@ struct bgp_static { struct prefix gatewayIp; }; +/* Aggreagete address: + * + * advertise-map Set condition to advertise attribute + * as-set Generate AS set path information + * attribute-map Set attributes of aggregate + * route-map Set parameters of aggregate + * summary-only Filter more specific routes from updates + * suppress-map Conditionally filter more specific routes from updates + * <cr> + */ +struct bgp_aggregate { + /* Summary-only flag. */ + uint8_t summary_only; + + /* AS set generation. */ + uint8_t as_set; + + /* Route-map for aggregated route. */ + struct route_map *map; + + /* Suppress-count. */ + unsigned long count; + + /* Count of routes of origin type incomplete under this aggregate. */ + unsigned long incomplete_origin_count; + + /* Count of routes of origin type egp under this aggregate. */ + unsigned long egp_origin_count; + + /* Hash containing the communities of all the + * routes under this aggregate. + */ + struct hash *community_hash; + + /* Hash containing the extended communities of all the + * routes under this aggregate. + */ + struct hash *ecommunity_hash; + + /* Hash containing the large communities of all the + * routes under this aggregate. + */ + struct hash *lcommunity_hash; + + /* Hash containing the AS-Path of all the + * routes under this aggregate. + */ + struct hash *aspath_hash; + + /* Aggregate route's community. */ + struct community *community; + + /* Aggregate route's extended community. */ + struct ecommunity *ecommunity; + + /* Aggregate route's large community. */ + struct lcommunity *lcommunity; + + /* Aggregate route's as-path. */ + struct aspath *aspath; + + /* SAFI configuration. */ + safi_t safi; +}; + #define BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen) \ ((nhlen) < IPV4_MAX_BYTELEN \ ? 0 \ @@ -277,7 +344,10 @@ struct bgp_static { #define BGP_ATTR_NEXTHOP_AFI_IP6(attr) \ (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) \ - && ((attr)->mp_nexthop_len == 16 || (attr)->mp_nexthop_len == 32)) + && ((attr)->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL \ + || (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL \ + || (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL \ + || (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)) #define BGP_PATH_COUNTABLE(BI) \ (!CHECK_FLAG((BI)->flags, BGP_PATH_HISTORY) \ && !CHECK_FLAG((BI)->flags, BGP_PATH_REMOVED)) @@ -355,6 +425,8 @@ extern void bgp_clear_route(struct peer *, afi_t, safi_t); extern void bgp_clear_route_all(struct peer *); extern void bgp_clear_adj_in(struct peer *, afi_t, safi_t); extern void bgp_clear_stale_route(struct peer *, afi_t, safi_t); +extern int bgp_outbound_policy_exists(struct peer *, struct bgp_filter *); +extern int bgp_inbound_policy_exists(struct peer *, struct bgp_filter *); extern struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p, diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index d7ee2aa19..17109281b 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -65,6 +65,10 @@ #include "bgpd/rfapi/bgp_rfapi_cfg.h" #endif +#ifndef VTYSH_EXTRACT_PL +#include "bgpd/bgp_routemap_clippy.c" +#endif + /* Memo of route-map commands. o Cisco route-map @@ -905,6 +909,53 @@ struct route_map_rule_cmd route_match_evpn_route_type_cmd = { "evpn route-type", route_match_evpn_route_type, route_match_evpn_route_type_compile, route_match_evpn_route_type_free}; +/* Route map commands for VRF route leak with source vrf matching */ +static route_map_result_t +route_match_vrl_source_vrf(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct bgp_path_info *path; + char *vrf_name; + + if (type == RMAP_BGP) { + vrf_name = rule; + path = (struct bgp_path_info *)object; + + if (strncmp(vrf_name, "n/a", VRF_NAMSIZ) == 0) + return RMAP_NOMATCH; + + if (path->extra == NULL) + return RMAP_NOMATCH; + + if (strncmp(vrf_name, vrf_id_to_name( + path->extra->bgp_orig->vrf_id), VRF_NAMSIZ) + == 0) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +static void *route_match_vrl_source_vrf_compile(const char *arg) +{ + uint8_t *vrf_name = NULL; + + vrf_name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); + + return vrf_name; +} + +/* Free route map's compiled `route-type' value. */ +static void route_match_vrl_source_vrf_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_vrl_source_vrf_cmd = { + "source-vrf", route_match_vrl_source_vrf, + route_match_vrl_source_vrf_compile, + route_match_vrl_source_vrf_free}; + /* `match local-preference LOCAL-PREF' */ /* Match function return 1 if match is success else return zero. */ @@ -3250,6 +3301,15 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, if (bgp->table_map[afi][safi].name && (strcmp(rmap_name, bgp->table_map[afi][safi].name) == 0)) { + + /* bgp->table_map[afi][safi].map is NULL. + * i.e Route map creation event. + * So update applied_counter. + * If it is not NULL, i.e It may be routemap updation or + * deletion. so no need to update the counter. + */ + if (!bgp->table_map[afi][safi].map) + route_map_counter_increment(map); bgp->table_map[afi][safi].map = map; if (BGP_DEBUG(zebra, ZEBRA)) @@ -3272,6 +3332,9 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, || (strcmp(rmap_name, bgp_static->rmap.name) != 0)) continue; + if (!bgp_static->rmap.map) + route_map_counter_increment(map); + bgp_static->rmap.map = map; if (route_update && !bgp_static->backdoor) { @@ -3303,6 +3366,9 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, || (strcmp(rmap_name, red->rmap.name) != 0)) continue; + if (!red->rmap.map) + route_map_counter_increment(map); + red->rmap.map = map; if (!route_update) @@ -3325,12 +3391,18 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, != 0) continue; + /* Make sure the route-map is populated here if not already done */ + bgp->adv_cmd_rmap[afi][safi].map = map; + if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug( "Processing route_map %s update on advertise type5 route command", rmap_name); - bgp_evpn_withdraw_type5_routes(bgp, afi, safi); - bgp_evpn_advertise_type5_routes(bgp, afi, safi); + + if (route_update) { + bgp_evpn_withdraw_type5_routes(bgp, afi, safi); + bgp_evpn_advertise_type5_routes(bgp, afi, safi); + } } } @@ -3517,6 +3589,29 @@ DEFUN (no_match_evpn_default_route, RMAP_EVENT_MATCH_DELETED); } +DEFPY(match_vrl_source_vrf, + match_vrl_source_vrf_cmd, + "match source-vrf NAME$vrf_name", + MATCH_STR + "source vrf\n" + "The VRF name\n") +{ + return bgp_route_match_add(vty, "source-vrf", vrf_name, + RMAP_EVENT_MATCH_ADDED); +} + +DEFPY(no_match_vrl_source_vrf, + no_match_vrl_source_vrf_cmd, + "no match source-vrf NAME$vrf_name", + NO_STR + MATCH_STR + "source vrf\n" + "The VRF name\n") +{ + return bgp_route_match_delete(vty, "source-vrf", vrf_name, + RMAP_EVENT_MATCH_DELETED); +} + DEFUN (match_peer, match_peer_cmd, "match peer <A.B.C.D|X:X::X:X|WORD>", @@ -4971,6 +5066,7 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_evpn_vni_cmd); route_map_install_match(&route_match_evpn_route_type_cmd); route_map_install_match(&route_match_evpn_default_route_cmd); + route_map_install_match(&route_match_vrl_source_vrf_cmd); route_map_install_set(&route_set_ip_nexthop_cmd); route_map_install_set(&route_set_local_pref_cmd); @@ -5009,6 +5105,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &no_match_evpn_route_type_cmd); install_element(RMAP_NODE, &match_evpn_default_route_cmd); install_element(RMAP_NODE, &no_match_evpn_default_route_cmd); + install_element(RMAP_NODE, &match_vrl_source_vrf_cmd); + install_element(RMAP_NODE, &no_match_vrl_source_vrf_cmd); install_element(RMAP_NODE, &match_aspath_cmd); install_element(RMAP_NODE, &no_match_aspath_cmd); diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index b614e87d2..a38d78916 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -1134,7 +1134,7 @@ DEFPY (no_rpki_cache, { struct cache *cache_p = find_cache(preference); - if (!cache) { + if (!cache_p) { vty_out(vty, "Could not find cache %ld\n", preference); return CMD_WARNING; } @@ -1190,9 +1190,23 @@ DEFUN (show_rpki_cache_server, struct cache *cache; for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { - vty_out(vty, "host: %s port: %s\n", - cache->tr_config.tcp_config->host, - cache->tr_config.tcp_config->port); + if (cache->type == TCP) { + vty_out(vty, "host: %s port: %s\n", + cache->tr_config.tcp_config->host, + cache->tr_config.tcp_config->port); + + } else if (cache->type == SSH) { + vty_out(vty, + "host: %s port: %d username: %s " + "server_hostkey_path: %s client_privkey_path: %s\n", + cache->tr_config.ssh_config->host, + cache->tr_config.ssh_config->port, + cache->tr_config.ssh_config->username, + cache->tr_config.ssh_config + ->server_hostkey_path, + cache->tr_config.ssh_config + ->client_privkey_path); + } } return CMD_SUCCESS; diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 2e2ad8831..b74dc33ea 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -1393,9 +1393,9 @@ static int updgrp_policy_update_walkcb(struct update_group *updgrp, void *arg) return UPDWALK_CONTINUE; } -static int update_group_walkcb(struct hash_backet *backet, void *arg) +static int update_group_walkcb(struct hash_bucket *bucket, void *arg) { - struct update_group *updgrp = backet->data; + struct update_group *updgrp = bucket->data; struct updwalk_context *wctx = arg; int ret = (*wctx->cb)(updgrp, wctx->context); return ret; diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index ca6bb5ab8..cbbf8b230 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -65,7 +65,7 @@ /******************** * PUBLIC FUNCTIONS ********************/ -struct bpacket *bpacket_alloc() +struct bpacket *bpacket_alloc(void) { struct bpacket *pkt; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index c6e48cc16..93d22087b 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -22,6 +22,7 @@ #include "command.h" #include "lib/json.h" +#include "lib/zclient.h" #include "prefix.h" #include "plist.h" #include "buffer.h" @@ -897,7 +898,7 @@ DEFUN_HIDDEN (no_bgp_local_mac, return CMD_WARNING; } - rv = bgp_evpn_local_macip_del(bgp, vni, &mac, &ip); + rv = bgp_evpn_local_macip_del(bgp, vni, &mac, &ip, ZEBRA_NEIGH_ACTIVE); if (rv < 0) { vty_out(vty, "Internal error\n"); return CMD_WARNING; @@ -1859,6 +1860,29 @@ DEFUN (no_bgp_always_compare_med, return CMD_SUCCESS; } + +DEFUN(bgp_ebgp_requires_policy, bgp_ebgp_requires_policy_cmd, + "bgp ebgp-requires-policy", + "BGP specific commands\n" + "Require in and out policy for eBGP peers (RFC8212)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_ENABLED; + return CMD_SUCCESS; +} + +DEFUN(no_bgp_ebgp_requires_policy, no_bgp_ebgp_requires_policy_cmd, + "no bgp ebgp-requires-policy", + NO_STR + "BGP specific commands\n" + "Require in and out policy for eBGP peers (RFC8212)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED; + return CMD_SUCCESS; +} + + /* "bgp deterministic-med" configuration. */ DEFUN (bgp_deterministic_med, bgp_deterministic_med_cmd, @@ -1944,7 +1968,7 @@ DEFUN (no_bgp_graceful_restart, DEFUN (bgp_graceful_restart_stalepath_time, bgp_graceful_restart_stalepath_time_cmd, - "bgp graceful-restart stalepath-time (1-3600)", + "bgp graceful-restart stalepath-time (1-4095)", "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the max time to hold onto restarting peer's stale paths\n" @@ -1961,7 +1985,7 @@ DEFUN (bgp_graceful_restart_stalepath_time, DEFUN (bgp_graceful_restart_restart_time, bgp_graceful_restart_restart_time_cmd, - "bgp graceful-restart restart-time (1-3600)", + "bgp graceful-restart restart-time (1-4095)", "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the time to wait to delete stale routes before a BGP open message is received\n" @@ -1978,7 +2002,7 @@ DEFUN (bgp_graceful_restart_restart_time, DEFUN (no_bgp_graceful_restart_stalepath_time, no_bgp_graceful_restart_stalepath_time_cmd, - "no bgp graceful-restart stalepath-time [(1-3600)]", + "no bgp graceful-restart stalepath-time [(1-4095)]", NO_STR "BGP specific commands\n" "Graceful restart capability parameters\n" @@ -1993,7 +2017,7 @@ DEFUN (no_bgp_graceful_restart_stalepath_time, DEFUN (no_bgp_graceful_restart_restart_time, no_bgp_graceful_restart_restart_time_cmd, - "no bgp graceful-restart restart-time [(1-3600)]", + "no bgp graceful-restart restart-time [(1-4095)]", NO_STR "BGP specific commands\n" "Graceful restart capability parameters\n" @@ -2846,13 +2870,11 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, switch (ret) { case BGP_ERR_PEER_GROUP_MEMBER: vty_out(vty, - "%% Peer-group AS %u. Cannot configure remote-as for member\n", - as); + "%% Peer-group member cannot override remote-as of peer-group\n"); return CMD_WARNING_CONFIG_FAILED; case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT: vty_out(vty, - "%% The AS# can not be changed from %u to %s, peer-group members must be all internal or all external\n", - as, as_str); + "%% Peer-group members must be all internal or all external\n"); return CMD_WARNING_CONFIG_FAILED; } return bgp_vty_return(vty, ret); @@ -2973,7 +2995,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, if (!CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE)) { SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE); SET_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE); - UNSET_FLAG(peer->flags_override, PEER_FLAG_CAPABILITY_ENHE); + SET_FLAG(peer->flags_override, PEER_FLAG_CAPABILITY_ENHE); } if (peer_group_name) { @@ -7141,7 +7163,7 @@ DEFUN_NOSH (address_family_vpnv6, vty->node = BGP_VPNV6_NODE; return CMD_SUCCESS; } -#endif +#endif /* KEEP_OLD_VPN_COMMANDS */ DEFUN_NOSH (address_family_evpn, address_family_evpn_cmd, @@ -7591,10 +7613,10 @@ DEFUN (show_bgp_mac_hash, return CMD_SUCCESS; } -static void show_tip_entry(struct hash_backet *backet, void *args) +static void show_tip_entry(struct hash_bucket *bucket, void *args) { struct vty *vty = (struct vty *)args; - struct tip_addr *tip = (struct tip_addr *)backet->data; + struct tip_addr *tip = (struct tip_addr *)bucket->data; vty_out(vty, "addr: %s, count: %d\n", inet_ntoa(tip->addr), tip->refcnt); @@ -7607,7 +7629,7 @@ static void bgp_show_martian_nexthops(struct vty *vty, struct bgp *bgp) vty_out(vty, "Tunnel-ip database:\n"); hash_iterate(bgp->tip_hash, - (void (*)(struct hash_backet *, void *))show_tip_entry, + (void (*)(struct hash_bucket *, void *))show_tip_entry, vty); } @@ -7762,7 +7784,7 @@ DEFUN (show_bgp_memory, if ((count = mtype_stats_alloc(MTYPE_HASH_BACKET))) vty_out(vty, "%ld hash buckets, using %s of memory\n", count, mtype_memstr(memstrbuf, sizeof(memstrbuf), - count * sizeof(struct hash_backet))); + count * sizeof(struct hash_bucket))); if ((count = mtype_stats_alloc(MTYPE_BGP_REGEXP))) vty_out(vty, "%ld compiled regexes, using %s of memory\n", count, mtype_memstr(memstrbuf, sizeof(memstrbuf), @@ -8830,6 +8852,20 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, json_addr, "routeMapForOutgoingAdvertisements", filter->map[RMAP_OUT].name); + /* ebgp-requires-policy (inbound) */ + if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED + && !bgp_inbound_policy_exists(p, filter)) + json_object_string_add( + json_addr, "inboundEbgpRequiresPolicy", + "Inbound updates discarded due to missing policy"); + + /* ebgp-requires-policy (outbound) */ + if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED + && (!bgp_outbound_policy_exists(p, filter))) + json_object_string_add( + json_addr, "outboundEbgpRequiresPolicy", + "Outbound updates discarded due to missing policy"); + /* unsuppress-map */ if (filter->usmap.name) json_object_string_add(json_addr, @@ -9106,6 +9142,18 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, filter->map[RMAP_OUT].map ? "*" : "", filter->map[RMAP_OUT].name); + /* ebgp-requires-policy (inbound) */ + if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED + && !bgp_inbound_policy_exists(p, filter)) + vty_out(vty, + " Inbound updates discarded due to missing policy\n"); + + /* ebgp-requires-policy (outbound) */ + if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED + && !bgp_outbound_policy_exists(p, filter)) + vty_out(vty, + " Outbound updates discarded due to missing policy\n"); + /* unsuppress-map */ if (filter->usmap.name) vty_out(vty, @@ -9212,8 +9260,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, ? " replace-as" : ""); } - /* peer type internal, external, confed-internal or confed-external */ - if (p->as == p->local_as) { + /* peer type internal or confed-internal */ + if ((p->as == p->local_as) || (p->as_type == AS_INTERNAL)) { if (use_json) { if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) json_object_boolean_true_add( @@ -9227,7 +9275,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, else vty_out(vty, "internal link\n"); } - } else { + /* peer type external or confed-external */ + } else if (p->as || (p->as_type == AS_EXTERNAL)) { if (use_json) { if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) json_object_boolean_true_add( @@ -9241,6 +9290,12 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, else vty_out(vty, "external link\n"); } + } else { + if (use_json) + json_object_boolean_true_add(json_neigh, + "nbrUnspecifiedLink"); + else + vty_out(vty, "unspecified link\n"); } /* Description. */ @@ -11006,6 +11061,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty, bgp_show_neighbor(vty, bgp, show_all, NULL, NULL, use_json, json); } + json_object_free(json); } if (use_json) { @@ -11140,12 +11196,12 @@ DEFUN (show_ip_bgp_paths, #include "hash.h" -static void community_show_all_iterator(struct hash_backet *backet, +static void community_show_all_iterator(struct hash_bucket *bucket, struct vty *vty) { struct community *com; - com = (struct community *)backet->data; + com = (struct community *)bucket->data; vty_out(vty, "[%p] (%ld) %s\n", (void *)com, com->refcnt, community_str(com, false)); } @@ -11162,19 +11218,19 @@ DEFUN (show_ip_bgp_community_info, vty_out(vty, "Address Refcnt Community\n"); hash_iterate(community_hash(), - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))community_show_all_iterator, vty); return CMD_SUCCESS; } -static void lcommunity_show_all_iterator(struct hash_backet *backet, +static void lcommunity_show_all_iterator(struct hash_bucket *bucket, struct vty *vty) { struct lcommunity *lcom; - lcom = (struct lcommunity *)backet->data; + lcom = (struct lcommunity *)bucket->data; vty_out(vty, "[%p] (%ld) %s\n", (void *)lcom, lcom->refcnt, lcommunity_str(lcom, false)); } @@ -11191,7 +11247,7 @@ DEFUN (show_ip_bgp_lcommunity_info, vty_out(vty, "Address Refcnt Large-community\n"); hash_iterate(lcommunity_hash(), - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))lcommunity_show_all_iterator, vty); @@ -11643,11 +11699,11 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group) conf = group->conf; if (conf->as_type == AS_SPECIFIED || conf->as_type == AS_EXTERNAL) { - vty_out(vty, "\nBGP peer-group %s, remote AS %d\n", group->name, - conf->as); + vty_out(vty, "\nBGP peer-group %s, remote AS %" PRIu32 "\n", + group->name, conf->as); } else if (conf->as_type == AS_INTERNAL) { - vty_out(vty, "\nBGP peer-group %s, remote AS %d\n", group->name, - group->bgp->as); + vty_out(vty, "\nBGP peer-group %s, remote AS %" PRIu32 "\n", + group->name, group->bgp->as); } else { vty_out(vty, "\nBGP peer-group %s\n", group->name); } @@ -12816,6 +12872,10 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_always_compare_med_cmd); install_element(BGP_NODE, &no_bgp_always_compare_med_cmd); + /* bgp ebgp-requires-policy */ + install_element(BGP_NODE, &bgp_ebgp_requires_policy_cmd); + install_element(BGP_NODE, &no_bgp_ebgp_requires_policy_cmd); + /* "bgp deterministic-med" commands */ install_element(BGP_NODE, &bgp_deterministic_med_cmd); install_element(BGP_NODE, &no_bgp_deterministic_med_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 3c4b21946..f833ab89d 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -36,6 +36,7 @@ #include "filter.h" #include "mpls.h" #include "vxlan.h" +#include "pbr.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" @@ -944,14 +945,17 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex) struct in6_addr *nexthop = NULL; /* Only global address nexthop exists. */ - if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) { + if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL + || path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL) { nexthop = &path->attr->mp_nexthop_global; if (IN6_IS_ADDR_LINKLOCAL(nexthop)) *ifindex = path->attr->nh_ifindex; } /* If both global and link-local address present. */ - if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL + || path->attr->mp_nexthop_len + == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { /* Check if route-map is set to prefer global over link-local */ if (path->attr->mp_nexthop_prefer_global) { nexthop = &path->attr->mp_nexthop_global; @@ -1110,20 +1114,24 @@ int bgp_zebra_get_table_range(uint32_t chunk_size, } static int update_ipv4nh_for_route_install(int nh_othervrf, + struct bgp *nh_bgp, struct in_addr *nexthop, struct attr *attr, bool is_evpn, struct zapi_nexthop *api_nh) { api_nh->gate.ipv4 = *nexthop; + api_nh->vrf_id = nh_bgp->vrf_id; /* Need to set fields appropriately for EVPN routes imported into * a VRF (which are programmed as onlink on l3-vni SVI) as well as * connected routes leaked into a VRF. */ - if (is_evpn) + if (is_evpn) { api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; - else if (nh_othervrf && + api_nh->onlink = true; + api_nh->ifindex = nh_bgp->l3vni_svi_ifindex; + } else if (nh_othervrf && api_nh->gate.ipv4.s_addr == INADDR_ANY) { api_nh->type = NEXTHOP_TYPE_IFINDEX; api_nh->ifindex = attr->nh_ifindex; @@ -1134,7 +1142,8 @@ static int update_ipv4nh_for_route_install(int nh_othervrf, } static int -update_ipv6nh_for_route_install(int nh_othervrf, struct in6_addr *nexthop, +update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, + struct in6_addr *nexthop, ifindex_t ifindex, struct bgp_path_info *pi, struct bgp_path_info *best_pi, bool is_evpn, struct zapi_nexthop *api_nh) @@ -1142,10 +1151,13 @@ update_ipv6nh_for_route_install(int nh_othervrf, struct in6_addr *nexthop, struct attr *attr; attr = pi->attr; + api_nh->vrf_id = nh_bgp->vrf_id; - if (is_evpn) + if (is_evpn) { api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; - else if (nh_othervrf) { + api_nh->onlink = true; + api_nh->ifindex = nh_bgp->l3vni_svi_ifindex; + } else if (nh_othervrf) { if (IN6_IS_ADDR_UNSPECIFIED(nexthop)) { api_nh->type = NEXTHOP_TYPE_IFINDEX; api_nh->ifindex = attr->nh_ifindex; @@ -1296,8 +1308,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, continue; api_nh = &api.nexthops[valid_nh_count]; - api_nh->vrf_id = nh_othervrf ? info->extra->bgp_orig->vrf_id - : bgp->vrf_id; if (nh_family == AF_INET) { if (bgp_debug_zebra(&api.prefix)) { if (mpinfo->extra) { @@ -1337,6 +1347,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, nh_updated = update_ipv4nh_for_route_install( nh_othervrf, + nh_othervrf ? + info->extra->bgp_orig : bgp, &mpinfo_cp->attr->nexthop, mpinfo_cp->attr, is_evpn, api_nh); } else { @@ -1371,7 +1383,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, nexthop = bgp_path_info_to_ipv6_nexthop(mpinfo_cp, &ifindex); nh_updated = update_ipv6nh_for_route_install( - nh_othervrf, nexthop, ifindex, + nh_othervrf, nh_othervrf ? + info->extra->bgp_orig : bgp, + nexthop, ifindex, mpinfo, info, is_evpn, api_nh); } @@ -1682,8 +1696,13 @@ int bgp_redistribute_rmap_set(struct bgp_redist *red, const char *name, if (red->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name); + /* Decrement the count for existing routemap and + * increment the count for new route map. + */ + route_map_counter_decrement(red->rmap.map); red->rmap.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name); red->rmap.map = route_map; + route_map_counter_increment(red->rmap.map); return 1; } @@ -1791,6 +1810,7 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, /* Unset route-map. */ if (red->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name); + route_map_counter_decrement(red->rmap.map); red->rmap.name = NULL; red->rmap.map = NULL; @@ -1929,6 +1949,29 @@ int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, vni_t vni) return zclient_send_message(zclient); } +int bgp_zebra_advertise_svi_macip(struct bgp *bgp, int advertise, vni_t vni) +{ + struct stream *s = NULL; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return 0; + + /* Don't try to register if Zebra doesn't know of this instance. */ + if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) + return 0; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_ADVERTISE_SVI_MACIP, bgp->vrf_id); + stream_putc(s, advertise); + stream_putl(s, vni); + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni) { struct stream *s = NULL; @@ -2051,6 +2094,7 @@ static int rule_notify_owner(int command, struct zclient *zclient, uint32_t seqno, priority, unique; enum zapi_rule_notify_owner note; struct bgp_pbr_action *bgp_pbra; + struct bgp_pbr_rule *bgp_pbr = NULL; ifindex_t ifi; if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique, @@ -2059,10 +2103,14 @@ static int rule_notify_owner(int command, struct zclient *zclient, bgp_pbra = bgp_pbr_action_rule_lookup(vrf_id, unique); if (!bgp_pbra) { - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: Fail to look BGP rule (%u)", - __PRETTY_FUNCTION__, unique); - return 0; + /* look in bgp pbr rule */ + bgp_pbr = bgp_pbr_rule_lookup(vrf_id, unique); + if (!bgp_pbr && note != ZAPI_RULE_REMOVED) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: Fail to look BGP rule (%u)", + __PRETTY_FUNCTION__, unique); + return 0; + } } switch (note) { @@ -2070,12 +2118,30 @@ static int rule_notify_owner(int command, struct zclient *zclient, if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("%s: Received RULE_FAIL_INSTALL", __PRETTY_FUNCTION__); - bgp_pbra->installed = false; - bgp_pbra->install_in_progress = false; + if (bgp_pbra) { + bgp_pbra->installed = false; + bgp_pbra->install_in_progress = false; + } else { + bgp_pbr->installed = false; + bgp_pbr->install_in_progress = false; + } break; case ZAPI_RULE_INSTALLED: - bgp_pbra->installed = true; - bgp_pbra->install_in_progress = false; + if (bgp_pbra) { + bgp_pbra->installed = true; + bgp_pbra->install_in_progress = false; + } else { + struct bgp_path_info *path; + struct bgp_path_info_extra *extra; + + bgp_pbr->installed = true; + bgp_pbr->install_in_progress = false; + bgp_pbr->action->refcnt++; + /* link bgp_info to bgp_pbr */ + path = (struct bgp_path_info *)bgp_pbr->path; + extra = bgp_path_info_extra_get(path); + listnode_add(extra->bgp_fs_iprule, bgp_pbr); + } if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("%s: Received RULE_INSTALLED", __PRETTY_FUNCTION__); @@ -2182,8 +2248,6 @@ static int ipset_entry_notify_owner(int command, struct zclient *zclient, /* link bgp_path_info to bpme */ path = (struct bgp_path_info *)bgp_pbime->path; extra = bgp_path_info_extra_get(path); - if (extra->bgp_fs_pbr == NULL) - extra->bgp_fs_pbr = list_new(); listnode_add(extra->bgp_fs_pbr, bgp_pbime); } break; @@ -2242,31 +2306,60 @@ static int iptable_notify_owner(int command, struct zclient *zclient, return 0; } +/* this function is used to forge ip rule, + * - either for iptable/ipset using fwmark id + * - or for sample ip rule command + */ static void bgp_encode_pbr_rule_action(struct stream *s, - struct bgp_pbr_action *pbra) + struct bgp_pbr_action *pbra, + struct bgp_pbr_rule *pbr) { - struct prefix any; + struct prefix pfx; stream_putl(s, 0); /* seqno unused */ - stream_putl(s, 0); /* ruleno unused */ - - stream_putl(s, pbra->unique); - - memset(&any, 0, sizeof(any)); - any.family = AF_INET; - stream_putc(s, any.family); - stream_putc(s, any.prefixlen); - stream_put(s, &any.u.prefix, prefix_blen(&any)); + if (pbr) + stream_putl(s, pbr->priority); + else + stream_putl(s, 0); + /* ruleno unused - priority change + * ruleno permits distinguishing various FS PBR entries + * - FS PBR entries based on ipset/iptables + * - FS PBR entries based on iprule + * the latter may contain default routing information injected by FS + */ + if (pbr) + stream_putl(s, pbr->unique); + else + stream_putl(s, pbra->unique); + if (pbr && pbr->flags & MATCH_IP_SRC_SET) + memcpy(&pfx, &(pbr->src), sizeof(struct prefix)); + else { + memset(&pfx, 0, sizeof(pfx)); + pfx.family = AF_INET; + } + stream_putc(s, pfx.family); + stream_putc(s, pfx.prefixlen); + stream_put(s, &pfx.u.prefix, prefix_blen(&pfx)); stream_putw(s, 0); /* src port */ - stream_putc(s, any.family); - stream_putc(s, any.prefixlen); - stream_put(s, &any.u.prefix, prefix_blen(&any)); + if (pbr && pbr->flags & MATCH_IP_DST_SET) + memcpy(&pfx, &(pbr->dst), sizeof(struct prefix)); + else { + memset(&pfx, 0, sizeof(pfx)); + pfx.family = AF_INET; + } + stream_putc(s, pfx.family); + stream_putc(s, pfx.prefixlen); + stream_put(s, &pfx.u.prefix, prefix_blen(&pfx)); stream_putw(s, 0); /* dst port */ - stream_putl(s, pbra->fwmark); /* fwmark */ + /* if pbr present, fwmark is not used */ + if (pbr) + stream_putl(s, 0); + else + stream_putl(s, pbra->fwmark); /* fwmark */ stream_putl(s, pbra->table_id); @@ -2406,6 +2499,7 @@ static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient, struct ethaddr rmac; struct in_addr originator_ip; struct stream *s; + ifindex_t svi_ifindex; memset(&rmac, 0, sizeof(struct ethaddr)); memset(&originator_ip, 0, sizeof(struct in_addr)); @@ -2415,20 +2509,24 @@ static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient, stream_get(&rmac, s, sizeof(struct ethaddr)); originator_ip.s_addr = stream_get_ipv4(s); stream_get(&filter, s, sizeof(int)); - } + svi_ifindex = stream_getl(s); - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx L3-VNI %s VRF %s VNI %u RMAC %s filter %s", - (cmd == ZEBRA_L3VNI_ADD) ? "add" : "del", - vrf_id_to_name(vrf_id), l3vni, - prefix_mac2str(&rmac, buf, sizeof(buf)), - filter ? "prefix-routes-only" : "none"); + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Rx L3-VNI ADD VRF %s VNI %u RMAC %s filter %s svi-if %u", + vrf_id_to_name(vrf_id), l3vni, + prefix_mac2str(&rmac, buf, sizeof(buf)), + filter ? "prefix-routes-only" : "none", + svi_ifindex); - if (cmd == ZEBRA_L3VNI_ADD) bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip, - filter); - else + filter, svi_ifindex); + } else { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Rx L3-VNI DEL VRF %s VNI %u", + vrf_id_to_name(vrf_id), l3vni); + bgp_evpn_local_l3vni_del(l3vni, vrf_id); + } return 0; } @@ -2480,6 +2578,7 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient, char buf1[INET6_ADDRSTRLEN]; uint8_t flags = 0; uint32_t seqnum = 0; + int state = 0; memset(&ip, 0, sizeof(ip)); s = zclient->ibuf; @@ -2503,6 +2602,8 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient, if (command == ZEBRA_MACIP_ADD) { flags = stream_getc(s); seqnum = stream_getl(s); + } else { + state = stream_getl(s); } bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -2510,16 +2611,17 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient, return 0; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%u:Recv MACIP %s flags 0x%x MAC %s IP %s VNI %u seq %u", + zlog_debug("%u:Recv MACIP %s flags 0x%x MAC %s IP %s VNI %u seq %u state %d", vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del", flags, prefix_mac2str(&mac, buf, sizeof(buf)), - ipaddr2str(&ip, buf1, sizeof(buf1)), vni, seqnum); + ipaddr2str(&ip, buf1, sizeof(buf1)), vni, seqnum, + state); if (command == ZEBRA_MACIP_ADD) return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, flags, seqnum); else - return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip); + return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip, state); } static void bgp_zebra_process_local_ip_prefix(int cmd, struct zclient *zclient, @@ -2672,16 +2774,26 @@ int bgp_zebra_num_connects(void) return zclient_num_connects; } -void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra, bool install) +void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra, + struct bgp_pbr_rule *pbr, + bool install) { struct stream *s; - if (pbra->install_in_progress) + if (pbra->install_in_progress && !pbr) return; - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: table %d fwmark %d %d", - __PRETTY_FUNCTION__, - pbra->table_id, pbra->fwmark, install); + if (pbr && pbr->install_in_progress) + return; + if (BGP_DEBUG(zebra, ZEBRA)) { + if (pbr) + zlog_debug("%s: table %d (ip rule) %d", + __PRETTY_FUNCTION__, + pbra->table_id, install); + else + zlog_debug("%s: table %d fwmark %d %d", + __PRETTY_FUNCTION__, + pbra->table_id, pbra->fwmark, install); + } s = zclient->obuf; stream_reset(s); @@ -2690,11 +2802,15 @@ void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra, bool install) VRF_DEFAULT); stream_putl(s, 1); /* send one pbr action */ - bgp_encode_pbr_rule_action(s, pbra); + bgp_encode_pbr_rule_action(s, pbra, pbr); stream_putw_at(s, 0, stream_get_endp(s)); - if (!zclient_send_message(zclient) && install) - pbra->install_in_progress = true; + if (!zclient_send_message(zclient) && install) { + if (!pbr) + pbra->install_in_progress = true; + else + pbr->install_in_progress = true; + } } void bgp_send_pbr_ipset_match(struct bgp_pbr_match *pbrim, bool install) diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index e7b7d683a..fc19c5e17 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -72,6 +72,8 @@ extern struct interface *if_lookup_by_ipv6_exact(struct in6_addr *, ifindex_t, extern int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, vni_t vni); extern int bgp_zebra_advertise_gw_macip(struct bgp *, int, vni_t); +extern int bgp_zebra_advertise_svi_macip(struct bgp *bgp, int advertise, + vni_t vni); extern int bgp_zebra_advertise_all_vni(struct bgp *, int); extern int bgp_zebra_dup_addr_detection(struct bgp *bgp); extern int bgp_zebra_vxlan_flood_control(struct bgp *bgp, @@ -84,9 +86,11 @@ extern bool bgp_zebra_nexthop_set(union sockunion *, union sockunion *, struct bgp_pbr_action; struct bgp_pbr_match; +struct bgp_pbr_rule; struct bgp_pbr_match_entry; extern void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra, - bool install); + struct bgp_pbr_rule *pbr, + bool install); extern void bgp_send_pbr_ipset_match(struct bgp_pbr_match *pbrim, bool install); extern void bgp_send_pbr_ipset_entry_match(struct bgp_pbr_match_entry *pbrime, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 5b8ceb054..a920cfeee 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1001,7 +1001,26 @@ static inline bgp_peer_sort_t peer_calc_sort(struct peer *peer) return BGP_PEER_EBGP; } else { - if (peer->as_type != AS_SPECIFIED) + if (peer->as_type == AS_UNSPECIFIED) { + /* check if in peer-group with AS information */ + if (peer->group + && (peer->group->conf->as_type != AS_UNSPECIFIED)) { + if (peer->group->conf->as_type + == AS_SPECIFIED) { + if (peer->local_as + == peer->group->conf->as) + return BGP_PEER_IBGP; + else + return BGP_PEER_EBGP; + } else if (peer->group->conf->as_type + == AS_INTERNAL) + return BGP_PEER_IBGP; + else + return BGP_PEER_EBGP; + } + /* no AS information anywhere, let caller know */ + return BGP_PEER_UNSPECIFIED; + } else if (peer->as_type != AS_SPECIFIED) return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP : BGP_PEER_EBGP); @@ -1711,20 +1730,32 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, /* When this peer is a member of peer-group. */ if (peer->group) { - if (peer->group->conf->as) { + /* peer-group already has AS number/internal/external */ + if (peer->group->conf->as + || peer->group->conf->as_type) { /* Return peer group's AS number. */ *as = peer->group->conf->as; return BGP_ERR_PEER_GROUP_MEMBER; } - if (peer_sort(peer->group->conf) == BGP_PEER_IBGP) { - if ((as_type != AS_INTERNAL) - && (bgp->as != *as)) { + + bgp_peer_sort_t peer_sort_type = + peer_sort(peer->group->conf); + + /* Explicit AS numbers used, compare AS numbers */ + if (as_type == AS_SPECIFIED) { + if (((peer_sort_type == BGP_PEER_IBGP) + && (bgp->as != *as)) + || ((peer_sort_type == BGP_PEER_EBGP) + && (bgp->as == *as))) { *as = peer->as; return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; } } else { - if ((as_type != AS_EXTERNAL) - && (bgp->as == *as)) { + /* internal/external used, compare as-types */ + if (((peer_sort_type == BGP_PEER_IBGP) + && (as_type != AS_INTERNAL)) + || ((peer_sort_type == BGP_PEER_EBGP) + && (as_type != AS_EXTERNAL))) { *as = peer->as; return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; } @@ -2688,6 +2719,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, if (peer->as_type == AS_UNSPECIFIED) { peer->as_type = group->conf->as_type; peer->as = group->conf->as; + peer->sort = group->conf->sort; } if (!group->conf->as) { @@ -2904,6 +2936,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT; bgp->dynamic_neighbors_count = 0; + bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED; #if DFLT_BGP_IMPORT_CHECK bgp_flag_set(bgp, BGP_FLAG_IMPORT_CHECK); #endif @@ -3252,6 +3285,10 @@ int bgp_delete(struct bgp *bgp) /* unmap from RT list */ bgp_evpn_vrf_delete(bgp); + /* unmap bgp vrf label */ + vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6); + /* Stop timers. */ if (bgp->t_rmap_def_originate_eval) { BGP_TIMER_OFF(bgp->t_rmap_def_originate_eval); @@ -3774,6 +3811,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset}, {PEER_FLAG_CAPABILITY_ENHE, 0, peer_change_reset}, {PEER_FLAG_ENFORCE_FIRST_AS, 0, peer_change_reset_in}, + {PEER_FLAG_IFPEER_V6ONLY, 0, peer_change_reset}, {PEER_FLAG_ROUTEADV, 0, peer_change_none}, {PEER_FLAG_TIMER, 0, peer_change_none}, {PEER_FLAG_TIMER_CONNECT, 0, peer_change_none}, @@ -4558,15 +4596,18 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name); + route_map_counter_decrement(peer->default_rmap[afi][safi].map); peer->default_rmap[afi][safi].name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); peer->default_rmap[afi][safi].map = route_map; + route_map_counter_increment(route_map); } } else if (!rmap) { if (peer->default_rmap[afi][safi].name) XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name); + route_map_counter_decrement(peer->default_rmap[afi][safi].map); peer->default_rmap[afi][safi].name = NULL; peer->default_rmap[afi][safi].map = NULL; } @@ -4601,10 +4642,12 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, if (member->default_rmap[afi][safi].name) XFREE(MTYPE_ROUTE_MAP_NAME, member->default_rmap[afi][safi].name); - + route_map_counter_decrement( + member->default_rmap[afi][safi].map); member->default_rmap[afi][safi].name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); member->default_rmap[afi][safi].map = route_map; + route_map_counter_increment(route_map); } /* Update peer route announcements. */ @@ -4641,6 +4684,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi) if (peer->default_rmap[afi][safi].name) XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name); + route_map_counter_decrement(peer->default_rmap[afi][safi].map); peer->default_rmap[afi][safi].name = NULL; peer->default_rmap[afi][safi].map = NULL; } @@ -4674,6 +4718,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi) if (peer->default_rmap[afi][safi].name) XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name); + route_map_counter_decrement(peer->default_rmap[afi][safi].map); peer->default_rmap[afi][safi].name = NULL; peer->default_rmap[afi][safi].map = NULL; @@ -6082,8 +6127,10 @@ int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct, filter = &peer->filter[afi][safi]; if (filter->map[direct].name) XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name); + route_map_counter_decrement(filter->map[direct].map); filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name); filter->map[direct].map = route_map; + route_map_counter_increment(route_map); /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { @@ -6111,8 +6158,10 @@ int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct, filter = &member->filter[afi][safi]; if (filter->map[direct].name) XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name); + route_map_counter_decrement(filter->map[direct].map); filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name); filter->map[direct].map = route_map; + route_map_counter_increment(route_map); /* Process peer route updates. */ peer_on_policy_change(member, afi, safi, @@ -6146,6 +6195,7 @@ int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct) filter = &peer->filter[afi][safi]; if (filter->map[direct].name) XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name); + route_map_counter_decrement(filter->map[direct].map); filter->map[direct].name = NULL; filter->map[direct].map = NULL; } @@ -6174,6 +6224,7 @@ int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct) filter = &member->filter[afi][safi]; if (filter->map[direct].name) XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name); + route_map_counter_decrement(filter->map[direct].map); filter->map[direct].name = NULL; filter->map[direct].map = NULL; @@ -6197,8 +6248,10 @@ int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi, filter = &peer->filter[afi][safi]; if (filter->usmap.name) XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name); + route_map_counter_decrement(filter->usmap.map); filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name); filter->usmap.map = route_map; + route_map_counter_increment(route_map); /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { @@ -6225,8 +6278,10 @@ int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi, filter = &member->filter[afi][safi]; if (filter->usmap.name) XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name); + route_map_counter_decrement(filter->usmap.map); filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name); filter->usmap.map = route_map; + route_map_counter_increment(route_map); /* Process peer route updates. */ peer_on_policy_change(member, afi, safi, 1); @@ -6257,6 +6312,7 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi) filter = &peer->filter[afi][safi]; if (filter->usmap.name) XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name); + route_map_counter_decrement(filter->usmap.map); filter->usmap.name = NULL; filter->usmap.map = NULL; } @@ -6284,6 +6340,7 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi) filter = &member->filter[afi][safi]; if (filter->usmap.name) XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name); + route_map_counter_decrement(filter->usmap.map); filter->usmap.name = NULL; filter->usmap.map = NULL; @@ -7020,14 +7077,17 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, /* capability extended-nexthop */ if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_ENHE)) { - if (CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE)) - vty_out(vty, - " no neighbor %s capability extended-nexthop\n", - addr); - else - vty_out(vty, - " neighbor %s capability extended-nexthop\n", - addr); + if (!peer->conf_if) { + if (CHECK_FLAG(peer->flags_invert, + PEER_FLAG_CAPABILITY_ENHE)) + vty_out(vty, + " no neighbor %s capability extended-nexthop\n", + addr); + else + vty_out(vty, + " neighbor %s capability extended-nexthop\n", + addr); + } } /* dont-capability-negotiation */ @@ -7519,6 +7579,11 @@ int bgp_config_write(struct vty *vty) if (bgp_flag_check(bgp, BGP_FLAG_ALWAYS_COMPARE_MED)) vty_out(vty, " bgp always-compare-med\n"); + /* RFC8212 default eBGP policy. */ + if (bgp->ebgp_requires_policy + == DEFAULT_EBGP_POLICY_ENABLED) + vty_out(vty, " bgp ebgp-requires-policy\n"); + /* BGP default ipv4-unicast. */ if (bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4)) vty_out(vty, " no bgp default ipv4-unicast\n"); @@ -7799,9 +7864,11 @@ void bgp_master_init(struct thread_master *master) */ static void bgp_if_finish(struct bgp *bgp) { - struct vrf *vrf = vrf_lookup_by_id(bgp->vrf_id); + struct vrf *vrf; struct interface *ifp; + vrf = bgp_vrf_lookup_by_instance_type(bgp); + if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW || !vrf) return; @@ -7839,7 +7906,7 @@ static const struct cmd_variable_handler bgp_viewvrf_var_handlers[] = { struct frr_pthread *bgp_pth_io; struct frr_pthread *bgp_pth_ka; -static void bgp_pthreads_init() +static void bgp_pthreads_init(void) { assert(!bgp_pth_io); assert(!bgp_pth_ka); @@ -7858,7 +7925,7 @@ static void bgp_pthreads_init() bgp_pth_ka = frr_pthread_new(&ka, "BGP Keepalives thread", "bgpd_ka"); } -void bgp_pthreads_run() +void bgp_pthreads_run(void) { frr_pthread_run(bgp_pth_io, NULL); frr_pthread_run(bgp_pth_ka, NULL); @@ -7868,7 +7935,7 @@ void bgp_pthreads_run() frr_pthread_wait_running(bgp_pth_ka); } -void bgp_pthreads_finish() +void bgp_pthreads_finish(void) { frr_pthread_stop_all(); frr_pthread_finish(); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 484fc105e..c7d137c76 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -414,6 +414,7 @@ struct bgp { * * pbr_action a <----- pbr_match i <--- pbr_match_entry 1..n * <----- pbr_match j <--- pbr_match_entry 1..m + * <----- pbr_rule k * * - here in BGP structure, the list of match and actions will * stand for the list of ipset sets, and table_ids in the kernel @@ -423,6 +424,7 @@ struct bgp { * contained in match, that lists the whole set of entries */ struct hash *pbr_match_hash; + struct hash *pbr_rule_hash; struct hash *pbr_action_hash; /* timer to re-evaluate neighbor default-originate route-maps */ @@ -485,6 +487,11 @@ struct bgp { /* EVPN enable - advertise local VNIs and their MACs etc. */ int advertise_all_vni; + /* RFC 8212 - prevent route leaks. */ + int ebgp_requires_policy; +#define DEFAULT_EBGP_POLICY_DISABLED 0 +#define DEFAULT_EBGP_POLICY_ENABLED 1 + struct bgp_evpn_info *evpn_info; /* EVPN - use RFC 8365 to auto-derive RT */ @@ -510,6 +517,9 @@ struct bgp { /* originator ip - to be used as NH for type-5 routes */ struct in_addr originator_ip; + /* SVI associated with the L3-VNI corresponding to this vrf */ + ifindex_t l3vni_svi_ifindex; + /* vrf flags */ uint32_t vrf_flags; #define BGP_VRF_AUTO (1 << 0) @@ -646,7 +656,8 @@ struct bgp_filter { /* IBGP/EBGP identifier. We also have a CONFED peer, which is to say, a peer who's AS is part of our Confederation. */ typedef enum { - BGP_PEER_IBGP = 1, + BGP_PEER_UNSPECIFIED, + BGP_PEER_IBGP, BGP_PEER_EBGP, BGP_PEER_INTERNAL, BGP_PEER_CONFED, diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index e4e676061..d621d58e4 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -575,7 +575,7 @@ static struct rfapi_l2_group_cfg *rfapi_l2_group_lookup_byname(struct bgp *bgp, return NULL; } -static struct rfapi_l2_group_cfg *rfapi_l2_group_new() +static struct rfapi_l2_group_cfg *rfapi_l2_group_new(void) { struct rfapi_l2_group_cfg *rfg; @@ -1164,9 +1164,16 @@ DEFUN (vnc_redist_bgpdirect_routemap, if (hc->routemap_redist_name[route_type]) free(hc->routemap_redist_name[route_type]); + + /* If the old route map config overwrite with new + * route map config , old routemap counter have to be + * reduced. + */ + route_map_counter_decrement(hc->routemap_redist[route_type]); hc->routemap_redist_name[route_type] = strdup(argv[4]->arg); hc->routemap_redist[route_type] = route_map_lookup_by_name(argv[4]->arg); + route_map_counter_increment(hc->routemap_redist[route_type]); vnc_redistribute_postchange(bgp); @@ -1285,6 +1292,8 @@ DEFUN (vnc_nve_group_redist_bgpdirect_no_routemap, if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) free(rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); + route_map_counter_decrement( + rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT] = NULL; rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT] = NULL; @@ -1316,10 +1325,14 @@ DEFUN (vnc_nve_group_redist_bgpdirect_routemap, if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) free(rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); + route_map_counter_decrement( + rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT] = strdup(argv[3]->arg); rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT] = route_map_lookup_by_name(argv[3]->arg); + route_map_counter_increment( + rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); vnc_redistribute_postchange(bgp); @@ -1396,7 +1409,7 @@ DEFUN (vnc_export_mode, return CMD_SUCCESS; } -static struct rfapi_rfg_name *rfgn_new() +static struct rfapi_rfg_name *rfgn_new(void) { return XCALLOC(MTYPE_RFAPI_RFG_NAME, sizeof(struct rfapi_rfg_name)); } @@ -1741,6 +1754,7 @@ DEFUN (vnc_nve_group_export_no_routemap, rfg->routemap_export_bgp_name))) { if (rfg->routemap_export_bgp_name) free(rfg->routemap_export_bgp_name); + route_map_counter_decrement(rfg->routemap_export_bgp); rfg->routemap_export_bgp_name = NULL; rfg->routemap_export_bgp = NULL; @@ -1754,6 +1768,7 @@ DEFUN (vnc_nve_group_export_no_routemap, rfg->routemap_export_zebra_name))) { if (rfg->routemap_export_zebra_name) free(rfg->routemap_export_zebra_name); + route_map_counter_decrement(rfg->routemap_export_zebra); rfg->routemap_export_zebra_name = NULL; rfg->routemap_export_zebra = NULL; @@ -1800,17 +1815,21 @@ DEFUN (vnc_nve_group_export_routemap, if (is_bgp) { if (rfg->routemap_export_bgp_name) free(rfg->routemap_export_bgp_name); + route_map_counter_decrement(rfg->routemap_export_bgp); rfg->routemap_export_bgp_name = strdup(argv[idx]->arg); rfg->routemap_export_bgp = route_map_lookup_by_name(argv[idx]->arg); + route_map_counter_increment(rfg->routemap_export_bgp); vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP); vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP6); } else { if (rfg->routemap_export_zebra_name) free(rfg->routemap_export_zebra_name); + route_map_counter_decrement(rfg->routemap_export_zebra); rfg->routemap_export_zebra_name = strdup(argv[idx]->arg); rfg->routemap_export_zebra = route_map_lookup_by_name(argv[idx]->arg); + route_map_counter_increment(rfg->routemap_export_zebra); vnc_zebra_reexport_group_afi(bgp, rfg, AFI_IP); vnc_zebra_reexport_group_afi(bgp, rfg, AFI_IP6); } @@ -1937,6 +1956,7 @@ DEFUN (vnc_nve_export_no_routemap, || (argc <= 5)) { free(hc->routemap_export_bgp_name); + route_map_counter_decrement(hc->routemap_export_bgp); hc->routemap_export_bgp_name = NULL; hc->routemap_export_bgp = NULL; vnc_direct_bgp_reexport(bgp, AFI_IP); @@ -1948,6 +1968,7 @@ DEFUN (vnc_nve_export_no_routemap, || (argc <= 5)) { free(hc->routemap_export_zebra_name); + route_map_counter_decrement(hc->routemap_export_zebra); hc->routemap_export_zebra_name = NULL; hc->routemap_export_zebra = NULL; /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP); */ @@ -1975,17 +1996,21 @@ DEFUN (vnc_nve_export_routemap, if (argv[2]->arg[0] == 'b') { if (hc->routemap_export_bgp_name) free(hc->routemap_export_bgp_name); + route_map_counter_decrement(hc->routemap_export_bgp); hc->routemap_export_bgp_name = strdup(argv[4]->arg); hc->routemap_export_bgp = route_map_lookup_by_name(argv[4]->arg); + route_map_counter_increment(hc->routemap_export_bgp); vnc_direct_bgp_reexport(bgp, AFI_IP); vnc_direct_bgp_reexport(bgp, AFI_IP6); } else { if (hc->routemap_export_zebra_name) free(hc->routemap_export_zebra_name); + route_map_counter_decrement(hc->routemap_export_zebra); hc->routemap_export_zebra_name = strdup(argv[4]->arg); hc->routemap_export_zebra = route_map_lookup_by_name(argv[4]->arg); + route_map_counter_increment(hc->routemap_export_zebra); /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP); */ /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP6); */ } @@ -2083,6 +2108,7 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused) struct rfapi_nve_group_cfg *rfg; struct rfapi_cfg *hc; int i; + struct route_map *old = NULL; vnc_zlog_debug_verbose("%s(arg=%s)", __func__, unused); @@ -2104,18 +2130,36 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused) rfg)) { if (rfg->routemap_export_bgp_name) { + old = rfg->routemap_export_bgp; rfg->routemap_export_bgp = route_map_lookup_by_name( rfg->routemap_export_bgp_name); + /* old is NULL. i.e Route map creation event. + * So update applied_counter. + * If Old is not NULL, i.e It may be routemap + * updation or deletion. + * So no need to update the counter. + */ + if (!old) + route_map_counter_increment( + rfg->routemap_export_bgp); } if (rfg->routemap_export_zebra_name) { + old = rfg->routemap_export_bgp; rfg->routemap_export_bgp = route_map_lookup_by_name( rfg->routemap_export_zebra_name); + if (!old) + route_map_counter_increment( + rfg->routemap_export_bgp); } for (i = 0; i < ZEBRA_ROUTE_MAX; ++i) { if (rfg->routemap_redist_name[i]) { + old = rfg->routemap_redist[i]; rfg->routemap_redist[i] = route_map_lookup_by_name( rfg->routemap_redist_name[i]); + if (!old) + route_map_counter_increment( + rfg->routemap_redist[i]); } } @@ -2128,17 +2172,27 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused) * RH config, too */ if (hc->routemap_export_bgp_name) { + old = hc->routemap_export_bgp; hc->routemap_export_bgp = route_map_lookup_by_name(hc->routemap_export_bgp_name); + if (!old) + route_map_counter_increment(hc->routemap_export_bgp); } if (hc->routemap_export_zebra_name) { + old = hc->routemap_export_bgp; hc->routemap_export_bgp = route_map_lookup_by_name( hc->routemap_export_zebra_name); + if (!old) + route_map_counter_increment(hc->routemap_export_bgp); } for (i = 0; i < ZEBRA_ROUTE_MAX; ++i) { if (hc->routemap_redist_name[i]) { + old = hc->routemap_redist[i]; hc->routemap_redist[i] = route_map_lookup_by_name( hc->routemap_redist_name[i]); + if (!old) + route_map_counter_increment( + hc->routemap_redist[i]); } } diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 904d43c65..df2d404f6 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -123,7 +123,7 @@ void rfapiDebugBacktrace(void) * Count remote routes and compare with actively-maintained values. * Abort if they disagree. */ -void rfapiCheckRouteCount() +void rfapiCheckRouteCount(void) { struct bgp *bgp = bgp_get_default(); struct rfapi *h; @@ -2190,7 +2190,7 @@ static void rfapiItBiIndexDump(struct agg_node *rn) prefix2str(&k->extra->vnc.import.aux_prefix, buf_aux_pfx, sizeof(buf_aux_pfx)); } else - strncpy(buf_aux_pfx, "(none)", PREFIX_STRLEN); + strlcpy(buf_aux_pfx, "(none)", sizeof(buf_aux_pfx)); vnc_zlog_debug_verbose("bpi %p, peer %p, rd %s, aux_prefix %s", k, k->peer, buf, buf_aux_pfx); @@ -2221,7 +2221,7 @@ static struct bgp_path_info *rfapiItBiIndexSearch( prefix2str(aux_prefix, buf_aux_pfx, sizeof(buf_aux_pfx)); } else - strncpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx)); + strlcpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx)); vnc_zlog_debug_verbose("%s want prd=%s, peer=%p, aux_prefix=%s", __func__, diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 520cc141c..8e8acbfb9 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -222,7 +222,7 @@ void rfapiRibCheckCounts( assert(t_ri_active + t_ri_deleted + t_ri_pend + offset == alloc_count); } -static struct rfapi_info *rfapi_info_new() +static struct rfapi_info *rfapi_info_new(void) { return XCALLOC(MTYPE_RFAPI_INFO, sizeof(struct rfapi_info)); } diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 04ddff934..ea82c254b 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -4964,7 +4964,7 @@ DEFUN (clear_vrf_all, return vnc_clear_vrf(vty, NULL, arg_vrf, NULL, NULL); } -void rfapi_vty_init() +void rfapi_vty_init(void) { install_element(ENABLE_NODE, &add_vnc_prefix_cost_life_lnh_cmd); install_element(ENABLE_NODE, &add_vnc_prefix_life_cost_lnh_cmd); diff --git a/bgpd/rfp-example/librfp/rfp_example.c b/bgpd/rfp-example/librfp/rfp_example.c index e8f670cf1..060fc7655 100644 --- a/bgpd/rfp-example/librfp/rfp_example.c +++ b/bgpd/rfp-example/librfp/rfp_example.c @@ -107,7 +107,7 @@ DEFUN (rfp_full_table_download, return CMD_SUCCESS; } -static void rfp_vty_install() +static void rfp_vty_install(void) { static int installed = 0; if (installed) /* do this only once */ diff --git a/bgpd/rfp-example/rfptest/rfptest.c b/bgpd/rfp-example/rfptest/rfptest.c index 48df6c0cc..1036829b8 100644 --- a/bgpd/rfp-example/rfptest/rfptest.c +++ b/bgpd/rfp-example/rfptest/rfptest.c @@ -26,7 +26,7 @@ #include <stdio.h> #include <stdlib.h> #include "rfptest.h" -int main() +int main(void) { printf("Your test code goes here.\n"); exit(1); diff --git a/bgpd/subdir.am b/bgpd/subdir.am index 7dd1d73f6..d281fe4e5 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -191,17 +191,20 @@ noinst_HEADERS += \ bgpd_bgpd_SOURCES = bgpd/bgp_main.c bgpd_bgp_btoa_SOURCES = bgpd/bgp_btoa.c +bgpd_bgpd_CFLAGS = $(AM_CFLAGS) +bgpd_bgp_btoa_CFLAGS = $(AM_CFLAGS) + if ENABLE_BGP_VNC bgpd_bgpd_SOURCES += bgpd/rfapi/rfapi_descriptor_rfp_utils.c -bgpd_bgpd_CFLAGS = -Irfapi -I@top_srcdir@/$(RFPINC) +bgpd_bgpd_CFLAGS += -Irfapi -I@top_srcdir@/$(RFPINC) bgpd_bgp_btoa_SOURCES += bgpd/rfapi/rfapi_descriptor_rfp_utils.c -bgpd_bgp_btoa_CFLAGS = -Irfapi -I@top_srcdir@/$(RFPINC) +bgpd_bgp_btoa_CFLAGS += -Irfapi -I@top_srcdir@/$(RFPINC) endif # RFPLDADD is set in bgpd/rfp-example/librfp/subdir.am -bgpd_bgpd_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la @LIBCAP@ @LIBM@ -bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la @LIBCAP@ @LIBM@ +bgpd_bgpd_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) +bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) bgpd_bgpd_snmp_la_SOURCES = bgpd/bgp_snmp.c bgpd_bgpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99 @@ -221,6 +224,8 @@ bgpd/bgp_route_clippy.c: $(CLIPPY_DEPS) bgpd/bgp_route.$(OBJEXT): bgpd/bgp_route_clippy.c bgpd/bgp_debug_clippy.c: $(CLIPPY_DEPS) bgpd/bgp_debug.$(OBJEXT): bgpd/bgp_debug_clippy.c +bgpd/bgp_routemap_clippy.c: $(CLIPPY_DEPS) +bgpd/bgp_routemap.$(OBJEXT): bgpd/bgp_routemap_clippy.c bgpd/bgp_rpki_clippy.c: $(CLIPPY_DEPS) $(AUTOMAKE_DUMMY)bgpd/bgpd_bgpd_rpki_la-bgp_rpki.lo: bgpd/bgp_rpki_clippy.c $(AUTOMAKE_DUMMY)bgpd/bgpd_rpki_la-bgp_rpki.lo: bgpd/bgp_rpki_clippy.c diff --git a/bgpd/valgrind.supp b/bgpd/valgrind.supp index 28c3f8274..7a25c8836 100644 --- a/bgpd/valgrind.supp +++ b/bgpd/valgrind.supp @@ -6,8 +6,4 @@ fun:dlopen@@GLIBC_2.2.5 fun:ly_load_plugins_dir fun:ly_load_plugins - fun:ly_ctx_new - fun:yang_init - fun:frr_init - fun:main } diff --git a/debianpkg/changelog.in b/changelog-auto.in index 8f3f4753d..127d7fe14 100644 --- a/debianpkg/changelog.in +++ b/changelog-auto.in @@ -1,4 +1,49 @@ -frr (@VERSION@) RELEASED; urgency=medium +frr (@VERSION@-0) UNRELEASED; urgency=medium + + * autoconf changelog entry -- for git autobuilds only. + remove and replace when creating releases! + (tools/tarsource.sh will handle this) + + -- FRRouting-Dev <dev@lists.frrouting.org> Thu, 25 Oct 2018 16:36:50 +0200 + +frr (6.0-2) testing; urgency=medium + + * add install-info to build deps + * remove trailing whitespace from control + * cleanup tcp-zebra configure options + * drop unused SMUX client OID MIBs + * remove /proc check + * remove --enable-poll + * remove libtool .la files + * drop texlive-latex-base, texlive-generic-recommended build deps + * consistently allow python2 or python3 + * remove bad USE_* options, add WERROR + * drop libncurses5 dep + * remove backports mechanism + * use better dependency for pythontools (binNMU compatible) + * remove bogus shlib:Depends on frr-dbg + * create frr-snmp and frr-rpki-rtrlib + * make frr-pythontools a "Recommends:" + * use redistclean target + * update to Debian Policy version 4.2.1 + * raise debhelper compat level to 9 + * ditch development-only files + * modernise dh_missing and use fail mode + * disable zeromq and FPM + * always install /etc/init.d/frr + * put frr-doc package in 'doc' section + * install HTML docs, drop tools/ + * fix install for {frr,rfptest,ospfclient} + * add watch file + * change python dependency and shebang to python3:any + * use set -e in maintscripts + * put myself in as maintainer + * update copyright file + * closes: #863249 + + -- David Lamparter <equinox-debian@diac24.net> Thu, 25 Oct 2018 16:36:50 +0200 + +frr (6.0-1) RELEASED; urgency=medium * New Enabled: PIM draft Unnumbered @@ -7,7 +52,7 @@ frr (@VERSION@) RELEASED; urgency=medium frr (3.0-1) RELEASED; urgency=medium * Added Debian 9 Backport - + -- FRRouting-Dev <dev@lists.frrouting.org> Mon, 16 Oct 2017 03:28:00 -0700 frr (3.0-0) RELEASED; urgency=medium @@ -28,7 +73,7 @@ frr (3.0-0) RELEASED; urgency=medium * New Enabled: PIM Sparse Mode * New Enabled: NHRP RFC 2332 * New Enabled: Label Manager - * Switched from hardening-wrapper to dpkg-buildflags. + * Switched from hardening-wrapper to dpkg-buildflags. -- FRRouting-Dev <dev@lists.frrouting.org> Fri, 13 Oct 2017 16:17:26 -0700 @@ -66,7 +111,7 @@ quagga (0.99.24+cl3u3) RELEASED; urgency=medium quagga (0.99.23.1-1+cl3u2) RELEASED; urgency=medium - * New Enabled: VRF - See Documentation for how to use + * New Enabled: VRF - See Documentation for how to use * New Enabled: Improved interface statistics * New Enabled: Various vtysh improvements * New Enabled: Numerous compile warnings and SA fixes @@ -84,7 +129,7 @@ quagga (0.99.23.1-1+cl3u2) RELEASED; urgency=medium * New Enabled: BGP default keepalive to 3s and holdtime to 9s * New Enabled: OSPF spf timers are now '0 50 5000' by default * New Enabled: BGP hostname is displayed by default - * New Enabled: BGP 'no-as-set' is the default for + * New Enabled: BGP 'no-as-set' is the default for 'bgp as-path multipath-relax" * New Enabled: RA is on by default if using 5549 on an interface * New Enabled: peer-group restrictions relaxed, update-groups determine @@ -108,11 +153,11 @@ quagga (0.99.23.1-1+cl3u2) RELEASED; urgency=medium * Closes: CM-9974 Get route counts right for show ip route summary * Closes: CM-9786 BGP memory leak in peer hostname * Closes: CM-9340 BGP: Ensure correct sequence of processing at exit - * Closes: CM-9270 ripd: Fix crash when a default route is passed to rip - * Closes: CM-9255 BGPD crash around bgp_config_write () + * Closes: CM-9270 ripd: Fix crash when a default route is passed to rip + * Closes: CM-9255 BGPD crash around bgp_config_write () * Closes: CM-9134 ospf6d: Fix for crash when non area 0 network entered first - * Closes: CM-8934 OSPFv3: Check area before scheduling SPF + * Closes: CM-8934 OSPFv3: Check area before scheduling SPF * Closes: CM-8514 zebra: Crash upon disabling a link * Closes: CM-8295 BGP crash in group_announce_route_walkcb * Closes: CM-8191 BGP: crash in update_subgroup_merge() @@ -148,15 +193,15 @@ quagga (0.99.22.4-4) unstable; urgency=medium quagga (0.99.22.4-3) unstable; urgency=low - * Added status to init script (thanks to Peter J. Holzer). Closes: #730625 + * Added status to init script (thanks to Peter J. Holzer). Closes: #730625 * Init script now sources /lib/lsb/init-functions. - * Switched from hardening-wrapper to dpkg-buildflags. + * Switched from hardening-wrapper to dpkg-buildflags. -- Christian Hammers <ch@debian.org> Wed, 01 Jan 2014 19:12:01 +0100 quagga (0.99.22.4-2) unstable; urgency=low - * Fixed typo in package description (thanks to Davide Prina). + * Fixed typo in package description (thanks to Davide Prina). Closes: #625860 * Added Italian Debconf translation (thanks to Beatrice Torracca) Closes: #729798 @@ -171,15 +216,15 @@ quagga (0.99.22.4-1) unstable; urgency=high the OSPF API-server (exporting the LSDB and allowing announcement of Opaque-LSAs) writes past the end of fixed on-stack buffers. This leads to an exploitable stack overflow. - + For this condition to occur, the following two conditions must be true: - Quagga is configured with --enable-opaque-lsa - ospfd is started with the "-a" command line option - + If either of these does not hold, the relevant code is not executed and the issue does not get triggered." Closes: #726724 - + * New upstream release - ospfd: protect vs. VU#229804 (malformed Router-LSA) (Quagga is said to be non-vulnerable but still adds some protection) @@ -188,7 +233,7 @@ quagga (0.99.22.4-1) unstable; urgency=high quagga (0.99.22.1-2) unstable; urgency=low - * Added autopkgtests (thanks to Yolanda Robla). Closes: #710147 + * Added autopkgtests (thanks to Yolanda Robla). Closes: #710147 * Added "status" command to init script (thanks to James Andrewartha). Closes: #690013 * Added "libsnmp-dev" to Build-Deps. There not needed for the official @@ -196,7 +241,7 @@ quagga (0.99.22.1-2) unstable; urgency=low SNMP feature (which for licence reasons cannot be done by Debian). Thanks to Ben Winslow). Closes: #694852 * Changed watchquagga_options to an array so that quotes can finally - be used as expected. Closes: #681088 + be used as expected. Closes: #681088 * Fixed bug that prevented restarting only the watchquagga daemon (thanks to Harald Kappe). Closes: #687124 @@ -215,7 +260,7 @@ quagga (0.99.22.1-1) unstable; urgency=low quagga (0.99.22-1) unstable; urgency=low - * New upstream release. + * New upstream release. - [bgpd] The semantics of default-originate route-map have changed. The route-map is now used to advertise the default route conditionally. The old behaviour which allowed to set attributes on the originated @@ -227,7 +272,7 @@ quagga (0.99.22-1) unstable; urgency=low - [isisd] is in "beta" state. - [ospf6d] is in "alpha/experimental" state - More changes are documented in the upstream changelog! - * debian/watch: Adjusted to new savannah.gnu.org site, thanks to Bart + * debian/watch: Adjusted to new savannah.gnu.org site, thanks to Bart Martens. * debian/patches/99_CVE-2012-1820_bgp_capability_orf.diff removed as its in the changelog. @@ -274,7 +319,7 @@ quagga (0.99.21-1) unstable; urgency=low - [babeld] a new routing daemon implementing the BABEL ad-hoc mesh routing protocol has been merged. - [isisd] a major overhaul has been picked up. Please note that isisd is - STILL NOT SUITABLE FOR PRODUCTION USE. + STILL NOT SUITABLE FOR PRODUCTION USE. - a lot of bugs have been fixed * Added watchquagga daemon. * Added DEP-3 conforming patch comments. @@ -309,7 +354,7 @@ quagga (0.99.20-2) unstable; urgency=low * Bumped standards version to 0.9.2. * Migrated to "dh" build system. - * Added quagga-dbg package. + * Added quagga-dbg package. -- Christian Hammers <ch@debian.org> Fri, 14 Oct 2011 23:59:26 +0200 @@ -317,7 +362,7 @@ quagga (0.99.20-1) unstable; urgency=low * New upstream release: "The primary focus of this release is a fix of SEGV regression in ospfd, - which was introduced in 0.99.19. It also features a series of minor + which was introduced in 0.99.19. It also features a series of minor improvements, including better RFC compliance in bgpd, better support of FreeBSD and some enhancements to isisd." * Fixes off-by-one bug (removed 20_ospf6_area_argv.dpatch). Closes: #519488 @@ -342,7 +387,7 @@ quagga (0.99.18-1) unstable; urgency=low * SECURITY: "This release fixes 2 denial of services in bgpd, which can be remotely triggered by malformed AS-Pathlimit or Extended-Community attributes. - These issues have been assigned CVE-2010-1674 and CVE-2010-1675. + These issues have been assigned CVE-2010-1674 and CVE-2010-1675. Support for AS-Pathlimit has been removed with this release." * Added Brazilian Portuguese debconf translation. Closes: #617735 * Changed section for quagga-doc from "doc" to "net". @@ -352,7 +397,7 @@ quagga (0.99.18-1) unstable; urgency=low quagga (0.99.17-4) unstable; urgency=low - * Added comment to init script (thanks to Marc Haber). Closes: #599524 + * Added comment to init script (thanks to Marc Haber). Closes: #599524 -- Christian Hammers <ch@debian.org> Thu, 13 Jan 2011 23:53:29 +0100 @@ -365,7 +410,7 @@ quagga (0.99.17-3) unstable; urgency=low quagga (0.99.17-2) unstable; urgency=low - * Added Danisch Debconf translation (thanks to Joe Dalton). Closes: #596259 + * Added Danisch Debconf translation (thanks to Joe Dalton). Closes: #596259 -- Christian Hammers <ch@debian.org> Sat, 18 Sep 2010 12:20:07 +0200 @@ -384,7 +429,7 @@ quagga (0.99.17-1) unstable; urgency=high quagga (0.99.16-1) unstable; urgency=low - * New upstream release. Closes: #574527 + * New upstream release. Closes: #574527 * Added chrpath to debian/rules to fix rpath problems that lintian spottet. -- Christian Hammers <ch@debian.org> Sun, 21 Mar 2010 17:05:40 +0100 @@ -401,16 +446,16 @@ quagga (0.99.15-1) unstable; urgency=low * New upstream release "This fixes some annoying little ospfd and ospf6d regressions, which made - 0.99.14 a bit of a problem release (...) This release still contains a - regression in the "no ip address ..." command, at least on Linux. - See bug #486, which contains a workaround patch. This release should be + 0.99.14 a bit of a problem release (...) This release still contains a + regression in the "no ip address ..." command, at least on Linux. + See bug #486, which contains a workaround patch. This release should be considered a 1.0.0 release candidate. Please test this release as widely as possible." - * Fixed wrong port number in zebra.8 (thanks to Thijs Kinkhorst). + * Fixed wrong port number in zebra.8 (thanks to Thijs Kinkhorst). Closes: #517860 - * Added Russian Debconf tanslation (thanks to Yuri Kozlov). + * Added Russian Debconf tanslation (thanks to Yuri Kozlov). Closes: #539464 - * Removed so-version in build-dep to libreadline-dev on request of + * Removed so-version in build-dep to libreadline-dev on request of Matthias Klose. * Added README.source with reference to dpatch as suggested by lintian. * Bumped standards versionto 3.8.3. @@ -431,8 +476,8 @@ quagga (0.99.14-1) unstable; urgency=low quagga (0.99.13-2) unstable; urgency=low - * Added Japanese Debconf translation (thanks to Hideki Yamane). - Closes: #510714 + * Added Japanese Debconf translation (thanks to Hideki Yamane). + Closes: #510714 * When checking for obsoleted config options in preinst, print filename where it occures (thanks to Michael Bussmann). Closes: #339489 @@ -456,7 +501,7 @@ quagga (0.99.12-1) unstable; urgency=high "This release fixes an urgent bug in bgpd where it could hit an assert if it received a long AS_PATH with a 4-byte ASN." Noteworthy bugfixes: + [bgpd] Fix bgp ipv4/ipv6 accept handling - + [bgpd] AS4 bugfix by Chris Caputo + + [bgpd] AS4 bugfix by Chris Caputo + [bgpd] Allow accepted peers to progress even if realpeer is in Connect + [ospfd] Switch Fletcher checksum back to old ospfd version @@ -481,7 +526,7 @@ quagga (0.99.10-1) unstable; urgency=medium + bgpd: 4-Byte AS Number support + Sessions were incorrectly reset if a partial AS-Pathlimit attribute was received. - + Advertisement of Multi-Protocol prefixes (i.e. non-IPv4) had been + + Advertisement of Multi-Protocol prefixes (i.e. non-IPv4) had been broken in the 0.99.9 release. Closes: #467656 -- Christian Hammers <ch@debian.org> Tue, 08 Jul 2008 23:32:42 +0200 @@ -516,7 +561,7 @@ quagga (0.99.9-3) unstable; urgency=low Closes: #428574 * debian/control: (thanks to Marco Rodrigues) + Bump Standards-Version to 3.7.3 (no changes needed). - + Add Homepage field. + + Add Homepage field. -- Christian Hammers <ch@debian.org> Mon, 28 Jan 2008 22:29:18 +0100 @@ -546,7 +591,7 @@ quagga (0.99.9-1) unstable; urgency=high quagga (0.99.8-1) unstable; urgency=low - * New upstream version. + * New upstream version. -- Christian Hammers <ch@debian.org> Fri, 17 Aug 2007 00:07:04 +0200 @@ -572,7 +617,7 @@ quagga (0.99.7-2) unstable; urgency=low quagga (0.99.7-1) unstable; urgency=low - * New upstream release. Closes: #421553 + * New upstream release. Closes: #421553 -- Christian Hammers <ch@debian.org> Mon, 30 Apr 2007 14:22:34 +0200 @@ -586,7 +631,7 @@ quagga (0.99.6-5) unstable; urgency=high * SECURITY: The bgpd daemon was vulnerable to a Denial-of-Service. Configured peers - could cause a Quagga bgpd to, typically, assert() and abort. The DoS + could cause a Quagga bgpd to, typically, assert() and abort. The DoS could be triggered by peers by sending an UPDATE message with a crafted, malformed Multi-Protocol reachable/unreachable NLRI attribute. This is CVE-2007-1995 and Quagga Bug#354. Closes: #418323 @@ -595,8 +640,8 @@ quagga (0.99.6-5) unstable; urgency=high quagga (0.99.6-4) unstable; urgency=low - * Improved note in README.Debian for SNMP self-builders (thanks to Matthias - Wamser). Closes: #414788 + * Improved note in README.Debian for SNMP self-builders (thanks to Matthias + Wamser). Closes: #414788 -- Christian Hammers <ch@debian.org> Wed, 14 Mar 2007 02:18:57 +0100 @@ -623,7 +668,7 @@ quagga (0.99.6-1) unstable; urgency=low quagga (0.99.5-5) unstable; urgency=high * Changed Depends on adduser to Pre-Depends to avoid uninstallability - in certain cases (thanks to Steve Langasek, Lucas Nussbaum). + in certain cases (thanks to Steve Langasek, Lucas Nussbaum). Closes: #398562 -- Christian Hammers <ch@debian.org> Wed, 15 Nov 2006 17:46:34 +0100 @@ -631,7 +676,7 @@ quagga (0.99.5-5) unstable; urgency=high quagga (0.99.5-4) unstable; urgency=low * Added default PAM file and some explanations regarding PAM authentication - of vtysh which could prevent the start at boot-time when used wrong. + of vtysh which could prevent the start at boot-time when used wrong. Now PAM permits anybody to access the vtysh tool (a malicious user could build his own vtysh without PAM anyway) and the access is controled by the read/write permissions of the vtysh socket which are only granted to @@ -652,7 +697,7 @@ quagga (0.99.5-3) unstable; urgency=medium quagga (0.99.5-2) unstable; urgency=medium - * Added LSB info section to initscript. + * Added LSB info section to initscript. * Removed unnecessary depends to libncurses5 to make checklib happy. The one to libcap should remain though as it is just temporarily unused. @@ -699,7 +744,7 @@ quagga (0.99.4-1) unstable; urgency=low quagga (0.99.3-3) unstable; urgency=low - * Added CVE numbers for the security patch in 0.99.3-2. + * Added CVE numbers for the security patch in 0.99.3-2. -- Christian Hammers <ch@debian.org> Sat, 6 May 2006 17:14:22 +0200 @@ -711,7 +756,7 @@ quagga (0.99.3-2) unstable; urgency=high CVE-2006-2223 - missing configuration to disable RIPv1 or require plaintext or MD5 authentication CVE-2006-2224 - lack of enforcement of RIPv2 authentication requirements - Closes: #365940 + Closes: #365940 * First amd64 upload. -- Christian Hammers <ch@debian.org> Thu, 4 May 2006 00:22:09 +0200 @@ -742,7 +787,7 @@ quagga (0.99.1-7) unstable; urgency=low quagga (0.99.1-6) unstable; urgency=low - * Fixed debconf dependency as requested by Joey Hess. + * Fixed debconf dependency as requested by Joey Hess. -- Christian Hammers <ch@debian.org> Mon, 26 Sep 2005 20:47:35 +0200 @@ -862,7 +907,7 @@ quagga (0.98.3-2) unstable; urgency=low quagga (0.98.3-1) unstable; urgency=low - * New upstream release. + * New upstream release. Mmost notably fixes last regression in bgpd (reannounce of prefixes with changed attributes works again), race condition in netlink handling while using IPv6, MTU changes handling in ospfd and several @@ -881,9 +926,9 @@ quagga (0.98.2-1) unstable; urgency=medium * Quoting the upstream announcement: The 0.98.1 release unfortunately was a brown paper bag release with - respect to ospfd. [...] 0.98.2 has been released, with one crucial change - to fix the unfortunate mistake in 0.98.1, which caused problems if - ospfd became DR. + respect to ospfd. [...] 0.98.2 has been released, with one crucial change + to fix the unfortunate mistake in 0.98.1, which caused problems if + ospfd became DR. * Note: the upstream tarball had a strange problem, apparently redhat.spec was twice in it? At least debuild gave a strange error message so I unpacked it by hand. No changes were made to the .orig.tar.gz! @@ -906,7 +951,7 @@ quagga (0.98.1-1) unstable; urgency=medium quagga (0.98.0-3) unstable; urgency=low - * Fixed problem in init script. Closes: #290317 + * Fixed problem in init script. Closes: #290317 * Removed obsolete "smux peer enable" patch. -- Christian Hammers <ch@debian.org> Fri, 14 Jan 2005 17:37:27 +0100 @@ -928,7 +973,7 @@ quagga (0.98.0-1) unstable; urgency=low quagga (0.97.5-1) unstable; urgency=low - * New upstream version. + * New upstream version. * Added Czech debconf translation (thanks to Miroslav Kure). Closes: #287293 * Added Brazilian debconf translation (thanks to Andre Luis Lopes). @@ -938,7 +983,7 @@ quagga (0.97.5-1) unstable; urgency=low quagga (0.97.4-2) unstable; urgency=low - * Fixed quagga.info build problem. + * Fixed quagga.info build problem. -- Christian Hammers <ch@debian.org> Wed, 5 Jan 2005 22:38:01 +0100 @@ -972,7 +1017,7 @@ quagga (0.97.2-4) unstable; urgency=low * Added Portuguese debconf translation (thanks to Andre Luis Lopes). Closes: #279352 - * Disabled ospfapi server by default on recommendation of Paul Jakma. + * Disabled ospfapi server by default on recommendation of Paul Jakma. -- Christian Hammers <ch@debian.org> Sun, 7 Nov 2004 15:07:05 +0100 @@ -988,14 +1033,14 @@ quagga (0.97.2-2) unstable; urgency=low suggestion from Paul Jakma. Still not perfect though. * Fixed upstream vtysh.conf.sample file. * "ip ospf network broadcast" is now saved correctly. Closes: #244116 - * Daemon options are now in /etc/quagga/debian.conf to be user + * Daemon options are now in /etc/quagga/debian.conf to be user configurable (thanks to Simon Raven and Hasso Tepper). Closes: #266715 -- Christian Hammers <ch@debian.org> Tue, 26 Oct 2004 23:35:45 +0200 quagga (0.97.2-1) unstable; urgency=low - * New upstream version. + * New upstream version. Closes: #254541 * Fixed warning on unmodular kernels (thanks to Christoph Biedl). Closes: #277973 @@ -1011,7 +1056,7 @@ quagga (0.97.1-2) unstable; urgency=low quagga (0.97.1-1) unstable; urgency=low - * New upstream version. + * New upstream version. * Removed some obsolete files from debian/patches. * Added patch from upstream bug 113. Closes: #254541 * Added patch from upstream that fixes a compilation problem in the @@ -1047,7 +1092,7 @@ quagga (0.96.5-10) unstable; urgency=medium quagga (0.96.5-9) unstable; urgency=low * Rewrote the documentation chapter about SNMP support. Closes: #195653 - * Added MPLS docs. + * Added MPLS docs. -- Christian Hammers <ch@debian.org> Thu, 29 Jul 2004 21:01:52 +0200 @@ -1074,7 +1119,7 @@ quagga (0.96.5-7) unstable; urgency=low quagga (0.96.5-6) unstable; urgency=low - * Try to load the capability module as it is needed now. + * Try to load the capability module as it is needed now. -- Christian Hammers <ch@debian.org> Tue, 8 Jun 2004 23:25:29 +0200 @@ -1103,9 +1148,9 @@ quagga (0.96.5-3) unstable; urgency=low quagga (0.96.5-2) unstable; urgency=low * New upstream version. - * New md5 patch version (thanks to Niklas Jakobsson and Hasso Tepper). + * New md5 patch version (thanks to Niklas Jakobsson and Hasso Tepper). Closes: #250985 - * Fixes info file generation (thanks to Peder Chr. Norgaard). + * Fixes info file generation (thanks to Peder Chr. Norgaard). Closes: #250992 * Added catalan debconf translation (thanks to Aleix Badia i Bosch). Closes: #250118 @@ -1136,14 +1181,14 @@ quagga (0.96.4x-10) unstable; urgency=low started to require it. See: CAN-2004-0230, http://www.us-cert.gov/cas/techalerts/TA04-111A.html * PATCHES: - This release contains the MD5 patch from Hasso Tepper. It also seems to + This release contains the MD5 patch from Hasso Tepper. It also seems to required a kernel patch. See /usr/share/doc/quagga/README.Debian.MD5. -- Christian Hammers <ch@debian.org> Thu, 29 Apr 2004 01:01:38 +0200 quagga (0.96.4x-9) unstable; urgency=low - * Fixed daemon loading order (thanks to Matt Kemner). + * Fixed daemon loading order (thanks to Matt Kemner). * Fixed typo in init script (thanks to Charlie Brett). Closes: #238582 -- Christian Hammers <ch@debian.org> Sun, 4 Apr 2004 15:32:18 +0200 @@ -1151,7 +1196,7 @@ quagga (0.96.4x-9) unstable; urgency=low quagga (0.96.4x-8) unstable; urgency=low * Patched upstream source so that quagga header files end up in - /usr/include/quagga/. Closes: #233792 + /usr/include/quagga/. Closes: #233792 -- Christian Hammers <ch@debian.org> Mon, 23 Feb 2004 01:42:53 +0100 @@ -1164,8 +1209,8 @@ quagga (0.96.4x-7) unstable; urgency=low quagga (0.96.4x-6) unstable; urgency=low - * Added dependency to iproute. - * Initscript now checks not only for the pid file but also for the + * Added dependency to iproute. + * Initscript now checks not only for the pid file but also for the daemons presence (thanks to Phil Gregory). Closes: #224389 * Added my patch to configure file permissions. @@ -1182,13 +1227,13 @@ quagga (0.96.4x-5) unstable; urgency=low obscure whitespaces inside an C macro. (Thanks to Marc Haber). Closes: #223529 * Now uses /usr/bin/pager. Closes: #204070 - * Added note about the "official woody backports" on my homepage. + * Added note about the "official woody backports" on my homepage. -- Christian Hammers <ch@debian.org> Mon, 15 Dec 2003 20:39:06 +0100 quagga (0.96.4x-4) unstable; urgency=high - * SECURITY: + * SECURITY: Fixes another bug that was originally reported against Zebra. . http://rhn.redhat.com/errata/RHSA-2003-307.html @@ -1210,7 +1255,7 @@ quagga (0.96.4x-3) unstable; urgency=low * Made the directory (but not the config/log files!) world accessible again on user request (thanks to Anand Kumria)). Closes: #213129 * No longer providing sample configuration in /etc/quagga/. They are - now only available in /usr/share/doc/quagga/ to avoid accidently + now only available in /usr/share/doc/quagga/ to avoid accidently using them without changing the adresses (thanks to Marc Haber). Closes: #215918 @@ -1219,13 +1264,13 @@ quagga (0.96.4x-3) unstable; urgency=low quagga (0.96.4x-2) unstable; urgency=low * Fixed permission problem with pidfile (thanks to Kir Kostuchenko). - Closes: #220938 + Closes: #220938 -- Christian Hammers <ch@debian.org> Sun, 16 Nov 2003 14:24:08 +0100 quagga (0.96.4x-1) unstable; urgency=low - * Reupload of 0.96.4. Last upload-in-a-hurry produced a totally + * Reupload of 0.96.4. Last upload-in-a-hurry produced a totally crappy .tar.gz file. Closes: #220621 -- Christian Hammers <ch@debian.org> Fri, 14 Nov 2003 19:45:57 +0100 @@ -1235,7 +1280,7 @@ quagga (0.96.4-1) unstable; urgency=high * SECURITY: Remote DoS of protocol daemons. Fix for a remote triggerable crash in vty layer. The management ports ("telnet myrouter ospfd") should not be open to the internet! - + * New upstream version. - OSPF bugfixes. - Some improvements for bgp and rip. @@ -1252,7 +1297,7 @@ quagga (0.96.3-3) unstable; urgency=low quagga (0.96.3-2) unstable; urgency=low - * Readded GNOME-PRODUCT-ZEBRA-MIB. + * Readded GNOME-PRODUCT-ZEBRA-MIB. -- Christian Hammers <ch@debian.org> Thu, 23 Oct 2003 06:17:03 +0200 diff --git a/configure.ac b/configure.ac index 7f08e8e76..fcfc4bd2f 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ([2.60]) -AC_INIT([frr], [6.1-dev], [https://github.com/frrouting/frr/issues]) +AC_INIT([frr], [7.1-dev], [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" AC_SUBST([PACKAGE_URL]) PACKAGE_FULLNAME="FRRouting" @@ -147,7 +147,7 @@ dnl - specifically, options to control warnings AC_USE_SYSTEM_EXTENSIONS AC_DEFUN([AC_C_FLAG], [{ - m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-],[___])]) + m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-+],[____])]) AC_CACHE_CHECK([[whether $CC supports $1]], cachename, [ AC_LANG_PUSH([C]) ac_c_flag_save="$CFLAGS" @@ -261,6 +261,9 @@ fi AC_C_FLAG([-Wno-unused-parameter]) AC_C_FLAG([-Wno-missing-field-initializers]) +AC_C_FLAG([-Wc++-compat], [], [CXX_COMPAT_CFLAGS="-Wc++-compat"]) +AC_SUBST([CXX_COMPAT_CFLAGS]) + dnl ICC emits a broken warning for const char *x = a ? "b" : "c"; dnl for some reason the string consts get 'promoted' to char *, dnl triggering a const to non-const conversion warning. @@ -346,7 +349,7 @@ AM_CONDITIONAL([STATIC_BIN], [test "x$enable_static_bin" = "xyes"]) dnl $AR and $RANLIB are set by LT_INIT above AC_MSG_CHECKING([whether $AR supports D option]) -if $AR crD conftest.a; then +if $AR crD conftest.a >/dev/null 2>/dev/null; then AC_MSG_RESULT([yes]) dnl ARFLAGS is for automake, AR_FLAGS for libtool m-( ARFLAGS="crD" @@ -360,7 +363,7 @@ AC_SUBST([ARFLAGS]) AC_SUBST([AR_FLAGS]) AC_MSG_CHECKING([whether $RANLIB supports D option]) -if $RANLIB -D conftest.a; then +if $RANLIB -D conftest.a >/dev/null 2>/dev/null; then AC_MSG_RESULT([yes]) RANLIB="$RANLIB -D" else @@ -817,15 +820,17 @@ fi AM_CONDITIONAL([GIT_VERSION], [test "x$with_pkg_git_version" = "xyes"]) AC_CHECK_TOOL([OBJCOPY], [objcopy], [:]) -AC_CACHE_CHECK([for .interp value to use], [frr_cv_interp], [ - frr_cv_interp="" - AC_LINK_IFELSE([AC_LANG_SOURCE([[int main() { return 0; }]])], [ - if $OBJCOPY -j.interp -Obinary conftest conftest.interp; then - frr_cv_interp="`xargs -0 echo < conftest.interp`" - fi - test -f conftest.interp && rm conftest.interp +if test "x${OBJCOPY}" != "x:"; then + AC_CACHE_CHECK([for .interp value to use], [frr_cv_interp], [ + frr_cv_interp="" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main() { return 0; }]])], [ + if $OBJCOPY -j.interp -Obinary conftest conftest.interp; then + frr_cv_interp="`xargs -0 echo < conftest.interp`" + fi + test -f conftest.interp && rm conftest.interp + ]) ]) -]) +fi if test -n "$frr_cv_interp"; then AC_DEFINE_UNQUOTED([INTERP], ["$frr_cv_interp"], [.interp value]) fi @@ -1598,22 +1603,43 @@ AC_SUBST([SNMP_CFLAGS]) dnl --------------- dnl libyang dnl --------------- -PKG_CHECK_MODULES([libyang], [libyang >= 0.16.7], , [ +PKG_CHECK_MODULES([LIBYANG], [libyang >= 0.16.7], , [ AC_MSG_ERROR([libyang (>= 0.16.7) was not found on your system.]) ]) +ac_cflags_save="$CFLAGS" +CFLAGS="$CFLAGS $LIBYANG_CFLAGS" AC_CHECK_MEMBER([struct lyd_node.priv], [], [ AC_MSG_ERROR([m4_normalize([ libyang needs to be compiled with ENABLE_LYD_PRIV=ON. - See http://docs.frrouting.org/projects/dev-guide/en/latest/building-libyang.html for details.]) + Instructions for this are included in the build documentation for your platform at http://docs.frrouting.org/projects/dev-guide/en/latest/building.html]) ]) ], [[#include <libyang/libyang.h>]]) +CFLAGS="$ac_cflags_save" + +ac_libs_save="$LIBS" +LIBS="$LIBS $LIBYANG_LIBS" +AC_CHECK_FUNC([ly_register_types], [ + libyang_ext_builtin=true + AC_DEFINE([LIBYANG_EXT_BUILTIN], [1], [have ly_register_types()]) +], [ + libyang_ext_builtin=false + AC_MSG_WARN([===== old libyang (before 0.16.74) detected =====]) + AC_MSG_WARN([The available version of libyang does not seem to support]) + AC_MSG_WARN([built-in YANG extension modules. This will cause "make check"]) + AC_MSG_WARN([to fail and may create installation and version mismatch issues.]) + AC_MSG_WARN([Support for the old mechanism will be removed at some point.]) + AC_MSG_WARN([Please update libyang to version 0.16.74 or newer.]) + AC_MSG_WARN([===== old libyang (before 0.16.74) detected =====]) +]) +AM_CONDITIONAL([LIBYANG_EXT_BUILTIN], [$libyang_ext_builtin]) +LIBS="$ac_libs_save" dnl --------------- dnl configuration rollbacks dnl --------------- SQLITE3=false if test "$enable_config_rollbacks" = "yes"; then - PKG_CHECK_MODULES([sqlite3], [sqlite3], [ + PKG_CHECK_MODULES([SQLITE3], [sqlite3], [ AC_DEFINE([HAVE_CONFIG_ROLLBACKS], [1], [Enable configuration rollbacks]) AC_DEFINE([HAVE_SQLITE3], [1], [Enable sqlite3 database]) SQLITE3=true @@ -1633,6 +1659,8 @@ if test "$enable_confd" != "" -a "$enable_confd" != "no"; then fi CONFD_CFLAGS="-I${enable_confd}/include -L${enable_confd}/lib" AC_SUBST([CONFD_CFLAGS]) + CONFD_LIBS="-lconfd" + AC_SUBST([CONFD_LIBS]) AC_DEFINE([HAVE_CONFD], [1], [Enable confd integration]) fi AM_CONDITIONAL([CONFD], [test "x$enable_confd" != "x"]) @@ -1641,7 +1669,7 @@ dnl --------------- dnl sysrepo dnl --------------- if test "$enable_sysrepo" = "yes"; then - PKG_CHECK_MODULES([sysrepo], [libsysrepo], + PKG_CHECK_MODULES([SYSREPO], [libsysrepo], [AC_DEFINE([HAVE_SYSREPO], [1], [Enable sysrepo integration]) SYSREPO=true], [SYSREPO=false @@ -1715,7 +1743,8 @@ AC_CHECK_TYPES([ vifi_t, struct sioc_vif_req, struct igmpmsg, struct ifaliasreq, struct if6_aliasreq, struct in6_aliasreq, struct nd_opt_adv_interval, struct rt_addrinfo, - struct nd_opt_homeagent_info, struct nd_opt_adv_interval], + struct nd_opt_homeagent_info, struct nd_opt_adv_interval, + struct nd_opt_rdnss, struct nd_opt_dnssl], [], [], FRR_INCLUDES) AC_CHECK_MEMBERS([struct sockaddr.sa_len, @@ -2128,6 +2157,7 @@ AC_SUBST([CFG_LIBYANG_PLUGINS]) AC_DEFINE_UNQUOTED([MODULE_PATH], ["$CFG_MODULE"], [path to modules]) AC_DEFINE_UNQUOTED([YANG_MODELS_PATH], ["$CFG_YANGMODELS"], [path to YANG data models]) AC_DEFINE_UNQUOTED([LIBYANG_PLUGINS_PATH], ["$CFG_LIBYANG_PLUGINS"], [path to libyang plugins]) +AC_DEFINE_UNQUOTED([WATCHFRR_SH_PATH], ["${CFG_SBIN%/}/watchfrr.sh"], [path to watchfrr.sh]) dnl ------------------------------------ dnl Enable RPKI and add librtr to libs @@ -2167,9 +2197,9 @@ AC_CONFIG_FILES([Makefile],[sed -e 's/^#AUTODERP# //' -i Makefile]) AC_CONFIG_FILES([ config.version + changelog-auto redhat/frr.spec solaris/Makefile - debianpkg/changelog alpine/APKBUILD snapcraft/snapcraft.yaml lib/version.h diff --git a/debianpkg/README.Debian b/debian/README.Debian index cd7be5e80..47a353310 100644 --- a/debianpkg/README.Debian +++ b/debian/README.Debian @@ -22,6 +22,36 @@ which itself is a fork of Zebra. Zebra was developed by Kunihiro Ishiguro. +* Build Profiles used in the upstream debian/ +============================================= + +The following Build Profiles have been added: + +- pkg.frr.nortrlib (pkg.frr.rtrlib) + controls whether the RPKI module is built. + Will be enabled by default at some point, adds some extra dependencies. + +- pkg.frr.nosnmp (pkg.frr.snmp) + controls whether the SNMP module is built, see below for license issues. + Will remain default-off as long as the license issue persists. + +- pkg.frr.nosystemd + Disables both systemd unit file installation as well as watchfrr sd_notify + support at startup. Removes libsystemd dependency. + +Note that all options have a "no" form; if you want to have your decision +be sticky regardless of changes to what it defaults to, then always use one +of the two. For example, all occurrences of <pkg.frr.rtrlib> will at some +point be replaced with <!pkg.frr.nortrlib>. + +The main frr package has the exact same contents regardless of rtrlib or snmp +choices. The options only control frr-snmp and frr-rpki-rtrlib packages. + +The main frr package does NOT have the same contents if pkg.frr.nosystemd is +used. This option should only be used for systems that do not have systemd, +e.g. Ubuntu 14.04. + + * Why has SNMP support been disabled? ===================================== FRR used to link against the NetSNMP libraries to provide SNMP @@ -43,12 +73,20 @@ during the last days before the Sarge release :-( It is allowed by the used licence mix that you fetch the sources and build FRR yourself with SNMP with - <remove the "grep ^smux" block at the end of debian/frr.preinst> - # export WANT_SNMP=1 - # apt-get -b source frr + # apt-get -b source -Ppkg.frr.snmp frr Just distributing it in binary form, linked against OpenSSL, is forbidden. +* Debian Policy compliance notes +================================ + +- 4.15 Reproducibility + FRR build is reproducible as outlined in version 4.2.1 of the Policy, but + won't be reproducible when the build directory is varied. This is because + configure parameters are burned into the executables which includes CFLAGS + like -fdebug-prefix-map=/build/directory/... + + * Daemon selection: =================== diff --git a/debianpkg/README.Maintainer b/debian/README.Maintainer index 84b68e194..9030022c5 100644 --- a/debianpkg/README.Maintainer +++ b/debian/README.Maintainer @@ -1,4 +1,14 @@ # +# TODO +# + +- check that tests/{control,daemons} actually do something useful and sensible +- /usr/share/doc/frr-doc should be named just frr? +- debian/watch pgpsigurlmangle / signing-key +- multiarch for DSOs? +- frr try-restart + +# # To check if the patches still apply on new upstream versions: # for i in debian/patches/*.diff; do echo -e "#\n# $i\n#"; patch --fuzz=3 --dry-run -p1 < $i; done diff --git a/debian/changelog b/debian/changelog new file mode 120000 index 000000000..021c52c2f --- /dev/null +++ b/debian/changelog @@ -0,0 +1 @@ +../changelog-auto
\ No newline at end of file diff --git a/debian/compat b/debian/compat new file mode 100644 index 000000000..ec635144f --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/control b/debian/control new file mode 100644 index 000000000..ab2df2043 --- /dev/null +++ b/debian/control @@ -0,0 +1,131 @@ +Source: frr +Section: net +Priority: optional +Maintainer: David Lamparter <equinox-debian@diac24.net> +Uploaders: FRRouting-dev <dev@lists.frrouting.org> +Build-Depends: + autotools-dev, + bison, + chrpath, + debhelper (>= 9), + debhelper (>= 9.20160709) <!pkg.frr.nosystemd> | dh-systemd <!pkg.frr.nosystemd>, + dh-autoreconf, + flex, + gawk, + install-info, + libc-ares-dev, + libcap-dev, + libjson-c-dev | libjson0-dev, + libpam0g-dev | libpam-dev, + libpcre3-dev, + libpython3-dev, + libreadline-dev, + librtr-dev <!pkg.frr.nortrlib>, + libsnmp-dev, + libssh-dev <!pkg.frr.nortrlib>, + libsystemd-dev <!pkg.frr.nosystemd>, + libyang-dev (>= 0.16.74), + pkg-config, + python3, + python3-dev, + python3-sphinx, + python3-pytest <!nocheck>, + texinfo (>= 4.7) +Standards-Version: 4.2.1 +Homepage: https://www.frrouting.org/ +Vcs-Browser: https://github.com/FRRouting/frr/ +Vcs-Git: https://github.com/FRRouting/frr.git + +Package: frr +Architecture: linux-any +Depends: + ${misc:Depends}, + ${shlibs:Depends}, + iproute2 | iproute, + logrotate (>= 3.2-11) +Pre-Depends: adduser +Recommends: frr-pythontools +Suggests: frr-doc +Conflicts: + zebra, + zebra-pj, + pimd, + quagga, + quagga-bgpd, + quagga-core, + quagga-isisd, + quagga-ospf6d, + quagga-ospfd, + quagga-pimd, + quagga-ripd, + quagga-ripngd +Replaces: zebra, zebra-pj +Description: FRRouting suite of internet protocols (BGP, OSPF, IS-IS, ...) + FRRouting implements the routing protocols commonly used in the + internet and private networks to exchange information between routers. + Both IP and IPv6 are supported, as are BGP, OSPF, IS-IS, BABEL, EIGRP, + RIP, LDP, BFD, PIM and NHRP protocols. + . + These protocols are used to turn your system into a dynamic router, + exchanging information about available connections with other routers + in a standards-compliant way. The actual packet forwarding + functionality is provided by the OS kernel. + . + FRRouting is a fork of Quagga with an open community model. The main + git lives on https://github.com/frrouting/frr.git and the project name + is commonly abbreviated as "FRR." + +Package: frr-snmp +Architecture: linux-any +Depends: + ${misc:Depends}, + ${shlibs:Depends}, + frr (= ${binary:Version}) +Recommends: snmpd +Description: FRRouting suite - SNMP support + Adds SNMP support to FRR's daemons by attaching to net-snmp's snmpd + through the AgentX protocol. Provides read-only access to current + routing state through standard SNMP MIBs. + +Package: frr-rpki-rtrlib +Architecture: linux-any +Depends: + ${misc:Depends}, + ${shlibs:Depends}, + frr (= ${binary:Version}) +Description: FRRouting suite - BGP RPKI support (rtrlib) + Adds RPKI support to FRR's bgpd, allowing validation of BGP routes + against cryptographic information stored in WHOIS databases. This is + used to prevent hijacking of networks on the wider internet. It is only + relevant to internet service providers using their own autonomous system + number. +Build-Profiles: <!pkg.frr.nortrlib> + +Package: frr-doc +Section: doc +Architecture: all +Depends: + ${misc:Depends}, + libjs-jquery, + libjs-underscore +Suggests: frr +Conflicts: quagga-doc +Description: FRRouting suite - user manual + This provides the FRR user manual in HTML form. This is the official + manual maintained as part of the package and is also available online + at https://frrouting.readthedocs.io/ + +Package: frr-pythontools +Architecture: all +Depends: + ${misc:Depends}, + frr (<< ${source:Upstream-Version}.0-~), + frr (>= ${source:Version}~), + python3:any +Description: FRRouting suite - Python tools + The FRRouting suite uses a small Python tool to provide configuration + reload functionality, particularly useful when the interactive configuration + shell is not used. + . + Without this package installed, "reload" (as a systemd or init script + invocation) will not work for the FRR daemons. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 000000000..61d87260d --- /dev/null +++ b/debian/copyright @@ -0,0 +1,484 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: FRR +Upstream-Contact: maintainers@frrouting.org, security@frrouting.org +Source: https://www.frrouting.org/ + +Files: * +Copyright: 1996-2003 by the original Zebra authors: + Kunihiro Ishiguro <kunihiro@zebra.org> + Toshiaki Takada <takada@zebra.org> + Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + 2003-2016 by the Quagga Project + 2016-2018 by the FRRouting Project + Adam Fitzgerald 2017 + Alex Couloumbis 2017 + Alexandre Chappuis 2011 + Alexis Fasquel 2015 + Ali Rezaee 2018 + Ameya Dharkar 2018 + Amritha Nambiar 2015 + Andreas Jaggi 2017 + Andrew Certain 2012 + Andrew J. Schorr 2004-2011 + Andrew Lunn 2017 + Andrey Korolyov 2017-2018 + Ang Way Chuang 2012 + Anuradha Karuppiah 2016-2018 + Arthur Jones 2018 + Avneesh Sachdev 2012, 2016 + Ayan Banerjee 2012 + Balaji G. 2011-2016 + Barry Friedman 2011 + Bartek Kania 2008 + Baruch Siach 2016 + Bingen Eguzkitza 2016-2017 + Boian Bonev 2013 + Boris Yakubov 2013 + Brad Smith 2012 + Brett Ciphery 2013 + Brian Bennett 2015 + Brian Rak 2017 + Chirag Shah 2017-2018 + Chris Caputo 2009-2010 + Chris Hall 2010 + Chris Luke 2011 + Christian Franke 2012-2018 + Christian Hammers 2011 + Christoffer Hansen 2018 + Christoph Dwertmann 2018 + Colin Petrie 2016 + Daniel Kozlowski 2012 + Daniel Ng 2008 + Daniel Walton 2015-2018 + Daniil Baturin 2018 + Dario Wiesner 2018 + Dave Olson 2016-2017 + David BÉRARD 2010 + David Lamparter 2009-2018 + David Lebrun 2016 + David Ward 2009-2012 + David Young 2007 + Denil Vira 2015 + Denis Ovsienko 2007-2012 + Dinesh Dutt 2012-2013 + Dinesh G. Dutt 2013-2017 + Dmitrij Tejblum 2009-2011 + Dmitry Popov 2011 + Don Slice 2016-2018 + Donald Sharp 2015-2018 + Donatas Abraitis 2018 + Dongling Duan 2018 + Donnie Savage 2017 + Doug VanLeuven 2012 + Dylan Hall 2011 + Emanuele Di Pascale 2018 + Eric Pulvino 2017 + Everton Marques 2012-2014 + Evgeny Uskov 2016 + F. Aragon 2018 + Fatih USTA 2017 + Feng Lu 2014-2015 + Fernando Soto 2015 + Francesco Dolcini 2009 + Fredi Raspall 2016-2018 + Fritz Reichmann 2011 + G. Paul Ziemba 2016-2018 + Greg Troxel 2003-2007, 2010-2015 + Hasso Tepper 2003-2007, 2012-2013 + Hiroshi Yokoi 2015 + Hongguang Li 2016 + Hung-Weic Chiu 2017 + Igor Ryzhov 2016 + Ilya Shipitsin 2018 + Ingo Flaschberger 2011 + Ivan Moskalyov 2010 + JR Rivers 2012 + Jafar Al-Gharaibeh 2009, 2015-2018 + Jarad Olson 2018 + Jaroslav Fojtik 2011 + Jeremy Jackson 2008-2009 + Jingjing Duan 2008-2009 + Joachim Nilsson 2012-2013 + Joakim Tjernlund 2008-2014 + Job Snijders 2016 + John Berezovik 2016 + John Glotzer 2014 + John Kemp 2011 + Jon Andersson 2009-2011 + Jorge Boncompte 2012-2013, 2017 + Josh Bailey 2011-2012 + Juergen Kammer 2017 + Julien Courtat 2016 + Juliusz Chroboczek 2012 + Kaloyan Kovachev 2015-2017 + Ken Williams 2014 + Khiruthigai Balasubramanian 2016 + Krisztian Kovacs 2009 + Kunihiro Ishiguro 2018 + Leonard Tracy 2012 + Leonid Rosenboim 2012-2013 + Liu Xiaofeng 2016 + Lou Berger 2013, 2016-2018 + Lu Feng 2014-2015 + Lucian Cristian 2017 + Maitane Zotes 2014 + Manuel Schweizer 2017 + Marcel Röthke 2017-2018 + Mark Stapp 2018 + Martin Buck 2018 + Martin Winter 2015-2018 + Martín Beauchamp 2017 + Mathias Krause 2010 + Mathieu Goessens 2009 + Matthew Smith 2017 + Matthias Ferdinand 2011 + Matthieu Boutier 2012, 2016-2017 + Matti-Oskari Leppänen 2013 + Michael Lambert 2008-2010 + Michael Rossberg 2015 + Michael Zingg 2012 + Michal Sekletar 2014 + Mike Tancsa 2017 + Milan Kocian 2013-2014 + Mitesh Kanjariya 2017-2018 + Mladen Sablic 2017-2018 + Morgan Stewart 2015 + Nathan Van Gheem 2018 + Nick Hilliard 2009-2012 + Nico Golde 2010 + Nicolas Dichtel 2015 + Nigel Kukard 2017 + Nolan Leake 2012 + Oleg A. Arkhangelsky 2011 + Olivier Cochard-Labbé 2014 + Olivier Dugeon 2014-2018 + Ondrej Zajicek 2009 + Pascal Mathis 2018 + Paul Jakma 2002-2016 + Paul P Komkoff Jr 2008 + Pawel Wieczorkiewicz 2016 + Peter Pentchev 2011 + Peter Szilagyi 2011 + Phil Huang 2017 + Phil Laverdiere 2012 + Philippe Guibert 2016-2018 + Piotr Jurkiewicz 2018 + Pradosh Mohapatra 2013-2014 + Quentin Young 2016-2018 + Radhika Mahankali 2015-2017 + Rafael Zalamena 2017-2018 + Rakesh Garimella 2013 + Raymond P. Burkholder 2017 + Remi Gacogne 2013 + Renato Westphal 2012, 2016-2018 + Robert Bays 2010 + Roderick Schertler 2011 + Rodny Molina 2018 + Roman Hoog Antink 2010-2013 + Ruben Kerkhof 2018 + Russ White 2017-2018 + Ryan Hagelstrom 2017 + Sam Tannous 2016-2017 + Sarita Patra 2018 + Sebastian Lohff 2017 + Sergey Fionov 2018 + Sergey Y. Afonin 2011 + Serj Kalichev 2012 + Sid Khot 2016 + Silas McCroskey 2017-2018 + Stephane Litkowski 2017 + Stephen Hemminger 2008-2014 + Stephen Worley 2018 + Steve Hill 2009 + Stig Thormodsrud 2008 + Subbaiah Venkata 2012 + Svata Dedic 2011 + Sébastien Luttringer 2014 + Takashi Sogabe 2009 + Thijs Kinkhorst 2009 + Thomas Gelf 2018 + Thomas Petazzoni 2016 + Thomas Ries 2011 + Thorvald Natvig 2017 + Tigran Martirosyan 2018 + Timo Teräs 2008-2009, 2013-2017 + Timothy Redaelli 2017 + Tom Goff 2009-2011 + Tom Henderson 2009 + Tomasz Pala 2009 + Udaya Shankara KS 2016 + Ulrich Weber 2011-2013 + Vasilis Tsiligiannis 2009 + Vincent Bernat 2012, 2017-2018 + Vincent Jardin 2003-2007, 2014, 2017-2018 + Vipin Kumar 2014-2015 + Vishal Dhingra 2018 + Vishal Kumar 2012 + Vitaliy Senchyshyn 2013 + Vivek Venkatraman 2015-2018 + Vladimir L Ivanov 2010 + Vyacheslav Trushkin 2011-2012 + Vystoropskyi, Sergii 2015 + Wataru Tanitsu 2010 + Wenjian Ma 2015 + Will McLendon 2017 + YAMAMOTO Shigeru 2011 + Yasuhiro Ohara 2009 + Zefan Xu 2018 + dturlupov 2018 + heasley 2009-2011 + jaydom 2017 + jpmondet 2018 + kssoman 2018 + lihongguang 2018 + lyq140 2018 + pcarana 2018 + pogojotz 2017 + tigranmartirosyan 2017 + tmartiro 2017 + vize 2007 + 高鹏 2012 +License: GPL-2+ + +Files: lib/strl*.c +License: LGPL-2.1+ +Copyright: Copyright (C) 2016 Free Software Foundation, Inc. + +Files: lib/skiplist.* +License: BSD-0-clause +Copyright: Copyright 1990 William Pugh + +Files: lib/sha256.* +License: BSD-2-clause +Copyright: Copyright 2005,2007,2009 Colin Percival + +Files: lib/qobj.h lib/monotime.h lib/memory.* lib/hook.* lib/frratomic.h lib/ferr.* lib/compiler.h lib/module.* +License: ISC +Copyright: Copyright (c) 2015-18 David Lamparter, for NetDEF, Inc. + +Files: nhrpd/nhrp_protocol.h +License: MIT +Copyright: Copyright (c) 2007-2012 Timo Teräs <timo.teras@iki.fi> + +Files: babeld/* +License: MIT +Copyright: + Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + Copyright 2007, 2008 by Grégoire Henry, Julien Cristau and Juliusz Chroboczek + +Files: babeld/babel_errors.* babeld/babel_memory.* +License: GPL-2+ +Copyright: Copyright (C) 2017-2018 Donald Sharp, Cumulus Networks, Inc. + +Files: ldpd/* +License: ISC +Copyright: + Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + Copyright (c) 2003, 2004 Markus Friedl <markus@openbsd.org> + Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> + Copyright (c) 2004, 2005, 2012 Claudio Jeker <claudio@openbsd.org> + Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> + Copyright (c) 2012 Alexander Bluhm <bluhm@openbsd.org> + Copyright (c) 2013-2016 Renato Westphal <renato@openbsd.org> + Copyright (C) 2016 by Open Source Routing. + +Files: ldpd/ldp_debug.* ldpd/ldp_vty* ldpd/ldp_zebra.c +License: GPL-2+ +Copyright: + Copyright (C) 2016 by Open Source Routing. + +Files: doc/user/*.rst doc/figures/fig* +Copyright: Copyright (c) 1996-2018 Kunihiro Ishiguro, et al. +License: FRR-docs + Permission is granted to make and distribute verbatim copies of this + manual provided the copyright notice and this permission notice are + preserved on all copies. + . + Permission is granted to copy and distribute modified versions of this + manual under the conditions for verbatim copying, provided that the + entire resulting derived work is distributed under the terms of a + permission notice identical to this one. + . + Permission is granted to copy and distribute translations of this manual + into another language, under the above conditions for modified versions, + except that this permission notice may be stated in a translation + approved by Kunihiro Ishiguro. + +Files: lib/freebsd-queue.h lib/openbsd-queue.h lib/md5.* +License: BSD-3-clause +Copyright: + Copyright (c) 1991, 1993 The Regents of the University of California. + Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + Copyright (C) 2004 6WIND <Vincent.Jardin@6WIND.com> + +Files: lib/openbsd-tree.* +License: BSD-2-clause +Copyright: + Copyright 2002 Niels Provos <provos@citi.umich.edu> + Copyright (c) 2016 David Gwynne <dlg@openbsd.org> + +Files: lib/imsg* +License: ISC +Copyright: + Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> + Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org> + +Files: isisd/dict.* +Copyright: Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net> +License: custom-BSD-like + All rights are reserved by the author, with the following exceptions: + Permission is granted to freely reproduce and distribute this software, + possibly in exchange for a fee, provided that this copyright notice appears + intact. Permission is also granted to adapt this software to produce + derivative works, as long as the modified versions carry this copyright + notice and additional notices stating that the work has been modified. + This source code may be translated into executable form and incorporated + into proprietary software; there is no requirement for such software to + contain a copyright notice related to this source. + +Files: qpb/qpb.proto fpm/fpm.proto +License: ISC +Copyright: Copyright (C) 2016 Sproute Networks, Inc. + +Files: doc/extra/frrlexer.py +License: ISC +Copyright: Copyright (c) 2017 Vincent Bernat <bernat@luffy.cx> + +Files: tests/helpers/python/frrsix.py +License: MIT +Copyright: Copyright (c) 2010-2017 Benjamin Peterson + +License: GPL-2+ + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + . + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the full text of the GNU General Public + License version 2 can be found in the file + `/usr/share/common-licenses/GPL-2'. + +License: LGPL-2.1+ + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + . + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. + . + On Debian systems, the full text of the GNU Lesser General Public + License version 2.1 can be found in the file + `/usr/share/common-licenses/LGPL-2.1'. + +License: BSD-0-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted. + . + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +License: BSD-2-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +License: BSD-3-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +License: ISC + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + . + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +License: MIT + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/debian/frr-doc.doc-base b/debian/frr-doc.doc-base new file mode 100644 index 000000000..ec7870d7a --- /dev/null +++ b/debian/frr-doc.doc-base @@ -0,0 +1,23 @@ +Document: frr +Title: FRRouting user manual +Abstract: General user/operator description for the FRRouting suite of + routing protocol daemons. +Section: Network/Communication + +Format: HTML +Index: /usr/share/doc/frr/html/index.html +Files: /usr/share/doc/frr/html/* + +Format: info +Index: /usr/share/info/frr.info.gz +Files: + /usr/share/info/frr.info.gz + /usr/share/info/fig-normal-processing.png + /usr/share/info/fig-rs-processing.png + /usr/share/info/fig-vnc-commercial-route-reflector.png + /usr/share/info/fig-vnc-frr-route-reflector.png + /usr/share/info/fig-vnc-gw.png + /usr/share/info/fig-vnc-mesh.png + /usr/share/info/fig-vnc-redundant-route-reflectors.png + /usr/share/info/fig_topologies_full.png + /usr/share/info/fig_topologies_rs.png diff --git a/debianpkg/frr-doc.info b/debian/frr-doc.info index a83255a24..a83255a24 100644 --- a/debianpkg/frr-doc.info +++ b/debian/frr-doc.info diff --git a/debian/frr-doc.install b/debian/frr-doc.install new file mode 100644 index 000000000..c48dc5a8d --- /dev/null +++ b/debian/frr-doc.install @@ -0,0 +1,10 @@ +# html docs include RST sources +usr/share/doc/frr/html + +# info + images referenced by it +usr/share/info/ +doc/user/_build/texinfo/*.png usr/share/info + +# other +README.md usr/share/doc/frr +doc/figures/*.png usr/share/doc/frr diff --git a/debian/frr-doc.lintian-overrides b/debian/frr-doc.lintian-overrides new file mode 100644 index 000000000..d4ada822a --- /dev/null +++ b/debian/frr-doc.lintian-overrides @@ -0,0 +1,2 @@ +# personal name +spelling-error-in-copyright Ang And diff --git a/debian/frr-pythontools.install b/debian/frr-pythontools.install new file mode 100644 index 000000000..28140382f --- /dev/null +++ b/debian/frr-pythontools.install @@ -0,0 +1 @@ +usr/lib/frr/frr-reload.py diff --git a/debian/frr-pythontools.lintian-overrides b/debian/frr-pythontools.lintian-overrides new file mode 100644 index 000000000..d4ada822a --- /dev/null +++ b/debian/frr-pythontools.lintian-overrides @@ -0,0 +1,2 @@ +# personal name +spelling-error-in-copyright Ang And diff --git a/debian/frr-rpki-rtrlib.install b/debian/frr-rpki-rtrlib.install new file mode 100644 index 000000000..0465c0d91 --- /dev/null +++ b/debian/frr-rpki-rtrlib.install @@ -0,0 +1 @@ +usr/lib/*/frr/modules/bgpd_rpki.so diff --git a/debian/frr-rpki-rtrlib.lintian-overrides b/debian/frr-rpki-rtrlib.lintian-overrides new file mode 100644 index 000000000..392773176 --- /dev/null +++ b/debian/frr-rpki-rtrlib.lintian-overrides @@ -0,0 +1,5 @@ +# module contains no function calls that can be hardened +frr-rpki-rtrlib binary: hardening-no-fortify-functions * + +# personal name +spelling-error-in-copyright Ang And diff --git a/debian/frr-snmp.install b/debian/frr-snmp.install new file mode 100644 index 000000000..5517ca7ee --- /dev/null +++ b/debian/frr-snmp.install @@ -0,0 +1,2 @@ +usr/lib/*/frr/libfrrsnmp.* +usr/lib/*/frr/modules/*_snmp.so diff --git a/debian/frr-snmp.lintian-overrides b/debian/frr-snmp.lintian-overrides new file mode 100644 index 000000000..d4ada822a --- /dev/null +++ b/debian/frr-snmp.lintian-overrides @@ -0,0 +1,2 @@ +# personal name +spelling-error-in-copyright Ang And diff --git a/debianpkg/frr.conf b/debian/frr.conf index dee3cd849..dee3cd849 100644 --- a/debianpkg/frr.conf +++ b/debian/frr.conf diff --git a/debianpkg/frr.dirs b/debian/frr.dirs index 4b05c8c90..4b05c8c90 100644 --- a/debianpkg/frr.dirs +++ b/debian/frr.dirs diff --git a/debianpkg/frr.docs b/debian/frr.docs index f72aae196..34dbbd7bc 100644 --- a/debianpkg/frr.docs +++ b/debian/frr.docs @@ -1,2 +1,2 @@ -tools +tools/zebra.el debian/README.Debian diff --git a/debian/frr.install b/debian/frr.install new file mode 100644 index 000000000..ebb87a0b3 --- /dev/null +++ b/debian/frr.install @@ -0,0 +1,16 @@ +etc/ +usr/bin/vtysh +usr/bin/mtracebis +usr/lib/*/frr/libfrr.* +usr/lib/*/frr/libfrrospfapiclient.* +usr/lib/frr/*.sh +usr/lib/frr/*d +usr/lib/frr/watchfrr +usr/lib/frr/zebra +usr/lib/*/frr/modules/zebra_irdp.so +usr/lib/*/frr/modules/zebra_fpm.so +usr/share/doc/frr/examples +usr/share/man/ +usr/share/yang/ +tools/frr-reload usr/lib/frr/ +debian/frr.conf usr/lib/tmpfiles.d diff --git a/debian/frr.lintian-overrides b/debian/frr.lintian-overrides new file mode 100644 index 000000000..a3e6fcdc2 --- /dev/null +++ b/debian/frr.lintian-overrides @@ -0,0 +1,10 @@ +# function names & co. +frr binary: spelling-error-in-binary usr/lib/*/frr/libfrr.so.0.0.0 writen written +frr binary: spelling-error-in-binary usr/lib/*/frr/libfrrospfapiclient.so.0.0.0 writen written +frr binary: spelling-error-in-binary usr/lib/frr/ospfd writen written +frr binary: spelling-error-in-binary usr/lib/frr/zebra writen written +frr binary: spelling-error-in-binary usr/lib/frr/pimd writen written +frr binary: spelling-error-in-binary usr/lib/frr/pimd iif if + +# personal name +spelling-error-in-copyright Ang And diff --git a/debianpkg/frr.logrotate b/debian/frr.logrotate index 1dc9122ac..1dc9122ac 100644 --- a/debianpkg/frr.logrotate +++ b/debian/frr.logrotate diff --git a/debianpkg/frr.manpages b/debian/frr.manpages index f5aa97230..f5aa97230 100644 --- a/debianpkg/frr.manpages +++ b/debian/frr.manpages diff --git a/debianpkg/frr.pam b/debian/frr.pam index 2b106d43b..2b106d43b 100644 --- a/debianpkg/frr.pam +++ b/debian/frr.pam diff --git a/debian/frr.postinst b/debian/frr.postinst new file mode 100644 index 000000000..505ff8eaf --- /dev/null +++ b/debian/frr.postinst @@ -0,0 +1,96 @@ +#!/bin/sh +set -e + +# most of this file makes sense to execute regardless of whether this is any +# of normal "configure" or error-handling "abort-upgrade", "abort-remove" or +# "abort-deconfigure" + +addgroup --system frrvty +addgroup --system frr +adduser \ + --system \ + --ingroup frr \ + --home /nonexistent \ + --gecos "Frr routing suite" \ + --no-create-home \ + frr +usermod -a -G frrvty frr + +mkdir -p /var/log/frr +mkdir -p /etc/frr + + +# only change ownership of files when they were previously owned by root or +# quagga; this is to ensure we don't trample over some custom user setup. +# +# if we are on a freshly installed package (or we added new configfiles), +# the files should be owned by root by default so we should end up with "frr" +# owned configfiles. + +quaggauid=`id -u quagga 2>/dev/null || echo 0` +quaggagid=`id -g quagga 2>/dev/null || echo 0` + +find \ + /etc/frr \ + /var/log/frr \ + \( -uid 0 -o -uid $quaggauid \) -a \ + \( -gid 0 -o -gid $quaggauid \) | \ + while read filename; do + + # don't chown anything that has ACLs (but don't fail if we don't + # have getfacl) + if { getfacl -c "$filename" 2>/dev/null || true; } \ + | egrep -q -v '^((user|group|other)::|$)'; then + : + else + chown frr: "$filename" + chmod o-rwx "$filename" + fi +done + +# fix misconfigured vtysh.conf & frr.conf ownership caused by config save +# mishandling in earlier FRR (and Quagga) versions +find /etc/frr -maxdepth 1 \( -name vtysh.conf -o -name frr.conf \) \ + -group frrvty -exec chgrp frr {} \; + +# more Quagga -> FRR upgrade smoothing. Not technically needed, but let's +# at least do the straightforward pieces. + +check_old_config() { + oldcfg="$1" + [ -r "$oldcfg" ] || return 0 + [ -s "$oldcfg" ] || return 0 + grep -v '^[[:blank:]]*\(#\|$\)' "$oldcfg" > /dev/null || return 0 + + cat >&2 <<EOF +Note: deprecated $oldcfg is present. This file is still read by +the FRR service but its contents should be migrated to /etc/frr/daemons. +EOF +} + +rmsum() { + fname="$1" + test -f "$1" || return 0 + fhash="`sha1sum \"$fname\"`" + fhash="${fhash%% *}" + if test "$fhash" = "$2"; then + rm "$fname" + fi +} + +case "$1" in +configure) + check_old_config /etc/frr/daemons.conf + check_old_config /etc/default/frr + if test -f /etc/frr/.pkg.frr.nointegrated; then + # remove integrated config setup + # (if checksums match, the files match freshly installed + # defaults, but the user has split config in place) + rmsum /etc/frr/vtysh.conf 5e7e3a488c51751e1ff98f27c9ad6085e1ad9cbb + rmsum /etc/frr/frr.conf dac6f2af4fca9919ba40eb338885a5d1773195c8 + rm /etc/frr/.pkg.frr.nointegrated + fi + ;; +esac + +#DEBHELPER# diff --git a/debian/frr.postrm b/debian/frr.postrm new file mode 100644 index 000000000..018f59e1c --- /dev/null +++ b/debian/frr.postrm @@ -0,0 +1,14 @@ +#!/bin/sh +set -e + +rm -f /etc/frr/.pkg.frr.nointegrated + +if [ "$1" = "purge" ]; then + rm -rf /run/frr || true + + # "purge" does not remove logfiles. therefore we shouldn't delete + # the "frr" user/group since that would leave files with "dangling" + # ownership. +fi + +#DEBHELPER# diff --git a/debian/frr.preinst b/debian/frr.preinst new file mode 100644 index 000000000..0e10e3924 --- /dev/null +++ b/debian/frr.preinst @@ -0,0 +1,93 @@ +#!/bin/bash +set -e +# bash is required since /etc/frr/daemons.conf used a bash array in some +# previous versions. + +# NOTE: this code exists specifically to make migrations from Quagga to +# FRR easier. FRR is able to load most Quagga configurations, but the +# config handling itself has changed with the move towards the "integrated" +# /etc/frr/frr.conf approach instead of separate per-daemon config files. +# +# That said, with this in place there's a good chance users can use a +# preexisting Quagga config with little hassle. + +case "$1" in +install|upgrade) + ( + test -f /etc/frr/daemons && . /etc/frr/daemons + test -f /etc/frr/daemons.conf && . /etc/frr/daemons.conf + test -f /etc/default/frr && . /etc/default/frr + + if [ "$watchfrr_enable" = no -o \ + "$watchfrr_enable" = "0" ]; then + cat >&2 <<EOF +ERROR: Pre-existing frr configuration file disables watchfrr. + +This configuration is deprecated upstream and not supported by the Debian +FRR package. Refusing to $1 in order to not break running setups. +Please change your setup to use watchfrr and remove the "watchfrr_enable" +option from /etc/frr/daemons, /etc/frr/daemons.conf and/or /etc/default/frr. +EOF + exit 1 + fi + ) + vtysh='' + if test -f /etc/frr/vtysh.conf; then + if grep -q '^[[:space:]]*service[[:space:]]\+integrated-vtysh-config' /etc/frr/vtysh.conf; then + # existing vtysh.conf with integrated statement + # - do nothing (=> integrated config) + vtysh='i' + elif grep -q '^[[:space:]]*no[[:space:]]\+service[[:space:]]\+integrated-vtysh-config' /etc/frr/vtysh.conf; then + # explicit non-integrated + # => need to fix vtysh.conf & frr.conf in postinst + vtysh='ni' + if test -f /etc/frr/frr.conf; then + cat >&2 <<EOF +ERROR: Pre-existing /etc/frr/vtysh.conf specifies +"no service integrated-vtysh-config", but /etc/frr/frr.conf exists. This +will cause the frr package to malfunction. Please remove /etc/frr/frr.conf +or remove the "no service integrated-vtysh-config" statement from +/etc/frr/vtysh.conf. +EOF + exit 1 + fi + else + # vtysh.conf exists but has no statement + : + fi + fi + if test -f /etc/frr/frr.conf; then + # vtysh.conf has no explicit statement but frr.conf exists + # => integrated config used + vtysh='i' + elif test -f /etc/frr/zebra.conf \ + -o -f /etc/frr/bgpd.conf \ + -o -f /etc/frr/ospfd.conf \ + -o -f /etc/frr/ospf6d.conf \ + -o -f /etc/frr/ripd.conf \ + -o -f /etc/frr/ripngd.conf \ + -o -f /etc/frr/isisd.conf \ + -o -f /etc/frr/pimd.conf \ + -o -f /etc/frr/ldpd.conf \ + -o -f /etc/frr/nhrpd.conf \ + -o -f /etc/frr/eigrpd.conf \ + -o -f /etc/frr/babeld.conf \ + -o -f /etc/frr/pbrd.conf \ + -o -f /etc/frr/bfdd.conf; then + # no explicit statement, but some split config file exists + # => need to fix vtysh.conf & frr.conf in postinst + test -n "$vtysh" || vtysh='ni' + else + # no config at all - use integrated + : + fi + if test "$vtysh" = "ni"; then + touch /etc/frr/.pkg.frr.nointegrated + fi + ;; +abort-upgrade) + # shouldn't fail an upgrade abort + ;; +esac + +#DEBHELPER# diff --git a/debian/not-installed b/debian/not-installed new file mode 100644 index 000000000..1a89f3585 --- /dev/null +++ b/debian/not-installed @@ -0,0 +1,3 @@ +usr/include +usr/lib/frr/ospfclient +usr/lib/frr/rfptest diff --git a/debian/rules b/debian/rules new file mode 100755 index 000000000..a546f38d7 --- /dev/null +++ b/debian/rules @@ -0,0 +1,120 @@ +#!/usr/bin/make -f + +# standard Debian options & profiles + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +ifneq (,$(filter terse,$(DEB_BUILD_OPTIONS))) + MAKE_SILENT="V=0" + export DH_VERBOSE=0 +else + MAKE_SILENT="V=1" + export DH_VERBOSE=1 + export DH_OPTIONS=-v +endif + +# package-specific build profiles + +ifeq ($(filter pkg.frr.nortrlib,$(DEB_BUILD_PROFILES)),) + CONF_RPKI=--enable-rpki +else + CONF_RPKI=--disable-rpki +endif + +ifeq ($(filter pkg.frr.nosystemd,$(DEB_BUILD_PROFILES)),) + DH_WITH_SYSTEMD=systemd, + CONF_SYSTEMD=--enable-systemd=yes +else + DH_WITH_SYSTEMD= + CONF_SYSTEMD=--enable-systemd=no +endif + +export PYTHON=python3 + +%: + dh $@ --with=$(DH_WITH_SYSTEMD)autoreconf --parallel + +override_dh_auto_configure: + $(shell dpkg-buildflags --export=sh); \ + dh_auto_configure -- \ + --enable-exampledir=/usr/share/doc/frr/examples/ \ + --localstatedir=/var/run/frr \ + --sbindir=/usr/lib/frr \ + --sysconfdir=/etc/frr \ + --with-vtysh-pager=/usr/bin/pager \ + --libdir=/usr/lib/$(DEB_HOST_MULTIARCH)/frr \ + --with-moduledir=/usr/lib/$(DEB_HOST_MULTIARCH)/frr/modules \ + LIBTOOLFLAGS="-rpath /usr/lib/$(DEB_HOST_MULTIARCH)/frr" \ + --disable-dependency-tracking \ + \ + $(CONF_SYSTEMD) \ + $(CONF_RPKI) \ + --with-libpam \ + --enable-doc \ + --enable-doc-html \ + --enable-snmp \ + --enable-fpm \ + --disable-protobuf \ + --disable-zeromq \ + --enable-ospfapi \ + --enable-bgp-vnc \ + --enable-multipath=256 \ + \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --enable-configfile-mask=0640 \ + --enable-logfile-mask=0640 \ + # end + +override_dh_auto_install: + dh_auto_install + + sed -e '1c #!/usr/bin/python3' -i debian/tmp/usr/lib/frr/frr-reload.py + +# let dh_systemd_* and dh_installinit do their thing automatically +ifeq ($(filter pkg.frr.nosystemd,$(DEB_BUILD_PROFILES)),) + cp tools/frr.service debian/frr.service +endif + cp tools/frrinit.sh debian/frr.init + -rm -f debian/tmp/usr/lib/frr/frr + +# install config files + mkdir -p debian/tmp/etc + cp -r tools/etc/* debian/tmp/etc/ + -rm debian/tmp/etc/frr/daemons.conf + + sed -e 's#^!log file #!log file /var/log/frr/#' -i debian/tmp/usr/share/doc/frr/examples/*sample* + +# drop dev-only files + find debian/tmp -name '*.la' -o -name '*.a' -o -name 'lib*.so' | xargs rm -f + rm -rf debian/tmp/usr/include + -rm debian/tmp/usr/lib/frr/ssd + +# use installed js libraries + -rm -f debian/tmp/usr/share/doc/frr/html/_static/jquery.js + ln -s /usr/share/javascript/jquery/jquery.js debian/tmp/usr/share/doc/frr/html/_static/jquery.js + -rm -f debian/tmp/usr/share/doc/frr/html/_static/underscore.js + ln -s /usr/share/javascript/underscore/underscore.js debian/tmp/usr/share/doc/frr/html/_static/underscore.js + +override_dh_auto_build: + dh_auto_build -- $(MAKE_SILENT) + +override_dh_installinit: + dh_installinit -r + +override_dh_installsystemd: + dh_installsystemd -r + +override_dh_makeshlibs: + dh_makeshlibs -n + +override_dh_missing: + dh_missing --fail-missing + +override_dh_auto_clean: +# we generally do NOT want a full distclean since that wipes both +# debian/changelog and config.version + if test -f Makefile; then make redistclean; fi + -rm -f debian/frr.init + -rm -f debian/frr.service diff --git a/debianpkg/source/format b/debian/source/format index af745b310..af745b310 100644 --- a/debianpkg/source/format +++ b/debian/source/format diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides new file mode 100644 index 000000000..112182c77 --- /dev/null +++ b/debian/source/lintian-overrides @@ -0,0 +1,2 @@ +# Debian Jessie and Ubuntu 16.04 need dh-systemd +frr source: ored-build-depends-on-obsolete-package diff --git a/debian/tests/bgpd-snmp-rpki b/debian/tests/bgpd-snmp-rpki new file mode 100755 index 000000000..930b8c26d --- /dev/null +++ b/debian/tests/bgpd-snmp-rpki @@ -0,0 +1,22 @@ +#!/bin/sh +set -e + +# enable bgpd with SNMP & RPKI modules +cat >> /etc/frr/daemons <<EOF +bgpd=yes +bgpd_options="-A 127.0.0.1 -Msnmp -Mrpki" +EOF + +service frr restart + +# check that it actually started +pgrep watchfrr +pgrep zebra +pgrep bgpd + +# just for debugging +vtysh -c 'show modules' + +# ... and SNMP & RPKI should be loaded +vtysh -c 'show modules' | grep -q snmp +vtysh -c 'show modules' | grep -q rpki diff --git a/debian/tests/control b/debian/tests/control new file mode 100644 index 000000000..5990a6937 --- /dev/null +++ b/debian/tests/control @@ -0,0 +1,11 @@ +Tests: zebra-lo +Depends: frr +Restrictions: needs-root, isolation-container + +Tests: bgpd-snmp-rpki +Depends: frr, frr-snmp, frr-rpki-rtrlib +Restrictions: needs-root, isolation-container + +Tests: py-frr-reload +Depends: frr, frr-pythontools +Restrictions: needs-root, isolation-container diff --git a/debian/tests/py-frr-reload b/debian/tests/py-frr-reload new file mode 100755 index 000000000..e2c97e874 --- /dev/null +++ b/debian/tests/py-frr-reload @@ -0,0 +1,28 @@ +#!/bin/sh +set -e + +# should have been started on install, but policy may have inhibited that +service frr restart + +# these should be running by default +pgrep watchfrr +pgrep zebra +pgrep staticd + +# configure interactively, save to file +vtysh -c 'configure terminal' -c 'ip route 198.51.100.0/28 127.0.0.1' +vtysh -c 'show running-config' | grep -q 'ip route 198.51.100.0/28 127.0.0.1' +vtysh -c 'write memory' + +grep -q 'ip route 198.51.100.0/28 127.0.0.1' /etc/frr/frr.conf + +# configure in file, check interactively +sed -e '/^ip route 198.51.100.0\/28 127.0.0.1/ c ip route 198.51.100.64/28 127.0.0.1' \ + -i /etc/frr/frr.conf + +service frr reload + +vtysh -c 'show running-config' | grep -q 'ip route 198.51.100.64/28 127.0.0.1' +if vtysh -c 'show running-config' | grep -q 'ip route 198.51.100.0/28 127.0.0.1'; then + exit 1 +fi diff --git a/debian/tests/zebra-lo b/debian/tests/zebra-lo new file mode 100755 index 000000000..2a388d5da --- /dev/null +++ b/debian/tests/zebra-lo @@ -0,0 +1,16 @@ +#!/bin/sh +set -e + +# should have been started on install, but policy may have inhibited that +service frr status >/dev/null || service frr restart + +# these should be running by default +pgrep watchfrr +pgrep zebra +pgrep staticd + +# check vtysh works at all +vtysh -c 'show version' + +# check zebra is properly talking to the kernel +vtysh -c 'show interface lo' | grep -q LOOPBACK diff --git a/debian/watch b/debian/watch new file mode 100644 index 000000000..c286392d7 --- /dev/null +++ b/debian/watch @@ -0,0 +1,4 @@ +version=4 + +https://github.com/FRRouting/frr/releases/ \ + download/frr-(?:\d[\d.]*)/frr-(\d[\d.]*)\.tar\.xz debian uupdate diff --git a/debianpkg/watchfrr.rc b/debian/watchfrr.rc index 4110b8639..4110b8639 100644 --- a/debianpkg/watchfrr.rc +++ b/debian/watchfrr.rc diff --git a/debianpkg/.gitignore b/debianpkg/.gitignore deleted file mode 100644 index 6d10dce74..000000000 --- a/debianpkg/.gitignore +++ /dev/null @@ -1 +0,0 @@ -changelog diff --git a/debianpkg/backports/.gitignore b/debianpkg/backports/.gitignore deleted file mode 100644 index 3b20d2689..000000000 --- a/debianpkg/backports/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*/*.dirhash -*/debian/changelog diff --git a/debianpkg/backports/README b/debianpkg/backports/README deleted file mode 100644 index efd322e1d..000000000 --- a/debianpkg/backports/README +++ /dev/null @@ -1,28 +0,0 @@ -This directory contains the debian directories for backports to other debian -platforms. These are built via the `3.0 (custom)' source format, which -allows one to build a source package directly out of tarballs (e.g. an -orig.tar.gz tarball and a debian.tar.gz file), at which point the format can -be changed to a real format (e.g. `3.0 (quilt)'). - -Source packages are assembled via targets of the same name as the system to -which the backport is done (e.g. `precise'), included in debian/rules. - -To create a new debian backport: - -* Add its name to `KNOWN_BACKPORTS', defined in debian/rules. -* Create a directory of the same name in debian/backports. -* Add the files `exclude', `versionext', and `debian/source/format' under - this directory: - * `exclude' contains whitespace-separated paths (relative to the root of - the source dir) that should be excluded from the source package (e.g. - debian/patches). - * `versionext' contains the suffix added to the version number for this - backport's build. Distributions often have guidelines for what this - should be. If left empty, no new debian/changelog entry is created. - * `debian/source/format' should contain the source format of the resulting - source package. As of of the writing of this document the only supported - format is `3.0 (quilt)'. -* Add appropriate files under the `debian/' subdirectory. These will be - included in the source package, overriding any top-level `debian/' files - with equivalent paths. - diff --git a/debianpkg/backports/debian8/debian/source/format b/debianpkg/backports/debian8/debian/source/format deleted file mode 100644 index 163aaf8d8..000000000 --- a/debianpkg/backports/debian8/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debianpkg/backports/debian8/exclude b/debianpkg/backports/debian8/exclude deleted file mode 100644 index e69de29bb..000000000 --- a/debianpkg/backports/debian8/exclude +++ /dev/null diff --git a/debianpkg/backports/debian8/versionext b/debianpkg/backports/debian8/versionext deleted file mode 100644 index 4824521f8..000000000 --- a/debianpkg/backports/debian8/versionext +++ /dev/null @@ -1 +0,0 @@ --1~debian8+1 diff --git a/debianpkg/backports/debian9/debian/source/format b/debianpkg/backports/debian9/debian/source/format deleted file mode 100644 index 163aaf8d8..000000000 --- a/debianpkg/backports/debian9/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debianpkg/backports/debian9/exclude b/debianpkg/backports/debian9/exclude deleted file mode 100644 index e69de29bb..000000000 --- a/debianpkg/backports/debian9/exclude +++ /dev/null diff --git a/debianpkg/backports/debian9/versionext b/debianpkg/backports/debian9/versionext deleted file mode 100644 index db8593211..000000000 --- a/debianpkg/backports/debian9/versionext +++ /dev/null @@ -1 +0,0 @@ --1~debian9+1 diff --git a/debianpkg/backports/rules b/debianpkg/backports/rules deleted file mode 100755 index d0c6dcc06..000000000 --- a/debianpkg/backports/rules +++ /dev/null @@ -1,137 +0,0 @@ -.PHONY: backports $(KNOWN_BACKPORTS) - -# error out if these files are missing -required_files = $(foreach backport,$(KNOWN_BACKPORTS), \ - $(addprefix debian/backports/$(backport)/, \ - debian/source/format \ - versionext \ - exclude)) -$(if $(filter-out $(wildcard $(required_files)),$(required_files)), \ - $(error missing required backports files: \ - $(filter-out $(wildcard $(required_files)),$(required_files)). \ - see debian/backports/README) \ -) - -TARBALLDIR ?= $(shell dh_testdir debian/changelog && realpath .) - -define backports-targets -# if this file is empty, no automatic changelog entry is created -VERSIONEXT_$(1) ?= $(strip \ - $(shell cat $(wildcard debian/backports/$(1)/versionext))) -DEBIAN_VERSION_$(1) = $(DEBIAN_VERSION)$$(VERSIONEXT_$(1)) -BACKPORTDIR_$(1) = $(realpath debian/backports/$(1)) - -# as of right now, must be '3.0 (quilt)' -SOURCEFORMAT_$(1) ?= $(strip \ - $(shell cat debian/backports/$(1)/debian/source/format)) - -# files checked for the dirhash (see below) -FINDCMD_$(1) = find -L debian/backports/$(1)/debian \ - -type f \ - ! -path debian/backports/$(1)/debian/changelog - -# files *not* pulled from the root debian directory into the backport tarball: -# debian/changelog (copied and edited for backport version entry) -# debian/backports itself (relevant contents are copied out separately) -# anything provided in the current backports debian dir -# anything specified in the 'exclude' file in the current backports debian dir -EXCLUDEROOT_$(1) = debian/changelog debian/backports \ - $$(subst debian/backports/$(1)/,,$$(shell $$(FINDCMD_$(1)))) \ - $$(shell cat debian/backports/$(1)/exclude) - -EXCLUDEROOT_TAR_$(1) = $$(foreach file,$$(EXCLUDEROOT_$(1)),--exclude $$(file)) -EXCLUDEROOT_FIND_$(1) = $$(foreach file,$$(EXCLUDEROOT_$(1)),-o -path $$(file)) - -# find command resulting in all files that *will* be pulled into the backport -# tarball. -FINDCMDROOT_$(1) = find -L debian/ \ - '(' -false $$(EXCLUDEROOT_FIND_$(1)) ')' -prune -o \ - -type f -a '!' '(' -false $$(EXCLUDEROOT_FIND_$(1)) ')' - -# usually using `find' output for dependencies has the downfall of not tracking -# file removal. Work around that by introducing a dependency on a file whose -# name contains the hash of `find' output, so that the name will change when a -# file is deleted. -DIRHASH_$(1) = \ - $$(shell $$(FINDCMD_$(1)) | sha1sum | sed -r 's/^(......).*/\1/') -DIRHASHROOT_$(1) = \ - $$(shell $$(FINDCMDROOT_$(1)) | sha1sum | sed -r 's/^(......).*/\1/') - -CONTROL_$(1) = $$(strip \ - $$(if $$(wildcard $$(BACKPORTDIR_$(1))/debian/control), \ - $$(BACKPORTDIR_$(1))/debian/control, \ - $(realpath debian/control) \ - )) - -# TARGETS: - -$(1): $(TARBALLDIR)/$(SRCPKG)_$$(DEBIAN_VERSION_$(1)).dsc ; - -# we use 3.0 (custom) to build a source package directly from tarballs, -# bypassing the usual checks (which wouldn't like our combination-of- -# directories approach) -$(TARBALLDIR)/$(SRCPKG)_$$(DEBIAN_VERSION_$(1)).dsc: - dpkg-source -l$$(BACKPORTDIR_$(1))/debian/changelog \ - -c$$(CONTROL_$(1)) \ - --format='3.0 (custom)' \ - --target-format='$$(SOURCEFORMAT_$(1))' \ - -b . $$^ - mv $(TARBALLDIR)/../$$(notdir $$@) $$@ - -ifeq ($$(SOURCEFORMAT_$(1)),3.0 (quilt)) -# this target depends on the orig.tar.gz file, for which there is no target in -# this makefile. It is assumed to either already exist or be built by a target -# provided elsewhere in debian/rules (e.g. via pristine-tar) -$$(if $$(findstring $(ORIG_VERSION),$$(DEBIAN_VERSION_$(1))), \ - $$(info downstream version matches upstream version (good)), \ - $$(error quilt format expects downstream version \ - ($$(DEBIAN_VERSION_$(1))) to contain upstream version \ - ($(ORIG_VERSION)). Make a new debian/changelog entry \ - to reflect the new upstream release) \ -) - -$(TARBALLDIR)/$(SRCPKG)_$$(DEBIAN_VERSION_$(1)).dsc: \ - $(TARBALLDIR)/$(SRCPKG)_$(ORIG_VERSION).orig.tar.gz \ - $(TARBALLDIR)/$(SRCPKG)_$$(DEBIAN_VERSION_$(1)).debian.tar.xz -else -$$(error unsupported source format for $(1) backport: $$(SOURCEFORMAT_$(1))) -endif #SOURCEFORMAT_$(1) - -# for 3.0 (quilt) -$(TARBALLDIR)/$(SRCPKG)_$$(DEBIAN_VERSION_$(1)).debian.tar.xz: \ - $$(BACKPORTDIR_$(1))/debian/changelog \ - $$(shell $$(FINDCMD_$(1))) \ - $$(BACKPORTDIR_$(1))/$$(DIRHASH_$(1)).backport.dirhash \ - $$(shell $$(FINDCMDROOT_$(1))) \ - $$(BACKPORTDIR_$(1))/$$(DIRHASHROOT_$(1)).root.dirhash \ - $$(BACKPORTDIR_$(1))/exclude - rm -f $$(subst .tar.xz,.tar,$$@) $$@ - tar -chf $$(subst .tar.xz,.tar,$$@) \ - --exclude-vcs $$(EXCLUDEROOT_TAR_$(1)) debian/ - cd debian/backports/$(1) && tar -uhf $$(subst .tar.xz,.tar,$$@) \ - --exclude-vcs debian/ - xz $$(subst .tar.xz,.tar,$$@) - -$$(BACKPORTDIR_$(1))/debian/changelog: \ - debian/changelog \ - debian/backports/$(1)/versionext - rm -f debian/backports/$(1)/debian/changelog - cp $$< $$@ - $(if $$(VERSIONEXT_$(1)), \ - dch -c $$@ -v '$$(DEBIAN_VERSION_$(1))' -b \ - 'backport to $(1) systems', \ - ) - -$$(BACKPORTDIR_$(1))/$$(DIRHASH_$(1)).backport.dirhash: - rm -f debian/backports/$(1)/*.backport.dirhash - touch $$@ - -$$(BACKPORTDIR_$(1))/$$(DIRHASHROOT_$(1)).root.dirhash: - rm -f debian/backports/$(1)/*.root.dirhash - touch $$@ - -endef # backports-targets -$(foreach backport,$(KNOWN_BACKPORTS),$(eval \ - $(call backports-targets,$(backport)))) - -backports: $(KNOWN_BACKPORTS) diff --git a/debianpkg/backports/ubuntu14.04/debian/control b/debianpkg/backports/ubuntu14.04/debian/control deleted file mode 100644 index 3f31f1846..000000000 --- a/debianpkg/backports/ubuntu14.04/debian/control +++ /dev/null @@ -1,56 +0,0 @@ -Source: frr -Section: net -Priority: optional -Maintainer: Nobody <nobody@frrouting.org> -Uploaders: Nobody <nobody@frrouting.org> -XSBC-Original-Maintainer: <maintainers@frrouting.org> -Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), imagemagick, ghostscript, groff, autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2, pkg-config, python (>= 2.7), python-ipaddr -Standards-Version: 3.9.6 -Homepage: http://www.frrouting.org/ -XS-Testsuite: autopkgtest - -Package: frr -Architecture: any -Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), ${misc:Depends} -Pre-Depends: adduser -Conflicts: zebra, zebra-pj, quagga -Replaces: zebra, zebra-pj -Suggests: snmpd -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon forked from Quagga - FRR is free software which manages TCP/IP based routing protocols. - It supports BGP4, BGP4+, OSPFv2, OSPFv3, IS-IS, RIPv1, RIPv2, RIPng, - PIM and LDP as well as the IPv6 versions of these. - . - FRR is a fork of Quagga with an open community model. The main git - lives on https://github.com/frrouting/frr.git - -Package: frr-dbg -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, frr (= ${binary:Version}) -Priority: extra -Section: debug -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (debug symbols) - This package provides debugging symbols for all binary packages built - from frr source package. It's highly recommended to have this package - installed before reporting any FRR crashes to either FRR developers or - Debian package maintainers. - -Package: frr-doc -Section: net -Architecture: all -Depends: ${misc:Depends} -Suggests: frr -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (documentation) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. - -Package: frr-pythontools -Section: net -Architecture: all -Depends: ${misc:Depends}, frr (= ${binary:Version}), python (>= 2.7), python-ipaddr -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (Python Tools) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. - diff --git a/debianpkg/backports/ubuntu14.04/debian/frr.install b/debianpkg/backports/ubuntu14.04/debian/frr.install deleted file mode 100644 index 7fb81c44a..000000000 --- a/debianpkg/backports/ubuntu14.04/debian/frr.install +++ /dev/null @@ -1,11 +0,0 @@ -etc/frr/ -usr/bin/vtysh -usr/bin/mtracebis -usr/include/frr/ -usr/lib/ -usr/share/doc/frr/ -usr/share/snmp/mibs/ -usr/share/yang/ -tools/etc/* etc/ -tools/*.service lib/systemd/system -debian/frr.conf usr/lib/tmpfiles.d diff --git a/debianpkg/backports/ubuntu14.04/debian/rules b/debianpkg/backports/ubuntu14.04/debian/rules deleted file mode 100755 index 21b442d85..000000000 --- a/debianpkg/backports/ubuntu14.04/debian/rules +++ /dev/null @@ -1,206 +0,0 @@ -#!/usr/bin/make -f - -# FRRouting Configuration options -###################################### -# -# WANT_xxxx --> Set to 1 for enable, 0 for disable -# The following are the defaults. They can be overridden by setting a -# env variable to a different value - -WANT_LDP ?= 1 -WANT_PIM ?= 1 -WANT_OSPFAPI ?= 1 -WANT_BGP_VNC ?= 1 -WANT_CUMULUS_MODE ?= 0 -WANT_MULTIPATH ?= 1 -WANT_SNMP ?= 0 -WANT_RPKI ?= 0 -WANT_BFD ?= 1 - -# NOTES: -# -# If you use WANT_RPKI, then there is a new dependency for librtr0 package -# and a build dependency of the librtr-dev package. -# While the librtr0 is added to the depenencies automatically, the build -# dependency can't be changed dynamically and building will fail if the -# librtr-dev isn't installed during package build -# Tested versions of both packages can be found at -# https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact -# -# If multipath is enabled (WANT_MULTIPATH=1), then set number of multipaths here -# Please be aware that 0 is NOT disabled, but treated as unlimited - -MULTIPATH ?= 256 - -# Set the following to the value required (or leave alone for the default below) -# WANT_FRR_USER is used for the username and groupname of the FRR user account - -WANT_FRR_USER ?= frr -WANT_FRR_VTY_GROUP ?= frrvty - -# Don't build PDF docs by default -GENERATE_PDF ?= 0 - -# -#################################### - -export DH_VERBOSE=1 -export DEB_BUILD_MAINT_OPTIONS = hardening=+all -export DH_OPTIONS=-v - -ifeq ($(WANT_SNMP), 1) - USE_SNMP=--enable-snmp - $(warning "DEBIAN: SNMP enabled, sorry for your inconvenience") -else - USE_SNMP=--disable-snmp - $(warning "DEBIAN: SNMP disabled, see README.Debian") -endif - -ifeq ($(WANT_LDP), 1) - USE_LDP=--enable-ldpd -else - USE_LDP=--disable-ldpd -endif - -ifeq ($(WANT_PIM), 1) - USE_PIM=--enable-pimd -else - USE_PIM=--disable-pimd -endif - -ifeq ($(WANT_OSPFAPI), 1) - USE_OSPFAPI=--enable-ospfapi=yes -else - USE_OSPFAPI=--enable-ospfapi=no -endif - -ifeq ($(WANT_BGP_VNC), 1) - USE_BGP_VNC=--enable-bgp-vnc=yes -else - USE_BGP_VNC=--enable-bgp-vnc=no -endif - -USE_FRR_USER=--enable-user=$(WANT_FRR_USER) -USE_FRR_GROUP=--enable-group=$(WANT_FRR_USER) -USE_FRR_VTY_GROUP=--enable-vty-group=$(WANT_FRR_VTY_GROUP) - -ifeq ($(WANT_MULTIPATH), 1) - USE_MULTIPATH=--enable-multipath=$(MULTIPATH) -else - USE_MULTIPATH=--disable-multipath -endif - -ifeq ($(WANT_CUMULUS_MODE), 1) - USE_CUMULUS=--enable-cumulus=yes -else - USE_CUMULUS=--enable-cumulus=no -endif - -ifeq ($(WANT_RPKI), 1) - USE_RPKI=--enable-rpki -else - USE_RPKI=--disable-rpki -endif - -ifeq ($(WANT_BFD), 1) - USE_BFD=--enable-bfdd -else - USE_BFD=--disable-bfdd -endif - -ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) - DEBIAN_JOBS := $(subst parallel=,,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) -endif - -ifdef DEBIAN_JOBS -MAKEFLAGS += -j$(DEBIAN_JOBS) -endif - -%: - dh $@ --with=autoreconf --parallel --dbg-package=frr-dbg --list-missing - -override_dh_gencontrol: -ifeq ($(WANT_RPKI), 1) - dh_gencontrol -- -Vdist:Depends="librtr0 (>= 0.5)" -else - dh_gencontrol -endif - -override_dh_auto_configure: - # Frr needs /proc to check some BSD vs Linux specific stuff. - # Else it fails with an obscure error message pointing out that - # IPCTL_FORWARDING is an undefined symbol which is not very helpful. - @if ! [ -d /proc/1 ]; then \ - echo "./configure needs a mounted /proc"; \ - exit 1; \ - fi - - if ! [ -e config.status ]; then \ - dh_auto_configure -- \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - $(USE_SNMP) \ - $(USE_OSPFAPI) \ - $(USE_MULTIPATH) \ - $(USE_LDP) \ - --enable-fpm \ - $(USE_FRR_USER) $(USE_FRR_GROUP) \ - $(USE_FRR_VTY_GROUP) \ - --enable-configfile-mask=0640 \ - --enable-logfile-mask=0640 \ - --with-libpam \ - --enable-systemd=no \ - --enable-poll=yes \ - $(USE_CUMULUS) \ - $(USE_PIM) \ - --enable-dependency-tracking \ - $(USE_BGP_VNC) \ - $(USE_RPKI) \ - $(USE_BFD) \ - $(shell dpkg-buildflags --export=configure); \ - fi - -override_dh_auto_build: - #dh_auto_build - $(MAKE) - - # doc/ is a bit crazy -ifeq ($(GENERATE_PDF), 1) - dh_auto_build -- -C doc pdf -endif - rm -vf doc/_build/texinfo/frr.info - dh_auto_build -- -C doc info - -override_dh_auto_test: - -override_dh_auto_install: - dh_auto_install - - cp tools/frrinit.sh debian/frr.init - - # installed in frr-pythontools - rm debian/tmp/usr/lib/frr/frr-reload.py - - # cleaning up the info dir - rm -f debian/tmp/usr/share/info/dir* - - # install config files - mkdir -p debian/tmp/etc/frr/ - perl -pi -e 's#^!log file #!log file /var/log/frr/#' debian/tmp/usr/share/doc/frr/examples/*sample* - - # leftover from previously shipping SMUX client OID MIB - mkdir -p debian/tmp/usr/share/snmp/mibs/ - - # cleaning .la files - sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/*.la - sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/frr/modules/*.la - sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/frr/libyang_plugins/*.la - -override_dh_systemd_start: - dh_systemd_start frr.service - -override_dh_systemd_enable: - dh_systemd_enable frr.service - diff --git a/debianpkg/backports/ubuntu14.04/debian/source/format b/debianpkg/backports/ubuntu14.04/debian/source/format deleted file mode 100644 index 163aaf8d8..000000000 --- a/debianpkg/backports/ubuntu14.04/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debianpkg/backports/ubuntu14.04/exclude b/debianpkg/backports/ubuntu14.04/exclude deleted file mode 100644 index e69de29bb..000000000 --- a/debianpkg/backports/ubuntu14.04/exclude +++ /dev/null diff --git a/debianpkg/backports/ubuntu14.04/versionext b/debianpkg/backports/ubuntu14.04/versionext deleted file mode 100644 index c5be0650a..000000000 --- a/debianpkg/backports/ubuntu14.04/versionext +++ /dev/null @@ -1 +0,0 @@ --1~ubuntu14.04+1 diff --git a/debianpkg/backports/ubuntu16.04/debian/source/format b/debianpkg/backports/ubuntu16.04/debian/source/format deleted file mode 100644 index 163aaf8d8..000000000 --- a/debianpkg/backports/ubuntu16.04/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debianpkg/backports/ubuntu16.04/exclude b/debianpkg/backports/ubuntu16.04/exclude deleted file mode 100644 index e69de29bb..000000000 --- a/debianpkg/backports/ubuntu16.04/exclude +++ /dev/null diff --git a/debianpkg/backports/ubuntu16.04/versionext b/debianpkg/backports/ubuntu16.04/versionext deleted file mode 100644 index dc33d97a1..000000000 --- a/debianpkg/backports/ubuntu16.04/versionext +++ /dev/null @@ -1 +0,0 @@ --1~ubuntu16.04+1 diff --git a/debianpkg/backports/ubuntu17.10/debian/control b/debianpkg/backports/ubuntu17.10/debian/control deleted file mode 100644 index ce73f9d1b..000000000 --- a/debianpkg/backports/ubuntu17.10/debian/control +++ /dev/null @@ -1,54 +0,0 @@ -Source: frr -Section: net -Priority: optional -Maintainer: Nobody <nobody@frrouting.org> -Uploaders: Nobody <nobody@frrouting.org> -XSBC-Original-Maintainer: <maintainers@frrouting.org> -Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), imagemagick, ghostscript, groff, autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7), python-ipaddress, libpython-dev -Standards-Version: 3.9.6 -Homepage: http://www.frrouting.org/ - -Package: frr -Architecture: any -Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), iproute2 | iproute, ${misc:Depends}, libc-ares2 -Pre-Depends: adduser -Conflicts: zebra, zebra-pj, quagga -Replaces: zebra, zebra-pj -Suggests: snmpd -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon forked from Quagga - FRR is free software which manages TCP/IP based routing protocols. - It supports BGP4, BGP4+, OSPFv2, OSPFv3, IS-IS, RIPv1, RIPv2, RIPng, - PIM and LDP as well as the IPv6 versions of these. - . - FRR is a fork of Quagga with an open community model. The main git - lives on https://github.com/frrouting/frr.git - -Package: frr-dbg -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, frr (= ${binary:Version}) -Priority: optional -Section: debug -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (debug symbols) - This package provides debugging symbols for all binary packages built - from frr source package. It's highly recommended to have this package - installed before reporting any FRR crashes to either FRR developers or - Debian package maintainers. - -Package: frr-doc -Section: net -Architecture: all -Depends: ${misc:Depends} -Suggests: frr -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (documentation) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. - -Package: frr-pythontools -Section: net -Architecture: all -Depends: ${misc:Depends}, frr (= ${binary:Version}), python (>= 2.7), python-ipaddress -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (Python Tools) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. diff --git a/debianpkg/backports/ubuntu17.10/debian/source/format b/debianpkg/backports/ubuntu17.10/debian/source/format deleted file mode 100644 index 163aaf8d8..000000000 --- a/debianpkg/backports/ubuntu17.10/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debianpkg/backports/ubuntu17.10/exclude b/debianpkg/backports/ubuntu17.10/exclude deleted file mode 100644 index e69de29bb..000000000 --- a/debianpkg/backports/ubuntu17.10/exclude +++ /dev/null diff --git a/debianpkg/backports/ubuntu17.10/versionext b/debianpkg/backports/ubuntu17.10/versionext deleted file mode 100644 index bfbeccd65..000000000 --- a/debianpkg/backports/ubuntu17.10/versionext +++ /dev/null @@ -1 +0,0 @@ --1~ubuntu17.10+1 diff --git a/debianpkg/backports/ubuntu18.04/debian/control b/debianpkg/backports/ubuntu18.04/debian/control deleted file mode 100644 index 3fccb46b7..000000000 --- a/debianpkg/backports/ubuntu18.04/debian/control +++ /dev/null @@ -1,54 +0,0 @@ -Source: frr -Section: net -Priority: optional -Maintainer: Nobody <nobody@frrouting.org> -Uploaders: Nobody <nobody@frrouting.org> -XSBC-Original-Maintainer: <maintainers@frrouting.org> -Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), imagemagick, ghostscript, groff, autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7), python-ipaddress, python-sphinx, libpython-dev -Standards-Version: 3.9.6 -Homepage: http://www.frrouting.org/ - -Package: frr -Architecture: any -Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), iproute2 | iproute, ${misc:Depends}, libc-ares2 -Pre-Depends: adduser -Conflicts: zebra, zebra-pj, quagga -Replaces: zebra, zebra-pj -Suggests: snmpd -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon forked from Quagga - FRR is free software which manages TCP/IP based routing protocols. - It supports BGP4, BGP4+, OSPFv2, OSPFv3, IS-IS, RIPv1, RIPv2, RIPng, - PIM and LDP as well as the IPv6 versions of these. - . - FRR is a fork of Quagga with an open community model. The main git - lives on https://github.com/frrouting/frr.git - -Package: frr-dbg -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, frr (= ${binary:Version}) -Priority: optional -Section: debug -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (debug symbols) - This package provides debugging symbols for all binary packages built - from frr source package. It's highly recommended to have this package - installed before reporting any FRR crashes to either FRR developers or - Debian package maintainers. - -Package: frr-doc -Section: net -Architecture: all -Depends: ${misc:Depends} -Suggests: frr -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (documentation) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. - -Package: frr-pythontools -Section: net -Architecture: all -Depends: ${misc:Depends}, frr (= ${binary:Version}), python (>= 2.7), python-ipaddress -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (Python Tools) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. diff --git a/debianpkg/backports/ubuntu18.04/debian/source/format b/debianpkg/backports/ubuntu18.04/debian/source/format deleted file mode 100644 index 163aaf8d8..000000000 --- a/debianpkg/backports/ubuntu18.04/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debianpkg/backports/ubuntu18.04/exclude b/debianpkg/backports/ubuntu18.04/exclude deleted file mode 100644 index e69de29bb..000000000 --- a/debianpkg/backports/ubuntu18.04/exclude +++ /dev/null diff --git a/debianpkg/backports/ubuntu18.04/versionext b/debianpkg/backports/ubuntu18.04/versionext deleted file mode 100644 index 832fb4c32..000000000 --- a/debianpkg/backports/ubuntu18.04/versionext +++ /dev/null @@ -1 +0,0 @@ --1~ubuntu18.04+1 diff --git a/debianpkg/compat b/debianpkg/compat deleted file mode 100644 index 7f8f011eb..000000000 --- a/debianpkg/compat +++ /dev/null @@ -1 +0,0 @@ -7 diff --git a/debianpkg/control b/debianpkg/control deleted file mode 100644 index ea977937b..000000000 --- a/debianpkg/control +++ /dev/null @@ -1,54 +0,0 @@ -Source: frr -Section: net -Priority: optional -Maintainer: Nobody <nobody@frrouting.org> -Uploaders: Nobody <nobody@frrouting.org> -XSBC-Original-Maintainer: <maintainers@frrouting.org> -Build-Depends: debhelper (>= 7.0.50~), libreadline-dev, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7) | python3, python-sphinx | python3-sphinx, libpython-dev | libpython3-dev, install-info -Standards-Version: 3.9.6 -Homepage: http://www.frrouting.org/ - -Package: frr -Architecture: any -Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), iproute2 | iproute, ${misc:Depends}, libc-ares2 -Pre-Depends: adduser -Conflicts: zebra, zebra-pj, quagga -Replaces: zebra, zebra-pj -Suggests: snmpd -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon forked from Quagga - FRR is free software which manages TCP/IP based routing protocols. - It supports BGP4, BGP4+, OSPFv2, OSPFv3, IS-IS, RIPv1, RIPv2, RIPng, - PIM and LDP as well as the IPv6 versions of these. - . - FRR is a fork of Quagga with an open community model. The main git - lives on https://github.com/frrouting/frr.git - -Package: frr-dbg -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, frr (= ${binary:Version}) -Priority: extra -Section: debug -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (debug symbols) - This package provides debugging symbols for all binary packages built - from frr source package. It's highly recommended to have this package - installed before reporting any FRR crashes to either FRR developers or - Debian package maintainers. - -Package: frr-doc -Section: net -Architecture: all -Depends: ${misc:Depends} -Suggests: frr -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (documentation) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. - -Package: frr-pythontools -Section: net -Architecture: all -Depends: ${misc:Depends}, frr (= ${binary:Version}), python (>= 2.7), python-ipaddr -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (Python Tools) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. diff --git a/debianpkg/copyright b/debianpkg/copyright deleted file mode 100644 index 7b873abd3..000000000 --- a/debianpkg/copyright +++ /dev/null @@ -1,29 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: Frr -Upstream-Contact: maintainers@frrouting.org, security@frrouting.org -Source: http://www.frrouting.org/ - -Files: * -Copyright: 1996-2003 by the original Zebra authors: - Kunihiro Ishiguro <kunihiro@zebra.org> - Toshiaki Takada <takada@zebra.org> - Yasuhiro Ohara <yasu@sfc.wide.ad.jp> - 2003-2012 by the Quagga Project, mostly Paul Jakma <paul@jakma.org> -License: GPL-2+ - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - . - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - . - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - . - On Debian systems, the full text of the GNU General Public - License version 2 can be found in the file - `/usr/share/common-licenses/GPL-2'. diff --git a/debianpkg/frr-dbg.lintian-overrides b/debianpkg/frr-dbg.lintian-overrides deleted file mode 100644 index 7880bba29..000000000 --- a/debianpkg/frr-dbg.lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -frr-dbg: debug-file-with-no-debug-symbols usr/lib/debug/usr/lib/libfrrfpm_pb.so.0.0.0 diff --git a/debianpkg/frr-doc.docs b/debianpkg/frr-doc.docs deleted file mode 100644 index 605353289..000000000 --- a/debianpkg/frr-doc.docs +++ /dev/null @@ -1,3 +0,0 @@ -README.md -doc/user/*.rst -doc/figures/*.png diff --git a/debianpkg/frr-doc.install b/debianpkg/frr-doc.install deleted file mode 100644 index 8854b2c54..000000000 --- a/debianpkg/frr-doc.install +++ /dev/null @@ -1 +0,0 @@ -doc/user/_build/texinfo/*.png usr/share/info diff --git a/debianpkg/frr-doc.lintian-overrides b/debianpkg/frr-doc.lintian-overrides deleted file mode 100644 index 1fe64ffd5..000000000 --- a/debianpkg/frr-doc.lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -frr-doc: wrong-section-according-to-package-name frr-doc => doc diff --git a/debianpkg/frr-pythontools.install b/debianpkg/frr-pythontools.install deleted file mode 100644 index aee093cf6..000000000 --- a/debianpkg/frr-pythontools.install +++ /dev/null @@ -1 +0,0 @@ -tools/frr-reload.py usr/lib/frr/ diff --git a/debianpkg/frr.install b/debianpkg/frr.install deleted file mode 100644 index a53c5d138..000000000 --- a/debianpkg/frr.install +++ /dev/null @@ -1,12 +0,0 @@ -etc/frr/ -usr/bin/vtysh -usr/bin/mtracebis -usr/include/frr/ -usr/lib/ -tools/frr usr/lib/frr -usr/share/doc/frr/ -usr/share/yang/ -tools/etc/* etc/ -tools/*.service lib/systemd/system -tools/frr-reload usr/lib/frr/ -debian/frr.conf usr/lib/tmpfiles.d diff --git a/debianpkg/frr.lintian-overrides b/debianpkg/frr.lintian-overrides deleted file mode 100644 index 2e9888ed4..000000000 --- a/debianpkg/frr.lintian-overrides +++ /dev/null @@ -1,6 +0,0 @@ -frr: non-dev-pkg-with-shlib-symlink usr/lib/libfrrospfapiclient.so.0.0.0 usr/lib/libfrrospfapiclient.so -frr: non-dev-pkg-with-shlib-symlink usr/lib/libfrr.so.0.0.0 usr/lib/libfrr.so -frr: non-dev-pkg-with-shlib-symlink usr/lib/libfrrfpm_pb.so.0.0.0 usr/lib/libfrrfpm_pb.so -frr: package-name-doesnt-match-sonames libfrr0 libfrrfpm-pb0 libfrrospfapiclient0 -frr: systemd-service-file-refers-to-unusual-wantedby-target lib/systemd/system/frr.service network-online.target -frr: shared-lib-without-dependency-information usr/lib/libfrrfpm_pb.so.0.0.0 diff --git a/debianpkg/frr.postinst b/debianpkg/frr.postinst deleted file mode 100644 index a8d6ab280..000000000 --- a/debianpkg/frr.postinst +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -e - -###################### -frruid=`getent passwd frr | awk -F ":" '{ print $3 }'` -frrgid=`getent group frr | awk -F ":" '{ print $3 }'` -frrvtygid=`getent group frrvty | awk -F ":" '{ print $3 }'` - -[ -n ${frruid} ] || (echo "No uid for frr" && /bin/false) -[ -n ${frrgid} ] || (echo "No gid for frr" && /bin/false) -[ -n ${frrVTYgid} ] || (echo "No gid for frrvty" && /bin/false) - -chown ${frruid}:${frrgid} /etc/frr -chown ${frruid}:${frrgid} /etc/frr/* -touch /etc/frr/vtysh.conf -chgrp ${frrvtygid} /etc/frr/vtysh* -chmod 644 /etc/frr/* - -ENVIRONMENTFILE=/etc/environment -if ! egrep --quiet '^VTYSH_PAGER=' ${ENVIRONMENTFILE}; then - echo "VTYSH_PAGER=/bin/cat" >> ${ENVIRONMENTFILE} -fi -################################################## - -if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi -${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"} - -# This is most likely due to the answer "no" to the "really stop the server" -# question in the prerm script. -if [ "$1" = "abort-upgrade" ]; then - exit 0 -fi - -#DEBHELPER# - diff --git a/debianpkg/frr.postrm b/debianpkg/frr.postrm deleted file mode 100644 index 26576fd13..000000000 --- a/debianpkg/frr.postrm +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -e - -if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi -${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"} -# set -u not because of debhelper - -if [ "$1" = "purge" ]; then - rm -rf /etc/frr /var/run/frr /var/log/frr - userdel frr >/dev/null 2>&1 || true -fi - -#DEBHELPER# diff --git a/debianpkg/frr.preinst b/debianpkg/frr.preinst deleted file mode 100644 index 477e690d0..000000000 --- a/debianpkg/frr.preinst +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash - -if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi -${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"} -set -e -set -u - -# creating frrvty group if it isn't already there -if ! getent group frrvty >/dev/null; then - addgroup --system frrvty >/dev/null -fi - -# creating frr group if it isn't already there -if ! getent group frr >/dev/null; then - addgroup --system frr >/dev/null -fi - -# creating frr user if he isn't already there -if ! getent passwd frr >/dev/null; then - adduser \ - --system \ - --ingroup frr \ - --home /var/run/frr/ \ - --gecos "Frr routing suite" \ - --shell /bin/false \ - frr >/dev/null -fi - -# We may be installing over an older version of -# frr and as such we need to intelligently -# check to see if the frr user is in the frrvty -# group. -if ! id frr | grep &>/dev/null 'frrvty'; then - usermod -a -G frrvty frr >/dev/null -fi - -# Do not change permissions when upgrading as it would violate policy. -if [ "$1" = "install" ]; then - # Logfiles are group readable in case users were put into the frr group. - d=/var/log/frr/ - mkdir -p $d - chown frr:frr $d - chown --quiet frr:frr $d/* | true - chmod u=rwx,go=rx $d - find $d -type f -print0 | xargs -0 --no-run-if-empty chmod u=rw,g=r,o= - - # Strict permissions for the sockets. - d=/var/run/frr/ - mkdir -p $d - chown frr:frr $d - chown --quiet frr:frr $d/* | true - chmod u=rwx,go=rx $d - find $d -type f -print0 | xargs -0 --no-run-if-empty chmod u=rw,go= - - # Config files. Vtysh does not have access to the individual daemons config file - d=/etc/frr/ - mkdir -p $d - chown frr:frrvty $d - chmod ug=rwx,o=rx $d - find $d -type f -print0 | xargs -0 --no-run-if-empty chown frr:frr - find $d -type f -print0 | xargs -0 --no-run-if-empty chmod u=rw,g=r,o= - - # Exceptions for vtysh. - f=$d/vtysh.conf - if [ -f $f ]; then - chown frr:frrvty $f - chmod u=rw,g=r,o= $f - fi - - # Exceptions for vtysh. - f=$d/frr.conf - if [ -f $d/Zebra.conf ]; then - mv $d/Zebra.conf $f - fi - if [ -f $f ]; then - chown frr:frrvty $f - chmod u=rw,g=r,o= $f - fi -fi - -#DEBHELPER# diff --git a/debianpkg/frr.prerm b/debianpkg/frr.prerm deleted file mode 100644 index 4b7120281..000000000 --- a/debianpkg/frr.prerm +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -e - -if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi -${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"} - -# prerm remove -# old-prerm upgrade new-version -# new-prerm failed-upgrade old-version -# conflictor's-prerm remove in-favour package new-version -# deconfigured's-prerm deconfigure in-favour package-being-installed version removing conflicting-package -case $1 in - remove|upgrade) - ;; - - failed-upgrade) - # If frr/really_stop was negated then this script exits with return - # code 1 and is called again with "failed-upgrade". Well, exit again. - exit 1 - ;; - -esac - -#DEBHELPER# diff --git a/debianpkg/rules b/debianpkg/rules deleted file mode 100755 index 12d6c3545..000000000 --- a/debianpkg/rules +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/make -f - -# FRRouting Configuration options -###################################### -# -# WANT_xxxx --> Set to 1 for enable, 0 for disable -# The following are the defaults. They can be overridden by setting a -# env variable to a different value - -# -Werror - don't enable this unless you're doing a dev package build -WANT_WERROR ?= 0 - -WANT_OSPFAPI ?= 1 -WANT_BGP_VNC ?= 1 -WANT_CUMULUS_MODE ?= 0 -WANT_MULTIPATH ?= 1 -WANT_SNMP ?= 0 -WANT_RPKI ?= 0 - -# NOTES: -# -# If you use WANT_RPKI, then there is a new dependency for librtr0 package -# and a build dependency of the librtr-dev package. -# While the librtr0 is added to the depenencies automatically, the build -# dependency can't be changed dynamically and building will fail if the -# librtr-dev isn't installed during package build -# Tested versions of both packages can be found at -# https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact -# -# If multipath is enabled (WANT_MULTIPATH=1), then set number of multipaths here -# Please be aware that 0 is NOT disabled, but treated as unlimited - -MULTIPATH ?= 256 - -# Set the following to the value required (or leave alone for the default below) -# WANT_FRR_USER is used for the username and groupname of the FRR user account - -WANT_FRR_USER ?= frr -WANT_FRR_VTY_GROUP ?= frrvty - -# Don't build PDF docs by default -# add build deps: texlive-latex-base, texlive-generic-recommended -GENERATE_PDF ?= 0 - -# -#################################### - -export DH_VERBOSE=1 -export DEB_BUILD_MAINT_OPTIONS = hardening=+all -export DH_OPTIONS=-v - -ifeq ($(WANT_SNMP), 1) - USE_SNMP=--enable-snmp - $(warning "DEBIAN: SNMP enabled, sorry for your inconvenience") -else - USE_SNMP=--disable-snmp - $(warning "DEBIAN: SNMP disabled, see README.Debian") -endif - -ifeq ($(WANT_OSPFAPI), 1) - USE_OSPFAPI=--enable-ospfapi=yes -else - USE_OSPFAPI=--enable-ospfapi=no -endif - -ifeq ($(WANT_BGP_VNC), 1) - USE_BGP_VNC=--enable-bgp-vnc=yes -else - USE_BGP_VNC=--enable-bgp-vnc=no -endif - -USE_FRR_USER=--enable-user=$(WANT_FRR_USER) -USE_FRR_GROUP=--enable-group=$(WANT_FRR_USER) -USE_FRR_VTY_GROUP=--enable-vty-group=$(WANT_FRR_VTY_GROUP) - -ifeq ($(WANT_MULTIPATH), 1) - USE_MULTIPATH=--enable-multipath=$(MULTIPATH) -else - USE_MULTIPATH=--disable-multipath -endif - -ifeq ($(WANT_CUMULUS_MODE), 1) - USE_CUMULUS=--enable-cumulus=yes -else - USE_CUMULUS=--enable-cumulus=no -endif - -ifeq ($(WANT_RPKI), 1) - USE_RPKI=--enable-rpki -else - USE_RPKI=--disable-rpki -endif - -ifeq ($(WANT_WERROR), 1) - USE_WERROR=--enable-werror -else - USE_WERROR=--disable-werror -endif - -ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) - DEBIAN_JOBS := $(subst parallel=,,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) -endif - -ifdef DEBIAN_JOBS -MAKEFLAGS += -j$(DEBIAN_JOBS) -endif - -%: - dh $@ --with=systemd,autoreconf --parallel --dbg-package=frr-dbg --list-missing - -override_dh_gencontrol: -ifeq ($(WANT_RPKI), 1) - dh_gencontrol -- -Vdist:Depends="librtr0 (>= 0.5)" -else - dh_gencontrol -endif - -override_dh_auto_configure: - if ! [ -e config.status ]; then \ - dh_auto_configure -- \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - $(USE_SNMP) \ - $(USE_OSPFAPI) \ - $(USE_MULTIPATH) \ - --enable-fpm \ - $(USE_FRR_USER) $(USE_FRR_GROUP) \ - $(USE_FRR_VTY_GROUP) \ - --enable-configfile-mask=0640 \ - --enable-logfile-mask=0640 \ - $(USE_WERROR) \ - --with-libpam \ - --enable-systemd=yes \ - $(USE_CUMULUS) \ - --disable-dependency-tracking \ - $(USE_BGP_VNC) \ - $(USE_RPKI) \ - $(shell dpkg-buildflags --export=configure); \ - fi - -override_dh_auto_build: - dh_auto_build - -override_dh_auto_test: - -override_dh_auto_install: - dh_auto_install - - # installed in frr-pythontools - rm debian/tmp/usr/lib/frr/frr-reload.py - - # cleaning up the info dir - rm -f debian/tmp/usr/share/info/dir* - - # install config files - mkdir -p debian/tmp/etc/frr/ - perl -pi -e 's#^!log file #!log file /var/log/frr/#' debian/tmp/usr/share/doc/frr/examples/*sample* - - # we don't need .la files - rm debian/tmp/usr/lib/*.la - rm debian/tmp/usr/lib/frr/modules/*.la - rm debian/tmp/usr/lib/frr/libyang_plugins/*.la - -override_dh_systemd_start: - dh_systemd_start frr.service - -override_dh_systemd_enable: - dh_systemd_enable frr.service - -# backports -SRCPKG = frr -KNOWN_BACKPORTS = debian8 debian9 ubuntu14.04 ubuntu16.04 ubuntu17.10 ubuntu18.04 -DEBIAN_VERSION := $(shell dh_testdir && \ - dpkg-parsechangelog -c1 < debian/changelog | \ - sed -rn 's/^Version: ?//p') -ORIG_VERSION := $(DEBIAN_VERSION) --include debian/backports/rules - -ifneq ($(TARBALLDIR),) -ifeq ($(wildcard frr-$(ORIG_VERSION).tar.gz),frr-$(ORIG_VERSION).tar.gz) - -$(TARBALLDIR)/$(SRCPKG)_$(ORIG_VERSION).orig.tar.gz: \ - frr-$(ORIG_VERSION).tar.gz - cp $< $@ - -else # wildcard frr-$(ORIG_VERSION).tar.gz - -# better error message on missing .orig.tar.gz -$(TARBALLDIR)/$(SRCPKG)_$(ORIG_VERSION).orig.tar.gz: - @ echo "\`$(TARBALLDIR)/$(SRCPKG)-$(ORIG_VERSION).tar.gz'" not \ - found and not generated by debian/rules. Provided you have the \ - necessary packages installed, you can generate it yourself via \ - "\"./bootstrap.sh && ./configure && make dist\"". - exit 1 - -endif # wildcard frr-$(ORIG_VERSION).tar.gz -endif # TARBALLDIR nonempty diff --git a/debianpkg/subdir.am b/debianpkg/subdir.am deleted file mode 100644 index af17e4642..000000000 --- a/debianpkg/subdir.am +++ /dev/null @@ -1,62 +0,0 @@ -# -# debianpkg -# - -EXTRA_DIST += \ - debianpkg/README.Debian \ - debianpkg/README.Maintainer \ - debianpkg/changelog \ - debianpkg/compat \ - debianpkg/control \ - debianpkg/copyright \ - debianpkg/rules \ - debianpkg/source/format \ - debianpkg/tests/control \ - debianpkg/tests/daemons \ - debianpkg/watchfrr.rc \ - \ - debianpkg/backports/README \ - debianpkg/backports/rules \ - debianpkg/backports/debian8/debian/source/format \ - debianpkg/backports/debian8/exclude \ - debianpkg/backports/debian8/versionext \ - debianpkg/backports/debian9/debian/source/format \ - debianpkg/backports/debian9/exclude \ - debianpkg/backports/debian9/versionext \ - debianpkg/backports/ubuntu14.04/debian/control \ - debianpkg/backports/ubuntu14.04/debian/frr.install \ - debianpkg/backports/ubuntu14.04/debian/rules \ - debianpkg/backports/ubuntu14.04/debian/source/format \ - debianpkg/backports/ubuntu14.04/exclude \ - debianpkg/backports/ubuntu14.04/versionext \ - debianpkg/backports/ubuntu16.04/debian/source/format \ - debianpkg/backports/ubuntu16.04/exclude \ - debianpkg/backports/ubuntu16.04/versionext \ - debianpkg/backports/ubuntu17.10/debian/control \ - debianpkg/backports/ubuntu17.10/debian/source/format \ - debianpkg/backports/ubuntu17.10/exclude \ - debianpkg/backports/ubuntu17.10/versionext \ - debianpkg/backports/ubuntu18.04/debian/control \ - debianpkg/backports/ubuntu18.04/debian/source/format \ - debianpkg/backports/ubuntu18.04/exclude \ - debianpkg/backports/ubuntu18.04/versionext \ - \ - debianpkg/frr-dbg.lintian-overrides \ - debianpkg/frr-doc.docs \ - debianpkg/frr-doc.info \ - debianpkg/frr-doc.install \ - debianpkg/frr-doc.lintian-overrides \ - debianpkg/frr-pythontools.install \ - debianpkg/frr.conf \ - debianpkg/frr.dirs \ - debianpkg/frr.docs \ - debianpkg/frr.install \ - debianpkg/frr.lintian-overrides \ - debianpkg/frr.logrotate \ - debianpkg/frr.manpages \ - debianpkg/frr.pam \ - debianpkg/frr.postinst \ - debianpkg/frr.postrm \ - debianpkg/frr.preinst \ - debianpkg/frr.prerm \ - # end diff --git a/debianpkg/tests/control b/debianpkg/tests/control deleted file mode 100644 index 53fd537e2..000000000 --- a/debianpkg/tests/control +++ /dev/null @@ -1,3 +0,0 @@ -Tests: daemons -Depends: frr -Restrictions: needs-root diff --git a/debianpkg/tests/daemons b/debianpkg/tests/daemons deleted file mode 100644 index 43966c834..000000000 --- a/debianpkg/tests/daemons +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -#--------------- -# Testing frr -#--------------- -set -e - -# modify config file to enable all daemons and copy config files -CONFIG_FILE=/etc/frr/daemons -DAEMONS=("zebra" "bgpd" "ospfd" "ospf6d" "ripd" "ripngd" "isisd" "pimd" "fabricd") - -for daemon in "${DAEMONS[@]}" -do - sed -i -e "s/${daemon}=no/${daemon}=yes/g" $CONFIG_FILE - cp /usr/share/doc/frr/examples/${daemon}.conf.sample /etc/frr/${daemon}.conf -done - -# reload frr -/etc/init.d/frr restart > /dev/null 2>&1 - -# check daemons -for daemon in "${DAEMONS[@]}" -do - echo -n "check $daemon - " - if pidof -x $daemon > /dev/null; then - echo "${daemon} OK" - else - echo "ERROR: ${daemon} IS NOT RUNNING" - exit 1 - fi -done diff --git a/doc/developer/_static/overrides.css b/doc/developer/_static/overrides.css index 0d871c961..1d702bb6e 100644 --- a/doc/developer/_static/overrides.css +++ b/doc/developer/_static/overrides.css @@ -3,6 +3,237 @@ div.body { max-width: none; } +/* Palette URL: http://paletton.com/#uid=70p0p0kt6uvcDRAlhBavokxLJ6w */ + +:root { +--primary-0: #F36F16; /* Main Primary color */ +--primary-1: #FFC39A; +--primary-2: #FF9A55; +--primary-3: #A34403; +--primary-4: #341500; +--primary-9: #FFF3EB; + +--secondary-1-0: #F39C16; /* Main Secondary color (1) */ +--secondary-1-1: #FFD79A; +--secondary-1-2: #FFBC55; +--secondary-1-3: #A36403; +--secondary-1-4: #341F00; +--secondary-1-9: #FFF7EB; + +--secondary-2-0: #1A599F; /* Main Secondary color (2) */ +--secondary-2-1: #92B9E5; +--secondary-2-2: #477CB8; +--secondary-2-3: #0A386B; +--secondary-2-4: #011122; +--secondary-2-9: #E3EBF4; + +--complement-0: #0E9A83; /* Main Complement color */ +--complement-1: #8AE4D4; +--complement-2: #3CB4A0; +--complement-3: #026857; +--complement-4: #00211B; +--complement-9: #E0F4F0; +} + +/* new */ + +body { + font-family: "Fira Sans", Helvetica, Arial, sans-serif; + font-weight:400; +} +h1, h2, h3, h4, h5, h6 { + font-family: "Fira Sans", Helvetica, Arial, sans-serif; + font-weight:500; +} +code, pre, tt { + font-family: "Fira Mono"; +} +h1 { + background-color:var(--secondary-1-1); + border-bottom:1px solid var(--secondary-1-0); + font-weight:300; +} +h2 { + margin-top:36pt; +} + +a, +a:hover, +a:visited, +.code-block-caption a.headerlink:hover, +.rst-content dl:not(.docutils) dt .headerlink { + color: var(--complement-0); +} +.code-block-caption a.headerlink { + visibility:hidden; +} + +/* admonitions */ + +.admonition.warning { + border:1px dashed var(--primary-2); +} +.admonition.warning .admonition-title { + color: var(--primary-3); + background-color: var(--primary-1); +} +.admonition.note, +.admonition.hint { + border:1px dashed var(--complement-2); +} +.admonition.note .admonition-title, +.admonition.hint .admonition-title { + color: var(--complement-3); + background-color: var(--complement-1); +} +.admonition.seealso, +div.seealso { + background-color:var(--complement-9); +} +.admonition.seealso .admonition-title { + color: var(--complement-3); + background-color:var(--complement-1); + border-bottom:1px solid var(--complement-2); +} +.admonition.admonition-todo .admonition-title { + background-image: repeating-linear-gradient( + 135deg, + #ffa, + #ffa 14.14213452px, + #bbb 14.14213452px, + #bbb 28.28427124px + ); + color:#000; +} +.admonition.admonition-todo { + background-image: repeating-linear-gradient( + 135deg, + #ffd, + #ffd 14.14213452px, + #eed 14.14213452px, + #eed 28.28427124px + ); +} + +.rst-content dl .admonition p.last { + margin-bottom:0 !important; +} + +/* file block */ + +.code-block-caption { +/* border-radius: 4px; */ + font-style:italic; + font-weight:300; + border-bottom: 1px solid var(--secondary-2-1); + background-color: var(--secondary-2-9); + padding:2px 8px; +} + +/* navbar */ + +.wy-nav-side { + background-color: var(--secondary-1-4); + border-right:2px solid var(--primary-3); +} +.wy-menu-vertical a, +.wy-menu-vertical a:visited, +.wy-menu-vertical a:hover, +.wy-side-nav-search>a, +.wy-side-nav-search .wy-dropdown>a { + color: var(--primary-0); +} + +nav div.wy-side-nav-search { + background-color: #eee; +} +nav div.wy-side-scroll { + background-color: var(--secondary-1-4); +} +nav .wy-menu-vertical a:hover { + background-color:var(--primary-0); + color:var(--primary-4); +} +nav .wy-menu-vertical li.current ul a:hover { + background-color:var(--secondary-1-2); + color:var(--primary-4); +} +nav .wy-menu-vertical li.current ul a { + background-color:var(--secondary-1-1); + color:var(--primary-3); +} +nav .wy-menu-vertical li.on a:hover, +nav .wy-menu-vertical li.current>a:hover { + background-color:#fcfcfc; +} +.wy-side-nav-search input[type=text] { + border-color:var(--primary-2); +} +.wy-menu-vertical li.toctree-l1.current>a { + border-top:1px solid var(--secondary-1-3); + border-bottom:1px solid var(--secondary-1-3); +} +.wy-menu-vertical li.toctree-l2.current>a { + background-color:var(--secondary-1-2); +} +.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a { + background-color:var(--secondary-1-9); +} + +.wy-nav-content { + padding: 25pt 40pt; +} +div[role=navigation] > hr { + display:none; +} +div[role=navigation] { + margin-bottom:15pt; +} +h1 { + margin-left:-40pt; + margin-right:-40pt; + padding:5pt 40pt 5pt 40pt; +} + +.rst-content pre.literal-block, .rst-content div[class^='highlight'] { + border-color:var(--secondary-1-1); +} + +span.pre { + color: var(--complement-3); +} pre { - background-color: #e2e2e2; + background-color: var(--secondary-1-9); + border-color: var(--secondary-1-1); +} +.highlight .p { color: var(--secondary-2-3); } +.highlight .k { color: var(--secondary-2-0); } +.highlight .kt { color: var(--complement-0); } +.highlight .cm { color: var(--primary-3); } +.highlight .ow { color: var(--primary-3); } +.highlight .na { color: var(--primary-2); } +.highlight .nv { color: var(--complement-0); } + +strong { + font-weight:500; +} +.rst-content dl:not(.docutils) dt { + font-family:Fira Mono; + font-weight:600; + background-color:var(--secondary-2-9); + color:var(--secondary-2-3); + border-top:2px solid var(--secondary-2-2); +} +dt code.descname { + color: var(--secondary-2-4); +} + +@media (min-width: 1200px) { + .container { width: auto; } +} +@media (min-width: 992px) { + .container { width: auto; } +} +@media (min-width: 768px) { + .container { width: auto; } } diff --git a/doc/developer/building-frr-for-debian8.rst b/doc/developer/building-frr-for-debian8.rst index 97e9382d4..d0f4182ba 100644 --- a/doc/developer/building-frr-for-debian8.rst +++ b/doc/developer/building-frr-for-debian8.rst @@ -15,9 +15,9 @@ Add packages: :: - sudo apt-get install git autoconf automake libtool make gawk \ - libreadline-dev texinfo libjson-c-dev pkg-config bison flex \ - python-pip libc-ares-dev python3-dev python3-sphinx + sudo apt-get install git autoconf automake libtool make gawk \ + libreadline-dev texinfo libjson-c-dev pkg-config bison flex python-pip \ + libc-ares-dev python3-dev python3-sphinx build-essential libsystemd-dev Install newer pytest (>3.0) from pip diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst index 7c9f567b8..39e7488cd 100644 --- a/doc/developer/building-frr-for-debian9.rst +++ b/doc/developer/building-frr-for-debian9.rst @@ -8,9 +8,10 @@ Add packages: :: - sudo apt-get install git autoconf automake libtool make \ - libreadline-dev texinfo libjson-c-dev pkg-config bison flex \ - python-pip libc-ares-dev python3-dev python-pytest python3-sphinx + sudo apt-get install git autoconf automake libtool make \ + libreadline-dev texinfo libjson-c-dev pkg-config bison flex python-pip \ + libc-ares-dev python3-dev python-pytest python3-sphinx build-essential \ + libsystemd-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1204.rst b/doc/developer/building-frr-for-ubuntu1204.rst deleted file mode 100644 index a2d58e225..000000000 --- a/doc/developer/building-frr-for-ubuntu1204.rst +++ /dev/null @@ -1,184 +0,0 @@ -Ubuntu 12.04LTS -=============================================== - -- MPLS is not supported on ``Ubuntu 12.04`` with default kernel. MPLS - requires Linux Kernel 4.5 or higher (LDP can be built, but may have - limited use without MPLS) For an updated Ubuntu Kernel, see - http://kernel.ubuntu.com/~kernel-ppa/mainline/ - -Install required packages -------------------------- - -Add packages: - -:: - - apt-get install \ - git autoconf automake libtool make gawk libreadline-dev texinfo \ - dejagnu pkg-config libpam0g-dev libjson0-dev flex python-pip \ - libc-ares-dev python3-dev python3-sphinx install-info - -Install newer bison from 14.04 package source (Ubuntu 12.04 package -source is too old) - -:: - - mkdir builddir - cd builddir - wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg-2.dsc - wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg.orig.tar.bz2 - wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg-2.debian.tar.gz - tar -jxvf bison_3.0.2.dfsg.orig.tar.bz2 - cd bison-3.0.2.dfsg/ - tar xzf ../bison_3.0.2.dfsg-2.debian.tar.gz - sudo apt-get build-dep bison - debuild -b -uc -us - cd .. - sudo dpkg -i ./libbison-dev_3.0.2.dfsg-2_amd64.deb ./bison_3.0.2.dfsg-2_amd64.deb - cd .. - rm -rf builddir - -Install newer version of autoconf and automake: - -:: - - wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz - tar xvf autoconf-2.69.tar.gz - cd autoconf-2.69 - ./configure --prefix=/usr - make - sudo make install - cd .. - - wget http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz - tar xvf automake-1.15.tar.gz - cd automake-1.15 - ./configure --prefix=/usr - make - sudo make install - cd .. - -Install pytest: - -:: - - pip install pytest - -.. include:: building-libyang.rst - -Get FRR, compile it and install it (from Git) ---------------------------------------------- - -**This assumes you want to build and install FRR from source and not -using any packages** - -Add frr groups and user -^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - sudo groupadd -r -g 92 frr - sudo groupadd -r -g 85 frrvty - sudo adduser --system --ingroup frr --home /var/run/frr/ \ - --gecos "FRR suite" --shell /sbin/nologin frr - sudo usermod -a -G frrvty frr - -Download Source, configure and compile it -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -(You may prefer different options on configure statement. These are just -an example.) - -:: - - git clone https://github.com/frrouting/frr.git frr - cd frr - ./bootstrap.sh - ./configure \ - --prefix=/usr \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - --enable-multipath=64 \ - --enable-user=frr \ - --enable-group=frr \ - --enable-vty-group=frrvty \ - --enable-configfile-mask=0640 \ - --enable-logfile-mask=0640 \ - --enable-fpm \ - --with-pkg-git-version \ - --with-pkg-extra-version=-MyOwnFRRVersion - make - make check - sudo make install - -Create empty FRR configuration files -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - sudo install -m 755 -o frr -g frr -d /var/log/frr - sudo install -m 775 -o frr -g frrvty -d /etc/frr - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf - sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf - -Enable IP & IPv6 forwarding -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the -other settings) - -:: - - # Uncomment the next line to enable packet forwarding for IPv4 - net.ipv4.ip_forward=1 - - # Uncomment the next line to enable packet forwarding for IPv6 - # Enabling this option disables Stateless Address Autoconfiguration - # based on Router Advertisements for this host - net.ipv6.conf.all.forwarding=1 - -**Reboot** or use ``sysctl -p`` to apply the same config to the running -system - -Install the init.d service -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - sudo install -m 755 tools/frr /etc/init.d/frr - sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons - sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf - -Enable daemons -^^^^^^^^^^^^^^ - -| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for - those daemons you want to start by systemd. -| For example. - -:: - - zebra=yes - bgpd=yes - ospfd=yes - ospf6d=yes - ripd=yes - ripngd=yes - isisd=yes - -Start the init.d service -^^^^^^^^^^^^^^^^^^^^^^^^ - -- /etc/init.d/frr start -- use ``/etc/init.d/frr status`` to check its status. diff --git a/doc/developer/building-frr-for-ubuntu1404.rst b/doc/developer/building-frr-for-ubuntu1404.rst index 7952cd682..b1eaf57e8 100644 --- a/doc/developer/building-frr-for-ubuntu1404.rst +++ b/doc/developer/building-frr-for-ubuntu1404.rst @@ -13,10 +13,10 @@ Add packages: :: - apt-get install \ - git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \ - pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ - libc-ares-dev python3-dev python3-sphinx install-info + apt-get install \ + git autoconf automake libtool make gawk libreadline-dev texinfo \ + dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ + libc-ares-dev python3-dev python3-sphinx install-info build-essential .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1604.rst b/doc/developer/building-frr-for-ubuntu1604.rst index f5329fef2..0762e07eb 100644 --- a/doc/developer/building-frr-for-ubuntu1604.rst +++ b/doc/developer/building-frr-for-ubuntu1604.rst @@ -13,11 +13,11 @@ Add packages: :: - apt-get install \ - git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \ - pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ - libc-ares-dev python3-dev libsystemd-dev python-ipaddress \ - python3-sphinx install-info + apt-get install \ + git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \ + pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ + libc-ares-dev python3-dev libsystemd-dev python-ipaddress \ + python3-sphinx install-info build-essential libsystemd-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst index 110bc6a0e..089d5a216 100644 --- a/doc/developer/building-frr-for-ubuntu1804.rst +++ b/doc/developer/building-frr-for-ubuntu1804.rst @@ -13,7 +13,7 @@ Required packages git autoconf automake libtool make gawk libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress \ - python3-sphinx install-info + python3-sphinx install-info build-essential libsystemd-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-libyang.rst b/doc/developer/building-libyang.rst index 005b6ba78..c45c294b7 100644 --- a/doc/developer/building-libyang.rst +++ b/doc/developer/building-libyang.rst @@ -4,6 +4,13 @@ The libyang library can be installed from third-party packages available `here Note: the libyang dev/devel packages need to be installed in addition to the libyang core package in order to build FRR successfully. +.. warning:: + libyang ABI version 0.16.74 or newer will be required to build FRR in the + near future since it significantly eases build and installation + considerations. "0.16-r3" is equal to 0.16.105 and will work, "0.16-r2" + is equal to 0.16.52 and will stop working. The CI artifacts will be + updated shortly. + For example, for CentOS 7.x: .. code-block:: shell @@ -21,6 +28,14 @@ or Ubuntu 18.04: sudo apt install libpcre3-dev sudo dpkg -i libyang-dev_0.16.46_amd64.deb libyang_0.16.46_amd64.deb +.. note:: + For Debian-based systems, the official libyang package requires recent + versions of swig (3.0.12) and debhelper (11) which are only available in + Debian buster (10). However, libyang packages built on Debian buster can + be installed on both Debian jessie (8) and Debian stretch (9), as well as + various Ubuntu systems. The python3-yang package will not work, but the + other packages (libyang-dev is the one needed for FRR) will. + Alternatively, libyang can be built and installed manually by following the steps below: diff --git a/doc/developer/building.rst b/doc/developer/building.rst index 4c18445f9..96559b0ab 100644 --- a/doc/developer/building.rst +++ b/doc/developer/building.rst @@ -21,7 +21,6 @@ Building FRR building-frr-for-omnios building-frr-for-openbsd6 building-frr-for-openwrt - building-frr-for-ubuntu1204 building-frr-for-ubuntu1404 building-frr-for-ubuntu1604 building-frr-for-ubuntu1804 diff --git a/doc/developer/conf.py b/doc/developer/conf.py index 254c9f6bf..af8673e5f 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -131,7 +131,7 @@ language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build', 'building-libyang.rst'] +exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst'] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -167,12 +167,19 @@ todo_include_todos = True # a list of builtin themes. html_theme = 'default' +try: + import sphinx_rtd_theme + + html_theme = 'sphinx_rtd_theme' +except ImportError: + pass + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -html_theme_options = { - 'sidebarbgcolor': '#374249' -} +#html_theme_options = { +# 'sidebarbgcolor': '#374249' +#} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] diff --git a/doc/developer/index.rst b/doc/developer/index.rst index 9838e1098..3a33d9a5e 100644 --- a/doc/developer/index.rst +++ b/doc/developer/index.rst @@ -9,6 +9,7 @@ FRRouting Developer's Guide packaging process-architecture library + testing bgpd ospf zebra diff --git a/doc/developer/maintainer-release-build.rst b/doc/developer/maintainer-release-build.rst index 85aaa5365..779217303 100644 --- a/doc/developer/maintainer-release-build.rst +++ b/doc/developer/maintainer-release-build.rst @@ -37,7 +37,7 @@ Release Build Procedure for FRR Maintainers 4. Update Changelog for Debian Packages: - Edit :file:`debianpkg/changelog.in`: + Edit :file:`debian/changelog-auto.in`: - Change last (top of list) entry from ``@VERSION@`` to previous fixed version number, i.e.:: diff --git a/doc/developer/memtypes.rst b/doc/developer/memtypes.rst index d43bc2555..43cbe002c 100644 --- a/doc/developer/memtypes.rst +++ b/doc/developer/memtypes.rst @@ -95,7 +95,7 @@ Usage .. c:function:: void *XCALLOC(struct memtype *mtype, size_t size) -.. c:function:: void *XSTRDUP(struct memtype *mtype, size_t size) +.. c:function:: void *XSTRDUP(struct memtype *mtype, const char *name) Allocation wrappers for malloc/calloc/realloc/strdup, taking an extra mtype parameter. diff --git a/doc/developer/modules.rst b/doc/developer/modules.rst index 99c79462a..763d8b1b8 100644 --- a/doc/developer/modules.rst +++ b/doc/developer/modules.rst @@ -53,6 +53,14 @@ Basic boilerplate: #include "hook.h" #include "module.h" + #include "libfrr.h" + #include "thread.h" + + static int module_late_init(struct thread_master *master) + { + /* Do initialization stuff here */ + return 0; + } static int module_init (void) diff --git a/doc/developer/packaging-debian.rst b/doc/developer/packaging-debian.rst index c812a3821..c660f9868 100644 --- a/doc/developer/packaging-debian.rst +++ b/doc/developer/packaging-debian.rst @@ -1,31 +1,16 @@ Packaging Debian ================ -(Tested on Ubuntu 12.04, 14.04, 16.04, 17.10, 18.04, Debian 8 and 9) +(Tested on Ubuntu 14.04, 16.04, 17.10, 18.04, Debian jessie, stretch and +buster.) -.. note:: - - If you try to build for a different distro, then it will most likely fail - because of the missing backport. See :ref:`deb-backports` about adding a new - backport. - -1. Install build dependencies for your platform as outlined in :ref:`building`. - -2. Install the following additional packages: - - - on Ubuntu 12.04, 14.04, 16.04, 17.10, Debian 8 and 9: - - .. code-block:: shell - - apt-get install realpath equivs groff fakeroot debhelper devscripts - - - on Ubuntu 18.04: (realpath is now part of preinstalled by coreutils) +1. Install the Debian packaging tools: .. code-block:: shell - apt-get install equivs groff fakeroot debhelper devscripts + sudo apt install fakeroot debhelper devscripts -3. Checkout FRR under a **unprivileged** user account: +2. Checkout FRR under an **unprivileged** user account: .. code-block:: shell @@ -38,143 +23,145 @@ Packaging Debian git checkout <branch> -4. Run ``bootstrap.sh`` and make a dist tarball: +3. Install build dependencies using the `mk-build-deps` tool from the + `devscripts` package: .. code-block:: shell - ./bootstrap.sh - ./configure --with-pkg-extra-version=-MyDebPkgVersion - make dist - - .. note:: - - Configure parameters are not important for the Debian Package building - - except the `with-pkg-extra-version` if you want to give the Debian - package a specific name to mark your own unoffical build. - -5. Edit :file:`debianpkg/rules` and set the configuration as needed. - - Look for section ``dh_auto_configure`` to modify the configure options as - needed. Options might be different between the top-level ``rules``` and - :file:`backports/XXXX/debian/rules`. Please adjust as needed on all files. + sudo mk-build-deps --install debian/control -6. Create backports debian sources + Alternatively, you can manually install build dependencies for your + platform as outlined in :ref:`building`. - Rename the :file:`debianpkg` directory to :file:`debian` and create the - backports (Debian requires to not ship a :file:`debian` directory inside the - source directory to avoid build conflicts with the reserved ``debian`` - subdirectory name during the build): +4. Run ``tools/tarsource.sh -V``: .. code-block:: shell - mv debianpkg debian - make -f debian/rules backports + ./tools/tarsource.sh -V - This will create a :file:`frr_*.orig.tar.gz` with the source (same as the - dist tarball), as well as multiple :file:`frr_*.debian.tar.xz` and - :file:`frr_*.dsc` corresponding to each distribution for which a backport is - available. + This script sets up the ``debian/changelog-auto`` file with proper version + information. -7. Create a new directory to build the package and populate with package - source. - - .. code-block:: shell +5. (optional) Append a distribution identifier if needed (see below under + :ref:`multi-dist`.) - mkdir frrpkg - cd frrpkg - tar xf ~/frr/frr_*.orig.tar.gz - cd frr* - . /etc/os-release - tar xf ~/frr/frr_*${ID}${VERSION_ID}*.debian.tar.xz - -8. Build Debian package dependencies and install them as needed. +6. Build Debian Package: .. code-block:: shell - sudo mk-build-deps --install debian/control + dpkg-buildpackage $options -9. Build Debian Package + Where `$options` may contain any or all of the following items: - Building with standard options: + * build profiles specified with ``-P``, e.g. + ``-Ppkg.frr.nortrlib,pkg.frr.nosystemd``. + Multiple values are separated by commas and there must not be a space + after the ``-P``. - .. code-block:: shell + The following build profiles are currently available: - debuild -b -uc -us + +----------------+-------------------+-----------------------------------------+ + | Profile | Negation | Effect | + +================+===================+=========================================+ + | pkg.frr.rtrlib | pkg.frr.nortrlib | builds frr-rpki-rtrlib package (or not) | + +----------------+-------------------+-----------------------------------------+ + | n/a | pkg.frr.nosystemd | removes libsystemd dependency and | + | | | disables unit file installation | + +----------------+-------------------+-----------------------------------------+ - Or change some options (see `rules` file for available options): + .. note:: - .. code-block:: shell + The ``pkg.frr.nosystemd`` option is only intended to support Ubuntu + 14.04 (and should be enabled when building for that.) - debuild --set-envvar=WANT_BGP_VNC=1 --set-envvar=WANT_CUMULUS_MODE=1 -b -uc -us + * the ``-uc -us`` options to disable signing the packages with your GPG key - To build with RPKI: + (git builds of the `master` or `stable/X.X` branches won't be signed by + default since their target release is set to ``UNRELEASED``.) - - Download the librtr packages from - https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact +7. Done! - - install librtr-dev on the build server + If all worked correctly, then you should end up with the Debian packages in + the parent directory of where `debuild` ran. If distributed, please make sure + you distribute it together with the sources (``frr_*.orig.tar.xz``, + ``frr_*.debian.tar.xz`` and ``frr_*.dsc``) - Then build with: +.. note:: - .. code-block:: shell + A package created from `master` or `stable/X.X` is slightly different from + a package created from the `debian` branch. The changelog for the former + is autogenerated and sets the Debian revision to ``-0``, which causes an + intentional lintian warning. The `debian` branch on the other hand has + a manually maintained changelog that contains proper Debian release + versioning. - debuild --set-envvar=WANT_RPKI=1 -b -uc -us + Furthermore, official Debian packages are built in ``3.0 (quilt)`` format + with an "orig" tarball and a "debian" tarball. These tarballs are created + by the ``tarsource.sh`` tool on any branch. The git repository however + contains a ``3.0 (git)`` source format specifier to easily allow direct + git builds. - RPKI packages have an additonal dependency of ``librtr0`` which can be found - at the same URL. -10. Done! +.. _multi-dist: -If all worked correctly, then you should end up with the Debian packages under -:file:`frrpkg`. If distributed, please make sure you distribute it together -with the sources (``frr_*.orig.tar.gz``, ``frr_*.debian.tar.xz`` and -``frr_*.dsc``) +Multi-Distribution builds +========================= -The build procedure can also be executed automatically using the ``tools/build-debian-package.sh`` -script. For example: +You can optionally append a distribution identifier in case you want to +make multiple versions of the package available in the same repository. +Do the following after creating the changelog with `tarsource.sh`: .. code-block:: shell - EXTRA_VERSION="-myversion" WANT_SNMP=1 WANT_CUMULUS_MODE=1 tools/build-debian-package.sh - -.. _deb-backports: - -Debian Backports ----------------- + dch -l '~deb8u' 'build for Debian 8 (jessie)' + dch -l '~deb9u' 'build for Debian 9 (stretch)' + dch -l '~ubuntu14.04.' 'build for Ubuntu 14.04 (trusty)' + dch -l '~ubuntu16.04.' 'build for Ubuntu 16.04 (xenial)' + dch -l '~ubuntu18.04.' 'build for Ubuntu 18.04 (bionic)' + +Between building packages for specific distributions, the only difference +in the package itself lies in the automatically generated shared library +dependencies, e.g. libjson-c2 or libjson-c3. This means that the +architecture independent packages should **not** have a suffix appended. +Also, the current Debian testing/unstable releases should not have any suffix +appended. + +For example, at the end of 2018 (i.e. ``buster``/Debian 10 is the current +"testing" release), the following is a complete list of `.deb` files for +Debian 8, 9 and 10 packages for FRR 6.0.1-1 with RPKI support:: + + frr_6.0.1-1_amd64.deb + frr_6.0.1-1~deb8u1_amd64.deb + frr_6.0.1-1~deb9u1_amd64.deb + frr-dbg_6.0.1-1_amd64.deb + frr-dbg_6.0.1-1~deb8u1_amd64.deb + frr-dbg_6.0.1-1~deb9u1_amd64.deb + frr-rpki-rtrlib_6.0.1-1_amd64.deb + frr-rpki-rtrlib_6.0.1-1~deb8u1_amd64.deb + frr-rpki-rtrlib_6.0.1-1~deb9u1_amd64.deb + frr-doc_6.0.1-1_all.deb + frr-pythontools_6.0.1-1_all.deb + +Note that there are no extra versions of the `frr-doc` and `frr-pythontools` +packages (because they are for architecture ``all``, not ``amd64``), and the +version for Debian 10 does **not** have a ``~deb10u1`` suffix. + +.. warning:: + + Do not use the ``-`` character in the version suffix. The last ``-`` in + the version number is the separator between upstream version and Debian + version. ``6.0.1-1~foobar-2`` means upstream version ``6.0.1-1~foobar``, + Debian version ``2``. This is not what you want. + + The only allowed characters in the Debian version are ``0-9 A-Z a-z + . ~`` -The :file:`debianpkg/backports` directory contains the Debian directories for -backports to other Debian platforms. These are built via the ``3.0 (custom)`` -source format, which allows one to build a source package directly out of -tarballs (e.g. an orig.tar.gz tarball and a debian.tar.gz file), at which point -the format can be changed to a real format (e.g. ``3.0 (quilt)``). - -Source packages are assembled via targets of the same name as the system to -which the backport is done (e.g. ``precise``), included in :file:`debian/rules`. - -To create a new Debian backport: - -- Add its name to ``KNOWN_BACKPORTS``, defined in :file:`debian/rules`. -- Create a directory of the same name in :file:`debian/backports`. -- Add the files ``exclude``, ``versionext``, and ``debian/source/format`` under - this directory. - -For the last point, these files should contain the following: - -``exclude`` - Contains whitespace-separated paths (relative to the root of the source dir) - that should be excluded from the source package (e.g. - :file:`debian/patches`). - -``versionext`` - Contains the suffix added to the version number for this backport's build. - Distributions often have guidelines for what this should be. If left empty, - no new :file:`debian/changelog` entry is created. +.. note:: -``debian/source/format`` - Contains the source format of the resulting source package. As of of the - writing of this document the only supported format is ``3.0 (quilt)``. + The separating character for the suffix **must** be the tilde (``~``) + because the tilde is ordered in version-comparison before the empty + string. That means the order of the above packages is the following: -- Add appropriate files under the :file:`debian/` subdirectory. These will be - included in the source package, overriding any top-level :file:`debian/` - files with equivalent paths. + ``6.0.1-1`` newer than ``6.0.1-1~deb9u1`` newer than ``6.0.1-1~deb8u1`` + If you use another character (e.g. ``+``), the untagged version will be + regarded as the "oldest"! diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index 575722a80..d76991367 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -19,7 +19,6 @@ dev_RSTFILES = \ doc/developer/building-frr-for-netbsd7.rst \ doc/developer/building-frr-for-omnios.rst \ doc/developer/building-frr-for-openbsd6.rst \ - doc/developer/building-frr-for-ubuntu1204.rst \ doc/developer/building-frr-for-ubuntu1404.rst \ doc/developer/building-frr-for-ubuntu1604.rst \ doc/developer/building-frr-for-ubuntu1804.rst \ @@ -38,6 +37,11 @@ dev_RSTFILES = \ doc/developer/ospf-api.rst \ doc/developer/ospf-sr.rst \ doc/developer/ospf.rst \ + doc/developer/packaging.rst \ + doc/developer/packaging-debian.rst \ + doc/developer/testing.rst \ + doc/developer/topotests-snippets.rst \ + doc/developer/topotests.rst \ doc/developer/workflow.rst \ doc/developer/zebra.rst \ # end diff --git a/doc/developer/testing.rst b/doc/developer/testing.rst new file mode 100644 index 000000000..6396faf9a --- /dev/null +++ b/doc/developer/testing.rst @@ -0,0 +1,10 @@ +.. _testing: + +******* +Testing +******* + +.. toctree:: + :maxdepth: 2 + + topotests diff --git a/doc/developer/topotests-snippets.rst b/doc/developer/topotests-snippets.rst new file mode 100644 index 000000000..649229b43 --- /dev/null +++ b/doc/developer/topotests-snippets.rst @@ -0,0 +1,272 @@ +.. _topotests-snippets: + +Snippets +-------- + +This document will describe common snippets of code that are frequently needed +to perform some test checks. + +Checking for router / test failures +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following check uses the topogen API to check for software failure (e.g. +zebra died) and/or for errors manually set by ``Topogen.set_error()``. + +.. code:: py + + # Get the topology reference + tgen = get_topogen() + + # Check for errors in the topology + if tgen.routers_have_failure(): + # Skip the test with the topology errors as reason + pytest.skip(tgen.errors) + +Checking FRR routers version +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This code snippet is usually run after the topology setup to make sure all +routers instantiated in the topology have the correct software version. + +.. code:: py + + # Get the topology reference + tgen = get_topogen() + + # Get the router list + router_list = tgen.routers() + + # Run the check for all routers + for router in router_list.values(): + if router.has_version('<', '3'): + # Set topology error, so the next tests are skipped + tgen.set_error('unsupported version') + +A sample of this snippet in a test can be found `here +<ldp-vpls-topo1/test_ldp_vpls_topo1.py>`__. + +Interacting with equipment +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You might want to interact with the topology equipments during the tests and +there are different ways to do so. + +Notes: + +1. When using the Topogen API, all the equipments code derive from ``Topogear`` + (`lib/topogen.py <lib/topogen.py>`__). If you feel brave you can look by + yourself how the abstractions that will be mentioned here works. + +2. When not using the ``Topogen`` API there is only one way to interact with + the equipments, which is by calling the ``mininet`` API functions directly + to spawn commands. + +Interacting with the Linux sandbox +"""""""""""""""""""""""""""""""""" + +Without ``Topogen``: + +.. code:: py + + global net + output = net['r1'].cmd('echo "foobar"') + print 'output is: {}'.format(output) + +With ``Topogen``: + +.. code:: py + + tgen = get_topogen() + output = tgen.gears['r1'].run('echo "foobar"') + print 'output is: {}'.format(output) + +Interacting with VTYSH +"""""""""""""""""""""" + +Without ``Topogen``: + +.. code:: py + + global net + output = net['r1'].cmd('vtysh "show ip route" 2>/dev/null') + print 'output is: {}'.format(output) + +With ``Topogen``: + +.. code:: py + + tgen = get_topogen() + output = tgen.gears['r1'].vtysh_cmd("show ip route") + print 'output is: {}'.format(output) + +``Topogen`` also supports sending multiple lines of command: + +.. code:: py + + tgen = get_topogen() + output = tgen.gears['r1'].vtysh_cmd(""" + configure terminal + router bgp 10 + bgp router-id 10.0.255.1 + neighbor 1.2.3.4 remote-as 10 + ! + router bgp 11 + bgp router-id 10.0.255.2 + ! + """) + print 'output is: {}'.format(output) + +You might also want to run multiple commands and get only the commands that +failed: + +.. code:: py + + tgen = get_topogen() + output = tgen.gears['r1'].vtysh_multicmd(""" + configure terminal + router bgp 10 + bgp router-id 10.0.255.1 + neighbor 1.2.3.4 remote-as 10 + ! + router bgp 11 + bgp router-id 10.0.255.2 + ! + """, pretty_output=false) + print 'output is: {}'.format(output) + +Translating vtysh JSON output into Python structures: + +.. code:: py + + tgen = get_topogen() + json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True) + output = json.dumps(json_output, indent=4) + print 'output is: {}'.format(output) + + # You can also access the data structure as normal. For example: + # protocol = json_output['1.1.1.1/32']['protocol'] + # assert protocol == "ospf", "wrong protocol" + +.. note:: + + ``vtysh_(multi)cmd`` is only available for router type of equipments. + +Invoking mininet CLI +^^^^^^^^^^^^^^^^^^^^ + +Without ``Topogen``: + +.. code:: py + + CLI(net) + +With ``Topogen``: + +.. code:: py + + tgen = get_topogen() + tgen.mininet_cli() + +Reading files +^^^^^^^^^^^^^ + +Loading a normal text file content in the current directory: + +.. code:: py + + # If you are using Topogen + # CURDIR = CWD + # + # Otherwise find the directory manually: + CURDIR = os.path.dirname(os.path.realpath(__file__)) + + file_name = '{}/r1/show_ip_route.txt'.format(CURDIR) + file_content = open(file_name).read() + +Loading JSON from a file: + +.. code:: py + + import json + + file_name = '{}/r1/show_ip_route.json'.format(CURDIR) + file_content = json.loads(open(file_name).read()) + +Comparing JSON output +^^^^^^^^^^^^^^^^^^^^^ + +After obtaining JSON output formated with Python data structures, you may use +it to assert a minimalist schema: + +.. code:: py + + tgen = get_topogen() + json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True) + + expect = { + '1.1.1.1/32': { + 'protocol': 'ospf' + } + } + + assertmsg = "route 1.1.1.1/32 was not learned through OSPF" + assert json_cmp(json_output, expect) is None, assertmsg + +``json_cmp`` function description (it might be outdated, you can find the +latest description in the source code at +:file:`tests/topotests/lib/topotest.py` + +.. code:: text + + JSON compare function. Receives two parameters: + * `d1`: json value + * `d2`: json subset which we expect + + Returns `None` when all keys that `d1` has matches `d2`, + otherwise a string containing what failed. + + Note: key absence can be tested by adding a key with value `None`. + +Pausing execution +^^^^^^^^^^^^^^^^^ + +Preferably, choose the ``sleep`` function that ``topotest`` provides, as it +prints a notice during the test execution to help debug topology test execution +time. + +.. code:: py + + # Using the topotest sleep + from lib import topotest + + topotest.sleep(10, 'waiting 10 seconds for bla') + # or just tell it the time: + # topotest.sleep(10) + # It will print 'Sleeping for 10 seconds'. + + # Or you can also use the Python sleep, but it won't show anything + from time import sleep + sleep(5) + +iproute2 Linux commands as JSON +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``topotest`` has two helpers implemented that parses the output of ``ip route`` +commands to JSON. It might simplify your comparison needs by only needing to +provide a Python dictionary. + +.. code:: py + + from lib import topotest + + tgen = get_topogen() + routes = topotest.ip4_route(tgen.gears['r1']) + expected = { + '10.0.1.0/24': {}, + '10.0.2.0/24': { + 'dev': 'r1-eth0' + } + } + + assertmsg = "failed to find 10.0.1.0/24 and/or 10.0.2.0/24" + assert json_cmp(routes, expected) is None, assertmsg diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst new file mode 100644 index 000000000..aa06c8dff --- /dev/null +++ b/doc/developer/topotests.rst @@ -0,0 +1,927 @@ +.. _topotests: + +Topotests +========= + +Topotests is a suite of topology tests for FRR built on top of Mininet. + +Installation and Setup +---------------------- + +Only tested with Ubuntu 16.04 and Ubuntu 18.04 (which uses Mininet 2.2.x). + +Instructions are the same for all setups (i.e. ExaBGP is only used for BGP +tests). + +Installing Mininet Infrastructure +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: shell + + apt-get install mininet + apt-get install python-pip + apt-get install iproute + pip install ipaddr + pip install pytest + pip install exabgp==3.4.17 (Newer 4.0 version of exabgp is not yet + supported) + useradd -d /var/run/exabgp/ -s /bin/false exabgp + +Enable Coredumps +"""""""""""""""" + +Optional, will give better output. + +.. code:: shell + + apt-get install gdb + disable apport (which move core files) + +Set ``enabled=0`` in ``/etc/default/apport``. + +Next, update security limits by changing :file:`/etc/security/limits.conf` to:: + + #<domain> <type> <item> <value> + * soft core unlimited + root soft core unlimited + * hard core unlimited + root hard core unlimited + +Reboot for options to take effect. + +FRR Installation +^^^^^^^^^^^^^^^^ + +FRR needs to be installed separately. It is assume to be configured like the +standard Ubuntu Packages: + +- Binaries in :file:`/usr/lib/frr` +- State Directory :file:`/var/run/frr` +- Running under user ``frr``, group ``frr`` +- vtygroup: ``frrvty`` +- config directory: :file:`/etc/frr` +- For FRR Packages, install the dbg package as well for coredump decoding + +No FRR config needs to be done and no FRR daemons should be run ahead of the +test. They are all started as part of the test. + +Manual FRR build +"""""""""""""""" + +If you prefer to manually build FRR, then use the following suggested config: + +.. code:: shell + + ./configure \ + --prefix=/usr \ + --localstatedir=/var/run/frr \ + --sbindir=/usr/lib/frr \ + --sysconfdir=/etc/frr \ + --enable-vtysh \ + --enable-pimd \ + --enable-multipath=64 \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --with-pkg-extra-version=-my-manual-build + +And create ``frr`` user and ``frrvty`` group as follows: + +.. code:: shell + + addgroup --system --gid 92 frr + addgroup --system --gid 85 frrvty + adduser --system --ingroup frr --home /var/run/frr/ \ + --gecos "FRRouting suite" --shell /bin/false frr + usermod -G frrvty frr + +Executing Tests +--------------- + +Execute all tests with output to console +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: shell + + py.test -s -v --tb=no + +All test\_\* scripts in subdirectories are detected and executed (unless +disabled in ``pytest.ini`` file). + +``--tb=no`` disables the python traceback which might be irrelevant unless the +test script itself is debugged. + +Execute single test +^^^^^^^^^^^^^^^^^^^ + +.. code:: shell + + cd test_to_be_run + ./test_to_be_run.py + +For further options, refer to pytest documentation. + +Test will set exit code which can be used with ``git bisect``. + +For the simulated topology, see the description in the python file. + +If you need to clear the mininet setup between tests (if it isn't cleanly +shutdown), then use the ``mn -c`` command to clean up the environment. + +StdErr log from daemos after exit +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To enable the reporting of any messages seen on StdErr after the daemons exit, +the following env variable can be set:: + + export TOPOTESTS_CHECK_STDERR=Yes + +(The value doesn't matter at this time. The check is if the env variable exists +or not) There is no pass/fail on this reporting. The Output will be reported to +the console:: + + export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" + +This will enable the check and output to console and the writing of the +information to files with the given prefix (followed by testname), ie +:file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a memory +leak. + +Collect Memory Leak Information +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +FRR processes have the capabilities to report remaining memory allocations upon +exit. To enable the reporting of the memory, define an enviroment variable +``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.:: + + export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" + +This will enable the check and output to console and the writing of the +information to files with the given prefix (followed by testname), ie +:file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a memory +leak. + +Running Topotests with AddressSanitizer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Topotests can be run with AddressSanitizer. It requires GCC 4.8 or newer. +(Ubuntu 16.04 as suggested here is fine with GCC 5 as default). For more +information on AddressSanitizer, see +https://github.com/google/sanitizers/wiki/AddressSanitizer. + +The checks are done automatically in the library call of ``checkRouterRunning`` +(ie at beginning of tests when there is a check for all daemons running). No +changes or extra configuration for topotests is required beside compiling the +suite with AddressSanitizer enabled. + +If a daemon crashed, then the errorlog is checked for AddressSanitizer output. +If found, then this is added with context (calling test) to +:file:`/tmp/AddressSanitizer.txt` in Markdown compatible format. + +Compiling for GCC AddressSanitizer requires to use ``gcc`` as a linker as well +(instead of ``ld``). Here is a suggest way to compile frr with AddressSanitizer +for ``stable/3.0`` branch: + +.. code:: shell + + git clone https://github.com/FRRouting/frr.git + cd frr + git checkout stable/3.0 + ./bootstrap.sh + export CC=gcc + export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer" + export LD=gcc + export LDFLAGS="-g -fsanitize=address -ldl" + ./configure --enable-shared=no \ + --prefix=/usr/lib/frr --sysconfdir=/etc/frr \ + --localstatedir=/var/run/frr \ + --sbindir=/usr/lib/frr --bindir=/usr/lib/frr \ + --enable-exampledir=/usr/lib/frr/examples \ + --with-moduledir=/usr/lib/frr/modules \ + --enable-multipath=0 --enable-rtadv \ + --enable-tcp-zebra --enable-fpm --enable-pimd + make + sudo make install + # Create symlink for vtysh, so topotest finds it in /usr/lib/frr + sudo ln -s /usr/lib/frr/vtysh /usr/bin/ + +and create ``frr`` user and ``frrvty`` group as shown above. + +.. _topotests_docker: + +Running Tests with Docker +------------------------- + +There is a Docker image which allows to run topotests. + +Quickstart +^^^^^^^^^^ + +If you have Docker installed, you can run the topotests in Docker. The easiest +way to do this, is to use the make targets from this repository. + +Your current user needs to have access to the Docker daemon. Alternatively you +can run these commands as root. + +.. code:: console + + make topotests + +This command will pull the most recent topotests image from Dockerhub, compile +FRR inside of it, and run the topotests. + +Advanced Usage +^^^^^^^^^^^^^^ + +Internally, the topotests make target uses a shell script to pull the image and +spawn the Docker container. + +There are several environment variables which can be used to modify the +behavior of the script, these can be listed by calling it with ``-h``: + +.. code:: console + + ./tests/topotests/docker/frr-topotests.sh -h + +For example, a volume is used to cache build artifacts between multiple runs of +the image. If you need to force a complete recompile, you can set +``TOPOTEST_CLEAN``: + +.. code:: console + + TOPOTEST_CLEAN=1 ./tests/topotests/docker/frr-topotests.sh + +By default, ``frr-topotests.sh`` will build frr and run pytest. If you append +arguments and the first one starts with ``/`` or ``./``, they will replace the +call to pytest. If the appended arguments do not match this patttern, they will +be provided to pytest as arguments. So, to run a specific test with more +verbose logging: + +.. code:: console + + ./tests/topotests/docker/frr-topotests.sh -vv -s all-protocol-startup/test_all_protocol_startup.py + +And to compile FRR but drop into a shell instead of running pytest: + +.. code:: console + + ./tests/topotests/docker/frr-topotests.sh /bin/bash + +Development +^^^^^^^^^^^ + +The Docker image just includes all the components to run the topotests, but not +the topotests themselves. So if you just want to write tests and don't want to +make changes to the environment provided by the Docker image. You don't need to +build your own Docker image if you do not want to. + +When developing new tests, there is one caveat though: The startup script of +the container will run a ``git-clean`` on its copy of the FRR tree to avoid any +pollution of the container with build artefacts from the host. This will also +result in your newly written tests being unavailable in the container unless at +least added to the index with ``git-add``. + +If you do want to test changes to the Docker image, you can locally build the +image and run the tests without pulling from the registry using the following +commands: + +.. code:: console + + make topotests-build + TOPOTEST_PULL=0 make topotests + + +.. _topotests-guidelines: + +Guidelines +---------- + +Executing Tests +^^^^^^^^^^^^^^^ + +To run the whole suite of tests the following commands must be executed at the +top level directory of topotest: + +.. code:: shell + + $ # Change to the top level directory of topotests. + $ cd path/to/topotests + $ # Tests must be run as root, since Mininet requires it. + $ sudo pytest + +In order to run a specific test, you can use the following command: + +.. code:: shell + + $ # running a specific topology + $ sudo pytest ospf-topo1/ + $ # or inside the test folder + $ cd ospf-topo1 + $ sudo pytest # to run all tests inside the directory + $ sudo pytest test_ospf_topo1.py # to run a specific test + $ # or outside the test folder + $ cd .. + $ sudo pytest ospf-topo1/test_ospf_topo1.py # to run a specific one + +The output of the tested daemons will be available at the temporary folder of +your machine: + +.. code:: shell + + $ ls /tmp/topotest/ospf-topo1.test_ospf-topo1/r1 + ... + zebra.err # zebra stderr output + zebra.log # zebra log file + zebra.out # zebra stdout output + ... + +You can also run memory leak tests to get reports: + +.. code:: shell + + $ # Set the environment variable to apply to a specific test... + $ sudo env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py + $ # ...or apply to all tests adding this line to the configuration file + $ echo 'memleak_path = /tmp/memleak_report_' >> pytest.ini + $ # You can also use your editor + $ $EDITOR pytest.ini + $ # After running tests you should see your files: + $ ls /tmp/memleak_report_* + memleak_report_test_ospf_topo1.txt + +Writing a New Test +^^^^^^^^^^^^^^^^^^ + +This section will guide you in all recommended steps to produce a standard +topology test. + +This is the recommended test writing routine: + +- Write a topology (Graphviz recommended) +- Obtain configuration files +- Write the test itself +- Create a Pull Request + +Topotest File Hierarchy +""""""""""""""""""""""" + +Before starting to write any tests one must know the file hierarchy. The +repository hierarchy looks like this: + +.. code:: shell + + $ cd path/to/topotest + $ find ./* + ... + ./README.md # repository read me + ./GUIDELINES.md # this file + ./conftest.py # test hooks - pytest related functions + ./example-test # example test folder + ./example-test/__init__.py # python package marker - must always exist. + ./example-test/test_template.jpg # generated topology picture - see next section + ./example-test/test_template.dot # Graphviz dot file + ./example-test/test_template.py # the topology plus the test + ... + ./ospf-topo1 # the ospf topology test + ./ospf-topo1/r1 # router 1 configuration files + ./ospf-topo1/r1/zebra.conf # zebra configuration file + ./ospf-topo1/r1/ospfd.conf # ospf configuration file + ./ospf-topo1/r1/ospfroute.txt # 'show ip ospf' output reference file + # removed other for shortness sake + ... + ./lib # shared test/topology functions + ./lib/topogen.py # topogen implementation + ./lib/topotest.py # topotest implementation + +Guidelines for creating/editing topotest: + +- New topologies that don't fit the existing directories should create its own +- Always remember to add the ``__init__.py`` to new folders, this makes auto + complete engines and pylint happy +- Router (Quagga/FRR) specific code should go on topotest.py +- Generic/repeated router actions should have an abstraction in + topogen.TopoRouter. +- Generic/repeated non-router code should go to topotest.py +- pytest related code should go to conftest.py (e.g. specialized asserts) + +Defining the Topology +""""""""""""""""""""" + +The first step to write a new test is to define the topology. This step can be +done in many ways, but the recommended is to use Graphviz to generate a drawing +of the topology. It allows us to see the topology graphically and to see the +names of equipments, links and addresses. + +Here is an example of Graphviz dot file that generates the template topology +:file:`tests/topotests/example-test/test_template.dot` (the inlined code might +get outdated, please see the linked file):: + + graph template { + label="template"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon, + label="r2", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + s1 [ + shape=oval, + label="s1\n192.168.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s2 [ + shape=oval, + label="s2\n192.168.1.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- s1 [label="eth0\n.1"]; + + r1 -- s2 [label="eth1\n.100"]; + r2 -- s2 [label="eth0\n.1"]; + } + +Here is the produced graph: + +.. graphviz:: + + graph template { + label="template"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon, + label="r2", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + s1 [ + shape=oval, + label="s1\n192.168.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s2 [ + shape=oval, + label="s2\n192.168.1.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- s1 [label="eth0\n.1"]; + + r1 -- s2 [label="eth1\n.100"]; + r2 -- s2 [label="eth0\n.1"]; + } + +Generating / Obtaining Configuration Files +"""""""""""""""""""""""""""""""""""""""""" + +In order to get the configuration files or command output for each router, we +need to run the topology and execute commands in ``vtysh``. The quickest way to +achieve that is writing the topology building code and running the topology. + +To bootstrap your test topology, do the following steps: + +- Copy the template test + +.. code:: shell + + $ mkdir new-topo/ + $ touch new-topo/__init__.py + $ cp example-test/test_template.py new-topo/test_new_topo.py + +- Modify the template according to your dot file + +Here is the template topology described in the previous section in python code: + +.. code:: py + + class TemplateTopo(Topo): + "Test topology builder" + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Create 2 routers + for routern in range(1, 3): + tgen.add_router('r{}'.format(routern)) + + # Create a switch with just one router connected to it to simulate a + # empty network. + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + + # Create a connection between r1 and r2 + switch = tgen.add_switch('s2') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + +- Run the topology + +Topogen allows us to run the topology without running any tests, you can do +that using the following example commands: + +.. code:: shell + + $ # Running your bootstraped topology + $ sudo pytest -s --topology-only new-topo/test_new_topo.py + $ # Running the test_template.py topology + $ sudo pytest -s --topology-only example-test/test_template.py + $ # Running the ospf_topo1.py topology + $ sudo pytest -s --topology-only ospf-topo1/test_ospf_topo1.py + +Parameters explanation: + +.. program:: pytest + +.. option:: -s + + Actives input/output capture. This is required by mininet in order to show + the interactive shell. + +.. option:: --topology-only + + Don't run any tests, just build the topology. + +After executing the commands above, you should get the following terminal +output: + +.. code:: shell + + === test session starts === + platform linux2 -- Python 2.7.12, pytest-3.1.2, py-1.4.34, pluggy-0.4.0 + rootdir: /media/sf_src/topotests, inifile: pytest.ini + collected 3 items + + ospf-topo1/test_ospf_topo1.py *** Starting controller + + *** Starting 6 switches + switch1 switch2 switch3 switch4 switch5 switch6 ... + r2: frr zebra started + r2: frr ospfd started + r3: frr zebra started + r3: frr ospfd started + r1: frr zebra started + r1: frr ospfd started + r4: frr zebra started + r4: frr ospfd started + *** Starting CLI: + mininet> + +The last line shows us that we are now using the Mininet CLI (Command Line +Interface), from here you can call your router ``vtysh`` or even bash. + +Here are some commands example: + +.. code:: shell + + mininet> r1 ping 10.0.3.1 + PING 10.0.3.1 (10.0.3.1) 56(84) bytes of data. + 64 bytes from 10.0.3.1: icmp_seq=1 ttl=64 time=0.576 ms + 64 bytes from 10.0.3.1: icmp_seq=2 ttl=64 time=0.083 ms + 64 bytes from 10.0.3.1: icmp_seq=3 ttl=64 time=0.088 ms + ^C + --- 10.0.3.1 ping statistics --- + 3 packets transmitted, 3 received, 0% packet loss, time 1998ms + rtt min/avg/max/mdev = 0.083/0.249/0.576/0.231 ms + + + + mininet> r1 ping 10.0.3.3 + PING 10.0.3.3 (10.0.3.3) 56(84) bytes of data. + 64 bytes from 10.0.3.3: icmp_seq=1 ttl=64 time=2.87 ms + 64 bytes from 10.0.3.3: icmp_seq=2 ttl=64 time=0.080 ms + 64 bytes from 10.0.3.3: icmp_seq=3 ttl=64 time=0.091 ms + ^C + --- 10.0.3.3 ping statistics --- + 3 packets transmitted, 3 received, 0% packet loss, time 2003ms + rtt min/avg/max/mdev = 0.080/1.014/2.872/1.313 ms + + + + mininet> r3 vtysh + + Hello, this is FRRouting (version 3.1-devrzalamena-build). + Copyright 1996-2005 Kunihiro Ishiguro, et al. + + frr-1# show running-config + Building configuration... + + Current configuration: + ! + frr version 3.1-devrzalamena-build + frr defaults traditional + hostname r3 + no service integrated-vtysh-config + ! + log file zebra.log + ! + log file ospfd.log + ! + interface r3-eth0 + ip address 10.0.3.1/24 + ! + interface r3-eth1 + ip address 10.0.10.1/24 + ! + interface r3-eth2 + ip address 172.16.0.2/24 + ! + router ospf + ospf router-id 10.0.255.3 + redistribute kernel + redistribute connected + redistribute static + network 10.0.3.0/24 area 0 + network 10.0.10.0/24 area 0 + network 172.16.0.0/24 area 1 + ! + line vty + ! + end + frr-1# + +After you successfully configured your topology, you can obtain the +configuration files (per-daemon) using the following commands: + +.. code:: shell + + mininet> r3 vtysh -d ospfd + + Hello, this is FRRouting (version 3.1-devrzalamena-build). + Copyright 1996-2005 Kunihiro Ishiguro, et al. + + frr-1# show running-config + Building configuration... + + Current configuration: + ! + frr version 3.1-devrzalamena-build + frr defaults traditional + no service integrated-vtysh-config + ! + log file ospfd.log + ! + router ospf + ospf router-id 10.0.255.3 + redistribute kernel + redistribute connected + redistribute static + network 10.0.3.0/24 area 0 + network 10.0.10.0/24 area 0 + network 172.16.0.0/24 area 1 + ! + line vty + ! + end + frr-1# + +Writing Tests +""""""""""""" + +Test topologies should always be bootstrapped from +:file:`tests/topotests/example-test/test_template.py` because it contains +important boilerplate code that can't be avoided, like: + +- imports: os, sys, pytest, topotest/topogen and mininet topology class +- The global variable CWD (Current Working directory): which is most likely + going to be used to reference the routers configuration file location + +Example: + +.. code:: py + + # For all registered routers, load the zebra configuration file + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + # os.path.join() joins the CWD string with arguments adding the necessary + # slashes ('/'). Arguments must not begin with '/'. + +- The topology class that inherits from Mininet Topo class: + +.. code:: py + + class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + # topology build code + +- pytest ``setup_module()`` and ``teardown_module()`` to start the topology + +.. code:: py + + def setup_module(_m): + tgen = Topogen(TemplateTopo) + tgen.start_topology('debug') + + def teardown_module(_m): + tgen = get_topogen() + tgen.stop_topology() + +- ``__main__`` initialization code (to support running the script directly) + +.. code:: py + + if __name__ == '__main__': + sys.exit(pytest.main(["-s"])) + +Requirements: + +- Test code should always be declared inside functions that begin with the + ``test_`` prefix. Functions beginning with different prefixes will not be run + by pytest. +- Configuration files and long output commands should go into separated files + inside folders named after the equipment. +- Tests must be able to run without any interaction. To make sure your test + conforms with this, run it without the :option:`-s` parameter. + +Tips: + +- Keep results in stack variables, so people inspecting code with ``pdb`` can + easily print their values. + +Don't do this: + +.. code:: py + + assert foobar(router1, router2) + +Do this instead: + +.. code:: py + + result = foobar(router1, router2) + assert result + +- Use ``assert`` messages to indicate where the test failed. + +Example: + +.. code:: py + + for router in router_list: + # ... + assert condition, 'Router "{}" condition failed'.format(router.name) + +Debugging Execution +^^^^^^^^^^^^^^^^^^^ + +The most effective ways to inspect topology tests are: + +- Run pytest with ``--pdb`` option. This option will cause a pdb shell to + appear when an assertion fails + +Example: ``pytest -s --pdb ospf-topo1/test_ospf_topo1.py`` + +- Set a breakpoint in the test code with ``pdb`` + +Example: + +.. code:: py + + # Add the pdb import at the beginning of the file + import pdb + # ... + + # Add a breakpoint where you think the problem is + def test_bla(): + # ... + pdb.set_trace() + # ... + +The `Python Debugger <https://docs.python.org/2.7/library/pdb.html>`__ (pdb) +shell allows us to run many useful operations like: + +- Setting breaking point on file/function/conditions (e.g. ``break``, + ``condition``) +- Inspecting variables (e.g. ``p`` (print), ``pp`` (pretty print)) +- Running python code + +.. tip:: + + The TopoGear (equipment abstraction class) implements the ``__str__`` method + that allows the user to inspect equipment information. + +Example of pdb usage: + +.. code:: shell + + > /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(121)test_ospf_convergence() + -> for rnum in range(1, 5): + (Pdb) help + Documented commands (type help <topic>): + ======================================== + EOF bt cont enable jump pp run unt + a c continue exit l q s until + alias cl d h list quit step up + args clear debug help n r tbreak w + b commands disable ignore next restart u whatis + break condition down j p return unalias where + + Miscellaneous help topics: + ========================== + exec pdb + + Undocumented commands: + ====================== + retval rv + + (Pdb) list + 116 title2="Expected output") + 117 + 118 def test_ospf_convergence(): + 119 "Test OSPF daemon convergence" + 120 pdb.set_trace() + 121 -> for rnum in range(1, 5): + 122 router = 'r{}'.format(rnum) + 123 + 124 # Load expected results from the command + 125 reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) + 126 expected = open(reffile).read() + (Pdb) step + > /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(122)test_ospf_convergence() + -> router = 'r{}'.format(rnum) + (Pdb) step + > /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(125)test_ospf_convergence() + -> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) + (Pdb) print rnum + 1 + (Pdb) print router + r1 + (Pdb) tgen = get_topogen() + (Pdb) pp tgen.gears[router] + <lib.topogen.TopoRouter object at 0x7f74e06c9850> + (Pdb) pp str(tgen.gears[router]) + 'TopoGear<name="r1",links=["r1-eth0"<->"s1-eth0","r1-eth1"<->"s3-eth0"]> TopoRouter<>' + (Pdb) l 125 + 120 pdb.set_trace() + 121 for rnum in range(1, 5): + 122 router = 'r{}'.format(rnum) + 123 + 124 # Load expected results from the command + 125 -> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) + 126 expected = open(reffile).read() + 127 + 128 # Run test function until we get an result. Wait at most 60 seconds. + 129 test_func = partial(compare_show_ip_ospf, router, expected) + 130 result, diff = topotest.run_and_expect(test_func, '', + (Pdb) router1 = tgen.gears[router] + (Pdb) router1.vtysh_cmd('show ip ospf route') + '============ OSPF network routing table ============\r\nN 10.0.1.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth0\r\nN 10.0.2.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.3, r1-eth1\r\nN 10.0.3.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth1\r\nN 10.0.10.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.0.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.1.0/24 [30] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF router routing table =============\r\nR 10.0.255.2 [10] area: 0.0.0.0, ASBR\r\n via 10.0.3.3, r1-eth1\r\nR 10.0.255.3 [10] area: 0.0.0.0, ABR, ASBR\r\n via 10.0.3.1, r1-eth1\r\nR 10.0.255.4 IA [20] area: 0.0.0.0, ASBR\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF external routing table ===========\r\n\r\n\r\n' + (Pdb) tgen.mininet_cli() + *** Starting CLI: + mininet> + +To enable more debug messages in other Topogen subsystems (like Mininet), more +logging messages can be displayed by modifying the test configuration file +``pytest.ini``: + +.. code:: ini + + [topogen] + # Change the default verbosity line from 'info'... + #verbosity = info + # ...to 'debug' + verbosity = debug + +Instructions for use, write or debug topologies can be found in :ref:`topotests-guidelines`. +To learn/remember common code snippets see :ref:`topotests-snippets`. + +Before creating a new topology, make sure that there isn't one already that +does what you need. If nothing is similar, then you may create a new topology, +preferably, using the newest template +(:file:`tests/topotests/example-test/test_template.py`). + +.. include:: topotests-snippets.rst + +License +------- + +All the configs and scripts are licensed under a ISC-style license. See Python +scripts for details. diff --git a/doc/developer/zebra.rst b/doc/developer/zebra.rst index f771d4823..74a8605bf 100644 --- a/doc/developer/zebra.rst +++ b/doc/developer/zebra.rst @@ -241,7 +241,7 @@ Zebra Protocol Commands +------------------------------------+-------+ | ZEBRA_INTERFACE_DISABLE_RADV | 42 | +------------------------------------+-------+ -| ZEBRA_IPV3_NEXTHOP_LOOKUP_MRIB | 44 | +| ZEBRA_IPV3_NEXTHOP_LOOKUP_MRIB | 43 | +------------------------------------+-------+ | ZEBRA_INTERFACE_LINK_PARAMS | 44 | +------------------------------------+-------+ @@ -279,9 +279,9 @@ Zebra Protocol Commands +------------------------------------+-------+ | ZEBRA_VNI_DEL | 61 | +------------------------------------+-------+ -| ZEBRA_L2VNI_ADD | 63 | +| ZEBRA_L3VNI_ADD | 62 | +------------------------------------+-------+ -| ZEBRA_L2VNI_DEL | 64 | +| ZEBRA_L3VNI_DEL | 63 | +------------------------------------+-------+ | ZEBRA_REMOTE_VTEP_ADD | 64 | +------------------------------------+-------+ diff --git a/doc/manpages/watchfrr.rst b/doc/manpages/watchfrr.rst index f0b733298..dceb423f8 100644 --- a/doc/manpages/watchfrr.rst +++ b/doc/manpages/watchfrr.rst @@ -22,21 +22,6 @@ In order to avoid restarting the daemons in quick succession, you can supply the OPTIONS ======= -The following 3 options specify scripts that |DAEMON| uses to perform start/stop/restart actions. These options are mandatory unless the --dry option is used: - -.. option:: -s command, --start-command command - - Supply a Bourne shell command to start a single daemon. The command string should contain the '%s' placeholder to be sub‐ stituted with the daemon name. - -.. option:: -k command, --kill-command command - - Supply a Bourne shell command to stop a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. - -.. option:: -r command, --restart command - - Supply a Bourne shell command to restart a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. - -Other options: .. option:: --dry @@ -92,6 +77,20 @@ Other options: Display the usage information and exit. +The following 3 options specify scripts that |DAEMON| uses to perform start/stop/restart actions. Reasonable default values are built into watchfrr, so the use of these options should no longer be necessary: + +.. option:: -s command, --start-command command + + Supply a Bourne shell command to start a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. + +.. option:: -k command, --kill-command command + + Supply a Bourne shell command to stop a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. + +.. option:: -r command, --restart command + + Supply a Bourne shell command to restart a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. + PREVIOUS OPTIONS ================ Prior versions of |DAEMON| supported some additional options that no longer exist::: diff --git a/doc/user/_static/overrides.css b/doc/user/_static/overrides.css index 41fcc66f8..638f61986 100644 --- a/doc/user/_static/overrides.css +++ b/doc/user/_static/overrides.css @@ -3,10 +3,6 @@ div.body { max-width: none; } -pre { - background-color: #e2e2e2; -} - /* styling for the protocols vs. OS table in overview.rst */ /* first, general bits */ div.body td.mark { @@ -40,6 +36,7 @@ td.mark span { border: 1px dotted #666; width: 36pt; margin:auto; + text-align:center; } table.mark tr td:first-child { padding-left:1.5em; @@ -61,3 +58,238 @@ li span.mark { width: 36pt; text-align: center; } + +/* Palette URL: http://paletton.com/#uid=70p0p0kt6uvcDRAlhBavokxLJ6w */ + +:root { +--primary-0: #F36F16; /* Main Primary color */ +--primary-1: #FFC39A; +--primary-2: #FF9A55; +--primary-3: #A34403; +--primary-4: #341500; +--primary-9: #FFF3EB; + +--secondary-1-0: #F39C16; /* Main Secondary color (1) */ +--secondary-1-1: #FFD79A; +--secondary-1-2: #FFBC55; +--secondary-1-3: #A36403; +--secondary-1-4: #341F00; +--secondary-1-9: #FFF7EB; + +--secondary-2-0: #1A599F; /* Main Secondary color (2) */ +--secondary-2-1: #92B9E5; +--secondary-2-2: #477CB8; +--secondary-2-3: #0A386B; +--secondary-2-4: #011122; +--secondary-2-9: #E3EBF4; + +--complement-0: #0E9A83; /* Main Complement color */ +--complement-1: #8AE4D4; +--complement-2: #3CB4A0; +--complement-3: #026857; +--complement-4: #00211B; +--complement-9: #E0F4F0; +} + +/* new */ + +body { + font-family: "Fira Sans", Helvetica, Arial, sans-serif; + font-weight:400; +} +h1, h2, h3, h4, h5, h6 { + font-family: "Fira Sans", Helvetica, Arial, sans-serif; + font-weight:500; +} +code, pre, tt { + font-family: "Fira Mono"; +} +h1 { + background-color:var(--secondary-1-1); + border-bottom:1px solid var(--secondary-1-0); + font-weight:300; +} +h2 { + margin-top:36pt; +} + +a, +a:hover, +a:visited, +.code-block-caption a.headerlink:hover, +.rst-content dl:not(.docutils) dt .headerlink { + color: var(--complement-0); +} +.code-block-caption a.headerlink { + visibility:hidden; +} + +/* admonitions */ + +.admonition.warning { + border:1px dashed var(--primary-2); +} +.admonition.warning .admonition-title { + color: var(--primary-3); + background-color: var(--primary-1); +} +.admonition.note, +.admonition.hint { + border:1px dashed var(--complement-2); +} +.admonition.note .admonition-title, +.admonition.hint .admonition-title { + color: var(--complement-3); + background-color: var(--complement-1); +} +.admonition.seealso, +div.seealso { + background-color:var(--complement-9); +} +.admonition.seealso .admonition-title { + color: var(--complement-3); + background-color:var(--complement-1); + border-bottom:1px solid var(--complement-2); +} +.admonition.admonition-todo .admonition-title { + background-image: repeating-linear-gradient( + 135deg, + #ffa, + #ffa 14.14213452px, + #bbb 14.14213452px, + #bbb 28.28427124px + ); + color:#000; +} +.admonition.admonition-todo { + background-image: repeating-linear-gradient( + 135deg, + #ffd, + #ffd 14.14213452px, + #eed 14.14213452px, + #eed 28.28427124px + ); +} + +.rst-content dl .admonition p.last { + margin-bottom:0 !important; +} + +/* file block */ + +.code-block-caption { +/* border-radius: 4px; */ + font-style:italic; + font-weight:300; + border-bottom: 1px solid var(--secondary-2-1); + background-color: var(--secondary-2-9); + padding:2px 8px; +} + +/* navbar */ + +.wy-nav-side { + background-color: var(--secondary-1-4); + border-right:2px solid var(--primary-3); +} +.wy-menu-vertical a, +.wy-menu-vertical a:visited, +.wy-menu-vertical a:hover, +.wy-side-nav-search>a, +.wy-side-nav-search .wy-dropdown>a { + color: var(--primary-0); +} + +nav div.wy-side-nav-search { + background-color: #eee; +} +nav div.wy-side-scroll { + background-color: var(--secondary-1-4); +} +nav .wy-menu-vertical a:hover { + background-color:var(--primary-0); + color:var(--primary-4); +} +nav .wy-menu-vertical li.current ul a:hover { + background-color:var(--secondary-1-2); + color:var(--primary-4); +} +nav .wy-menu-vertical li.current ul a { + background-color:var(--secondary-1-1); + color:var(--primary-3); +} +nav .wy-menu-vertical li.on a:hover, +nav .wy-menu-vertical li.current>a:hover { + background-color:#fcfcfc; +} +.wy-side-nav-search input[type=text] { + border-color:var(--primary-2); +} +.wy-menu-vertical li.toctree-l1.current>a { + border-top:1px solid var(--secondary-1-3); + border-bottom:1px solid var(--secondary-1-3); +} +.wy-menu-vertical li.toctree-l2.current>a { + background-color:var(--secondary-1-2); +} +.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a { + background-color:var(--secondary-1-9); +} + +.wy-nav-content { + padding: 25pt 40pt; +} +div[role=navigation] > hr { + display:none; +} +div[role=navigation] { + margin-bottom:15pt; +} +h1 { + margin-left:-40pt; + margin-right:-40pt; + padding:5pt 40pt 5pt 40pt; +} + +.rst-content pre.literal-block, .rst-content div[class^='highlight'] { + border-color:var(--secondary-1-1); +} + +span.pre { + color: var(--complement-3); +} +pre { + background-color: var(--secondary-1-9); + border-color: var(--secondary-1-1); +} +.highlight .p { color: var(--secondary-2-3); } +.highlight .k { color: var(--secondary-2-0); } +.highlight .kt { color: var(--complement-0); } +.highlight .cm { color: var(--primary-3); } +.highlight .ow { color: var(--primary-3); } +.highlight .na { color: var(--primary-2); } +.highlight .nv { color: var(--complement-0); } + +strong { + font-weight:500; +} +.rst-content dl:not(.docutils) dt { + font-family:Fira Mono; + font-weight:600; + background-color:var(--secondary-2-9); + color:var(--secondary-2-3); + border-top:2px solid var(--secondary-2-2); +} +dt code.descname { + color: var(--secondary-2-4); +} + +@media (min-width: 1200px) { + .container { width: auto; } +} +@media (min-width: 992px) { + .container { width: auto; } +} +@media (min-width: 768px) { + .container { width: auto; } +} diff --git a/doc/user/conf.py b/doc/user/conf.py index 57a7c0847..558284743 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -168,12 +168,19 @@ todo_include_todos = True # a list of builtin themes. html_theme = 'default' +try: + import sphinx_rtd_theme + + html_theme = 'sphinx_rtd_theme' +except ImportError: + pass + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -html_theme_options = { - 'sidebarbgcolor': '#374249' -} +#html_theme_options = { +# 'sidebarbgcolor': '#374249' +#} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] diff --git a/doc/user/installation.rst b/doc/user/installation.rst index ebca53ea3..4e1582ccd 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -335,6 +335,9 @@ options to the configuration script. Look for libyang plugins in `dir` [`prefix`/lib/frr/libyang_plugins]. Note that the FRR libyang plugins will be installed here. + This option is meaningless with libyang 0.16.74 or newer and will be + removed once support for older libyang versions is dropped. + When it's desired to run FRR without installing it in the system, it's possible to configure it as follows to look for YANG modules and libyang plugins in the compile directory: diff --git a/doc/user/ipv6.rst b/doc/user/ipv6.rst index 585c3a505..cc8fd18fe 100644 --- a/doc/user/ipv6.rst +++ b/doc/user/ipv6.rst @@ -179,10 +179,56 @@ Router Advertisement hosts in proper interface configuration. The announced value is not verified to be consistent with router interface MTU. - Default: don't advertise any MTU option.:: - interface eth0 - no ipv6 nd suppress-ra - ipv6 nd prefix 2001:0DB8:5009::/64 + Default: don't advertise any MTU option. + +.. index:: + single: ipv6 nd rdnss ipv6address [lifetime] + single: no ipv6 nd rdnss ipv6address [lifetime] +.. clicmd:: [no] ipv6 nd rdnss ipv6address [lifetime] + + Recursive DNS server address to advertise using the RDNSS (type 25) option + described in RFC8106. Can be specified more than once to advertise multiple + addresses. Note that hosts may choose to limit the number of RDNSS addresses + to track. + + Optional parameter: + + - ``lifetime``: the maximum time in seconds over which the specified address + may be used for domain name resolution. Value ``infinite`` represents + infinity (i.e. a value of all one bits (``0xffffffff``)). A value of 0 + indicates that the address must no longer be used. + Range: ``(0-4294967295)`` Default: ``3 * ra-interval`` + + Default: do not emit RDNSS option + +.. index:: + single: ipv6 nd dnssl domain-name-suffix [lifetime] + single: no ipv6 nd dnssl domain-name-suffix [lifetime] +.. clicmd:: [no] ipv6 nd dnssl domain-name-suffix [lifetime] + + Advertise DNS search list using the DNSSL (type 31) option described in + RFC8106. Specify more than once to advertise multiple domain name suffixes. + Host implementations may limit the number of honored search list entries. + + Optional parameter: + + - ``lifetime``: the maximum time in seconds over which the specified domain + suffix may be used in the course of name resolution. Value ``infinite`` + represents infinity (i.e. a value of all one bits (``0xffffffff``)). A + value of 0 indicates that the name suffix must no longer be used. + Range: ``(0-4294967295)`` Default: ``3 * ra-interval`` + + Default: do not emit DNSSL option + +Router Advertisement Configuration Example +========================================== +A small example: + +.. code-block:: frr + + interface eth0 + no ipv6 nd suppress-ra + ipv6 nd prefix 2001:0DB8:5009::/64 .. seealso:: @@ -191,3 +237,4 @@ Router Advertisement - :rfc:`4861` (Neighbor Discovery for IP Version 6 (IPv6)) - :rfc:`6275` (Mobility Support in IPv6) - :rfc:`4191` (Default Router Preferences and More-Specific Routes) + - :rfc:`8106` (IPv6 Router Advertisement Options for DNS Configuration) diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index 42a8250ae..ef9ebe8dd 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -38,11 +38,12 @@ to four distinct sets of clauses: the ordered entry in the route-map. See below. Call Action - Call to another route-map, after any :term:`Set Actions` have been carried out. - If the route-map called returns `deny` then processing of the route-map - finishes and the route is denied, regardless of the :term:Matching Policy` or - the :term:`Exit Policy`. If the called route-map returns `permit`, then - :term:`Matching Policy` and :term:`Exit Policy` govern further behaviour, as normal. + Call to another route-map, after any :term:`Set Actions` have been + carried out. If the route-map called returns `deny` then processing of + the route-map finishes and the route is denied, regardless of the + :term:`Matching Policy` or the :term:`Exit Policy`. If the called + route-map returns `permit`, then :term:`Matching Policy` and :term:`Exit + Policy` govern further behaviour, as normal. Exit Policy An entry may, optionally, specify an alternative :dfn:`Exit Policy` to diff --git a/doc/user/setup.rst b/doc/user/setup.rst index 3a09c5030..ffefe3790 100644 --- a/doc/user/setup.rst +++ b/doc/user/setup.rst @@ -72,13 +72,14 @@ This file has several parts. Here is an example: fabricd_options=" --daemon -A 127.0.0.1" # The list of daemons to watch is automatically generated by the init script. - watchfrr_enable=yes - watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB) + #watchfrr_options="" - # If valgrind_enable is 'yes' the frr daemons will be started via valgrind. - # The use case for doing so is tracking down memory leaks, etc in frr. - valgrind_enable=no - valgrind=/usr/bin/valgrind + # for debugging purposes, you can specify a "wrap" command to start instead + # of starting the daemon directly, e.g. to use valgrind on ospfd: + # ospfd_wrap="/usr/bin/valgrind" + # or you can use "all_wrap" for all daemons, e.g. to use perf record: + # all_wrap="/usr/bin/perf record --call-graph -" + # the normal daemon command is added to this at the end. Breaking this file down: @@ -101,22 +102,8 @@ from the service script. Usually daemons will have ``--daemon`` and ``-A <address>`` specified in order to daemonize and listen for VTY commands on a particular address. -:: - - # The list of daemons to watch is automatically generated by the init script. - watchfrr_enable=yes - watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB) - -Options for the ``watchfrr``, the watchdog daemon. - -:: - - valgrind_enable=no - valgrind=/usr/bin/valgrind - -Whether or not to start FRR daemons under Valgrind. This is primarily useful -for gathering information for bug reports and for developers. -``valgrind_enable`` should be ``no`` for production use. +The remaining file content regarding `watchfrr_options` and `*_wrap` settings +should not normally be needed; refer to the comments in case they are. Services -------- diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index c2d32a718..ca8f1f512 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -56,6 +56,14 @@ keyword. At present, no sharp commands will be preserved in the config. log and when all routes have been successfully deleted the debug log will be updated with this information as well. +.. index:: sharp data route +.. clicmd:: sharp data route + + Allow end user doing route install and deletion to get timing information + from the vty or vtysh instead of having to read the log file. This command + is informational only and you should look at sharp_vty.c for explanation + of the output as that it may change. + .. index:: sharp label .. clicmd:: sharp label <ipv4|ipv6> vrf NAME label (0-1000000) @@ -63,7 +71,18 @@ keyword. At present, no sharp commands will be preserved in the config. be used for pop and forward operations when the specified label is seen. .. index:: sharp watch -.. clicmd:: sharp watch nexthop <A.B.C.D|X:X::X:X> +.. clicmd:: [no] sharp watch <nexthop|import> <A.B.C.D|X:X::X:X> [connected] Instruct zebra to monitor and notify sharp when the specified nexthop is changed. The notification from zebra is written into the debug log. + The nexthop or import choice chooses the type of nexthop we are asking + zebra to watch for us. This choice affects zebra's decision on what + matches. Connected tells zebra whether or not that we want the route + matched against to be a static or connected route. The no form of + the command obviously turns this watching off. + +.. index:: sharp data nexthop +.. clicmd:: sharp data nexthop + + Allow end user to dump associated data with the nexthop tracking that + may have been turned on. diff --git a/doc/user/vtysh.rst b/doc/user/vtysh.rst index 07109a0e5..6d569f5fb 100644 --- a/doc/user/vtysh.rst +++ b/doc/user/vtysh.rst @@ -22,6 +22,37 @@ administrator with an external editor. have effect for vtysh) need to be manually updated in :file:`vtysh.conf`. +Pager usage +=========== + +*vtysh* can call an external paging program (e.g. *more* or *less*) to +paginate long output from commands. This feature used to be enabled by +default but is now controlled by the ``VTYSH_PAGER`` environment variable +and the :clicmd:`terminal paginate` command: + +.. envvar:: VTYSH_PAGER + + If set, the ``VTYSH_PAGER`` environment variable causes *vtysh* to pipe + output from commands through the given command. Note that this happens + regardless of the length of the output. As such, standard pager behavior + (particularly waiting at the end of output) tends to be annoying to the + user. Using ``less -EFX`` is recommended for a better user experience. + + If this environment variable is unset, *vtysh* defaults to not using any + pager. + + This variable should be set by the user according to their preferences, + in their :file:`~/.profile` file. + +.. index:: [no] terminal paginate +.. clicmd:: [no] terminal paginate + + Enables/disables vtysh output pagination. This command is intended to + be placed in :file:`vtysh.conf` to set a system-wide default. If this + is enabled but ``VTYSH_PAGER`` is not set, the system default pager + (likely ``more`` or ``/usr/bin/pager``) will be used. + + Permissions and setup requirements ================================== diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile new file mode 100644 index 000000000..4f192ec33 --- /dev/null +++ b/docker/debian/Dockerfile @@ -0,0 +1,10 @@ +FROM debian:stretch +MAINTAINER Rob Gil (rob@rem5.com) +RUN apt-get update +RUN apt-get install -y libpcre3-dev apt-transport-https ca-certificates curl wget logrotate \ + libc-ares2 libjson-c3 vim systemd procps +RUN curl -sLO https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Debian-9-x86_64-Packages/libyang_0.16.46_amd64.deb && dpkg -i libyang_0.16.46_amd64.deb +RUN curl -sLO https://github.com/FRRouting/frr/releases/download/frr-6.0.2/frr_6.0.2-0.deb9u1_amd64.deb && dpkg -i frr_6.0.2-0.deb9u1_amd64.deb +ADD daemons /etc/frr/daemons +ADD docker-start /usr/sbin/docker-start +ENTRYPOINT ["/usr/sbin/docker-start"] diff --git a/docker/debian/README.md b/docker/debian/README.md new file mode 100644 index 000000000..b10d696a7 --- /dev/null +++ b/docker/debian/README.md @@ -0,0 +1,17 @@ +# Debian9 Docker +This is a binary docker container build of debian9. + +# Build +``` +docker build --rm -t frr:6.0.2 . +``` + +# Running +``` +docker run -itd --privileged --name frr frr:latest +``` + +vtysh +``` +docker exec -it frr vtysh +``` diff --git a/docker/debian/daemons b/docker/debian/daemons new file mode 100644 index 000000000..ed4d98e1f --- /dev/null +++ b/docker/debian/daemons @@ -0,0 +1,65 @@ +# This file tells the frr package which daemons to start. +# +# Sample configurations for these daemons can be found in +# /usr/share/doc/frr/examples/. +# +# ATTENTION: +# +# When activation a daemon at the first time, a config file, even if it is +# empty, has to be present *and* be owned by the user and group "frr", else +# the daemon will not be started by /etc/init.d/frr. The permissions should +# be u=rw,g=r,o=. +# When using "vtysh" such a config file is also needed. It should be owned by +# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. +# +# The watchfrr and zebra daemons are always started. +# +bgpd=yes +ospfd=no +ospf6d=no +ripd=no +ripngd=no +isisd=no +pimd=no +ldpd=no +nhrpd=no +eigrpd=no +babeld=no +sharpd=no +pbrd=no +bfdd=no +fabricd=no + +# +# If this option is set the /etc/init.d/frr script automatically loads +# the config via "vtysh -b" when the servers are started. +# Check /etc/pam.d/frr if you intend to use "vtysh"! +# +vtysh_enable=yes +zebra_options=" -A 127.0.0.1 -s 90000000" +bgpd_options=" -A 127.0.0.1" +ospfd_options=" -A 127.0.0.1" +ospf6d_options=" -A ::1" +ripd_options=" -A 127.0.0.1" +ripngd_options=" -A ::1" +isisd_options=" -A 127.0.0.1" +pimd_options=" -A 127.0.0.1" +ldpd_options=" -A 127.0.0.1" +nhrpd_options=" -A 127.0.0.1" +eigrpd_options=" -A 127.0.0.1" +babeld_options=" -A 127.0.0.1" +sharpd_options=" -A 127.0.0.1" +pbrd_options=" -A 127.0.0.1" +staticd_options="-A 127.0.0.1" +bfdd_options=" -A 127.0.0.1" +fabricd_options="-A 127.0.0.1" + +# The list of daemons to watch is automatically generated by the init script. +watchfrr_options="-r '/usr/lib/frr/watchfrr.sh restart %s' -s '/usr/lib/frr/watchfrr.sh start %s' -k '/usr/lib/frr/watchfrr.sh stop %s'" + +# for debugging purposes, you can specify a "wrap" command to start instead +# of starting the daemon directly, e.g. to use valgrind on ospfd: +# ospfd_wrap="/usr/bin/valgrind" +# or you can use "all_wrap" for all daemons, e.g. to use perf record: +# all_wrap="/usr/bin/perf record --call-graph -" +# the normal daemon command is added to this at the end. diff --git a/docker/debian/docker-start b/docker/debian/docker-start new file mode 100755 index 000000000..43854ab14 --- /dev/null +++ b/docker/debian/docker-start @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +## +# For volume mounts... +## +chown -R frr:frr /etc/frr +/etc/init.d/frr start +exec sleep 10000d diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c index c975c0abc..583db6622 100644 --- a/eigrpd/eigrp_dump.c +++ b/eigrpd/eigrp_dump.c @@ -174,7 +174,7 @@ const char *eigrp_if_ip_string(struct eigrp_interface *ei) if (!ei) return "inactive"; - ifaddr = ntohl(ei->address->u.prefix4.s_addr); + ifaddr = ntohl(ei->address.u.prefix4.s_addr); snprintf(buf, EIGRP_IF_STRING_MAXLEN, "%u.%u.%u.%u", (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, (ifaddr >> 8) & 0xff, ifaddr & 0xff); @@ -301,14 +301,14 @@ void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn) } void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp, - struct eigrp_nexthop_entry *te, int *first) + struct eigrp_nexthop_entry *te, bool *first) { if (te->reported_distance == EIGRP_MAX_METRIC) return; if (*first) { show_ip_eigrp_prefix_entry(vty, te->prefix); - *first = 0; + *first = false; } if (te->adv_router == eigrp->neighbor_self) @@ -605,7 +605,7 @@ static struct cmd_node eigrp_debug_node = { }; /* Initialize debug commands. */ -void eigrp_debug_init() +void eigrp_debug_init(void) { install_node(&eigrp_debug_node, config_write_debug); diff --git a/eigrpd/eigrp_dump.h b/eigrpd/eigrp_dump.h index 389ac1b5f..34b55ab41 100644 --- a/eigrpd/eigrp_dump.h +++ b/eigrpd/eigrp_dump.h @@ -156,8 +156,9 @@ extern void show_ip_eigrp_neighbor_sub(struct vty *, struct eigrp_neighbor *, int); extern void show_ip_eigrp_prefix_entry(struct vty *, struct eigrp_prefix_entry *); -extern void show_ip_eigrp_nexthop_entry(struct vty *, struct eigrp *, - struct eigrp_nexthop_entry *, int *); +extern void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp, + struct eigrp_nexthop_entry *ne, + bool *first); extern void eigrp_debug_init(void); diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c index 413a35f2f..b4d850be0 100644 --- a/eigrpd/eigrp_hello.c +++ b/eigrpd/eigrp_hello.c @@ -248,7 +248,7 @@ static void eigrp_peer_termination_decode(struct eigrp_neighbor *nbr, struct TLV_Peer_Termination_type *param = (struct TLV_Peer_Termination_type *)tlv; - uint32_t my_ip = nbr->ei->address->u.prefix4.s_addr; + uint32_t my_ip = nbr->ei->address.u.prefix4.s_addr; uint32_t received_ip = param->neighbor_ip; if (my_ip == received_ip) { diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c index e450c7d99..c52a98ee2 100644 --- a/eigrpd/eigrp_interface.c +++ b/eigrpd/eigrp_interface.c @@ -68,7 +68,7 @@ struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp, /* Set zebra interface pointer. */ ei->ifp = ifp; - ei->address = p; + prefix_copy(&ei->address, p); ifp->info = ei; listnode_add(eigrp->eiflist, ei); @@ -114,6 +114,8 @@ int eigrp_if_delete_hook(struct interface *ifp) eigrp = ei->eigrp; listnode_delete(eigrp->eiflist, ei); + eigrp_fifo_free(ei->obuf); + XFREE(MTYPE_EIGRP_IF_INFO, ifp->info); ifp->info = NULL; @@ -122,7 +124,7 @@ int eigrp_if_delete_hook(struct interface *ifp) struct list *eigrp_iflist; -void eigrp_if_init() +void eigrp_if_init(void) { /* Initialize Zebra interface data structure. */ // hook_register_prio(if_add, 0, eigrp_if_new); @@ -183,7 +185,7 @@ int eigrp_if_up(struct eigrp_interface *ei) struct prefix dest_addr; - dest_addr = *ei->address; + dest_addr = ei->address; apply_mask(&dest_addr); pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table, &dest_addr); @@ -265,16 +267,11 @@ void eigrp_if_stream_unset(struct eigrp_interface *ei) { struct eigrp *eigrp = ei->eigrp; - if (ei->obuf) { - eigrp_fifo_free(ei->obuf); - ei->obuf = NULL; - - if (ei->on_write_q) { - listnode_delete(eigrp->oi_write_q, ei); - if (list_isempty(eigrp->oi_write_q)) - thread_cancel(eigrp->t_write); - ei->on_write_q = 0; - } + if (ei->on_write_q) { + listnode_delete(eigrp->oi_write_q, ei); + if (list_isempty(eigrp->oi_write_q)) + thread_cancel(eigrp->t_write); + ei->on_write_q = 0; } } @@ -295,7 +292,7 @@ void eigrp_if_set_multicast(struct eigrp_interface *ei) /* The interface should belong to the EIGRP-all-routers group. */ if (!ei->member_allrouters - && (eigrp_if_add_allspfrouters(ei->eigrp, ei->address, + && (eigrp_if_add_allspfrouters(ei->eigrp, &ei->address, ei->ifp->ifindex) >= 0)) /* Set the flag only if the system call to join @@ -306,7 +303,7 @@ void eigrp_if_set_multicast(struct eigrp_interface *ei) * group. */ if (ei->member_allrouters) { /* Only actually drop if this is the last reference */ - eigrp_if_drop_allspfrouters(ei->eigrp, ei->address, + eigrp_if_drop_allspfrouters(ei->eigrp, &ei->address, ei->ifp->ifindex); /* Unset the flag regardless of whether the system call to leave @@ -342,7 +339,7 @@ void eigrp_if_free(struct eigrp_interface *ei, int source) eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL); } - dest_addr = *ei->address; + dest_addr = ei->address; apply_mask(&dest_addr); pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table, &dest_addr); @@ -351,7 +348,6 @@ void eigrp_if_free(struct eigrp_interface *ei, int source) eigrp_if_down(ei); - list_delete(&ei->nbrs); listnode_delete(ei->eigrp->eiflist, ei); } @@ -379,7 +375,7 @@ struct eigrp_interface *eigrp_if_lookup_by_local_addr(struct eigrp *eigrp, if (ifp && ei->ifp != ifp) continue; - if (IPV4_ADDR_SAME(&address, &ei->address->u.prefix4)) + if (IPV4_ADDR_SAME(&address, &ei->address.u.prefix4)) return ei; } diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index b19b383e6..3db59a838 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -211,10 +211,7 @@ int main(int argc, char **argv, char **envp) /*eigrp_route_map_init(); route_map_add_hook (eigrp_rmap_update); route_map_delete_hook (eigrp_rmap_update);*/ - /*if_rmap_init (EIGRP_NODE); - if_rmap_hook_add (eigrp_if_rmap_update); - if_rmap_hook_delete (eigrp_if_rmap_update);*/ - + /*if_rmap_init (EIGRP_NODE); */ /* Distribute list install. */ distribute_list_init(EIGRP_NODE); diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c index 6bb619f0e..76f8cfc93 100644 --- a/eigrpd/eigrp_network.c +++ b/eigrpd/eigrp_network.c @@ -293,7 +293,7 @@ void eigrp_if_update(struct interface *ifp) */ for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) { /* EIGRP must be on and Router-ID must be configured. */ - if (!eigrp || eigrp->router_id.s_addr == 0) + if (eigrp->router_id.s_addr == 0) continue; /* Run each network for this interface. */ @@ -333,7 +333,7 @@ int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p) if (rn->info == NULL) continue; - if (eigrp_network_match_iface(ei->address, &rn->p)) { + if (eigrp_network_match_iface(&ei->address, &rn->p)) { found = true; route_unlock_node(rn); break; diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c index f3b583abd..bedaf15c4 100644 --- a/eigrpd/eigrp_packet.c +++ b/eigrpd/eigrp_packet.c @@ -281,7 +281,7 @@ int eigrp_make_sha256_digest(struct eigrp_interface *ei, struct stream *s, return 0; } - inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, PREFIX_STRLEN); + inet_ntop(AF_INET, &ei->address.u.prefix4, source_ip, PREFIX_STRLEN); memset(&ctx, 0, sizeof(ctx)); buffer[0] = '\n'; @@ -362,7 +362,7 @@ int eigrp_write(struct thread *thread) } if (ep->dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) - eigrp_if_ipmulticast(eigrp, ei->address, ei->ifp->ifindex); + eigrp_if_ipmulticast(eigrp, &ei->address, ei->ifp->ifindex); memset(&iph, 0, sizeof(struct ip)); memset(&sa_dst, 0, sizeof(sa_dst)); @@ -418,7 +418,7 @@ int eigrp_write(struct thread *thread) iph.ip_ttl = EIGRP_IP_TTL; iph.ip_p = IPPROTO_EIGRPIGP; iph.ip_sum = 0; - iph.ip_src.s_addr = ei->address->u.prefix4.s_addr; + iph.ip_src.s_addr = ei->address.u.prefix4.s_addr; iph.ip_dst.s_addr = ep->dst.s_addr; memset(&msg, 0, sizeof(msg)); @@ -547,7 +547,7 @@ int eigrp_read(struct thread *thread) /* Self-originated packet should be discarded silently. */ if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src) - || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address->u.prefix4))) { + || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address.u.prefix4))) { if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) zlog_debug( "eigrp_read[%s]: Dropping self-originated packet", @@ -581,7 +581,7 @@ int eigrp_read(struct thread *thread) sizeof(buf[0])), inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])), - inet_ntop(AF_INET, &ei->address->u.prefix4, + inet_ntop(AF_INET, &ei->address.u.prefix4, buf[2], sizeof(buf[2]))); if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) { @@ -981,9 +981,9 @@ static int eigrp_check_network_mask(struct eigrp_interface *ei, if (ei->type == EIGRP_IFTYPE_POINTOPOINT) return 1; - masklen2ip(ei->address->prefixlen, &mask); + masklen2ip(ei->address.prefixlen, &mask); - me.s_addr = ei->address->u.prefix4.s_addr & mask.s_addr; + me.s_addr = ei->address.u.prefix4.s_addr & mask.s_addr; him.s_addr = ip_src.s_addr & mask.s_addr; if (IPV4_ADDR_SAME(&me, &him)) @@ -1101,7 +1101,7 @@ struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old, return new; } -static struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new() +static struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new(void) { struct TLV_IPv4_Internal_type *new; @@ -1327,7 +1327,7 @@ uint16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *s, return 0; } -struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new() +struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new(void) { struct TLV_MD5_Authentication_Type *new; @@ -1342,7 +1342,7 @@ void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *authTLV) XFREE(MTYPE_EIGRP_AUTH_TLV, authTLV); } -struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new() +struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new(void) { struct TLV_SHA256_Authentication_Type *new; @@ -1363,7 +1363,7 @@ void eigrp_IPv4_InternalTLV_free( XFREE(MTYPE_EIGRP_IPV4_INT_TLV, IPv4_InternalTLV); } -struct TLV_Sequence_Type *eigrp_SequenceTLV_new() +struct TLV_Sequence_Type *eigrp_SequenceTLV_new(void) { struct TLV_Sequence_Type *new; diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h index 644ab0829..a78e5a53c 100644 --- a/eigrpd/eigrp_structs.h +++ b/eigrpd/eigrp_structs.h @@ -180,7 +180,7 @@ struct eigrp_interface { /* EIGRP Network Type. */ uint8_t type; - struct prefix *address; /* Interface prefix */ + struct prefix address; /* Interface prefix */ /* Neighbor information. */ struct list *nbrs; /* EIGRP Neighbor List */ diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c index 0cb4e0e9f..e861cdb33 100644 --- a/eigrpd/eigrp_topology.c +++ b/eigrpd/eigrp_topology.c @@ -61,7 +61,7 @@ static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *, * del - assigned function executed before deleting topology node by list * function */ -struct route_table *eigrp_topology_new() +struct route_table *eigrp_topology_new(void) { return route_table_init(); } @@ -70,7 +70,7 @@ struct route_table *eigrp_topology_new() * Returns new created toplogy node * cmp - assigned function for comparing topology entry */ -struct eigrp_prefix_entry *eigrp_prefix_entry_new() +struct eigrp_prefix_entry *eigrp_prefix_entry_new(void) { struct eigrp_prefix_entry *new; new = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY, @@ -102,7 +102,7 @@ static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *entry1, * Returns new topology entry */ -struct eigrp_nexthop_entry *eigrp_nexthop_entry_new() +struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void) { struct eigrp_nexthop_entry *new; @@ -141,10 +141,10 @@ void eigrp_prefix_entry_add(struct route_table *topology, __PRETTY_FUNCTION__, prefix2str(pe->destination, buf, sizeof(buf))); } + route_unlock_node(rn); } rn->info = pe; - route_lock_node(rn); } /* @@ -161,7 +161,7 @@ void eigrp_nexthop_entry_add(struct eigrp_prefix_entry *node, listnode_add_sort(node->entries, entry); entry->prefix = node; - eigrp_zebra_route_add(node->destination, l); + eigrp_zebra_route_add(node->destination, l, node->fdistance); } list_delete(&l); @@ -477,7 +477,8 @@ void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix) successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths); if (successors) { - eigrp_zebra_route_add(prefix->destination, successors); + eigrp_zebra_route_add(prefix->destination, successors, + prefix->fdistance); for (ALL_LIST_ELEMENTS_RO(successors, node, entry)) entry->flags |= EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG; diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c index 474f68398..a9b103de4 100644 --- a/eigrpd/eigrp_vty.c +++ b/eigrpd/eigrp_vty.c @@ -455,9 +455,33 @@ DEFUN (no_eigrp_neighbor, return CMD_SUCCESS; } -DEFUN (show_ip_eigrp_topology, - show_ip_eigrp_topology_cmd, - "show ip eigrp topology [all-links]", +static void eigrp_vty_display_prefix_entry(struct vty *vty, + struct eigrp *eigrp, + struct eigrp_prefix_entry *pe, + bool all) +{ + bool first = true; + struct eigrp_nexthop_entry *te; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(pe->entries, node, te)) { + if (all + || (((te->flags + & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) + == EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) + || ((te->flags + & EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG) + == EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG))) { + show_ip_eigrp_nexthop_entry(vty, eigrp, te, + &first); + first = false; + } + } +} + +DEFPY (show_ip_eigrp_topology_all, + show_ip_eigrp_topology_all_cmd, + "show ip eigrp topology [all-links$all]", SHOW_STR IP_STR "IP-EIGRP show commands\n" @@ -465,11 +489,8 @@ DEFUN (show_ip_eigrp_topology, "Show all links in topology table\n") { struct eigrp *eigrp; - struct listnode *node; struct eigrp_prefix_entry *tn; - struct eigrp_nexthop_entry *te; struct route_node *rn; - int first; eigrp = eigrp_lookup(); if (eigrp == NULL) { @@ -484,34 +505,63 @@ DEFUN (show_ip_eigrp_topology, continue; tn = rn->info; - first = 1; - for (ALL_LIST_ELEMENTS_RO(tn->entries, node, te)) { - if (argc == 5 - || (((te->flags - & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) - == EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) - || ((te->flags - & EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG) - == EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG))) { - show_ip_eigrp_nexthop_entry(vty, eigrp, te, - &first); - first = 0; - } - } + eigrp_vty_display_prefix_entry(vty, eigrp, tn, + all ? true : false); } return CMD_SUCCESS; + } -ALIAS(show_ip_eigrp_topology, show_ip_eigrp_topology_detail_cmd, - "show ip eigrp topology <A.B.C.D|A.B.C.D/M|detail|summary>", - SHOW_STR IP_STR - "IP-EIGRP show commands\n" - "IP-EIGRP topology\n" - "Netwok to display information about\n" - "IP prefix <network>/<length>, e.g., 192.168.0.0/16\n" - "Show all links in topology table\n" - "Show a summary of the topology table\n") +DEFPY (show_ip_eigrp_topology, + show_ip_eigrp_topology_cmd, + "show ip eigrp topology <A.B.C.D$address|A.B.C.D/M$prefix>", + SHOW_STR + IP_STR + "IP-EIGRP show commands\n" + "IP-EIGRP topology\n" + "For a specific address\n" + "For a specific prefix\n") +{ + struct eigrp *eigrp; + struct eigrp_prefix_entry *tn; + struct route_node *rn; + struct prefix cmp; + + eigrp = eigrp_lookup(); + if (eigrp == NULL) { + vty_out(vty, " EIGRP Routing Process not enabled\n"); + return CMD_SUCCESS; + } + + show_ip_eigrp_topology_header(vty, eigrp); + + if (address_str) + prefix_str = address_str; + + if (str2prefix(prefix_str, &cmp) < 0) { + vty_out(vty, "%% Malformed address\n"); + return CMD_WARNING; + } + + rn = route_node_match(eigrp->topology_table, &cmp); + if (!rn) { + vty_out(vty, "%% Network not in table\n"); + return CMD_WARNING; + } + + if (!rn->info) { + vty_out(vty, "%% Network not in table\n"); + route_unlock_node(rn); + return CMD_WARNING; + } + + tn = rn->info; + eigrp_vty_display_prefix_entry(vty, eigrp, tn, argc == 5); + + route_unlock_node(rn); + return CMD_SUCCESS; +} DEFUN (show_ip_eigrp_interfaces, show_ip_eigrp_interfaces_cmd, @@ -1485,8 +1535,7 @@ void eigrp_vty_show_init(void) install_element(VIEW_NODE, &show_ip_eigrp_neighbors_cmd); install_element(VIEW_NODE, &show_ip_eigrp_topology_cmd); - - install_element(VIEW_NODE, &show_ip_eigrp_topology_detail_cmd); + install_element(VIEW_NODE, &show_ip_eigrp_topology_all_cmd); } /* eigrpd's interface node. */ diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index a810e0146..dc1ae675b 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -258,7 +258,8 @@ static int eigrp_interface_address_delete(int command, struct zclient *zclient, return 0; /* Call interface hook functions to clean up */ - eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA); + if (prefix_cmp(&ei->address, c->address) == 0) + eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA); connected_free(c); @@ -353,7 +354,8 @@ static struct interface *zebra_interface_if_lookup(struct stream *s) return if_lookup_by_name(ifname_tmp, VRF_DEFAULT); } -void eigrp_zebra_route_add(struct prefix *p, struct list *successors) +void eigrp_zebra_route_add(struct prefix *p, struct list *successors, + uint32_t distance) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -368,9 +370,11 @@ void eigrp_zebra_route_add(struct prefix *p, struct list *successors) api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_EIGRP; api.safi = SAFI_UNICAST; + api.metric = distance; memcpy(&api.prefix, p, sizeof(*p)); SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); /* Nexthop, ifindex, distance and metric information. */ for (ALL_LIST_ELEMENTS_RO(successors, node, te)) { diff --git a/eigrpd/eigrp_zebra.h b/eigrpd/eigrp_zebra.h index 1c418ddde..86b337cfe 100644 --- a/eigrpd/eigrp_zebra.h +++ b/eigrpd/eigrp_zebra.h @@ -33,7 +33,8 @@ extern void eigrp_zebra_init(void); -extern void eigrp_zebra_route_add(struct prefix *, struct list *); +extern void eigrp_zebra_route_add(struct prefix *, struct list *, + uint32_t distance); extern void eigrp_zebra_route_delete(struct prefix *); extern int eigrp_redistribute_set(struct eigrp *, int, struct eigrp_metrics); extern int eigrp_redistribute_unset(struct eigrp *, int); diff --git a/eigrpd/eigrpd.c b/eigrpd/eigrpd.c index 5541ec15f..93f8b6f90 100644 --- a/eigrpd/eigrpd.c +++ b/eigrpd/eigrpd.c @@ -122,7 +122,7 @@ void eigrp_router_id_update(struct eigrp *eigrp) } } -void eigrp_master_init() +void eigrp_master_init(void) { struct timeval tv; @@ -206,6 +206,13 @@ static struct eigrp *eigrp_new(const char *AS) eigrp_distribute_update); distribute_list_delete_hook(eigrp->distribute_ctx, eigrp_distribute_update); + + /* + eigrp->if_rmap_ctx = if_rmap_ctx_create( + VRF_DEFAULT_NAME); + if_rmap_hook_add (eigrp_if_rmap_update); + if_rmap_hook_delete (eigrp_if_rmap_update); + */ QOBJ_REG(eigrp, eigrp); return eigrp; } diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am index d532afbbe..4503030fd 100644 --- a/eigrpd/subdir.am +++ b/eigrpd/subdir.am @@ -65,4 +65,4 @@ noinst_HEADERS += \ # end eigrpd_eigrpd_SOURCES = eigrpd/eigrp_main.c -eigrpd_eigrpd_LDADD = eigrpd/libeigrp.a lib/libfrr.la @LIBCAP@ +eigrpd_eigrpd_LDADD = eigrpd/libeigrp.a lib/libfrr.la $(LIBCAP) diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h new file mode 100644 index 000000000..a924606f3 --- /dev/null +++ b/include/linux/if_addr.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LINUX_IF_ADDR_H +#define __LINUX_IF_ADDR_H + +#include <linux/types.h> +#include <linux/netlink.h> + +struct ifaddrmsg { + __u8 ifa_family; + __u8 ifa_prefixlen; /* The prefix length */ + __u8 ifa_flags; /* Flags */ + __u8 ifa_scope; /* Address scope */ + __u32 ifa_index; /* Link index */ +}; + +/* + * Important comment: + * IFA_ADDRESS is prefix address, rather than local interface address. + * It makes no difference for normally configured broadcast interfaces, + * but for point-to-point IFA_ADDRESS is DESTINATION address, + * local address is supplied in IFA_LOCAL attribute. + * + * IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags. + * If present, the value from struct ifaddrmsg will be ignored. + */ +enum { + IFA_UNSPEC, + IFA_ADDRESS, + IFA_LOCAL, + IFA_LABEL, + IFA_BROADCAST, + IFA_ANYCAST, + IFA_CACHEINFO, + IFA_MULTICAST, + IFA_FLAGS, + IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */ + __IFA_MAX, +}; + +#define IFA_MAX (__IFA_MAX - 1) + +/* ifa_flags */ +#define IFA_F_SECONDARY 0x01 +#define IFA_F_TEMPORARY IFA_F_SECONDARY + +#define IFA_F_NODAD 0x02 +#define IFA_F_OPTIMISTIC 0x04 +#define IFA_F_DADFAILED 0x08 +#define IFA_F_HOMEADDRESS 0x10 +#define IFA_F_DEPRECATED 0x20 +#define IFA_F_TENTATIVE 0x40 +#define IFA_F_PERMANENT 0x80 +#define IFA_F_MANAGETEMPADDR 0x100 +#define IFA_F_NOPREFIXROUTE 0x200 +#define IFA_F_MCAUTOJOIN 0x400 +#define IFA_F_STABLE_PRIVACY 0x800 + +struct ifa_cacheinfo { + __u32 ifa_prefered; + __u32 ifa_valid; + __u32 cstamp; /* created timestamp, hundredths of seconds */ + __u32 tstamp; /* updated timestamp, hundredths of seconds */ +}; + +/* backwards compatibility for userspace */ +#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) +#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) + +#endif diff --git a/include/subdir.am b/include/subdir.am index 731785d4b..0d7fed285 100644 --- a/include/subdir.am +++ b/include/subdir.am @@ -1,4 +1,5 @@ noinst_HEADERS += \ + include/linux/if_addr.h \ include/linux/if_bridge.h \ include/linux/if_link.h \ include/linux/lwtunnel.h \ diff --git a/isisd/fabricd.c b/isisd/fabricd.c index e8b729c77..96af28f0a 100644 --- a/isisd/fabricd.c +++ b/isisd/fabricd.c @@ -559,18 +559,18 @@ static void move_to_queue(struct isis_lsp *lsp, struct neighbor_entry *n, listnode_add(lsp->flooding_neighbors[type], neighbor_id); } -static void mark_neighbor_as_present(struct hash_backet *backet, void *arg) +static void mark_neighbor_as_present(struct hash_bucket *bucket, void *arg) { - struct neighbor_entry *n = backet->data; + struct neighbor_entry *n = bucket->data; n->present = true; } -static void handle_firsthops(struct hash_backet *backet, void *arg) +static void handle_firsthops(struct hash_bucket *bucket, void *arg) { struct isis_lsp *lsp = arg; struct fabricd *f = lsp->area->fabricd; - struct isis_vertex *vertex = backet->data; + struct isis_vertex *vertex = bucket->data; struct neighbor_entry *n; diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 81b4b397e..8377638b9 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -69,7 +69,7 @@ int isis_interface_config_write(struct vty *); int isis_if_new_hook(struct interface *); int isis_if_delete_hook(struct interface *); -struct isis_circuit *isis_circuit_new() +struct isis_circuit *isis_circuit_new(void) { struct isis_circuit *circuit; int i; @@ -1305,8 +1305,8 @@ ferr_r isis_circuit_passwd_unset(struct isis_circuit *circuit) return ferr_ok(); } -static int isis_circuit_passwd_set(struct isis_circuit *circuit, - uint8_t passwd_type, const char *passwd) +ferr_r isis_circuit_passwd_set(struct isis_circuit *circuit, + uint8_t passwd_type, const char *passwd) { int len; @@ -1319,7 +1319,8 @@ static int isis_circuit_passwd_set(struct isis_circuit *circuit, "circuit password too long (max 254 chars)"); circuit->passwd.len = len; - strncpy((char *)circuit->passwd.passwd, passwd, 255); + strlcpy((char *)circuit->passwd.passwd, passwd, + sizeof(circuit->passwd.passwd)); circuit->passwd.type = passwd_type; return ferr_ok(); } @@ -1393,7 +1394,7 @@ int isis_if_delete_hook(struct interface *ifp) return 0; } -void isis_circuit_init() +void isis_circuit_init(void) { /* Initialize Zebra interface data structure */ hook_register_prio(if_add, 0, isis_if_new_hook); diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 73ead8f7d..e0ea4f78b 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -190,6 +190,8 @@ ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level, int metric); ferr_r isis_circuit_passwd_unset(struct isis_circuit *circuit); +ferr_r isis_circuit_passwd_set(struct isis_circuit *circuit, + uint8_t passwd_type, const char *passwd); ferr_r isis_circuit_passwd_cleartext_set(struct isis_circuit *circuit, const char *passwd); ferr_r isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit, diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index c68f49f92..ab5faf76b 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -89,7 +89,7 @@ DEFPY(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag", return CMD_ERR_NOTHING_TODO; } - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); area = isis_area_lookup(tag); if (area && area->circuit_list && listcount(area->circuit_list)) { for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode, @@ -103,7 +103,7 @@ DEFPY(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag", temp_xpath, XPATH_MAXLEN, "/frr-interface:lib/interface[name='%s'][vrf='%s']/frr-isisd:isis", circuit->interface->name, vrf_name); - nb_cli_enqueue_change(vty, temp_xpath, NB_OP_DELETE, + nb_cli_enqueue_change(vty, temp_xpath, NB_OP_DESTROY, NULL); } } @@ -279,27 +279,28 @@ DEFPY(no_ip_router_isis, no_ip_router_isis_cmd, "IS-IS routing protocol\n" "Routing process tag\n") { - const struct lyd_node *dnode = - yang_dnode_get(running_config->dnode, VTY_CURR_XPATH); + const struct lyd_node *dnode; - /* if both ipv4 and ipv6 are off delete the interface isis container too + dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-isisd:isis", VTY_CURR_XPATH); + if (!dnode) + return CMD_SUCCESS; + + /* + * If both ipv4 and ipv6 are off delete the interface isis container. */ - if (!strncmp(ip, "ipv6", strlen("ipv6"))) { - if (dnode - && !yang_dnode_get_bool(dnode, - "./frr-isisd:isis/ipv4-routing")) + if (strmatch(ip, "ipv6")) { + if (!yang_dnode_get_bool(dnode, "./ipv4-routing")) nb_cli_enqueue_change(vty, "./frr-isisd:isis", - NB_OP_DELETE, NULL); + NB_OP_DESTROY, NULL); else nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing", NB_OP_MODIFY, "false"); - } else { /* no ipv4 */ - if (dnode - && !yang_dnode_get_bool(dnode, - "./frr-isisd:isis/ipv6-routing")) + } else { + if (!yang_dnode_get_bool(dnode, "./ipv6-routing")) nb_cli_enqueue_change(vty, "./frr-isisd:isis", - NB_OP_DELETE, NULL); + NB_OP_DESTROY, NULL); else nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing", @@ -336,7 +337,7 @@ DEFPY(net, net_cmd, "[no] net WORD", "XX.XXXX. ... .XXX.XX Network entity title (NET)\n") { nb_cli_enqueue_change(vty, "./area-address", - no ? NB_OP_DELETE : NB_OP_CREATE, net); + no ? NB_OP_DESTROY : NB_OP_CREATE, net); return nb_cli_apply_changes(vty, NULL); } @@ -589,7 +590,7 @@ DEFPY(no_area_passwd, no_area_passwd_cmd, "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n") { - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./%s", cmd); } @@ -892,7 +893,7 @@ DEFPY(no_spf_delay_ietf, no_spf_delay_ietf_cmd, "Maximum duration needed to learn all the events related to a single failure\n" "Maximum duration needed to learn all the events related to a single failure (in milliseconds)\n") { - nb_cli_enqueue_change(vty, "./spf/ietf-backoff-delay", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "./spf/ietf-backoff-delay", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -947,7 +948,7 @@ DEFPY(no_isis_mpls_te_on, no_isis_mpls_te_on_cmd, "no mpls-te [on]", "Disable the MPLS-TE functionality\n" "Enable the MPLS-TE functionality\n") { - nb_cli_enqueue_change(vty, "/frr-isisd:isis/mpls-te", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "/frr-isisd:isis/mpls-te", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -1014,16 +1015,16 @@ DEFPY(isis_default_originate, isis_default_originate_cmd, "Pointer to route-map entries\n") { if (no) - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); else { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./always", NB_OP_MODIFY, always ? "true" : "false"); nb_cli_enqueue_change(vty, "./route-map", - rmap ? NB_OP_MODIFY : NB_OP_DELETE, + rmap ? NB_OP_MODIFY : NB_OP_DESTROY, rmap ? rmap : NULL); nb_cli_enqueue_change(vty, "./metric", - metric ? NB_OP_MODIFY : NB_OP_DELETE, + metric ? NB_OP_MODIFY : NB_OP_DESTROY, metric ? metric_str : NULL); if (strmatch(ip, "ipv6") && !always) { vty_out(vty, @@ -1094,14 +1095,14 @@ DEFPY(isis_redistribute, isis_redistribute_cmd, "Pointer to route-map entries\n") { if (no) - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); else { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./route-map", - route_map ? NB_OP_MODIFY : NB_OP_DELETE, + route_map ? NB_OP_MODIFY : NB_OP_DESTROY, route_map ? route_map : NULL); nb_cli_enqueue_change(vty, "./metric", - metric ? NB_OP_MODIFY : NB_OP_DELETE, + metric ? NB_OP_MODIFY : NB_OP_DESTROY, metric ? metric_str : NULL); } @@ -1182,7 +1183,7 @@ DEFPY(isis_topology, isis_topology_cmd, topology); if (no) - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); else { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./overload", NB_OP_MODIFY, @@ -1297,7 +1298,7 @@ DEFPY(no_isis_passwd, no_isis_passwd_cmd, "no isis password [<md5|clear> WORD]", "Cleartext password\n" "Circuit password\n") { - nb_cli_enqueue_change(vty, "./frr-isisd:isis/password", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "./frr-isisd:isis/password", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 658624370..b56a56fa3 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1930,6 +1930,27 @@ int lsp_tick(struct thread *thread) area->area_tag, lsp->level, rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.seqno); + + /* if we're aging out fragment 0, + * lsp_destroy() below will delete all + * other fragments too, so we need to + * skip over those + */ + while (!LSP_FRAGMENT(lsp->hdr.lsp_id) + && dnode_next) { + struct isis_lsp *nextlsp; + + nextlsp = dnode_get(dnode_next); + if (memcmp(nextlsp->hdr.lsp_id, + lsp->hdr.lsp_id, + ISIS_SYS_ID_LEN + 1)) + break; + + dnode_next = dict_next( + area->lspdb[level], + dnode_next); + } + lsp_destroy(lsp); lsp = NULL; dict_delete_free(area->lspdb[level], diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c index 9c2bb1728..2d1d6f592 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -72,7 +72,7 @@ static int isis_instance_create(enum nb_event event, return NB_OK; } -static int isis_instance_delete(enum nb_event event, +static int isis_instance_destroy(enum nb_event event, const struct lyd_node *dnode) { const char *area_tag; @@ -193,7 +193,7 @@ static int isis_instance_area_address_create(enum nb_event event, return NB_OK; } -static int isis_instance_area_address_delete(enum nb_event event, +static int isis_instance_area_address_destroy(enum nb_event event, const struct lyd_node *dnode) { struct area_addr addr, *addrp = NULL; @@ -536,7 +536,7 @@ isis_instance_spf_ietf_backoff_delay_create(enum nb_event event, } static int -isis_instance_spf_ietf_backoff_delay_delete(enum nb_event event, +isis_instance_spf_ietf_backoff_delay_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -676,7 +676,7 @@ static int isis_instance_area_password_create(enum nb_event event, return NB_OK; } -static int isis_instance_area_password_delete(enum nb_event event, +static int isis_instance_area_password_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -755,7 +755,7 @@ static int isis_instance_domain_password_create(enum nb_event event, return NB_OK; } -static int isis_instance_domain_password_delete(enum nb_event event, +static int isis_instance_domain_password_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -851,7 +851,7 @@ static int isis_instance_default_information_originate_ipv4_create( return NB_OK; } -static int isis_instance_default_information_originate_ipv4_delete( +static int isis_instance_default_information_originate_ipv4_destroy( enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -889,7 +889,7 @@ static int isis_instance_default_information_originate_ipv4_route_map_modify( return NB_OK; } -static int isis_instance_default_information_originate_ipv4_route_map_delete( +static int isis_instance_default_information_originate_ipv4_route_map_destroy( enum nb_event event, const struct lyd_node *dnode) { /* It's all done by default_info_origin_apply_finish */ @@ -907,7 +907,7 @@ static int isis_instance_default_information_originate_ipv4_metric_modify( return NB_OK; } -static int isis_instance_default_information_originate_ipv4_metric_delete( +static int isis_instance_default_information_originate_ipv4_metric_destroy( enum nb_event event, const struct lyd_node *dnode) { /* It's all done by default_info_origin_apply_finish */ @@ -925,7 +925,7 @@ static int isis_instance_default_information_originate_ipv6_create( return NB_OK; } -static int isis_instance_default_information_originate_ipv6_delete( +static int isis_instance_default_information_originate_ipv6_destroy( enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -963,7 +963,7 @@ static int isis_instance_default_information_originate_ipv6_route_map_modify( return NB_OK; } -static int isis_instance_default_information_originate_ipv6_route_map_delete( +static int isis_instance_default_information_originate_ipv6_route_map_destroy( enum nb_event event, const struct lyd_node *dnode) { /* It's all done by default_info_origin_apply_finish */ @@ -981,7 +981,7 @@ static int isis_instance_default_information_originate_ipv6_metric_modify( return NB_OK; } -static int isis_instance_default_information_originate_ipv6_metric_delete( +static int isis_instance_default_information_originate_ipv6_metric_destroy( enum nb_event event, const struct lyd_node *dnode) { /* It's all done by default_info_origin_apply_finish */ @@ -1029,7 +1029,7 @@ static int isis_instance_redistribute_ipv4_create(enum nb_event event, return NB_OK; } -static int isis_instance_redistribute_ipv4_delete(enum nb_event event, +static int isis_instance_redistribute_ipv4_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -1059,7 +1059,7 @@ isis_instance_redistribute_ipv4_route_map_modify(enum nb_event event, } static int -isis_instance_redistribute_ipv4_route_map_delete(enum nb_event event, +isis_instance_redistribute_ipv4_route_map_destroy(enum nb_event event, const struct lyd_node *dnode) { /* It's all done by redistribute_apply_finish */ @@ -1079,7 +1079,7 @@ isis_instance_redistribute_ipv4_metric_modify(enum nb_event event, } static int -isis_instance_redistribute_ipv4_metric_delete(enum nb_event event, +isis_instance_redistribute_ipv4_metric_destroy(enum nb_event event, const struct lyd_node *dnode) { /* It's all done by redistribute_apply_finish */ @@ -1097,7 +1097,7 @@ static int isis_instance_redistribute_ipv6_create(enum nb_event event, return NB_OK; } -static int isis_instance_redistribute_ipv6_delete(enum nb_event event, +static int isis_instance_redistribute_ipv6_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -1127,7 +1127,7 @@ isis_instance_redistribute_ipv6_route_map_modify(enum nb_event event, } static int -isis_instance_redistribute_ipv6_route_map_delete(enum nb_event event, +isis_instance_redistribute_ipv6_route_map_destroy(enum nb_event event, const struct lyd_node *dnode) { /* It's all done by redistribute_apply_finish */ @@ -1147,7 +1147,7 @@ isis_instance_redistribute_ipv6_metric_modify(enum nb_event event, } static int -isis_instance_redistribute_ipv6_metric_delete(enum nb_event event, +isis_instance_redistribute_ipv6_metric_destroy(enum nb_event event, const struct lyd_node *dnode) { /* It's all done by redistribute_apply_finish */ @@ -1217,7 +1217,7 @@ isis_instance_multi_topology_ipv4_multicast_create(enum nb_event event, } static int -isis_instance_multi_topology_ipv4_multicast_delete(enum nb_event event, +isis_instance_multi_topology_ipv4_multicast_destroy(enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv4-multicast", @@ -1245,7 +1245,7 @@ static int isis_instance_multi_topology_ipv4_management_create( return isis_multi_topology_common(event, dnode, "ipv4-mgmt", true); } -static int isis_instance_multi_topology_ipv4_management_delete( +static int isis_instance_multi_topology_ipv4_management_destroy( enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv4-mgmt", false); @@ -1273,7 +1273,7 @@ isis_instance_multi_topology_ipv6_unicast_create(enum nb_event event, } static int -isis_instance_multi_topology_ipv6_unicast_delete(enum nb_event event, +isis_instance_multi_topology_ipv6_unicast_destroy(enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv6-unicast", false); @@ -1302,7 +1302,7 @@ isis_instance_multi_topology_ipv6_multicast_create(enum nb_event event, } static int -isis_instance_multi_topology_ipv6_multicast_delete(enum nb_event event, +isis_instance_multi_topology_ipv6_multicast_destroy(enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv6-multicast", @@ -1330,7 +1330,7 @@ static int isis_instance_multi_topology_ipv6_management_create( return isis_multi_topology_common(event, dnode, "ipv6-mgmt", true); } -static int isis_instance_multi_topology_ipv6_management_delete( +static int isis_instance_multi_topology_ipv6_management_destroy( enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv6-mgmt", false); @@ -1358,7 +1358,7 @@ isis_instance_multi_topology_ipv6_dstsrc_create(enum nb_event event, } static int -isis_instance_multi_topology_ipv6_dstsrc_delete(enum nb_event event, +isis_instance_multi_topology_ipv6_dstsrc_destroy(enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv6-dstsrc", false); @@ -1436,7 +1436,7 @@ static int isis_mpls_te_create(enum nb_event event, return NB_OK; } -static int isis_mpls_te_delete(enum nb_event event, +static int isis_mpls_te_destroy(enum nb_event event, const struct lyd_node *dnode) { struct listnode *node; @@ -1494,7 +1494,7 @@ static int isis_mpls_te_router_address_modify(enum nb_event event, return NB_OK; } -static int isis_mpls_te_router_address_delete(enum nb_event event, +static int isis_mpls_te_router_address_destroy(enum nb_event event, const struct lyd_node *dnode) { struct listnode *node; @@ -1555,7 +1555,7 @@ static int lib_interface_isis_create(enum nb_event event, return NB_OK; } -static int lib_interface_isis_delete(enum nb_event event, +static int lib_interface_isis_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_circuit *circuit; @@ -2062,7 +2062,7 @@ static int lib_interface_isis_password_create(enum nb_event event, return NB_OK; } -static int lib_interface_isis_password_delete(enum nb_event event, +static int lib_interface_isis_password_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_circuit *circuit; @@ -2092,8 +2092,8 @@ lib_interface_isis_password_password_modify(enum nb_event event, password = yang_dnode_get_string(dnode, NULL); circuit = yang_dnode_get_entry(dnode, true); - circuit->passwd.len = strlen(password); - strncpy((char *)circuit->passwd.passwd, password, 255); + + isis_circuit_passwd_set(circuit, circuit->passwd.type, password); return NB_OK; } @@ -2749,7 +2749,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance", .cbs.create = isis_instance_create, - .cbs.delete = isis_instance_delete, + .cbs.destroy = isis_instance_destroy, .cbs.cli_show = cli_show_router_isis, .priority = NB_DFLT_PRIORITY - 1, }, @@ -2761,7 +2761,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/area-address", .cbs.create = isis_instance_area_address_create, - .cbs.delete = isis_instance_area_address_delete, + .cbs.destroy = isis_instance_area_address_destroy, .cbs.cli_show = cli_show_isis_area_address, }, { @@ -2833,7 +2833,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay", .cbs.create = isis_instance_spf_ietf_backoff_delay_create, - .cbs.delete = isis_instance_spf_ietf_backoff_delay_delete, + .cbs.destroy = isis_instance_spf_ietf_backoff_delay_destroy, .cbs.apply_finish = ietf_backoff_delay_apply_finish, .cbs.cli_show = cli_show_isis_spf_ietf_backoff, }, @@ -2872,7 +2872,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/area-password", .cbs.create = isis_instance_area_password_create, - .cbs.delete = isis_instance_area_password_delete, + .cbs.destroy = isis_instance_area_password_destroy, .cbs.apply_finish = area_password_apply_finish, .cbs.cli_show = cli_show_isis_area_pwd, }, @@ -2891,7 +2891,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/domain-password", .cbs.create = isis_instance_domain_password_create, - .cbs.delete = isis_instance_domain_password_delete, + .cbs.destroy = isis_instance_domain_password_destroy, .cbs.apply_finish = domain_password_apply_finish, .cbs.cli_show = cli_show_isis_domain_pwd, }, @@ -2910,7 +2910,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4", .cbs.create = isis_instance_default_information_originate_ipv4_create, - .cbs.delete = isis_instance_default_information_originate_ipv4_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv4_destroy, .cbs.apply_finish = default_info_origin_ipv4_apply_finish, .cbs.cli_show = cli_show_isis_def_origin_ipv4, }, @@ -2921,17 +2921,17 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/route-map", .cbs.modify = isis_instance_default_information_originate_ipv4_route_map_modify, - .cbs.delete = isis_instance_default_information_originate_ipv4_route_map_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv4_route_map_destroy, }, { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/metric", .cbs.modify = isis_instance_default_information_originate_ipv4_metric_modify, - .cbs.delete = isis_instance_default_information_originate_ipv4_metric_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv4_metric_destroy, }, { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6", .cbs.create = isis_instance_default_information_originate_ipv6_create, - .cbs.delete = isis_instance_default_information_originate_ipv6_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv6_destroy, .cbs.apply_finish = default_info_origin_ipv6_apply_finish, .cbs.cli_show = cli_show_isis_def_origin_ipv6, }, @@ -2942,51 +2942,51 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/route-map", .cbs.modify = isis_instance_default_information_originate_ipv6_route_map_modify, - .cbs.delete = isis_instance_default_information_originate_ipv6_route_map_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv6_route_map_destroy, }, { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/metric", .cbs.modify = isis_instance_default_information_originate_ipv6_metric_modify, - .cbs.delete = isis_instance_default_information_originate_ipv6_metric_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv6_metric_destroy, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv4", .cbs.create = isis_instance_redistribute_ipv4_create, - .cbs.delete = isis_instance_redistribute_ipv4_delete, + .cbs.destroy = isis_instance_redistribute_ipv4_destroy, .cbs.apply_finish = redistribute_ipv4_apply_finish, .cbs.cli_show = cli_show_isis_redistribute_ipv4, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/route-map", .cbs.modify = isis_instance_redistribute_ipv4_route_map_modify, - .cbs.delete = isis_instance_redistribute_ipv4_route_map_delete, + .cbs.destroy = isis_instance_redistribute_ipv4_route_map_destroy, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/metric", .cbs.modify = isis_instance_redistribute_ipv4_metric_modify, - .cbs.delete = isis_instance_redistribute_ipv4_metric_delete, + .cbs.destroy = isis_instance_redistribute_ipv4_metric_destroy, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv6", .cbs.create = isis_instance_redistribute_ipv6_create, - .cbs.delete = isis_instance_redistribute_ipv6_delete, + .cbs.destroy = isis_instance_redistribute_ipv6_destroy, .cbs.apply_finish = redistribute_ipv6_apply_finish, .cbs.cli_show = cli_show_isis_redistribute_ipv6, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/route-map", .cbs.modify = isis_instance_redistribute_ipv6_route_map_modify, - .cbs.delete = isis_instance_redistribute_ipv6_route_map_delete, + .cbs.destroy = isis_instance_redistribute_ipv6_route_map_destroy, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/metric", .cbs.modify = isis_instance_redistribute_ipv6_metric_modify, - .cbs.delete = isis_instance_redistribute_ipv6_metric_delete, + .cbs.destroy = isis_instance_redistribute_ipv6_metric_destroy, }, { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-multicast", .cbs.create = isis_instance_multi_topology_ipv4_multicast_create, - .cbs.delete = isis_instance_multi_topology_ipv4_multicast_delete, + .cbs.destroy = isis_instance_multi_topology_ipv4_multicast_destroy, .cbs.cli_show = cli_show_isis_mt_ipv4_multicast, }, { @@ -2996,7 +2996,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-management", .cbs.create = isis_instance_multi_topology_ipv4_management_create, - .cbs.delete = isis_instance_multi_topology_ipv4_management_delete, + .cbs.destroy = isis_instance_multi_topology_ipv4_management_destroy, .cbs.cli_show = cli_show_isis_mt_ipv4_mgmt, }, { @@ -3006,7 +3006,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-unicast", .cbs.create = isis_instance_multi_topology_ipv6_unicast_create, - .cbs.delete = isis_instance_multi_topology_ipv6_unicast_delete, + .cbs.destroy = isis_instance_multi_topology_ipv6_unicast_destroy, .cbs.cli_show = cli_show_isis_mt_ipv6_unicast, }, { @@ -3016,7 +3016,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-multicast", .cbs.create = isis_instance_multi_topology_ipv6_multicast_create, - .cbs.delete = isis_instance_multi_topology_ipv6_multicast_delete, + .cbs.destroy = isis_instance_multi_topology_ipv6_multicast_destroy, .cbs.cli_show = cli_show_isis_mt_ipv6_multicast, }, { @@ -3026,7 +3026,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-management", .cbs.create = isis_instance_multi_topology_ipv6_management_create, - .cbs.delete = isis_instance_multi_topology_ipv6_management_delete, + .cbs.destroy = isis_instance_multi_topology_ipv6_management_destroy, .cbs.cli_show = cli_show_isis_mt_ipv6_mgmt, }, { @@ -3036,7 +3036,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-dstsrc", .cbs.create = isis_instance_multi_topology_ipv6_dstsrc_create, - .cbs.delete = isis_instance_multi_topology_ipv6_dstsrc_delete, + .cbs.destroy = isis_instance_multi_topology_ipv6_dstsrc_destroy, .cbs.cli_show = cli_show_isis_mt_ipv6_dstsrc, }, { @@ -3051,19 +3051,19 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/mpls-te", .cbs.create = isis_mpls_te_create, - .cbs.delete = isis_mpls_te_delete, + .cbs.destroy = isis_mpls_te_destroy, .cbs.cli_show = cli_show_isis_mpls_te, }, { .xpath = "/frr-isisd:isis/mpls-te/router-address", .cbs.modify = isis_mpls_te_router_address_modify, - .cbs.delete = isis_mpls_te_router_address_delete, + .cbs.destroy = isis_mpls_te_router_address_destroy, .cbs.cli_show = cli_show_isis_mpls_te_router_addr, }, { .xpath = "/frr-interface:lib/interface/frr-isisd:isis", .cbs.create = lib_interface_isis_create, - .cbs.delete = lib_interface_isis_delete, + .cbs.destroy = lib_interface_isis_destroy, }, { .xpath = "/frr-interface:lib/interface/frr-isisd:isis/area-tag", @@ -3174,7 +3174,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-interface:lib/interface/frr-isisd:isis/password", .cbs.create = lib_interface_isis_password_create, - .cbs.delete = lib_interface_isis_password_delete, + .cbs.destroy = lib_interface_isis_password_destroy, .cbs.cli_show = cli_show_ip_isis_password, }, { diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index 815de513f..20f3e62a7 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -338,12 +338,14 @@ static void isis_redist_routemap_set(struct isis_redist *redist, { if (redist->map_name) { XFREE(MTYPE_ISIS, redist->map_name); + route_map_counter_decrement(redist->map); redist->map = NULL; } if (routemap && strlen(routemap)) { redist->map_name = XSTRDUP(MTYPE_ISIS, routemap); redist->map = route_map_lookup_by_name(routemap); + route_map_counter_increment(redist->map); } } diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index b6f751463..18eb857ec 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -352,10 +352,10 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree, return vertex; } -static void vertex_add_parent_firsthop(struct hash_backet *backet, void *arg) +static void vertex_add_parent_firsthop(struct hash_bucket *bucket, void *arg) { struct isis_vertex *vertex = arg; - struct isis_vertex *hop = backet->data; + struct isis_vertex *hop = bucket->data; hash_get(vertex->firsthops, hop, hash_alloc_intern); } @@ -1471,7 +1471,7 @@ DEFUN (show_isis_topology, return CMD_SUCCESS; } -void isis_spf_cmds_init() +void isis_spf_cmds_init(void) { install_element(VIEW_NODE, &show_isis_topology_cmd); } diff --git a/isisd/isis_te.c b/isisd/isis_te.c index a69c95cad..23a1f10a1 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -68,7 +68,7 @@ const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"}; *------------------------------------------------------------------------*/ /* Create new MPLS TE Circuit context */ -struct mpls_te_circuit *mpls_te_circuit_new() +struct mpls_te_circuit *mpls_te_circuit_new(void) { struct mpls_te_circuit *mtc; diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 958f8c228..dfe74e325 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -219,11 +219,11 @@ static int isis_zebra_if_address_del(int command, struct zclient *client, } static int isis_zebra_link_params(int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; - ifp = zebra_interface_link_params_read(zclient->ibuf); + ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id); if (ifp == NULL) return 0; @@ -249,8 +249,6 @@ static void isis_zebra_route_add_route(struct prefix *prefix, return; memset(&api, 0, sizeof(api)); - if (fabricd) - api.flags |= ZEBRA_FLAG_ONLINK; api.vrf_id = VRF_DEFAULT; api.type = PROTO_TYPE; api.safi = SAFI_UNICAST; @@ -275,6 +273,8 @@ static void isis_zebra_route_add_route(struct prefix *prefix, if (count >= MULTIPATH_NUM) break; api_nh = &api.nexthops[count]; + if (fabricd) + api_nh->onlink = true; api_nh->vrf_id = VRF_DEFAULT; /* FIXME: can it be ? */ if (nexthop->ip.s_addr != INADDR_ANY) { @@ -298,6 +298,8 @@ static void isis_zebra_route_add_route(struct prefix *prefix, } api_nh = &api.nexthops[count]; + if (fabricd) + api_nh->onlink = true; api_nh->vrf_id = VRF_DEFAULT; api_nh->gate.ipv6 = nexthop6->ip6; api_nh->ifindex = nexthop6->ifindex; diff --git a/isisd/isisd.c b/isisd/isisd.c index 419127c34..ad0222043 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1363,7 +1363,7 @@ struct isis_lsp *lsp_for_arg(const char *argv, dict_t *lspdb) * xxxx.xxxx.xxxx */ if (argv) - strncpy(sysid, argv, 254); + strlcpy(sysid, argv, sizeof(sysid)); if (argv && strlen(argv) > 3) { pos = argv + strlen(argv) - 3; if (strncmp(pos, "-", 1) == 0) { @@ -1639,7 +1639,8 @@ static int isis_area_passwd_set(struct isis_area *area, int level, return -1; modified.len = len; - strncpy((char *)modified.passwd, passwd, 255); + strlcpy((char *)modified.passwd, passwd, + sizeof(modified.passwd)); modified.type = passwd_type; modified.snp_auth = snp_auth; } @@ -2161,7 +2162,7 @@ int isis_config_write(struct vty *vty) struct cmd_node router_node = {ROUTER_NODE, "%s(config-router)# ", 1}; -void isis_init() +void isis_init(void) { /* Install IS-IS top node */ install_node(&router_node, isis_config_write); diff --git a/isisd/subdir.am b/isisd/subdir.am index c5b9b31a4..4371d5993 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -98,7 +98,7 @@ ISIS_SOURCES = \ isisd/isis_pfpacket.c \ # end -ISIS_LDADD_COMMON = lib/libfrr.la @LIBCAP@ +ISIS_LDADD_COMMON = lib/libfrr.la $(LIBCAP) # Building isisd diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 944f93331..5e1b422a4 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -37,7 +37,7 @@ enqueue_pdu(struct nbr *nbr, uint16_t type, struct ibuf *buf, uint16_t size) struct ldp_hdr *ldp_hdr; ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr)); - ldp_hdr->length = htons(size); + ldp_hdr->length = htons(size - LDP_HDR_DEAD_LEN); evbuf_enqueue(&nbr->tcp->wbuf, buf); } @@ -65,7 +65,7 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) /* real size will be set up later */ err |= gen_ldp_hdr(buf, 0); - size = LDP_HDR_PDU_LEN; + size = LDP_HDR_SIZE; first = 0; } diff --git a/ldpd/subdir.am b/ldpd/subdir.am index 24e738d62..42c5ad024 100644 --- a/ldpd/subdir.am +++ b/ldpd/subdir.am @@ -55,4 +55,4 @@ noinst_HEADERS += \ # end ldpd_ldpd_SOURCES = ldpd/ldpd.c -ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la @LIBCAP@ +ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la $(LIBCAP) diff --git a/lib/agg_table.h b/lib/agg_table.h index dc2ff03b6..40ffe8c75 100644 --- a/lib/agg_table.h +++ b/lib/agg_table.h @@ -23,6 +23,10 @@ #include "prefix.h" #include "table.h" +#ifdef __cplusplus +extern "C" { +#endif + struct agg_table { struct route_table *route_table; @@ -150,4 +154,9 @@ static inline struct agg_table *agg_get_table(struct agg_node *node) { return (struct agg_table *)route_table_get_info(node->table); } + +#ifdef __cplusplus +} +#endif + #endif @@ -26,6 +26,10 @@ #include "lib/json.h" #include "lib/zclient.h" +#ifdef __cplusplus +extern "C" { +#endif + #define BFD_DEF_MIN_RX 300 #define BFD_MIN_MIN_RX 50 #define BFD_MAX_MIN_RX 60000 @@ -104,4 +108,8 @@ extern void bfd_gbl_init(void); extern void bfd_gbl_exit(void); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_BFD_H */ diff --git a/lib/bitfield.h b/lib/bitfield.h index 0e031ccc4..eebfc049d 100644 --- a/lib/bitfield.h +++ b/lib/bitfield.h @@ -44,6 +44,10 @@ #include <string.h> #include <stdlib.h> +#ifdef __cplusplus +extern "C" { +#endif + typedef unsigned int word_t; #define WORD_MAX 0xFFFFFFFF #define WORD_SIZE (sizeof(word_t) * 8) @@ -153,4 +157,8 @@ typedef unsigned int word_t; } \ } while (0) +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/buffer.h b/lib/buffer.h index 0c945a2ac..8b5a89825 100644 --- a/lib/buffer.h +++ b/lib/buffer.h @@ -22,6 +22,10 @@ #ifndef _ZEBRA_BUFFER_H #define _ZEBRA_BUFFER_H +#ifdef __cplusplus +extern "C" { +#endif + /* Create a new buffer. Memory will be allocated in chunks of the given size. If the argument is 0, the library will supply a reasonable default size suitable for buffering socket I/O. */ @@ -99,4 +103,8 @@ extern buffer_status_t buffer_flush_all(struct buffer *, int fd); extern buffer_status_t buffer_flush_window(struct buffer *, int fd, int width, int height, int erase, int no_more); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_BUFFER_H */ diff --git a/lib/checksum.h b/lib/checksum.h index c2764e35f..7d5037143 100644 --- a/lib/checksum.h +++ b/lib/checksum.h @@ -1,4 +1,12 @@ +#ifdef __cplusplus +extern "C" { +#endif + extern int in_cksum(void *, int); #define FLETCHER_CHECKSUM_VALIDATE 0xffff extern uint16_t fletcher_checksum(uint8_t *, const size_t len, const uint16_t offset); + +#ifdef __cplusplus +} +#endif diff --git a/lib/clippy.h b/lib/clippy.h index 8df98cbb8..be4db6e63 100644 --- a/lib/clippy.h +++ b/lib/clippy.h @@ -22,7 +22,15 @@ #include <Python.h> +#ifdef __cplusplus +extern "C" { +#endif + extern PyObject *clippy_parse(PyObject *self, PyObject *args); extern PyMODINIT_FUNC command_py_init(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_CLIPPY_H */ diff --git a/lib/command.c b/lib/command.c index d1dafa3a1..b46241ac8 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1009,7 +1009,7 @@ enum node_type node_parent(enum node_type node) } /* Execute command by argument vline vector. */ -static int cmd_execute_command_real(vector vline, enum filter_type filter, +static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter, struct vty *vty, const struct cmd_element **cmd) { @@ -1535,67 +1535,11 @@ DEFUN (config_end, "end", "End current mode and change to enable mode.\n") { - switch (vty->node) { - case VIEW_NODE: - case ENABLE_NODE: - /* Nothing to do. */ - break; - case CONFIG_NODE: - case INTERFACE_NODE: - case PW_NODE: - case LOGICALROUTER_NODE: - case VRF_NODE: - case NH_GROUP_NODE: - case ZEBRA_NODE: - case RIP_NODE: - case RIPNG_NODE: - case EIGRP_NODE: - case BABEL_NODE: - case BGP_NODE: - case BGP_VRF_POLICY_NODE: - case BGP_VNC_DEFAULTS_NODE: - case BGP_VNC_NVE_GROUP_NODE: - case BGP_VNC_L2_GROUP_NODE: - case BGP_VPNV4_NODE: - case BGP_VPNV6_NODE: - case BGP_FLOWSPECV4_NODE: - case BGP_FLOWSPECV6_NODE: - case BGP_IPV4_NODE: - case BGP_IPV4M_NODE: - case BGP_IPV4L_NODE: - case BGP_IPV6_NODE: - case BGP_IPV6M_NODE: - case BGP_EVPN_NODE: - case BGP_EVPN_VNI_NODE: - case BGP_IPV6L_NODE: - case RMAP_NODE: - case PBRMAP_NODE: - case OSPF_NODE: - case OSPF6_NODE: - case LDP_NODE: - case LDP_IPV4_NODE: - case LDP_IPV6_NODE: - case LDP_IPV4_IFACE_NODE: - case LDP_IPV6_IFACE_NODE: - case LDP_L2VPN_NODE: - case LDP_PSEUDOWIRE_NODE: - case ISIS_NODE: - case OPENFABRIC_NODE: - case KEYCHAIN_NODE: - case KEYCHAIN_KEY_NODE: - case VTY_NODE: - case LINK_PARAMS_NODE: - case BFD_NODE: - case BFD_PEER_NODE: + if (vty->config) { vty_config_exit(vty); vty->node = ENABLE_NODE; - break; - default: - break; } - vty->xpath_index = 0; - return CMD_SUCCESS; } @@ -2571,8 +2515,6 @@ DEFUN (config_log_syslog, { int idx_log_levels = 2; - disable_log_file(); - if (argc == 3) { int level; if ((level = level_match(argv[idx_log_levels]->arg)) @@ -2939,7 +2881,7 @@ void cmd_init(int terminal) #endif } -void cmd_terminate() +void cmd_terminate(void) { struct cmd_node *cmd_node; diff --git a/lib/command.h b/lib/command.h index 11514fd5e..a5f9616db 100644 --- a/lib/command.h +++ b/lib/command.h @@ -30,6 +30,10 @@ #include "hash.h" #include "command_graph.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(HOST) DECLARE_MTYPE(COMPLETION) @@ -314,6 +318,9 @@ struct cmd_node { #define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) + +#define DEFPY_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) #endif /* VTYSH_EXTRACT_PL */ /* Some macroes */ @@ -488,4 +495,9 @@ cmd_variable_handler_register(const struct cmd_variable_handler *cvh); extern char *cmd_variable_comp2str(vector comps, unsigned short cols); extern void command_setup_early_logging(const char *dest, const char *level); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_COMMAND_H */ diff --git a/lib/command_graph.h b/lib/command_graph.h index 82d562694..903d51583 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -32,6 +32,10 @@ #include "vector.h" #include "graph.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(CMD_ARG) struct vty; @@ -114,7 +118,7 @@ extern void cmd_token_varname_set(struct cmd_token *token, const char *varname); extern void cmd_graph_parse(struct graph *graph, struct cmd_element *cmd); extern void cmd_graph_names(struct graph *graph); -extern void cmd_graph_merge(struct graph *old, struct graph *new, +extern void cmd_graph_merge(struct graph *old, struct graph *n, int direction); /* * Print callback for DOT dumping. @@ -133,4 +137,8 @@ extern void cmd_graph_node_print_cb(struct graph_node *gn, struct buffer *buf); */ char *cmd_graph_dump_dot(struct graph *cmdgraph); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_COMMAND_GRAPH_H */ diff --git a/lib/command_match.h b/lib/command_match.h index c636d2dd9..fcb333120 100644 --- a/lib/command_match.h +++ b/lib/command_match.h @@ -28,10 +28,14 @@ #include "linklist.h" #include "command.h" +#ifdef __cplusplus +extern "C" { +#endif + /* These definitions exist in command.c in the current engine but should be * relocated here in the new engine */ -enum filter_type { FILTER_RELAXED, FILTER_STRICT }; +enum cmd_filter_type { FILTER_RELAXED, FILTER_STRICT }; /* matcher result value */ enum matcher_rv { @@ -98,4 +102,8 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline, enum matcher_rv command_complete(struct graph *cmdgraph, vector vline, struct list **completions); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_COMMAND_MATCH_H */ diff --git a/lib/compiler.h b/lib/compiler.h index 24b8fafd1..cb4f7531e 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -17,6 +17,10 @@ #ifndef _FRR_COMPILER_H #define _FRR_COMPILER_H +#ifdef __cplusplus +extern "C" { +#endif + /* function attributes, use like * void prototype(void) __attribute__((_CONSTRUCTOR(100))); */ @@ -88,4 +92,8 @@ #define CPP_NOTICE(text) #endif +#ifdef __cplusplus +} +#endif + #endif /* _FRR_COMPILER_H */ @@ -70,6 +70,10 @@ #include <stdarg.h> #include <sys/queue.h> +#ifdef __cplusplus +extern "C" { +#endif + typedef struct _csv_field_t_ csv_field_t; typedef struct _csv_record_t_ csv_record_t; typedef struct _csv_t_ csv_t; @@ -185,4 +189,8 @@ void csv_clone_record(csv_t *csv, csv_record_t *in_rec, csv_record_t **out_rec); */ int csv_num_records(csv_t *csv); +#ifdef __cplusplus +} +#endif + #endif @@ -38,6 +38,10 @@ #include <sqlite3.h> +#ifdef __cplusplus +extern "C" { +#endif + extern int db_init(const char *path_fmt, ...); extern int db_close(void); extern int db_bindf(struct sqlite3_stmt *ss, const char *fmt, ...); @@ -48,5 +52,9 @@ extern int db_loadf(struct sqlite3_stmt *ss, const char *fmt, ...); extern void db_finalize(struct sqlite3_stmt **ss); extern int db_execute(const char *stmt_fmt, ...); +#ifdef __cplusplus +} +#endif + #endif /* HAVE_SQLITE3 */ #endif /* _FRR_DB_H_ */ diff --git a/lib/debug.h b/lib/debug.h index d0fa27d3f..ace060d05 100644 --- a/lib/debug.h +++ b/lib/debug.h @@ -24,6 +24,10 @@ #include "command.h" #include "frratomic.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Debugging modes. * @@ -76,7 +80,7 @@ * Human-readable description of this debugging record. */ struct debug { - _Atomic uint32_t flags; + atomic_uint_fast32_t flags; const char *desc; }; @@ -231,4 +235,8 @@ struct debug_callbacks { */ void debug_init(const struct debug_callbacks *cb); +#ifdef __cplusplus +} +#endif + #endif /* _FRRDEBUG_H */ diff --git a/lib/distribute.c b/lib/distribute.c index 3a6b775bc..7cc10a230 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -409,7 +409,7 @@ int config_show_distribute(struct vty *vty, struct distribute_ctx *dist_ctxt) { unsigned int i; int has_print = 0; - struct hash_backet *mp; + struct hash_bucket *mp; struct distribute *dist; /* Output filter configuration. */ @@ -512,7 +512,7 @@ int config_write_distribute(struct vty *vty, unsigned int i; int j; int output, v6; - struct hash_backet *mp; + struct hash_bucket *mp; int write = 0; for (i = 0; i < dist_ctxt->disthash->size; i++) diff --git a/lib/distribute.h b/lib/distribute.h index 44c699b38..4016d3b13 100644 --- a/lib/distribute.h +++ b/lib/distribute.h @@ -25,6 +25,10 @@ #include "if.h" #include "filter.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Disctirubte list types. */ enum distribute_type { DISTRIBUTE_V4_IN, @@ -81,4 +85,8 @@ extern enum filter_type distribute_apply_in(struct interface *, extern enum filter_type distribute_apply_out(struct interface *, struct prefix *); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_DISTRIBUTE_H */ diff --git a/lib/event_counter.c b/lib/event_counter.c index c520937a3..57dbfb5fd 100644 --- a/lib/event_counter.c +++ b/lib/event_counter.c @@ -62,7 +62,7 @@ const char *event_counter_format(const struct event_counter *counter) || strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %T %z", last_change) == 0) { - strncpy(timebuf, "???", sizeof(timebuf)); + strlcpy(timebuf, "???", sizeof(timebuf)); } snprintf(rv, sizeof(rv), "%5llu last: %s", counter->count, diff --git a/lib/event_counter.h b/lib/event_counter.h index de5dbc066..8ae276ffe 100644 --- a/lib/event_counter.h +++ b/lib/event_counter.h @@ -43,6 +43,10 @@ #ifndef _ZEBRA_EVENT_COUNTER_H #define _ZEBRA_EVENT_COUNTER_H +#ifdef __cplusplus +extern "C" { +#endif + struct event_counter { unsigned long long count; time_t last; @@ -51,4 +55,8 @@ struct event_counter { void event_counter_inc(struct event_counter *counter); const char *event_counter_format(const struct event_counter *counter); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/ferr.h b/lib/ferr.h index 335875c16..93d0ced53 100644 --- a/lib/ferr.h +++ b/lib/ferr.h @@ -27,6 +27,10 @@ #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + /* return type when this error indication stuff is used. * * guaranteed to have boolean evaluation to "false" when OK, "true" when error @@ -253,4 +257,8 @@ DEFUN("bla") #endif /* THIS_IS_AN_EXAMPLE */ +#ifdef __cplusplus +} +#endif + #endif /* _FERR_H */ diff --git a/lib/fifo.h b/lib/fifo.h index f59e4dc6c..6f9c59b5c 100644 --- a/lib/fifo.h +++ b/lib/fifo.h @@ -20,6 +20,10 @@ #ifndef __LIB_FIFO_H__ #define __LIB_FIFO_H__ +#ifdef __cplusplus +extern "C" { +#endif + /* FIFO -- first in first out structure and macros. */ struct fifo { struct fifo *next; @@ -55,4 +59,8 @@ struct fifo { #define FIFO_TOP(F) (FIFO_EMPTY(F) ? NULL : ((struct fifo *)(F))->next) +#ifdef __cplusplus +} +#endif + #endif /* __LIB_FIFO_H__ */ diff --git a/lib/filter.c b/lib/filter.c index 1aae58b61..317c1b68b 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -2212,14 +2212,14 @@ static void access_list_init_ipv6(void) install_element(CONFIG_NODE, &no_ipv6_access_list_remark_comment_cmd); } -void access_list_init() +void access_list_init(void) { access_list_init_ipv4(); access_list_init_ipv6(); access_list_init_mac(); } -void access_list_reset() +void access_list_reset(void) { access_list_reset_ipv4(); access_list_reset_ipv6(); diff --git a/lib/filter.h b/lib/filter.h index 97854b1e9..3dd2eaaf1 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -24,6 +24,10 @@ #include "if.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Maximum ACL name length */ #define ACL_NAMSIZ 128 @@ -62,4 +66,8 @@ extern struct access_list *access_list_lookup(afi_t, const char *); extern enum filter_type access_list_apply(struct access_list *access, const void *object); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_FILTER_H */ diff --git a/lib/freebsd-queue.h b/lib/freebsd-queue.h index 4fcfe85a6..793cfff8d 100644 --- a/lib/freebsd-queue.h +++ b/lib/freebsd-queue.h @@ -33,6 +33,10 @@ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ +#ifdef __cplusplus +extern "C" { +#endif + /* * This file defines four types of data structures: singly-linked lists, * singly-linked tail queues, lists and tail queues. @@ -675,4 +679,8 @@ struct qm_trace { (head2)->tqh_last = &(head2)->tqh_first; \ } while (0) +#ifdef __cplusplus +} +#endif + #endif /* !_SYS_QUEUE_H_ */ diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index d5a2007c4..d7f655271 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -47,7 +47,7 @@ static struct list *frr_pthread_list; /* ------------------------------------------------------------------------ */ -void frr_pthread_init() +void frr_pthread_init(void) { pthread_mutex_lock(&frr_pthread_list_mtx); { @@ -57,7 +57,7 @@ void frr_pthread_init() pthread_mutex_unlock(&frr_pthread_list_mtx); } -void frr_pthread_finish() +void frr_pthread_finish(void) { pthread_mutex_lock(&frr_pthread_list_mtx); { @@ -83,9 +83,9 @@ struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr, name = (name ? name : "Anonymous thread"); fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name); if (os_name) - snprintf(fpt->os_name, OS_THREAD_NAMELEN, "%s", os_name); + strlcpy(fpt->os_name, os_name, OS_THREAD_NAMELEN); else - snprintf(fpt->os_name, OS_THREAD_NAMELEN, "%s", name); + strlcpy(fpt->os_name, name, OS_THREAD_NAMELEN); /* initialize startup synchronization primitives */ fpt->running_cond_mtx = XCALLOC( MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t)); @@ -124,7 +124,7 @@ int frr_pthread_set_name(struct frr_pthread *fpt) #ifdef HAVE_PTHREAD_SETNAME_NP # ifdef GNU_LINUX ret = pthread_setname_np(fpt->thread, fpt->os_name); -# else /* NetBSD */ +# elif defined(__NetBSD__) ret = pthread_setname_np(fpt->thread, fpt->os_name, NULL); # endif #elif defined(HAVE_PTHREAD_SET_NAME_NP) @@ -178,7 +178,7 @@ int frr_pthread_stop(struct frr_pthread *fpt, void **result) return ret; } -void frr_pthread_stop_all() +void frr_pthread_stop_all(void) { pthread_mutex_lock(&frr_pthread_list_mtx); { diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h index e6b3f031b..9bc7b9403 100644 --- a/lib/frr_pthread.h +++ b/lib/frr_pthread.h @@ -25,6 +25,10 @@ #include "memory.h" #include "thread.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(FRR_PTHREAD); DECLARE_MTYPE(PTHREAD_PRIM); @@ -73,7 +77,7 @@ struct frr_pthread { */ pthread_cond_t *running_cond; pthread_mutex_t *running_cond_mtx; - _Atomic bool running; + atomic_bool running; /* * Fake thread-specific storage. No constraints on usage. Helpful when @@ -211,4 +215,8 @@ void frr_pthread_stop_all(void); #define pthread_condattr_setclock(A, B) #endif +#ifdef __cplusplus +} +#endif + #endif /* _FRR_PTHREAD_H */ diff --git a/lib/frr_zmq.h b/lib/frr_zmq.h index 1146b8796..4303df9cc 100644 --- a/lib/frr_zmq.h +++ b/lib/frr_zmq.h @@ -23,6 +23,10 @@ #include "thread.h" #include <zmq.h> +#ifdef __cplusplus +extern "C" { +#endif + /* linking/packaging note: this is a separate library that needs to be * linked into any daemon/library/module that wishes to use its * functionality. The purpose of this is to encapsulate the libzmq @@ -124,4 +128,8 @@ extern void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core); extern void frrzmq_check_events(struct frrzmq_cb **cbp, struct cb_core *core, int event); +#ifdef __cplusplus +} +#endif + #endif /* _FRRZMQ_H */ diff --git a/lib/frratomic.h b/lib/frratomic.h index 1f1d1b569..e86030f83 100644 --- a/lib/frratomic.h +++ b/lib/frratomic.h @@ -26,7 +26,23 @@ #endif /* ISO C11 */ -#ifdef HAVE_STDATOMIC_H +#ifdef __cplusplus +#include <stdint.h> +#include <atomic> +using std::atomic_int; +using std::memory_order; +using std::memory_order_relaxed; +using std::memory_order_acquire; +using std::memory_order_release; +using std::memory_order_acq_rel; +using std::memory_order_consume; +using std::memory_order_seq_cst; + +typedef std::atomic<bool> atomic_bool; +typedef std::atomic<size_t> atomic_size_t; +typedef std::atomic<uint_fast32_t> atomic_uint_fast32_t; + +#elif defined(HAVE_STDATOMIC_H) #include <stdatomic.h> /* These are available in gcc, but not in stdatomic */ @@ -39,6 +55,7 @@ #elif defined(HAVE___ATOMIC) #define _Atomic volatile +#define _ATOMIC_WANT_TYPEDEFS #define memory_order_relaxed __ATOMIC_RELAXED #define memory_order_consume __ATOMIC_CONSUME @@ -74,6 +91,7 @@ #elif defined(HAVE___SYNC) #define _Atomic volatile +#define _ATOMIC_WANT_TYPEDEFS #define memory_order_relaxed 0 #define memory_order_consume 0 @@ -198,4 +216,15 @@ #error no atomic functions... #endif +#ifdef _ATOMIC_WANT_TYPEDEFS +#undef _ATOMIC_WANT_TYPEDEFS + +#include <stdint.h> +#include <stdbool.h> + +typedef _Atomic bool atomic_bool; +typedef _Atomic size_t atomic_size_t; +typedef _Atomic uint_fast32_t atomic_uint_fast32_t; +#endif + #endif /* _FRRATOMIC_H */ diff --git a/lib/frrstr.h b/lib/frrstr.h index 891a3f337..8b591849a 100644 --- a/lib/frrstr.h +++ b/lib/frrstr.h @@ -27,6 +27,10 @@ #include "vector.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Tokenizes a string, storing tokens in a vector. Whitespace is ignored. * Delimiter characters are not included. @@ -108,4 +112,8 @@ bool begins_with(const char *str, const char *prefix); */ int all_digit(const char *str); +#ifdef __cplusplus +} +#endif + #endif /* _FRRSTR_H_ */ diff --git a/lib/graph.c b/lib/graph.c index 4bc3eb82b..128e45c57 100644 --- a/lib/graph.c +++ b/lib/graph.c @@ -27,7 +27,7 @@ DEFINE_MTYPE_STATIC(LIB, GRAPH, "Graph") DEFINE_MTYPE_STATIC(LIB, GRAPH_NODE, "Graph Node") -struct graph *graph_new() +struct graph *graph_new(void) { struct graph *graph = XCALLOC(MTYPE_GRAPH, sizeof(struct graph)); graph->nodes = vector_init(VECTOR_MIN_SIZE); diff --git a/lib/graph.h b/lib/graph.h index 87262a07b..8e126e6be 100644 --- a/lib/graph.h +++ b/lib/graph.h @@ -28,6 +28,10 @@ #include "vector.h" #include "buffer.h" +#ifdef __cplusplus +extern "C" { +#endif + struct graph { vector nodes; }; @@ -164,4 +168,9 @@ char *graph_dump_dot(struct graph *graph, struct graph_node *start, void (*pcb)(struct graph_node *, struct buffer *buf)); #endif /* BUILDING_CLIPPY */ + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_COMMAND_GRAPH_H */ diff --git a/lib/hash.c b/lib/hash.c index 641c75136..9f9fc31d3 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -46,7 +46,7 @@ struct hash *hash_create_size(unsigned int size, assert((size & (size - 1)) == 0); hash = XCALLOC(MTYPE_HASH, sizeof(struct hash)); hash->index = - XCALLOC(MTYPE_HASH_INDEX, sizeof(struct hash_backet *) * size); + XCALLOC(MTYPE_HASH_INDEX, sizeof(struct hash_bucket *) * size); hash->size = size; hash->hash_key = hash_key; hash->hash_cmp = hash_cmp; @@ -86,7 +86,7 @@ void *hash_alloc_intern(void *arg) static void hash_expand(struct hash *hash) { unsigned int i, new_size; - struct hash_backet *hb, *hbnext, **new_index; + struct hash_bucket *hb, *hbnext, **new_index; new_size = hash->size * 2; @@ -94,7 +94,7 @@ static void hash_expand(struct hash *hash) return; new_index = XCALLOC(MTYPE_HASH_INDEX, - sizeof(struct hash_backet *) * new_size); + sizeof(struct hash_bucket *) * new_size); if (new_index == NULL) return; @@ -133,7 +133,7 @@ void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *)) unsigned int key; unsigned int index; void *newdata; - struct hash_backet *backet; + struct hash_bucket *bucket; if (!alloc_func && !hash->count) return NULL; @@ -141,10 +141,10 @@ void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *)) key = (*hash->hash_key)(data); index = key & (hash->size - 1); - for (backet = hash->index[index]; backet != NULL; - backet = backet->next) { - if (backet->key == key && (*hash->hash_cmp)(backet->data, data)) - return backet->data; + for (bucket = hash->index[index]; bucket != NULL; + bucket = bucket->next) { + if (bucket->key == key && (*hash->hash_cmp)(bucket->data, data)) + return bucket->data; } if (alloc_func) { @@ -157,26 +157,26 @@ void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *)) index = key & (hash->size - 1); } - backet = XCALLOC(MTYPE_HASH_BACKET, sizeof(struct hash_backet)); - backet->data = newdata; - backet->key = key; - backet->next = hash->index[index]; - hash->index[index] = backet; + bucket = XCALLOC(MTYPE_HASH_BACKET, sizeof(struct hash_bucket)); + bucket->data = newdata; + bucket->key = key; + bucket->next = hash->index[index]; + hash->index[index] = bucket; hash->count++; - int oldlen = backet->next ? backet->next->len : 0; + int oldlen = bucket->next ? bucket->next->len : 0; int newlen = oldlen + 1; if (newlen == 1) hash->stats.empty--; else - backet->next->len = 0; + bucket->next->len = 0; - backet->len = newlen; + bucket->len = newlen; hash_update_ssq(hash, oldlen, newlen); - return backet->data; + return bucket->data; } return NULL; } @@ -201,22 +201,22 @@ void *hash_release(struct hash *hash, void *data) void *ret; unsigned int key; unsigned int index; - struct hash_backet *backet; - struct hash_backet *pp; + struct hash_bucket *bucket; + struct hash_bucket *pp; key = (*hash->hash_key)(data); index = key & (hash->size - 1); - for (backet = pp = hash->index[index]; backet; backet = backet->next) { - if (backet->key == key - && (*hash->hash_cmp)(backet->data, data)) { + for (bucket = pp = hash->index[index]; bucket; bucket = bucket->next) { + if (bucket->key == key + && (*hash->hash_cmp)(bucket->data, data)) { int oldlen = hash->index[index]->len; int newlen = oldlen - 1; - if (backet == pp) - hash->index[index] = backet->next; + if (bucket == pp) + hash->index[index] = bucket->next; else - pp->next = backet->next; + pp->next = bucket->next; if (hash->index[index]) hash->index[index]->len = newlen; @@ -225,26 +225,26 @@ void *hash_release(struct hash *hash, void *data) hash_update_ssq(hash, oldlen, newlen); - ret = backet->data; - XFREE(MTYPE_HASH_BACKET, backet); + ret = bucket->data; + XFREE(MTYPE_HASH_BACKET, bucket); hash->count--; return ret; } - pp = backet; + pp = bucket; } return NULL; } -void hash_iterate(struct hash *hash, void (*func)(struct hash_backet *, void *), +void hash_iterate(struct hash *hash, void (*func)(struct hash_bucket *, void *), void *arg) { unsigned int i; - struct hash_backet *hb; - struct hash_backet *hbnext; + struct hash_bucket *hb; + struct hash_bucket *hbnext; for (i = 0; i < hash->size; i++) for (hb = hash->index[i]; hb; hb = hbnext) { - /* get pointer to next hash backet here, in case (*func) + /* get pointer to next hash bucket here, in case (*func) * decides to delete hb by calling hash_release */ hbnext = hb->next; @@ -252,17 +252,17 @@ void hash_iterate(struct hash *hash, void (*func)(struct hash_backet *, void *), } } -void hash_walk(struct hash *hash, int (*func)(struct hash_backet *, void *), +void hash_walk(struct hash *hash, int (*func)(struct hash_bucket *, void *), void *arg) { unsigned int i; - struct hash_backet *hb; - struct hash_backet *hbnext; + struct hash_bucket *hb; + struct hash_bucket *hbnext; int ret = HASHWALK_CONTINUE; for (i = 0; i < hash->size; i++) { for (hb = hash->index[i]; hb; hb = hbnext) { - /* get pointer to next hash backet here, in case (*func) + /* get pointer to next hash bucket here, in case (*func) * decides to delete hb by calling hash_release */ hbnext = hb->next; @@ -276,8 +276,8 @@ void hash_walk(struct hash *hash, int (*func)(struct hash_backet *, void *), void hash_clean(struct hash *hash, void (*free_func)(void *)) { unsigned int i; - struct hash_backet *hb; - struct hash_backet *next; + struct hash_bucket *hb; + struct hash_bucket *next; for (i = 0; i < hash->size; i++) { for (hb = hash->index[i]; hb; hb = next) { @@ -296,7 +296,7 @@ void hash_clean(struct hash *hash, void (*free_func)(void *)) hash->stats.empty = hash->size; } -static void hash_to_list_iter(struct hash_backet *hb, void *arg) +static void hash_to_list_iter(struct hash_bucket *hb, void *arg) { struct list *list = arg; @@ -445,7 +445,7 @@ DEFUN_NOSH(show_hash_stats, return CMD_SUCCESS; } -void hash_cmd_init() +void hash_cmd_init(void) { install_element(ENABLE_NODE, &show_hash_stats_cmd); } diff --git a/lib/hash.h b/lib/hash.h index 45ae6ce60..60c412b8e 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -24,6 +24,10 @@ #include "memory.h" #include "frratomic.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(HASH) DECLARE_MTYPE(HASH_BACKET) @@ -35,15 +39,20 @@ DECLARE_MTYPE(HASH_BACKET) #define HASHWALK_CONTINUE 0 #define HASHWALK_ABORT -1 -struct hash_backet { +#if CONFDATE > 20200225 +CPP_NOTICE("hash.h: time to remove hash_backet #define") +#endif +#define hash_backet hash_bucket + +struct hash_bucket { /* - * if this backet is the head of the linked listed, len denotes the + * if this bucket is the head of the linked listed, len denotes the * number of elements in the list */ int len; /* Linked list. */ - struct hash_backet *next; + struct hash_bucket *next; /* Hash key. */ unsigned int key; @@ -54,14 +63,14 @@ struct hash_backet { struct hashstats { /* number of empty hash buckets */ - _Atomic uint_fast32_t empty; + atomic_uint_fast32_t empty; /* sum of squares of bucket length */ - _Atomic uint_fast32_t ssq; + atomic_uint_fast32_t ssq; }; struct hash { - /* Hash backet. */ - struct hash_backet **index; + /* Hash bucket. */ + struct hash_bucket **index; /* Hash table size. Must be power of 2 */ unsigned int size; @@ -168,9 +177,9 @@ hash_create_size(unsigned int size, unsigned int (*hash_key)(void *), * hash table to operate on * * data - * data to insert or retrieve - A hash backet will not be created if + * data to insert or retrieve - A hash bucket will not be created if * the alloc_func returns a NULL pointer and nothing will be added to - * the hash. As such backet->data will always be non-NULL. + * the hash. As such bucket->data will always be non-NULL. * * alloc_func * function to call if the item is not found in the hash table. This @@ -239,7 +248,7 @@ extern void *hash_release(struct hash *hash, void *data); * during the walk will cause undefined behavior in that some new entries * will be walked and some will not. So do not do this. * - * The backet passed to func will have a non-NULL data pointer. + * The bucket passed to func will have a non-NULL data pointer. * * hash * hash table to operate on @@ -251,7 +260,7 @@ extern void *hash_release(struct hash *hash, void *data); * arbitrary argument passed as the second parameter in each call to 'func' */ extern void hash_iterate(struct hash *hash, - void (*func)(struct hash_backet *, void *), void *arg); + void (*func)(struct hash_bucket *, void *), void *arg); /* * Iterate over the elements in a hash table, stopping on condition. @@ -261,7 +270,7 @@ extern void hash_iterate(struct hash *hash, * during the walk will cause undefined behavior in that some new entries * will be walked and some will not. So do not do this. * - * The backet passed to func will have a non-NULL data pointer. + * The bucket passed to func will have a non-NULL data pointer. * * hash * hash table to operate on @@ -274,7 +283,7 @@ extern void hash_iterate(struct hash *hash, * arbitrary argument passed as the second parameter in each call to 'func' */ extern void hash_walk(struct hash *hash, - int (*func)(struct hash_backet *, void *), void *arg); + int (*func)(struct hash_bucket *, void *), void *arg); /* * Remove all elements from a hash table. @@ -325,4 +334,8 @@ extern unsigned int string_hash_make(const char *); */ extern void hash_cmd_init(void); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_HASH_H */ diff --git a/lib/hook.h b/lib/hook.h index 96fec97d7..f7fb7b8a5 100644 --- a/lib/hook.h +++ b/lib/hook.h @@ -22,6 +22,10 @@ #include "module.h" #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + /* type-safe subscribable hook points * * where "type-safe" applies to the function pointers used for subscriptions @@ -219,4 +223,8 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, #define DEFINE_KOOH(hookname, arglist, passlist) \ DEFINE_HOOK_INT(hookname, arglist, passlist, true) +#ifdef __cplusplus +} +#endif + #endif /* _FRR_HOOK_H */ diff --git a/lib/id_alloc.h b/lib/id_alloc.h index efe355658..8705ffb37 100644 --- a/lib/id_alloc.h +++ b/lib/id_alloc.h @@ -24,6 +24,10 @@ #include <limits.h> #include <stdint.h> +#ifdef __cplusplus +extern "C" { +#endif + #define IDALLOC_INVALID 0 #define IDALLOC_DIR_BITS 8 @@ -87,4 +91,8 @@ uint32_t idalloc_reserve(struct id_alloc *alloc, uint32_t id); struct id_alloc *idalloc_new(const char *name); void idalloc_destroy(struct id_alloc *alloc); +#ifdef __cplusplus +} +#endif + #endif @@ -1160,7 +1160,7 @@ DEFPY (no_interface, if (!vrfname) vrfname = VRF_DEFAULT_NAME; - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes( vty, "/frr-interface:lib/interface[name='%s'][vrf='%s']", @@ -1207,7 +1207,7 @@ DEFPY (no_interface_desc, NO_STR "Interface specific description\n") { - nb_cli_enqueue_change(vty, "./description", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, "./description", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -1379,13 +1379,13 @@ const struct frr_yang_module_info frr_interface_info = { { .xpath = "/frr-interface:lib/interface", .cbs.create = lib_interface_create, - .cbs.delete = lib_interface_delete, + .cbs.destroy = lib_interface_delete, .cbs.cli_show = cli_show_interface, }, { .xpath = "/frr-interface:lib/interface/description", .cbs.modify = lib_interface_description_modify, - .cbs.delete = lib_interface_description_delete, + .cbs.destroy = lib_interface_description_delete, .cbs.cli_show = cli_show_interface_desc, }, { @@ -27,6 +27,10 @@ #include "qobj.h" #include "hook.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(IF) DECLARE_MTYPE(CONNECTED_LABEL) @@ -290,9 +294,9 @@ struct interface { }; RB_HEAD(if_name_head, interface); -RB_PROTOTYPE(if_name_head, interface, name_entry, if_cmp_func); +RB_PROTOTYPE(if_name_head, interface, name_entry, if_cmp_func) RB_HEAD(if_index_head, interface); -RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_func); +RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_func) DECLARE_QOBJ_TYPE(interface) #define IFNAME_RB_INSERT(vrf, ifp) \ @@ -341,6 +345,8 @@ DECLARE_QOBJ_TYPE(interface) DECLARE_HOOK(if_add, (struct interface * ifp), (ifp)) DECLARE_KOOH(if_del, (struct interface * ifp), (ifp)) +#define METRIC_MAX (~0) + /* Connected address structure. */ struct connected { /* Attached interface. */ @@ -388,6 +394,13 @@ struct connected { /* Label for Linux 2.2.X and upper. */ char *label; + + /* + * Used for setting the connected route's cost. If the metric + * here is set to METRIC_MAX the connected route falls back to + * "struct interface" + */ + uint32_t metric; }; /* Nbr Connected address structure. */ @@ -536,4 +549,8 @@ void if_link_params_free(struct interface *); extern void if_cmd_init(void); extern const struct frr_yang_module_info frr_interface_info; +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_IF_H */ diff --git a/lib/if_rmap.c b/lib/if_rmap.c index 108ab7ec6..53bbcbfe5 100644 --- a/lib/if_rmap.c +++ b/lib/if_rmap.c @@ -26,14 +26,12 @@ #include "if.h" #include "if_rmap.h" +DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX, "Interface route map container") +DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX_NAME, "Interface route map container name") DEFINE_MTYPE_STATIC(LIB, IF_RMAP, "Interface route map") DEFINE_MTYPE_STATIC(LIB, IF_RMAP_NAME, "I.f. route map name") -struct hash *ifrmaphash; - -/* Hook functions. */ -static void (*if_rmap_add_hook)(struct if_rmap *) = NULL; -static void (*if_rmap_delete_hook)(struct if_rmap *) = NULL; +struct list *if_rmap_ctx_list; static struct if_rmap *if_rmap_new(void) { @@ -57,7 +55,7 @@ static void if_rmap_free(struct if_rmap *if_rmap) XFREE(MTYPE_IF_RMAP, if_rmap); } -struct if_rmap *if_rmap_lookup(const char *ifname) +struct if_rmap *if_rmap_lookup(struct if_rmap_ctx *ctx, const char *ifname) { struct if_rmap key; struct if_rmap *if_rmap; @@ -65,7 +63,7 @@ struct if_rmap *if_rmap_lookup(const char *ifname) /* temporary copy */ key.ifname = (ifname) ? XSTRDUP(MTYPE_IF_RMAP_NAME, ifname) : NULL; - if_rmap = hash_lookup(ifrmaphash, &key); + if_rmap = hash_lookup(ctx->ifrmaphash, &key); if (key.ifname) XFREE(MTYPE_IF_RMAP_NAME, key.ifname); @@ -73,14 +71,18 @@ struct if_rmap *if_rmap_lookup(const char *ifname) return if_rmap; } -void if_rmap_hook_add(void (*func)(struct if_rmap *)) +void if_rmap_hook_add(struct if_rmap_ctx *ctx, + void (*func)(struct if_rmap_ctx *ctx, + struct if_rmap *)) { - if_rmap_add_hook = func; + ctx->if_rmap_add_hook = func; } -void if_rmap_hook_delete(void (*func)(struct if_rmap *)) +void if_rmap_hook_delete(struct if_rmap_ctx *ctx, + void (*func)(struct if_rmap_ctx *ctx, + struct if_rmap *)) { - if_rmap_delete_hook = func; + ctx->if_rmap_delete_hook = func; } static void *if_rmap_hash_alloc(void *arg) @@ -94,7 +96,7 @@ static void *if_rmap_hash_alloc(void *arg) return if_rmap; } -static struct if_rmap *if_rmap_get(const char *ifname) +static struct if_rmap *if_rmap_get(struct if_rmap_ctx *ctx, const char *ifname) { struct if_rmap key; struct if_rmap *ret; @@ -102,7 +104,7 @@ static struct if_rmap *if_rmap_get(const char *ifname) /* temporary copy */ key.ifname = (ifname) ? XSTRDUP(MTYPE_IF_RMAP_NAME, ifname) : NULL; - ret = hash_get(ifrmaphash, &key, if_rmap_hash_alloc); + ret = hash_get(ctx->ifrmaphash, &key, if_rmap_hash_alloc); if (key.ifname) XFREE(MTYPE_IF_RMAP_NAME, key.ifname); @@ -125,12 +127,13 @@ static bool if_rmap_hash_cmp(const void *arg1, const void *arg2) return strcmp(if_rmap1->ifname, if_rmap2->ifname) == 0; } -static struct if_rmap *if_rmap_set(const char *ifname, enum if_rmap_type type, +static struct if_rmap *if_rmap_set(struct if_rmap_ctx *ctx, + const char *ifname, enum if_rmap_type type, const char *routemap_name) { struct if_rmap *if_rmap; - if_rmap = if_rmap_get(ifname); + if_rmap = if_rmap_get(ctx, ifname); if (type == IF_RMAP_IN) { if (if_rmap->routemap[IF_RMAP_IN]) @@ -147,18 +150,19 @@ static struct if_rmap *if_rmap_set(const char *ifname, enum if_rmap_type type, XSTRDUP(MTYPE_IF_RMAP_NAME, routemap_name); } - if (if_rmap_add_hook) - (*if_rmap_add_hook)(if_rmap); + if (ctx->if_rmap_add_hook) + (ctx->if_rmap_add_hook)(ctx, if_rmap); return if_rmap; } -static int if_rmap_unset(const char *ifname, enum if_rmap_type type, +static int if_rmap_unset(struct if_rmap_ctx *ctx, + const char *ifname, enum if_rmap_type type, const char *routemap_name) { struct if_rmap *if_rmap; - if_rmap = if_rmap_lookup(ifname); + if_rmap = if_rmap_lookup(ctx, ifname); if (!if_rmap) return 0; @@ -182,12 +186,12 @@ static int if_rmap_unset(const char *ifname, enum if_rmap_type type, if_rmap->routemap[IF_RMAP_OUT] = NULL; } - if (if_rmap_delete_hook) - (*if_rmap_delete_hook)(if_rmap); + if (ctx->if_rmap_delete_hook) + ctx->if_rmap_delete_hook(ctx, if_rmap); if (if_rmap->routemap[IF_RMAP_IN] == NULL && if_rmap->routemap[IF_RMAP_OUT] == NULL) { - hash_release(ifrmaphash, if_rmap); + hash_release(ctx->ifrmaphash, if_rmap); if_rmap_free(if_rmap); } @@ -207,6 +211,8 @@ DEFUN (if_rmap, int idx_in_out = 2; int idx_ifname = 3; enum if_rmap_type type; + struct if_rmap_ctx *ctx = + (struct if_rmap_ctx *)listnode_head(if_rmap_ctx_list); if (strncmp(argv[idx_in_out]->text, "in", 1) == 0) type = IF_RMAP_IN; @@ -217,7 +223,8 @@ DEFUN (if_rmap, return CMD_WARNING_CONFIG_FAILED; } - if_rmap_set(argv[idx_ifname]->arg, type, argv[idx_rmap_name]->arg); + if_rmap_set(ctx, argv[idx_ifname]->arg, + type, argv[idx_rmap_name]->arg); return CMD_SUCCESS; } @@ -237,6 +244,8 @@ DEFUN (no_if_rmap, int idx_ifname = 4; int ret; enum if_rmap_type type; + struct if_rmap_ctx *ctx = + (struct if_rmap_ctx *)listnode_head(if_rmap_ctx_list); if (strncmp(argv[idx_in_out]->arg, "i", 1) == 0) type = IF_RMAP_IN; @@ -247,7 +256,7 @@ DEFUN (no_if_rmap, return CMD_WARNING_CONFIG_FAILED; } - ret = if_rmap_unset(argv[idx_ifname]->arg, type, + ret = if_rmap_unset(ctx, argv[idx_ifname]->arg, type, argv[idx_routemap_name]->arg); if (!ret) { vty_out(vty, "route-map doesn't exist\n"); @@ -258,11 +267,13 @@ DEFUN (no_if_rmap, /* Configuration write function. */ -int config_write_if_rmap(struct vty *vty) +int config_write_if_rmap(struct vty *vty, + struct if_rmap_ctx *ctx) { unsigned int i; - struct hash_backet *mp; + struct hash_bucket *mp; int write = 0; + struct hash *ifrmaphash = ctx->ifrmaphash; for (i = 0; i < ifrmaphash->size; i++) for (mp = ifrmaphash->index[i]; mp; mp = mp->next) { @@ -287,18 +298,44 @@ int config_write_if_rmap(struct vty *vty) return write; } -void if_rmap_reset() +void if_rmap_ctx_delete(struct if_rmap_ctx *ctx) +{ + hash_clean(ctx->ifrmaphash, (void (*)(void *))if_rmap_free); + if (ctx->name) + XFREE(MTYPE_IF_RMAP_CTX_NAME, ctx); + XFREE(MTYPE_IF_RMAP_CTX, ctx); +} + +/* name is optional: either vrf name, or other */ +struct if_rmap_ctx *if_rmap_ctx_create(const char *name) { - hash_clean(ifrmaphash, (void (*)(void *))if_rmap_free); + struct if_rmap_ctx *ctx; + + ctx = XCALLOC(MTYPE_IF_RMAP_CTX, sizeof(struct if_rmap_ctx)); + + if (ctx->name) + ctx->name = XSTRDUP(MTYPE_IF_RMAP_CTX_NAME, name); + ctx->ifrmaphash = hash_create_size(4, if_rmap_hash_make, if_rmap_hash_cmp, + "Interface Route-Map Hash"); + if (!if_rmap_ctx_list) + if_rmap_ctx_list = list_new(); + listnode_add(if_rmap_ctx_list, ctx); + return ctx; } void if_rmap_init(int node) { - ifrmaphash = hash_create_size(4, if_rmap_hash_make, if_rmap_hash_cmp, - "Interface Route-Map Hash"); if (node == RIPNG_NODE) { } else if (node == RIP_NODE) { install_element(RIP_NODE, &if_rmap_cmd); install_element(RIP_NODE, &no_if_rmap_cmd); } + if_rmap_ctx_list = list_new(); +} + +void if_rmap_terminate(void) +{ + if (!if_rmap_ctx_list) + return; + list_delete(&if_rmap_ctx_list); } diff --git a/lib/if_rmap.h b/lib/if_rmap.h index 4468b9fb9..dfc729882 100644 --- a/lib/if_rmap.h +++ b/lib/if_rmap.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_IF_RMAP_H #define _ZEBRA_IF_RMAP_H +#ifdef __cplusplus +extern "C" { +#endif + enum if_rmap_type { IF_RMAP_IN, IF_RMAP_OUT, IF_RMAP_MAX }; struct if_rmap { @@ -30,11 +34,36 @@ struct if_rmap { char *routemap[IF_RMAP_MAX]; }; -extern void if_rmap_init(int); -extern void if_rmap_reset(void); -extern void if_rmap_hook_add(void (*)(struct if_rmap *)); -extern void if_rmap_hook_delete(void (*)(struct if_rmap *)); -extern struct if_rmap *if_rmap_lookup(const char *); -extern int config_write_if_rmap(struct vty *); +struct if_rmap_ctx { + /* if_rmap */ + struct hash *ifrmaphash; + + /* Hook functions. */ + void (*if_rmap_add_hook)(struct if_rmap_ctx *ctx, + struct if_rmap *ifrmap); + void (*if_rmap_delete_hook)(struct if_rmap_ctx *ctx, + struct if_rmap *ifrmap); + + /* naming information */ + char *name; +}; + +extern struct if_rmap_ctx *if_rmap_ctx_create(const char *name); +extern void if_rmap_ctx_delete(struct if_rmap_ctx *ctx); +extern void if_rmap_init(int node); +extern void if_rmap_terminate(void); +void if_rmap_hook_add(struct if_rmap_ctx *ctx, + void (*func)(struct if_rmap_ctx *ctx, + struct if_rmap *)); +void if_rmap_hook_delete(struct if_rmap_ctx *ctx, + void (*func)(struct if_rmap_ctx *ctx, + struct if_rmap *)); +extern struct if_rmap *if_rmap_lookup(struct if_rmap_ctx *ctx, + const char *ifname); +extern int config_write_if_rmap(struct vty *, struct if_rmap_ctx *ctx); + +#ifdef __cplusplus +} +#endif #endif /* _ZEBRA_IF_RMAP_H */ diff --git a/lib/imsg.h b/lib/imsg.h index eed7074e4..3f81b76be 100644 --- a/lib/imsg.h +++ b/lib/imsg.h @@ -21,6 +21,10 @@ #ifndef _IMSG_H_ #define _IMSG_H_ +#ifdef __cplusplus +extern "C" { +#endif + #define IBUF_READ_SIZE 65535 #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) #define MAX_IMSGSIZE 16384 @@ -108,4 +112,8 @@ void imsg_free(struct imsg *); int imsg_flush(struct imsgbuf *); void imsg_clear(struct imsgbuf *); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/ipaddr.h b/lib/ipaddr.h index 7f2d06548..f4ddadc66 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -25,6 +25,10 @@ #include <zebra.h> +#ifdef __cplusplus +extern "C" { +#endif + /* * Generic IP address - union of IPv4 and IPv6 address. */ @@ -112,4 +116,8 @@ static inline void ipv4_mapped_ipv6_to_ipv4(struct in6_addr *in6, memcpy(in, (char *)in6 + 12, sizeof(struct in_addr)); } +#ifdef __cplusplus +} +#endif + #endif /* __IPADDR_H__ */ diff --git a/lib/jhash.h b/lib/jhash.h index f8ab4209a..977421495 100644 --- a/lib/jhash.h +++ b/lib/jhash.h @@ -20,6 +20,10 @@ #ifndef _QUAGGA_JHASH_H #define _QUAGGA_JHASH_H +#ifdef __cplusplus +extern "C" { +#endif + /* The most generic version, hashes an arbitrary sequence * of bytes. No alignment or length assumptions are made about * the input key. @@ -42,4 +46,8 @@ extern uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, extern uint32_t jhash_2words(uint32_t a, uint32_t b, uint32_t initval); extern uint32_t jhash_1word(uint32_t a, uint32_t initval); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_JHASH_H */ diff --git a/lib/json.h b/lib/json.h index d34916230..a5251662b 100644 --- a/lib/json.h +++ b/lib/json.h @@ -21,6 +21,10 @@ #ifndef _QUAGGA_JSON_H #define _QUAGGA_JSON_H +#ifdef __cplusplus +extern "C" { +#endif + #if defined(HAVE_JSON_C_JSON_H) #include <json-c/json.h> @@ -81,4 +85,8 @@ extern void json_object_free(struct json_object *obj); #define JSON_C_TO_STRING_NOSLASHESCAPE (1<<4) #endif +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_JSON_H */ diff --git a/lib/keychain.c b/lib/keychain.c index 601b44a4f..9aa3ef695 100644 --- a/lib/keychain.c +++ b/lib/keychain.c @@ -1040,7 +1040,7 @@ static int keychain_config_write(struct vty *vty) return 0; } -void keychain_init() +void keychain_init(void) { keychain_list = list_new(); diff --git a/lib/keychain.h b/lib/keychain.h index 49da9ba45..e5cf39f7c 100644 --- a/lib/keychain.h +++ b/lib/keychain.h @@ -23,6 +23,10 @@ #include "qobj.h" +#ifdef __cplusplus +extern "C" { +#endif + struct keychain { char *name; @@ -57,4 +61,8 @@ extern struct key *key_lookup_for_accept(const struct keychain *, uint32_t); extern struct key *key_match_for_accept(const struct keychain *, const char *); extern struct key *key_lookup_for_send(const struct keychain *); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_KEYCHAIN_H */ diff --git a/lib/lib_errors.h b/lib/lib_errors.h index 86a83df46..fc405c209 100644 --- a/lib/lib_errors.h +++ b/lib/lib_errors.h @@ -23,6 +23,10 @@ #include "lib/ferr.h" +#ifdef __cplusplus +extern "C" { +#endif + enum lib_log_refs { EC_LIB_PRIVILEGES = LIB_FERR_START, EC_LIB_VRF_START, @@ -82,4 +86,8 @@ enum lib_log_refs { extern void lib_error_init(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/libfrr.h b/lib/libfrr.h index 2705397b8..891e2c128 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -30,6 +30,10 @@ #include "hook.h" #include "northbound.h" +#ifdef __cplusplus +extern "C" { +#endif + /* The following options disable specific command line options that * are not applicable for a particular daemon. */ @@ -152,4 +156,8 @@ extern char frr_protonameinst[]; extern bool debug_memstats_at_exit; +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_FRR_H */ diff --git a/lib/libospf.h b/lib/libospf.h index 45aedb6a7..d2bb29d80 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -22,6 +22,10 @@ #ifndef _LIBOSPFD_H #define _LIBOSPFD_H +#ifdef __cplusplus +extern "C" { +#endif + /* IP precedence. */ #ifndef IPTOS_PREC_INTERNETCONTROL #define IPTOS_PREC_INTERNETCONTROL 0xC0 @@ -94,4 +98,8 @@ #define OSPF_LSA_MAXAGE_CHECK_INTERVAL 30 #define OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT 60 +#ifdef __cplusplus +} +#endif + #endif /* _LIBOSPFD_H */ diff --git a/lib/linklist.h b/lib/linklist.h index 0475391e9..76fad45d0 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_LINKLIST_H #define _ZEBRA_LINKLIST_H +#ifdef __cplusplus +extern "C" { +#endif + /* listnodes must always contain data to be valid. Adding an empty node * to a list is invalid */ @@ -291,7 +295,8 @@ extern void list_add_list(struct list *list, struct list *add); #define ALL_LIST_ELEMENTS(list, node, nextnode, data) \ (node) = listhead(list), ((data) = NULL); \ (node) != NULL \ - && ((data) = listgetdata(node), (nextnode) = node->next, 1); \ + && ((data) = static_cast(data, listgetdata(node)), \ + (nextnode) = node->next, 1); \ (node) = (nextnode), ((data) = NULL) /* read-only list iteration macro. @@ -302,7 +307,7 @@ extern void list_add_list(struct list *list, struct list *add); */ #define ALL_LIST_ELEMENTS_RO(list, node, data) \ (node) = listhead(list), ((data) = NULL); \ - (node) != NULL && ((data) = listgetdata(node), 1); \ + (node) != NULL && ((data) = static_cast(data, listgetdata(node)), 1); \ (node) = listnextnode(node), ((data) = NULL) /* these *do not* cleanup list nodes and referenced data, as the functions @@ -336,4 +341,8 @@ extern void list_add_list(struct list *list, struct list *add); (L)->count--; \ } while (0) +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_LINKLIST_H */ @@ -29,6 +29,7 @@ #include "memory.h" #include "command.h" #include "lib_errors.h" +#include "lib/hook.h" #ifndef SUNOS_5 #include <sys/un.h> @@ -46,6 +47,10 @@ DEFINE_MTYPE_STATIC(LIB, ZLOG, "Logging") +/* hook for external logging */ +DEFINE_HOOK(zebra_ext_log, (int priority, const char *format, va_list args), + (priority, format, args)); + static int logfile_fd = -1; /* Used in signal handler. */ struct zlog *zlog_default = NULL; @@ -213,6 +218,9 @@ void vzlog(int priority, const char *format, va_list args) tsctl.already_rendered = 0; struct zlog *zl = zlog_default; + /* call external hook */ + hook_call(zebra_ext_log, priority, format, args); + /* When zlog_default is also NULL, use stderr for logging. */ if (zl == NULL) { tsctl.precision = 0; @@ -1019,6 +1027,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK), DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI), DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW), + DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP), DESC_ENTRY(ZEBRA_ADVERTISE_SUBNET), DESC_ENTRY(ZEBRA_LOCAL_ES_ADD), DESC_ENTRY(ZEBRA_LOCAL_ES_DEL), @@ -26,6 +26,16 @@ #include <stdint.h> #include <stdbool.h> #include <stdio.h> +#include <stdarg.h> +#include "lib/hook.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Hook for external logging function */ +DECLARE_HOOK(zebra_ext_log, (int priority, const char *format, va_list args), + (priority, format, args)); /* Here is some guidance on logging levels to use: * @@ -87,11 +97,11 @@ extern void zlog_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); /* For logs which have error codes associated with them */ #define flog_err(ferr_id, format, ...) \ - zlog_err("[EC %"PRIu32"] " format, ferr_id, ##__VA_ARGS__) + zlog_err("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__) #define flog_err_sys(ferr_id, format, ...) \ flog_err(ferr_id, format, ##__VA_ARGS__) #define flog_warn(ferr_id, format, ...) \ - zlog_warn("[EC %"PRIu32"] " format, ferr_id, ##__VA_ARGS__) + zlog_warn("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__) extern void zlog_thread_info(int log_level); @@ -190,4 +200,8 @@ struct timestamp_control { "Local use\n" \ "Local use\n" +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_LOG_H */ diff --git a/lib/log_int.h b/lib/log_int.h index a7f8be9ae..58ae031e1 100644 --- a/lib/log_int.h +++ b/lib/log_int.h @@ -24,6 +24,10 @@ #include "log.h" +#ifdef __cplusplus +extern "C" { +#endif + struct zlog { const char *ident; /* daemon name (first arg to openlog) */ const char *protoname; @@ -49,4 +53,8 @@ extern const char *zlog_priority[]; extern void vzlog(int priority, const char *format, va_list args); extern void zlog(int priority, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_LOG_PRIVATE_H */ diff --git a/lib/logicalrouter.h b/lib/logicalrouter.h index 5a0780c00..d18832ef7 100644 --- a/lib/logicalrouter.h +++ b/lib/logicalrouter.h @@ -20,6 +20,10 @@ #ifndef _ZEBRA_LOGICAL_ROUTER_H #define _ZEBRA_LOGICAL_ROUTER_H +#ifdef __cplusplus +extern "C" { +#endif + /* Logical Router Backend defines */ #define LOGICALROUTER_BACKEND_OFF 0 #define LOGICALROUTER_BACKEND_NETNS 1 @@ -38,4 +42,8 @@ extern void logicalrouter_terminate(void); */ extern void logicalrouter_configure_backend(int backend_netns); +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_LOGICAL_ROUTER_H*/ @@ -29,6 +29,10 @@ #include <lualib.h> #include <lauxlib.h> +#ifdef __cplusplus +extern "C" { +#endif + /* * These functions are helper functions that * try to glom some of the lua_XXX functionality @@ -75,5 +79,10 @@ enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule); */ const char *get_string(lua_State *L, const char *key); int get_integer(lua_State *L, const char *key); + +#ifdef __cplusplus +} +#endif + #endif #endif @@ -375,13 +375,8 @@ static void md5_calc(const uint8_t *b64, md5_ctxt *ctxt) } /* From RFC 2104 */ -void hmac_md5(text, text_len, key, key_len, - digest) unsigned char *text; /* pointer to data stream */ -int text_len; /* length of data stream */ -unsigned char *key; /* pointer to authentication key */ -int key_len; /* length of authentication key */ -uint8_t *digest; /* caller digest to be filled in */ - +void hmac_md5(unsigned char *text, int text_len, unsigned char *key, + int key_len, uint8_t *digest) { MD5_CTX context; unsigned char k_ipad[65]; /* inner padding - @@ -38,6 +38,10 @@ #ifndef _LIBZEBRA_MD5_H_ #define _LIBZEBRA_MD5_H_ +#ifdef __cplusplus +extern "C" { +#endif + #define MD5_BUFLEN 64 typedef struct { @@ -82,4 +86,8 @@ extern void md5_result(uint8_t *, md5_ctxt *); void hmac_md5(unsigned char *text, int text_len, unsigned char *key, int key_len, uint8_t *digest); +#ifdef __cplusplus +} +#endif + #endif /* ! _LIBZEBRA_MD5_H_*/ diff --git a/lib/memory.c b/lib/memory.c index fee23a75a..149e294d5 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -35,7 +35,6 @@ struct memgroup **mg_insert = &mg_first; DEFINE_MGROUP(LIB, "libfrr") DEFINE_MTYPE(LIB, TMP, "Temporary memory") -DEFINE_MTYPE(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec") static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr) { diff --git a/lib/memory.h b/lib/memory.h index 2d6c14477..91a02b796 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -22,6 +22,10 @@ #include <frratomic.h> #include "compiler.h" +#ifdef __cplusplus +extern "C" { +#endif + #define array_size(ar) (sizeof(ar) / sizeof(ar[0])) #if defined(HAVE_MALLOC_SIZE) && !defined(HAVE_MALLOC_USABLE_SIZE) @@ -33,12 +37,12 @@ struct memtype { struct memtype *next, **ref; const char *name; - _Atomic size_t n_alloc; - _Atomic size_t n_max; - _Atomic size_t size; + atomic_size_t n_alloc; + atomic_size_t n_max; + atomic_size_t size; #ifdef HAVE_MALLOC_USABLE_SIZE - _Atomic size_t total; - _Atomic size_t max_size; + atomic_size_t total; + atomic_size_t max_size; #endif }; @@ -137,7 +141,6 @@ struct memgroup { DECLARE_MGROUP(LIB) DECLARE_MTYPE(TMP) -DECLARE_MTYPE(PREFIX_FLOWSPEC) extern void *qmalloc(struct memtype *mt, size_t size) @@ -177,4 +180,8 @@ extern int log_memstats(FILE *fp, const char *); extern void memory_oom(size_t size, const char *name); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_MEMORY_H */ diff --git a/lib/memory_vty.h b/lib/memory_vty.h index b66c3b6d6..941255be1 100644 --- a/lib/memory_vty.h +++ b/lib/memory_vty.h @@ -23,9 +23,18 @@ #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + extern void memory_init(void); /* Human friendly string for given byte count */ #define MTYPE_MEMSTR_LEN 20 extern const char *mtype_memstr(char *, size_t, unsigned long); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_MEMORY_VTY_H */ diff --git a/lib/mlag.h b/lib/mlag.h index 73725ca3f..2b904d44f 100644 --- a/lib/mlag.h +++ b/lib/mlag.h @@ -22,6 +22,10 @@ #ifndef __MLAG_H__ #define __MLAG_H__ +#ifdef __cplusplus +extern "C" { +#endif + enum mlag_role { MLAG_ROLE_NONE, MLAG_ROLE_PRIMARY, @@ -29,4 +33,9 @@ enum mlag_role { }; extern char *mlag_role2str(enum mlag_role role, char *buf, size_t size); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/module.h b/lib/module.h index 68ed95927..c5f96db85 100644 --- a/lib/module.h +++ b/lib/module.h @@ -20,6 +20,10 @@ #include <stdint.h> #include <stdbool.h> +#ifdef __cplusplus +extern "C" { +#endif + #if !defined(__GNUC__) #error module code needs GCC visibility extensions #elif __GNUC__ < 4 @@ -78,9 +82,10 @@ extern union _frrmod_runtime_u _frrmod_this_module; #define FRR_COREMOD_SETUP(...) \ static const struct frrmod_info _frrmod_info = {__VA_ARGS__}; \ - DSO_LOCAL union _frrmod_runtime_u _frrmod_this_module = { \ - .r.info = &_frrmod_info, \ - }; + DSO_LOCAL union _frrmod_runtime_u _frrmod_this_module = {{ \ + NULL, \ + &_frrmod_info, \ + }}; #define FRR_MODULE_SETUP(...) \ FRR_COREMOD_SETUP(__VA_ARGS__) \ DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r; @@ -95,4 +100,8 @@ extern struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, extern void frrmod_unload(struct frrmod_runtime *module); #endif +#ifdef __cplusplus +} +#endif + #endif /* _FRR_MODULE_H */ diff --git a/lib/monotime.h b/lib/monotime.h index 00b940046..6aac966ea 100644 --- a/lib/monotime.h +++ b/lib/monotime.h @@ -21,6 +21,10 @@ #include <time.h> #include <sys/time.h> +#ifdef __cplusplus +extern "C" { +#endif + #ifndef TIMESPEC_TO_TIMEVAL /* should be in sys/time.h on BSD & Linux libcs */ #define TIMESPEC_TO_TIMEVAL(tv, ts) \ @@ -91,4 +95,8 @@ static inline char *time_to_string(time_t ts) return ctime(&tbuf); } +#ifdef __cplusplus +} +#endif + #endif /* _FRR_MONOTIME_H */ diff --git a/lib/mpls.h b/lib/mpls.h index 614698561..b140c8e31 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -25,6 +25,10 @@ #include <zebra.h> #include <arpa/inet.h> +#ifdef __cplusplus +extern "C" { +#endif + #ifdef MPLS_LABEL_MAX #undef MPLS_LABEL_MAX #endif @@ -209,4 +213,8 @@ int mpls_str2label(const char *label_str, uint8_t *num_labels, char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf, int len, int pretty); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/network.h b/lib/network.h index 4703dc9b6..a00c5a0a6 100644 --- a/lib/network.h +++ b/lib/network.h @@ -22,6 +22,10 @@ #ifndef _ZEBRA_NETWORK_H #define _ZEBRA_NETWORK_H +#ifdef __cplusplus +extern "C" { +#endif + /* Both readn and writen are deprecated and will be removed. They are not suitable for use with non-blocking file descriptors. */ @@ -41,4 +45,8 @@ extern int set_cloexec(int fd); extern float htonf(float); extern float ntohf(float); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_NETWORK_H */ diff --git a/lib/nexthop.h b/lib/nexthop.h index e4af405d5..fd27ca207 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -26,6 +26,10 @@ #include "prefix.h" #include "mpls.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Maximum next hop string length - gateway + ifindex */ #define NEXTHOP_STRLEN (INET6_ADDRSTRLEN + 30) @@ -79,7 +83,6 @@ struct nexthop { #define NEXTHOP_FLAG_MATCHED (1 << 4) /* Already matched vs a nexthop */ #define NEXTHOP_FLAG_FILTERED (1 << 5) /* rmap filtered, used by static only */ #define NEXTHOP_FLAG_DUPLICATE (1 << 6) /* nexthop duplicates another active one */ -#define NEXTHOP_FLAG_EVPN_RVTEP (1 << 7) /* EVPN remote vtep nexthop */ #define NEXTHOP_IS_ACTIVE(flags) \ (CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \ && !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE)) @@ -146,4 +149,9 @@ extern int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2); extern const char *nexthop2str(const struct nexthop *nexthop, char *str, int size); extern struct nexthop *nexthop_next(struct nexthop *nexthop); extern unsigned int nexthop_level(struct nexthop *nexthop); + +#ifdef __cplusplus +} +#endif + #endif /*_LIB_NEXTHOP_H */ diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 473ecb34f..b14cbb5b5 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -23,6 +23,10 @@ #include <vty.h> +#ifdef __cplusplus +extern "C" { +#endif + /* * What is a nexthop group? * @@ -92,12 +96,12 @@ DECLARE_QOBJ_TYPE(nexthop_group_cmd) * code */ void nexthop_group_init( - void (*new)(const char *name), + void (*create)(const char *name), void (*add_nexthop)(const struct nexthop_group_cmd *nhgc, const struct nexthop *nhop), void (*del_nexthop)(const struct nexthop_group_cmd *nhgc, const struct nexthop *nhop), - void (*delete)(const char *name)); + void (*destroy)(const char *name)); void nexthop_group_enable_vrf(struct vrf *vrf); void nexthop_group_disable_vrf(struct vrf *vrf); @@ -110,4 +114,9 @@ extern struct nexthop *nexthop_exists(struct nexthop_group *nhg, extern struct nexthop_group_cmd *nhgc_find(const char *name); extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/northbound.c b/lib/northbound.c index 6fe612d72..15139aa8d 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -184,8 +184,8 @@ static unsigned int nb_node_validate_cbs(const struct nb_node *nb_node) !!nb_node->cbs.create, false); error += nb_node_validate_cb(nb_node, NB_OP_MODIFY, !!nb_node->cbs.modify, false); - error += nb_node_validate_cb(nb_node, NB_OP_DELETE, - !!nb_node->cbs.delete, false); + error += nb_node_validate_cb(nb_node, NB_OP_DESTROY, + !!nb_node->cbs.destroy, false); error += nb_node_validate_cb(nb_node, NB_OP_MOVE, !!nb_node->cbs.move, false); error += nb_node_validate_cb(nb_node, NB_OP_APPLY_FINISH, @@ -417,7 +417,7 @@ static void nb_config_diff(const struct nb_config *config1, break; case LYD_DIFF_DELETED: dnode = diff->first[i]; - operation = NB_OP_DELETE; + operation = NB_OP_DESTROY; break; case LYD_DIFF_CHANGED: dnode = diff->second[i]; @@ -485,7 +485,7 @@ int nb_candidate_edit(struct nb_config *candidate, lyd_validate(&dnode, LYD_OPT_CONFIG, ly_native_ctx); } break; - case NB_OP_DELETE: + case NB_OP_DESTROY: dnode = yang_dnode_get(candidate->dnode, xpath_edit); if (!dnode) /* @@ -741,8 +741,8 @@ static int nb_configuration_callback(const enum nb_event event, case NB_OP_MODIFY: ret = (*nb_node->cbs.modify)(event, dnode, resource); break; - case NB_OP_DELETE: - ret = (*nb_node->cbs.delete)(event, dnode); + case NB_OP_DESTROY: + ret = (*nb_node->cbs.destroy)(event, dnode); break; case NB_OP_MOVE: ret = (*nb_node->cbs.move)(event, dnode); @@ -912,7 +912,7 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction) * (the 'apply_finish' callbacks from the node ancestors should * be called though). */ - if (change->cb.operation == NB_OP_DELETE) { + if (change->cb.operation == NB_OP_DESTROY) { char xpath[XPATH_MAXLEN]; dnode = dnode->parent; @@ -1359,7 +1359,7 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; } return true; - case NB_OP_DELETE: + case NB_OP_DESTROY: if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; @@ -1511,8 +1511,8 @@ const char *nb_operation_name(enum nb_operation operation) return "create"; case NB_OP_MODIFY: return "modify"; - case NB_OP_DELETE: - return "delete"; + case NB_OP_DESTROY: + return "destroy"; case NB_OP_MOVE: return "move"; case NB_OP_APPLY_FINISH: diff --git a/lib/northbound.h b/lib/northbound.h index 9d35a4e64..bb6b62af7 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -27,6 +27,10 @@ #include "yang.h" #include "yang_translator.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declaration(s). */ struct vty; @@ -65,7 +69,7 @@ enum nb_event { enum nb_operation { NB_OP_CREATE, NB_OP_MODIFY, - NB_OP_DELETE, + NB_OP_DESTROY, NB_OP_MOVE, NB_OP_APPLY_FINISH, NB_OP_GET_ELEM, @@ -168,7 +172,7 @@ struct nb_callbacks { * - NB_ERR_INCONSISTENCY when an inconsistency was detected. * - NB_ERR for other errors. */ - int (*delete)(enum nb_event event, const struct lyd_node *dnode); + int (*destroy)(enum nb_event event, const struct lyd_node *dnode); /* * Configuration callback. @@ -839,4 +843,8 @@ extern void nb_init(struct thread_master *tm, const struct frr_yang_module_info */ extern void nb_terminate(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_NORTHBOUND_H_ */ diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h index 884f25094..209239ca6 100644 --- a/lib/northbound_cli.h +++ b/lib/northbound_cli.h @@ -22,6 +22,10 @@ #include "northbound.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Possible formats in which a configuration can be displayed. */ enum nb_cfg_format { NB_CFG_FMT_CMDS = 0, @@ -111,4 +115,8 @@ extern void nb_cli_install_default(int node); extern void nb_cli_init(struct thread_master *tm); extern void nb_cli_terminate(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_NORTHBOUND_CLI_H_ */ diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index 53149d0fd..a8e001781 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -228,7 +228,7 @@ frr_confd_cdb_diff_iter(confd_hkeypath_t *kp, enum cdb_iter_op cdb_op, nb_op = NB_OP_CREATE; break; case MOP_DELETED: - nb_op = NB_OP_DELETE; + nb_op = NB_OP_DESTROY; break; case MOP_VALUE_SET: if (nb_operation_is_valid(NB_OP_MODIFY, nb_node->snode)) diff --git a/lib/northbound_db.h b/lib/northbound_db.h index ad6096644..14df09caa 100644 --- a/lib/northbound_db.h +++ b/lib/northbound_db.h @@ -22,6 +22,10 @@ #include "northbound.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Initialize the northbound database. * @@ -101,4 +105,8 @@ extern int nb_db_transactions_iterate( const char *date, const char *comment), void *arg); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_NORTHBOUND_DB_H_ */ diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index 860c27edb..f426f52bd 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -202,10 +202,10 @@ static int frr_sr_process_change(struct nb_config *candidate, * notified about the removal of all of its leafs, even the ones * that are non-optional. We need to ignore these notifications. */ - if (!nb_operation_is_valid(NB_OP_DELETE, nb_node->snode)) + if (!nb_operation_is_valid(NB_OP_DESTROY, nb_node->snode)) return NB_OK; - nb_op = NB_OP_DELETE; + nb_op = NB_OP_DESTROY; break; case SR_OP_MOVED: nb_op = NB_OP_MOVE; @@ -26,6 +26,10 @@ #include "linklist.h" #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef uint32_t ns_id_t; /* the default NS ID */ @@ -174,4 +178,8 @@ extern int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *)); extern struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id); extern void ns_disable(struct ns *ns); +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_NS_H*/ diff --git a/lib/openbsd-queue.h b/lib/openbsd-queue.h index e09cc3d4e..d4c08a3be 100644 --- a/lib/openbsd-queue.h +++ b/lib/openbsd-queue.h @@ -35,6 +35,10 @@ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ +#ifdef __cplusplus +extern "C" { +#endif + /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues and XOR simple queues. @@ -572,4 +576,8 @@ } \ } while (0) +#ifdef __cplusplus +} +#endif + #endif /* !_SYS_QUEUE_H_ */ diff --git a/lib/openbsd-tree.h b/lib/openbsd-tree.h index 1383ef6de..d2f078133 100644 --- a/lib/openbsd-tree.h +++ b/lib/openbsd-tree.h @@ -27,6 +27,10 @@ #ifndef _SYS_TREE_H_ #define _SYS_TREE_H_ +#ifdef __cplusplus +extern "C" { +#endif + /* * This file defines data structures for different types of trees: * splay trees and red-black trees. @@ -397,31 +401,36 @@ int _rb_check(const struct rb_type *, void *, unsigned long); __attribute__((__unused__)) static inline struct _type \ *_name##_RB_INSERT(struct _name *head, struct _type *elm) \ { \ - return _rb_insert(_name##_RB_TYPE, &head->rbh_root, elm); \ + return (struct _type *)_rb_insert( \ + _name##_RB_TYPE, &head->rbh_root, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_REMOVE(struct _name *head, struct _type *elm) \ { \ - return _rb_remove(_name##_RB_TYPE, &head->rbh_root, elm); \ + return (struct _type *)_rb_remove( \ + _name##_RB_TYPE, &head->rbh_root, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_FIND(struct _name *head, const struct _type *key) \ { \ - return _rb_find(_name##_RB_TYPE, &head->rbh_root, key); \ + return (struct _type *)_rb_find( \ + _name##_RB_TYPE, &head->rbh_root, key); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_NFIND(struct _name *head, const struct _type *key) \ { \ - return _rb_nfind(_name##_RB_TYPE, &head->rbh_root, key); \ + return (struct _type *)_rb_nfind( \ + _name##_RB_TYPE, &head->rbh_root, key); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_ROOT(struct _name *head) \ { \ - return _rb_root(_name##_RB_TYPE, &head->rbh_root); \ + return (struct _type *)_rb_root( \ + _name##_RB_TYPE, &head->rbh_root); \ } \ \ __attribute__((__unused__)) static inline int _name##_RB_EMPTY( \ @@ -433,43 +442,45 @@ int _rb_check(const struct rb_type *, void *, unsigned long); __attribute__((__unused__)) static inline struct _type \ *_name##_RB_MIN(struct _name *head) \ { \ - return _rb_min(_name##_RB_TYPE, &head->rbh_root); \ + return (struct _type *)_rb_min( \ + _name##_RB_TYPE, &head->rbh_root); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_MAX(struct _name *head) \ { \ - return _rb_max(_name##_RB_TYPE, &head->rbh_root); \ + return (struct _type *)_rb_max( \ + _name##_RB_TYPE, &head->rbh_root); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_NEXT(struct _type *elm) \ { \ - return _rb_next(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_next(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_PREV(struct _type *elm) \ { \ - return _rb_prev(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_prev(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_LEFT(struct _type *elm) \ { \ - return _rb_left(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_left(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_RIGHT(struct _type *elm) \ { \ - return _rb_right(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_right(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_PARENT(struct _type *elm) \ { \ - return _rb_parent(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_parent(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline void _name##_RB_SET_LEFT( \ @@ -560,4 +571,8 @@ int _rb_check(const struct rb_type *, void *, unsigned long); for ((_e) = RB_MAX(_name, (_head)); \ (_e) != NULL && ((_n) = RB_PREV(_name, (_e)), 1); (_e) = (_n)) +#ifdef __cplusplus +} +#endif + #endif /* _SYS_TREE_H_ */ @@ -24,6 +24,10 @@ #include "stream.h" #include "prefix.h" +#ifdef __cplusplus +extern "C" { +#endif + #define PBR_STR "Policy Based Routing\n" /* @@ -121,4 +125,8 @@ struct pbr_rule { extern int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule); +#ifdef __cplusplus +} +#endif + #endif /* _PBR_H */ diff --git a/lib/plist.c b/lib/plist.c index ee68fbc0f..41c8e4f8c 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -2111,7 +2111,7 @@ static void prefix_list_init_ipv6(void) install_element(ENABLE_NODE, &clear_ipv6_prefix_list_cmd); } -void prefix_list_init() +void prefix_list_init(void) { cmd_variable_handler_register(plist_var_handlers); @@ -2119,7 +2119,7 @@ void prefix_list_init() prefix_list_init_ipv6(); } -void prefix_list_reset() +void prefix_list_reset(void) { prefix_list_reset_afi(AFI_IP, 0); prefix_list_reset_afi(AFI_IP6, 0); diff --git a/lib/plist.h b/lib/plist.h index 8a4fa8d3c..ba2846d74 100644 --- a/lib/plist.h +++ b/lib/plist.h @@ -27,6 +27,10 @@ #include "stream.h" #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + enum prefix_list_type { PREFIX_DENY, PREFIX_PERMIT, @@ -75,4 +79,8 @@ extern void prefix_bgp_orf_remove_all(afi_t, char *); extern int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name, bool use_json); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_PLIST_H */ diff --git a/lib/plist_int.h b/lib/plist_int.h index 6bc2d034d..443b0c614 100644 --- a/lib/plist_int.h +++ b/lib/plist_int.h @@ -22,6 +22,10 @@ #ifndef _QUAGGA_PLIST_INT_H #define _QUAGGA_PLIST_INT_H +#ifdef __cplusplus +extern "C" { +#endif + enum prefix_name_type { PREFIX_TYPE_STRING, PREFIX_TYPE_NUMBER }; struct pltrie_table; @@ -68,4 +72,8 @@ struct prefix_list_entry { struct prefix_list_entry *next_best; }; +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_PLIST_INT_H */ diff --git a/lib/pqueue.h b/lib/pqueue.h index 53e5aa833..032ee9db4 100644 --- a/lib/pqueue.h +++ b/lib/pqueue.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_PQUEUE_H #define _ZEBRA_PQUEUE_H +#ifdef __cplusplus +extern "C" { +#endif + struct pqueue { void **array; int array_size; @@ -43,4 +47,8 @@ extern void pqueue_remove(void *data, struct pqueue *queue); extern void trickle_down(int index, struct pqueue *queue); extern void trickle_up(int index, struct pqueue *queue); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PQUEUE_H */ diff --git a/lib/prefix.c b/lib/prefix.c index 020330156..80a89cc3c 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -30,6 +30,7 @@ #include "lib_errors.h" DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix") +DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec") /* Maskbit. */ static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, @@ -820,7 +821,7 @@ const char *prefix_family_str(const struct prefix *p) } /* Allocate new prefix_ipv4 structure. */ -struct prefix_ipv4 *prefix_ipv4_new() +struct prefix_ipv4 *prefix_ipv4_new(void) { struct prefix_ipv4 *p; @@ -865,7 +866,7 @@ int str2prefix_ipv4(const char *str, struct prefix_ipv4 *p) return ret; } else { cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1); - strncpy(cp, str, pnt - str); + memcpy(cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; ret = inet_aton(cp, &p->prefix); XFREE(MTYPE_TMP, cp); @@ -912,7 +913,7 @@ int str2prefix_eth(const char *str, struct prefix_eth *p) } cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1); - strncpy(cp, str, pnt - str); + memcpy(cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; str_addr = cp; @@ -1029,7 +1030,7 @@ int str2prefix_ipv6(const char *str, struct prefix_ipv6 *p) int plen; cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1); - strncpy(cp, str, pnt - str); + memcpy(cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; ret = inet_pton(AF_INET6, cp, &p->prefix); XFREE(MTYPE_TMP, cp); @@ -1359,7 +1360,7 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) return str; } -struct prefix *prefix_new() +struct prefix *prefix_new(void) { struct prefix *p; diff --git a/lib/prefix.h b/lib/prefix.h index aaffb1e0c..ae931288c 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -35,6 +35,10 @@ #include "ipaddr.h" #include "compiler.h" +#ifdef __cplusplus +extern "C" { +#endif + #ifndef ETH_ALEN #define ETH_ALEN 6 #endif @@ -276,20 +280,29 @@ struct prefix_sg { * side, which strips type safety since the cast will accept any pointer * type.) */ +#ifndef __cplusplus +#define prefixtype(uname, typename, fieldname) \ + typename *fieldname; +#else +#define prefixtype(uname, typename, fieldname) \ + typename *fieldname; \ + uname(typename *x) { this->fieldname = x; } +#endif + union prefixptr { - struct prefix *p; - struct prefix_ipv4 *p4; - struct prefix_ipv6 *p6; - struct prefix_evpn *evp; - const struct prefix_fs *fs; + prefixtype(prefixptr, struct prefix, p) + prefixtype(prefixptr, struct prefix_ipv4, p4) + prefixtype(prefixptr, struct prefix_ipv6, p6) + prefixtype(prefixptr, struct prefix_evpn, evp) + prefixtype(prefixptr, struct prefix_fs, fs) } __attribute__((transparent_union)); union prefixconstptr { - const struct prefix *p; - const struct prefix_ipv4 *p4; - const struct prefix_ipv6 *p6; - const struct prefix_evpn *evp; - const struct prefix_fs *fs; + prefixtype(prefixconstptr, const struct prefix, p) + prefixtype(prefixconstptr, const struct prefix_ipv4, p4) + prefixtype(prefixconstptr, const struct prefix_ipv6, p6) + prefixtype(prefixconstptr, const struct prefix_evpn, evp) + prefixtype(prefixconstptr, const struct prefix_fs, fs) } __attribute__((transparent_union)); #ifndef INET_ADDRSTRLEN @@ -497,4 +510,9 @@ static inline int is_host_route(struct prefix *p) return (p->prefixlen == IPV6_MAX_BITLEN); return 0; } + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PREFIX_H */ diff --git a/lib/privs.c b/lib/privs.c index 838ff8fc9..293280007 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -789,7 +789,7 @@ void zprivs_preinit(struct zebra_privs_t *zprivs) void zprivs_init(struct zebra_privs_t *zprivs) { - gid_t groups[NGROUPS_MAX]; + gid_t groups[NGROUPS_MAX] = {}; int i, ngroups = 0; int found = 0; @@ -799,7 +799,7 @@ void zprivs_init(struct zebra_privs_t *zprivs) return; if (zprivs->user) { - ngroups = sizeof(groups); + ngroups = array_size(groups); if (getgrouplist(zprivs->user, zprivs_state.zgid, groups, &ngroups) < 0) { diff --git a/lib/privs.h b/lib/privs.h index b061370b7..1fee423a9 100644 --- a/lib/privs.h +++ b/lib/privs.h @@ -23,6 +23,10 @@ #ifndef _ZEBRA_PRIVS_H #define _ZEBRA_PRIVS_H +#ifdef __cplusplus +extern "C" { +#endif + /* list of zebra capabilities */ typedef enum { ZCAP_SETID, @@ -120,4 +124,8 @@ extern void _zprivs_lower(struct zebra_privs_t **privs); _zprivs_raise(privs, __func__); \ _once == NULL; _once = (void *)1) +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PRIVS_H */ diff --git a/lib/ptm_lib.h b/lib/ptm_lib.h index fc4d520dc..c2170407c 100644 --- a/lib/ptm_lib.h +++ b/lib/ptm_lib.h @@ -20,6 +20,10 @@ #ifndef __PTM_LIB_H__ #define __PTM_LIB_H__ +#ifdef __cplusplus +extern "C" { +#endif + #define PTMLIB_MSG_SZ 1024 #define PTMLIB_MSG_HDR_LEN 37 #define PTMLIB_MSG_VERSION 2 @@ -65,4 +69,8 @@ int ptm_lib_append_msg(ptm_lib_handle_t *, void *, const char *, const char *); int ptm_lib_complete_msg(ptm_lib_handle_t *, void *, char *, int *); int ptm_lib_cleanup_msg(ptm_lib_handle_t *, void *); +#ifdef __cplusplus +} +#endif + #endif @@ -20,6 +20,10 @@ #ifndef _FRR_PW_H #define _FRR_PW_H +#ifdef __cplusplus +extern "C" { +#endif + /* L2VPN name length. */ #define L2VPN_NAME_LEN 32 @@ -44,9 +48,10 @@ union pw_protocol_fields { uint32_t pwid; char vpn_name[L2VPN_NAME_LEN]; } ldp; - struct { - /* TODO */ - } bgp; }; +#ifdef __cplusplus +} +#endif + #endif /* _FRR_PW_H */ diff --git a/lib/qobj.h b/lib/qobj.h index b701eeec5..d63988cba 100644 --- a/lib/qobj.h +++ b/lib/qobj.h @@ -21,6 +21,10 @@ #include <stdlib.h> #include <stddef.h> +#ifdef __cplusplus +extern "C" { +#endif + /* reserve a specific amount of bytes for a struct, which can grow up to * that size (or be dummy'd out if not needed) * @@ -28,11 +32,17 @@ * this is intentional to prevent the struct from growing beyond the allocated * space. */ +#ifndef __cplusplus #define RESERVED_SPACE_STRUCT(name, fieldname, size) \ struct { \ struct name fieldname; \ char padding##fieldname[size - sizeof(struct name)]; \ }; +#else +#define RESERVED_SPACE_STRUCT(name, fieldname, size) \ + struct name fieldname; \ + char padding##fieldname[size - sizeof(struct name)]; +#endif /* don't need struct definitions for these here. code actually using * these needs to define the struct *before* including this header. @@ -127,4 +137,8 @@ void *qobj_get_typed(uint64_t id, struct qobj_nodetype *type); void qobj_init(void); void qobj_finish(void); +#ifdef __cplusplus +} +#endif + #endif /* _QOBJ_H */ diff --git a/lib/queue.h b/lib/queue.h index 11e28b4c9..dab43e3c5 100644 --- a/lib/queue.h +++ b/lib/queue.h @@ -19,6 +19,10 @@ #ifndef _FRR_QUEUE_H #define _FRR_QUEUE_H +#ifdef __cplusplus +extern "C" { +#endif + #if defined(__OpenBSD__) && !defined(STAILQ_HEAD) #include "openbsd-queue.h" @@ -85,4 +89,8 @@ }; _elm; }) #endif +#ifdef __cplusplus +} +#endif + #endif /* _FRR_QUEUE_H */ diff --git a/lib/ringbuf.h b/lib/ringbuf.h index 15049e3ee..b8f4d9798 100644 --- a/lib/ringbuf.h +++ b/lib/ringbuf.h @@ -25,6 +25,10 @@ #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + struct ringbuf { size_t size; ssize_t start; @@ -122,4 +126,8 @@ void ringbuf_reset(struct ringbuf *buf); */ void ringbuf_wipe(struct ringbuf *buf); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_RINGBUF_H_ */ diff --git a/lib/route_types.pl b/lib/route_types.pl index 66384fe44..f29709663 100755 --- a/lib/route_types.pl +++ b/lib/route_types.pl @@ -121,7 +121,7 @@ sub codelist { } $str =~ s/ $//; push @lines, $str . "\\n\" \\\n"; - push @lines, " \" > - selected route, * - FIB route\\n\\n\""; + push @lines, " \" > - selected route, * - FIB route, q - queued route, r - rejected route\\n\\n\""; return join("", @lines); } diff --git a/lib/routemap.c b/lib/routemap.c index 5c6d106d8..7c1ee2353 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -1007,6 +1007,34 @@ static int vty_show_route_map(struct vty *vty, const char *name) return CMD_SUCCESS; } +/* Unused route map details */ +static int vty_show_unused_route_map(struct vty *vty) +{ + struct list *maplist = list_new(); + struct listnode *ln; + struct route_map *map; + + for (map = route_map_master.head; map; map = map->next) { + /* If use_count is zero, No protocol is using this routemap. + * so adding to the list. + */ + if (!map->use_count) + listnode_add(maplist, map); + } + + if (maplist->count > 0) { + vty_out(vty, "\n%s:\n", frr_protonameinst); + list_sort(maplist, sort_route_map); + + for (ALL_LIST_ELEMENTS_RO(maplist, ln, map)) + vty_show_route_map_entry(vty, map); + } else { + vty_out(vty, "\n%s: None\n", frr_protonameinst); + } + + list_delete(&maplist); + return CMD_SUCCESS; +} /* New route map allocation. Please note route map's name must be specified. */ @@ -1636,9 +1664,9 @@ static bool route_map_dep_hash_cmp(const void *p1, const void *p2) == 0); } -static void route_map_clear_reference(struct hash_backet *backet, void *arg) +static void route_map_clear_reference(struct hash_bucket *bucket, void *arg) { - struct route_map_dep *dep = (struct route_map_dep *)backet->data; + struct route_map_dep *dep = (struct route_map_dep *)bucket->data; char *rmap_name; if (arg) { @@ -1692,9 +1720,9 @@ static unsigned int route_map_dep_hash_make_key(void *p) return (string_hash_make((char *)p)); } -static void route_map_print_dependency(struct hash_backet *backet, void *data) +static void route_map_print_dependency(struct hash_bucket *bucket, void *data) { - char *rmap_name = (char *)backet->data; + char *rmap_name = (char *)bucket->data; char *dep_name = (char *)data; zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name, @@ -1818,9 +1846,9 @@ static struct hash *route_map_get_dep_hash(route_map_event_t event) return (upd8_hash); } -static void route_map_process_dependency(struct hash_backet *backet, void *data) +static void route_map_process_dependency(struct hash_bucket *bucket, void *data) { - char *rmap_name = (char *)backet->data; + char *rmap_name = (char *)bucket->data; route_map_event_t type = (route_map_event_t)(ptrdiff_t)data; if (rmap_debug) @@ -2759,6 +2787,15 @@ DEFUN (rmap_show_name, return vty_show_route_map(vty, name); } +DEFUN (rmap_show_unused, + rmap_show_unused_cmd, + "show route-map-unused", + SHOW_STR + "unused route-map information\n") +{ + return vty_show_unused_route_map(vty); +} + DEFUN (rmap_call, rmap_call_cmd, "call WORD", @@ -2949,6 +2986,23 @@ static void rmap_autocomplete(vector comps, struct cmd_token *token) vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name)); } +/* Increment the use_count counter while attaching the route map */ +void route_map_counter_increment(struct route_map *map) +{ + if (map) + map->use_count++; +} + +/* Decrement the use_count counter while detaching the route map. */ +void route_map_counter_decrement(struct route_map *map) +{ + if (map) { + if (map->use_count <= 0) + return; + map->use_count--; + } +} + static const struct cmd_variable_handler rmap_var_handlers[] = { {/* "route-map WORD" */ .varname = "route_map", @@ -3006,6 +3060,7 @@ void route_map_init(void) /* Install show command */ install_element(ENABLE_NODE, &rmap_show_name_cmd); + install_element(ENABLE_NODE, &rmap_show_unused_cmd); install_element(RMAP_NODE, &match_interface_cmd); install_element(RMAP_NODE, &no_match_interface_cmd); diff --git a/lib/routemap.h b/lib/routemap.h index 463aa9172..e43e74a63 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -26,6 +26,10 @@ #include "qobj.h" #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(ROUTE_MAP_NAME) DECLARE_MTYPE(ROUTE_MAP_RULE) DECLARE_MTYPE(ROUTE_MAP_COMPILED) @@ -169,6 +173,9 @@ struct route_map { /* How many times have we applied this route-map */ uint64_t applied; + /* Counter to track active usage of this route-map */ + uint16_t use_count; + QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(route_map) @@ -379,4 +386,14 @@ extern void route_map_no_set_tag_hook(int (*func)(struct vty *vty, extern void *route_map_rule_tag_compile(const char *arg); extern void route_map_rule_tag_free(void *rule); +/* Increment the route-map used counter */ +extern void route_map_counter_increment(struct route_map *map); + +/* Decrement the route-map used counter */ +extern void route_map_counter_decrement(struct route_map *map); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_ROUTEMAP_H */ diff --git a/lib/sbuf.h b/lib/sbuf.h index c38e96912..b1518a3aa 100644 --- a/lib/sbuf.h +++ b/lib/sbuf.h @@ -23,6 +23,10 @@ #ifndef SBUF_H #define SBUF_H +#ifdef __cplusplus +extern "C" { +#endif + /* * sbuf provides a simple string buffer. One application where this comes * in handy is the parsing of binary data: If there is an error in the parsing @@ -76,4 +80,8 @@ void sbuf_free(struct sbuf *buf); void sbuf_push(struct sbuf *buf, int indent, const char *format, ...) PRINTF_ATTRIBUTE(3, 4); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/sha256.h b/lib/sha256.h index 2473da7bd..c93d25305 100644 --- a/lib/sha256.h +++ b/lib/sha256.h @@ -29,6 +29,10 @@ #ifndef _SHA256_H_ #define _SHA256_H_ +#ifdef __cplusplus +extern "C" { +#endif + typedef struct SHA256Context { uint32_t state[8]; uint32_t count[2]; @@ -55,4 +59,8 @@ void HMAC__SHA256_Final(unsigned char[32], HMAC_SHA256_CTX *); void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, uint8_t *, size_t); +#ifdef __cplusplus +} +#endif + #endif /* !_SHA256_H_ */ diff --git a/lib/sigevent.h b/lib/sigevent.h index d4ab5741a..a0ad88fca 100644 --- a/lib/sigevent.h +++ b/lib/sigevent.h @@ -25,6 +25,10 @@ #include <thread.h> +#ifdef __cplusplus +extern "C" { +#endif + #define QUAGGA_SIGNAL_TIMER_INTERVAL 2L struct quagga_signal_t { @@ -47,4 +51,8 @@ extern void signal_init(struct thread_master *m, int sigc, /* check whether there are signals to handle, process any found */ extern int quagga_sigevent_process(void); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_SIGNAL_H */ diff --git a/lib/skiplist.c b/lib/skiplist.c index 3933429c3..dda442580 100644 --- a/lib/skiplist.c +++ b/lib/skiplist.c @@ -88,7 +88,7 @@ static struct skiplist *skiplist_last_created; /* debugging hack */ #endif -static int randomLevel() +static int randomLevel(void) { register int level = 0; register int b; diff --git a/lib/skiplist.h b/lib/skiplist.h index a2e8c374b..2ab37331c 100644 --- a/lib/skiplist.h +++ b/lib/skiplist.h @@ -31,6 +31,10 @@ #ifndef _ZEBRA_SKIPLIST_H #define _ZEBRA_SKIPLIST_H +#ifdef __cplusplus +extern "C" { +#endif + #define SKIPLIST_0TIMER_DEBUG 1 /* @@ -122,4 +126,8 @@ extern void skiplist_debug(struct vty *vty, struct skiplist *l); extern void skiplist_test(struct vty *vty); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_SKIPLIST_H */ diff --git a/lib/smux.h b/lib/smux.h index 9adfacb3e..3f860db0d 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -26,6 +26,10 @@ #include "thread.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Structures here are mostly compatible with UCD SNMP 4.1.1 */ #define MATCH_FAILED (-1) #define MATCH_SUCCEEDED 0 @@ -103,4 +107,8 @@ extern void oid2in_addr(oid[], int, struct in_addr *); extern void *oid_copy(void *, const void *, size_t); extern void oid_copy_addr(oid[], struct in_addr *, int); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_SNMP_H */ diff --git a/lib/sockopt.h b/lib/sockopt.h index f54f60ffd..8fa5987cf 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -23,6 +23,10 @@ #include "sockunion.h" +#ifdef __cplusplus +extern "C" { +#endif + extern void setsockopt_so_recvbuf(int sock, int size); extern void setsockopt_so_sendbuf(const int sock, int size); extern int getsockopt_so_sendbuf(const int sock); @@ -98,4 +102,9 @@ extern void sockopt_iphdrincl_swab_systoh(struct ip *iph); extern int sockopt_tcp_rtt(int); extern int sockopt_tcp_signature(int sock, union sockunion *su, const char *password); + +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_SOCKOPT_H */ diff --git a/lib/sockunion.h b/lib/sockunion.h index b585aee5b..d7d26ba85 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -28,6 +28,10 @@ #include <netmpls/mpls.h> #endif +#ifdef __cplusplus +extern "C" { +#endif + union sockunion { struct sockaddr sa; struct sockaddr_in sin; @@ -99,4 +103,8 @@ extern union sockunion *sockunion_dup(const union sockunion *); extern void sockunion_free(union sockunion *); extern void sockunion_init(union sockunion *); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_SOCKUNION_H */ diff --git a/lib/spf_backoff.h b/lib/spf_backoff.h index 6de5804ac..11b2701e3 100644 --- a/lib/spf_backoff.h +++ b/lib/spf_backoff.h @@ -26,6 +26,10 @@ #ifndef _ZEBRA_SPF_BACKOFF_H #define _ZEBRA_SPF_BACKOFF_H +#ifdef __cplusplus +extern "C" { +#endif + struct spf_backoff; struct thread_master; struct vty; @@ -58,4 +62,8 @@ long spf_backoff_long_delay(struct spf_backoff *backoff); long spf_backoff_holddown(struct spf_backoff *backoff); long spf_backoff_timetolearn(struct spf_backoff *backoff); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h index 54acb51b0..8845931de 100644 --- a/lib/srcdest_table.h +++ b/lib/srcdest_table.h @@ -46,6 +46,10 @@ #include "prefix.h" #include "table.h" +#ifdef __cplusplus +extern "C" { +#endif + #define SRCDEST2STR_BUFFER (2*PREFIX2STR_BUFFER + sizeof(" from ")) /* extended route node for IPv6 srcdest routing */ @@ -84,7 +88,8 @@ static inline int rnode_is_srcnode(struct route_node *rn) static inline struct route_table *srcdest_rnode_table(struct route_node *rn) { if (rnode_is_srcnode(rn)) { - struct route_node *dst_rn = route_table_get_info(rn->table); + struct route_node *dst_rn = + (struct route_node *)route_table_get_info(rn->table); return dst_rn->table; } else { return rn->table; @@ -95,4 +100,8 @@ static inline void *srcdest_rnode_table_info(struct route_node *rn) return route_table_get_info(srcdest_rnode_table(rn)); } +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_SRC_DEST_TABLE_H */ diff --git a/lib/stream.h b/lib/stream.h index 32b6fb5af..5341bfa40 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -28,6 +28,10 @@ #include "mpls.h" #include "prefix.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * A stream is an arbitrary buffer, whose contents generally are assumed to * be in network order. @@ -115,9 +119,9 @@ struct stream_fifo { pthread_mutex_t mtx; /* number of streams in this fifo */ - _Atomic size_t count; + atomic_size_t count; #if defined DEV_BUILD - _Atomic size_t max_count; + atomic_size_t max_count; #endif struct stream *head; @@ -404,4 +408,8 @@ static inline uint8_t *ptr_get_be32(uint8_t *ptr, uint32_t *out) goto stream_failure; \ } while (0) +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_STREAM_H */ diff --git a/lib/subdir.am b/lib/subdir.am index ccbe13bca..f245560c4 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -3,7 +3,7 @@ # lib_LTLIBRARIES += lib/libfrr.la lib_libfrr_la_LDFLAGS = -version-info 0:0:0 -Xlinker -e_libfrr_version -lib_libfrr_la_LIBADD = @LIBCAP@ $(UNWIND_LIBS) -lyang +lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) lib_libfrr_la_SOURCES = \ lib/agg_table.c \ @@ -116,7 +116,7 @@ vtysh_scan += \ vtysh_scan += $(top_srcdir)/lib/agentx.c if SQLITE3 -lib_libfrr_la_LIBADD += -lsqlite3 +lib_libfrr_la_LIBADD += $(SQLITE3_LIBS) lib_libfrr_la_SOURCES += lib/db.c endif @@ -289,7 +289,7 @@ endif lib_confd_la_CFLAGS = $(WERROR) $(CONFD_CFLAGS) lib_confd_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -lib_confd_la_LIBADD = lib/libfrr.la -lconfd +lib_confd_la_LIBADD = lib/libfrr.la $(CONFD_LIBS) lib_confd_la_SOURCES = lib/northbound_confd.c # @@ -299,9 +299,9 @@ if SYSREPO module_LTLIBRARIES += lib/sysrepo.la endif -lib_sysrepo_la_CFLAGS = $(WERROR) +lib_sysrepo_la_CFLAGS = $(WERROR) $(SYSREPO_CFLAGS) lib_sysrepo_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -lib_sysrepo_la_LIBADD = lib/libfrr.la -lsysrepo +lib_sysrepo_la_LIBADD = lib/libfrr.la $(SYSREPO_LIBS) lib_sysrepo_la_SOURCES = lib/northbound_sysrepo.c # @@ -387,11 +387,13 @@ lib/command_lex.h: lib/command_lex.c @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) "lib/command_lex.c"; else :; fi lib/command_lex.lo: lib/command_parse.h lib/command_parse.lo: lib/command_lex.h +lib/clippy-command_lex.$(OBJEXT): lib/command_parse.h +lib/clippy-command_parse.$(OBJEXT): lib/command_lex.h lib/lib_clippy-command_lex.$(OBJEXT): lib/command_parse.h lib/lib_clippy-command_parse.$(OBJEXT): lib/command_lex.h lib/route_types.h: $(top_srcdir)/lib/route_types.txt $(top_srcdir)/lib/route_types.pl - @PERL@ $(top_srcdir)/lib/route_types.pl < $(top_srcdir)/lib/route_types.txt > $@ + $(PERL) $(top_srcdir)/lib/route_types.pl < $(top_srcdir)/lib/route_types.txt > $@ DISTCLEANFILES += lib/route_types.h if GIT_VERSION @@ -405,7 +407,7 @@ PHONY_GITVERSION=lib/gitversion.h.tmp .SILENT: lib/gitversion.h lib/gitversion.h.tmp GITH=lib/gitversion.h lib/gitversion.h.tmp: $(top_srcdir)/.git - @PERL@ $(top_srcdir)/lib/gitversion.pl $(top_srcdir) > ${GITH}.tmp + $(PERL) $(top_srcdir)/lib/gitversion.pl $(top_srcdir) > ${GITH}.tmp lib/gitversion.h: lib/gitversion.h.tmp { test -f ${GITH} && diff -s -q ${GITH}.tmp ${GITH}; } || cp ${GITH}.tmp ${GITH} diff --git a/lib/systemd.h b/lib/systemd.h index a13ea7bfd..6e43df527 100644 --- a/lib/systemd.h +++ b/lib/systemd.h @@ -19,6 +19,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifdef __cplusplus +extern "C" { +#endif + /* * Wrapper functions to systemd calls. * @@ -37,3 +41,7 @@ void systemd_send_stopping(void); * process? */ void systemd_send_started(struct thread_master *master, int the_process); + +#ifdef __cplusplus +} +#endif diff --git a/lib/table.h b/lib/table.h index 541d74d77..ce578e795 100644 --- a/lib/table.h +++ b/lib/table.h @@ -25,6 +25,11 @@ #include "memory.h" #include "hash.h" #include "prefix.h" + +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(ROUTE_TABLE) DECLARE_MTYPE(ROUTE_NODE) @@ -318,4 +323,8 @@ static inline int route_table_iter_started(route_table_iter_t *iter) return iter->state != RT_ITER_STATE_INIT; } +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_TABLE_H */ diff --git a/lib/termtable.c b/lib/termtable.c index 4f5f9ff21..01468b820 100644 --- a/lib/termtable.c +++ b/lib/termtable.c @@ -163,7 +163,7 @@ static struct ttable_cell *ttable_insert_row_va(struct ttable *tt, int i, orig = res; - while (res) { + while (res && col < tt->ncols) { section = strsep(&res, "|"); row[col].text = XSTRDUP(MTYPE_TTABLE, section); row[col].style = tt->style.cell; diff --git a/lib/termtable.h b/lib/termtable.h index ca5cc1df9..491010a85 100644 --- a/lib/termtable.h +++ b/lib/termtable.h @@ -22,6 +22,10 @@ #include <zebra.h> +#ifdef __cplusplus +extern "C" { +#endif + enum ttable_align { LEFT, RIGHT, @@ -294,4 +298,8 @@ void ttable_rowseps(struct ttable *tt, unsigned int row, */ char *ttable_dump(struct ttable *tt, const char *newline); +#ifdef __cplusplus +} +#endif + #endif /* _TERMTABLE_H */ diff --git a/lib/thread.c b/lib/thread.c index 867ca2dc6..055587434 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -93,7 +93,8 @@ static void cpu_record_hash_free(void *a) static void vty_out_cpu_thread_history(struct vty *vty, struct cpu_thread_history *a) { - vty_out(vty, "%5d %10lu.%03lu %9u %8lu %9lu %8lu %9lu", a->total_active, + vty_out(vty, "%5"PRIdFAST32" %10lu.%03lu %9"PRIuFAST32 + " %8lu %9lu %8lu %9lu", a->total_active, a->cpu.total / 1000, a->cpu.total % 1000, a->total_calls, a->cpu.total / a->total_calls, a->cpu.max, a->real.total / a->total_calls, a->real.max); @@ -105,7 +106,7 @@ static void vty_out_cpu_thread_history(struct vty *vty, a->types & (1 << THREAD_EXECUTE) ? 'X' : ' ', a->funcname); } -static void cpu_record_hash_print(struct hash_backet *bucket, void *args[]) +static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[]) { struct cpu_thread_history *totals = args[0]; struct cpu_thread_history copy; @@ -177,7 +178,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) if (m->cpu_record->count) hash_iterate( m->cpu_record, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))cpu_record_hash_print, args); else @@ -201,7 +202,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) vty_out_cpu_thread_history(vty, &tmp); } -static void cpu_record_hash_clear(struct hash_backet *bucket, void *args[]) +static void cpu_record_hash_clear(struct hash_bucket *bucket, void *args[]) { uint8_t *filter = args[0]; struct hash *cpu_record = args[1]; @@ -228,7 +229,7 @@ static void cpu_record_clear(uint8_t filter) void *args[2] = {tmp, m->cpu_record}; hash_iterate( m->cpu_record, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))cpu_record_hash_clear, args); } @@ -400,7 +401,7 @@ static void cancelreq_del(void *cr) } /* initializer, only ever called once */ -static void initializer() +static void initializer(void) { pthread_key_create(&thread_current, NULL); } diff --git a/lib/thread.h b/lib/thread.h index f404d9275..ec774a654 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -27,6 +27,10 @@ #include "monotime.h" #include "frratomic.h" +#ifdef __cplusplus +extern "C" { +#endif + struct rusage_t { struct rusage cpu; struct timeval real; @@ -119,13 +123,13 @@ struct thread { struct cpu_thread_history { int (*func)(struct thread *); - _Atomic unsigned int total_calls; - _Atomic unsigned int total_active; + atomic_uint_fast32_t total_calls; + atomic_uint_fast32_t total_active; struct time_stats { - _Atomic unsigned long total, max; + atomic_size_t total, max; } real; struct time_stats cpu; - _Atomic uint32_t types; + atomic_uint_fast32_t types; const char *funcname; }; @@ -233,4 +237,8 @@ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before, /* only for use in logging functions! */ extern pthread_key_t thread_current; +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_THREAD_H */ diff --git a/lib/vector.h b/lib/vector.h index 97e15da04..d5857eb59 100644 --- a/lib/vector.h +++ b/lib/vector.h @@ -24,6 +24,10 @@ #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + /* struct for vector */ struct _vector { unsigned int active; /* number of active slots */ @@ -63,4 +67,9 @@ extern void *vector_lookup(vector, unsigned int); extern void *vector_lookup_ensure(vector, unsigned int); extern void vector_to_array(vector v, void ***dest, int *argc); extern vector array_to_vector(void **src, int argc); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_VECTOR_H */ diff --git a/lib/vlan.h b/lib/vlan.h index 6d15e62df..eea2633d4 100644 --- a/lib/vlan.h +++ b/lib/vlan.h @@ -22,8 +22,16 @@ #ifndef __VLAN_H__ #define __VLAN_H__ +#ifdef __cplusplus +extern "C" { +#endif + /* VLAN Identifier */ typedef uint16_t vlanid_t; #define VLANID_MAX 4095 +#ifdef __cplusplus +} +#endif + #endif /* __VLAN_H__ */ @@ -471,7 +471,7 @@ static const struct cmd_variable_handler vrf_var_handlers[] = { /* Initialize VRF module. */ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), - int (*disable)(struct vrf *), int (*delete)(struct vrf *), + int (*disable)(struct vrf *), int (*destroy)(struct vrf *), int ((*update)(struct vrf *))) { struct vrf *default_vrf; @@ -485,7 +485,7 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), vrf_master.vrf_new_hook = create; vrf_master.vrf_enable_hook = enable; vrf_master.vrf_disable_hook = disable; - vrf_master.vrf_delete_hook = delete; + vrf_master.vrf_delete_hook = destroy; vrf_master.vrf_update_name_hook = update; /* The default VRF always exists. */ @@ -716,13 +716,6 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname, return CMD_SUCCESS; } -int vrf_is_mapped_on_netns(struct vrf *vrf) -{ - if (!vrf || vrf->data.l.netns_name[0] == '\0') - return 0; - return 1; -} - /* vrf CLI commands */ DEFUN_NOSH(vrf_exit, vrf_exit_cmd, @@ -953,7 +946,7 @@ int vrf_bind(vrf_id_t vrf_id, int fd, const char *name) if (fd < 0 || name == NULL) return fd; - if (vrf_is_mapped_on_netns(vrf_lookup_by_id(vrf_id))) + if (vrf_is_backend_netns()) return fd; #ifdef SO_BINDTODEVICE ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name)+1); @@ -28,6 +28,10 @@ #include "vty.h" #include "ns.h" +#ifdef __cplusplus +extern "C" { +#endif + /* The default VRF ID */ #define VRF_UNKNOWN UINT32_MAX @@ -200,7 +204,7 @@ extern int vrf_bitmap_check(vrf_bitmap_t, vrf_id_t); * the system ( 2 and 3 ) above. */ extern void vrf_init(int (*create)(struct vrf *vrf), int (*enable)(struct vrf *vrf), - int (*disable)(struct vrf *vrf), int (*delete)(struct vrf *vrf), + int (*disable)(struct vrf *vrf), int (*destroy)(struct vrf *vrf), int (*update)(struct vrf *vrf)); /* @@ -240,9 +244,6 @@ extern void vrf_set_default_name(const char *default_name, bool force); extern const char *vrf_get_default_name(void); #define VRF_DEFAULT_NAME vrf_get_default_name() -/* VRF is mapped on netns or not ? */ -int vrf_is_mapped_on_netns(struct vrf *vrf); - /* VRF switch from NETNS */ extern int vrf_switch_to_netns(vrf_id_t vrf_id); extern int vrf_switchback_to_initial(void); @@ -295,4 +296,8 @@ extern int vrf_enable(struct vrf *vrf); extern void vrf_delete(struct vrf *vrf); extern vrf_id_t vrf_generate_id(void); +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_VRF_H*/ diff --git a/lib/vrf_int.h b/lib/vrf_int.h index d7fe73581..8dc078e4f 100644 --- a/lib/vrf_int.h +++ b/lib/vrf_int.h @@ -25,6 +25,10 @@ #include "vrf.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * These functions should only be called by: * zebra/if_netlink.c -> The interface from OS into Zebra @@ -52,4 +56,8 @@ extern int vrf_enable(struct vrf *); */ extern void vrf_delete(struct vrf *); +#ifdef __cplusplus +} +#endif + #endif @@ -775,61 +775,11 @@ static void vty_end_config(struct vty *vty) { vty_out(vty, "\n"); - switch (vty->node) { - case VIEW_NODE: - case ENABLE_NODE: - /* Nothing to do. */ - break; - case CONFIG_NODE: - case INTERFACE_NODE: - case PW_NODE: - case ZEBRA_NODE: - case RIP_NODE: - case RIPNG_NODE: - case EIGRP_NODE: - case BGP_NODE: - case BGP_VPNV4_NODE: - case BGP_VPNV6_NODE: - case BGP_VRF_POLICY_NODE: - case BGP_VNC_DEFAULTS_NODE: - case BGP_VNC_NVE_GROUP_NODE: - case BGP_VNC_L2_GROUP_NODE: - case BGP_IPV4_NODE: - case BGP_IPV4M_NODE: - case BGP_IPV4L_NODE: - case BGP_IPV6_NODE: - case BGP_IPV6M_NODE: - case BGP_EVPN_NODE: - case BGP_IPV6L_NODE: - case RMAP_NODE: - case PBRMAP_NODE: - case OSPF_NODE: - case OSPF6_NODE: - case LDP_NODE: - case LDP_IPV4_NODE: - case LDP_IPV6_NODE: - case LDP_IPV4_IFACE_NODE: - case LDP_IPV6_IFACE_NODE: - case LDP_L2VPN_NODE: - case LDP_PSEUDOWIRE_NODE: - case ISIS_NODE: - case OPENFABRIC_NODE: - case KEYCHAIN_NODE: - case KEYCHAIN_KEY_NODE: - case VTY_NODE: - case BGP_EVPN_VNI_NODE: - case BFD_NODE: - case BFD_PEER_NODE: + if (vty->config) { vty_config_exit(vty); vty->node = ENABLE_NODE; - break; - default: - /* Unknown node, we have to ignore it. */ - break; } - vty->xpath_index = 0; - vty_prompt(vty); vty->cp = 0; } @@ -1190,44 +1140,11 @@ static void vty_stop_input(struct vty *vty) vty_clear_buf(vty); vty_out(vty, "\n"); - switch (vty->node) { - case VIEW_NODE: - case ENABLE_NODE: - /* Nothing to do. */ - break; - case CONFIG_NODE: - case INTERFACE_NODE: - case PW_NODE: - case ZEBRA_NODE: - case RIP_NODE: - case RIPNG_NODE: - case EIGRP_NODE: - case BGP_NODE: - case RMAP_NODE: - case PBRMAP_NODE: - case OSPF_NODE: - case OSPF6_NODE: - case LDP_NODE: - case LDP_IPV4_NODE: - case LDP_IPV6_NODE: - case LDP_IPV4_IFACE_NODE: - case LDP_IPV6_IFACE_NODE: - case LDP_L2VPN_NODE: - case LDP_PSEUDOWIRE_NODE: - case ISIS_NODE: - case OPENFABRIC_NODE: - case KEYCHAIN_NODE: - case KEYCHAIN_KEY_NODE: - case VTY_NODE: - case BFD_NODE: - case BFD_PEER_NODE: + if (vty->config) { vty_config_exit(vty); vty->node = ENABLE_NODE; - break; - default: - /* Unknown node, we have to ignore it. */ - break; } + vty_prompt(vty); /* Set history pointer to the latest one. */ @@ -1688,7 +1605,7 @@ static int vty_flush(struct thread *thread) } /* Allocate new vty struct. */ -struct vty *vty_new() +struct vty *vty_new(void) { struct vty *new = XCALLOC(MTYPE_VTY, sizeof(struct vty)); @@ -2696,6 +2613,7 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive) vty->node = CONFIG_NODE; vty->config = true; vty->private_config = private_config; + vty->xpath_index = 0; if (private_config) { vty->candidate_config = nb_config_dup(running_config); @@ -2733,6 +2651,8 @@ void vty_config_exit(struct vty *vty) nb_config_free(vty->candidate_config_base); vty->candidate_config_base = NULL; } + + vty->config = false; } int vty_config_exclusive_lock(struct vty *vty) @@ -3115,7 +3035,7 @@ struct cmd_node vty_node = { }; /* Reset all VTY status. */ -void vty_reset() +void vty_reset(void) { unsigned int i; struct vty *vty; @@ -3180,7 +3100,7 @@ static void vty_save_cwd(void) strcpy(vty_cwd, cwd); } -char *vty_get_cwd() +char *vty_get_cwd(void) { return vty_cwd; } @@ -3195,7 +3115,7 @@ int vty_shell_serv(struct vty *vty) return vty->type == VTY_SHELL_SERV ? 1 : 0; } -void vty_init_vtysh() +void vty_init_vtysh(void) { vtyvec = vector_init(VECTOR_MIN_SIZE); } @@ -31,6 +31,10 @@ #include "compiler.h" #include "northbound.h" +#ifdef __cplusplus +extern "C" { +#endif + #define VTY_BUFSIZ 4096 #define VTY_MAXHIST 20 #define VTY_MAXDEPTH 8 @@ -333,4 +337,8 @@ extern void vty_stdio_close(void); an async-signal-safe function. */ extern void vty_log_fixed(char *buf, size_t len); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_VTY_H */ diff --git a/lib/vxlan.h b/lib/vxlan.h index bcf835453..2a8077f8c 100644 --- a/lib/vxlan.h +++ b/lib/vxlan.h @@ -22,6 +22,10 @@ #ifndef __VXLAN_H__ #define __VXLAN_H__ +#ifdef __cplusplus +extern "C" { +#endif + /* VxLAN Network Identifier - 24-bit (RFC 7348) */ typedef uint32_t vni_t; #define VNI_MAX 16777215 /* (2^24 - 1) */ @@ -35,4 +39,9 @@ enum vxlan_flood_control { VXLAN_FLOOD_HEAD_END_REPL = 0, VXLAN_FLOOD_DISABLED, }; + +#ifdef __cplusplus +} +#endif + #endif /* __VXLAN_H__ */ diff --git a/lib/wheel.h b/lib/wheel.h index c8e83fafc..e66751c1d 100644 --- a/lib/wheel.h +++ b/lib/wheel.h @@ -20,6 +20,10 @@ #ifndef __WHEEL_H__ #define __WHEEL_H__ +#ifdef __cplusplus +extern "C" { +#endif + struct timer_wheel { char *name; struct thread_master *master; @@ -115,4 +119,8 @@ int wheel_add_item(struct timer_wheel *wheel, void *item); */ int wheel_remove_item(struct timer_wheel *wheel, void *item); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/workqueue.c b/lib/workqueue.c index 24ef24c77..fa69ec600 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -99,8 +99,10 @@ struct work_queue *work_queue_new(struct thread_master *m, return new; } -void work_queue_free_original(struct work_queue *wq) +void work_queue_free_and_null(struct work_queue **wqp) { + struct work_queue *wq = *wqp; + if (wq->thread != NULL) thread_cancel(wq->thread); @@ -114,13 +116,8 @@ void work_queue_free_original(struct work_queue *wq) XFREE(MTYPE_WORK_QUEUE_NAME, wq->name); XFREE(MTYPE_WORK_QUEUE, wq); - return; -} -void work_queue_free_and_null(struct work_queue **wq) -{ - work_queue_free_original(*wq); - *wq = NULL; + *wqp = NULL; } bool work_queue_is_scheduled(struct work_queue *wq) diff --git a/lib/workqueue.h b/lib/workqueue.h index 7c8465506..7c610f5dd 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -25,6 +25,11 @@ #include "memory.h" #include "queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(WORK_QUEUE) /* Hold time for the initial schedule of a queue run, in millisec */ @@ -159,19 +164,10 @@ extern struct work_queue *work_queue_new(struct thread_master *, const char *); * The usage of work_queue_free is being transitioned to pass * in the double pointer to remove use after free's. */ -#if CONFDATE > 20190205 -CPP_NOTICE("work_queue_free without double pointer is deprecated, please fixup") -#endif -extern void work_queue_free_and_null(struct work_queue **); -extern void work_queue_free_original(struct work_queue *); -#define work_queue_free(X) \ - do { \ - work_queue_free_original((X)); \ - CPP_WARN("Please use work_queue_free_and_null"); \ - } while (0) +extern void work_queue_free_and_null(struct work_queue **wqp); /* Add the supplied data as an item onto the workqueue */ -extern void work_queue_add(struct work_queue *, void *); +extern void work_queue_add(struct work_queue *wq, void *item); /* plug the queue, ie prevent it from being drained / processed */ extern void work_queue_plug(struct work_queue *wq); @@ -185,4 +181,8 @@ extern int work_queue_run(struct thread *); extern void workqueue_cmd_init(void); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_WORK_QUEUE_H */ diff --git a/lib/yang.c b/lib/yang.c index 4077b2974..7982d14fd 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -26,6 +26,8 @@ #include "yang_translator.h" #include "northbound.h" +#include <libyang/user_types.h> + DEFINE_MTYPE(LIB, YANG_MODULE, "YANG module") DEFINE_MTYPE(LIB, YANG_DATA, "YANG data structure") @@ -658,8 +660,41 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path) zlog(priority, "libyang: %s", msg); } +#if CONFDATE > 20190401 +CPP_NOTICE("lib/yang: time to remove non-LIBYANG_EXT_BUILTIN support") +#endif + +#ifdef LIBYANG_EXT_BUILTIN +extern struct lytype_plugin_list frr_user_types[]; +#endif + +struct ly_ctx *yang_ctx_new_setup(void) +{ + struct ly_ctx *ctx; + const char *yang_models_path = YANG_MODELS_PATH; + + if (access(yang_models_path, R_OK | X_OK)) { + yang_models_path = NULL; + if (errno == ENOENT) + zlog_info("yang model directory \"%s\" does not exist", + YANG_MODELS_PATH); + else + flog_err_sys(EC_LIB_LIBYANG, + "cannot access yang model directory \"%s\"", + YANG_MODELS_PATH); + } + + ctx = ly_ctx_new(yang_models_path, LY_CTX_DISABLE_SEARCHDIR_CWD); + if (!ctx) + return NULL; + ly_ctx_set_module_imp_clb(ctx, yang_module_imp_clb, NULL); + return ctx; +} + void yang_init(void) { +#ifndef LIBYANG_EXT_BUILTIN +CPP_NOTICE("lib/yang: deprecated libyang <0.16.74 extension loading in use!") static char ly_plugin_dir[PATH_MAX]; const char *const *ly_loaded_plugins; const char *ly_plugin; @@ -669,21 +704,29 @@ void yang_init(void) snprintf(ly_plugin_dir, sizeof(ly_plugin_dir), "%s=%s", "LIBYANG_USER_TYPES_PLUGINS_DIR", LIBYANG_PLUGINS_PATH); putenv(ly_plugin_dir); +#endif /* Initialize libyang global parameters that affect all containers. */ ly_set_log_clb(ly_log_cb, 1); ly_log_options(LY_LOLOG | LY_LOSTORE); +#ifdef LIBYANG_EXT_BUILTIN + if (ly_register_types(frr_user_types, "frr_user_types")) { + flog_err(EC_LIB_LIBYANG_PLUGIN_LOAD, + "ly_register_types() failed"); + exit(1); + } +#endif + /* Initialize libyang container for native models. */ - ly_native_ctx = - ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD); + ly_native_ctx = yang_ctx_new_setup(); if (!ly_native_ctx) { flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); exit(1); } - ly_ctx_set_module_imp_clb(ly_native_ctx, yang_module_imp_clb, NULL); ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb); +#ifndef LIBYANG_EXT_BUILTIN /* Detect if the required libyang plugin(s) were loaded successfully. */ ly_loaded_plugins = ly_get_loaded_plugins(); for (size_t i = 0; (ly_plugin = ly_loaded_plugins[i]); i++) { @@ -697,6 +740,7 @@ void yang_init(void) "%s: failed to load frr_user_types.so", __func__); exit(1); } +#endif yang_translator_init(); } diff --git a/lib/yang.h b/lib/yang.h index 09d92cafd..15f0ec7ae 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -29,6 +29,10 @@ #include "yang_wrappers.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(YANG_MODULE) DECLARE_MTYPE(YANG_DATA) @@ -525,6 +529,11 @@ extern struct yang_data *yang_data_list_find(const struct list *list, const char *xpath_fmt, ...); /* + * Create and set up a libyang context (for use by the translator) + */ +extern struct ly_ctx *yang_ctx_new_setup(void); + +/* * Initialize the YANG subsystem. Should be called only once during the * daemon initialization process. */ @@ -536,4 +545,8 @@ extern void yang_init(void); */ extern void yang_terminate(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_YANG_H_ */ diff --git a/lib/yang_translator.c b/lib/yang_translator.c index c3092e56e..76a6cc5fd 100644 --- a/lib/yang_translator.c +++ b/lib/yang_translator.c @@ -162,8 +162,7 @@ struct yang_translator *yang_translator_load(const char *path) RB_INSERT(yang_translators, &yang_translators, translator); /* Initialize the translator libyang context. */ - translator->ly_ctx = - ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD); + translator->ly_ctx = yang_ctx_new_setup(); if (!translator->ly_ctx) { flog_warn(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); goto error; @@ -512,7 +511,7 @@ static void str_replace(char *o_string, const char *s_string, if (!ch) return; - strncpy(buffer, o_string, ch - o_string); + memcpy(buffer, o_string, ch - o_string); buffer[ch - o_string] = 0; sprintf(buffer + (ch - o_string), "%s%s", r_string, @@ -525,8 +524,7 @@ static void str_replace(char *o_string, const char *s_string, void yang_translator_init(void) { - ly_translator_ctx = - ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD); + ly_translator_ctx = yang_ctx_new_setup(); if (!ly_translator_ctx) { flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); exit(1); diff --git a/lib/yang_translator.h b/lib/yang_translator.h index 6b49d1acf..55f396a43 100644 --- a/lib/yang_translator.h +++ b/lib/yang_translator.h @@ -20,6 +20,10 @@ #ifndef _FRR_YANG_TRANSLATOR_H_ #define _FRR_YANG_TRANSLATOR_H_ +#ifdef __cplusplus +extern "C" { +#endif + #define YANG_TRANSLATE_TO_NATIVE 0 #define YANG_TRANSLATE_FROM_NATIVE 1 #define YANG_TRANSLATE_MAX 2 @@ -141,4 +145,8 @@ extern void yang_translator_init(void); */ extern void yang_translator_terminate(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_YANG_TRANSLATOR_H_ */ diff --git a/lib/zclient.c b/lib/zclient.c index cc936d47d..9db1dd74f 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -414,9 +414,6 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id) /* We need router-id information. */ zebra_message_send(zclient, ZEBRA_ROUTER_ID_ADD, vrf_id); - /* We need interface information. */ - zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, vrf_id); - /* Set unwanted redistribute route. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) vrf_bitmap_set(zclient->redist[afi][zclient->redist_default], @@ -457,8 +454,7 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id) vrf_id); /* If default information is needed. */ - if (vrf_bitmap_check(zclient->default_information[afi], - VRF_DEFAULT)) + if (vrf_bitmap_check(zclient->default_information[afi], vrf_id)) zebra_redistribute_default_send( ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, afi, vrf_id); @@ -482,9 +478,6 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id) /* We need router-id information. */ zebra_message_send(zclient, ZEBRA_ROUTER_ID_DELETE, vrf_id); - /* We need interface information. */ - zebra_message_send(zclient, ZEBRA_INTERFACE_DELETE, vrf_id); - /* Set unwanted redistribute route. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) vrf_bitmap_unset(zclient->redist[afi][zclient->redist_default], @@ -525,8 +518,7 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id) i, 0, vrf_id); /* If default information is needed. */ - if (vrf_bitmap_check(zclient->default_information[afi], - VRF_DEFAULT)) + if (vrf_bitmap_check(zclient->default_information[afi], vrf_id)) zebra_redistribute_default_send( ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient, afi, vrf_id); @@ -598,6 +590,8 @@ int zclient_start(struct zclient *zclient) zebra_hello_send(zclient); + zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, VRF_DEFAULT); + /* Inform the successful connection. */ if (zclient->zebra_connected) (*zclient->zebra_connected)(zclient); @@ -756,10 +750,24 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) stream_reset(s); zclient_create_header(s, cmd, api->vrf_id); + if (api->type >= ZEBRA_ROUTE_MAX) { + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: Specified route type (%u) is not a legal value\n", + __PRETTY_FUNCTION__, api->type); + return -1; + } stream_putc(s, api->type); + stream_putw(s, api->instance); stream_putl(s, api->flags); stream_putc(s, api->message); + + if (api->safi < SAFI_UNICAST || api->safi >= SAFI_MAX) { + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: Specified route SAFI (%u) is not a legal value\n", + __PRETTY_FUNCTION__, api->safi); + return -1; + } stream_putc(s, api->safi); /* Put prefix information. */ @@ -795,6 +803,7 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) stream_putl(s, api_nh->vrf_id); stream_putc(s, api_nh->type); + stream_putc(s, api_nh->onlink); switch (api_nh->type) { case NEXTHOP_TYPE_BLACKHOLE: stream_putc(s, api_nh->bh_type); @@ -875,7 +884,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) /* Type, flags, message. */ STREAM_GETC(s, api->type); - if (api->type > ZEBRA_ROUTE_MAX) { + if (api->type >= ZEBRA_ROUTE_MAX) { flog_err(EC_LIB_ZAPI_ENCODE, "%s: Specified route type: %d is not a legal value\n", __PRETTY_FUNCTION__, api->type); @@ -886,6 +895,12 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) STREAM_GETL(s, api->flags); STREAM_GETC(s, api->message); STREAM_GETC(s, api->safi); + if (api->safi < SAFI_UNICAST || api->safi >= SAFI_MAX) { + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: Specified route SAFI (%u) is not a legal value\n", + __PRETTY_FUNCTION__, api->safi); + return -1; + } /* Prefix. */ STREAM_GETC(s, api->prefix.family); @@ -955,6 +970,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) STREAM_GETL(s, api_nh->vrf_id); STREAM_GETC(s, api_nh->type); + STREAM_GETC(s, api_nh->onlink); switch (api_nh->type) { case NEXTHOP_TYPE_BLACKHOLE: STREAM_GETC(s, api_nh->bh_type); @@ -1497,7 +1513,8 @@ static void link_params_set_value(struct stream *s, struct if_link_params *iflp) iflp->use_bw = stream_getf(s); } -struct interface *zebra_interface_link_params_read(struct stream *s) +struct interface *zebra_interface_link_params_read(struct stream *s, + vrf_id_t vrf_id) { struct if_link_params *iflp; ifindex_t ifindex; @@ -1506,7 +1523,7 @@ struct interface *zebra_interface_link_params_read(struct stream *s) ifindex = stream_getl(s); - struct interface *ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); + struct interface *ifp = if_lookup_by_index(ifindex, vrf_id); if (ifp == NULL) { flog_err(EC_LIB_ZAPI_ENCODE, @@ -2372,8 +2389,12 @@ static void zclient_capability_decode(int command, struct zclient *zclient, { struct zclient_capabilities cap; struct stream *s = zclient->ibuf; + int vrf_backend; uint8_t mpls_enabled; + STREAM_GETL(s, vrf_backend); + vrf_configure_backend(vrf_backend); + memset(&cap, 0, sizeof(cap)); STREAM_GETC(s, mpls_enabled); cap.mpls_enabled = !!mpls_enabled; @@ -2583,7 +2604,7 @@ static int zclient_read(struct thread *thread) case ZEBRA_INTERFACE_LINK_PARAMS: if (zclient->interface_link_params) (*zclient->interface_link_params)(command, zclient, - length); + length, vrf_id); break; case ZEBRA_FEC_UPDATE: if (zclient_debug) diff --git a/lib/zclient.h b/lib/zclient.h index 401d6c400..3a054e5e7 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -125,6 +125,7 @@ typedef enum { ZEBRA_FEC_UNREGISTER, ZEBRA_FEC_UPDATE, ZEBRA_ADVERTISE_DEFAULT_GW, + ZEBRA_ADVERTISE_SVI_MACIP, ZEBRA_ADVERTISE_SUBNET, ZEBRA_ADVERTISE_ALL_VNI, ZEBRA_LOCAL_ES_ADD, @@ -229,7 +230,7 @@ struct zclient { int (*interface_address_add)(int, struct zclient *, uint16_t, vrf_id_t); int (*interface_address_delete)(int, struct zclient *, uint16_t, vrf_id_t); - int (*interface_link_params)(int, struct zclient *, uint16_t); + int (*interface_link_params)(int, struct zclient *, uint16_t, vrf_id_t); int (*interface_bfd_dest_update)(int, struct zclient *, uint16_t, vrf_id_t); int (*interface_nbr_address_add)(int, struct zclient *, uint16_t, @@ -306,6 +307,7 @@ struct zapi_nexthop { enum nexthop_types_t type; vrf_id_t vrf_id; ifindex_t ifindex; + bool onlink; union { union g_addr gate; enum blackhole_type bh_type; @@ -426,6 +428,8 @@ enum zapi_iptable_notify_owner { #define ZEBRA_MACIP_TYPE_ROUTER_FLAG 0x04 /* Router Flag - proxy NA */ #define ZEBRA_MACIP_TYPE_OVERRIDE_FLAG 0x08 /* Override Flag */ +enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 }; + struct zclient_options { bool receive_notify; }; @@ -564,7 +568,8 @@ extern struct interface *zebra_interface_vrf_update_read(struct stream *s, extern void zebra_interface_if_set_value(struct stream *, struct interface *); extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid); -extern struct interface *zebra_interface_link_params_read(struct stream *); +extern struct interface *zebra_interface_link_params_read(struct stream *s, + vrf_id_t vrf_id); extern size_t zebra_interface_link_params_write(struct stream *, struct interface *); extern int zclient_send_get_label_chunk( diff --git a/lib/zebra.h b/lib/zebra.h index 09115951e..b96fb5a20 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -232,6 +232,15 @@ typedef unsigned char uint8_t; #include "zassert.h" +/* + * Add explicit static cast only when using a C++ compiler. + */ +#ifdef __cplusplus +#define static_cast(l, r) static_cast<decltype(l)>((r)) +#else +#define static_cast(l, r) (r) +#endif + #ifndef HAVE_STRLCAT size_t strlcat(char *__restrict dest, const char *__restrict src, size_t destsize); @@ -446,11 +455,6 @@ extern const char *zserv_command_string(unsigned int command); * route entry. This mainly is used for backup static routes. */ #define ZEBRA_FLAG_RR_USE_DISTANCE 0x40 -/* - * This flag tells Zebra that the passed down route is ONLINK and the - * kernel install flag for it should be turned on - */ -#define ZEBRA_FLAG_ONLINK 0x80 #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ diff --git a/nhrpd/linux.c b/nhrpd/linux.c index 85e941e7b..bb5ce0fec 100644 --- a/nhrpd/linux.c +++ b/nhrpd/linux.c @@ -110,7 +110,7 @@ static int linux_configure_arp(const char *iface, int on) { struct ifreq ifr; - strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1); + strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); if (ioctl(nhrp_socket_fd, SIOCGIFFLAGS, &ifr)) return -1; diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c index 1316a4aad..550877824 100644 --- a/nhrpd/nhrp_cache.c +++ b/nhrpd/nhrp_cache.c @@ -345,7 +345,7 @@ struct nhrp_cache_iterator_ctx { void *ctx; }; -static void nhrp_cache_iterator(struct hash_backet *b, void *ctx) +static void nhrp_cache_iterator(struct hash_bucket *b, void *ctx) { struct nhrp_cache_iterator_ctx *ic = ctx; ic->cb(b->data, ic->ctx); diff --git a/nhrpd/nhrp_vc.c b/nhrpd/nhrp_vc.c index 79a655396..f92ea4ac9 100644 --- a/nhrpd/nhrp_vc.c +++ b/nhrpd/nhrp_vc.c @@ -183,7 +183,7 @@ struct nhrp_vc_iterator_ctx { void *ctx; }; -static void nhrp_vc_iterator(struct hash_backet *b, void *ctx) +static void nhrp_vc_iterator(struct hash_bucket *b, void *ctx) { struct nhrp_vc_iterator_ctx *ic = ctx; ic->cb(b->data, ic->ctx); diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am index 758c22e2b..6e2b91780 100644 --- a/nhrpd/subdir.am +++ b/nhrpd/subdir.am @@ -8,8 +8,8 @@ vtysh_scan += $(top_srcdir)/nhrpd/nhrp_vty.c man8 += $(MANBUILD)/nhrpd.8 endif -nhrpd_nhrpd_LDADD = lib/libfrr.la @LIBCAP@ @CARES_LIBS@ -nhrpd_nhrpd_CFLAGS = $(AM_CFLAGS) @CARES_CFLAGS@ +nhrpd_nhrpd_LDADD = lib/libfrr.la $(LIBCAP) $(CARES_LIBS) +nhrpd_nhrpd_CFLAGS = $(AM_CFLAGS) $(CARES_CFLAGS) nhrpd_nhrpd_SOURCES = \ nhrpd/linux.c \ nhrpd/netlink_arp.c \ diff --git a/nhrpd/vici.c b/nhrpd/vici.c index 3de4609a2..fab99588c 100644 --- a/nhrpd/vici.c +++ b/nhrpd/vici.c @@ -550,7 +550,7 @@ int sock_open_unix(const char *path) memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + strlcpy(addr.sun_path, path, sizeof(addr.sun_path)); ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr.sun_family) + strlen(addr.sun_path)); diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 30f0e9e77..76722aad1 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -1022,3 +1022,16 @@ void ospf6_area_init(void) install_element(OSPF6_NODE, &area_filter_list_cmd); install_element(OSPF6_NODE, &no_area_filter_list_cmd); } + +void ospf6_area_interface_delete(struct ospf6_interface *oi) +{ + struct ospf6_area *oa; + struct listnode *node, *nnode; + + if (!ospf6) + return; + for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) + if(listnode_lookup(oa->if_list, oi)) + listnode_delete(oa->if_list, oi); + +} diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index ba497a168..5648b1dfe 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -132,5 +132,7 @@ extern void ospf6_area_show(struct vty *, struct ospf6_area *); extern void ospf6_area_plist_update(struct prefix_list *plist, int add); extern void ospf6_area_config_write(struct vty *vty); extern void ospf6_area_init(void); +struct ospf6_interface; +extern void ospf6_area_interface_delete(struct ospf6_interface *oi); #endif /* OSPF_AREA_H */ diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index dc7a3f6d4..3153c29aa 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -856,16 +856,22 @@ void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry) static void ospf6_asbr_routemap_set(int type, const char *mapname) { - if (ospf6->rmap[type].name) + if (ospf6->rmap[type].name) { + route_map_counter_decrement(ospf6->rmap[type].map); free(ospf6->rmap[type].name); + } ospf6->rmap[type].name = strdup(mapname); ospf6->rmap[type].map = route_map_lookup_by_name(mapname); + route_map_counter_increment(ospf6->rmap[type].map); } static void ospf6_asbr_routemap_unset(int type) { if (ospf6->rmap[type].name) free(ospf6->rmap[type].name); + + route_map_counter_decrement(ospf6->rmap[type].map); + ospf6->rmap[type].name = NULL; ospf6->rmap[type].map = NULL; } @@ -939,6 +945,10 @@ static void ospf6_asbr_routemap_update(const char *mapname) "%s: route-map %s update, reset redist %s", __PRETTY_FUNCTION__, mapname, ZROUTE_NAME(type)); + + route_map_counter_increment( + ospf6->rmap[type].map); + ospf6_asbr_distribute_list_update(type); } } else @@ -1897,7 +1907,7 @@ int config_write_ospf6_debug_asbr(struct vty *vty) return 0; } -void install_element_ospf6_debug_asbr() +void install_element_ospf6_debug_asbr(void) { install_element(ENABLE_NODE, &debug_ospf6_asbr_cmd); install_element(ENABLE_NODE, &no_debug_ospf6_asbr_cmd); diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 2bfa4201c..83b9001fe 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -246,6 +246,7 @@ void ospf6_interface_delete(struct ospf6_interface *oi) THREAD_OFF(oi->thread_send_hello); THREAD_OFF(oi->thread_send_lsupdate); THREAD_OFF(oi->thread_send_lsack); + THREAD_OFF(oi->thread_sso); ospf6_lsdb_remove_all(oi->lsdb); ospf6_lsdb_remove_all(oi->lsupdate_list); @@ -268,6 +269,9 @@ void ospf6_interface_delete(struct ospf6_interface *oi) ospf6_bfd_info_free(&(oi->bfd_info)); + /* disable from area list if possible */ + ospf6_area_interface_delete(oi); + XFREE(MTYPE_OSPF6_IF, oi); } @@ -291,6 +295,7 @@ void ospf6_interface_disable(struct ospf6_interface *oi) THREAD_OFF(oi->thread_send_hello); THREAD_OFF(oi->thread_send_lsupdate); THREAD_OFF(oi->thread_send_lsack); + THREAD_OFF(oi->thread_sso); THREAD_OFF(oi->thread_network_lsa); THREAD_OFF(oi->thread_link_lsa); @@ -381,9 +386,9 @@ void ospf6_interface_state_update(struct interface *ifp) if (if_is_operative(ifp) && (ospf6_interface_get_linklocal_address(oi->interface) || if_is_loopback(oi->interface))) - thread_add_event(master, interface_up, oi, 0, NULL); + thread_execute(master, interface_up, oi, 0); else - thread_add_event(master, interface_down, oi, 0, NULL); + thread_execute(master, interface_down, oi, 0); return; } @@ -679,6 +684,12 @@ int interface_up(struct thread *thread) oi = (struct ospf6_interface *)THREAD_ARG(thread); assert(oi && oi->interface); + /* + * Remove old pointer. If this thread wasn't a timer this + * operation won't make a difference, because it is already NULL. + */ + oi->thread_sso = NULL; + if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug("Interface Event %s: [InterfaceUp]", oi->interface->name); @@ -721,6 +732,22 @@ int interface_up(struct thread *thread) return 0; } +#ifdef __FreeBSD__ + /* + * XXX: Schedule IPv6 group join for later, otherwise we might + * lose the multicast group registration caused by IPv6 group + * leave race. + */ + if (oi->sso_try_cnt == 0) { + oi->sso_try_cnt++; + zlog_info("Scheduling %s for sso", oi->interface->name); + thread_add_timer(master, interface_up, oi, + OSPF6_INTERFACE_SSO_RETRY_INT, + &oi->thread_sso); + return 0; + } +#endif /* __FreeBSD__ */ + /* Join AllSPFRouters */ if (ospf6_sso(oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP) < 0) { @@ -729,7 +756,8 @@ int interface_up(struct thread *thread) "Scheduling %s for sso retry, trial count: %d", oi->interface->name, oi->sso_try_cnt); thread_add_timer(master, interface_up, oi, - OSPF6_INTERFACE_SSO_RETRY_INT, NULL); + OSPF6_INTERFACE_SSO_RETRY_INT, + &oi->thread_sso); } return 0; } @@ -830,6 +858,9 @@ int interface_down(struct thread *thread) /* Stop Hellos */ THREAD_OFF(oi->thread_send_hello); + /* Stop trying to set socket options. */ + THREAD_OFF(oi->thread_sso); + /* Leave AllSPFRouters */ if (oi->state > OSPF6_INTERFACE_DOWN) ospf6_sso(oi->interface->ifindex, &allspfrouters6, @@ -1602,6 +1633,7 @@ DEFUN (ipv6_ospf6_passive, SET_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE); THREAD_OFF(oi->thread_send_hello); + THREAD_OFF(oi->thread_sso); for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) { THREAD_OFF(on->inactivity_timer); @@ -1631,7 +1663,7 @@ DEFUN (no_ipv6_ospf6_passive, UNSET_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE); THREAD_OFF(oi->thread_send_hello); - oi->thread_send_hello = NULL; + THREAD_OFF(oi->thread_sso); thread_add_event(master, ospf6_hello_send, oi, 0, &oi->thread_send_hello); @@ -1791,8 +1823,8 @@ DEFUN (ipv6_ospf6_network, } /* Reset the interface */ - thread_add_event(master, interface_down, oi, 0, NULL); - thread_add_event(master, interface_up, oi, 0, NULL); + thread_execute(master, interface_down, oi, 0); + thread_execute(master, interface_up, oi, 0); return CMD_SUCCESS; } @@ -1825,8 +1857,8 @@ DEFUN (no_ipv6_ospf6_network, oi->type = type; /* Reset the interface */ - thread_add_event(master, interface_down, oi, 0, NULL); - thread_add_event(master, interface_up, oi, 0, NULL); + thread_execute(master, interface_down, oi, 0); + thread_execute(master, interface_up, oi, 0); return CMD_SUCCESS; } @@ -1969,8 +2001,8 @@ static void ospf6_interface_clear(struct vty *vty, struct interface *ifp) zlog_debug("Interface %s: clear by reset", ifp->name); /* Reset the interface */ - thread_add_event(master, interface_down, oi, 0, NULL); - thread_add_event(master, interface_up, oi, 0, NULL); + thread_execute(master, interface_down, oi, 0); + thread_execute(master, interface_up, oi, 0); } /* Clear interface */ diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 8fd43f099..e0c39a29b 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -80,6 +80,7 @@ struct ospf6_interface { /* Interface socket setting trial counter, resets on success */ uint8_t sso_try_cnt; + struct thread *thread_sso; /* OSPF6 Interface flag */ char flag; diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 046badc82..61094c7cd 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -43,6 +43,7 @@ #include "ospf6d.h" #include "ospf6_top.h" #include "ospf6_message.h" +#include "ospf6_network.h" #include "ospf6_asbr.h" #include "ospf6_lsa.h" #include "ospf6_interface.h" @@ -84,8 +85,10 @@ static void __attribute__((noreturn)) ospf6_exit(int status) frr_early_fini(); - if (ospf6) + if (ospf6) { ospf6_delete(ospf6); + ospf6 = NULL; + } bfd_gbl_exit(); @@ -97,6 +100,7 @@ static void __attribute__((noreturn)) ospf6_exit(int status) ospf6_asbr_terminate(); ospf6_lsa_terminate(); + ospf6_serv_close(); /* reverse access_list_init */ access_list_reset(); diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index 8df5f1cc4..625ad884f 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -73,6 +73,15 @@ static void ospf6_set_checksum(void) #endif /* DISABLE_IPV6_CHECKSUM */ } +void ospf6_serv_close(void) +{ + if (ospf6_sock > 0) { + close(ospf6_sock); + ospf6_sock = -1; + return; + } +} + /* Make ospf6d's server socket. */ int ospf6_serv_sock(void) { @@ -163,6 +172,7 @@ int ospf6_sendmsg(struct in6_addr *src, struct in6_addr *dst, assert(dst); assert(*ifindex); + memset(&cmsgbuf, 0, sizeof(cmsgbuf)); scmsgp = (struct cmsghdr *)&cmsgbuf; pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); memset(&dst_sin6, 0, sizeof(struct sockaddr_in6)); diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index 7c7c155fb..7fe6e33ff 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -26,6 +26,7 @@ extern struct in6_addr allspfrouters6; extern struct in6_addr alldrouters6; extern int ospf6_serv_sock(void); +extern void ospf6_serv_close(void); extern int ospf6_sso(ifindex_t ifindex, struct in6_addr *group, int option); extern int ospf6_sendmsg(struct in6_addr *, struct in6_addr *, ifindex_t *, diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index d9c29f265..eac0eee45 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -73,7 +73,7 @@ noinst_HEADERS += \ ospf6d/ospf6d.h \ # end -ospf6d_ospf6d_LDADD = ospf6d/libospf6.a lib/libfrr.la @LIBCAP@ +ospf6d_ospf6d_LDADD = ospf6d/libospf6.a lib/libfrr.la $(LIBCAP) ospf6d_ospf6d_SOURCES = \ ospf6d/ospf6_main.c \ # end diff --git a/ospfclient/subdir.am b/ospfclient/subdir.am index c05d920d5..94d489358 100644 --- a/ospfclient/subdir.am +++ b/ospfclient/subdir.am @@ -23,7 +23,7 @@ endif ospfclient_ospfclient_LDADD = \ ospfclient/libfrrospfapiclient.la \ - @LIBCAP@ \ + $(LIBCAP) \ # end if STATIC_BIN diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index b1175a2f6..a3b337a0c 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -300,7 +300,7 @@ uint32_t msg_get_seq(struct msg *msg) * ----------------------------------------------------------- */ -struct msg_fifo *msg_fifo_new() +struct msg_fifo *msg_fifo_new(void) { return XCALLOC(MTYPE_OSPF_API_FIFO, sizeof(struct msg_fifo)); } diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 48d210d27..f74d9733e 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -538,8 +538,7 @@ static void ospf_header_dump(struct ospf_header *ospfh) case OSPF_AUTH_NULL: break; case OSPF_AUTH_SIMPLE: - memset(buf, 0, 9); - strncpy(buf, (char *)ospfh->u.auth_data, 8); + strlcpy(buf, (char *)ospfh->u.auth_data, sizeof(buf)); zlog_debug(" Simple Password %s", buf); break; case OSPF_AUTH_CRYPTOGRAPHIC: diff --git a/ospfd/ospf_errors.c b/ospfd/ospf_errors.c index 566fc2920..dd0216019 100644 --- a/ospfd/ospf_errors.c +++ b/ospfd/ospf_errors.c @@ -170,6 +170,12 @@ static struct log_ref ferr_ospf_err[] = { .suggestion = "Gather log files and open an issue", }, { + .code = EC_OSPF_LARGE_HELLO, + .title = "OSPF Encountered a Large Hello", + .description = "OSPF attempted to send a Hello larger than MTU but did not", + .suggestion = "Too many neighbors configured on a single interface. Suggestion is to decrease the number of neighbors on a single interface/subnet" + }, + { .code = END_FERR, } }; diff --git a/ospfd/ospf_errors.h b/ospfd/ospf_errors.h index cea649a6f..726f7d9c8 100644 --- a/ospfd/ospf_errors.h +++ b/ospfd/ospf_errors.h @@ -47,6 +47,7 @@ enum ospf_log_refs { EC_OSPF_LSA_MISSING, EC_OSPF_PTP_NEIGHBOR, EC_OSPF_LSA_SIZE, + EC_OSPF_LARGE_HELLO, }; extern void ospf_error_init(void); diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index f1477ba14..ce1604a5b 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -1182,7 +1182,7 @@ int ospf_vls_in_area(struct ospf_area *area) } -struct crypt_key *ospf_crypt_key_new() +struct crypt_key *ospf_crypt_key_new(void) { return XCALLOC(MTYPE_OSPF_CRYPT_KEY, sizeof(struct crypt_key)); } @@ -1230,7 +1230,7 @@ uint8_t ospf_default_iftype(struct interface *ifp) return OSPF_IFTYPE_BROADCAST; } -void ospf_if_init() +void ospf_if_init(void) { /* Initialize Zebra interface data structure. */ hook_register_prio(if_add, 0, ospf_if_new_hook); diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 288ce43f7..c9710e916 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -150,7 +150,7 @@ int ospf_lsa_checksum_valid(struct lsa_header *lsa) /* Create OSPF LSA. */ -struct ospf_lsa *ospf_lsa_new() +struct ospf_lsa *ospf_lsa_new(void) { struct ospf_lsa *new; @@ -2249,6 +2249,22 @@ void ospf_external_lsa_refresh_default(struct ospf *ospf) } } +void ospf_default_originate_lsa_update(struct ospf *ospf) +{ + struct prefix_ipv4 p; + struct ospf_lsa *lsa; + + p.family = AF_INET; + p.prefixlen = 0; + p.prefix.s_addr = 0; + + lsa = ospf_external_info_find_lsa(ospf, &p); + if (lsa && IS_LSA_MAXAGE(lsa)) { + ospf_discard_from_db(ospf, lsa->lsdb, lsa); + ospf_lsdb_delete(lsa->lsdb, lsa); + } +} + void ospf_external_lsa_refresh_type(struct ospf *ospf, uint8_t type, unsigned short instance, int force) { diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index ba4c4c1ca..4b4d760f4 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -296,6 +296,7 @@ extern int ospf_lsa_maxage_walker(struct thread *); extern struct ospf_lsa *ospf_lsa_refresh(struct ospf *, struct ospf_lsa *); extern void ospf_external_lsa_refresh_default(struct ospf *); +extern void ospf_default_originate_lsa_update(struct ospf *ospf); extern void ospf_external_lsa_refresh_type(struct ospf *, uint8_t, unsigned short, int); diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c index f39bea976..2e850c4e2 100644 --- a/ospfd/ospf_lsdb.c +++ b/ospfd/ospf_lsdb.c @@ -31,7 +31,7 @@ #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" -struct ospf_lsdb *ospf_lsdb_new() +struct ospf_lsdb *ospf_lsdb_new(void) { struct ospf_lsdb *new; diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 3bb3b79a6..b3c91b900 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -148,7 +148,7 @@ void ospf_packet_free(struct ospf_packet *op) XFREE(MTYPE_OSPF_PACKET, op); } -struct ospf_fifo *ospf_fifo_new() +struct ospf_fifo *ospf_fifo_new(void) { struct ospf_fifo *new; @@ -2098,10 +2098,22 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (current == NULL || (ret = ospf_lsa_more_recent(current, lsa)) < 0) { + /* CVE-2017-3224 */ + if (current && (lsa->data->ls_seqnum == + htonl(OSPF_MAX_SEQUENCE_NUMBER) + && !IS_LSA_MAXAGE(lsa))) { + zlog_debug( + "Link State Update[%s]: has Max Seq but not MaxAge. Dropping it", + dump_lsa_key(lsa)); + + DISCARD_LSA(lsa, 4); + continue; + } + /* Actual flooding procedure. */ if (ospf_flood(oi->ospf, nbr, current, lsa) < 0) /* Trap NSSA later. */ - DISCARD_LSA(lsa, 4); + DISCARD_LSA(lsa, 5); continue; } @@ -2158,7 +2170,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, oi->ls_ack, ospf_lsa_lock(lsa)); - DISCARD_LSA(lsa, 5); + DISCARD_LSA(lsa, 6); } else /* Acknowledge the receipt of the LSA by sending a Link State Acknowledgment packet back out the @@ -2166,7 +2178,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, interface. */ { ospf_ls_ack_send(nbr, lsa); - DISCARD_LSA(lsa, 6); + DISCARD_LSA(lsa, 7); } } @@ -2183,7 +2195,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (IS_LSA_MAXAGE(current) && current->data->ls_seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER)) { - DISCARD_LSA(lsa, 7); + DISCARD_LSA(lsa, 8); } /* Otherwise, as long as the database copy has not been sent in a @@ -2206,7 +2218,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, ospf_ls_upd_send_lsa( nbr, current, OSPF_SEND_PACKET_DIRECT); - DISCARD_LSA(lsa, 8); + DISCARD_LSA(lsa, 9); } } } @@ -3309,6 +3321,15 @@ static int ospf_make_hello(struct ospf_interface *oi, struct stream *s) .prefix4)) flag = 1; + /* Hello packet overflows interface MTU. */ + if (length + sizeof(uint32_t) + > ospf_packet_max(oi)) { + flog_err( + EC_OSPF_LARGE_HELLO, + "Oversized Hello packet! Larger than MTU. Not sending it out"); + return 0; + } + stream_put_ipv4( s, nbr->router_id @@ -3578,6 +3599,11 @@ static void ospf_hello_send_sub(struct ospf_interface *oi, in_addr_t addr) /* Prepare OSPF Hello body. */ length += ospf_make_hello(oi, op->s); + if (length == OSPF_HEADER_SIZE) { + /* Hello overshooting MTU */ + ospf_packet_free(op); + return; + } /* Fill OSPF header. */ ospf_fill_header(oi, op->s, length); diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index 72f6dbe08..4a0d4add1 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -146,7 +146,7 @@ static int ospf_router_info_register(uint8_t scope) return rc; } -static int ospf_router_info_unregister() +static int ospf_router_info_unregister(void) { if ((OspfRI.scope != OSPF_OPAQUE_AS_LSA) diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index 7ee91b5b6..da83c1dda 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -39,7 +39,7 @@ #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_dump.h" -struct ospf_route *ospf_route_new() +struct ospf_route *ospf_route_new(void) { struct ospf_route *new; @@ -51,7 +51,7 @@ struct ospf_route *ospf_route_new() return new; } -void ospf_route_free(struct ospf_route * or) +void ospf_route_free(struct ospf_route *or) { if (or->paths) list_delete(& or->paths); @@ -59,7 +59,7 @@ void ospf_route_free(struct ospf_route * or) XFREE(MTYPE_OSPF_ROUTE, or); } -struct ospf_path *ospf_path_new() +struct ospf_path *ospf_path_new(void) { struct ospf_path *new; diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index 54009639f..a15e605ac 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -70,11 +70,19 @@ static void ospf_route_map_update(const char *name) /* Keep old route-map. */ struct route_map *old = ROUTEMAP(red); - /* Update route-map. */ - ROUTEMAP(red) = - route_map_lookup_by_name( - ROUTEMAP_NAME(red)); - + if (!old) { + /* Route-map creation */ + /* Update route-map. */ + ROUTEMAP(red) = + route_map_lookup_by_name( + ROUTEMAP_NAME(red)); + + route_map_counter_increment( + ROUTEMAP(red)); + } else { + /* Route-map deletion */ + ROUTEMAP(red) = NULL; + } /* No update for this distribute type. */ if (old == NULL diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 43842e414..f0ddf7cc0 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -1020,10 +1020,10 @@ static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp) * When change the FRR Self SRGB, update the NHLFE Input Label * for all Extended Prefix with SID index through hash_iterate() */ -static void update_in_nhlfe(struct hash_backet *backet, void *args) +static void update_in_nhlfe(struct hash_bucket *bucket, void *args) { struct listnode *node; - struct sr_node *srn = (struct sr_node *)backet->data; + struct sr_node *srn = (struct sr_node *)bucket->data; struct sr_prefix *srp; struct sr_nhlfe new; @@ -1052,10 +1052,10 @@ static void update_in_nhlfe(struct hash_backet *backet, void *args) * When SRGB has changed, update NHLFE Output Label for all Extended Prefix * with SID index which use the given SR-Node as nexthop though hash_iterate() */ -static void update_out_nhlfe(struct hash_backet *backet, void *args) +static void update_out_nhlfe(struct hash_bucket *bucket, void *args) { struct listnode *node; - struct sr_node *srn = (struct sr_node *)backet->data; + struct sr_node *srn = (struct sr_node *)bucket->data; struct sr_node *srnext = (struct sr_node *)args; struct sr_prefix *srp; struct sr_nhlfe new; @@ -1192,7 +1192,7 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) /* Update NHLFE if it is a neighbor SR node */ if (srn->neighbor == OspfSR.self) hash_iterate(OspfSR.neighbors, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))update_out_nhlfe, (void *)srn); } @@ -1531,10 +1531,10 @@ void ospf_sr_update_prefix(struct interface *ifp, struct prefix *p) * Following functions are used to update MPLS LFIB after a SPF run */ -static void ospf_sr_nhlfe_update(struct hash_backet *backet, void *args) +static void ospf_sr_nhlfe_update(struct hash_bucket *bucket, void *args) { - struct sr_node *srn = (struct sr_node *)backet->data; + struct sr_node *srn = (struct sr_node *)bucket->data; struct listnode *node; struct sr_prefix *srp; struct sr_nhlfe old; @@ -1593,7 +1593,7 @@ static int ospf_sr_update_schedule(struct thread *t) if (IS_DEBUG_OSPF_SR) zlog_debug("SR (%s): Start SPF update", __func__); - hash_iterate(OspfSR.neighbors, (void (*)(struct hash_backet *, + hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *, void *))ospf_sr_nhlfe_update, NULL); @@ -1818,7 +1818,7 @@ DEFUN (sr_sid_label_range, /* Update NHLFE entries */ hash_iterate(OspfSR.neighbors, - (void (*)(struct hash_backet *, void *))update_in_nhlfe, + (void (*)(struct hash_bucket *, void *))update_in_nhlfe, NULL); return CMD_SUCCESS; @@ -1850,7 +1850,7 @@ DEFUN (no_sr_sid_label_range, /* Update NHLFE entries */ hash_iterate(OspfSR.neighbors, - (void (*)(struct hash_backet *, void *))update_in_nhlfe, + (void (*)(struct hash_bucket *, void *))update_in_nhlfe, NULL); return CMD_SUCCESS; @@ -2281,18 +2281,18 @@ static void show_sr_node(struct vty *vty, struct json_object *json, vty_out(vty, "\n"); } -static void show_vty_srdb(struct hash_backet *backet, void *args) +static void show_vty_srdb(struct hash_bucket *bucket, void *args) { struct vty *vty = (struct vty *)args; - struct sr_node *srn = (struct sr_node *)backet->data; + struct sr_node *srn = (struct sr_node *)bucket->data; show_sr_node(vty, NULL, srn); } -static void show_json_srdb(struct hash_backet *backet, void *args) +static void show_json_srdb(struct hash_bucket *bucket, void *args) { struct json_object *json = (struct json_object *)args; - struct sr_node *srn = (struct sr_node *)backet->data; + struct sr_node *srn = (struct sr_node *)bucket->data; show_sr_node(NULL, json, srn); } @@ -2366,14 +2366,14 @@ DEFUN (show_ip_opsf_srdb, /* No parameters have been provided, Iterate through all the SRDB */ if (uj) { - hash_iterate(OspfSR.neighbors, (void (*)(struct hash_backet *, + hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *, void *))show_json_srdb, (void *)json_node_array); vty_out(vty, "%s\n", json_object_to_json_string_ext( json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); } else { - hash_iterate(OspfSR.neighbors, (void (*)(struct hash_backet *, + hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *, void *))show_vty_srdb, (void *)vty); } diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 3efc219fc..bd8cbee11 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -150,7 +150,7 @@ static int ospf_mpls_te_register(enum inter_as_mode mode) return rc; } -static int ospf_mpls_te_unregister() +static int ospf_mpls_te_unregister(void) { uint8_t scope; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 3ab9c018e..bb22f211a 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -954,8 +954,9 @@ static int ospf_vl_set_security(struct ospf_vl_data *vl_data, if (vl_config->auth_key) { memset(IF_DEF_PARAMS(ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE + 1); - strncpy((char *)IF_DEF_PARAMS(ifp)->auth_simple, - vl_config->auth_key, OSPF_AUTH_SIMPLE_SIZE); + strlcpy((char *)IF_DEF_PARAMS(ifp)->auth_simple, + vl_config->auth_key, + sizeof(IF_DEF_PARAMS(ifp)->auth_simple)); } else if (vl_config->md5_key) { if (ospf_crypt_key_lookup(IF_DEF_PARAMS(ifp)->auth_crypt, vl_config->crypto_key_id) @@ -967,8 +968,8 @@ static int ospf_vl_set_security(struct ospf_vl_data *vl_data, ck = ospf_crypt_key_new(); ck->key_id = vl_config->crypto_key_id; memset(ck->auth_key, 0, OSPF_AUTH_MD5_SIZE + 1); - strncpy((char *)ck->auth_key, vl_config->md5_key, - OSPF_AUTH_MD5_SIZE); + strlcpy((char *)ck->auth_key, vl_config->md5_key, + sizeof(ck->auth_key)); ospf_crypt_key_add(IF_DEF_PARAMS(ifp)->auth_crypt, ck); } else if (vl_config->crypto_key_id != 0) { @@ -1147,14 +1148,12 @@ DEFUN (ospf_area_vlink, if (vl_config.crypto_key_id < 0) return CMD_WARNING_CONFIG_FAILED; - memset(md5_key, 0, OSPF_AUTH_MD5_SIZE + 1); - strncpy(md5_key, argv[idx + 3]->arg, OSPF_AUTH_MD5_SIZE); + strlcpy(md5_key, argv[idx + 3]->arg, sizeof(md5_key)); vl_config.md5_key = md5_key; } if (argv_find(argv, argc, "authentication-key", &idx)) { - memset(auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1); - strncpy(auth_key, argv[idx + 1]->arg, OSPF_AUTH_SIMPLE_SIZE); + strlcpy(auth_key, argv[idx + 1]->arg, sizeof(auth_key)); vl_config.auth_key = auth_key; } @@ -1205,14 +1204,17 @@ DEFUN (no_ospf_area_vlink, return CMD_WARNING_CONFIG_FAILED; } + vl_data = ospf_vl_lookup(ospf, area, vl_config.vl_peer); + if (!vl_data) { + vty_out(vty, "Virtual link does not exist\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (argc <= 5) { /* Basic VLink no command */ /* Thats all folks! - BUGS B. strikes again!!!*/ - if ((vl_data = ospf_vl_lookup(ospf, area, vl_config.vl_peer))) - ospf_vl_delete(ospf, vl_data); - + ospf_vl_delete(ospf, vl_data); ospf_area_check_free(ospf, vl_config.area_id); - return CMD_SUCCESS; } @@ -6892,9 +6894,8 @@ DEFUN (ip_ospf_authentication_key, ospf_if_update_params(ifp, addr); } - memset(params->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE + 1); - strncpy((char *)params->auth_simple, argv[3]->arg, - OSPF_AUTH_SIMPLE_SIZE); + strlcpy((char *)params->auth_simple, argv[3]->arg, + sizeof(params->auth_simple)); SET_IF_PARAM(params, auth_simple); return CMD_SUCCESS; @@ -7003,8 +7004,7 @@ DEFUN (ip_ospf_message_digest_key, ck = ospf_crypt_key_new(); ck->key_id = (uint8_t)key_id; - memset(ck->auth_key, 0, OSPF_AUTH_MD5_SIZE + 1); - strncpy((char *)ck->auth_key, cryptkey, OSPF_AUTH_MD5_SIZE); + strlcpy((char *)ck->auth_key, cryptkey, sizeof(ck->auth_key)); ospf_crypt_key_add(params->auth_crypt, ck); SET_IF_PARAM(params, auth_crypt); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 79ddb192c..ea2c492e1 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -340,11 +340,11 @@ static int ospf_interface_address_delete(int command, struct zclient *zclient, } static int ospf_interface_link_params(int command, struct zclient *zclient, - zebra_size_t length) + zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; - ifp = zebra_interface_link_params_read(zclient->ibuf); + ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id); if (ifp == NULL) return 0; @@ -869,6 +869,9 @@ int ospf_redistribute_default_unset(struct ospf *ospf) ospf_asbr_status_update(ospf, --ospf->redistribute); + /* clean up maxage default originate external lsa */ + ospf_default_originate_lsa_update(ospf); + return CMD_SUCCESS; } @@ -980,17 +983,22 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei, /* OSPF route-map set for redistribution */ void ospf_routemap_set(struct ospf_redist *red, const char *name) { - if (ROUTEMAP_NAME(red)) + if (ROUTEMAP_NAME(red)) { + route_map_counter_decrement(ROUTEMAP(red)); free(ROUTEMAP_NAME(red)); + } ROUTEMAP_NAME(red) = strdup(name); ROUTEMAP(red) = route_map_lookup_by_name(name); + route_map_counter_increment(ROUTEMAP(red)); } void ospf_routemap_unset(struct ospf_redist *red) { - if (ROUTEMAP_NAME(red)) + if (ROUTEMAP_NAME(red)) { + route_map_counter_decrement(ROUTEMAP(red)); free(ROUTEMAP_NAME(red)); + } ROUTEMAP_NAME(red) = NULL; ROUTEMAP(red) = NULL; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index a18e2de72..073a51561 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -234,8 +234,12 @@ static struct ospf *ospf_new(unsigned short instance, const char *name) new->instance = instance; new->router_id.s_addr = htonl(0); new->router_id_static.s_addr = htonl(0); - if (name && !strmatch(name, VRF_DEFAULT_NAME)) { - new->vrf_id = VRF_UNKNOWN; + if (name) { + vrf = vrf_lookup_by_name(name); + if (vrf) + new->vrf_id = vrf->vrf_id; + else + new->vrf_id = VRF_UNKNOWN; /* Freed in ospf_finish_final */ new->name = XSTRDUP(MTYPE_OSPF_TOP, name); if (IS_DEBUG_OSPF_EVENT) diff --git a/ospfd/subdir.am b/ospfd/subdir.am index 3ad1b870b..48dd741b2 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -98,7 +98,7 @@ noinst_HEADERS += \ ospfd/ospf_zebra.h \ # end -ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la @LIBCAP@ @LIBM@ +ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la $(LIBCAP) $(LIBM) ospfd_ospfd_SOURCES = ospfd/ospf_main.c ospfd_ospfd_snmp_la_SOURCES = ospfd/ospf_snmp.c diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index eb2c082fb..8f8b6aeed 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -121,6 +121,17 @@ void pbr_map_reason_string(unsigned int reason, char *buf, int size) } } +void pbr_map_final_interface_deletion(struct pbr_map *pbrm, + struct pbr_map_interface *pmi) +{ + if (pmi->delete == true) { + listnode_delete(pbrm->incoming, pmi); + pmi->pbrm = NULL; + + bf_release_index(pbrm->ifi_bitfield, pmi->install_bit); + XFREE(MTYPE_PBR_MAP_INTERFACE, pmi); + } +} void pbr_map_interface_delete(struct pbr_map *pbrm, struct interface *ifp_del) { @@ -409,7 +420,8 @@ void pbr_map_schedule_policy_from_nhg(const char *nh_group) pbrm->name); for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) { DEBUGD(&pbr_dbg_map, "\tNH Grp name: %s", - pbrms->nhgrp_name ? pbrms->nhgrp_name : "NULL"); + pbrms->nhgrp_name ? + pbrms->nhgrp_name : pbrms->internal_nhg_name); if (pbrms->nhgrp_name && (strcmp(nh_group, pbrms->nhgrp_name) == 0)) { @@ -465,11 +477,7 @@ void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi) for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) pbr_send_pbr_map(pbrms, pmi, false); - listnode_delete(pbrm->incoming, pmi); - pmi->pbrm = NULL; - - bf_release_index(pbrm->ifi_bitfield, pmi->install_bit); - XFREE(MTYPE_PBR_MAP_INTERFACE, pmi); + pmi->delete = true; } /* @@ -526,12 +534,9 @@ void pbr_map_check(struct pbr_map_sequence *pbrms) DEBUGD(&pbr_dbg_map, "%s: for %s(%u)", __PRETTY_FUNCTION__, pbrm->name, pbrms->seqno); if (pbr_map_check_valid(pbrm->name)) - DEBUGD(&pbr_dbg_map, "We are totally valid %s\n", + DEBUGD(&pbr_dbg_map, "We are totally valid %s", pbrm->name); - DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64, - __PRETTY_FUNCTION__, pbrm->name, pbrms->seqno, pbrms->reason); - if (pbrms->reason == PBR_MAP_VALID_SEQUENCE_NUMBER) { install = true; DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64, diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h index 7cd079d16..945f76bb2 100644 --- a/pbrd/pbr_map.h +++ b/pbrd/pbr_map.h @@ -147,6 +147,8 @@ extern void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms); extern void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp); extern void pbr_map_interface_delete(struct pbr_map *pbrm, struct interface *ifp); +extern void pbr_map_final_interface_deletion(struct pbr_map *pbrm, + struct pbr_map_interface *pmi); extern void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp); extern void pbr_map_init(void); diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 6103bd7db..2cba657f6 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -124,7 +124,7 @@ static void pbr_nh_delete(struct pbr_nexthop_cache **pnhc) XFREE(MTYPE_PBR_NHG, *pnhc); } -static void pbr_nh_delete_iterate(struct hash_backet *b, void *p) +static void pbr_nh_delete_iterate(struct hash_bucket *b, void *p) { pbr_nh_delete((struct pbr_nexthop_cache **)&b->data); } @@ -164,8 +164,8 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2) == pbrnc2->nexthop->gate.ipv4.s_addr; case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6: - return !!memcmp(&pbrnc1->nexthop->gate.ipv6, - &pbrnc2->nexthop->gate.ipv6, 16); + return !memcmp(&pbrnc1->nexthop->gate.ipv6, + &pbrnc2->nexthop->gate.ipv6, 16); case NEXTHOP_TYPE_BLACKHOLE: return pbrnc1->nexthop->bh_type == pbrnc2->nexthop->bh_type; } @@ -319,7 +319,7 @@ static struct pbr_nexthop_cache *pbr_nht_lookup_nexthop(struct nexthop *nexthop) } #endif -static void pbr_nht_find_nhg_from_table_install(struct hash_backet *b, +static void pbr_nht_find_nhg_from_table_install(struct hash_bucket *b, void *data) { struct pbr_nexthop_group_cache *pnhgc = @@ -348,7 +348,7 @@ void pbr_nht_route_installed_for_table(uint32_t table_id) &table_id); } -static void pbr_nht_find_nhg_from_table_remove(struct hash_backet *b, +static void pbr_nht_find_nhg_from_table_remove(struct hash_bucket *b, void *data) { ; @@ -657,7 +657,7 @@ struct pbr_nht_individual { uint32_t valid; }; -static void pbr_nht_individual_nexthop_update_lookup(struct hash_backet *b, +static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b, void *data) { struct pbr_nexthop_cache *pnhc = b->data; @@ -689,7 +689,7 @@ static void pbr_nht_individual_nexthop_update_lookup(struct hash_backet *b, pnhi->valid += 1; } -static void pbr_nht_nexthop_update_lookup(struct hash_backet *b, void *data) +static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data) { struct pbr_nexthop_group_cache *pnhgc = b->data; struct pbr_nht_individual pnhi; @@ -822,7 +822,7 @@ bool pbr_nht_get_installed(const char *name) return pnhgc->installed; } -static void pbr_nht_show_nhg_nexthops(struct hash_backet *b, void *data) +static void pbr_nht_show_nhg_nexthops(struct hash_bucket *b, void *data) { struct pbr_nexthop_cache *pnhc = b->data; struct vty *vty = data; @@ -836,7 +836,7 @@ struct pbr_nht_show { const char *name; }; -static void pbr_nht_show_nhg(struct hash_backet *b, void *data) +static void pbr_nht_show_nhg(struct hash_bucket *b, void *data) { struct pbr_nexthop_group_cache *pnhgc = b->data; struct pbr_nht_show *pns = data; diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index a4b87f99d..f8232c958 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -300,7 +300,7 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, char buf[PBR_NHC_NAMELEN]; if (no) { - vty_out(vty, "No nexthops to delete"); + vty_out(vty, "No nexthops to delete\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -349,6 +349,7 @@ DEFPY (pbr_policy, struct pbr_map *pbrm, *old_pbrm; struct pbr_interface *pbr_ifp = ifp->info; + old_pbrm = NULL; pbrm = pbrm_find(mapname); if (!pbr_ifp) { @@ -369,12 +370,23 @@ DEFPY (pbr_policy, } else { if (strcmp(pbr_ifp->mapname, "") != 0) { old_pbrm = pbrm_find(pbr_ifp->mapname); - if (old_pbrm) + + /* + * So if we have an old pbrm we should only + * delete it if we are actually deleting and + * moving to a new pbrm + */ + if (old_pbrm && old_pbrm != pbrm) pbr_map_interface_delete(old_pbrm, ifp); } snprintf(pbr_ifp->mapname, sizeof(pbr_ifp->mapname), "%s", mapname); - if (pbrm) + + /* + * So only reinstall if the old_pbrm and this pbrm are + * different. + */ + if (pbrm && pbrm != old_pbrm) pbr_map_add_interface(pbrm, ifp); } diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 7974bbfb4..558e63574 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -69,6 +69,9 @@ static int interface_add(int command, struct zclient *zclient, if (!ifp) return 0; + DEBUGD(&pbr_dbg_zebra, + "%s: %s", __PRETTY_FUNCTION__, ifp->name); + if (!ifp->info) pbr_if_new(ifp); @@ -89,6 +92,9 @@ static int interface_delete(int command, struct zclient *zclient, if (ifp == NULL) return 0; + DEBUGD(&pbr_dbg_zebra, + "%s: %s", __PRETTY_FUNCTION__, ifp->name); + if_set_index(ifp, IFINDEX_INTERNAL); return 0; @@ -97,7 +103,14 @@ static int interface_delete(int command, struct zclient *zclient, static int interface_address_add(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { - zebra_interface_address_read(command, zclient->ibuf, vrf_id); + struct connected *c; + char buf[PREFIX_STRLEN]; + + c = zebra_interface_address_read(command, zclient->ibuf, vrf_id); + + DEBUGD(&pbr_dbg_zebra, + "%s: %s added %s", __PRETTY_FUNCTION__, c->ifp->name, + prefix2str(c->address, buf, sizeof(buf))); return 0; } @@ -106,12 +119,17 @@ static int interface_address_delete(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; + char buf[PREFIX_STRLEN]; c = zebra_interface_address_read(command, zclient->ibuf, vrf_id); if (!c) return 0; + DEBUGD(&pbr_dbg_zebra, + "%s: %s deleted %s", __PRETTY_FUNCTION__, c->ifp->name, + prefix2str(c->address, buf, sizeof(buf))); + connected_free(c); return 0; } @@ -119,8 +137,12 @@ static int interface_address_delete(int command, struct zclient *zclient, static int interface_state_up(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { + struct interface *ifp; - zebra_interface_state_read(zclient->ibuf, vrf_id); + ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); + + DEBUGD(&pbr_dbg_zebra, + "%s: %s is up", __PRETTY_FUNCTION__, ifp->name); return 0; } @@ -128,8 +150,12 @@ static int interface_state_up(int command, struct zclient *zclient, static int interface_state_down(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { + struct interface *ifp; + + ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - zebra_interface_state_read(zclient->ibuf, vrf_id); + DEBUGD(&pbr_dbg_zebra, + "%s: %s is down", __PRETTY_FUNCTION__, ifp->name); return 0; } @@ -142,11 +168,11 @@ static int route_notify_owner(int command, struct zclient *zclient, uint32_t table_id; char buf[PREFIX_STRLEN]; - prefix2str(&p, buf, sizeof(buf)); - if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, ¬e)) return -1; + prefix2str(&p, buf, sizeof(buf)); + switch (note) { case ZAPI_ROUTE_FAIL_INSTALL: DEBUGD(&pbr_dbg_zebra, @@ -207,28 +233,32 @@ static int rule_notify_owner(int command, struct zclient *zclient, switch (note) { case ZAPI_RULE_FAIL_INSTALL: - DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_FAIL_INSTALL", - __PRETTY_FUNCTION__); pbrms->installed &= ~installed; + DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_FAIL_INSTALL: %lu", + __PRETTY_FUNCTION__, pbrms->installed); break; case ZAPI_RULE_INSTALLED: pbrms->installed |= installed; - DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED", - __PRETTY_FUNCTION__); + DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED: %lu", + __PRETTY_FUNCTION__, pbrms->installed); break; case ZAPI_RULE_FAIL_REMOVE: case ZAPI_RULE_REMOVED: pbrms->installed &= ~installed; - DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED", - __PRETTY_FUNCTION__); + DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED: %lu", + __PRETTY_FUNCTION__, pbrms->installed); break; } + pbr_map_final_interface_deletion(pbrms->parent, pmi); + return 0; } static void zebra_connected(struct zclient *zclient) { + DEBUGD(&pbr_dbg_zebra, "%s: Registering for fun and profit", + __PRETTY_FUNCTION__); zclient_send_reg_requests(zclient, VRF_DEFAULT); } @@ -236,11 +266,15 @@ static void route_add_helper(struct zapi_route *api, struct nexthop_group nhg, uint8_t install_afi) { struct zapi_nexthop *api_nh; + char buf[PREFIX_STRLEN]; struct nexthop *nhop; int i; api->prefix.family = install_afi; + DEBUGD(&pbr_dbg_zebra, "\tEncoding %s", + prefix2str(&api->prefix, buf, sizeof(buf))); + i = 0; for (ALL_NEXTHOPS(nhg, nhop)) { api_nh = &api->nexthops[i]; @@ -284,6 +318,9 @@ void route_add(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg, { struct zapi_route api; + DEBUGD(&pbr_dbg_zebra, "%s for Table: %d", __PRETTY_FUNCTION__, + pnhgc->table_id); + memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; @@ -323,6 +360,9 @@ void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi) { struct zapi_route api; + DEBUGD(&pbr_dbg_zebra, "%s for Table: %d", __PRETTY_FUNCTION__, + pnhgc->table_id); + memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_PBR; diff --git a/pbrd/subdir.am b/pbrd/subdir.am index 794755903..0f2e7ad8b 100644 --- a/pbrd/subdir.am +++ b/pbrd/subdir.am @@ -38,5 +38,5 @@ pbrd/pbr_debug_clippy.c: $(CLIPPY_DEPS) pbrd/pbr_debug.$(OBJEXT): pbrd/pbr_debug_clippy.c pbrd_pbrd_SOURCES = pbrd/pbr_main.c -pbrd_pbrd_LDADD = pbrd/libpbr.a lib/libfrr.la @LIBCAP@ +pbrd_pbrd_LDADD = pbrd/libpbr.a lib/libfrr.la $(LIBCAP) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 7089e2151..eaec002a7 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -62,6 +62,10 @@ #include "pim_bfd.h" #include "bfd.h" +#ifndef VTYSH_EXTRACT_PL +#include "pimd/pim_cmd_clippy.c" +#endif + static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */ }; @@ -2785,9 +2789,9 @@ struct pnc_cache_walk_data { struct pim_instance *pim; }; -static int pim_print_pnc_cache_walkcb(struct hash_backet *backet, void *arg) +static int pim_print_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg) { - struct pim_nexthop_cache *pnc = backet->data; + struct pim_nexthop_cache *pnc = bucket->data; struct pnc_cache_walk_data *cwd = arg; struct vty *vty = cwd->vty; struct pim_instance *pim = cwd->pim; @@ -5138,6 +5142,12 @@ static int pim_rp_cmd_worker(struct pim_instance *pim, struct vty *vty, return CMD_WARNING_CONFIG_FAILED; } + if (result == PIM_GROUP_BAD_ADDR_MASK_COMBO) { + vty_out(vty, "%% Inconsistent address and mask: %s\n", + group); + return CMD_WARNING_CONFIG_FAILED; + } + return CMD_SUCCESS; } @@ -6394,6 +6404,81 @@ static int pim_cmd_interface_add(struct interface *ifp) return 1; } +DEFPY_HIDDEN (pim_test_sg_keepalive, + pim_test_sg_keepalive_cmd, + "test pim [vrf NAME$name] keepalive-reset A.B.C.D$source A.B.C.D$group", + "Test code\n" + PIM_STR + VRF_CMD_HELP_STR + "Reset the Keepalive Timer\n" + "The Source we are resetting\n" + "The Group we are resetting\n") +{ + struct pim_upstream *up; + struct pim_instance *pim; + struct prefix_sg sg; + + sg.src = source; + sg.grp = group; + + if (!name) + pim = pim_get_pim_instance(VRF_DEFAULT); + else { + struct vrf *vrf = vrf_lookup_by_name(name); + + if (!vrf) { + vty_out(vty, "%% Vrf specified: %s does not exist\n", + name); + return CMD_WARNING; + } + + pim = pim_get_pim_instance(vrf->vrf_id); + } + + if (!pim) { + vty_out(vty, "%% Unable to find pim instance\n"); + return CMD_WARNING; + } + + up = pim_upstream_find(pim, &sg); + if (!up) { + vty_out(vty, "%% Unable to find %s specified\n", + pim_str_sg_dump(&sg)); + return CMD_WARNING; + } + + vty_out(vty, "Setting %s to current keep alive time: %d\n", + pim_str_sg_dump(&sg), pim->keep_alive_time); + pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time); + + return CMD_SUCCESS; +} + +DEFPY_HIDDEN (interface_ip_pim_activeactive, + interface_ip_pim_activeactive_cmd, + "[no$no] ip pim active-active", + NO_STR + IP_STR + PIM_STR + "Mark interface as Active-Active for MLAG operations, Hidden because not finished yet\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct pim_interface *pim_ifp; + + if (!no && !pim_cmd_interface_add(ifp)) { + vty_out(vty, "Could not enable PIM SM active-active on interface\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + pim_ifp = ifp->info; + if (no) + pim_ifp->activeactive = false; + else + pim_ifp->activeactive = true; + + return CMD_SUCCESS; +} + DEFUN_HIDDEN (interface_ip_pim_ssm, interface_ip_pim_ssm_cmd, "ip pim ssm", @@ -8632,7 +8717,6 @@ DEFUN (show_ip_msdp_sa_sg_vrf_all, return CMD_SUCCESS; } - void pim_cmd_init(void) { install_node(&interface_node, @@ -8641,6 +8725,8 @@ void pim_cmd_init(void) install_node(&debug_node, pim_debug_config_write); + install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); + install_element(CONFIG_NODE, &ip_pim_rp_cmd); install_element(VRF_NODE, &ip_pim_rp_cmd); install_element(CONFIG_NODE, &no_ip_pim_rp_cmd); @@ -8722,6 +8808,7 @@ void pim_cmd_init(void) &interface_ip_igmp_query_max_response_time_dsec_cmd); install_element(INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_dsec_cmd); + install_element(INTERFACE_NODE, &interface_ip_pim_activeactive_cmd); install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd); install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); install_element(INTERFACE_NODE, &interface_ip_pim_sm_cmd); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 0451ab1e7..6933f4d5b 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -170,6 +170,8 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, pim_ifp->sec_addr_list->cmp = (int (*)(void *, void *))pim_sec_addr_comp; + pim_ifp->activeactive = false; + RB_INIT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb); ifp->info = pim_ifp; diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index a7dc097f8..5066998cb 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -124,6 +124,9 @@ struct pim_interface { /* boundary prefix-list */ char *boundary_oil_plist; + /* Turn on Active-Active for this interface */ + bool activeactive; + int64_t pim_ifstat_start; /* start timestamp for stats */ uint32_t pim_ifstat_hello_sent; uint32_t pim_ifstat_hello_sendfail; diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 2d808639b..b6cd1a7d1 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -266,10 +266,10 @@ void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p) } /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/ -static int pim_update_upstream_nh_helper(struct hash_backet *backet, void *arg) +static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg) { struct pim_instance *pim = (struct pim_instance *)arg; - struct pim_upstream *up = (struct pim_upstream *)backet->data; + struct pim_upstream *up = (struct pim_upstream *)bucket->data; int vif_index = 0; enum pim_rpf_result rpf_result; diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 1290bfe56..2e12d728c 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -392,8 +392,10 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) { - channel_oil->oif_creation[pim_ifp->mroute_vif_index] = - pim_time_monotonic_sec(); + /* Updating time here is not required as this time has to + * indicate when the interface is added + */ + channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask; /* Check the OIF really exists before returning, and only log warning otherwise */ diff --git a/pimd/pim_register.c b/pimd/pim_register.c index b9908ae22..4b402de63 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -189,8 +189,8 @@ void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src, if (PIM_DEBUG_PIM_REG) { char rp_str[INET_ADDRSTRLEN]; - strncpy(rp_str, inet_ntoa(rpg->rpf_addr.u.prefix4), - INET_ADDRSTRLEN - 1); + strlcpy(rp_str, inet_ntoa(rpg->rpf_addr.u.prefix4), + sizeof(rp_str)); zlog_debug("%s: Sending %s %sRegister Packet to %s on %s", __PRETTY_FUNCTION__, up->sg_str, null_register ? "NULL " : "", rp_str, ifp->name); diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 6b76794b7..08f2ffc4e 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -345,6 +345,7 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, struct rp_info *tmp_rp_info; char buffer[BUFSIZ]; struct prefix nht_p; + struct prefix temp; struct pim_nexthop_cache pnc; struct route_node *rn; @@ -352,8 +353,17 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, if (group_range == NULL) result = str2prefix("224.0.0.0/4", &rp_info->group); - else + else { result = str2prefix(group_range, &rp_info->group); + if (result) { + prefix_copy(&temp, &rp_info->group); + apply_mask(&temp); + if (!prefix_same(&rp_info->group, &temp)) { + XFREE(MTYPE_PIM_RP, rp_info); + return PIM_GROUP_BAD_ADDR_MASK_COMBO; + } + } + } if (!result) { XFREE(MTYPE_PIM_RP, rp_info); diff --git a/pimd/pim_signals.c b/pimd/pim_signals.c index 0e9b09bf8..38387d38c 100644 --- a/pimd/pim_signals.c +++ b/pimd/pim_signals.c @@ -33,26 +33,26 @@ * Signal handlers */ -static void pim_sighup() +static void pim_sighup(void) { zlog_info("SIGHUP received, ignoring"); } -static void pim_sigint() +static void pim_sigint(void) { zlog_notice("Terminating on signal SIGINT"); pim_terminate(); exit(1); } -static void pim_sigterm() +static void pim_sigterm(void) { zlog_notice("Terminating on signal SIGTERM"); pim_terminate(); exit(1); } -static void pim_sigusr1() +static void pim_sigusr1(void) { zlog_rotate(); } diff --git a/pimd/pim_static.c b/pimd/pim_static.c index 9569b7dca..442b22e06 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -37,12 +37,12 @@ void pim_static_route_free(struct static_route *s_route) XFREE(MTYPE_PIM_STATIC_ROUTE, s_route); } -static struct static_route *static_route_alloc() +static struct static_route *static_route_alloc(void) { return XCALLOC(MTYPE_PIM_STATIC_ROUTE, sizeof(struct static_route)); } -static struct static_route *static_route_new(unsigned int iif, unsigned int oif, +static struct static_route *static_route_new(ifindex_t iif, ifindex_t oif, struct in_addr group, struct in_addr source) { @@ -76,7 +76,7 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif, ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0; ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0; - if (!iif_index || !oif_index) { + if (!iif_index || !oif_index || iif_index == -1 || oif_index == -1) { zlog_warn( "%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)", __FILE__, __PRETTY_FUNCTION__, iif_index, oif_index); diff --git a/pimd/pim_time.c b/pimd/pim_time.c index 23c85c2fa..f12f76753 100644 --- a/pimd/pim_time.c +++ b/pimd/pim_time.c @@ -47,7 +47,7 @@ static int gettime_monotonic(struct timeval *tv) pim_time_monotonic_sec(): number of seconds since some unspecified starting point */ -int64_t pim_time_monotonic_sec() +int64_t pim_time_monotonic_sec(void) { struct timeval now_tv; @@ -65,7 +65,7 @@ int64_t pim_time_monotonic_sec() pim_time_monotonic_dsec(): number of deciseconds since some unspecified starting point */ -int64_t pim_time_monotonic_dsec() +int64_t pim_time_monotonic_dsec(void) { struct timeval now_tv; int64_t now_dsec; diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index f6385a0ac..649578874 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -362,6 +362,9 @@ int pim_interface_config_write(struct vty *vty) } } + if (pim_ifp->activeactive) + vty_out(vty, " ip pim active-active\n"); + /* boundary */ if (pim_ifp->boundary_oil_plist) { vty_out(vty, diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index b7111cf7b..11ca6e8a1 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -267,6 +267,27 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient, return 0; } +static int pim_zebra_interface_vrf_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + vrf_id_t new_vrf_id; + + ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, + &new_vrf_id); + if (!ifp) + return 0; + + if (PIM_DEBUG_ZEBRA) + zlog_debug("%s: %s updating from %u to %u", + __PRETTY_FUNCTION__, + ifp->name, vrf_id, new_vrf_id); + + if_update_to_new_vrf(ifp, new_vrf_id); + + return 0; +} + #ifdef PIM_DEBUG_IFADDR_DUMP static void dump_if_address(struct interface *ifp) { @@ -762,6 +783,7 @@ void pim_zebra_init(void) zclient->interface_down = pim_zebra_if_state_down; zclient->interface_address_add = pim_zebra_if_address_add; zclient->interface_address_delete = pim_zebra_if_address_del; + zclient->interface_vrf_update = pim_zebra_interface_vrf_update; zclient->nexthop_update = pim_parse_nexthop_update; zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs); diff --git a/pimd/pimd.c b/pimd/pimd.c index b993bcdc0..656b00057 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -67,7 +67,7 @@ void pim_prefix_list_update(struct prefix_list *plist) } } -static void pim_free() +static void pim_free(void) { pim_route_map_terminate(); @@ -123,7 +123,7 @@ void pim_init(void) pim_cmd_init(); } -void pim_terminate() +void pim_terminate(void) { struct zclient *zclient; diff --git a/pimd/pimd.h b/pimd/pimd.h index 73ea9f82c..50c19658d 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -116,16 +116,17 @@ /* Remember 32 bits!!! */ /* PIM error codes */ -#define PIM_SUCCESS 0 -#define PIM_GROUP_BAD_ADDRESS -2 -#define PIM_GROUP_OVERLAP -3 -#define PIM_GROUP_PFXLIST_OVERLAP -4 -#define PIM_RP_BAD_ADDRESS -5 -#define PIM_RP_NO_PATH -6 -#define PIM_RP_NOT_FOUND -7 -#define PIM_RP_PFXLIST_IN_USE -8 -#define PIM_IFACE_NOT_FOUND -9 -#define PIM_UPDATE_SOURCE_DUP -10 +#define PIM_SUCCESS 0 +#define PIM_GROUP_BAD_ADDRESS -2 +#define PIM_GROUP_OVERLAP -3 +#define PIM_GROUP_PFXLIST_OVERLAP -4 +#define PIM_RP_BAD_ADDRESS -5 +#define PIM_RP_NO_PATH -6 +#define PIM_RP_NOT_FOUND -7 +#define PIM_RP_PFXLIST_IN_USE -8 +#define PIM_IFACE_NOT_FOUND -9 +#define PIM_UPDATE_SOURCE_DUP -10 +#define PIM_GROUP_BAD_ADDR_MASK_COMBO -11 const char *const PIM_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS; diff --git a/pimd/subdir.am b/pimd/subdir.am index fef8e3657..7d8df7d10 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -115,7 +115,10 @@ noinst_HEADERS += \ pimd/mtracebis_routeget.h \ # end -pimd_pimd_LDADD = pimd/libpim.a lib/libfrr.la @LIBCAP@ +pimd/pim_cmd_clippy.c: $(CLIPPY_DEPS) +pimd/pim_cmd.$(OBJEXT): pimd/pim_cmd_clippy.c + +pimd_pimd_LDADD = pimd/libpim.a lib/libfrr.la $(LIBCAP) pimd_pimd_SOURCES = pimd/pim_main.c pimd_test_igmpv3_join_LDADD = lib/libfrr.la diff --git a/python/clidef.py b/python/clidef.py index a140ce3d5..f8d96115b 100644 --- a/python/clidef.py +++ b/python/clidef.py @@ -41,7 +41,7 @@ class RenderHandler(object): class StringHandler(RenderHandler): argtype = 'const char *' decl = Template('const char *$varname = NULL;') - code = Template('$varname = argv[_i]->arg;') + code = Template('$varname = (argv[_i]->type == WORD_TKN) ? argv[_i]->text : argv[_i]->arg;') drop_str = True canfail = False diff --git a/redhat/frr.service b/redhat/frr.service index 3ae0aabfe..01934a94e 100644 --- a/redhat/frr.service +++ b/redhat/frr.service @@ -1,6 +1,8 @@ [Unit] Description=FRRouting (FRR) -After=syslog.target networking.service +Wants=network.target +After=network-pre.target systemd-sysctl.service +Before=network.target OnFailure=heartbeat-failed@%n.service [Service] @@ -19,5 +21,4 @@ ExecStop=/usr/lib/frr/frr stop ExecReload=/usr/lib/frr/frr reload [Install] -WantedBy=network-online.target - +WantedBy=multi-user.target diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 7a6344aa4..78b1f7c87 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -162,7 +162,7 @@ BuildRequires: make BuildRequires: ncurses-devel BuildRequires: readline-devel BuildRequires: texinfo -BuildRequires: libyang >= 0.16.7 +BuildRequires: libyang-devel >= 0.16.74 %if 0%{?rhel} && 0%{?rhel} < 7 #python27-devel is available from ius community repo for RedHat/CentOS 6 BuildRequires: python27-devel @@ -171,6 +171,7 @@ BuildRequires: python27-sphinx BuildRequires: python-devel >= 2.7 BuildRequires: python-sphinx %endif +Requires: initscripts %if %{with_pam} BuildRequires: pam-devel %endif @@ -188,7 +189,6 @@ Requires(post): chkconfig Requires(preun): chkconfig # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 -Requires: initscripts %endif Provides: routingdaemon = %{version}-%{release} Obsoletes: gated mrt zebra frr-sysvinit @@ -624,7 +624,6 @@ fi %{_libdir}/frr/modules/bgpd_rpki.so %endif %{_libdir}/frr/modules/zebra_irdp.so -%{_libdir}/frr/libyang_plugins/frr_user_types.so %{_bindir}/* %config(noreplace) %{configdir}/[!v]*.conf* %config(noreplace) %attr(750,%{frr_user},%{frr_user}) %{configdir}/daemons diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c index 149b30b5d..6b94258ea 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -78,7 +78,7 @@ DEFPY (no_router_rip, snprintf(xpath, sizeof(xpath), "/frr-ripd:ripd/instance[vrf='%s']", vrf); - nb_cli_enqueue_change(vty, xpath, NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -235,9 +235,9 @@ DEFPY (rip_distance_source, nb_cli_enqueue_change(vty, "./distance", NB_OP_MODIFY, distance_str); nb_cli_enqueue_change(vty, "./access-list", - acl ? NB_OP_MODIFY : NB_OP_DELETE, acl); + acl ? NB_OP_MODIFY : NB_OP_DESTROY, acl); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./distance/source[prefix='%s']", prefix_str); @@ -266,7 +266,7 @@ DEFPY (rip_neighbor, "Neighbor address\n") { nb_cli_enqueue_change(vty, "./explicit-neighbor", - no ? NB_OP_DELETE : NB_OP_CREATE, neighbor_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, neighbor_str); return nb_cli_apply_changes(vty, NULL); } @@ -288,7 +288,7 @@ DEFPY (rip_network_prefix, "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") { nb_cli_enqueue_change(vty, "./network", - no ? NB_OP_DELETE : NB_OP_CREATE, network_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, network_str); return nb_cli_apply_changes(vty, NULL); } @@ -310,7 +310,7 @@ DEFPY (rip_network_if, "Interface name\n") { nb_cli_enqueue_change(vty, "./interface", - no ? NB_OP_DELETE : NB_OP_CREATE, network); + no ? NB_OP_DESTROY : NB_OP_CREATE, network); return nb_cli_apply_changes(vty, NULL); } @@ -341,7 +341,7 @@ DEFPY (rip_offset_list, nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY, metric_str); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes( vty, "./offset-list[interface='%s'][direction='%s']", @@ -401,9 +401,9 @@ DEFPY (rip_passive_interface, "Interface name\n") { nb_cli_enqueue_change(vty, "./passive-interface", - no ? NB_OP_DELETE : NB_OP_CREATE, ifname); + no ? NB_OP_DESTROY : NB_OP_CREATE, ifname); nb_cli_enqueue_change(vty, "./non-passive-interface", - no ? NB_OP_CREATE : NB_OP_DELETE, ifname); + no ? NB_OP_CREATE : NB_OP_DESTROY, ifname); return nb_cli_apply_changes(vty, NULL); } @@ -439,13 +439,13 @@ DEFPY (rip_redistribute, if (!no) { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./route-map", - route_map ? NB_OP_MODIFY : NB_OP_DELETE, + route_map ? NB_OP_MODIFY : NB_OP_DESTROY, route_map); nb_cli_enqueue_change(vty, "./metric", - metric_str ? NB_OP_MODIFY : NB_OP_DELETE, + metric_str ? NB_OP_MODIFY : NB_OP_DESTROY, metric_str); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./redistribute[protocol='%s']", protocol); @@ -476,7 +476,7 @@ DEFPY (rip_route, "IP prefix <network>/<length>\n") { nb_cli_enqueue_change(vty, "./static-route", - no ? NB_OP_DELETE : NB_OP_CREATE, route_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, route_str); return nb_cli_apply_changes(vty, NULL); } @@ -915,7 +915,7 @@ DEFPY (no_ip_rip_authentication_string, "Authentication string\n" "Authentication string\n") { - nb_cli_enqueue_change(vty, "./authentication-password", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "./authentication-password", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./frr-ripd:rip"); @@ -964,7 +964,7 @@ DEFPY (no_ip_rip_authentication_key_chain, "Authentication key-chain\n" "name of key-chain\n") { - nb_cli_enqueue_change(vty, "./authentication-key-chain", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "./authentication-key-chain", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./frr-ripd:rip"); diff --git a/ripd/rip_main.c b/ripd/rip_main.c index 8b6e3a620..65da51f83 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -34,6 +34,7 @@ #include "sigevent.h" #include "zclient.h" #include "vrf.h" +#include "if_rmap.h" #include "libfrr.h" #include "ripd/ripd.h" @@ -82,6 +83,7 @@ static void sigint(void) zlog_notice("Terminating on signal"); rip_vrf_terminate(); + if_rmap_terminate(); rip_zclient_stop(); frr_fini(); diff --git a/ripd/rip_northbound.c b/ripd/rip_northbound.c index 13520d11d..2c53824ea 100644 --- a/ripd/rip_northbound.c +++ b/ripd/rip_northbound.c @@ -1486,7 +1486,7 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance", .cbs.create = ripd_instance_create, - .cbs.delete = ripd_instance_delete, + .cbs.destroy = ripd_instance_delete, .cbs.get_next = ripd_instance_get_next, .cbs.get_keys = ripd_instance_get_keys, .cbs.lookup_entry = ripd_instance_lookup_entry, @@ -1515,7 +1515,7 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/distance/source", .cbs.create = ripd_instance_distance_source_create, - .cbs.delete = ripd_instance_distance_source_delete, + .cbs.destroy = ripd_instance_distance_source_delete, .cbs.cli_show = cli_show_rip_distance_source, }, { @@ -1525,30 +1525,30 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/distance/source/access-list", .cbs.modify = ripd_instance_distance_source_access_list_modify, - .cbs.delete = ripd_instance_distance_source_access_list_delete, + .cbs.destroy = ripd_instance_distance_source_access_list_delete, }, { .xpath = "/frr-ripd:ripd/instance/explicit-neighbor", .cbs.create = ripd_instance_explicit_neighbor_create, - .cbs.delete = ripd_instance_explicit_neighbor_delete, + .cbs.destroy = ripd_instance_explicit_neighbor_delete, .cbs.cli_show = cli_show_rip_neighbor, }, { .xpath = "/frr-ripd:ripd/instance/network", .cbs.create = ripd_instance_network_create, - .cbs.delete = ripd_instance_network_delete, + .cbs.destroy = ripd_instance_network_delete, .cbs.cli_show = cli_show_rip_network_prefix, }, { .xpath = "/frr-ripd:ripd/instance/interface", .cbs.create = ripd_instance_interface_create, - .cbs.delete = ripd_instance_interface_delete, + .cbs.destroy = ripd_instance_interface_delete, .cbs.cli_show = cli_show_rip_network_interface, }, { .xpath = "/frr-ripd:ripd/instance/offset-list", .cbs.create = ripd_instance_offset_list_create, - .cbs.delete = ripd_instance_offset_list_delete, + .cbs.destroy = ripd_instance_offset_list_delete, .cbs.cli_show = cli_show_rip_offset_list, }, { @@ -1567,36 +1567,36 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/passive-interface", .cbs.create = ripd_instance_passive_interface_create, - .cbs.delete = ripd_instance_passive_interface_delete, + .cbs.destroy = ripd_instance_passive_interface_delete, .cbs.cli_show = cli_show_rip_passive_interface, }, { .xpath = "/frr-ripd:ripd/instance/non-passive-interface", .cbs.create = ripd_instance_non_passive_interface_create, - .cbs.delete = ripd_instance_non_passive_interface_delete, + .cbs.destroy = ripd_instance_non_passive_interface_delete, .cbs.cli_show = cli_show_rip_non_passive_interface, }, { .xpath = "/frr-ripd:ripd/instance/redistribute", .cbs.create = ripd_instance_redistribute_create, - .cbs.delete = ripd_instance_redistribute_delete, + .cbs.destroy = ripd_instance_redistribute_delete, .cbs.apply_finish = ripd_instance_redistribute_apply_finish, .cbs.cli_show = cli_show_rip_redistribute, }, { .xpath = "/frr-ripd:ripd/instance/redistribute/route-map", .cbs.modify = ripd_instance_redistribute_route_map_modify, - .cbs.delete = ripd_instance_redistribute_route_map_delete, + .cbs.destroy = ripd_instance_redistribute_route_map_delete, }, { .xpath = "/frr-ripd:ripd/instance/redistribute/metric", .cbs.modify = ripd_instance_redistribute_metric_modify, - .cbs.delete = ripd_instance_redistribute_metric_delete, + .cbs.destroy = ripd_instance_redistribute_metric_delete, }, { .xpath = "/frr-ripd:ripd/instance/static-route", .cbs.create = ripd_instance_static_route_create, - .cbs.delete = ripd_instance_static_route_delete, + .cbs.destroy = ripd_instance_static_route_delete, .cbs.cli_show = cli_show_rip_route, }, { @@ -1659,18 +1659,18 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/md5-auth-length", .cbs.modify = lib_interface_rip_authentication_scheme_md5_auth_length_modify, - .cbs.delete = lib_interface_rip_authentication_scheme_md5_auth_length_delete, + .cbs.destroy = lib_interface_rip_authentication_scheme_md5_auth_length_delete, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-password", .cbs.modify = lib_interface_rip_authentication_password_modify, - .cbs.delete = lib_interface_rip_authentication_password_delete, + .cbs.destroy = lib_interface_rip_authentication_password_delete, .cbs.cli_show = cli_show_ip_rip_authentication_string, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain", .cbs.modify = lib_interface_rip_authentication_key_chain_modify, - .cbs.delete = lib_interface_rip_authentication_key_chain_delete, + .cbs.destroy = lib_interface_rip_authentication_key_chain_delete, .cbs.cli_show = cli_show_ip_rip_authentication_key_chain, }, { diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index b34f944c9..3216b8f89 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -518,7 +518,7 @@ static struct route_map_rule_cmd route_set_tag_cmd = { #define SET_STR "Set values in destination routing protocol\n" /* Route-map init */ -void rip_route_map_init() +void rip_route_map_init(void) { route_map_init(); diff --git a/ripd/ripd.c b/ripd/ripd.c index 7fe8fc8c8..9683e26b5 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -64,6 +64,9 @@ static void rip_instance_disable(struct rip *rip); static void rip_distribute_update(struct distribute_ctx *ctx, struct distribute *dist); +static void rip_if_rmap_update(struct if_rmap_ctx *ctx, + struct if_rmap *if_rmap); + /* RIP output routes type. */ enum { rip_all_route, rip_changed_route }; @@ -864,7 +867,7 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, MD5_CTX ctx; uint8_t digest[RIP_AUTH_MD5_SIZE]; uint16_t packet_len; - char auth_str[RIP_AUTH_MD5_SIZE]; + char auth_str[RIP_AUTH_MD5_SIZE] = {}; if (IS_RIP_DEBUG_EVENT) zlog_debug("RIPv2 MD5 authentication from %s", @@ -908,8 +911,6 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, /* retrieve authentication data */ md5data = (struct rip_md5_data *)(((uint8_t *)packet) + packet_len); - memset(auth_str, 0, RIP_AUTH_MD5_SIZE); - if (ri->key_chain) { keychain = keychain_lookup(ri->key_chain); if (keychain == NULL) @@ -919,9 +920,9 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, if (key == NULL || key->string == NULL) return 0; - strncpy(auth_str, key->string, RIP_AUTH_MD5_SIZE); + strlcpy(auth_str, key->string, sizeof(auth_str)); } else if (ri->auth_str) - strncpy(auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE); + strlcpy(auth_str, ri->auth_str, sizeof(auth_str)); if (auth_str[0] == 0) return 0; @@ -954,9 +955,9 @@ static void rip_auth_prepare_str_send(struct rip_interface *ri, struct key *key, memset(auth_str, 0, len); if (key && key->string) - strncpy(auth_str, key->string, len); + strlcpy(auth_str, key->string, len); else if (ri->auth_str) - strncpy(auth_str, ri->auth_str, len); + strlcpy(auth_str, ri->auth_str, len); return; } @@ -1420,13 +1421,12 @@ static int rip_send_packet(uint8_t *buf, int size, struct sockaddr_in *to, if (IS_RIP_DEBUG_PACKET) { #define ADDRESS_SIZE 20 char dst[ADDRESS_SIZE]; - dst[ADDRESS_SIZE - 1] = '\0'; if (to) { - strncpy(dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1); + strlcpy(dst, inet_ntoa(to->sin_addr), sizeof(dst)); } else { sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP); - strncpy(dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1); + strlcpy(dst, inet_ntoa(sin.sin_addr), sizeof(dst)); } #undef ADDRESS_SIZE zlog_debug("rip_send_packet %s > %s (%s)", @@ -2086,8 +2086,7 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to, key = key_lookup_for_send(keychain); } /* to be passed to auth functions later */ - rip_auth_prepare_str_send(ri, key, auth_str, - RIP_AUTH_SIMPLE_SIZE); + rip_auth_prepare_str_send(ri, key, auth_str, sizeof(auth_str)); if (strlen(auth_str) == 0) return; } @@ -2720,6 +2719,11 @@ struct rip *rip_create(const char *vrf_name, struct vrf *vrf, int socket) distribute_list_add_hook(rip->distribute_ctx, rip_distribute_update); distribute_list_delete_hook(rip->distribute_ctx, rip_distribute_update); + /* if rmap install. */ + rip->if_rmap_ctx = if_rmap_ctx_create(vrf_name); + if_rmap_hook_add(rip->if_rmap_ctx, rip_if_rmap_update); + if_rmap_hook_delete(rip->if_rmap_ctx, rip_if_rmap_update); + /* Make output stream. */ rip->obuf = stream_new(1500); @@ -3272,8 +3276,7 @@ static int config_write_rip(struct vty *vty) config_write_distribute(vty, rip->distribute_ctx); /* Interface routemap configuration */ - if (strmatch(rip->vrf_name, VRF_DEFAULT_NAME)) - config_write_if_rmap(vty); + config_write_if_rmap(vty, rip->if_rmap_ctx); write = 1; } @@ -3388,6 +3391,7 @@ void rip_clean(struct rip *rip) route_table_finish(rip->neighbor); list_delete(&rip->peer_list); distribute_list_delete(&rip->distribute_ctx); + if_rmap_ctx_delete(rip->if_rmap_ctx); rip_clean_network(rip); rip_passive_nondefault_clean(rip); @@ -3403,13 +3407,18 @@ void rip_clean(struct rip *rip) XFREE(MTYPE_RIP, rip); } -static void rip_if_rmap_update(struct if_rmap *if_rmap) +static void rip_if_rmap_update(struct if_rmap_ctx *ctx, + struct if_rmap *if_rmap) { - struct interface *ifp; + struct interface *ifp = NULL; struct rip_interface *ri; struct route_map *rmap; + struct vrf *vrf = NULL; - ifp = if_lookup_by_name(if_rmap->ifname, VRF_DEFAULT); + if (ctx->name) + vrf = vrf_lookup_by_name(ctx->name); + if (vrf) + ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id); if (ifp == NULL) return; @@ -3435,19 +3444,30 @@ static void rip_if_rmap_update(struct if_rmap *if_rmap) void rip_if_rmap_update_interface(struct interface *ifp) { + struct rip_interface *ri = ifp->info; + struct rip *rip = ri->rip; struct if_rmap *if_rmap; + struct if_rmap_ctx *ctx; - if_rmap = if_rmap_lookup(ifp->name); + if (!rip) + return; + ctx = rip->if_rmap_ctx; + if (!ctx) + return; + if_rmap = if_rmap_lookup(ctx, ifp->name); if (if_rmap) - rip_if_rmap_update(if_rmap); + rip_if_rmap_update(ctx, if_rmap); } static void rip_routemap_update_redistribute(struct rip *rip) { for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (rip->redist[i].route_map.name) + if (rip->redist[i].route_map.name) { rip->redist[i].route_map.map = route_map_lookup_by_name( rip->redist[i].route_map.name); + route_map_counter_increment( + rip->redist[i].route_map.map); + } } } @@ -3669,6 +3689,4 @@ void rip_init(void) route_map_delete_hook(rip_routemap_update); if_rmap_init(RIP_NODE); - if_rmap_hook_add(rip_if_rmap_update); - if_rmap_hook_delete(rip_if_rmap_update); } diff --git a/ripd/ripd.h b/ripd/ripd.h index f78dae7a8..7b196a16b 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -184,6 +184,9 @@ struct rip { /* For distribute-list container */ struct distribute_ctx *distribute_ctx; + /* For if_rmap container */ + struct if_rmap_ctx *if_rmap_ctx; + /* Counters for SNMP. */ struct { /* RIP route changes. */ @@ -469,7 +472,7 @@ extern void rip_zebra_ipv4_add(struct rip *rip, struct route_node *rp); extern void rip_zebra_ipv4_delete(struct rip *rip, struct route_node *rp); extern void rip_interface_multicast_set(int, struct connected *); extern void rip_distribute_update_interface(struct interface *); -extern void rip_if_rmap_update_interface(struct interface *); +extern void rip_if_rmap_update_interface(struct interface *ifp); extern int rip_show_network_config(struct vty *vty, struct rip *rip); extern void rip_show_redistribute_config(struct vty *vty, struct rip *rip); diff --git a/ripd/subdir.am b/ripd/subdir.am index 1c2f8d64c..2a63cc522 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -44,7 +44,7 @@ noinst_HEADERS += \ ripd/ripd.h \ # end -ripd_ripd_LDADD = ripd/librip.a lib/libfrr.la @LIBCAP@ +ripd_ripd_LDADD = ripd/librip.a lib/libfrr.la $(LIBCAP) ripd_ripd_SOURCES = \ ripd/rip_main.c \ # end diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c index 804fa8dea..e95c0e95d 100644 --- a/ripngd/ripng_cli.c +++ b/ripngd/ripng_cli.c @@ -78,7 +78,7 @@ DEFPY (no_router_ripng, snprintf(xpath, sizeof(xpath), "/frr-ripngd:ripngd/instance[vrf='%s']", vrf); - nb_cli_enqueue_change(vty, xpath, NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -192,7 +192,7 @@ DEFPY (ripng_network_prefix, "IPv6 network\n") { nb_cli_enqueue_change(vty, "./network", - no ? NB_OP_DELETE : NB_OP_CREATE, network_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, network_str); return nb_cli_apply_changes(vty, NULL); } @@ -214,7 +214,7 @@ DEFPY (ripng_network_if, "Interface name\n") { nb_cli_enqueue_change(vty, "./interface", - no ? NB_OP_DELETE : NB_OP_CREATE, network); + no ? NB_OP_DESTROY : NB_OP_CREATE, network); return nb_cli_apply_changes(vty, NULL); } @@ -245,7 +245,7 @@ DEFPY (ripng_offset_list, nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY, metric_str); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes( vty, "./offset-list[interface='%s'][direction='%s']", @@ -279,7 +279,7 @@ DEFPY (ripng_passive_interface, "Interface name\n") { nb_cli_enqueue_change(vty, "./passive-interface", - no ? NB_OP_DELETE : NB_OP_CREATE, ifname); + no ? NB_OP_DESTROY : NB_OP_CREATE, ifname); return nb_cli_apply_changes(vty, NULL); } @@ -308,13 +308,13 @@ DEFPY (ripng_redistribute, if (!no) { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./route-map", - route_map ? NB_OP_MODIFY : NB_OP_DELETE, + route_map ? NB_OP_MODIFY : NB_OP_DESTROY, route_map); nb_cli_enqueue_change(vty, "./metric", - metric_str ? NB_OP_MODIFY : NB_OP_DELETE, + metric_str ? NB_OP_MODIFY : NB_OP_DESTROY, metric_str); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./redistribute[protocol='%s']", protocol); @@ -345,7 +345,7 @@ DEFPY (ripng_route, "Set static RIPng route announcement\n") { nb_cli_enqueue_change(vty, "./static-route", - no ? NB_OP_DELETE : NB_OP_CREATE, route_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, route_str); return nb_cli_apply_changes(vty, NULL); } @@ -367,7 +367,7 @@ DEFPY (ripng_aggregate_address, "Aggregate network\n") { nb_cli_enqueue_change(vty, "./aggregate-address", - no ? NB_OP_DELETE : NB_OP_CREATE, + no ? NB_OP_DESTROY : NB_OP_CREATE, aggregate_address_str); return nb_cli_apply_changes(vty, NULL); diff --git a/ripngd/ripng_debug.c b/ripngd/ripng_debug.c index c56ff1262..fe63d8fde 100644 --- a/ripngd/ripng_debug.c +++ b/ripngd/ripng_debug.c @@ -207,7 +207,7 @@ static int config_write_debug(struct vty *vty) return write; } -void ripng_debug_init() +void ripng_debug_init(void) { ripng_debug_event = 0; ripng_debug_packet = 0; diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index edc258c05..43fa66320 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -994,7 +994,7 @@ static struct cmd_node interface_node = { }; /* Initialization of interface. */ -void ripng_if_init() +void ripng_if_init(void) { /* Interface initialize. */ hook_register_prio(if_add, 0, ripng_if_new_hook); diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 37b163c5e..c755bd83c 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -35,6 +35,7 @@ #include "privs.h" #include "sigevent.h" #include "vrf.h" +#include "if_rmap.h" #include "libfrr.h" #include "ripngd/ripngd.h" @@ -83,6 +84,7 @@ static void sigint(void) zlog_notice("Terminating on signal"); ripng_vrf_terminate(); + if_rmap_terminate(); ripng_zebra_stop(); frr_fini(); exit(0); diff --git a/ripngd/ripng_northbound.c b/ripngd/ripng_northbound.c index dda57a31f..66b9e13d7 100644 --- a/ripngd/ripng_northbound.c +++ b/ripngd/ripng_northbound.c @@ -1013,7 +1013,7 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance", .cbs.create = ripngd_instance_create, - .cbs.delete = ripngd_instance_delete, + .cbs.destroy = ripngd_instance_delete, .cbs.get_next = ripngd_instance_get_next, .cbs.get_keys = ripngd_instance_get_keys, .cbs.lookup_entry = ripngd_instance_lookup_entry, @@ -1037,19 +1037,19 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/network", .cbs.create = ripngd_instance_network_create, - .cbs.delete = ripngd_instance_network_delete, + .cbs.destroy = ripngd_instance_network_delete, .cbs.cli_show = cli_show_ripng_network_prefix, }, { .xpath = "/frr-ripngd:ripngd/instance/interface", .cbs.create = ripngd_instance_interface_create, - .cbs.delete = ripngd_instance_interface_delete, + .cbs.destroy = ripngd_instance_interface_delete, .cbs.cli_show = cli_show_ripng_network_interface, }, { .xpath = "/frr-ripngd:ripngd/instance/offset-list", .cbs.create = ripngd_instance_offset_list_create, - .cbs.delete = ripngd_instance_offset_list_delete, + .cbs.destroy = ripngd_instance_offset_list_delete, .cbs.cli_show = cli_show_ripng_offset_list, }, { @@ -1063,36 +1063,36 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/passive-interface", .cbs.create = ripngd_instance_passive_interface_create, - .cbs.delete = ripngd_instance_passive_interface_delete, + .cbs.destroy = ripngd_instance_passive_interface_delete, .cbs.cli_show = cli_show_ripng_passive_interface, }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute", .cbs.create = ripngd_instance_redistribute_create, - .cbs.delete = ripngd_instance_redistribute_delete, + .cbs.destroy = ripngd_instance_redistribute_delete, .cbs.apply_finish = ripngd_instance_redistribute_apply_finish, .cbs.cli_show = cli_show_ripng_redistribute, }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute/route-map", .cbs.modify = ripngd_instance_redistribute_route_map_modify, - .cbs.delete = ripngd_instance_redistribute_route_map_delete, + .cbs.destroy = ripngd_instance_redistribute_route_map_delete, }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute/metric", .cbs.modify = ripngd_instance_redistribute_metric_modify, - .cbs.delete = ripngd_instance_redistribute_metric_delete, + .cbs.destroy = ripngd_instance_redistribute_metric_delete, }, { .xpath = "/frr-ripngd:ripngd/instance/static-route", .cbs.create = ripngd_instance_static_route_create, - .cbs.delete = ripngd_instance_static_route_delete, + .cbs.destroy = ripngd_instance_static_route_delete, .cbs.cli_show = cli_show_ripng_route, }, { .xpath = "/frr-ripngd:ripngd/instance/aggregate-address", .cbs.create = ripngd_instance_aggregate_address_create, - .cbs.delete = ripngd_instance_aggregate_address_delete, + .cbs.destroy = ripngd_instance_aggregate_address_delete, .cbs.cli_show = cli_show_ripng_aggregate_address, }, { diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c index 9a9e346a5..0604e272c 100644 --- a/ripngd/ripng_routemap.c +++ b/ripngd/ripng_routemap.c @@ -337,7 +337,7 @@ static struct route_map_rule_cmd route_set_tag_cmd = { #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" -void ripng_route_map_init() +void ripng_route_map_init(void) { route_map_init(); diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index c3aa9d8db..b36cee2c5 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -55,8 +55,9 @@ void ripng_output_process(struct interface *, struct sockaddr_in6 *, int); static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf, int sock); static void ripng_instance_disable(struct ripng *ripng); - int ripng_triggered_update(struct thread *); +static void ripng_if_rmap_update(struct if_rmap_ctx *ctx, + struct if_rmap *if_rmap); /* Generate rb-tree of RIPng instances. */ static inline int ripng_instance_compare(const struct ripng *a, @@ -84,7 +85,7 @@ int ripng_route_rte(struct ripng_info *rinfo) } /* Allocate new ripng information. */ -struct ripng_info *ripng_info_new() +struct ripng_info *ripng_info_new(void) { struct ripng_info *new; @@ -1895,6 +1896,10 @@ struct ripng *ripng_create(const char *vrf_name, struct vrf *vrf, int socket) distribute_list_delete_hook(ripng->distribute_ctx, ripng_distribute_update); + /* if rmap install. */ + ripng->if_rmap_ctx = if_rmap_ctx_create(vrf_name); + if_rmap_hook_add(ripng->if_rmap_ctx, ripng_if_rmap_update); + if_rmap_hook_delete(ripng->if_rmap_ctx, ripng_if_rmap_update); /* Enable the routing instance if possible. */ if (vrf && vrf_is_enabled(vrf)) @@ -2425,8 +2430,7 @@ static int ripng_config_write(struct vty *vty) nb_cli_show_dnode_cmds(vty, dnode, false); config_write_distribute(vty, ripng->distribute_ctx); - if (strmatch(ripng->vrf_name, VRF_DEFAULT_NAME)) - config_write_if_rmap(vty); + config_write_if_rmap(vty, ripng->if_rmap_ctx); write = 1; } @@ -2538,6 +2542,7 @@ void ripng_clean(struct ripng *ripng) agg_table_finish(ripng->table); list_delete(&ripng->peer_list); distribute_list_delete(&ripng->distribute_ctx); + if_rmap_ctx_delete(ripng->if_rmap_ctx); stream_free(ripng->ibuf); stream_free(ripng->obuf); @@ -2555,13 +2560,18 @@ void ripng_clean(struct ripng *ripng) XFREE(MTYPE_RIPNG, ripng); } -static void ripng_if_rmap_update(struct if_rmap *if_rmap) +static void ripng_if_rmap_update(struct if_rmap_ctx *ctx, + struct if_rmap *if_rmap) { - struct interface *ifp; + struct interface *ifp = NULL; struct ripng_interface *ri; struct route_map *rmap; + struct vrf *vrf = NULL; - ifp = if_lookup_by_name(if_rmap->ifname, VRF_DEFAULT); + if (ctx->name) + vrf = vrf_lookup_by_name(ctx->name); + if (vrf) + ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id); if (ifp == NULL) return; @@ -2588,20 +2598,31 @@ static void ripng_if_rmap_update(struct if_rmap *if_rmap) void ripng_if_rmap_update_interface(struct interface *ifp) { + struct ripng_interface *ri = ifp->info; + struct ripng *ripng = ri->ripng; struct if_rmap *if_rmap; + struct if_rmap_ctx *ctx; - if_rmap = if_rmap_lookup(ifp->name); + if (!ripng) + return; + ctx = ripng->if_rmap_ctx; + if (!ctx) + return; + if_rmap = if_rmap_lookup(ctx, ifp->name); if (if_rmap) - ripng_if_rmap_update(if_rmap); + ripng_if_rmap_update(ctx, if_rmap); } static void ripng_routemap_update_redistribute(struct ripng *ripng) { for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (ripng->redist[i].route_map.name) + if (ripng->redist[i].route_map.name) { ripng->redist[i].route_map.map = route_map_lookup_by_name( ripng->redist[i].route_map.name); + route_map_counter_increment( + ripng->redist[i].route_map.map); + } } } @@ -2801,7 +2822,7 @@ void ripng_vrf_terminate(void) } /* Initialize ripng structure and set commands. */ -void ripng_init() +void ripng_init(void) { /* Install RIPNG_NODE. */ install_node(&cmd_ripng_node, ripng_config_write); @@ -2845,6 +2866,4 @@ void ripng_init() route_map_delete_hook(ripng_routemap_update); if_rmap_init(RIPNG_NODE); - if_rmap_hook_add(ripng_if_rmap_update); - if_rmap_hook_delete(ripng_if_rmap_update); } diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index b38e6b3a9..dcc61ae58 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -162,6 +162,9 @@ struct ripng { /* For distribute-list container */ struct distribute_ctx *distribute_ctx; + + /* For if_rmap container */ + struct if_rmap_ctx *if_rmap_ctx; }; RB_HEAD(ripng_instance_head, ripng); RB_PROTOTYPE(ripng_instance_head, ripng, entry, ripng_instance_compare) diff --git a/ripngd/subdir.am b/ripngd/subdir.am index d401e9bbf..ea0ccf148 100644 --- a/ripngd/subdir.am +++ b/ripngd/subdir.am @@ -40,7 +40,7 @@ noinst_HEADERS += \ ripngd/ripngd.h \ # end -ripngd_ripngd_LDADD = ripngd/libripng.a lib/libfrr.la @LIBCAP@ +ripngd_ripngd_LDADD = ripngd/libripng.a lib/libfrr.la $(LIBCAP) ripngd_ripngd_SOURCES = \ ripngd/ripng_main.c \ # end diff --git a/sharpd/Makefile b/sharpd/Makefile new file mode 100644 index 000000000..6a904d1a6 --- /dev/null +++ b/sharpd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. sharpd/sharpd +%: ALWAYS + @$(MAKE) -s -C .. sharpd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h new file mode 100644 index 000000000..065fb092d --- /dev/null +++ b/sharpd/sharp_globals.h @@ -0,0 +1,55 @@ +/* + * SHARP - code to track globals + * Copyright (C) 2019 Cumulus Networks, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __SHARP_GLOBAL_H__ +#define __SHARP_GLOBAL_H__ + +DECLARE_MGROUP(SHARPD) + +struct sharp_routes { + /* The original prefix for route installation */ + struct prefix orig_prefix; + + /* The nexthop group we are using for installation */ + struct nexthop nhop; + struct nexthop_group nhop_group; + + uint32_t total_routes; + uint32_t installed_routes; + uint32_t removed_routes; + int32_t repeat; + + uint8_t inst; + + struct timeval t_start; + struct timeval t_end; +}; + +struct sharp_global { + /* Global data about route install/deletions */ + struct sharp_routes r; + + /* The list of nexthops that we are watching and data about them */ + struct list *nhs; +}; + +extern struct sharp_global sg; +#endif diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index 175a27608..39453ee9a 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -46,10 +46,9 @@ #include "sharp_zebra.h" #include "sharp_vty.h" +#include "sharp_globals.h" -uint32_t total_routes = 0; -uint32_t installed_routes = 0; -uint32_t removed_routes = 0; +DEFINE_MGROUP(SHARPD, "sharpd") zebra_capabilities_t _caps_p[] = { }; @@ -125,7 +124,13 @@ FRR_DAEMON_INFO(sharpd, SHARP, .vty_port = SHARP_VTY_PORT, .privs = &sharp_privs, .yang_modules = sharpd_yang_modules, .n_yang_modules = array_size(sharpd_yang_modules), ) -extern void sharp_vty_init(void); +struct sharp_global sg; + +static void sharp_global_init(void) +{ + memset(&sg, 0, sizeof(sg)); + sg.nhs = list_new(); +} int main(int argc, char **argv, char **envp) { @@ -151,6 +156,8 @@ int main(int argc, char **argv, char **envp) master = frr_init(); + sharp_global_init(); + nexthop_group_init(NULL, NULL, NULL, NULL); vrf_init(NULL, NULL, NULL, NULL, NULL); diff --git a/sharpd/sharp_nht.c b/sharpd/sharp_nht.c new file mode 100644 index 000000000..174f18686 --- /dev/null +++ b/sharpd/sharp_nht.c @@ -0,0 +1,67 @@ +/* + * SHARP - code to track nexthops + * Copyright (C) Cumulus Networks, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <zebra.h> + +#include "memory.h" +#include "nexthop.h" +#include "nexthop_group.h" +#include "vty.h" + +#include "sharp_nht.h" +#include "sharp_globals.h" + +DEFINE_MTYPE_STATIC(SHARPD, NH_TRACKER, "Nexthop Tracker") + +struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p) +{ + struct listnode *node; + struct sharp_nh_tracker *nht; + + for (ALL_LIST_ELEMENTS_RO(sg.nhs, node, nht)) { + if (prefix_same(&nht->p, p)) + break; + } + + if (nht) + return nht; + + nht = XCALLOC(MTYPE_NH_TRACKER, sizeof(*nht)); + prefix_copy(&nht->p, p); + + listnode_add(sg.nhs, nht); + return nht; +} + +void sharp_nh_tracker_dump(struct vty *vty) +{ + struct listnode *node; + struct sharp_nh_tracker *nht; + + for (ALL_LIST_ELEMENTS_RO(sg.nhs, node, nht)) { + char buf[PREFIX_STRLEN]; + + vty_out(vty, "%s: Nexthops: %u Updates: %u\n", + prefix2str(&nht->p, buf, sizeof(buf)), + nht->nhop_num, + nht->updates); + } +} diff --git a/sharpd/sharp_nht.h b/sharpd/sharp_nht.h new file mode 100644 index 000000000..0b00774a8 --- /dev/null +++ b/sharpd/sharp_nht.h @@ -0,0 +1,38 @@ +/* + * SHARP - code to track nexthops + * Copyright (C) Cumulus Networks, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __SHARP_NHT_H__ +#define __SHARP_NHT_H__ + +struct sharp_nh_tracker { + /* What are we watching */ + struct prefix p; + + /* Number of valid nexthops */ + uint32_t nhop_num; + + uint32_t updates; +}; + +extern struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p); + +extern void sharp_nh_tracker_dump(struct vty *vty); +#endif diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 86c8bfe1c..9018cfb35 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -30,32 +30,31 @@ #include "zclient.h" #include "nexthop_group.h" +#include "sharpd/sharp_globals.h" #include "sharpd/sharp_zebra.h" +#include "sharpd/sharp_nht.h" #include "sharpd/sharp_vty.h" #ifndef VTYSH_EXTRACT_PL #include "sharpd/sharp_vty_clippy.c" #endif -extern uint32_t total_routes; -extern uint32_t installed_routes; -extern uint32_t removed_routes; - -uint8_t inst; -struct prefix prefix; -struct prefix orig_prefix; -struct nexthop nhop; -struct nexthop_group nhop_group; -uint32_t rts; -int32_t repeat; - DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, - "sharp watch nexthop X:X::X:X$nhop", + "sharp watch <nexthop$n|import$import> X:X::X:X$nhop [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "Watch for nexthop changes\n" - "The v6 nexthop to signal for watching\n") + "Watch for import check changes\n" + "The v6 nexthop to signal for watching\n" + "Should the route be connected\n") { struct prefix p; + bool type_import; + + + if (n) + type_import = false; + else + type_import = true; memset(&p, 0, sizeof(p)); @@ -63,27 +62,70 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, memcpy(&p.u.prefix6, &nhop, 16); p.family = AF_INET6; - sharp_zebra_nexthop_watch(&p, true); + sharp_nh_tracker_get(&p); + sharp_zebra_nexthop_watch(&p, type_import, true, !!connected); return CMD_SUCCESS; } DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, - "sharp watch nexthop A.B.C.D$nhop", + "sharp watch <nexthop$n|import$import> A.B.C.D$nhop [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "Watch for nexthop changes\n" - "The v4 nexthop to signal for watching\n") + "Watch for import check changes\n" + "The v4 nexthop to signal for watching\n" + "Should the route be connected\n") { struct prefix p; + bool type_import; memset(&p, 0, sizeof(p)); + if (n) + type_import = false; + else + type_import = true; + p.prefixlen = 32; p.u.prefix4 = nhop; p.family = AF_INET; - sharp_zebra_nexthop_watch(&p, true); + sharp_nh_tracker_get(&p); + sharp_zebra_nexthop_watch(&p, type_import, true, !!connected); + + return CMD_SUCCESS; +} + +DEFPY(sharp_nht_data_dump, + sharp_nht_data_dump_cmd, + "sharp data nexthop", + "Sharp routing Protocol\n" + "Nexthop information\n" + "Data Dump\n") +{ + sharp_nh_tracker_dump(vty); + + return CMD_SUCCESS; +} + +DEFPY (install_routes_data_dump, + install_routes_data_dump_cmd, + "sharp data route", + "Sharp routing Protocol\n" + "Data about what is going on\n" + "Route Install/Removal Information\n") +{ + char buf[PREFIX_STRLEN]; + struct timeval r; + + timersub(&sg.r.t_end, &sg.r.t_start, &r); + vty_out(vty, "Prefix: %s Total: %u %u %u Time: %ld.%ld\n", + prefix2str(&sg.r.orig_prefix, buf, sizeof(buf)), + sg.r.total_routes, + sg.r.installed_routes, + sg.r.removed_routes, + r.tv_sec, r.tv_usec); return CMD_SUCCESS; } @@ -107,18 +149,21 @@ DEFPY (install_routes, "Should we repeat this command\n" "How many times to repeat this command\n") { - total_routes = routes; - installed_routes = 0; + struct prefix prefix; + uint32_t rts; + + sg.r.total_routes = routes; + sg.r.installed_routes = 0; if (rpt >= 2) - repeat = rpt * 2; + sg.r.repeat = rpt * 2; else - repeat = 0; + sg.r.repeat = 0; memset(&prefix, 0, sizeof(prefix)); - memset(&orig_prefix, 0, sizeof(orig_prefix)); - memset(&nhop, 0, sizeof(nhop)); - memset(&nhop_group, 0, sizeof(nhop_group)); + memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix)); + memset(&sg.r.nhop, 0, sizeof(sg.r.nhop)); + memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group)); if (start4.s_addr != 0) { prefix.family = AF_INET; @@ -129,7 +174,7 @@ DEFPY (install_routes, prefix.prefixlen = 128; prefix.u.prefix6 = start6; } - orig_prefix = prefix; + sg.r.orig_prefix = prefix; if (nexthop_group) { struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group); @@ -140,22 +185,22 @@ DEFPY (install_routes, return CMD_WARNING; } - nhop_group.nexthop = nhgc->nhg.nexthop; + sg.r.nhop_group.nexthop = nhgc->nhg.nexthop; } else { if (nexthop4.s_addr != INADDR_ANY) { - nhop.gate.ipv4 = nexthop4; - nhop.type = NEXTHOP_TYPE_IPV4; + sg.r.nhop.gate.ipv4 = nexthop4; + sg.r.nhop.type = NEXTHOP_TYPE_IPV4; } else { - nhop.gate.ipv6 = nexthop6; - nhop.type = NEXTHOP_TYPE_IPV6; + sg.r.nhop.gate.ipv6 = nexthop6; + sg.r.nhop.type = NEXTHOP_TYPE_IPV6; } - nhop_group.nexthop = &nhop; + sg.r.nhop_group.nexthop = &sg.r.nhop; } - inst = instance; + sg.r.inst = instance; rts = routes; - sharp_install_routes_helper(&prefix, inst, &nhop_group, rts); + sharp_install_routes_helper(&prefix, sg.r.inst, &sg.r.nhop_group, rts); return CMD_SUCCESS; } @@ -202,8 +247,11 @@ DEFPY (remove_routes, "instance to use\n" "Value of instance\n") { - total_routes = routes; - removed_routes = 0; + struct prefix prefix; + + sg.r.total_routes = routes; + sg.r.removed_routes = 0; + uint32_t rts; memset(&prefix, 0, sizeof(prefix)); @@ -217,9 +265,9 @@ DEFPY (remove_routes, prefix.u.prefix6 = start6; } - inst = instance; + sg.r.inst = instance; rts = routes; - sharp_remove_routes_helper(&prefix, inst, rts); + sharp_remove_routes_helper(&prefix, sg.r.inst, rts); return CMD_SUCCESS; } @@ -238,9 +286,11 @@ DEFUN_NOSH (show_debugging_sharpd, void sharp_vty_init(void) { + install_element(ENABLE_NODE, &install_routes_data_dump_cmd); install_element(ENABLE_NODE, &install_routes_cmd); install_element(ENABLE_NODE, &remove_routes_cmd); install_element(ENABLE_NODE, &vrf_label_cmd); + install_element(ENABLE_NODE, &sharp_nht_data_dump_cmd); install_element(ENABLE_NODE, &watch_nexthop_v6_cmd); install_element(ENABLE_NODE, &watch_nexthop_v4_cmd); diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index c9f333e34..4682dbc73 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -36,6 +36,8 @@ #include "nexthop.h" #include "nexthop_group.h" +#include "sharp_globals.h" +#include "sharp_nht.h" #include "sharp_zebra.h" /* Zebra structure to hold current status. */ @@ -129,16 +131,6 @@ static int interface_state_down(int command, struct zclient *zclient, return 0; } -static struct timeval t_start; -static struct timeval t_end; -extern uint32_t total_routes; -extern uint32_t installed_routes; -extern uint32_t removed_routes; -extern int32_t repeat; -extern struct prefix orig_prefix; -extern struct nexthop_group nhop_group; -extern uint8_t inst; - void sharp_install_routes_helper(struct prefix *p, uint8_t instance, struct nexthop_group *nhg, uint32_t routes) @@ -154,7 +146,7 @@ void sharp_install_routes_helper(struct prefix *p, uint8_t instance, } else temp = ntohl(p->u.val32[3]); - monotime(&t_start); + monotime(&sg.r.t_start); for (i = 0; i < routes; i++) { route_add(p, (uint8_t)instance, nhg); if (v4) @@ -178,7 +170,7 @@ void sharp_remove_routes_helper(struct prefix *p, uint8_t instance, } else temp = ntohl(p->u.val32[3]); - monotime(&t_start); + monotime(&sg.r.t_start); for (i = 0; i < routes; i++) { route_delete(p, (uint8_t)instance); if (v4) @@ -190,21 +182,21 @@ void sharp_remove_routes_helper(struct prefix *p, uint8_t instance, static void handle_repeated(bool installed) { - struct prefix p = orig_prefix; - repeat--; + struct prefix p = sg.r.orig_prefix; + sg.r.repeat--; - if (repeat <= 0) + if (sg.r.repeat <= 0) return; if (installed) { - removed_routes = 0; - sharp_remove_routes_helper(&p, inst, total_routes); + sg.r.removed_routes = 0; + sharp_remove_routes_helper(&p, sg.r.inst, sg.r.total_routes); } - if (!installed) { - installed_routes = 0; - sharp_install_routes_helper(&p, inst, &nhop_group, - total_routes); + if (installed) { + sg.r.installed_routes = 0; + sharp_install_routes_helper(&p, sg.r.inst, &sg.r.nhop_group, + sg.r.total_routes); } } @@ -221,10 +213,10 @@ static int route_notify_owner(int command, struct zclient *zclient, switch (note) { case ZAPI_ROUTE_INSTALLED: - installed_routes++; - if (total_routes == installed_routes) { - monotime(&t_end); - timersub(&t_end, &t_start, &r); + sg.r.installed_routes++; + if (sg.r.total_routes == sg.r.installed_routes) { + monotime(&sg.r.t_end); + timersub(&sg.r.t_end, &sg.r.t_start, &r); zlog_debug("Installed All Items %ld.%ld", r.tv_sec, r.tv_usec); handle_repeated(true); @@ -237,10 +229,10 @@ static int route_notify_owner(int command, struct zclient *zclient, zlog_debug("Better Admin Distance won over us"); break; case ZAPI_ROUTE_REMOVED: - removed_routes++; - if (total_routes == removed_routes) { - monotime(&t_end); - timersub(&t_end, &t_start, &r); + sg.r.removed_routes++; + if (sg.r.total_routes == sg.r.removed_routes) { + monotime(&sg.r.t_end); + timersub(&sg.r.t_end, &sg.r.t_start, &r); zlog_debug("Removed all Items %ld.%ld", r.tv_sec, r.tv_usec); handle_repeated(false); @@ -328,14 +320,24 @@ void route_delete(struct prefix *p, uint8_t instance) return; } -void sharp_zebra_nexthop_watch(struct prefix *p, bool watch) +void sharp_zebra_nexthop_watch(struct prefix *p, bool import, + bool watch, bool connected) { - int command = ZEBRA_NEXTHOP_REGISTER; + int command; - if (!watch) - command = ZEBRA_NEXTHOP_UNREGISTER; + if (!import) { + command = ZEBRA_NEXTHOP_REGISTER; - if (zclient_send_rnh(zclient, command, p, true, VRF_DEFAULT) < 0) + if (!watch) + command = ZEBRA_NEXTHOP_UNREGISTER; + } else { + command = ZEBRA_IMPORT_ROUTE_REGISTER; + + if (!watch) + command = ZEBRA_IMPORT_ROUTE_UNREGISTER; + } + + if (zclient_send_rnh(zclient, command, p, connected, VRF_DEFAULT) < 0) zlog_warn("%s: Failure to send nexthop to zebra", __PRETTY_FUNCTION__); } @@ -343,6 +345,7 @@ void sharp_zebra_nexthop_watch(struct prefix *p, bool watch) static int sharp_nexthop_update(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { + struct sharp_nh_tracker *nht; struct zapi_route nhr; char buf[PREFIX_STRLEN]; int i; @@ -355,6 +358,11 @@ static int sharp_nexthop_update(int command, struct zclient *zclient, zlog_debug("Received update for %s", prefix2str(&nhr.prefix, buf, sizeof(buf))); + + nht = sharp_nh_tracker_get(&nhr.prefix); + nht->nhop_num = nhr.nexthop_num; + nht->updates++; + for (i = 0; i < nhr.nexthop_num; i++) { struct zapi_nexthop *znh = &nhr.nexthops[i]; @@ -407,4 +415,5 @@ void sharp_zebra_init(void) zclient->interface_address_delete = interface_address_delete; zclient->route_notify_owner = route_notify_owner; zclient->nexthop_update = sharp_nexthop_update; + zclient->import_check_update = sharp_nexthop_update; } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 7326056ca..b219022f0 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -28,7 +28,8 @@ extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label); extern void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg); extern void route_delete(struct prefix *p, uint8_t instance); -extern void sharp_zebra_nexthop_watch(struct prefix *p, bool watch); +extern void sharp_zebra_nexthop_watch(struct prefix *p, bool import, + bool watch, bool connected); extern void sharp_install_routes_helper(struct prefix *p, uint8_t instance, struct nexthop_group *nhg, diff --git a/sharpd/subdir.am b/sharpd/subdir.am index 2a34aecfb..4a9028f6f 100644 --- a/sharpd/subdir.am +++ b/sharpd/subdir.am @@ -11,12 +11,15 @@ man8 += $(MANBUILD)/sharpd.8 endif sharpd_libsharp_a_SOURCES = \ + sharpd/sharp_nht.c \ sharpd/sharp_zebra.c \ sharpd/sharp_vty.c \ # end noinst_HEADERS += \ + sharpd/sharp_nht.h \ sharpd/sharp_vty.h \ + sharpd/sharp_globals.h \ sharpd/sharp_zebra.h \ # end @@ -24,5 +27,5 @@ sharpd/sharp_vty_clippy.c: $(CLIPPY_DEPS) sharpd/sharp_vty.$(OBJEXT): sharpd/sharp_vty_clippy.c sharpd_sharpd_SOURCES = sharpd/sharp_main.c -sharpd_sharpd_LDADD = sharpd/libsharp.a lib/libfrr.la @LIBCAP@ +sharpd_sharpd_LDADD = sharpd/libsharp.a lib/libfrr.la $(LIBCAP) diff --git a/staticd/static_vty.c b/staticd/static_vty.c index ae0026cc9..f09c30435 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -775,7 +775,7 @@ DEFPY(ip_route_blackhole, "Table to configure\n" "The table number to configure\n") { - if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) { + if (table_str && vrf && !vrf_is_backend_netns()) { vty_out(vty, "%% table param only available when running on netns-based vrfs\n"); return CMD_WARNING_CONFIG_FAILED; @@ -814,7 +814,7 @@ DEFPY(ip_route_blackhole_vrf, VTY_DECLVAR_CONTEXT(vrf, vrf); struct static_vrf *svrf = vrf->info; - if (table_str && !vrf_is_mapped_on_netns(vrf)) { + if (table_str && !vrf_is_backend_netns()) { vty_out(vty, "%% table param only available when running on netns-based vrfs\n"); return CMD_WARNING_CONFIG_FAILED; @@ -880,7 +880,7 @@ DEFPY(ip_route_address_interface, return CMD_WARNING_CONFIG_FAILED; } - if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) { + if (table_str && vrf && !vrf_is_backend_netns()) { vty_out(vty, "%% table param only available when running on netns-based vrfs\n"); return CMD_WARNING_CONFIG_FAILED; @@ -938,7 +938,7 @@ DEFPY(ip_route_address_interface_vrf, struct static_vrf *svrf = vrf->info; struct static_vrf *nh_svrf; - if (table_str && !vrf_is_mapped_on_netns(vrf)) { + if (table_str && !vrf_is_backend_netns()) { vty_out(vty, "%% table param only available when running on netns-based vrfs\n"); return CMD_WARNING_CONFIG_FAILED; @@ -999,7 +999,7 @@ DEFPY(ip_route, struct static_vrf *nh_svrf; const char *flag = NULL; - if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) { + if (table_str && vrf && !vrf_is_backend_netns()) { vty_out(vty, "%% table param only available when running on netns-based vrfs\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1065,7 +1065,7 @@ DEFPY(ip_route_vrf, struct static_vrf *nh_svrf; const char *flag = NULL; - if (table_str && !vrf_is_mapped_on_netns(vrf)) { + if (table_str && !vrf_is_backend_netns()) { vty_out(vty, "%% table param only available when running on netns-based vrfs\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1119,7 +1119,7 @@ DEFPY(ipv6_route_blackhole, "Table to configure\n" "The table number to configure\n") { - if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) { + if (table_str && vrf && !vrf_is_backend_netns()) { vty_out(vty, "%% table param only available when running on netns-based vrfs\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1158,7 +1158,7 @@ DEFPY(ipv6_route_blackhole_vrf, VTY_DECLVAR_CONTEXT(vrf, vrf); struct static_vrf *svrf = vrf->info; - if (table_str && !vrf_is_mapped_on_netns(vrf)) { + if (table_str && !vrf_is_backend_netns()) { vty_out(vty, "%% table param only available when running on netns-based vrfs\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1213,7 +1213,7 @@ DEFPY(ipv6_route_address_interface, struct static_vrf *nh_svrf; const char *flag = NULL; - if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) { + if (table_str && vrf && !vrf_is_backend_netns()) { vty_out(vty, "%% table param only available when running on netns-based vrfs\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1282,7 +1282,7 @@ DEFPY(ipv6_route_address_interface_vrf, struct static_vrf *nh_svrf; const char *flag = NULL; - if (table_str && !vrf_is_mapped_on_netns(vrf)) { + if (table_str && !vrf_is_backend_netns()) { vty_out(vty, "%% table param only available when running on netns-based vrfs\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1343,7 +1343,7 @@ DEFPY(ipv6_route, struct static_vrf *nh_svrf; const char *flag = NULL; - if (table_str && vrf && !vrf_is_mapped_on_netns(vrf_lookup_by_name(vrf))) { + if (table_str && vrf && !vrf_is_backend_netns()) { vty_out(vty, "%% table param only available when running on netns-based vrfs\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1409,7 +1409,7 @@ DEFPY(ipv6_route_vrf, struct static_vrf *nh_svrf; const char *flag = NULL; - if (table_str && !vrf_is_mapped_on_netns(vrf)) { + if (table_str && !vrf_is_backend_netns()) { vty_out(vty, "%% table param only available when running on netns-based vrfs\n"); return CMD_WARNING_CONFIG_FAILED; diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index d6db60d3e..3f3117752 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -370,8 +370,6 @@ extern void static_zebra_route_add(struct route_node *rn, memcpy(&api.src_prefix, src_pp, sizeof(api.src_prefix)); } SET_FLAG(api.flags, ZEBRA_FLAG_RR_USE_DISTANCE); - if (si_changed->onlink) - SET_FLAG(api.flags, ZEBRA_FLAG_ONLINK); SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); if (si_changed->distance) { SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); @@ -397,6 +395,8 @@ extern void static_zebra_route_add(struct route_node *rn, continue; api_nh->vrf_id = si->nh_vrf_id; + api_nh->onlink = si->onlink; + switch (si->type) { case STATIC_IFNAME: if (si->ifindex == IFINDEX_INTERNAL) diff --git a/staticd/subdir.am b/staticd/subdir.am index 33cc0e205..17c4536fe 100644 --- a/staticd/subdir.am +++ b/staticd/subdir.am @@ -32,4 +32,4 @@ staticd/static_vty_clippy.c: $(CLIPPY_DEPS) staticd/static_vty.$(OBJEXT): staticd/static_vty_clippy.c staticd_staticd_SOURCES = staticd/static_main.c -staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la @LIBCAP@ +staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la $(LIBCAP) diff --git a/tests/.gitignore b/tests/.gitignore index 5453c0d80..de648015f 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -19,6 +19,7 @@ /lib/cli/test_commands /lib/cli/test_commands_defun.c /lib/northbound/test_oper_data +/lib/cxxcompat /lib/test_buffer /lib/test_checksum /lib/test_graph diff --git a/tests/Makefile.in b/tests/Makefile.in new file mode 100644 index 000000000..29d903e70 --- /dev/null +++ b/tests/Makefile.in @@ -0,0 +1,1338 @@ +# Makefile.in generated by automake 1.15.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2017 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Automake fragment intended to be shared by Makefile.am files in the +# tree. +# + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +check_PROGRAMS = lib/test_buffer$(EXEEXT) lib/test_checksum$(EXEEXT) \ + lib/test_heavy_thread$(EXEEXT) lib/test_heavy_wq$(EXEEXT) \ + lib/test_heavy$(EXEEXT) lib/test_memory$(EXEEXT) \ + lib/test_nexthop_iter$(EXEEXT) lib/test_privs$(EXEEXT) \ + lib/test_ringbuf$(EXEEXT) lib/test_srcdest_table$(EXEEXT) \ + lib/test_segv$(EXEEXT) lib/test_sig$(EXEEXT) \ + lib/test_stream$(EXEEXT) lib/test_table$(EXEEXT) \ + lib/test_timer_correctness$(EXEEXT) \ + lib/test_timer_performance$(EXEEXT) lib/test_ttable$(EXEEXT) \ + lib/cli/test_cli$(EXEEXT) lib/cli/test_commands$(EXEEXT) \ + $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ + $(am__EXEEXT_4) +@ZEROMQ_TRUE@am__append_1 = \ +@ZEROMQ_TRUE@ lib/test_zmq \ +@ZEROMQ_TRUE@ # end + +subdir = tests +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \ + $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@BGPD_TRUE@am__EXEEXT_1 = bgpd/test_aspath$(EXEEXT) \ +@BGPD_TRUE@ bgpd/test_capability$(EXEEXT) \ +@BGPD_TRUE@ bgpd/test_packet$(EXEEXT) \ +@BGPD_TRUE@ bgpd/test_ecommunity$(EXEEXT) \ +@BGPD_TRUE@ bgpd/test_mp_attr$(EXEEXT) bgpd/test_mpath$(EXEEXT) +@ISISD_TRUE@@SOLARIS_FALSE@am__EXEEXT_2 = \ +@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_fuzz_isis_tlv$(EXEEXT) \ +@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_isis_vertex_queue$(EXEEXT) +@OSPF6D_TRUE@am__EXEEXT_3 = ospf6d/test_lsdb$(EXEEXT) +@ZEROMQ_TRUE@am__EXEEXT_4 = lib/test_zmq$(EXEEXT) +am__dirstamp = $(am__leading_dot)dirstamp +am_bgpd_test_aspath_OBJECTS = bgpd/test_aspath.$(OBJEXT) +bgpd_test_aspath_OBJECTS = $(am_bgpd_test_aspath_OBJECTS) +@ENABLE_BGP_VNC_TRUE@am__DEPENDENCIES_1 = \ +@ENABLE_BGP_VNC_TRUE@ @top_builddir@/$(LIBRFP)/librfp.a +am__DEPENDENCIES_2 = ../lib/libfrr.la +am__DEPENDENCIES_3 = ../bgpd/libbgp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_2) +bgpd_test_aspath_DEPENDENCIES = $(am__DEPENDENCIES_3) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +am_bgpd_test_capability_OBJECTS = bgpd/test_capability.$(OBJEXT) +bgpd_test_capability_OBJECTS = $(am_bgpd_test_capability_OBJECTS) +bgpd_test_capability_DEPENDENCIES = $(am__DEPENDENCIES_3) +am_bgpd_test_ecommunity_OBJECTS = bgpd/test_ecommunity.$(OBJEXT) +bgpd_test_ecommunity_OBJECTS = $(am_bgpd_test_ecommunity_OBJECTS) +bgpd_test_ecommunity_DEPENDENCIES = $(am__DEPENDENCIES_3) +am_bgpd_test_mp_attr_OBJECTS = bgpd/test_mp_attr.$(OBJEXT) +bgpd_test_mp_attr_OBJECTS = $(am_bgpd_test_mp_attr_OBJECTS) +bgpd_test_mp_attr_DEPENDENCIES = $(am__DEPENDENCIES_3) +am_bgpd_test_mpath_OBJECTS = bgpd/test_mpath.$(OBJEXT) +bgpd_test_mpath_OBJECTS = $(am_bgpd_test_mpath_OBJECTS) +bgpd_test_mpath_DEPENDENCIES = $(am__DEPENDENCIES_3) +am_bgpd_test_packet_OBJECTS = bgpd/test_packet.$(OBJEXT) +bgpd_test_packet_OBJECTS = $(am_bgpd_test_packet_OBJECTS) +bgpd_test_packet_DEPENDENCIES = $(am__DEPENDENCIES_3) +am_isisd_test_fuzz_isis_tlv_OBJECTS = \ + isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT) +isisd_test_fuzz_isis_tlv_OBJECTS = \ + $(am_isisd_test_fuzz_isis_tlv_OBJECTS) +am__DEPENDENCIES_4 = ../isisd/libisis.a $(am__DEPENDENCIES_2) +isisd_test_fuzz_isis_tlv_DEPENDENCIES = $(am__DEPENDENCIES_4) +am_isisd_test_isis_vertex_queue_OBJECTS = \ + isisd/test_isis_vertex_queue.$(OBJEXT) +isisd_test_isis_vertex_queue_OBJECTS = \ + $(am_isisd_test_isis_vertex_queue_OBJECTS) +isisd_test_isis_vertex_queue_DEPENDENCIES = $(am__DEPENDENCIES_4) +am_lib_cli_test_cli_OBJECTS = lib/cli/test_cli.$(OBJEXT) \ + lib/cli/common_cli.$(OBJEXT) +lib_cli_test_cli_OBJECTS = $(am_lib_cli_test_cli_OBJECTS) +lib_cli_test_cli_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_cli_test_commands_OBJECTS = \ + lib/cli/test_commands_defun.$(OBJEXT) \ + lib/cli/test_commands.$(OBJEXT) helpers/c/prng.$(OBJEXT) +lib_cli_test_commands_OBJECTS = $(am_lib_cli_test_commands_OBJECTS) +lib_cli_test_commands_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_buffer_OBJECTS = lib/test_buffer.$(OBJEXT) +lib_test_buffer_OBJECTS = $(am_lib_test_buffer_OBJECTS) +lib_test_buffer_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_checksum_OBJECTS = lib/test_checksum.$(OBJEXT) +lib_test_checksum_OBJECTS = $(am_lib_test_checksum_OBJECTS) +lib_test_checksum_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_heavy_OBJECTS = lib/test_heavy.$(OBJEXT) \ + helpers/c/main.$(OBJEXT) +lib_test_heavy_OBJECTS = $(am_lib_test_heavy_OBJECTS) +lib_test_heavy_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_heavy_thread_OBJECTS = lib/test_heavy_thread.$(OBJEXT) \ + helpers/c/main.$(OBJEXT) +lib_test_heavy_thread_OBJECTS = $(am_lib_test_heavy_thread_OBJECTS) +lib_test_heavy_thread_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_heavy_wq_OBJECTS = lib/test_heavy_wq.$(OBJEXT) \ + helpers/c/main.$(OBJEXT) +lib_test_heavy_wq_OBJECTS = $(am_lib_test_heavy_wq_OBJECTS) +lib_test_heavy_wq_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_memory_OBJECTS = lib/test_memory.$(OBJEXT) +lib_test_memory_OBJECTS = $(am_lib_test_memory_OBJECTS) +lib_test_memory_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_nexthop_iter_OBJECTS = lib/test_nexthop_iter.$(OBJEXT) \ + helpers/c/prng.$(OBJEXT) +lib_test_nexthop_iter_OBJECTS = $(am_lib_test_nexthop_iter_OBJECTS) +lib_test_nexthop_iter_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_privs_OBJECTS = lib/test_privs.$(OBJEXT) +lib_test_privs_OBJECTS = $(am_lib_test_privs_OBJECTS) +lib_test_privs_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_ringbuf_OBJECTS = lib/test_ringbuf.$(OBJEXT) +lib_test_ringbuf_OBJECTS = $(am_lib_test_ringbuf_OBJECTS) +lib_test_ringbuf_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_segv_OBJECTS = lib/test_segv.$(OBJEXT) +lib_test_segv_OBJECTS = $(am_lib_test_segv_OBJECTS) +lib_test_segv_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_sig_OBJECTS = lib/test_sig.$(OBJEXT) +lib_test_sig_OBJECTS = $(am_lib_test_sig_OBJECTS) +lib_test_sig_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_srcdest_table_OBJECTS = lib/test_srcdest_table.$(OBJEXT) \ + helpers/c/prng.$(OBJEXT) +lib_test_srcdest_table_OBJECTS = $(am_lib_test_srcdest_table_OBJECTS) +lib_test_srcdest_table_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_stream_OBJECTS = lib/test_stream.$(OBJEXT) +lib_test_stream_OBJECTS = $(am_lib_test_stream_OBJECTS) +lib_test_stream_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_table_OBJECTS = lib/test_table.$(OBJEXT) +lib_test_table_OBJECTS = $(am_lib_test_table_OBJECTS) +lib_test_table_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_timer_correctness_OBJECTS = \ + lib/test_timer_correctness.$(OBJEXT) helpers/c/prng.$(OBJEXT) +lib_test_timer_correctness_OBJECTS = \ + $(am_lib_test_timer_correctness_OBJECTS) +lib_test_timer_correctness_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_timer_performance_OBJECTS = \ + lib/test_timer_performance.$(OBJEXT) helpers/c/prng.$(OBJEXT) +lib_test_timer_performance_OBJECTS = \ + $(am_lib_test_timer_performance_OBJECTS) +lib_test_timer_performance_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_ttable_OBJECTS = lib/test_ttable.$(OBJEXT) +lib_test_ttable_OBJECTS = $(am_lib_test_ttable_OBJECTS) +lib_test_ttable_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_zmq_OBJECTS = lib/lib_test_zmq-test_zmq.$(OBJEXT) +lib_test_zmq_OBJECTS = $(am_lib_test_zmq_OBJECTS) +am__DEPENDENCIES_5 = +lib_test_zmq_DEPENDENCIES = ../lib/libfrrzmq.la $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_5) +lib_test_zmq_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(lib_test_zmq_CFLAGS) \ + $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +am_ospf6d_test_lsdb_OBJECTS = ospf6d/test_lsdb.$(OBJEXT) \ + lib/cli/common_cli.$(OBJEXT) +ospf6d_test_lsdb_OBJECTS = $(am_ospf6d_test_lsdb_OBJECTS) +am__DEPENDENCIES_6 = ../ospf6d/libospf6.a $(am__DEPENDENCIES_2) +ospf6d_test_lsdb_DEPENDENCIES = $(am__DEPENDENCIES_6) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(bgpd_test_aspath_SOURCES) $(bgpd_test_capability_SOURCES) \ + $(bgpd_test_ecommunity_SOURCES) $(bgpd_test_mp_attr_SOURCES) \ + $(bgpd_test_mpath_SOURCES) $(bgpd_test_packet_SOURCES) \ + $(isisd_test_fuzz_isis_tlv_SOURCES) \ + $(isisd_test_isis_vertex_queue_SOURCES) \ + $(lib_cli_test_cli_SOURCES) $(lib_cli_test_commands_SOURCES) \ + $(lib_test_buffer_SOURCES) $(lib_test_checksum_SOURCES) \ + $(lib_test_heavy_SOURCES) $(lib_test_heavy_thread_SOURCES) \ + $(lib_test_heavy_wq_SOURCES) $(lib_test_memory_SOURCES) \ + $(lib_test_nexthop_iter_SOURCES) $(lib_test_privs_SOURCES) \ + $(lib_test_ringbuf_SOURCES) $(lib_test_segv_SOURCES) \ + $(lib_test_sig_SOURCES) $(lib_test_srcdest_table_SOURCES) \ + $(lib_test_stream_SOURCES) $(lib_test_table_SOURCES) \ + $(lib_test_timer_correctness_SOURCES) \ + $(lib_test_timer_performance_SOURCES) \ + $(lib_test_ttable_SOURCES) $(lib_test_zmq_SOURCES) \ + $(ospf6d_test_lsdb_SOURCES) +DIST_SOURCES = $(bgpd_test_aspath_SOURCES) \ + $(bgpd_test_capability_SOURCES) \ + $(bgpd_test_ecommunity_SOURCES) $(bgpd_test_mp_attr_SOURCES) \ + $(bgpd_test_mpath_SOURCES) $(bgpd_test_packet_SOURCES) \ + $(isisd_test_fuzz_isis_tlv_SOURCES) \ + $(isisd_test_isis_vertex_queue_SOURCES) \ + $(lib_cli_test_cli_SOURCES) $(lib_cli_test_commands_SOURCES) \ + $(lib_test_buffer_SOURCES) $(lib_test_checksum_SOURCES) \ + $(lib_test_heavy_SOURCES) $(lib_test_heavy_thread_SOURCES) \ + $(lib_test_heavy_wq_SOURCES) $(lib_test_memory_SOURCES) \ + $(lib_test_nexthop_iter_SOURCES) $(lib_test_privs_SOURCES) \ + $(lib_test_ringbuf_SOURCES) $(lib_test_segv_SOURCES) \ + $(lib_test_sig_SOURCES) $(lib_test_srcdest_table_SOURCES) \ + $(lib_test_stream_SOURCES) $(lib_test_table_SOURCES) \ + $(lib_test_timer_correctness_SOURCES) \ + $(lib_test_timer_performance_SOURCES) \ + $(lib_test_ttable_SOURCES) $(lib_test_zmq_SOURCES) \ + $(ospf6d_test_lsdb_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/../common.am $(srcdir)/Makefile.in \ + $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BGPD = @BGPD@ +BISON_CLOSEBRACE = @BISON_CLOSEBRACE@ +BISON_OPENBRACE = @BISON_OPENBRACE@ +BISON_VERBOSE = @BISON_VERBOSE@ +CARES_CFLAGS = @CARES_CFLAGS@ +CARES_LIBS = @CARES_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFG_MODULE = @CFG_MODULE@ +CFG_SBIN = @CFG_SBIN@ +CFG_STATE = @CFG_STATE@ +CFG_SYSCONF = @CFG_SYSCONF@ +CFLAGS = @CFLAGS@ +CONFDATE = @CONFDATE@ +CONFIG_ARGS = @CONFIG_ARGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURSES = @CURSES@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" +DEPDIR = @DEPDIR@ +DFLT_NAME = @DFLT_NAME@ +DLLTOOL = @DLLTOOL@ +DOC = @DOC@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ +HOSTTOOLS = @HOSTTOOLS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBPAM = @LIBPAM@ +LIBREADLINE = @LIBREADLINE@ +LIBRFP = @LIBRFP@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NETSNMP_CONFIG = @NETSNMP_CONFIG@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_EXTRAVERSION = @PACKAGE_EXTRAVERSION@ +PACKAGE_FULLNAME = @PACKAGE_FULLNAME@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ +PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ +PROTOC_C = @PROTOC_C@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +PYTHONCONFIG = @PYTHONCONFIG@ +PYTHON_CFLAGS = @PYTHON_CFLAGS@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +RFPINC = @RFPINC@ +RFPTEST = @RFPTEST@ +RTRLIB_CFLAGS = @RTRLIB_CFLAGS@ +RTRLIB_LIBS = @RTRLIB_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SNMP_CFLAGS = @SNMP_CFLAGS@ +SNMP_LIBS = @SNMP_LIBS@ +SOLARIS = @SOLARIS@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VNC_RFP_PATH = @VNC_RFP_PATH@ +VTYSH = @VTYSH@ +WERROR = @WERROR@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZEROMQ_CFLAGS = @ZEROMQ_CFLAGS@ +ZEROMQ_LIBS = @ZEROMQ_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_PYTHONCONFIG = @ac_ct_PYTHONCONFIG@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +ax_pthread_config = @ax_pthread_config@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_group = @enable_group@ +enable_user = @enable_user@ +enable_vty_group = @enable_vty_group@ +exampledir = @exampledir@ +exec_prefix = @exec_prefix@ +frr_statedir = @frr_statedir@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgsrcrcdir = @pkgsrcrcdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_V_CLIPPY = $(am__v_CLIPPY_$(V)) +am__v_CLIPPY_ = $(am__v_CLIPPY_$(AM_DEFAULT_VERBOSITY)) +am__v_CLIPPY_0 = @echo " CLIPPY " $@; +am__v_CLIPPY_1 = +CLIPPY_DEPS = $(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py +SUFFIXES = _clippy.c .proto .pb-c.c .pb-c.h .pb.h + +# Uncomment to use an non-system version of libprotobuf-c. +# +# Q_PROTOBUF_C_CLIENT_INCLUDES = -I$(top_srcdir)/third-party/protobuf-c/src +# Q_PROTOBUF_C_CLIENT_LDOPTS = $(top_builddir)/third-party/protobuf-c/src/libprotobuf-c.la +@HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_INCLUDES = +@HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_LDOPTS = -lprotobuf-c +@HAVE_PROTOBUF_TRUE@Q_PROTOC = protoc +@HAVE_PROTOBUF_TRUE@Q_PROTOC_C = protoc-c +@HAVE_PROTOBUF_TRUE@AM_V_PROTOC_C = $(am__v_PROTOC_C_$(V)) +@HAVE_PROTOBUF_TRUE@am__v_PROTOC_C_ = $(am__v_PROTOC_C_$(AM_DEFAULT_VERBOSITY)) +@HAVE_PROTOBUF_TRUE@am__v_PROTOC_C_0 = @echo " PROTOC_C" $@; +@HAVE_PROTOBUF_TRUE@am__v_PROTOC_C_1 = + +# +# Information about how to link to various libraries. +# +@HAVE_PROTOBUF_TRUE@Q_FRR_PB_CLIENT_LDOPTS = $(top_srcdir)/qpb/libfrr_pb.la $(Q_PROTOBUF_C_CLIENT_LDOPTS) +@HAVE_PROTOBUF_TRUE@Q_FPM_PB_CLIENT_LDOPTS = $(top_srcdir)/fpm/libfrrfpm_pb.la $(Q_FRR_PB_CLIENT_LDOPTS) +AUTOMAKE_OPTIONS = subdir-objects +AM_CPPFLAGS = \ + -I.. \ + -I$(top_srcdir) \ + -I$(top_srcdir)/lib \ + -I$(top_builddir)/lib \ + -I$(top_srcdir)/tests/helpers/c \ + -I$(top_builddir)/tests/helpers/c \ + -O + +@BGPD_FALSE@TESTS_BGPD = +@BGPD_TRUE@TESTS_BGPD = \ +@BGPD_TRUE@ bgpd/test_aspath \ +@BGPD_TRUE@ bgpd/test_capability \ +@BGPD_TRUE@ bgpd/test_packet \ +@BGPD_TRUE@ bgpd/test_ecommunity \ +@BGPD_TRUE@ bgpd/test_mp_attr \ +@BGPD_TRUE@ bgpd/test_mpath + +@ISISD_FALSE@TESTS_ISISD = +@ISISD_TRUE@@SOLARIS_FALSE@TESTS_ISISD = \ +@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_fuzz_isis_tlv \ +@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_isis_vertex_queue \ +@ISISD_TRUE@@SOLARIS_FALSE@ # end + +@ISISD_TRUE@@SOLARIS_TRUE@TESTS_ISISD = +@OSPF6D_FALSE@TESTS_OSPF6D = +@OSPF6D_TRUE@TESTS_OSPF6D = \ +@OSPF6D_TRUE@ ospf6d/test_lsdb \ +@OSPF6D_TRUE@ # end + +@ENABLE_BGP_VNC_FALSE@BGP_VNC_RFP_LIB = +@ENABLE_BGP_VNC_TRUE@BGP_VNC_RFP_LIB = @top_builddir@/$(LIBRFP)/librfp.a +noinst_HEADERS = \ + ./helpers/c/prng.h \ + ./helpers/c/tests.h \ + ./lib/cli/common_cli.h + +lib_test_buffer_SOURCES = lib/test_buffer.c +lib_test_checksum_SOURCES = lib/test_checksum.c +lib_test_heavy_thread_SOURCES = lib/test_heavy_thread.c helpers/c/main.c +lib_test_heavy_wq_SOURCES = lib/test_heavy_wq.c helpers/c/main.c +lib_test_heavy_SOURCES = lib/test_heavy.c helpers/c/main.c +lib_test_memory_SOURCES = lib/test_memory.c +lib_test_nexthop_iter_SOURCES = lib/test_nexthop_iter.c helpers/c/prng.c +lib_test_privs_SOURCES = lib/test_privs.c +lib_test_srcdest_table_SOURCES = lib/test_srcdest_table.c \ + helpers/c/prng.c + +lib_test_ringbuf_SOURCES = lib/test_ringbuf.c +lib_test_segv_SOURCES = lib/test_segv.c +lib_test_sig_SOURCES = lib/test_sig.c +lib_test_stream_SOURCES = lib/test_stream.c +lib_test_table_SOURCES = lib/test_table.c +lib_test_timer_correctness_SOURCES = lib/test_timer_correctness.c \ + helpers/c/prng.c + +lib_test_timer_performance_SOURCES = lib/test_timer_performance.c \ + helpers/c/prng.c + +lib_test_ttable_SOURCES = lib/test_ttable.c +lib_test_zmq_SOURCES = lib/test_zmq.c +lib_test_zmq_CFLAGS = $(AM_CFLAGS) $(ZEROMQ_CFLAGS) +lib_cli_test_cli_SOURCES = lib/cli/test_cli.c lib/cli/common_cli.c +lib_cli_test_commands_SOURCES = lib/cli/test_commands_defun.c \ + lib/cli/test_commands.c \ + helpers/c/prng.c + +bgpd_test_aspath_SOURCES = bgpd/test_aspath.c +bgpd_test_capability_SOURCES = bgpd/test_capability.c +bgpd_test_packet_SOURCES = bgpd/test_packet.c +bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c +bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c +bgpd_test_mpath_SOURCES = bgpd/test_mpath.c +isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv.c +isisd_test_fuzz_isis_tlv_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/tests/isisd +isisd_test_isis_vertex_queue_SOURCES = isisd/test_isis_vertex_queue.c +ospf6d_test_lsdb_SOURCES = ospf6d/test_lsdb.c lib/cli/common_cli.c +ALL_TESTS_LDADD = ../lib/libfrr.la @LIBCAP@ +BGP_TEST_LDADD = ../bgpd/libbgp.a $(BGP_VNC_RFP_LIB) $(ALL_TESTS_LDADD) -lm +ISISD_TEST_LDADD = ../isisd/libisis.a $(ALL_TESTS_LDADD) +OSPF6_TEST_LDADD = ../ospf6d/libospf6.a $(ALL_TESTS_LDADD) +lib_test_buffer_LDADD = $(ALL_TESTS_LDADD) +lib_test_checksum_LDADD = $(ALL_TESTS_LDADD) +lib_test_heavy_thread_LDADD = $(ALL_TESTS_LDADD) -lm +lib_test_heavy_wq_LDADD = $(ALL_TESTS_LDADD) -lm +lib_test_heavy_LDADD = $(ALL_TESTS_LDADD) -lm +lib_test_memory_LDADD = $(ALL_TESTS_LDADD) +lib_test_nexthop_iter_LDADD = $(ALL_TESTS_LDADD) +lib_test_privs_LDADD = $(ALL_TESTS_LDADD) +lib_test_ringbuf_LDADD = $(ALL_TESTS_LDADD) +lib_test_srcdest_table_LDADD = $(ALL_TESTS_LDADD) +lib_test_segv_LDADD = $(ALL_TESTS_LDADD) +lib_test_sig_LDADD = $(ALL_TESTS_LDADD) +lib_test_stream_LDADD = $(ALL_TESTS_LDADD) +lib_test_table_LDADD = $(ALL_TESTS_LDADD) -lm +lib_test_timer_correctness_LDADD = $(ALL_TESTS_LDADD) +lib_test_timer_performance_LDADD = $(ALL_TESTS_LDADD) +lib_test_ttable_LDADD = $(ALL_TESTS_LDADD) +lib_test_zmq_LDADD = ../lib/libfrrzmq.la $(ALL_TESTS_LDADD) $(ZEROMQ_LIBS) +lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD) +lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD) +bgpd_test_aspath_LDADD = $(BGP_TEST_LDADD) +bgpd_test_capability_LDADD = $(BGP_TEST_LDADD) +bgpd_test_packet_LDADD = $(BGP_TEST_LDADD) +bgpd_test_ecommunity_LDADD = $(BGP_TEST_LDADD) +bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD) +bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD) +isisd_test_fuzz_isis_tlv_LDADD = $(ISISD_TEST_LDADD) +isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD) +ospf6d_test_lsdb_LDADD = $(OSPF6_TEST_LDADD) +EXTRA_DIST = \ + runtests.py \ + bgpd/test_aspath.py \ + bgpd/test_capability.py \ + bgpd/test_ecommunity.py \ + bgpd/test_mp_attr.py \ + bgpd/test_mpath.py \ + helpers/python/frrsix.py \ + helpers/python/frrtest.py \ + isisd/test_fuzz_isis_tlv.py \ + isisd/test_fuzz_isis_tlv_tests.h.gz \ + isisd/test_isis_vertex_queue.py \ + lib/cli/test_commands.in \ + lib/cli/test_commands.py \ + lib/cli/test_commands.refout \ + lib/cli/test_cli.in \ + lib/cli/test_cli.py \ + lib/cli/test_cli.refout \ + lib/test_nexthop_iter.py \ + lib/test_ringbuf.py \ + lib/test_srcdest_table.py \ + lib/test_stream.py \ + lib/test_stream.refout \ + lib/test_table.py \ + lib/test_timer_correctness.py \ + lib/test_ttable.py \ + lib/test_ttable.refout \ + ospf6d/test_lsdb.py \ + ospf6d/test_lsdb.in \ + ospf6d/test_lsdb.refout \ + # end + +all: all-am + +.SUFFIXES: +.SUFFIXES: _clippy.c .proto .pb-c.c .pb-c.h .pb.h .c .l .lo .o .obj .y +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../common.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; +$(srcdir)/../common.am $(am__empty): + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +bgpd/$(am__dirstamp): + @$(MKDIR_P) bgpd + @: > bgpd/$(am__dirstamp) +bgpd/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) bgpd/$(DEPDIR) + @: > bgpd/$(DEPDIR)/$(am__dirstamp) +bgpd/test_aspath.$(OBJEXT): bgpd/$(am__dirstamp) \ + bgpd/$(DEPDIR)/$(am__dirstamp) + +bgpd/test_aspath$(EXEEXT): $(bgpd_test_aspath_OBJECTS) $(bgpd_test_aspath_DEPENDENCIES) $(EXTRA_bgpd_test_aspath_DEPENDENCIES) bgpd/$(am__dirstamp) + @rm -f bgpd/test_aspath$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(bgpd_test_aspath_OBJECTS) $(bgpd_test_aspath_LDADD) $(LIBS) +bgpd/test_capability.$(OBJEXT): bgpd/$(am__dirstamp) \ + bgpd/$(DEPDIR)/$(am__dirstamp) + +bgpd/test_capability$(EXEEXT): $(bgpd_test_capability_OBJECTS) $(bgpd_test_capability_DEPENDENCIES) $(EXTRA_bgpd_test_capability_DEPENDENCIES) bgpd/$(am__dirstamp) + @rm -f bgpd/test_capability$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(bgpd_test_capability_OBJECTS) $(bgpd_test_capability_LDADD) $(LIBS) +bgpd/test_ecommunity.$(OBJEXT): bgpd/$(am__dirstamp) \ + bgpd/$(DEPDIR)/$(am__dirstamp) + +bgpd/test_ecommunity$(EXEEXT): $(bgpd_test_ecommunity_OBJECTS) $(bgpd_test_ecommunity_DEPENDENCIES) $(EXTRA_bgpd_test_ecommunity_DEPENDENCIES) bgpd/$(am__dirstamp) + @rm -f bgpd/test_ecommunity$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(bgpd_test_ecommunity_OBJECTS) $(bgpd_test_ecommunity_LDADD) $(LIBS) +bgpd/test_mp_attr.$(OBJEXT): bgpd/$(am__dirstamp) \ + bgpd/$(DEPDIR)/$(am__dirstamp) + +bgpd/test_mp_attr$(EXEEXT): $(bgpd_test_mp_attr_OBJECTS) $(bgpd_test_mp_attr_DEPENDENCIES) $(EXTRA_bgpd_test_mp_attr_DEPENDENCIES) bgpd/$(am__dirstamp) + @rm -f bgpd/test_mp_attr$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(bgpd_test_mp_attr_OBJECTS) $(bgpd_test_mp_attr_LDADD) $(LIBS) +bgpd/test_mpath.$(OBJEXT): bgpd/$(am__dirstamp) \ + bgpd/$(DEPDIR)/$(am__dirstamp) + +bgpd/test_mpath$(EXEEXT): $(bgpd_test_mpath_OBJECTS) $(bgpd_test_mpath_DEPENDENCIES) $(EXTRA_bgpd_test_mpath_DEPENDENCIES) bgpd/$(am__dirstamp) + @rm -f bgpd/test_mpath$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(bgpd_test_mpath_OBJECTS) $(bgpd_test_mpath_LDADD) $(LIBS) +bgpd/test_packet.$(OBJEXT): bgpd/$(am__dirstamp) \ + bgpd/$(DEPDIR)/$(am__dirstamp) + +bgpd/test_packet$(EXEEXT): $(bgpd_test_packet_OBJECTS) $(bgpd_test_packet_DEPENDENCIES) $(EXTRA_bgpd_test_packet_DEPENDENCIES) bgpd/$(am__dirstamp) + @rm -f bgpd/test_packet$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(bgpd_test_packet_OBJECTS) $(bgpd_test_packet_LDADD) $(LIBS) +isisd/$(am__dirstamp): + @$(MKDIR_P) isisd + @: > isisd/$(am__dirstamp) +isisd/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) isisd/$(DEPDIR) + @: > isisd/$(DEPDIR)/$(am__dirstamp) +isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \ + isisd/$(am__dirstamp) isisd/$(DEPDIR)/$(am__dirstamp) + +isisd/test_fuzz_isis_tlv$(EXEEXT): $(isisd_test_fuzz_isis_tlv_OBJECTS) $(isisd_test_fuzz_isis_tlv_DEPENDENCIES) $(EXTRA_isisd_test_fuzz_isis_tlv_DEPENDENCIES) isisd/$(am__dirstamp) + @rm -f isisd/test_fuzz_isis_tlv$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(isisd_test_fuzz_isis_tlv_OBJECTS) $(isisd_test_fuzz_isis_tlv_LDADD) $(LIBS) +isisd/test_isis_vertex_queue.$(OBJEXT): isisd/$(am__dirstamp) \ + isisd/$(DEPDIR)/$(am__dirstamp) + +isisd/test_isis_vertex_queue$(EXEEXT): $(isisd_test_isis_vertex_queue_OBJECTS) $(isisd_test_isis_vertex_queue_DEPENDENCIES) $(EXTRA_isisd_test_isis_vertex_queue_DEPENDENCIES) isisd/$(am__dirstamp) + @rm -f isisd/test_isis_vertex_queue$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(isisd_test_isis_vertex_queue_OBJECTS) $(isisd_test_isis_vertex_queue_LDADD) $(LIBS) +lib/cli/$(am__dirstamp): + @$(MKDIR_P) lib/cli + @: > lib/cli/$(am__dirstamp) +lib/cli/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) lib/cli/$(DEPDIR) + @: > lib/cli/$(DEPDIR)/$(am__dirstamp) +lib/cli/test_cli.$(OBJEXT): lib/cli/$(am__dirstamp) \ + lib/cli/$(DEPDIR)/$(am__dirstamp) +lib/cli/common_cli.$(OBJEXT): lib/cli/$(am__dirstamp) \ + lib/cli/$(DEPDIR)/$(am__dirstamp) + +lib/cli/test_cli$(EXEEXT): $(lib_cli_test_cli_OBJECTS) $(lib_cli_test_cli_DEPENDENCIES) $(EXTRA_lib_cli_test_cli_DEPENDENCIES) lib/cli/$(am__dirstamp) + @rm -f lib/cli/test_cli$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_cli_test_cli_OBJECTS) $(lib_cli_test_cli_LDADD) $(LIBS) +lib/cli/test_commands_defun.$(OBJEXT): lib/cli/$(am__dirstamp) \ + lib/cli/$(DEPDIR)/$(am__dirstamp) +lib/cli/test_commands.$(OBJEXT): lib/cli/$(am__dirstamp) \ + lib/cli/$(DEPDIR)/$(am__dirstamp) +helpers/c/$(am__dirstamp): + @$(MKDIR_P) helpers/c + @: > helpers/c/$(am__dirstamp) +helpers/c/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) helpers/c/$(DEPDIR) + @: > helpers/c/$(DEPDIR)/$(am__dirstamp) +helpers/c/prng.$(OBJEXT): helpers/c/$(am__dirstamp) \ + helpers/c/$(DEPDIR)/$(am__dirstamp) + +lib/cli/test_commands$(EXEEXT): $(lib_cli_test_commands_OBJECTS) $(lib_cli_test_commands_DEPENDENCIES) $(EXTRA_lib_cli_test_commands_DEPENDENCIES) lib/cli/$(am__dirstamp) + @rm -f lib/cli/test_commands$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_cli_test_commands_OBJECTS) $(lib_cli_test_commands_LDADD) $(LIBS) +lib/$(am__dirstamp): + @$(MKDIR_P) lib + @: > lib/$(am__dirstamp) +lib/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) lib/$(DEPDIR) + @: > lib/$(DEPDIR)/$(am__dirstamp) +lib/test_buffer.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_buffer$(EXEEXT): $(lib_test_buffer_OBJECTS) $(lib_test_buffer_DEPENDENCIES) $(EXTRA_lib_test_buffer_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_buffer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_buffer_OBJECTS) $(lib_test_buffer_LDADD) $(LIBS) +lib/test_checksum.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_checksum$(EXEEXT): $(lib_test_checksum_OBJECTS) $(lib_test_checksum_DEPENDENCIES) $(EXTRA_lib_test_checksum_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_checksum$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_checksum_OBJECTS) $(lib_test_checksum_LDADD) $(LIBS) +lib/test_heavy.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) +helpers/c/main.$(OBJEXT): helpers/c/$(am__dirstamp) \ + helpers/c/$(DEPDIR)/$(am__dirstamp) + +lib/test_heavy$(EXEEXT): $(lib_test_heavy_OBJECTS) $(lib_test_heavy_DEPENDENCIES) $(EXTRA_lib_test_heavy_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_heavy$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_heavy_OBJECTS) $(lib_test_heavy_LDADD) $(LIBS) +lib/test_heavy_thread.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_heavy_thread$(EXEEXT): $(lib_test_heavy_thread_OBJECTS) $(lib_test_heavy_thread_DEPENDENCIES) $(EXTRA_lib_test_heavy_thread_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_heavy_thread$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_heavy_thread_OBJECTS) $(lib_test_heavy_thread_LDADD) $(LIBS) +lib/test_heavy_wq.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_heavy_wq$(EXEEXT): $(lib_test_heavy_wq_OBJECTS) $(lib_test_heavy_wq_DEPENDENCIES) $(EXTRA_lib_test_heavy_wq_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_heavy_wq$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_heavy_wq_OBJECTS) $(lib_test_heavy_wq_LDADD) $(LIBS) +lib/test_memory.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_memory$(EXEEXT): $(lib_test_memory_OBJECTS) $(lib_test_memory_DEPENDENCIES) $(EXTRA_lib_test_memory_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_memory$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_memory_OBJECTS) $(lib_test_memory_LDADD) $(LIBS) +lib/test_nexthop_iter.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_nexthop_iter$(EXEEXT): $(lib_test_nexthop_iter_OBJECTS) $(lib_test_nexthop_iter_DEPENDENCIES) $(EXTRA_lib_test_nexthop_iter_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_nexthop_iter$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_nexthop_iter_OBJECTS) $(lib_test_nexthop_iter_LDADD) $(LIBS) +lib/test_privs.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_privs$(EXEEXT): $(lib_test_privs_OBJECTS) $(lib_test_privs_DEPENDENCIES) $(EXTRA_lib_test_privs_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_privs$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_privs_OBJECTS) $(lib_test_privs_LDADD) $(LIBS) +lib/test_ringbuf.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_ringbuf$(EXEEXT): $(lib_test_ringbuf_OBJECTS) $(lib_test_ringbuf_DEPENDENCIES) $(EXTRA_lib_test_ringbuf_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_ringbuf$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_ringbuf_OBJECTS) $(lib_test_ringbuf_LDADD) $(LIBS) +lib/test_segv.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_segv$(EXEEXT): $(lib_test_segv_OBJECTS) $(lib_test_segv_DEPENDENCIES) $(EXTRA_lib_test_segv_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_segv$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_segv_OBJECTS) $(lib_test_segv_LDADD) $(LIBS) +lib/test_sig.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_sig$(EXEEXT): $(lib_test_sig_OBJECTS) $(lib_test_sig_DEPENDENCIES) $(EXTRA_lib_test_sig_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_sig$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_sig_OBJECTS) $(lib_test_sig_LDADD) $(LIBS) +lib/test_srcdest_table.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_srcdest_table$(EXEEXT): $(lib_test_srcdest_table_OBJECTS) $(lib_test_srcdest_table_DEPENDENCIES) $(EXTRA_lib_test_srcdest_table_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_srcdest_table$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_srcdest_table_OBJECTS) $(lib_test_srcdest_table_LDADD) $(LIBS) +lib/test_stream.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_stream$(EXEEXT): $(lib_test_stream_OBJECTS) $(lib_test_stream_DEPENDENCIES) $(EXTRA_lib_test_stream_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_stream$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_stream_OBJECTS) $(lib_test_stream_LDADD) $(LIBS) +lib/test_table.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_table$(EXEEXT): $(lib_test_table_OBJECTS) $(lib_test_table_DEPENDENCIES) $(EXTRA_lib_test_table_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_table$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_table_OBJECTS) $(lib_test_table_LDADD) $(LIBS) +lib/test_timer_correctness.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_timer_correctness$(EXEEXT): $(lib_test_timer_correctness_OBJECTS) $(lib_test_timer_correctness_DEPENDENCIES) $(EXTRA_lib_test_timer_correctness_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_timer_correctness$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_timer_correctness_OBJECTS) $(lib_test_timer_correctness_LDADD) $(LIBS) +lib/test_timer_performance.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_timer_performance$(EXEEXT): $(lib_test_timer_performance_OBJECTS) $(lib_test_timer_performance_DEPENDENCIES) $(EXTRA_lib_test_timer_performance_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_timer_performance$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_timer_performance_OBJECTS) $(lib_test_timer_performance_LDADD) $(LIBS) +lib/test_ttable.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_ttable$(EXEEXT): $(lib_test_ttable_OBJECTS) $(lib_test_ttable_DEPENDENCIES) $(EXTRA_lib_test_ttable_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_ttable$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_ttable_OBJECTS) $(lib_test_ttable_LDADD) $(LIBS) +lib/lib_test_zmq-test_zmq.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_zmq$(EXEEXT): $(lib_test_zmq_OBJECTS) $(lib_test_zmq_DEPENDENCIES) $(EXTRA_lib_test_zmq_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_zmq$(EXEEXT) + $(AM_V_CCLD)$(lib_test_zmq_LINK) $(lib_test_zmq_OBJECTS) $(lib_test_zmq_LDADD) $(LIBS) +ospf6d/$(am__dirstamp): + @$(MKDIR_P) ospf6d + @: > ospf6d/$(am__dirstamp) +ospf6d/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) ospf6d/$(DEPDIR) + @: > ospf6d/$(DEPDIR)/$(am__dirstamp) +ospf6d/test_lsdb.$(OBJEXT): ospf6d/$(am__dirstamp) \ + ospf6d/$(DEPDIR)/$(am__dirstamp) + +ospf6d/test_lsdb$(EXEEXT): $(ospf6d_test_lsdb_OBJECTS) $(ospf6d_test_lsdb_DEPENDENCIES) $(EXTRA_ospf6d_test_lsdb_DEPENDENCIES) ospf6d/$(am__dirstamp) + @rm -f ospf6d/test_lsdb$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(ospf6d_test_lsdb_OBJECTS) $(ospf6d_test_lsdb_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f bgpd/*.$(OBJEXT) + -rm -f helpers/c/*.$(OBJEXT) + -rm -f isisd/*.$(OBJEXT) + -rm -f lib/*.$(OBJEXT) + -rm -f lib/cli/*.$(OBJEXT) + -rm -f ospf6d/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_aspath.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_capability.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_ecommunity.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_mp_attr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_mpath.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_packet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@helpers/c/$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@helpers/c/$(DEPDIR)/prng.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@isisd/$(DEPDIR)/test_isis_vertex_queue.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/lib_test_zmq-test_zmq.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_buffer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_checksum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_heavy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_heavy_thread.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_heavy_wq.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_memory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_nexthop_iter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_privs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_ringbuf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_segv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_sig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_srcdest_table.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_stream.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_table.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_timer_correctness.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_timer_performance.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_ttable.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/common_cli.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/test_cli.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/test_commands.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/test_commands_defun.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@ospf6d/$(DEPDIR)/test_lsdb.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o: isisd/test_fuzz_isis_tlv.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o -MD -MP -MF isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o `test -f 'isisd/test_fuzz_isis_tlv.c' || echo '$(srcdir)/'`isisd/test_fuzz_isis_tlv.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='isisd/test_fuzz_isis_tlv.c' object='isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o `test -f 'isisd/test_fuzz_isis_tlv.c' || echo '$(srcdir)/'`isisd/test_fuzz_isis_tlv.c + +isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj: isisd/test_fuzz_isis_tlv.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj -MD -MP -MF isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj `if test -f 'isisd/test_fuzz_isis_tlv.c'; then $(CYGPATH_W) 'isisd/test_fuzz_isis_tlv.c'; else $(CYGPATH_W) '$(srcdir)/isisd/test_fuzz_isis_tlv.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='isisd/test_fuzz_isis_tlv.c' object='isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj `if test -f 'isisd/test_fuzz_isis_tlv.c'; then $(CYGPATH_W) 'isisd/test_fuzz_isis_tlv.c'; else $(CYGPATH_W) '$(srcdir)/isisd/test_fuzz_isis_tlv.c'; fi` + +lib/lib_test_zmq-test_zmq.o: lib/test_zmq.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -MT lib/lib_test_zmq-test_zmq.o -MD -MP -MF lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo -c -o lib/lib_test_zmq-test_zmq.o `test -f 'lib/test_zmq.c' || echo '$(srcdir)/'`lib/test_zmq.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo lib/$(DEPDIR)/lib_test_zmq-test_zmq.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib/test_zmq.c' object='lib/lib_test_zmq-test_zmq.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -c -o lib/lib_test_zmq-test_zmq.o `test -f 'lib/test_zmq.c' || echo '$(srcdir)/'`lib/test_zmq.c + +lib/lib_test_zmq-test_zmq.obj: lib/test_zmq.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -MT lib/lib_test_zmq-test_zmq.obj -MD -MP -MF lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo -c -o lib/lib_test_zmq-test_zmq.obj `if test -f 'lib/test_zmq.c'; then $(CYGPATH_W) 'lib/test_zmq.c'; else $(CYGPATH_W) '$(srcdir)/lib/test_zmq.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo lib/$(DEPDIR)/lib_test_zmq-test_zmq.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib/test_zmq.c' object='lib/lib_test_zmq-test_zmq.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -c -o lib/lib_test_zmq-test_zmq.obj `if test -f 'lib/test_zmq.c'; then $(CYGPATH_W) 'lib/test_zmq.c'; else $(CYGPATH_W) '$(srcdir)/lib/test_zmq.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf bgpd/.libs bgpd/_libs + -rm -rf isisd/.libs isisd/_libs + -rm -rf lib/.libs lib/_libs + -rm -rf lib/cli/.libs lib/cli/_libs + -rm -rf ospf6d/.libs ospf6d/_libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f bgpd/$(DEPDIR)/$(am__dirstamp) + -rm -f bgpd/$(am__dirstamp) + -rm -f helpers/c/$(DEPDIR)/$(am__dirstamp) + -rm -f helpers/c/$(am__dirstamp) + -rm -f isisd/$(DEPDIR)/$(am__dirstamp) + -rm -f isisd/$(am__dirstamp) + -rm -f lib/$(DEPDIR)/$(am__dirstamp) + -rm -f lib/$(am__dirstamp) + -rm -f lib/cli/$(DEPDIR)/$(am__dirstamp) + -rm -f lib/cli/$(am__dirstamp) + -rm -f ospf6d/$(DEPDIR)/$(am__dirstamp) + -rm -f ospf6d/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf bgpd/$(DEPDIR) helpers/c/$(DEPDIR) isisd/$(DEPDIR) lib/$(DEPDIR) lib/cli/$(DEPDIR) ospf6d/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf bgpd/$(DEPDIR) helpers/c/$(DEPDIR) isisd/$(DEPDIR) lib/$(DEPDIR) lib/cli/$(DEPDIR) ospf6d/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \ + ctags ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + +.c_clippy.c: + @{ test -x $(top_builddir)/$(HOSTTOOLS)lib/clippy || $(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/clippy; } + $(AM_V_CLIPPY)$(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py -o $@ $< + +.l.c: + $(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $< +.y.c: + $(AM_V_YACC)$(am__skipyacc) $(YACCCOMPILE) $< + +# Rules +@HAVE_PROTOBUF_TRUE@.proto.pb.h: +@HAVE_PROTOBUF_TRUE@ $(Q_PROTOC) -I$(top_srcdir) --cpp_out=$(top_srcdir) $(top_srcdir)/$^ + +@HAVE_PROTOBUF_TRUE@.proto.pb-c.c: +@HAVE_PROTOBUF_TRUE@ $(AM_V_PROTOC_C)$(Q_PROTOC_C) -I$(top_srcdir) --c_out=$(top_srcdir) $(top_srcdir)/$^ +@HAVE_PROTOBUF_TRUE@.pb-c.c.pb-c.h: +@HAVE_PROTOBUF_TRUE@ @/bin/true + +PYTHON ?= python + +lib/cli/test_cli.o: lib/cli/test_cli_clippy.c +ospf6d/test_lsdb.o: ospf6d/test_lsdb_clippy.c + +../vtysh/vtysh_cmd.c: + $(MAKE) -C ../vtysh vtysh_cmd.c + +lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c + sed \ + -e 's/"vtysh\.h"/"tests.h"/' \ + -e 's/vtysh_init_cmd/test_init_cmd/' \ + -e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \ + < ../vtysh/vtysh_cmd.c \ + > "$@" + +isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz + gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@" +isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \ + isisd/test_fuzz_isis_tlv_tests.h + +.PHONY: tests.xml +tests.xml: $(check_PROGRAMS) + $(PYTHON) $(srcdir)/runtests.py --junitxml=$@ -v $(srcdir) +check: tests.xml + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index d2d960f27..b2612892f 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -1074,7 +1074,7 @@ static int validate(struct aspath *as, const struct test_spec *sp) return fails; } -static void empty_get_test() +static void empty_get_test(void) { struct aspath *as = aspath_empty_get(); struct test_spec sp = {"", "", 0, 0, 0, 0, 0, 0}; @@ -1219,7 +1219,7 @@ static void aggregate_test(struct tests *t) } /* cmp_left tests */ -static void cmp_test() +static void cmp_test(void) { unsigned int i; #define CMP_TESTS_MAX (sizeof(left_compare) / sizeof(struct compare_tests)) diff --git a/tests/bgpd/test_peer_attr.py b/tests/bgpd/test_peer_attr.py index bafd131b7..44068605e 100644 --- a/tests/bgpd/test_peer_attr.py +++ b/tests/bgpd/test_peer_attr.py @@ -9,7 +9,7 @@ class TestFlag(frrtest.TestMultiOut): TestFlag.okfail('peer\\advertisement-interval') TestFlag.okfail('peer\\capability dynamic') TestFlag.okfail('peer\\capability extended-nexthop') -TestFlag.okfail('peer\\capability extended-nexthop') +#TestFlag.okfail('peer\\capability extended-nexthop') TestFlag.okfail('peer\\description') TestFlag.okfail('peer\\disable-connected-check') TestFlag.okfail('peer\\dont-capability-negotiate') diff --git a/tests/helpers/c/main.c b/tests/helpers/c/main.c index 768cf296a..11db2dabc 100644 --- a/tests/helpers/c/main.c +++ b/tests/helpers/c/main.c @@ -26,7 +26,7 @@ #include "memory.h" #include "memory_vty.h" -extern void test_init(); +extern void test_init(void); struct thread_master *master; @@ -56,12 +56,12 @@ static int test_timer(struct thread *thread) return 0; } -static void test_timer_init() +static void test_timer_init(void) { thread_add_timer(master, test_timer, &timer_count, 10, NULL); } -static void test_vty_init() +static void test_vty_init(void) { install_element(VIEW_NODE, &daemon_exit_cmd); } diff --git a/tests/lib/cxxcompat.c b/tests/lib/cxxcompat.c new file mode 100644 index 000000000..530468642 --- /dev/null +++ b/tests/lib/cxxcompat.c @@ -0,0 +1,113 @@ +/* + * C++ compatibility compile-time smoketest + * Copyright (C) 2019 David Lamparter for NetDEF, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "lib/zebra.h" + +#include "lib/agg_table.h" +#include "lib/bfd.h" +#include "lib/bitfield.h" +#include "lib/buffer.h" +#include "lib/checksum.h" +#include "lib/command.h" +#include "lib/command_graph.h" +#include "lib/command_match.h" +#include "lib/compiler.h" +#include "lib/csv.h" +#include "lib/debug.h" +#include "lib/distribute.h" +#include "lib/event_counter.h" +#include "lib/ferr.h" +#include "lib/fifo.h" +#include "lib/filter.h" +#include "lib/frr_pthread.h" +#include "lib/frratomic.h" +#include "lib/frrstr.h" +#include "lib/getopt.h" +#include "lib/graph.h" +#include "lib/hash.h" +#include "lib/hook.h" +#include "lib/id_alloc.h" +#include "lib/if.h" +#include "lib/if_rmap.h" +#include "lib/imsg.h" +#include "lib/ipaddr.h" +#include "lib/jhash.h" +#include "lib/json.h" +#include "lib/keychain.h" +#include "lib/lib_errors.h" +#include "lib/libfrr.h" +#include "lib/libospf.h" +#include "lib/linklist.h" +#include "lib/log.h" +#include "lib/logicalrouter.h" +#include "lib/md5.h" +#include "lib/memory.h" +#include "lib/memory_vty.h" +#include "lib/mlag.h" +#include "lib/module.h" +#include "lib/monotime.h" +#include "lib/mpls.h" +#include "lib/network.h" +#include "lib/nexthop.h" +#include "lib/nexthop_group.h" +#include "lib/northbound.h" +#include "lib/northbound_cli.h" +#include "lib/northbound_db.h" +#include "lib/ns.h" +#include "lib/openbsd-tree.h" +#include "lib/pbr.h" +#include "lib/plist.h" +#include "lib/pqueue.h" +#include "lib/prefix.h" +#include "lib/privs.h" +#include "lib/ptm_lib.h" +#include "lib/pw.h" +#include "lib/qobj.h" +#include "lib/queue.h" +#include "lib/ringbuf.h" +#include "lib/routemap.h" +#include "lib/sbuf.h" +#include "lib/sha256.h" +#include "lib/sigevent.h" +#include "lib/skiplist.h" +#include "lib/sockopt.h" +#include "lib/sockunion.h" +#include "lib/spf_backoff.h" +#include "lib/srcdest_table.h" +#include "lib/stream.h" +#include "lib/table.h" +#include "lib/termtable.h" +#include "lib/thread.h" +#include "lib/vector.h" +#include "lib/vlan.h" +#include "lib/vrf.h" +#include "lib/vty.h" +#include "lib/vxlan.h" +#include "lib/wheel.h" +/* #include "lib/workqueue.h" -- macro problem with STAILQ_LAST */ +#include "lib/yang.h" +#include "lib/yang_translator.h" +#include "lib/yang_wrappers.h" +#include "lib/zassert.h" +#include "lib/zclient.h" + +int main(int argc, char **argv) +{ + return 0; +} diff --git a/tests/lib/test_heavy.c b/tests/lib/test_heavy.c index e2a0a2d49..afc7a08e6 100644 --- a/tests/lib/test_heavy.c +++ b/tests/lib/test_heavy.c @@ -92,12 +92,12 @@ DEFUN (clear_foo, return CMD_SUCCESS; } -static void slow_vty_init() +static void slow_vty_init(void) { install_element(VIEW_NODE, &clear_foo_cmd); } -void test_init() +void test_init(void) { slow_vty_init(); } diff --git a/tests/lib/test_heavy_thread.c b/tests/lib/test_heavy_thread.c index b3c6e4c2f..d516ed0de 100644 --- a/tests/lib/test_heavy_thread.c +++ b/tests/lib/test_heavy_thread.c @@ -122,7 +122,7 @@ DEFUN (clear_foo, return CMD_SUCCESS; } -void test_init() +void test_init(void) { install_element(VIEW_NODE, &clear_foo_cmd); } diff --git a/tests/lib/test_heavy_wq.c b/tests/lib/test_heavy_wq.c index 00ddc836d..442b8c838 100644 --- a/tests/lib/test_heavy_wq.c +++ b/tests/lib/test_heavy_wq.c @@ -139,7 +139,7 @@ DEFUN (clear_foo, return CMD_SUCCESS; } -static int heavy_wq_init() +static int heavy_wq_init(void) { heavy_wq = work_queue_new(master, "heavy_work_queue"); @@ -152,7 +152,7 @@ static int heavy_wq_init() return 0; } -void test_init() +void test_init(void) { install_element(VIEW_NODE, &clear_foo_cmd); heavy_wq_init(); diff --git a/tests/lib/test_srcdest_table.c b/tests/lib/test_srcdest_table.c index 959358bbe..5c0e17177 100644 --- a/tests/lib/test_srcdest_table.c +++ b/tests/lib/test_srcdest_table.c @@ -195,10 +195,10 @@ static void test_state_del_route(struct test_state *test, XFREE(MTYPE_TMP, hash_entry_intern); } -static void verify_log(struct hash_backet *backet, void *arg) +static void verify_log(struct hash_bucket *bucket, void *arg) { struct test_state *test = arg; - struct prefix *hash_entry = backet->data; + struct prefix *hash_entry = bucket->data; struct prefix *dst_p = &hash_entry[0]; struct prefix_ipv6 *src_p = (struct prefix_ipv6 *)&hash_entry[1]; struct route_node *rn = srcdest_rnode_lookup(test->table, dst_p, src_p); @@ -209,9 +209,9 @@ static void verify_log(struct hash_backet *backet, void *arg) route_unlock_node(rn); } -static void dump_log(struct hash_backet *backet, void *arg) +static void dump_log(struct hash_bucket *bucket, void *arg) { - struct prefix *hash_entry = backet->data; + struct prefix *hash_entry = bucket->data; struct prefix_ipv6 *dst_p = (struct prefix_ipv6 *)&hash_entry[0]; struct prefix_ipv6 *src_p = (struct prefix_ipv6 *)&hash_entry[1]; char *route_id = format_srcdest(dst_p, src_p); diff --git a/tests/lib/test_table.c b/tests/lib/test_table.c index 2c2a01053..2b6504062 100644 --- a/tests/lib/test_table.c +++ b/tests/lib/test_table.c @@ -402,7 +402,7 @@ static void verify_prefix_iter_cmp(const char *p1, const char *p2, * * Tests comparision of prefixes according to order of iteration. */ -static void test_prefix_iter_cmp() +static void test_prefix_iter_cmp(void) { printf("\n\nTesting route_table_prefix_iter_cmp()\n"); diff --git a/tests/subdir.am b/tests/subdir.am index 7d2800a3a..365fe00cc 100644 --- a/tests/subdir.am +++ b/tests/subdir.am @@ -46,6 +46,7 @@ tests/ospf6d/tests_ospf6d_test_lsdb-test_lsdb.$(OBJEXT): tests/ospf6d/test_lsdb_ tests/ospf6d/test_lsdb-test_lsdb.$(OBJEXT): tests/ospf6d/test_lsdb_clippy.c check_PROGRAMS = \ + tests/lib/cxxcompat \ tests/lib/test_buffer \ tests/lib/test_checksum \ tests/lib/test_heavy_thread \ @@ -112,10 +113,13 @@ TESTS_CPPFLAGS = $(AM_CPPFLAGS) \ -I$(top_srcdir)/tests/helpers/c \ -I$(top_builddir)/tests/helpers/c \ # end -TESTS_CFLAGS = $(SAN_FLAGS) +TESTS_CFLAGS = \ + $(LIBYANG_CFLAGS) \ + $(SAN_FLAGS) \ + # end # note no -Werror -ALL_TESTS_LDADD = lib/libfrr.la @LIBCAP@ +ALL_TESTS_LDADD = lib/libfrr.la $(LIBCAP) BGP_TEST_LDADD = bgpd/libbgp.a $(RFPLDADD) $(ALL_TESTS_LDADD) -lm ISISD_TEST_LDADD = isisd/libisis.a $(ALL_TESTS_LDADD) OSPF6_TEST_LDADD = ospf6d/libospf6.a $(ALL_TESTS_LDADD) @@ -167,6 +171,10 @@ tests_isisd_test_isis_vertex_queue_CPPFLAGS = $(TESTS_CPPFLAGS) tests_isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD) tests_isisd_test_isis_vertex_queue_SOURCES = tests/isisd/test_isis_vertex_queue.c +tests_lib_cxxcompat_CFLAGS = $(TESTS_CFLAGS) $(CXX_COMPAT_CFLAGS) $(WERROR) +tests_lib_cxxcompat_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_cxxcompat_SOURCES = tests/lib/cxxcompat.c +tests_lib_cxxcompat_LDADD = $(ALL_TESTS_LDADD) tests_lib_cli_test_cli_CFLAGS = $(TESTS_CFLAGS) tests_lib_cli_test_cli_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD) diff --git a/tests/topotests/GUIDELINES.md b/tests/topotests/GUIDELINES.md deleted file mode 100644 index 4bd373796..000000000 --- a/tests/topotests/GUIDELINES.md +++ /dev/null @@ -1,571 +0,0 @@ -# Guidelines - -This document describes how to use the topotests testing framework. - - -## Executing Tests - -To run the whole suite of tests the following commands must be executed at the -top level directory of topotest: - -```shell -$ # Change to the top level directory of topotests. -$ cd path/to/topotests -$ # Tests must be run as root, since Mininet requires it. -$ sudo pytest -``` - -In order to run a specific test, you can use the following command: - -```shell -$ # running a specific topology -$ sudo pytest ospf-topo1/ -$ # or inside the test folder -$ cd ospf-topo1 -$ sudo pytest # to run all tests inside the directory -$ sudo pytest test_ospf_topo1.py # to run a specific test -$ # or outside the test folder -$ cd .. -$ sudo pytest ospf-topo1/test_ospf_topo1.py # to run a specific one -``` - -The output of the tested daemons will be available at the temporary folder of -your machine: - -```shell -$ ls /tmp/topotest/ospf-topo1.test_ospf-topo1/r1 -... -zebra.err # zebra stderr output -zebra.log # zebra log file -zebra.out # zebra stdout output -... -``` - -You can also run memory leak tests to get reports: - -```shell -$ # Set the environment variable to apply to a specific test... -$ sudo env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py -$ # ...or apply to all tests adding this line to the configuration file -$ echo 'memleak_path = /tmp/memleak_report_' >> pytest.ini -$ # You can also use your editor -$ $EDITOR pytest.ini -$ # After running tests you should see your files: -$ ls /tmp/memleak_report_* -memleak_report_test_ospf_topo1.txt -``` - - -## Writing a New Test - -This section will guide you in all recommended steps to produce a standard -topology test. - -This is the recommended test writing routine: - -* Write a topology (Graphviz recommended) -* Obtain configuration files -* Write the test itself -* Create a Pull Request - - -### Topotest File Hierarchy - -Before starting to write any tests one must know the file hierarchy. The -repository hierarchy looks like this: - -```shell -$ cd path/to/topotest -$ find ./* -... -./README.md # repository read me -./GUIDELINES.md # this file -./conftest.py # test hooks - pytest related functions -./example-test # example test folder -./example-test/__init__.py # python package marker - must always exist. -./example-test/test_template.jpg # generated topology picture - see next section -./example-test/test_template.dot # Graphviz dot file -./example-test/test_template.py # the topology plus the test -... -./ospf-topo1 # the ospf topology test -./ospf-topo1/r1 # router 1 configuration files -./ospf-topo1/r1/zebra.conf # zebra configuration file -./ospf-topo1/r1/ospfd.conf # ospf configuration file -./ospf-topo1/r1/ospfroute.txt # 'show ip ospf' output reference file -# removed other for shortness sake -... -./lib # shared test/topology functions -./lib/topogen.py # topogen implementation -./lib/topotest.py # topotest implementation -``` - -Guidelines for creating/editing topotest: - -* New topologies that don't fit the existing directories should create its own -* Always remember to add the `__init__.py` to new folders, this makes auto - complete engines and pylint happy -* Router (Quagga/FRR) specific code should go on topotest.py -* Generic/repeated router actions should have an abstraction in - topogen.TopoRouter. -* Generic/repeated non-router code should go to topotest.py -* pytest related code should go to conftest.py (e.g. specialized asserts) - - -### Defining the Topology - -The first step to write a new test is to define the topology. This step can be -done in many ways, but the recommended is to use Graphviz to generate a drawing -of the Topology. It allows us to see the topology graphically and to see the -names of equipments, links and addresses. - -Here is an example of Graphviz dot file that generates the -[template topology](example-test/test_template.dot) (the inlined code might get -outdated, please see the linked file): - -```dot -graph template { - label="template"; - - # Routers - r1 [ - shape=doubleoctagon, - label="r1", - fillcolor="#f08080", - style=filled, - ]; - r2 [ - shape=doubleoctagon, - label="r2", - fillcolor="#f08080", - style=filled, - ]; - - # Switches - s1 [ - shape=oval, - label="s1\n192.168.0.0/24", - fillcolor="#d0e0d0", - style=filled, - ]; - s2 [ - shape=oval, - label="s2\n192.168.1.0/24", - fillcolor="#d0e0d0", - style=filled, - ]; - - # Connections - r1 -- s1 [label="eth0\n.1"]; - - r1 -- s2 [label="eth1\n.100"]; - r2 -- s2 [label="eth0\n.1"]; -} -``` - -Here is the produced graph: - -![template topology graph](example-test/test_template.jpg) - - -### Generating / Obtaining Configuration Files - -In order to get the configuration files or command output for each router, we -need to run the topology and execute commands in vtysh. The quickest way to -achieve that is writing the topology building code and running the topology. - -To bootstrap your test topology, do the following steps: - -* Copy the template test - -```shell -$ mkdir new-topo/ -$ touch new-topo/__init__.py -$ cp example-test/test_template.py new-topo/test_new_topo.py -``` - -* Modify the template according to your dot file - -Here is the template topology described in the previous section in python code: - -```py -class TemplateTopo(Topo): - "Test topology builder" - def build(self, *_args, **_opts): - "Build function" - tgen = get_topogen(self) - - # Create 2 routers - for routern in range(1, 3): - tgen.add_router('r{}'.format(routern)) - - # Create a switch with just one router connected to it to simulate a - # empty network. - switch = tgen.add_switch('s1') - switch.add_link(tgen.gears['r1']) - - # Create a connection between r1 and r2 - switch = tgen.add_switch('s2') - switch.add_link(tgen.gears['r1']) - switch.add_link(tgen.gears['r2']) -``` - -* Run the topology - -Topogen allows us to run the topology without running any tests, you can do that -using the following example commands: - -```shell -$ # Running your bootstraped topology -$ sudo pytest -s --topology-only new-topo/test_new_topo.py -$ # Running the test_template.py topology -$ sudo pytest -s --topology-only example-test/test_template.py -$ # Running the ospf_topo1.py topology -$ sudo pytest -s --topology-only ospf-topo1/test_ospf_topo1.py -``` - -Parameters explanation: - -* `-s`: actives input/output capture. This is required by mininet in order to show - the interactive shell. -* `--topology-only`: don't run any tests, just build the topology. - -After executing the commands above, you should get the following terminal -output: - -```shell -=== test session starts === -platform linux2 -- Python 2.7.12, pytest-3.1.2, py-1.4.34, pluggy-0.4.0 -rootdir: /media/sf_src/topotests, inifile: pytest.ini -collected 3 items - -ospf-topo1/test_ospf_topo1.py *** Starting controller - -*** Starting 6 switches -switch1 switch2 switch3 switch4 switch5 switch6 ... -r2: frr zebra started -r2: frr ospfd started -r3: frr zebra started -r3: frr ospfd started -r1: frr zebra started -r1: frr ospfd started -r4: frr zebra started -r4: frr ospfd started -*** Starting CLI: -mininet> -``` - -The last line shows us that we are now using the Mininet CLI (Command Line -Interface), from here you can call your router vtysh or even bash. - -Here are some commands example: - -```shell -mininet> r1 ping 10.0.3.1 -PING 10.0.3.1 (10.0.3.1) 56(84) bytes of data. -64 bytes from 10.0.3.1: icmp_seq=1 ttl=64 time=0.576 ms -64 bytes from 10.0.3.1: icmp_seq=2 ttl=64 time=0.083 ms -64 bytes from 10.0.3.1: icmp_seq=3 ttl=64 time=0.088 ms -^C ---- 10.0.3.1 ping statistics --- -3 packets transmitted, 3 received, 0% packet loss, time 1998ms -rtt min/avg/max/mdev = 0.083/0.249/0.576/0.231 ms - - - -mininet> r1 ping 10.0.3.3 -PING 10.0.3.3 (10.0.3.3) 56(84) bytes of data. -64 bytes from 10.0.3.3: icmp_seq=1 ttl=64 time=2.87 ms -64 bytes from 10.0.3.3: icmp_seq=2 ttl=64 time=0.080 ms -64 bytes from 10.0.3.3: icmp_seq=3 ttl=64 time=0.091 ms -^C ---- 10.0.3.3 ping statistics --- -3 packets transmitted, 3 received, 0% packet loss, time 2003ms -rtt min/avg/max/mdev = 0.080/1.014/2.872/1.313 ms - - - -mininet> r3 vtysh - -Hello, this is FRRouting (version 3.1-devrzalamena-build). -Copyright 1996-2005 Kunihiro Ishiguro, et al. - -frr-1# show running-config -Building configuration... - -Current configuration: -! -frr version 3.1-devrzalamena-build -frr defaults traditional -hostname r3 -no service integrated-vtysh-config -! -log file zebra.log -! -log file ospfd.log -! -interface r3-eth0 - ip address 10.0.3.1/24 -! -interface r3-eth1 - ip address 10.0.10.1/24 -! -interface r3-eth2 - ip address 172.16.0.2/24 -! -router ospf - ospf router-id 10.0.255.3 - redistribute kernel - redistribute connected - redistribute static - network 10.0.3.0/24 area 0 - network 10.0.10.0/24 area 0 - network 172.16.0.0/24 area 1 -! -line vty -! -end -frr-1# -``` - -After you successfully configured your topology, you can obtain the -configuration files (per-daemon) using the following commands: - -```shell -mininet> r3 vtysh -d ospfd - -Hello, this is FRRouting (version 3.1-devrzalamena-build). -Copyright 1996-2005 Kunihiro Ishiguro, et al. - -frr-1# show running-config -Building configuration... - -Current configuration: -! -frr version 3.1-devrzalamena-build -frr defaults traditional -no service integrated-vtysh-config -! -log file ospfd.log -! -router ospf - ospf router-id 10.0.255.3 - redistribute kernel - redistribute connected - redistribute static - network 10.0.3.0/24 area 0 - network 10.0.10.0/24 area 0 - network 172.16.0.0/24 area 1 -! -line vty -! -end -frr-1# -``` - - -### Writing Tests - -Test topologies should always be bootstrapped from the -[example-test/test_template.py](example-test/test_template.py), -because it contains important boilerplate code that can't be avoided, like: - -* imports: os, sys, pytest, topotest/topogen and mininet topology class -* The global variable CWD (Current Working directory): which is most likely - going to be used to reference the routers configuration file location - - Example: - -```py -# For all registered routers, load the zebra configuration file -for rname, router in router_list.iteritems(): - router.load_config( - TopoRouter.RD_ZEBRA, - os.path.join(CWD, '{}/zebra.conf'.format(rname)) - ) - # os.path.join() joins the CWD string with arguments adding the necessary - # slashes ('/'). Arguments must not begin with '/'. -``` - -* The topology class that inherits from Mininet Topo class - -```py -class TemplateTopo(Topo): - def build(self, *_args, **_opts): - tgen = get_topogen(self) - # topology build code -``` - -* pytest `setup_module()` and `teardown_module()` to start the topology - -```py -def setup_module(_m): - tgen = Topogen(TemplateTopo) - tgen.start_topology('debug') - -def teardown_module(_m): - tgen = get_topogen() - tgen.stop_topology() -``` - -* `__main__` initialization code (to support running the script directly) - -```py -if __name__ == '__main__': - sys.exit(pytest.main(["-s"])) -``` - -Requirements: - -* Test code should always be declared inside functions that begin with the - `test_` prefix. Functions beginning with different prefixes will not be run by - pytest. -* Configuration files and long output commands should go into separated files - inside folders named after the equipment. -* Tests must be able to run without any interaction. To make sure your test - conforms with this, run it without the `-s` parameter. - -Tips: - -* Keep results in stack variables, so people inspecting code with `pdb` can - easily print their values. - - Don't do this: - - ```py - assert foobar(router1, router2) - ``` - - Do this instead: - - ```py - result = foobar(router1, router2) - assert result - ``` - -* Use `assert` messages to indicate where the test failed. - - Example: - - ```py - for router in router_list: - # ... - assert condition, 'Router "{}" condition failed'.format(router.name) - ``` - - -### Debugging Execution - -The most effective ways to inspect topology tests are: - -* Run pytest with `--pdb` option. This option will cause a pdb shell to appear - when an assertion fails - - Example: `pytest -s --pdb ospf-topo1/test_ospf_topo1.py` - -* Set a breakpoint in the test code with `pdb` - - Example: - -```py -# Add the pdb import at the beginning of the file -import pdb -# ... - -# Add a breakpoint where you think the problem is -def test_bla(): - # ... - pdb.set_trace() - # ... -``` - -The [Python Debugger](https://docs.python.org/2.7/library/pdb.html) (pdb) shell -allows us to run many useful operations like: - -* Setting breaking point on file/function/conditions (e.g. `break`, `condition`) -* Inspecting variables (e.g. `p` (print), `pp` (pretty print)) -* Running python code - -TIP: The TopoGear (equipment abstraction class) implements the `__str__` method -that allows the user to inspect equipment information. - -Example of pdb usage: - -```shell -> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(121)test_ospf_convergence() --> for rnum in range(1, 5): -(Pdb) help -Documented commands (type help <topic>): -======================================== -EOF bt cont enable jump pp run unt -a c continue exit l q s until -alias cl d h list quit step up -args clear debug help n r tbreak w -b commands disable ignore next restart u whatis -break condition down j p return unalias where - -Miscellaneous help topics: -========================== -exec pdb - -Undocumented commands: -====================== -retval rv - -(Pdb) list -116 title2="Expected output") -117 -118 def test_ospf_convergence(): -119 "Test OSPF daemon convergence" -120 pdb.set_trace() -121 -> for rnum in range(1, 5): -122 router = 'r{}'.format(rnum) -123 -124 # Load expected results from the command -125 reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) -126 expected = open(reffile).read() -(Pdb) step -> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(122)test_ospf_convergence() --> router = 'r{}'.format(rnum) -(Pdb) step -> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(125)test_ospf_convergence() --> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) -(Pdb) print rnum -1 -(Pdb) print router -r1 -(Pdb) tgen = get_topogen() -(Pdb) pp tgen.gears[router] -<lib.topogen.TopoRouter object at 0x7f74e06c9850> -(Pdb) pp str(tgen.gears[router]) -'TopoGear<name="r1",links=["r1-eth0"<->"s1-eth0","r1-eth1"<->"s3-eth0"]> TopoRouter<>' -(Pdb) l 125 -120 pdb.set_trace() -121 for rnum in range(1, 5): -122 router = 'r{}'.format(rnum) -123 -124 # Load expected results from the command -125 -> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) -126 expected = open(reffile).read() -127 -128 # Run test function until we get an result. Wait at most 60 seconds. -129 test_func = partial(compare_show_ip_ospf, router, expected) -130 result, diff = topotest.run_and_expect(test_func, '', -(Pdb) router1 = tgen.gears[router] -(Pdb) router1.vtysh_cmd('show ip ospf route') -'============ OSPF network routing table ============\r\nN 10.0.1.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth0\r\nN 10.0.2.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.3, r1-eth1\r\nN 10.0.3.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth1\r\nN 10.0.10.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.0.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.1.0/24 [30] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF router routing table =============\r\nR 10.0.255.2 [10] area: 0.0.0.0, ASBR\r\n via 10.0.3.3, r1-eth1\r\nR 10.0.255.3 [10] area: 0.0.0.0, ABR, ASBR\r\n via 10.0.3.1, r1-eth1\r\nR 10.0.255.4 IA [20] area: 0.0.0.0, ASBR\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF external routing table ===========\r\n\r\n\r\n' -(Pdb) tgen.mininet_cli() -*** Starting CLI: -mininet> -``` - -To enable more debug messages in other Topogen subsystems (like Mininet), more -logging messages can be displayed by modifying the test configuration file -`pytest.ini`: - -```ini -[topogen] -# Change the default verbosity line from 'info'... -#verbosity = info -# ...to 'debug' -verbosity = debug -``` diff --git a/tests/topotests/README.md b/tests/topotests/README.md index a495675ee..d9d849b39 100644 --- a/tests/topotests/README.md +++ b/tests/topotests/README.md @@ -1,199 +1 @@ -# FRRouting Topology Tests with Mininet - -## Running tests with docker - -There is a docker image which allows to run topotests. Instructions can be -found [here](docker/README.md). - -## Guidelines - -Instructions for use, write or debug topologies can be found in the -[guidelines](GUIDELINES.md). To learn/remember common code snippets see -[here](SNIPPETS.md). - -Before creating a new topology, make sure that there isn't one already -that does what you need. If nothing is similar, then you may create a -new topology, preferably, using the newest -[template](example-test/test_template.py). - -## Installation of Mininet for running tests -Only tested with Ubuntu 16.04 and Ubuntu 18.04 (which uses Mininet 2.2.x) - -Instructions are the same for all setups (ie ExaBGP is only used for BGP -tests) - -### Installing Mininet Infrastructure: - -1. apt-get install mininet -2. apt-get install python-pip -3. apt-get install iproute -4. pip install ipaddr -5. pip install pytest -6. pip install exabgp==3.4.17 - (Newer 4.0 version of exabgp is not yet supported) -7. useradd -d /var/run/exabgp/ -s /bin/false exabgp - -### Enable Coredumps -Optional, will give better output - -1. apt-get install gdb -2. disable apport (which move core files) - - Set `enabled=0` in `/etc/default/apport` - -3. Update security limits - - Add/change `/etc/security/limits.conf` to - - #<domain> <type> <item> <value> - * soft core unlimited - root soft core unlimited - * hard core unlimited - root hard core unlimited - -4. reboot (for options to take effect) - -## FRRouting (FRR) Installation -FRR needs to be installed separatly. It is assume to be configured -like the standard Ubuntu Packages: - -- Binaries in /usr/lib/frr -- State Directory /var/run/frr -- Running under user frr, group frr -- vtygroup: frrvty -- config directory: /etc/frr -- For FRR Packages, install the dbg package as well for coredump decoding - -No FRR config needs to be done and no FRR daemons should be run ahead -of the test. They are all started as part of the test - -#### Manual FRRouting (FRR) build - -If you prefer to manually build FRR, then use the following suggested config: - - ./configure \ - --prefix=/usr \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - --enable-vtysh \ - --enable-pimd \ - --enable-multipath=64 \ - --enable-user=frr \ - --enable-group=frr \ - --enable-vty-group=frrvty \ - --with-pkg-extra-version=-my-manual-build - -And create frr User and frrvty group as follows: - - addgroup --system --gid 92 frr - addgroup --system --gid 85 frrvty - adduser --system --ingroup frr --home /var/run/frr/ \ - --gecos "FRRouting suite" --shell /bin/false frr - usermod -G frrvty frr - -## Executing Tests - -#### Execute all tests with output to console - - py.test -s -v --tb=no - -All test_* scripts in subdirectories are detected and executed (unless -disabled in `pytest.ini` file) - -`--tb=no` disables the python traceback which might be irrelevant unless the -test script itself is debugged - -#### Execute single test - - cd test_to_be_run - ./test_to_be_run.py - -For further options, refer to pytest documentation - -Test will set exit code which can be used with `git bisect` - -For the simulated topology, see the description in the python file - -If you need to clear the mininet setup between tests (if it isn't cleanly -shutdown), then use the `mn -c` command to clean up the environment - -#### (Optional) StdErr log from daemos after exit - -To enable the reporting of any messages seen on StdErr after the -daemons exit, the following env variable can be set. - - export TOPOTESTS_CHECK_STDERR=Yes - -(The value doesn't matter at this time. The check is if the env variable -exists or not) -There is no pass/fail on this reporting. The Output will be reported to -the console - - export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" - -This will enable the check and output to console and the writing of -the information to files with the given prefix (followed by testname), -ie `/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a -memory leak. - -#### (Optional) Collect Memory Leak Information - -FreeRangeRouting processes have the capabilities to report remaining memory -allocations upon exit. To enable the reporting of the memory, define an -enviroment variable `TOPOTESTS_CHECK_MEMLEAK` with the file prefix, ie - - export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" - -This will enable the check and output to console and the writing of -the information to files with the given prefix (followed by testname), -ie `/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a -memory leak. - -#### (Optional) Run topotests with GCC AddressSanitizer enabled - -Topotests can be run with the GCC AddressSanitizer. It requires GCC 4.8 or -newer. (Ubuntu 16.04 as suggested here is fine with GCC 5 as default) -For more information on AddressSanitizer, see -https://github.com/google/sanitizers/wiki/AddressSanitizer - -The checks are done automatically in the library call of `checkRouterRunning` -(ie at beginning of tests when there is a check for all daemons running). -No changes or extra configuration for topotests is required beside compiling -the suite with AddressSanitizer enabled. - -If a daemon crashed, then the errorlog is checked for AddressSanitizer -output. If found, then this is added with context (calling test) to -`/tmp/AddressSanitizer.txt` in markdown compatible format. - -Compiling for GCC AddressSanitizer requires to use gcc as a linker as well -(instead of ld). Here is a suggest way to compile frr with AddressSanitizer -for `stable/3.0` branch: - - git clone https://github.com/FRRouting/frr.git - cd frr - git checkout stable/3.0 - ./bootstrap.sh - export CC=gcc - export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer" - export LD=gcc - export LDFLAGS="-g -fsanitize=address -ldl" - ./configure --enable-shared=no \ - --prefix=/usr/lib/frr --sysconfdir=/etc/frr \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr --bindir=/usr/lib/frr \ - --enable-exampledir=/usr/lib/frr/examples \ - --with-moduledir=/usr/lib/frr/modules \ - --enable-multipath=0 --enable-rtadv \ - --enable-tcp-zebra --enable-fpm --enable-pimd - make - sudo make install - # Create symlink for vtysh, so topotest finds it in /usr/lib/frr - sudo ln -s /usr/lib/frr/vtysh /usr/bin/ - -and create `frr` user and `frrvty` group as shown above - -## License - -All the configs and scripts are licensed under a ISC-style license. See -Python scripts for details. +Documentation is located in /doc/developer/topotests.rst diff --git a/tests/topotests/SNIPPETS.md b/tests/topotests/SNIPPETS.md deleted file mode 100644 index 6c16c44af..000000000 --- a/tests/topotests/SNIPPETS.md +++ /dev/null @@ -1,275 +0,0 @@ -# Snippets - -This document will describe common snippets of code that are frequently -needed to perform some test checks. - - -## Checking for router / test failures - -The following check uses the topogen API to check for software failure -(e.g. zebra died) and/or for errors manually set by `Topogen.set_error()`. - -```py -# Get the topology reference -tgen = get_topogen() - -# Check for errors in the topology -if tgen.routers_have_failure(): - # Skip the test with the topology errors as reason - pytest.skip(tgen.errors) -``` - - -## Checking FRR routers version - -This code snippet is usually run after the topology setup to make sure -all routers instantiated in the topology have the correct software -version. - -```py -# Get the topology reference -tgen = get_topogen() - -# Get the router list -router_list = tgen.routers() - -# Run the check for all routers -for router in router_list.values(): - if router.has_version('<', '3'): - # Set topology error, so the next tests are skipped - tgen.set_error('unsupported version') -``` - -A sample of this snippet in a test can be found -[here](ldp-vpls-topo1/test_ldp_vpls_topo1.py). - - -## Interacting with equipments - -You might want to interact with the topology equipments during the tests -and there are different ways to do so. - -Notes: - -1. -> When using the Topogen API, all the equipments code derive from -> `Topogear` ([lib/topogen.py](lib/topogen.py)). If you feel brave you -> can look by yourself how the abstractions that will be mentioned here -> works. - -2. -> When not using the `Topogen` API there is only one way to interact -> with the equipments, which is by calling the `mininet` API functions -> directly to spawn commands. - - -### Interacting with the Linux sandbox - -*Without `Topogen`* - -```py -global net -output = net['r1'].cmd('echo "foobar"') -print 'output is: {}'.format(output) -``` - ---- - -*With `Topogen`* - -```py -tgen = get_topogen() -output = tgen.gears['r1'].run('echo "foobar"') -print 'output is: {}'.format(output) -``` - - -### Interacting with VTYSH - -*Without `Topogen`* - -```py -global net -output = net['r1'].cmd('vtysh "show ip route" 2>/dev/null') -print 'output is: {}'.format(output) -``` - ---- - -*With `Topogen`* - -```py -tgen = get_topogen() -output = tgen.gears['r1'].vtysh_cmd("show ip route") -print 'output is: {}'.format(output) -``` - -`Topogen` also supports sending multiple lines of command: - -```py -tgen = get_topogen() -output = tgen.gears['r1'].vtysh_cmd(""" -configure terminal -router bgp 10 - bgp router-id 10.0.255.1 - neighbor 1.2.3.4 remote-as 10 - ! -router bgp 11 - bgp router-id 10.0.255.2 - ! -""") -print 'output is: {}'.format(output) -``` - -You might also want to run multiple commands and get only the commands -that failed: - -```py -tgen = get_topogen() -output = tgen.gears['r1'].vtysh_multicmd(""" -configure terminal -router bgp 10 - bgp router-id 10.0.255.1 - neighbor 1.2.3.4 remote-as 10 - ! -router bgp 11 - bgp router-id 10.0.255.2 - ! -""", pretty_output=false) -print 'output is: {}'.format(output) -``` - -Translating vtysh JSON output into Python structures: -```py -tgen = get_topogen() -json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True) -output = json.dumps(json_output, indent=4) -print 'output is: {}'.format(output) - -# You can also access the data structure as normal. For example: -# protocol = json_output['1.1.1.1/32']['protocol'] -# assert protocol == "ospf", "wrong protocol" -``` - -*NOTE:* `vtysh_(multi)cmd` is only available for router type of -equipments. - - -### Invoking `mininet` CLI - -*Without `Topogen`* - -```py -CLI(net) -``` - ---- - -*With `Topogen`* -```py -tgen = get_topogen() -tgen.mininet_cli() -``` - - -## Reading files - -Loading a normal text file content in the current directory: - -```py -# If you are using Topogen -# CURDIR = CWD -# -# Otherwise find the directory manually: -CURDIR = os.path.dirname(os.path.realpath(__file__)) - -file_name = '{}/r1/show_ip_route.txt'.format(CURDIR) -file_content = open(file_name).read() -``` - -Loading JSON from a file: - -```py -import json - -file_name = '{}/r1/show_ip_route.json'.format(CURDIR) -file_content = json.loads(open(file_name).read()) -``` - - -## Comparing JSON output - -After obtaining JSON output formated with Python data structures, you -may use it to assert a minimalist schema: - -```py -tgen = get_topogen() -json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True) - -expect = { - '1.1.1.1/32': { - 'protocol': 'ospf' - } -} - -assertmsg = "route 1.1.1.1/32 was not learned through OSPF" -assert json_cmp(json_output, expect) is None, assertmsg -``` - -`json_cmp` function description (it might be outdated, you can find the -latest description in the source code at [lib/topotest.py](lib/topotest.py)): - -```text - JSON compare function. Receives two parameters: - * `d1`: json value - * `d2`: json subset which we expect - - Returns `None` when all keys that `d1` has matches `d2`, - otherwise a string containing what failed. - - Note: key absence can be tested by adding a key with value `None`. -``` - - -## Pausing execution - -Preferably, choose the `sleep` function that `topotest` provides, as it -prints a notice during the test execution to help debug topology test -execution time. - -```py -# Using the topotest sleep -from lib import topotest - -topotest.sleep(10, 'waiting 10 seconds for bla') -# or just tell it the time: -# topotest.sleep(10) -# It will print 'Sleeping for 10 seconds'. - -# Or you can also use the Python sleep, but it won't show anything -from time import sleep -sleep(5) -``` - - -## `ip route` Linux command as JSON - -`topotest` has two helpers implemented that parses the output of -`ip route` commands to JSON. It might simplify your comparison needs by -only needing to provide a Python dictionary. - -```py -from lib import topotest - -tgen = get_topogen() -routes = topotest.ip4_route(tgen.gears['r1']) -expected = { - '10.0.1.0/24': {}, - '10.0.2.0/24': { - 'dev': 'r1-eth0' - } -} - -assertmsg = "failed to find 10.0.1.0/24 and/or 10.0.2.0/24" -assert json_cmp(routes, expected) is None, assertmsg -``` diff --git a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref new file mode 100644 index 000000000..e75d89672 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref @@ -0,0 +1,12 @@ +C>* 192.168.0.0/24 is directly connected, r1-eth0, XX:XX:XX +C>* 192.168.1.0/26 is directly connected, r1-eth1, XX:XX:XX +C>* 192.168.2.0/26 is directly connected, r1-eth2, XX:XX:XX +C>* 192.168.3.0/26 is directly connected, r1-eth3, XX:XX:XX +C>* 192.168.4.0/26 is directly connected, r1-eth4, XX:XX:XX +C>* 192.168.5.0/26 is directly connected, r1-eth5, XX:XX:XX +C>* 192.168.6.0/26 is directly connected, r1-eth6, XX:XX:XX +C>* 192.168.7.0/26 is directly connected, r1-eth7, XX:XX:XX +C>* 192.168.8.0/26 is directly connected, r1-eth8, XX:XX:XX +C>* 192.168.9.0/26 is directly connected, r1-eth9, XX:XX:XX +O 192.168.0.0/24 [110/10] is directly connected, r1-eth0, XX:XX:XX +O 192.168.3.0/26 [110/10] is directly connected, r1-eth3, XX:XX:XX diff --git a/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref new file mode 100644 index 000000000..88cee964d --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref @@ -0,0 +1,22 @@ +C>* fc00:0:0:1::/64 is directly connected, r1-eth1, XX:XX:XX +C>* fc00:0:0:2::/64 is directly connected, r1-eth2, XX:XX:XX +C>* fc00:0:0:3::/64 is directly connected, r1-eth3, XX:XX:XX +C>* fc00:0:0:4::/64 is directly connected, r1-eth4, XX:XX:XX +C>* fc00:0:0:5::/64 is directly connected, r1-eth5, XX:XX:XX +C>* fc00:0:0:6::/64 is directly connected, r1-eth6, XX:XX:XX +C>* fc00:0:0:7::/64 is directly connected, r1-eth7, XX:XX:XX +C>* fc00:0:0:8::/64 is directly connected, r1-eth8, XX:XX:XX +C>* fc00:0:0:9::/64 is directly connected, r1-eth9, XX:XX:XX +C>* fc00::/64 is directly connected, r1-eth0, XX:XX:XX +C>* fe80::/64 is directly connected, lo, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth0, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth1, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth2, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth3, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth4, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth5, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth6, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth7, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth8, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth9, XX:XX:XX +O fc00:0:0:4::/64 [110/10] is directly connected, r1-eth4, XX:XX:XX diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index fb2100e03..239de55bd 100755 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -296,10 +296,53 @@ def test_converge_protocols(): sleep(60) # Make sure that all daemons are running + failures = 0 for i in range(1, 2): fatal_error = net['r%s' % i].checkRouterRunning() assert fatal_error == "", fatal_error + print("Show that v4 routes are right\n"); + v4_routesFile = '%s/r%s/ipv4_routes.ref' % (thisDir, i) + expected = open(v4_routesFile).read().rstrip() + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + actual = net['r%s' %i].cmd('vtysh -c "show ip route" | /usr/bin/tail -n +7 | sort 2> /dev/null').rstrip() + # Drop time in last update + actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + diff = topotest.get_textdiff(actual, expected, + title1="Actual IP Routing Table", + title2="Expected IP RoutingTable") + if diff: + sys.stderr.write('r%s failed IP Routing table check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" %i) + + assert failures == 0, "IP Routing table failed for r%s\n%s" % (i, diff) + + failures = 0 + + print("Show that v6 routes are right\n") + v6_routesFile = '%s/r%s/ipv6_routes.ref' % (thisDir, i) + expected = open(v6_routesFile).read().rstrip() + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + actual = net['r%s' %i].cmd('vtysh -c "show ipv6 route" | /usr/bin/tail -n +7 | sort 2> /dev/null').rstrip() + # Drop time in last update + actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + diff = topotest.get_textdiff(actual, expected, + title1="Actual IPv6 Routing Table", + title2="Expected IPv6 RoutingTable") + if diff: + sys.stderr.write('r%s failed IPv6 Routing table check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" %i) + + assert failures == 0, "IPv6 Routing table failed for r%s\n%s" % (i, diff) + # For debugging after starting FRR/Quagga daemons, uncomment the next line ## CLI(net) diff --git a/tests/topotests/bfd-topo1/test_bfd_topo1.py b/tests/topotests/bfd-topo1/test_bfd_topo1.py index 91904c6aa..4fd4f9743 100644 --- a/tests/topotests/bfd-topo1/test_bfd_topo1.py +++ b/tests/topotests/bfd-topo1/test_bfd_topo1.py @@ -138,7 +138,7 @@ def test_bgp_convergence(): expected = json.loads(open(ref_file).read()) test_func = partial(topotest.router_json_cmp, router, 'show ip bgp summary json', expected) - _, res = topotest.run_and_expect(test_func, None, count=20, wait=0.5) + _, res = topotest.run_and_expect(test_func, None, count=125, wait=1.0) assertmsg = '{}: bgp did not converge'.format(router.name) assert res is None, assertmsg diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py index 31e23faed..ce542413b 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py @@ -141,7 +141,10 @@ class ThisTestTopo(Topo): switch[1].add_link(tgen.gears['r2'], nodeif='r2-eth2') switch[1].add_link(tgen.gears['r3'], nodeif='r3-eth1') +l3mdev_accept = 0 + def ltemplatePreRouterStartHook(): + global l3mdev_accept cc = ltemplateRtrCmd() krel = platform.release() tgen = get_topogen() @@ -172,7 +175,7 @@ def ltemplatePreRouterStartHook(): 'ip ru add oif {0}-cust1 table 10', 'ip ru add iif {0}-cust1 table 10', 'ip link set dev {0}-cust1 up', - 'sysctl -w net.ipv4.udp_l3mdev_accept={}'.format(l3mdev_accept)] + 'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)] for rtr in rtrs: router = tgen.gears[rtr] for cmd in cmds: @@ -202,7 +205,7 @@ def ltemplatePreRouterStartHook(): 'ip ru add oif {0}-cust2 table 20', 'ip ru add iif {0}-cust2 table 20', 'ip link set dev {0}-cust2 up', - 'sysctl -w net.ipv4.udp_l3mdev_accept={}'.format(l3mdev_accept)] + 'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)] for rtr in rtrs: for cmd in cmds: cc.doCmd(tgen, rtr, cmd.format(rtr)) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py index 778d50404..f5d73a8c4 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py @@ -1,11 +1,12 @@ from lutil import luCommand - -rtrs = ['r1', 'r3', 'r4', 'ce1', 'ce2', 'ce3', 'ce4'] -for rtr in rtrs: +from customize import l3mdev_accept +l3mdev_rtrs = ['r1', 'r3', 'r4', 'ce4'] +for rtr in l3mdev_rtrs: luCommand(rtr,'sysctl net.ipv4.tcp_l3mdev_accept',' = \d*','none','') found = luLast() - luCommand(rtr,'ss -aep',':bgp','pass','IPv4:bgp, l3mdev%s' % found.group(0)) - luCommand(rtr,'ss -aep',':.:bgp','pass','IPv6:bgp') + luCommand(rtr,'ss -naep',':179','pass','IPv4:bgp, l3mdev{}'.format(found.group(0))) + luCommand(rtr,'ss -naep',':.*:179','pass','IPv6:bgp') + luCommand(rtr,'sysctl net.ipv4.tcp_l3mdev_accept',' = {}'.format(l3mdev_accept),'pass','l3mdev matches expected (real/expected{}/{})'.format(found.group(0),l3mdev_accept)) rtrs = ['r1', 'r3', 'r4'] for rtr in rtrs: diff --git a/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref b/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref index 36dd5da59..26fa7ca41 100644 --- a/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref +++ b/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref @@ -3,7 +3,7 @@ { "prefix":"192.168.1.0/24", "protocol":"eigrp", - "metric":0, + "metric":28160, "nexthops":[ { "directlyConnected":true, @@ -31,7 +31,7 @@ "prefix":"192.168.3.0/24", "protocol":"eigrp", "selected":true, - "metric":0, + "metric":33280, "nexthops":[ { "fib":true, @@ -47,7 +47,7 @@ { "prefix":"193.1.1.0/26", "protocol":"eigrp", - "metric":0, + "metric":28160, "nexthops":[ { "directlyConnected":true, @@ -75,7 +75,7 @@ "prefix":"193.1.2.0/24", "protocol":"eigrp", "selected":true, - "metric":0, + "metric":30720, "nexthops":[ { "fib":true, diff --git a/tests/topotests/eigrp-topo1/r1/zebra.conf b/tests/topotests/eigrp-topo1/r1/zebra.conf index 8537f6dd8..56ae4a66f 100644 --- a/tests/topotests/eigrp-topo1/r1/zebra.conf +++ b/tests/topotests/eigrp-topo1/r1/zebra.conf @@ -1,4 +1,5 @@ log file zebra.log +debug zebra rib detail ! hostname r1 ! diff --git a/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref b/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref index 44903ce3f..71c931b17 100644 --- a/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref +++ b/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref @@ -4,7 +4,7 @@ "prefix":"192.168.1.0/24", "protocol":"eigrp", "selected":true, - "metric":0, + "metric":30720, "nexthops":[ { "fib":true, @@ -21,7 +21,7 @@ "prefix":"192.168.3.0/24", "protocol":"eigrp", "selected":true, - "metric":0, + "metric":30720, "nexthops":[ { "fib":true, @@ -37,7 +37,7 @@ { "prefix":"193.1.1.0/26", "protocol":"eigrp", - "metric":0, + "metric":28160, "nexthops":[ { "directlyConnected":true, @@ -64,7 +64,7 @@ { "prefix":"193.1.2.0/24", "protocol":"eigrp", - "metric":0, + "metric":28160, "nexthops":[ { "directlyConnected":true, diff --git a/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref b/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref index d80e1d97e..5e0b79d81 100644 --- a/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref +++ b/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref @@ -4,7 +4,7 @@ "prefix":"192.168.1.0/24", "protocol":"eigrp", "selected":true, - "metric":0, + "metric":33280, "nexthops":[ { "fib":true, @@ -38,7 +38,7 @@ { "prefix":"192.168.3.0/24", "protocol":"eigrp", - "metric":0, + "metric":28160, "nexthops":[ { "directlyConnected":true, @@ -66,7 +66,7 @@ "prefix":"193.1.1.0/26", "protocol":"eigrp", "selected":true, - "metric":0, + "metric":30720, "nexthops":[ { "fib":true, @@ -82,7 +82,7 @@ { "prefix":"193.1.2.0/24", "protocol":"eigrp", - "metric":0, + "metric":28160, "nexthops":[ { "directlyConnected":true, diff --git a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py index de8cb81f8..1c00face4 100755 --- a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py +++ b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py @@ -153,7 +153,6 @@ def test_eigrp_routes(): assertmsg = '"show ip eigrp topo" mismatches on {}'.format(router.name) assert topotest.json_cmp(actual, expected) is None, assertmsg - def test_zebra_ipv4_routingTable(): "Test 'show ip route'" @@ -172,6 +171,16 @@ def test_zebra_ipv4_routingTable(): assertmsg = 'Zebra IPv4 Routing Table verification failed for router {}'.format(router.name) assert topotest.json_cmp(output, expected) is None, assertmsg +def test_shut_interface_and_recover(): + "Test shutdown of an interface and recovery of the interface" + + tgen = get_topogen() + router = tgen.gears['r1'] + router.run('ip link set r1-eth1 down') + topotest.sleep(5, 'Waiting for EIGRP convergence') + router.run('ip link set r1-eth1 up') + + def test_shutdown_check_stderr(): if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: diff --git a/tests/topotests/ospf-topo1-vrf/r1/zebra.conf b/tests/topotests/ospf-topo1-vrf/r1/zebra.conf index b1cf34289..e82679365 100644 --- a/tests/topotests/ospf-topo1-vrf/r1/zebra.conf +++ b/tests/topotests/ospf-topo1-vrf/r1/zebra.conf @@ -1,3 +1,7 @@ +debug zebra kernel +debug zebra dplane detail +debug zebra rib +debug zebra event ! hostname r1 password zebra diff --git a/tools/build-debian-package.sh b/tools/build-debian-package.sh index 73231f0ae..d21f468bf 100755 --- a/tools/build-debian-package.sh +++ b/tools/build-debian-package.sh @@ -2,39 +2,26 @@ # # Written by Daniil Baturin, 2018 # This file is public domain +set -e -git diff-index --quiet HEAD || echo "Warning: git working directory is not clean!" - -# Set the defaults -if [ "$EXTRA_VERSION" = "" ]; then - EXTRA_VERSION="-MyDebPkgVersion" -fi +cd "`dirname $0`" +cd .. -if [ "$WANT_SNMP" = "" ]; then - WANT_SNMP=0 +if [ "`id -u`" = 0 ]; then + echo "Running as root - installing dependencies" + apt-get install fakeroot debhelper devscripts + mk-build-deps --install debian/control + exit 0 fi -if [ "$WANT_CUMULUS_MODE" = "" ]; then - WANT_CUMULUS_MODE=0 -fi +git diff-index --quiet HEAD || echo "Warning: git working directory is not clean!" echo "Preparing the build" -./bootstrap.sh -./configure --with-pkg-extra-version=$EXTRA_VERSION -make dist - -echo "Preparing Debian source package" -mv debianpkg debian -make -f debian/rules backports - -echo "Unpacking the source to frrpkg/" -mkdir frrpkg -cd frrpkg -tar xf ../frr_*.orig.tar.gz -cd frr* -. /etc/os-release -tar xf ../../frr_*${ID}${VERSION_ID}*.debian.tar.xz +tools/tarsource.sh -V echo "Building the Debian package" -debuild --no-lintian --set-envvar=WANT_SNMP=$WANT_SNMP --set-envvar=WANT_CUMULUS_MODE=$WANT_CUMULUS_MODE -b -uc -us - +if test $# -eq 0; then + dpkg-buildpackage -b -uc -us +else + dpkg-buildpackage "$@" +fi diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons index 2d56fe1b9..0fca54113 100644 --- a/tools/etc/frr/daemons +++ b/tools/etc/frr/daemons @@ -55,7 +55,7 @@ bfdd_options=" -A 127.0.0.1" fabricd_options="-A 127.0.0.1" # The list of daemons to watch is automatically generated by the init script. -watchfrr_options="-r '/usr/lib/frr/watchfrr.sh restart %s' -s '/usr/lib/frr/watchfrr.sh start %s' -k '/usr/lib/frr/watchfrr.sh stop %s'" +#watchfrr_options="" # for debugging purposes, you can specify a "wrap" command to start instead # of starting the daemon directly, e.g. to use valgrind on ospfd: diff --git a/tools/frr-reload.py b/tools/frr-reload.py index c48c8b97a..59f1bcf52 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -300,13 +300,11 @@ class Config(object): ''' More fixups in user specification and what running config shows. - "null0" in routes must be replaced by Null0, and "blackhole" must - be replaced by Null0 as well. + "null0" in routes must be replaced by Null0. ''' if (key[0].startswith('ip route') or key[0].startswith('ipv6 route') and - 'null0' in key[0] or 'blackhole' in key[0]): + 'null0' in key[0]): key[0] = re.sub(r'\s+null0(\s*$)', ' Null0', key[0]) - key[0] = re.sub(r'\s+blackhole(\s*$)', ' Null0', key[0]) if lines: if tuple(key) not in self.contexts: @@ -435,7 +433,7 @@ end self.save_contexts(ctx_keys, current_context_lines) new_ctx = True - elif line in ["end", "exit-vrf"]: + elif line == "end": self.save_contexts(ctx_keys, current_context_lines) log.debug('LINE %-50s: exiting old context, %-50s', line, ctx_keys) @@ -445,6 +443,17 @@ end ctx_keys = [] current_context_lines = [] + elif line == "exit-vrf": + self.save_contexts(ctx_keys, current_context_lines) + current_context_lines.append(line) + log.debug('LINE %-50s: append to current_context_lines, %-50s', line, ctx_keys) + + #Start a new context + new_ctx = True + main_ctx_key = [] + ctx_keys = [] + current_context_lines = [] + elif line in ["exit-address-family", "exit", "exit-vnc"]: # if this exit is for address-family ipv4 unicast, ignore the pop if main_ctx_key: diff --git a/tools/frr.service b/tools/frr.service index c7568593b..aa45f420f 100644 --- a/tools/frr.service +++ b/tools/frr.service @@ -1,7 +1,9 @@ [Unit] Description=FRRouting Documentation=https://frrouting.readthedocs.io/en/latest/setup.html -After=networking.service +Wants=network.target +After=network-pre.target systemd-sysctl.service +Before=network.target OnFailure=heartbeat-failed@%n.service [Service] @@ -20,4 +22,4 @@ ExecStop=/usr/lib/frr/frrinit.sh stop ExecReload=/usr/lib/frr/frrinit.sh reload [Install] -WantedBy=network-online.target +WantedBy=multi-user.target diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in index fa2fdc94b..76a0d617b 100644 --- a/tools/frrcommon.sh.in +++ b/tools/frrcommon.sh.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # This is a "library" of sorts for use by the other FRR shell scripts. It # has most of the daemon start/stop logic, but expects the following shell @@ -67,9 +67,9 @@ vtysh_b () { daemon_inst() { # note this sets global variables ($dmninst, $daemon, $inst) dmninst="$1" - daemon="${dmninst%:*}" + daemon="${dmninst%-*}" inst="" - [ "$daemon" != "$dmninst" ] && inst="${dmninst#*:}" + [ "$daemon" != "$dmninst" ] && inst="${dmninst#*-}" } daemon_list() { @@ -85,13 +85,19 @@ daemon_list() { eval inst=\$${daemon}_instances [ "$daemon" = zebra -o "$daemon" = staticd ] && cfg=yes if [ -n "$cfg" -a "$cfg" != "no" -a "$cfg" != "0" ]; then + if ! daemon_prep "$daemon" "$inst"; then + continue + fi debug "$daemon enabled" enabled="$enabled $daemon" if [ -n "$inst" ]; then debug "$daemon multi-instance $inst" + oldifs="${IFS}" + IFS="${IFS}," for i in $inst; do - enabled="$enabled $daemon:$inst" + enabled="$enabled $daemon-$i" done + IFS="${oldifs}" fi else debug "$daemon disabled" @@ -116,7 +122,7 @@ daemon_prep() { inst="$2" [ "$daemon" = "watchfrr" ] && return 0 [ -x "$D_PATH/$daemon" ] || { - log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed\n" + log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed" return 1 } [ -r "$C_PATH/frr.conf" ] && return 0 @@ -276,7 +282,7 @@ load_old_config() { } [ -r "$C_PATH/daemons" ] || { - log_failure_msg "cannot run $@: $C_PATH/daemons does not exist\n" + log_failure_msg "cannot run $@: $C_PATH/daemons does not exist" exit 1 } . "$C_PATH/daemons" @@ -285,6 +291,13 @@ load_old_config "$C_PATH/daemons.conf" load_old_config "/etc/default/frr" load_old_config "/etc/sysconfig/frr" +if declare -p watchfrr_options | grep -q '^declare \-a'; then + log_warning_msg "watchfrr_options contains a bash array value." \ + "The configured value is intentionally ignored since it is likely wrong." \ + "Please remove or fix the setting." + unset watchfrr_options +fi + # # other defaults and dispatch # diff --git a/tools/frrinit.sh.in b/tools/frrinit.sh.in index 3dddf5bd4..0f5ed8586 100644 --- a/tools/frrinit.sh.in +++ b/tools/frrinit.sh.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # ### BEGIN INIT INFO # Provides: frr diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c index eded87c12..f6c757f5d 100644 --- a/tools/gen_northbound_callbacks.c +++ b/tools/gen_northbound_callbacks.c @@ -54,7 +54,7 @@ static struct nb_callback_info { "enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource", }, { - .operation = NB_OP_DELETE, + .operation = NB_OP_DESTROY, .return_type = "int ", .return_value = "NB_OK", .arguments = diff --git a/tools/start-stop-daemon.c b/tools/start-stop-daemon.c index f2a1e9434..5903f8732 100644 --- a/tools/start-stop-daemon.c +++ b/tools/start-stop-daemon.c @@ -280,7 +280,7 @@ static void add_namespace(const char *path) #endif #ifdef HAVE_LXC -static void set_namespaces() +static void set_namespaces(void) { struct namespace *namespace; int fd; @@ -294,7 +294,7 @@ static void set_namespaces() } } #else -static void set_namespaces() +static void set_namespaces(void) { if (!LIST_EMPTY(&namespace_head)) fatal("LCX namespaces not supported"); diff --git a/tools/subdir.am b/tools/subdir.am index ff41fe2c6..7713bb1ad 100644 --- a/tools/subdir.am +++ b/tools/subdir.am @@ -23,10 +23,10 @@ tools_permutations_SOURCES = tools/permutations.c tools_permutations_LDADD = lib/libfrr.la tools_gen_northbound_callbacks_SOURCES = tools/gen_northbound_callbacks.c -tools_gen_northbound_callbacks_LDADD = lib/libfrr.la -lyang +tools_gen_northbound_callbacks_LDADD = lib/libfrr.la $(LIBYANG_LIBS) tools_gen_yang_deviations_SOURCES = tools/gen_yang_deviations.c -tools_gen_yang_deviations_LDADD = lib/libfrr.la -lyang +tools_gen_yang_deviations_LDADD = lib/libfrr.la $(LIBYANG_LIBS) tools_ssd_SOURCES = tools/start-stop-daemon.c diff --git a/tools/tarsource.sh b/tools/tarsource.sh new file mode 100755 index 000000000..eee2a9739 --- /dev/null +++ b/tools/tarsource.sh @@ -0,0 +1,331 @@ +#!/bin/bash +# 2018 by David Lamparter, placed in the Public Domain + +help() { + cat <<EOF +FRR tarball/dsc helper, intended to run from a git checkout + +Usage: + ./tarsource.sh [-dDn] [-i GITPATH] [-o OUTDIR] [-S KEYID] + [-C COMMIT] [-e EXTRAVERSION] [-z gz|xz] + +options: + -i GITPATH path to git working tree or bare repository. + - default: parent directory containing this script + -o OUTDIR path to place the generated output files in. + - default: current directory + -C COMMIT build tarball for specified git commit + - default: current HEAD + -e EXTRAVERSION override automatic package extraversion + - default "-YYYYMMDD-NN-gGGGGGGGGGGGG", but the script + autodetects if a release tag is checked out + -z gz|xz compression format to use + - default: xz + -S KEYID sign the output with gpg key + -d use dirty git tree with local changes + -D generate Debian .dsc and .debian.tar.xz too + (note: output files are moved to parent directory) + -l remove Debian auto-build changelog entry + (always done for releases) + -V write version information to config.version and exit + -n allow executing from non-git source (NOT RECOMMENDED) + -h show this help text + +Note(1) that this script tries very hard to generate a deterministic, +reproducible tarball by eliminating timestamps and similar things. However, +since the tarball includes autoconf/automake files, the versions of these +tools need to be _exactly_ identical to get the same tarball. + +Note(2) the debian ".orig" tarball is always identical to the "plain" tarball +generated without the -D option. + +Note(3) if you want the tool to identify github PRs, you need to edit your +.git/config to fetch PRs from github like this: + + [remote "origin"] + url = git@github.com:frrouting/frr.git + fetch = +refs/heads/*:refs/remotes/origin/* +ADD: fetch = +refs/pull/*/head:refs/remotes/origin/pull/* +EOF +} + +set -e + +options=`getopt -o 'hi:o:C:S:e:z:DdnlV' -l help -- "$@"` +debian=false +dirty=false +nongit=false +zip=xz +adjchangelog=false +writeversion=false +extraset=false +set - $options +while test $# -gt 0; do + arg="$1"; shift; optarg=$1 + case "$arg" in + -h|--help) help; exit 0;; + -d) dirty=true;; + -D) debian=true;; + -n) nongit=true;; + -i) eval src=$optarg; shift;; + -C) eval commit=$optarg; shift;; + -o) eval outdir=$optarg; shift;; + -e) eval extraver=$optarg; extraset=true; shift;; + -z) eval zip=$optarg; shift;; + -S) eval keyid=$optarg; shift;; + -l) adjchangelog=true;; + -V) writeversion=true;; + --) break;; + *) echo something went wrong with getopt >&2 + exit 1 + ;; + esac +done + +cwd="`pwd`" +outdir="${outdir:-$cwd}" + +if test -e "$outdir" -a \! -d "$outdir"; then + echo "output $outdir must be a directory" >&2 + exit 1 +elif test \! -d "$outdir"; then + mkdir -p "$outdir" +fi + +cd "$outdir" +outdir="`pwd`" +cd "$cwd" +cd "`dirname $0`/.." +selfdir="`pwd`" +src="${src:-$selfdir}" + +if $writeversion; then + if $nongit; then + echo "The -V option cannot be used without a git tree" >&2 + exit 1 + fi + dirty=true +fi + +case "$zip" in +gz) ziptarget=dist-gzip; ziptool="gzip -n -9"; unzip="gzip -k -c";; +xz) ziptarget=dist-xz; ziptool="xz -z -e"; unzip="xz -d -k -c";; +*) echo "unknown compression format $zip" >&2 + exit 1 +esac + +# always overwrite file ownership in tars +taropt="--owner=root --group=root" + +onexit() { + rv="$?" + set +e + test -n "$tmpdir" -a -d "$tmpdir" && rm -rf "$tmpdir" + + if test "$rv" -ne 0; then + echo -e "\n\033[31;1mfailed\n" >&2 + if test "$dirty" = true; then + echo please try running the script without the -d option.>&2 + fi + fi + exit $rv +} +trap onexit EXIT +tmpdir="`mktemp -d -t frrtar.XXXXXX`" + +if test -e "$src/.git"; then + commit="`git -C \"$src\" rev-parse \"${commit:-HEAD}\"`" + + if $dirty; then + cd "$src" + echo -e "\033[31;1mgit: using dirty worktree in $src\033[m" >&2 + else + echo -e "\033[33;1mgit: preparing a clean clone of $src\033[m" + branch="${tmpdir##*/}" + cd "$tmpdir" + + git -C "$src" branch "$branch" "$commit" + git clone --single-branch -s -b "$branch" "$src" source + git -C "$src" branch -D "$branch" + cd source + fi + + # if we're creating a tarball from git, force the timestamps inside + # the tar to match the commit date - this makes the tarball itself + # reproducible + gitts="`TZ=UTC git show -s --format=%cd --date=local $commit`" + gitts="`TZ=UTC date -d "$gitts" '+%Y-%m-%dT%H:%M:%SZ'`" + taropt="--mtime=$gitts $taropt" + + # check if we're on a release tag + gittag="`git -C \"$src\" describe --tags --match 'frr-*' --first-parent --long $commit`" + gittag="${gittag%-g*}" + gittag="${gittag%-*}" + + # if there have been changes to packaging or tests, it's still the + # same release + changes="`git diff --name-only "$gittag" $commit | \ + egrep -v '\.git|^m4/|^config|^README|^alpine/|^debian/|^pkgsrc/|^ports/|^redhat/|^snapcraft/|^solaris/|^tests/|^tools/|^gdb/|^docker/|^\.' | \ + wc -l`" + if test "$changes" -eq 0; then + adjchangelog=true + echo "detected release build for tag $gittag" >&2 + $extraset || extraver="" + elif ! $adjchangelog; then + gitdate="`TZ=UTC date -d "$gitts" '+%Y%m%d'`" + gitrev="`git rev-parse --short $commit`" + dayseq="`git rev-list --since \"${gitts%T*} 00:00:00 +0000\" $commit | wc -l`" + dayseq="`printf '%02d' $(( $dayseq - 1 ))`" + + $extraset || extraver="-$gitdate-$dayseq-g$gitrev" + + git -C "$src" remote -v | grep fetch | sed -e 's% (fetch)$%%' \ + | egrep -i '\b(git@github\.com:frrouting/frr\.git|https://github\.com/FRRouting/frr\.git)$' \ + | while read remote; do + remote="${remote%% *}" + + git -C "$src" var -l | egrep "^remote.$remote.fetch=" \ + | while read fetch; do + fetch="${fetch#*=}" + from="${fetch%:*}" + to="${fetch#*:}" + if test "$from" = "+refs/pull/*/head"; then + name="`git -C \"$src\" name-rev --name-only --refs \"$to\" $commit`" + test "$name" = "undefined" && continue + realname="${name%~*}" + realname="${realname%%^*}" + realname="${realname%%@*}" + if test "$realname" = "$name"; then + echo "${name##*/}" > "$tmpdir/.gitpr" + break + fi + fi + done || true + test -n "$gitpr" && break + done || true + test $extraset = false -a -f "$tmpdir/.gitpr" && extraver="-PR`cat \"$tmpdir/.gitpr\"`$extraver" + fi + + debsrc="git ls-files debian/" +else + if $nongit; then + echo -e "\033[31;1mWARNING: this script should be executed from a git tree\033[m" >&2 + else + echo -e "\033[31;1mERROR: this script should be executed from a git tree\033[m" >&2 + exit 1 + fi + debsrc="echo debian" +fi + +if $writeversion; then + pkgver="`egrep ^AC_INIT configure.ac`" + pkgver="${pkgver#*,}" + pkgver="${pkgver%,*}" + pkgver="`echo $pkgver`" # strip whitespace + pkgver="${pkgver#[}" + pkgver="${pkgver%]}" + + echo -e "\033[32;1mwriting version ID \033[36;1mfrr-$pkgver$extraver\033[m" + + cat > config.version <<EOF +# config.version override by tarsource.sh +EXTRAVERSION="$extraver" +DIST_PACKAGE_VERSION="$pkgver$extraver" +gitts="$gitts" +taropt="$taropt" +EOF + sed -e "s%@VERSION@%$pkgver$extraver%" \ + < changelog-auto.in \ + > changelog-auto + exit 0 +fi + +echo -e "\033[33;1mpreparing source tree\033[m" + +# config.version will also overwrite gitts and taropt when tarsource.sh +# was used to write the config.version file before - but configure will +# overwrite config.version down below! +if test -f config.version; then + # never executed for clean git build + . ./config.version + if $nongit; then + $extraset || extraver="$EXTRAVERSION" + fi +fi +if test \! -f configure; then + # always executed for clean git build + ./bootstrap.sh +fi +if test "$EXTRAVERSION" != "$extraver" -o \! -f config.status; then + # always executed for clean git build + # options don't matter really - we just want to make a dist tarball + ./configure --with-pkg-extra-version=$extraver +fi + +. ./config.version +PACKAGE_VERSION="$DIST_PACKAGE_VERSION" + +echo -e "\033[33;1mpacking up \033[36;1mfrr-$PACKAGE_VERSION\033[m" + +make GZIP_ENV="-n9" am__tar="tar -chof - $taropt \"\$\$tardir\"" $ziptarget +mv frr-${PACKAGE_VERSION}.tar.$zip "$outdir" || true +lsfiles="frr-${PACKAGE_VERSION}.tar.$zip" + +if $debian; then + mkdir -p "$tmpdir/debian/source" + cat debian/changelog > "$tmpdir/debian/changelog" + if $adjchangelog; then + if grep -q 'autoconf changelog entry' debian/changelog; then + tail -n +9 debian/changelog > "$tmpdir/debian/changelog" + fi + fi + echo '3.0 (quilt)' > "$tmpdir/debian/source/format" + DEBVER="`dpkg-parsechangelog -l\"$tmpdir/debian/changelog\" -SVersion`" + + eval $debsrc | tar -cho $taropt \ + --exclude-vcs --exclude debian/source/format \ + --exclude debian/changelog \ + --exclude debian/changelog-auto \ + --exclude debian/changelog-auto.in \ + --exclude debian/subdir.am \ + -T - -f ../frr_${DEBVER}.debian.tar + # add specially prepared files from above + tar -uf ../frr_${DEBVER}.debian.tar $taropt -C "$tmpdir" debian/source/format debian/changelog + + test -f ../frr_${DEBVER}.debian.tar.$zip && rm -f ../frr_${DEBVER}.debian.tar.$zip + $ziptool ../frr_${DEBVER}.debian.tar + + # pack up debian files proper + ln -s "$outdir/frr-${PACKAGE_VERSION}.tar.$zip" ../frr_${PACKAGE_VERSION}.orig.tar.$zip + dpkg-source -l"$tmpdir/debian/changelog" \ + --format='3.0 (custom)' --target-format='3.0 (quilt)' \ + -b . frr_${PACKAGE_VERSION}.orig.tar.$zip frr_${DEBVER}.debian.tar.$zip + + mv ../frr_${DEBVER}.dsc "$outdir" || true + mv ../frr_${DEBVER}.debian.tar.$zip "$outdir" || true + if test -h ../frr_${PACKAGE_VERSION}.orig.tar.$zip; then + rm ../frr_${PACKAGE_VERSION}.orig.tar.$zip || true + fi + ln -s frr-${PACKAGE_VERSION}.tar.$zip "$outdir/frr_${PACKAGE_VERSION}.orig.tar.$zip" || true + + cd "$outdir" + test -n "$keyid" && debsign -k "$keyid" "frr_${DEBVER}.dsc" + + lsfiles="$lsfiles \ + frr_${DEBVER}.dsc \ + frr_${DEBVER}.debian.tar.$zip \ + frr_${PACKAGE_VERSION}.orig.tar.$zip" +fi + +cd "$outdir" +if test -n "$keyid"; then + $unzip frr-${PACKAGE_VERSION}.tar.$zip > frr-${PACKAGE_VERSION}.tar + test -f frr-${PACKAGE_VERSION}.tar.asc && rm frr-${PACKAGE_VERSION}.tar.asc + if gpg -a --detach-sign -u "$keyid" frr-${PACKAGE_VERSION}.tar; then + lsfiles="$lsfiles frr-${PACKAGE_VERSION}.tar.asc" + fi + rm frr-${PACKAGE_VERSION}.tar +fi + +echo -e "\n\033[32;1mdone: \033[36;1mfrr-$PACKAGE_VERSION\033[m\n" +ls -l $lsfiles diff --git a/tools/watchfrr.sh.in b/tools/watchfrr.sh.in index 3051d9104..712f962a0 100644 --- a/tools/watchfrr.sh.in +++ b/tools/watchfrr.sh.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # This is NOT the init script! This is the watchfrr start/stop/restart # command handler, passed to watchfrr with the -s/-r/-k commands. It is used diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 2b48f1f36..332fd248c 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -248,8 +248,7 @@ foreach (sort keys %live) { # Output install_element print <<EOF; -void -vtysh_init_cmd () +void vtysh_init_cmd(void) { EOF diff --git a/vtysh/subdir.am b/vtysh/subdir.am index c9cdb5854..74595788b 100644 --- a/vtysh/subdir.am +++ b/vtysh/subdir.am @@ -24,7 +24,7 @@ noinst_HEADERS += \ vtysh/vtysh_user.h \ # end -vtysh_vtysh_LDADD = lib/libfrr.la @LIBCAP@ @LIBREADLINE@ @LIBS@ @LIBPAM@ +vtysh_vtysh_LDADD = lib/libfrr.la $(LIBCAP) $(LIBREADLINE) $(LIBS) $(LIBPAM) AM_V_EXTRACT = $(am__v_EXTRACT_$(V)) am__v_EXTRACT_ = $(am__v_EXTRACT_$(AM_DEFAULT_VERBOSITY)) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 41bc50670..b8da90ca8 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -104,7 +104,7 @@ static int vty_close_pager(struct vty *vty) return 0; } -static void vtysh_pager_envdef(void) +static void vtysh_pager_envdef(bool fallback) { char *pager_defined; @@ -112,7 +112,7 @@ static void vtysh_pager_envdef(void) if (pager_defined) vtysh_pager_name = strdup(pager_defined); - else + else if (fallback) vtysh_pager_name = strdup(VTYSH_PAGER); } @@ -1305,6 +1305,7 @@ DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd, return CMD_SUCCESS; } +#ifdef KEEP_OLD_VPN_COMMANDS DEFUNSH(VTYSH_BGPD, address_family_vpnv4, address_family_vpnv4_cmd, "address-family vpnv4 [unicast]", "Enter Address Family command mode\n" @@ -1324,6 +1325,7 @@ DEFUNSH(VTYSH_BGPD, address_family_vpnv6, address_family_vpnv6_cmd, vty->node = BGP_VPNV6_NODE; return CMD_SUCCESS; } +#endif /* KEEP_OLD_VPN_COMMANDS */ DEFUNSH(VTYSH_BGPD, address_family_ipv4, address_family_ipv4_cmd, "address-family ipv4 [unicast]", @@ -2893,7 +2895,7 @@ DEFUN (vtysh_terminal_paginate, vtysh_pager_name = NULL; if (strcmp(argv[0]->text, "no")) - vtysh_pager_envdef(); + vtysh_pager_envdef(true); return CMD_SUCCESS; } @@ -2913,7 +2915,7 @@ DEFUN (vtysh_terminal_length, if (!strcmp(argv[0]->text, "no") || !strcmp(argv[1]->text, "no")) { /* "terminal no length" = use VTYSH_PAGER */ - vtysh_pager_envdef(); + vtysh_pager_envdef(true); return CMD_SUCCESS; } @@ -2922,7 +2924,7 @@ DEFUN (vtysh_terminal_length, vty_out(vty, "%% The \"terminal length\" command is deprecated and its value is ignored.\n" "%% Please use \"terminal paginate\" instead with OS TTY length handling.\n"); - vtysh_pager_envdef(); + vtysh_pager_envdef(true); } return CMD_SUCCESS; @@ -3330,7 +3332,7 @@ static void vtysh_client_sorted_insert(struct vtysh_client *head_client, #define MAXIMUM_INSTANCES 10 -static void vtysh_update_all_insances(struct vtysh_client *head_client) +static void vtysh_update_all_instances(struct vtysh_client *head_client) { struct vtysh_client *client; DIR *dir; @@ -3373,7 +3375,7 @@ static int vtysh_connect_all_instances(struct vtysh_client *head_client) struct vtysh_client *client; int rc = 0; - vtysh_update_all_insances(head_client); + vtysh_update_all_instances(head_client); client = head_client->next; while (client) { @@ -3464,7 +3466,7 @@ static const struct cmd_variable_handler vtysh_var_handler[] = { .completions = vtysh_autocomplete}, {.completions = NULL}}; -void vtysh_uninit() +void vtysh_uninit(void) { if (vty->of != stdout) fclose(vty->of); @@ -3479,6 +3481,7 @@ void vtysh_init_vty(void) /* set default output */ vty->of = stdout; + vtysh_pager_envdef(false); /* Initialize commands. */ cmd_init(0); @@ -3734,8 +3737,10 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &router_isis_cmd); install_element(CONFIG_NODE, &router_openfabric_cmd); install_element(CONFIG_NODE, &router_bgp_cmd); +#ifdef KEEP_OLD_VPN_COMMANDS install_element(BGP_NODE, &address_family_vpnv4_cmd); install_element(BGP_NODE, &address_family_vpnv6_cmd); +#endif /* KEEP_OLD_VPN_COMMANDS */ #if defined(ENABLE_BGP_VNC) install_element(BGP_NODE, &vnc_vrf_policy_cmd); install_element(BGP_NODE, &vnc_defaults_cmd); @@ -3812,6 +3817,7 @@ void vtysh_init_vty(void) /* "write memory" command. */ install_element(ENABLE_NODE, &vtysh_write_memory_cmd); + install_element(CONFIG_NODE, &vtysh_terminal_paginate_cmd); install_element(VIEW_NODE, &vtysh_terminal_paginate_cmd); install_element(VIEW_NODE, &vtysh_terminal_length_cmd); install_element(VIEW_NODE, &vtysh_terminal_no_length_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index fe12f82ef..91e49c45c 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -516,7 +516,7 @@ int vtysh_read_config(const char *config_default_dir) * be edited by hand. So, we handle only "write terminal" case here and * integrate vtysh specific conf with conf from daemons. */ -void vtysh_config_write() +void vtysh_config_write(void) { char line[81]; @@ -539,7 +539,7 @@ void vtysh_config_write() user_config_write(); } -void vtysh_config_init() +void vtysh_config_init(void) { config_top = list_new(); config_top->del = (void (*)(void *))line_del; diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index e575b7154..dcf8ca047 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -122,7 +122,7 @@ static struct vtysh_user *user_lookup(const char *name) return NULL; } -void user_config_write() +void user_config_write(void) { struct listnode *node, *nnode; struct vtysh_user *user; diff --git a/watchfrr/subdir.am b/watchfrr/subdir.am index f0b49c9a8..c27491e55 100644 --- a/watchfrr/subdir.am +++ b/watchfrr/subdir.am @@ -13,7 +13,7 @@ noinst_HEADERS += \ watchfrr/watchfrr_errors.h \ # end -watchfrr_watchfrr_LDADD = lib/libfrr.la @LIBCAP@ +watchfrr_watchfrr_LDADD = lib/libfrr.la $(LIBCAP) watchfrr_watchfrr_SOURCES = \ watchfrr/watchfrr.c \ watchfrr/watchfrr_errors.c \ diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index e28da6db8..34f8dabdf 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -53,6 +53,10 @@ #define DEFAULT_MIN_RESTART 60 #define DEFAULT_MAX_RESTART 600 +#define DEFAULT_RESTART_CMD WATCHFRR_SH_PATH " restart %s" +#define DEFAULT_START_CMD WATCHFRR_SH_PATH " start %s" +#define DEFAULT_STOP_CMD WATCHFRR_SH_PATH " stop %s" + #define PING_TOKEN "PING" DEFINE_MGROUP(WATCHFRR, "watchfrr") @@ -83,6 +87,7 @@ static const char *phase_str[] = { }; #define PHASE_TIMEOUT (3*gs.restart_timeout) +#define STARTUP_TIMEOUT 55 * 1000 struct restart_info { const char *name; @@ -97,6 +102,7 @@ struct restart_info { static struct global_state { restart_phase_t phase; struct thread *t_phase_hanging; + struct thread *t_startup_timeout; const char *vtydir; long period; long timeout; @@ -122,6 +128,9 @@ static struct global_state { .loglevel = DEFAULT_LOGLEVEL, .min_restart_interval = DEFAULT_MIN_RESTART, .max_restart_interval = DEFAULT_MAX_RESTART, + .restart_command = DEFAULT_RESTART_CMD, + .start_command = DEFAULT_START_CMD, + .stop_command = DEFAULT_STOP_CMD, }; typedef enum { @@ -225,14 +234,17 @@ Otherwise, the interval is doubled (but capped at the -M value).\n\n", -r, --restart Supply a Bourne shell command to use to restart a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ + (default: '%s')\n\ -s, --start-command\n\ Supply a Bourne shell to command to use to start a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ + (default: '%s')\n\ -k, --kill-command\n\ Supply a Bourne shell to command to use to stop a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ + (default: '%s')\n\ --dry Do not start or restart anything, just log.\n\ -p, --pid-file Set process identifier file name\n\ (default is %s/watchfrr.pid).\n\ @@ -245,7 +257,9 @@ Otherwise, the interval is doubled (but capped at the -M value).\n\n", -h, --help Display this help and exit\n", frr_vtydir, DEFAULT_LOGLEVEL, LOG_EMERG, LOG_DEBUG, LOG_DEBUG, DEFAULT_MIN_RESTART, DEFAULT_MAX_RESTART, DEFAULT_PERIOD, - DEFAULT_TIMEOUT, DEFAULT_RESTART_TIMEOUT, frr_vtydir); + DEFAULT_TIMEOUT, DEFAULT_RESTART_TIMEOUT, + DEFAULT_RESTART_CMD, DEFAULT_START_CMD, DEFAULT_STOP_CMD, + frr_vtydir); } static pid_t run_background(char *shell_cmd) @@ -630,23 +644,38 @@ static int handle_read(struct thread *t_read) * Wait till we notice that all daemons are ready before * we send we are ready to systemd */ -static void daemon_send_ready(void) +static void daemon_send_ready(int exitcode) { + FILE *fp; static int sent = 0; - if (!sent && gs.numdown == 0) { - FILE *fp; + if (sent) + return; + + if (exitcode == 0) zlog_notice("all daemons up, doing startup-complete notify"); - frr_detach(); + else if (gs.numdown < gs.numdaemons) + flog_err(EC_WATCHFRR_CONNECTION, + "startup did not complete within timeout" + " (%d/%d daemons running)", + gs.numdaemons - gs.numdown, gs.numdaemons); + else { + flog_err(EC_WATCHFRR_CONNECTION, + "all configured daemons failed to start" + " -- exiting watchfrr"); + exit(exitcode); + + } - fp = fopen(DAEMON_VTY_DIR "/watchfrr.started", "w"); - if (fp) - fclose(fp); + frr_detach(); + + fp = fopen(DAEMON_VTY_DIR "/watchfrr.started", "w"); + if (fp) + fclose(fp); #if defined HAVE_SYSTEMD - systemd_send_started(master, 0); + systemd_send_started(master, 0); #endif - sent = 1; - } + sent = 1; } static void daemon_up(struct daemon *dmn, const char *why) @@ -655,7 +684,8 @@ static void daemon_up(struct daemon *dmn, const char *why) gs.numdown--; dmn->connect_tries = 0; zlog_notice("%s state -> up : %s", dmn->name, why); - daemon_send_ready(); + if (gs.numdown == 0) + daemon_send_ready(0); SET_WAKEUP_ECHO(dmn); phase_check(); } @@ -1030,6 +1060,12 @@ static char *translate_blanks(const char *cmd, const char *blankstr) return res; } +static int startup_timeout(struct thread *t_wakeup) +{ + daemon_send_ready(1); + return 0; +} + static void watchfrr_init(int argc, char **argv) { const char *special = "zebra"; @@ -1037,6 +1073,9 @@ static void watchfrr_init(int argc, char **argv) struct daemon *dmn, **add = &gs.daemons; char alldaemons[512] = "", *p = alldaemons; + thread_add_timer_msec(master, startup_timeout, NULL, STARTUP_TIMEOUT, + &gs.t_startup_timeout); + for (i = optind; i < argc; i++) { dmn = XCALLOC(MTYPE_WATCHFRR_DAEMON, sizeof(*dmn)); diff --git a/yang/libyang_plugins/subdir.am b/yang/libyang_plugins/subdir.am index 956d22587..fe5f34a28 100644 --- a/yang/libyang_plugins/subdir.am +++ b/yang/libyang_plugins/subdir.am @@ -1,9 +1,14 @@ # # libyang user types # + +if LIBYANG_EXT_BUILTIN +lib_libfrr_la_SOURCES += yang/libyang_plugins/frr_user_types.c +else libyang_plugins_LTLIBRARIES += yang/libyang_plugins/frr_user_types.la +endif -yang_libyang_plugins_frr_user_types_la_CFLAGS = $(WERROR) +yang_libyang_plugins_frr_user_types_la_CFLAGS = $(WERROR) $(LIBYANG_CFLAGS) yang_libyang_plugins_frr_user_types_la_LDFLAGS = -avoid-version -module -shared -export-dynamic yang_libyang_plugins_frr_user_types_la_LIBADD = yang_libyang_plugins_frr_user_types_la_SOURCES = yang/libyang_plugins/frr_user_types.c diff --git a/zebra/connected.c b/zebra/connected.c index ab66eb332..c449855f6 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -209,6 +209,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) .ifindex = ifp->ifindex, .vrf_id = ifp->vrf_id, }; + uint32_t metric; if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) return; @@ -243,11 +244,13 @@ void connected_up(struct interface *ifp, struct connected *ifc) break; } + metric = (ifc->metric < (uint32_t)METRIC_MAX) ? + ifc->metric : ifp->metric; rib_add(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p, - NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0); + NULL, &nh, RT_TABLE_MAIN, metric, 0, 0, 0); rib_add(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p, - NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0); + NULL, &nh, RT_TABLE_MAIN, metric, 0, 0, 0); if (IS_ZEBRA_DEBUG_RIB_DETAILED) { char buf[PREFIX_STRLEN]; @@ -276,7 +279,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) /* Add connected IPv4 route to the interface. */ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, uint16_t prefixlen, struct in_addr *broad, - const char *label) + const char *label, uint32_t metric) { struct prefix_ipv4 *p; struct connected *ifc; @@ -288,6 +291,7 @@ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, ifc = connected_new(); ifc->ifp = ifp; ifc->flags = flags; + ifc->metric = metric; /* If we get a notification from the kernel, * we can safely assume the address is known to the kernel */ SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); @@ -500,7 +504,7 @@ void connected_delete_ipv4(struct interface *ifp, int flags, /* Add connected IPv6 route to the interface. */ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, struct in6_addr *broad, uint16_t prefixlen, - const char *label) + const char *label, uint32_t metric) { struct prefix_ipv6 *p; struct connected *ifc; @@ -512,6 +516,7 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, ifc = connected_new(); ifc->ifp = ifp; ifc->flags = flags; + ifc->metric = metric; /* If we get a notification from the kernel, * we can safely assume the address is known to the kernel */ SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); diff --git a/zebra/connected.h b/zebra/connected.h index 415ecfd96..faba30b0d 100644 --- a/zebra/connected.h +++ b/zebra/connected.h @@ -36,7 +36,8 @@ extern struct connected *connected_check_ptp(struct interface *ifp, extern void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, uint16_t prefixlen, - struct in_addr *broad, const char *label); + struct in_addr *broad, const char *label, + uint32_t metric); extern void connected_delete_ipv4(struct interface *ifp, int flags, struct in_addr *addr, uint16_t prefixlen, @@ -49,7 +50,8 @@ extern void connected_down(struct interface *ifp, struct connected *ifc); extern void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *address, struct in6_addr *broad, - uint16_t prefixlen, const char *label); + uint16_t prefixlen, const char *label, + uint32_t metric); extern void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address, struct in6_addr *broad, uint16_t prefixlen); diff --git a/zebra/debug.c b/zebra/debug.c index 0eb06d7f2..87999a1bb 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -23,6 +23,10 @@ #include "command.h" #include "debug.h" +#ifndef VTYSH_EXTRACT_PL +#include "zebra/debug_clippy.c" +#endif + /* For debug statement. */ unsigned long zebra_debug_event; unsigned long zebra_debug_packet; @@ -34,6 +38,7 @@ unsigned long zebra_debug_mpls; unsigned long zebra_debug_vxlan; unsigned long zebra_debug_pw; unsigned long zebra_debug_dplane; +unsigned long zebra_debug_mlag; DEFINE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty)); @@ -94,6 +99,8 @@ DEFUN_NOSH (show_debugging_zebra, vty_out(vty, " Zebra detailed dataplane debugging is on\n"); else if (IS_ZEBRA_DEBUG_DPLANE) vty_out(vty, " Zebra dataplane debugging is on\n"); + if (IS_ZEBRA_DEBUG_MLAG) + vty_out(vty, " Zebra mlag debugging is on\n"); hook_call(zebra_debug_show_debugging, vty); return CMD_SUCCESS; @@ -284,6 +291,21 @@ DEFUN (debug_zebra_dplane, return CMD_SUCCESS; } +DEFPY (debug_zebra_mlag, + debug_zebra_mlag_cmd, + "[no$no] debug zebra mlag", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for mlag events\n") +{ + if (no) + UNSET_FLAG(zebra_debug_mlag, ZEBRA_DEBUG_MLAG); + else + SET_FLAG(zebra_debug_mlag, ZEBRA_DEBUG_MLAG); + return CMD_SUCCESS; +} + DEFUN (no_debug_zebra_events, no_debug_zebra_events_cmd, "no debug zebra events", @@ -507,6 +529,7 @@ void zebra_debug_init(void) zebra_debug_vxlan = 0; zebra_debug_pw = 0; zebra_debug_dplane = 0; + zebra_debug_mlag = 0; install_node(&debug_node, config_write_debug); @@ -523,6 +546,7 @@ void zebra_debug_init(void) install_element(ENABLE_NODE, &debug_zebra_rib_cmd); install_element(ENABLE_NODE, &debug_zebra_fpm_cmd); install_element(ENABLE_NODE, &debug_zebra_dplane_cmd); + install_element(ENABLE_NODE, &debug_zebra_mlag_cmd); install_element(ENABLE_NODE, &no_debug_zebra_events_cmd); install_element(ENABLE_NODE, &no_debug_zebra_nht_cmd); install_element(ENABLE_NODE, &no_debug_zebra_mpls_cmd); diff --git a/zebra/debug.h b/zebra/debug.h index cd15441ec..c79cd96c2 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -51,6 +51,8 @@ #define ZEBRA_DEBUG_DPLANE 0x01 #define ZEBRA_DEBUG_DPLANE_DETAILED 0x02 +#define ZEBRA_DEBUG_MLAG 0x01 + /* Debug related macro. */ #define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT) @@ -79,6 +81,8 @@ #define IS_ZEBRA_DEBUG_DPLANE_DETAIL \ (zebra_debug_dplane & ZEBRA_DEBUG_DPLANE_DETAILED) +#define IS_ZEBRA_DEBUG_MLAG (zebra_debug_mlag & ZEBRA_DEBUG_MLAG) + extern unsigned long zebra_debug_event; extern unsigned long zebra_debug_packet; extern unsigned long zebra_debug_kernel; @@ -89,6 +93,7 @@ extern unsigned long zebra_debug_mpls; extern unsigned long zebra_debug_vxlan; extern unsigned long zebra_debug_pw; extern unsigned long zebra_debug_dplane; +extern unsigned long zebra_debug_mlag; extern void zebra_debug_init(void); diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index df79d285a..8bec25635 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -147,7 +147,7 @@ static int if_get_hwaddr(struct interface *ifp) struct ifreq ifreq; int i; - strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ); + strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name)); ifreq.ifr_addr.sa_family = AF_INET; /* Fetch Hardware address if available. */ @@ -236,7 +236,8 @@ static int if_getaddrs(void) } connected_add_ipv4(ifp, flags, &addr->sin_addr, - prefixlen, dest_pnt, NULL); + prefixlen, dest_pnt, NULL, + METRIC_MAX); } if (ifap->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr; @@ -258,7 +259,7 @@ static int if_getaddrs(void) #endif connected_add_ipv6(ifp, flags, &addr->sin6_addr, NULL, - prefixlen, NULL); + prefixlen, NULL, METRIC_MAX); } } diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index 0206d4938..8b539a904 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -247,7 +247,8 @@ static int if_get_addr(struct interface *ifp, struct sockaddr *addr, * We need to use the logical interface name / label, if we've been * given one, in order to get the right address */ - strncpy(lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ); + strlcpy(lifreq.lifr_name, (label ? label : ifp->name), + sizeof(lifreq.lifr_name)); /* Interface's address. */ memcpy(&lifreq.lifr_addr, addr, ADDRLEN(addr)); @@ -302,10 +303,11 @@ static int if_get_addr(struct interface *ifp, struct sockaddr *addr, /* Set address to the interface. */ if (af == AF_INET) connected_add_ipv4(ifp, flags, &SIN(addr)->sin_addr, prefixlen, - (struct in_addr *)dest_pnt, label); + (struct in_addr *)dest_pnt, label, + METRIC_MAX); else if (af == AF_INET6) connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, NULL, - prefixlen, label); + prefixlen, label, METRIC_MAX); return 0; } diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 4e49c1fc5..3583d63d3 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -68,6 +68,7 @@ #include "zebra/kernel_netlink.h" #include "zebra/if_netlink.h" #include "zebra/zebra_errors.h" +#include "zebra/zebra_vxlan.h" extern struct zebra_privs_t zserv_privs; @@ -731,6 +732,7 @@ static int netlink_request_intf_addr(struct nlsock *netlink_cmd, int family, /* Form the request, specifying filter (rtattr) if needed. */ memset(&req, 0, sizeof(req)); req.n.nlmsg_type = type; + req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.ifm.ifi_family = family; @@ -923,6 +925,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) uint8_t flags = 0; char *label = NULL; struct zebra_ns *zns; + uint32_t metric = METRIC_MAX; + uint32_t kernel_flags = 0; zns = zebra_ns_lookup(ns_id); ifa = NLMSG_DATA(h); @@ -959,12 +963,18 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) return -1; } + /* Flags passed through */ + if (tb[IFA_FLAGS]) + kernel_flags = *(int *)RTA_DATA(tb[IFA_FLAGS]); + else + kernel_flags = ifa->ifa_flags; + if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */ { char buf[BUFSIZ]; zlog_debug("netlink_interface_addr %s %s flags 0x%x:", nl_msg_type_to_str(h->nlmsg_type), ifp->name, - ifa->ifa_flags); + kernel_flags); if (tb[IFA_LOCAL]) zlog_debug(" IFA_LOCAL %s/%d", inet_ntop(ifa->ifa_family, @@ -1021,7 +1031,7 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) } /* Flags. */ - if (ifa->ifa_flags & IFA_F_SECONDARY) + if (kernel_flags & IFA_F_SECONDARY) SET_FLAG(flags, ZEBRA_IFA_SECONDARY); /* Label */ @@ -1031,6 +1041,9 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (label && strcmp(ifp->name, label) == 0) label = NULL; + if (tb[IFA_RT_PRIORITY]) + metric = *(uint32_t *)RTA_DATA(tb[IFA_RT_PRIORITY]); + /* Register interface address to the interface. */ if (ifa->ifa_family == AF_INET) { if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) { @@ -1043,7 +1056,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv4(ifp, flags, (struct in_addr *)addr, ifa->ifa_prefixlen, - (struct in_addr *)broad, label); + (struct in_addr *)broad, label, + metric); else connected_delete_ipv4( ifp, flags, (struct in_addr *)addr, @@ -1064,12 +1078,13 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) * time, Quagga * does query for and will receive all addresses. */ - if (!(ifa->ifa_flags + if (!(kernel_flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE))) connected_add_ipv6(ifp, flags, (struct in6_addr *)addr, (struct in6_addr *)broad, - ifa->ifa_prefixlen, label); + ifa->ifa_prefixlen, label, + metric); } else connected_delete_ipv6(ifp, (struct in6_addr *)addr, (struct in6_addr *)broad, @@ -1097,6 +1112,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifindex_t bridge_ifindex = IFINDEX_INTERNAL; ifindex_t bond_ifindex = IFINDEX_INTERNAL; ifindex_t link_ifindex = IFINDEX_INTERNAL; + uint8_t old_hw_addr[INTERFACE_HWADDR_MAX]; zns = zebra_ns_lookup(ns_id); @@ -1298,6 +1314,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) was_bond_slave = IS_ZEBRA_IF_BOND_SLAVE(ifp); zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); + memcpy(old_hw_addr, ifp->hw_addr, INTERFACE_HWADDR_MAX); + netlink_interface_update_hw_addr(tb, ifp); if (if_is_no_ptm_operative(ifp)) { @@ -1316,6 +1334,22 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) "Intf %s(%u) PTM up, notifying clients", name, ifp->ifindex); zebra_interface_up_update(ifp); + + /* Update EVPN VNI when SVI MAC change + */ + if (IS_ZEBRA_IF_VLAN(ifp) && + memcmp(old_hw_addr, ifp->hw_addr, + INTERFACE_HWADDR_MAX)) { + struct interface *link_if; + + link_if = + if_lookup_by_index_per_ns( + zebra_ns_lookup(NS_DEFAULT), + link_ifindex); + if (link_if) + zebra_vxlan_svi_up(ifp, + link_if); + } } } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; diff --git a/zebra/interface.c b/zebra/interface.c index ac765e784..229f9c1da 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -41,7 +41,7 @@ #include "zebra/interface.h" #include "zebra/rib.h" #include "zebra/rt.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/irdp.h" @@ -135,6 +135,8 @@ static int if_zebra_new_hook(struct interface *ifp) rtadv->DefaultPreference = RTADV_PREF_MEDIUM; rtadv->AdvPrefixList = list_new(); + rtadv->AdvRDNSSList = list_new(); + rtadv->AdvDNSSLList = list_new(); } #endif /* HAVE_RTADV */ @@ -153,7 +155,7 @@ static int if_zebra_new_hook(struct interface *ifp) * of seconds and ask again. Hopefully it's all settled * down upon startup. */ - thread_add_timer(zebrad.master, if_zebra_speed_update, ifp, 15, + thread_add_timer(zrouter.master, if_zebra_speed_update, ifp, 15, &zebra_if->speed_update); return 0; } @@ -175,6 +177,8 @@ static int if_zebra_delete_hook(struct interface *ifp) rtadv = &zebra_if->rtadv; list_delete(&rtadv->AdvPrefixList); + list_delete(&rtadv->AdvRDNSSList); + list_delete(&rtadv->AdvDNSSLList); #endif /* HAVE_RTADV */ THREAD_OFF(zebra_if->speed_update); @@ -1156,6 +1160,106 @@ static const char *zebra_ziftype_2str(zebra_iftype_t zif_type) } } +/* Interface's brief information print out to vty interface. */ +static void ifs_dump_brief_vty(struct vty *vty, struct vrf *vrf) +{ + struct connected *connected; + struct listnode *node; + struct route_node *rn; + struct zebra_if *zebra_if; + struct prefix *p; + struct interface *ifp; + bool print_header = true; + + FOR_ALL_INTERFACES (vrf, ifp) { + char global_pfx[PREFIX_STRLEN] = {0}; + char buf[PREFIX_STRLEN] = {0}; + bool first_pfx_printed = false; + + if (print_header) { + vty_out(vty, "%-16s%-8s%-16s%s\n", "Interface", + "Status", "VRF", "Addresses"); + vty_out(vty, "%-16s%-8s%-16s%s\n", "---------", + "------", "---", "---------"); + print_header = false; /* We have at least 1 iface */ + } + zebra_if = ifp->info; + + vty_out(vty, "%-16s", ifp->name); + + if (if_is_up(ifp)) + vty_out(vty, "%-8s", "up"); + else + vty_out(vty, "%-8s", "down"); + + vty_out(vty, "%-16s", vrf->name); + + for (rn = route_top(zebra_if->ipv4_subnets); rn; + rn = route_next(rn)) { + if (!rn->info) + continue; + uint32_t list_size = listcount((struct list *)rn->info); + + for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, + connected)) { + if (!CHECK_FLAG(connected->flags, + ZEBRA_IFA_SECONDARY)) { + p = connected->address; + prefix2str(p, buf, sizeof(buf)); + if (first_pfx_printed) { + /* padding to prepare row only for ip addr */ + vty_out(vty, "%-40s", ""); + if (list_size > 1) + vty_out(vty, "+ "); + vty_out(vty, "%s\n", buf); + } else { + if (list_size > 1) + vty_out(vty, "+ "); + vty_out(vty, "%s\n", buf); + } + first_pfx_printed = true; + break; + } + } + } + + uint32_t v6_list_size = 0; + for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) + && (connected->address->family == AF_INET6)) + v6_list_size++; + } + for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) + && !CHECK_FLAG(connected->flags, + ZEBRA_IFA_SECONDARY) + && (connected->address->family == AF_INET6)) { + p = connected->address; + /* Don't print link local pfx */ + if (!IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) { + prefix2str(p, global_pfx, PREFIX_STRLEN); + if (first_pfx_printed) { + /* padding to prepare row only for ip addr */ + vty_out(vty, "%-40s", ""); + if (v6_list_size > 1) + vty_out(vty, "+ "); + vty_out(vty, "%s\n", global_pfx); + } else { + if (v6_list_size > 1) + vty_out(vty, "+ "); + vty_out(vty, "%s\n", global_pfx); + } + first_pfx_printed = true; + break; + } + } + } + if (!first_pfx_printed) + vty_out(vty, "\n"); + } + vty_out(vty, "\n"); +} + /* Interface's information print out to vty interface. */ static void if_dump_vty(struct vty *vty, struct interface *ifp) { @@ -1456,13 +1560,16 @@ static void interface_update_stats(void) struct cmd_node interface_node = {INTERFACE_NODE, "%s(config-if)# ", 1}; +#ifndef VTYSH_EXTRACT_PL +#include "zebra/interface_clippy.c" +#endif /* Show all interfaces to vty. */ -DEFUN (show_interface, - show_interface_cmd, - "show interface [vrf NAME]", - SHOW_STR - "Interface status and configuration\n" - VRF_CMD_HELP_STR) +DEFPY(show_interface, show_interface_cmd, + "show interface [vrf NAME$name] [brief$brief]", + SHOW_STR + "Interface status and configuration\n" + VRF_CMD_HELP_STR + "Interface status and configuration summary\n") { struct vrf *vrf; struct interface *ifp; @@ -1470,13 +1577,18 @@ DEFUN (show_interface, interface_update_stats(); - if (argc > 2) - VRF_GET_ID(vrf_id, argv[3]->arg, false); + if (name) + VRF_GET_ID(vrf_id, name, false); /* All interface print. */ vrf = vrf_lookup_by_id(vrf_id); - FOR_ALL_INTERFACES (vrf, ifp) - if_dump_vty(vty, ifp); + if (brief) { + ifs_dump_brief_vty(vty, vrf); + } else { + FOR_ALL_INTERFACES (vrf, ifp) { + if_dump_vty(vty, ifp); + } + } return CMD_SUCCESS; } diff --git a/zebra/interface.h b/zebra/interface.h index 01dd69777..1dbcf33fa 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -168,6 +168,22 @@ struct rtadvconf { int DefaultPreference; #define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */ + /* + * List of recursive DNS servers to include in the RDNSS option. + * See [RFC8106 5.1] + * + * Default: empty list; do not emit RDNSS option + */ + struct list *AdvRDNSSList; + + /* + * List of DNS search domains to include in the DNSSL option. + * See [RFC8106 5.2] + * + * Default: empty list; do not emit DNSSL option + */ + struct list *AdvDNSSLList; + uint8_t inFastRexmit; /* True if we're rexmits faster than usual */ /* Track if RA was configured by BGP or by the Operator or both */ @@ -182,6 +198,41 @@ struct rtadvconf { #define RTADV_NUM_FAST_REXMITS 4 /* Fast Rexmit RA 4 times on certain events */ }; +struct rtadv_rdnss { + /* Address of recursive DNS server to advertise */ + struct in6_addr addr; + + /* + * Lifetime in seconds; all-ones means infinity, zero + * stop using it. + */ + uint32_t lifetime; + + /* If lifetime not set, use a default of 3*MaxRtrAdvInterval */ + int lifetime_set; +}; + +/* + * [RFC1035 2.3.4] sets the maximum length of a domain name (a sequence of + * labels, each prefixed by a length octet) at 255 octets. + */ +#define RTADV_MAX_ENCODED_DOMAIN_NAME 255 + +struct rtadv_dnssl { + /* Domain name without trailing root zone dot (NUL-terminated) */ + char name[RTADV_MAX_ENCODED_DOMAIN_NAME - 1]; + + /* Name encoded as in [RFC1035 3.1] */ + uint8_t encoded_name[RTADV_MAX_ENCODED_DOMAIN_NAME]; + + /* Actual length of encoded_name */ + size_t encoded_len; + + /* Lifetime as for RDNSS */ + uint32_t lifetime; + int lifetime_set; +}; + #endif /* HAVE_RTADV */ /* Zebra interface type - ones of interest. */ diff --git a/zebra/ioctl.c b/zebra/ioctl.c index ebe1edcae..9499c731e 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -213,7 +213,7 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc) rib_lookup_and_pushup(p, ifp->vrf_id); memset(&addreq, 0, sizeof addreq); - strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_addr = p->prefix; @@ -267,7 +267,7 @@ int if_unset_prefix(struct interface *ifp, struct connected *ifc) p = (struct prefix_ipv4 *)ifc->address; memset(&addreq, 0, sizeof addreq); - strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_addr = p->prefix; @@ -412,7 +412,7 @@ void if_get_flags(struct interface *ifp) if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) { (void)memset(&ifmr, 0, sizeof(ifmr)); - strncpy(ifmr.ifm_name, ifp->name, IFNAMSIZ); + strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); /* Seems not all interfaces implement this ioctl */ if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1 && @@ -514,7 +514,7 @@ int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc) p = (struct prefix_ipv6 *)ifc->address; memset(&addreq, 0, sizeof addreq); - strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_addr = p->prefix; @@ -557,7 +557,7 @@ int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc) p = (struct prefix_ipv6 *)ifc->address; memset(&addreq, 0, sizeof addreq); - strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_addr = p->prefix; diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index fc554219b..c523ee983 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -44,7 +44,7 @@ extern struct zebra_privs_t zserv_privs; /* clear and set interface name string */ void lifreq_set_name(struct lifreq *lifreq, const char *ifname) { - strncpy(lifreq->lifr_name, ifname, IFNAMSIZ); + strlcpy(lifreq->lifr_name, ifname, sizeof(lifreq->lifr_name)); } int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id) @@ -199,7 +199,7 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc) ifaddr = *p; - strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ); + strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name)); addr.sin_addr = p->prefix; addr.sin_family = p->family; @@ -250,7 +250,7 @@ int if_unset_prefix(struct interface *ifp, struct connected *ifc) p = (struct prefix_ipv4 *)ifc->address; - strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ); + strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name)); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = p->family; diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c index 3e50550dd..c0b772cd0 100644 --- a/zebra/irdp_interface.c +++ b/zebra/irdp_interface.c @@ -45,7 +45,7 @@ #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/rib.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/irdp.h" #include "zebra/zebra_errors.h" @@ -285,7 +285,7 @@ static void irdp_if_start(struct interface *ifp, int multicast, timer); irdp->t_advertise = NULL; - thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer, + thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer, &irdp->t_advertise); } @@ -706,7 +706,7 @@ DEFUN (ip_irdp_debug_disable, return CMD_SUCCESS; } -void irdp_if_init() +void irdp_if_init(void) { hook_register(zebra_if_config_wr, irdp_config_write); hook_register(if_del, irdp_if_delete); diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c index 9300ba603..a9734056b 100644 --- a/zebra/irdp_main.c +++ b/zebra/irdp_main.c @@ -56,7 +56,7 @@ #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/rib.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/irdp.h" #include "zebra/zebra_errors.h" @@ -113,7 +113,7 @@ int irdp_sock_init(void) }; t_irdp_raw = NULL; - thread_add_read(zebrad.master, irdp_read_raw, NULL, sock, &t_irdp_raw); + thread_add_read(zrouter.master, irdp_read_raw, NULL, sock, &t_irdp_raw); return sock; } @@ -245,7 +245,7 @@ int irdp_send_thread(struct thread *t_advert) timer); irdp->t_advertise = NULL; - thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer, + thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer, &irdp->t_advertise); return 0; } @@ -306,7 +306,7 @@ void process_solicit(struct interface *ifp) timer = (random() % MAX_RESPONSE_DELAY) + 1; irdp->t_advertise = NULL; - thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer, + thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer, &irdp->t_advertise); } diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index bebccd716..774d84d66 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -58,7 +58,7 @@ #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/rib.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/irdp.h" #include "zebra/zebra_errors.h" @@ -230,7 +230,7 @@ int irdp_read_raw(struct thread *r) int irdp_sock = THREAD_FD(r); t_irdp_raw = NULL; - thread_add_read(zebrad.master, irdp_read_raw, NULL, irdp_sock, + thread_add_read(zrouter.master, irdp_read_raw, NULL, irdp_sock, &t_irdp_raw); ret = irdp_recvmsg(irdp_sock, (uint8_t *)buf, IRDP_RX_BUF, &ifindex); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 360f596b8..2f850c633 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -43,7 +43,8 @@ #include "mpls.h" #include "lib_errors.h" -#include "zebra/zserv.h" +//#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/rt.h" @@ -388,7 +389,7 @@ static int kernel_read(struct thread *thread) netlink_parse_info(netlink_information_fetch, &zns->netlink, &dp_info, 5, 0); zns->t_netlink = NULL; - thread_add_read(zebrad.master, kernel_read, zns, zns->netlink.sock, + thread_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock, &zns->t_netlink); return 0; @@ -1032,7 +1033,6 @@ int netlink_request(struct nlsock *nl, struct nlmsghdr *n) } /* Fill common fields for all requests. */ - n->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; n->nlmsg_pid = nl->snl.nl_pid; n->nlmsg_seq = ++nl->seq; @@ -1159,7 +1159,7 @@ void kernel_init(struct zebra_ns *zns) zns->t_netlink = NULL; - thread_add_read(zebrad.master, kernel_read, zns, + thread_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock, &zns->t_netlink); rt_netlink_init(); diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 84b06e579..792756efe 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -43,7 +43,7 @@ #include "zebra/rt.h" #include "zebra/interface.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/debug.h" #include "zebra/kernel_socket.h" #include "zebra/rib.h" @@ -236,6 +236,7 @@ size_t _rta_get(caddr_t sap, void *destp, size_t destlen, bool checkaf); size_t rta_get(caddr_t sap, void *dest, size_t destlen); size_t rta_getattr(caddr_t sap, void *destp, size_t destlen); size_t rta_getsdlname(caddr_t sap, void *dest, short *destlen); +const char *rtatostr(unsigned int flags, char *buf, size_t buflen); /* Supported address family check. */ static inline int af_check(int family) @@ -273,7 +274,7 @@ size_t _rta_get(caddr_t sap, void *destp, size_t destlen, bool checkaf) if (sa->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)sa; if (sdl->sdl_index == 0 || sdl->sdl_nlen == 0) - copylen = sizeof(*sdl) - sizeof(sdl->sdl_data); + copylen = destlen; } if (copylen > destlen) { @@ -329,6 +330,85 @@ size_t rta_getsdlname(caddr_t sap, void *destp, short *destlen) return tlen; } +const char *rtatostr(unsigned int flags, char *buf, size_t buflen) +{ + const char *flagstr, *bufstart; + int bit, wlen; + char ustr[32]; + + /* Hold the pointer to the buffer beginning. */ + bufstart = buf; + + for (bit = 1; bit; bit <<= 1) { + if ((flags & bit) == 0) + continue; + + switch (bit) { + case RTA_DST: + flagstr = "DST"; + break; + case RTA_GATEWAY: + flagstr = "GATEWAY"; + break; + case RTA_NETMASK: + flagstr = "NETMASK"; + break; +#ifdef RTA_GENMASK + case RTA_GENMASK: + flagstr = "GENMASK"; + break; +#endif /* RTA_GENMASK */ + case RTA_IFP: + flagstr = "IFP"; + break; + case RTA_IFA: + flagstr = "IFA"; + break; +#ifdef RTA_AUTHOR + case RTA_AUTHOR: + flagstr = "AUTHOR"; + break; +#endif /* RTA_AUTHOR */ + case RTA_BRD: + flagstr = "BRD"; + break; +#ifdef RTA_SRC + case RTA_SRC: + flagstr = "SRC"; + break; +#endif /* RTA_SRC */ +#ifdef RTA_SRCMASK + case RTA_SRCMASK: + flagstr = "SRCMASK"; + break; +#endif /* RTA_SRCMASK */ +#ifdef RTA_LABEL + case RTA_LABEL: + flagstr = "LABEL"; + break; +#endif /* RTA_LABEL */ + + default: + snprintf(ustr, sizeof(ustr), "0x%x", bit); + flagstr = ustr; + break; + } + + wlen = snprintf(buf, buflen, "%s,", flagstr); + buf += wlen; + buflen -= wlen; + } + + /* Check for empty buffer. */ + if (bufstart != buf) + buf--; + + /* Remove the last comma. */ + *buf = 0; + + return bufstart; +} + /* Dump routing table flag for debug purpose. */ static void rtm_flag_dump(int flag) { @@ -443,6 +523,7 @@ int ifm_read(struct if_msghdr *ifm) short ifnlen = 0; int maskbit; caddr_t cp; + char fbuf[64]; /* terminate ifname at head (for strnlen) and tail (for safety) */ ifname[IFNAMSIZ - 1] = '\0'; @@ -488,8 +569,9 @@ int ifm_read(struct if_msghdr *ifm) } if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: sdl ifname %s", __func__, - (ifnlen ? ifname : "(nil)")); + zlog_debug("%s: sdl ifname %s addrs {%s}", __func__, + (ifnlen ? ifname : "(nil)"), + rtatostr(ifm->ifm_addrs, fbuf, sizeof(fbuf))); /* * Look up on ifindex first, because ifindices are the primary handle @@ -687,6 +769,7 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr, union sockunion dst; union sockunion gateway; int maskbit; + char fbuf[64]; pnt = (caddr_t)(ifm + 1); end = ((caddr_t)ifm) + ifm->ifam_msglen; @@ -736,33 +819,35 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr, } if (IS_ZEBRA_DEBUG_KERNEL) { - int family = sockunion_family(addr); - switch (family) { + switch (sockunion_family(addr)) { case AF_INET: case AF_INET6: { char buf[4][INET6_ADDRSTRLEN]; + int masklen = + (sockunion_family(addr) == AF_INET) + ? ip_masklen(mask->sin.sin_addr) + : ip6_masklen(mask->sin6.sin6_addr); zlog_debug( - "%s: ifindex %d, ifname %s, ifam_addrs 0x%x, " + "%s: ifindex %d, ifname %s, ifam_addrs {%s}, " "ifam_flags 0x%x, addr %s/%d broad %s dst %s " "gateway %s", __func__, ifm->ifam_index, - (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs, + (ifnlen ? ifname : "(nil)"), + rtatostr(ifm->ifam_addrs, fbuf, sizeof(fbuf)), ifm->ifam_flags, - inet_ntop(family, &addr->sin.sin_addr, buf[0], - sizeof(buf[0])), - ip_masklen(mask->sin.sin_addr), - inet_ntop(family, &brd->sin.sin_addr, buf[1], - sizeof(buf[1])), - inet_ntop(family, &dst.sin.sin_addr, buf[2], - sizeof(buf[2])), - inet_ntop(family, &gateway.sin.sin_addr, buf[3], - sizeof(buf[3]))); + sockunion2str(addr, buf[0], sizeof(buf[0])), + masklen, + sockunion2str(brd, buf[1], sizeof(buf[1])), + sockunion2str(&dst, buf[2], sizeof(buf[2])), + sockunion2str(&gateway, buf[2], + sizeof(buf[2]))); } break; default: - zlog_debug("%s: ifindex %d, ifname %s, ifam_addrs 0x%x", + zlog_debug("%s: ifindex %d, ifname %s, ifam_addrs {%s}", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), - ifm->ifam_addrs); + rtatostr(ifm->ifam_addrs, fbuf, + sizeof(fbuf))); break; } } @@ -821,7 +906,8 @@ int ifam_read(struct ifa_msghdr *ifam) connected_add_ipv4(ifp, flags, &addr.sin.sin_addr, ip_masklen(mask.sin.sin_addr), &brd.sin.sin_addr, - (isalias ? ifname : NULL)); + (isalias ? ifname : NULL), + METRIC_MAX); else connected_delete_ipv4(ifp, flags, &addr.sin.sin_addr, ip_masklen(mask.sin.sin_addr), @@ -838,7 +924,8 @@ int ifam_read(struct ifa_msghdr *ifam) connected_add_ipv6(ifp, flags, &addr.sin6.sin6_addr, NULL, ip6_masklen(mask.sin6.sin6_addr), - (isalias ? ifname : NULL)); + (isalias ? ifname : NULL), + METRIC_MAX); else connected_delete_ipv6(ifp, &addr.sin6.sin6_addr, NULL, ip6_masklen(mask.sin6.sin6_addr)); @@ -909,7 +996,7 @@ static int rtm_read_mesg(struct rt_msghdr *rtm, union sockunion *dest, pnt += rta_get(pnt, gate, sizeof(*gate)); break; case RTA_NETMASK: - pnt += rta_get(pnt, mask, sizeof(*mask)); + pnt += rta_getattr(pnt, mask, sizeof(*mask)); break; case RTA_IFP: pnt += rta_getsdlname(pnt, ifname, ifnlen); @@ -950,6 +1037,7 @@ void rtm_read(struct rt_msghdr *rtm) struct prefix p; ifindex_t ifindex = 0; afi_t afi; + char fbuf[64]; zebra_flags = 0; @@ -959,9 +1047,10 @@ void rtm_read(struct rt_msghdr *rtm) if (!(flags & RTF_DONE)) return; if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: got rtm of type %d (%s)", __func__, + zlog_debug("%s: got rtm of type %d (%s) addrs {%s}", __func__, rtm->rtm_type, - lookup_msg(rtm_type_str, rtm->rtm_type, NULL)); + lookup_msg(rtm_type_str, rtm->rtm_type, NULL), + rtatostr(rtm->rtm_addrs, fbuf, sizeof(fbuf))); #ifdef RTF_CLONED /*bsdi, netbsd 1.6*/ if (flags & RTF_CLONED) @@ -1207,12 +1296,14 @@ int rtm_write(int message, union sockunion *dest, union sockunion *mask, /* For debug purpose. */ static void rtmsg_debug(struct rt_msghdr *rtm) { + char fbuf[64]; + zlog_debug("Kernel: Len: %d Type: %s", rtm->rtm_msglen, lookup_msg(rtm_type_str, rtm->rtm_type, NULL)); rtm_flag_dump(rtm->rtm_flags); zlog_debug("Kernel: message seq %d", rtm->rtm_seq); - zlog_debug("Kernel: pid %lld, rtm_addrs 0x%x", (long long)rtm->rtm_pid, - rtm->rtm_addrs); + zlog_debug("Kernel: pid %lld, rtm_addrs {%s}", (long long)rtm->rtm_pid, + rtatostr(rtm->rtm_addrs, fbuf, sizeof(fbuf))); } /* This is pretty gross, better suggestions welcome -- mhandler */ @@ -1281,7 +1372,7 @@ static int kernel_read(struct thread *thread) return 0; } - thread_add_read(zebrad.master, kernel_read, NULL, sock, NULL); + thread_add_read(zrouter.master, kernel_read, NULL, sock, NULL); if (IS_ZEBRA_DEBUG_KERNEL) rtmsg_debug(&buf.r.rtm); @@ -1354,7 +1445,7 @@ static void routing_socket(struct zebra_ns *zns) zlog_warn ("Can't set O_NONBLOCK to routing socket");*/ /* kernel_read needs rewrite. */ - thread_add_read(zebrad.master, kernel_read, NULL, routing_sock, NULL); + thread_add_read(zrouter.master, kernel_read, NULL, routing_sock, NULL); } /* Exported interface function. This function simply calls diff --git a/zebra/label_manager.c b/zebra/label_manager.c index bfad8ea64..1b17845e4 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -34,7 +34,8 @@ #include "lib/zclient.h" #include "lib/libfrr.h" -#include "zebra/zserv.h" +//#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/label_manager.h" #include "zebra/zebra_errors.h" @@ -294,7 +295,7 @@ static int lm_zclient_connect(struct thread *t) if (zclient_socket_connect(zclient) < 0) { flog_err(EC_ZEBRA_LM_CLIENT_CONNECTION_FAILED, "Error connecting synchronous zclient!"); - thread_add_timer(zebrad.master, lm_zclient_connect, zclient, + thread_add_timer(zrouter.master, lm_zclient_connect, zclient, CONNECTION_DELAY, &zclient->t_connect); return -1; } @@ -318,7 +319,7 @@ static void lm_zclient_init(char *lm_zserv_path) lm_zserv_path); /* Set default values. */ - zclient = zclient_new(zebrad.master, &zclient_options_default); + zclient = zclient_new(zrouter.master, &zclient_options_default); zclient->privs = &zserv_privs; zclient->sock = -1; zclient->t_connect = NULL; @@ -480,7 +481,7 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start, } -void label_manager_close() +void label_manager_close(void) { list_delete(&lbl_mgr.lc_list); stream_free(obuf); diff --git a/zebra/main.c b/zebra/main.c index b54c36c10..c605050c5 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -62,12 +62,6 @@ #define ZEBRA_PTM_SUPPORT -/* Zebra instance */ -struct zebra_t zebrad = { - .rtm_table_default = 0, - .packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS, -}; - /* process id. */ pid_t pid; @@ -156,10 +150,10 @@ static void sigint(void) zebra_dplane_pre_finish(); - for (ALL_LIST_ELEMENTS(zebrad.client_list, ln, nn, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, ln, nn, client)) zserv_close_client(client); - list_delete_all_node(zebrad.client_list); + list_delete_all_node(zrouter.client_list); zebra_ptm_finish(); if (retain_mode) @@ -168,8 +162,8 @@ static void sigint(void) if (zvrf) SET_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN); } - if (zebrad.lsp_process_q) - work_queue_free_and_null(&zebrad.lsp_process_q); + if (zrouter.lsp_process_q) + work_queue_free_and_null(&zrouter.lsp_process_q); vrf_terminate(); ns_walk_func(zebra_ns_early_shutdown); @@ -179,7 +173,7 @@ static void sigint(void) prefix_list_reset(); route_map_finish(); - list_delete(&zebrad.client_list); + list_delete(&zrouter.client_list); /* Indicate that all new dplane work has been enqueued. When that * work is complete, the dataplane will enqueue an event @@ -202,9 +196,6 @@ int zebra_finalize(struct thread *dummy) /* Stop dplane thread and finish any cleanup */ zebra_dplane_shutdown(); - work_queue_free_and_null(&zebrad.ribq); - meta_queue_free(zebrad.mq); - zebra_router_terminate(); frr_fini(); @@ -391,7 +382,7 @@ int main(int argc, char **argv) } } - zebrad.master = frr_init(); + zrouter.master = frr_init(); /* Initialize pthread library */ frr_pthread_init(); @@ -479,7 +470,7 @@ int main(int argc, char **argv) #endif /* HANDLE_NETLINK_FUZZING */ - frr_run(zebrad.master); + frr_run(zrouter.master); /* Not reached... */ return 0; diff --git a/zebra/redistribute.c b/zebra/redistribute.c index b9c1f0aef..f98a4c02c 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -33,7 +33,7 @@ #include "srcdest_table.h" #include "zebra/rib.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_routemap.h" @@ -159,10 +159,10 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, if (IS_ZEBRA_DEBUG_RIB) { zlog_debug( - "%u:%s: Redist update re %p (type %d), old %p (type %d)", + "%u:%s: Redist update re %p (%s), old %p (%s)", re->vrf_id, prefix2str(p, buf, sizeof(buf)), - re, re->type, prev_re, - prev_re ? prev_re->type : -1); + re, zebra_route_string(re->type), prev_re, + prev_re ? zebra_route_string(prev_re->type) : "None"); } afi = family2afi(p->family); @@ -173,7 +173,7 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, return; } - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { send_redistribute = 0; if (is_default_prefix(p) @@ -229,8 +229,9 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, if (IS_ZEBRA_DEBUG_RIB) { inet_ntop(p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug("%u:%s/%d: Redist delete re %p (type %d)", - re->vrf_id, buf, p->prefixlen, re, re->type); + zlog_debug("%u:%s/%d: Redist delete re %p (%s)", + re->vrf_id, buf, p->prefixlen, re, + zebra_route_string(re->type)); } /* Add DISTANCE_INFINITY check. */ @@ -245,7 +246,7 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, return; } - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { if ((is_default_prefix(p) && vrf_bitmap_check(client->redist_default[afi], re->vrf_id)) @@ -404,12 +405,12 @@ void zebra_interface_up_update(struct interface *ifp) ifp->name, ifp->vrf_id); if (ifp->ptm_status || !ifp->ptm_enable) { - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) - if (client->ifinfo) { - zsend_interface_update(ZEBRA_INTERFACE_UP, - client, ifp); - zsend_interface_link_params(client, ifp); - } + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, + client)) { + zsend_interface_update(ZEBRA_INTERFACE_UP, + client, ifp); + zsend_interface_link_params(client, ifp); + } } } @@ -423,7 +424,7 @@ void zebra_interface_down_update(struct interface *ifp) zlog_debug("MESSAGE: ZEBRA_INTERFACE_DOWN %s(%u)", ifp->name, ifp->vrf_id); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); } } @@ -438,12 +439,11 @@ void zebra_interface_add_update(struct interface *ifp) zlog_debug("MESSAGE: ZEBRA_INTERFACE_ADD %s(%u)", ifp->name, ifp->vrf_id); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) - if (client->ifinfo) { - client->ifadd_cnt++; - zsend_interface_add(client, ifp); - zsend_interface_link_params(client, ifp); - } + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + client->ifadd_cnt++; + zsend_interface_add(client, ifp); + zsend_interface_link_params(client, ifp); + } } void zebra_interface_delete_update(struct interface *ifp) @@ -455,7 +455,7 @@ void zebra_interface_delete_update(struct interface *ifp) zlog_debug("MESSAGE: ZEBRA_INTERFACE_DELETE %s(%u)", ifp->name, ifp->vrf_id); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { client->ifdel_cnt++; zsend_interface_delete(client, ifp); } @@ -487,7 +487,7 @@ void zebra_interface_address_add_update(struct interface *ifp, router_id_add_address(ifc); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) { client->connected_rt_add_cnt++; zsend_interface_address(ZEBRA_INTERFACE_ADDRESS_ADD, @@ -516,7 +516,7 @@ void zebra_interface_address_delete_update(struct interface *ifp, router_id_del_address(ifc); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) { client->connected_rt_del_cnt++; zsend_interface_address(ZEBRA_INTERFACE_ADDRESS_DELETE, @@ -537,7 +537,7 @@ void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id) "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/DEL %s VRF Id %u -> %u", ifp->name, ifp->vrf_id, new_vrf_id); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Need to delete if the client is not interested in the new * VRF. */ zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); @@ -560,7 +560,7 @@ void zebra_interface_vrf_update_add(struct interface *ifp, vrf_id_t old_vrf_id) "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/ADD %s VRF Id %u -> %u", ifp->name, old_vrf_id, ifp->vrf_id); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Need to add if the client is interested in the new VRF. */ client->ifadd_cnt++; zsend_interface_add(client, ifp); @@ -612,7 +612,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re, newre->flags = re->flags; newre->metric = re->metric; newre->mtu = re->mtu; - newre->table = zebrad.rtm_table_default; + newre->table = zrouter.rtm_table_default; newre->nexthop_num = 0; newre->uptime = time(NULL); newre->instance = re->table; @@ -633,7 +633,7 @@ int zebra_del_import_table_entry(struct route_node *rn, struct route_entry *re) rib_delete(afi, SAFI_UNICAST, re->vrf_id, ZEBRA_ROUTE_TABLE, re->table, re->flags, &p, NULL, re->ng.nexthop, - zebrad.rtm_table_default, re->metric, re->distance, false); + zrouter.rtm_table_default, re->metric, re->distance, false); return 0; } @@ -648,7 +648,7 @@ int zebra_import_table(afi_t afi, uint32_t table_id, uint32_t distance, if (!is_zebra_valid_kernel_table(table_id) || ((table_id == RT_TABLE_MAIN) - || (table_id == zebrad.rtm_table_default))) + || (table_id == zrouter.rtm_table_default))) return (-1); if (afi >= AFI_MAX) @@ -811,7 +811,6 @@ void zebra_interface_parameters_update(struct interface *ifp) zlog_debug("MESSAGE: ZEBRA_INTERFACE_LINK_PARAMS %s(%u)", ifp->name, ifp->vrf_id); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) - if (client->ifinfo) - zsend_interface_link_params(client, ifp); + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) + zsend_interface_link_params(client, ifp); } diff --git a/zebra/router-id.c b/zebra/router-id.c index c500f79a6..569ffbab4 100644 --- a/zebra/router-id.c +++ b/zebra/router-id.c @@ -38,15 +38,12 @@ #include "rib.h" #include "vrf.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zapi_msg.h" #include "zebra/zebra_vrf.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" -/* master zebra server structure */ -extern struct zebra_t zebrad; - static struct connected *router_id_find_node(struct list *l, struct connected *ifc) { @@ -114,7 +111,7 @@ static void router_id_set(struct prefix *p, vrf_id_t vrf_id) router_id_get(&p2, vrf_id); - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) zsend_router_id_update(client, &p2, vrf_id); } @@ -145,7 +142,7 @@ void router_id_add_address(struct connected *ifc) if (prefix_same(&before, &after)) return; - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) zsend_router_id_update(client, &after, zvrf_id(zvrf)); } @@ -177,7 +174,7 @@ void router_id_del_address(struct connected *ifc) if (prefix_same(&before, &after)) return; - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) zsend_router_id_update(client, &after, zvrf_id(zvrf)); } diff --git a/zebra/rt.h b/zebra/rt.h index 0317dc85b..4080b0ccb 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -32,12 +32,17 @@ #include "zebra/zebra_dplane.h" /* - * Update or delete a prefix from the kernel, + * Update or delete a route, LSP, or pseudowire from the kernel, * using info from a dataplane context. */ extern enum zebra_dplane_result kernel_route_update( struct zebra_dplane_ctx *ctx); +extern enum zebra_dplane_result kernel_lsp_update( + struct zebra_dplane_ctx *ctx); + +enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx); + extern int kernel_address_add_ipv4(struct interface *, struct connected *); extern int kernel_address_delete_ipv4(struct interface *, struct connected *); extern int kernel_address_add_ipv6(struct interface *, struct connected *); @@ -47,21 +52,6 @@ extern int kernel_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, extern int kernel_interface_set_master(struct interface *master, struct interface *slave); -extern enum zebra_dplane_result kernel_add_lsp(zebra_lsp_t *lsp); -extern enum zebra_dplane_result kernel_upd_lsp(zebra_lsp_t *lsp); -extern enum zebra_dplane_result kernel_del_lsp(zebra_lsp_t *lsp); - -/* - * Add the ability to pass back up the lsp install/delete - * success/failure. - * - * This functions goal is similiar to kernel_route_rib_pass_fail - * in that we are separating out the mechanics for - * the install/failure to set/unset flags and to notify - * as needed. - */ -extern void kernel_lsp_pass_fail(zebra_lsp_t *lsp, enum zebra_dplane_status res); - extern int mpls_kernel_init(void); extern uint32_t kernel_get_speed(struct interface *ifp); @@ -79,6 +69,8 @@ extern int kernel_del_mac(struct interface *ifp, vlanid_t vid, extern int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, struct ethaddr *mac, uint8_t flags); extern int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip); +extern int kernel_upd_neigh(struct interface *ifp, struct ipaddr *ip, + struct ethaddr *mac, uint8_t flags, uint16_t state); /* * Southbound Initialization routines to get initial starting @@ -90,8 +82,13 @@ extern void kernel_terminate(struct zebra_ns *zns, bool complete); extern void macfdb_read(struct zebra_ns *zns); extern void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, struct interface *br_if); +extern void macfdb_read_specific_mac(struct zebra_ns *zns, + struct interface *br_if, + struct ethaddr *mac, vlanid_t vid); extern void neigh_read(struct zebra_ns *zns); extern void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *ifp); +extern void neigh_read_specific_ip(struct ipaddr *ip, + struct interface *vlan_if); extern void route_read(struct zebra_ns *zns); #endif /* _ZEBRA_RT_H */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index ae4bc5272..18cf389d5 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -556,6 +556,9 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, parse_encap_mpls(tb[RTA_ENCAP], labels); } + if (rtm->rtm_flags & RTNH_F_ONLINK) + SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK); + if (num_labels) nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, labels); @@ -663,6 +666,10 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, nexthop_add_labels(nh, ZEBRA_LSP_STATIC, num_labels, labels); + if (nh && (rtnh->rtnh_flags & RTNH_F_ONLINK)) + SET_FLAG(nh->flags, + NEXTHOP_FLAG_ONLINK); + if (rtnh->rtnh_len == 0) break; @@ -879,6 +886,7 @@ static int netlink_request_route(struct zebra_ns *zns, int family, int type) /* Form the request, specifying filter (rtattr) if needed. */ memset(&req, 0, sizeof(req)); req.n.nlmsg_type = type; + req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.rtm.rtm_family = family; @@ -1132,8 +1140,7 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, 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 (nexthop->type == NEXTHOP_TYPE_IFINDEX) { if (cmd == RTM_NEWROUTE) { if (nexthop->rmap_src.ipv4.s_addr) addattr_l(nlmsg, req_size, RTA_PREFSRC, @@ -1149,23 +1156,6 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, "nexthop via if %u(%u)", routedesc, nexthop->ifindex, nexthop->vrf_id); } - - if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { - if (cmd == RTM_NEWROUTE) { - if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv6, bytelen); - else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv6, bytelen); - } - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "netlink_route_multipath() (%s): " - "nexthop via if %u(%u)", - routedesc, nexthop->ifindex, nexthop->vrf_id); - } } /* This function takes a nexthop as argument and @@ -1337,8 +1327,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, rtnh->rtnh_ifindex = nexthop->ifindex; /* ifindex */ - if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX - || nexthop->type == NEXTHOP_TYPE_IFINDEX) { + if (nexthop->type == NEXTHOP_TYPE_IFINDEX) { if (nexthop->rmap_src.ipv4.s_addr) *src = &nexthop->rmap_src; else if (nexthop->src.ipv4.s_addr) @@ -1477,10 +1466,9 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; - if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) { - if ((p->family == AF_INET) || v6_rr_semantics) - req.n.nlmsg_flags |= NLM_F_REPLACE; - } + if ((cmd == RTM_NEWROUTE) && + ((p->family == AF_INET) || v6_rr_semantics)) + req.n.nlmsg_flags |= NLM_F_REPLACE; req.n.nlmsg_type = cmd; @@ -2127,6 +2115,7 @@ static int netlink_request_macs(struct nlsock *netlink_cmd, int family, /* Form the request, specifying filter (rtattr) if needed. */ memset(&req, 0, sizeof(req)); req.n.nlmsg_type = type; + req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.ifm.ifi_family = family; if (master_ifindex) @@ -2195,6 +2184,70 @@ int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, return ret; } + +/* Request for MAC FDB for a specific MAC address in VLAN from the kernel */ +static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns, + int family, + int type, + struct interface *br_if, + struct ethaddr *mac, + vlanid_t vid) +{ + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + struct zebra_if *br_zif; + char buf[ETHER_ADDR_STRLEN]; + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.n.nlmsg_type = type; /* RTM_GETNEIGH */ + req.n.nlmsg_flags = NLM_F_REQUEST; + req.ndm.ndm_family = family; /* AF_BRIDGE */ + /* req.ndm.ndm_state = NUD_REACHABLE; */ + + addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6); + + br_zif = (struct zebra_if *)br_if->info; + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0) + addattr16(&req.n, sizeof(req), NDA_VLAN, vid); + + addattr32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: Tx family %s IF %s(%u) MAC %s vid %u", + __PRETTY_FUNCTION__, + nl_family_to_str(req.ndm.ndm_family), br_if->name, + br_if->ifindex, + prefix_mac2str(mac, buf, sizeof(buf)), vid); + + return netlink_request(&zns->netlink_cmd, &req.n); +} + +int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, + struct interface *br_if, + struct ethaddr *mac, vlanid_t vid) +{ + int ret = 0; + struct zebra_dplane_info dp_info; + + zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); + + /* Get bridge FDB table for specific bridge - we do the VLAN filtering. + */ + ret = netlink_request_specific_mac_in_bridge(zns, AF_BRIDGE, + RTM_GETNEIGH, + br_if, mac, vid); + if (ret < 0) + return ret; + + ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd, + &dp_info, 1, 0); + + return ret; +} static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, struct in_addr vtep_ip, int cmd, bool sticky) @@ -2454,6 +2507,7 @@ static int netlink_request_neigh(struct nlsock *netlink_cmd, int family, /* Form the request, specifying filter (rtattr) if needed. */ memset(&req, 0, sizeof(req)); req.n.nlmsg_type = type; + req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.ndm.ndm_family = family; if (ifindex) @@ -2505,6 +2559,73 @@ int netlink_neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) return ret; } +/* + * Request for a specific IP in VLAN (SVI) device from IP Neighbor table, + * read using netlink interface. + */ +static int netlink_request_specific_neigh_in_vlan(struct zebra_ns *zns, + int type, struct ipaddr *ip, + ifindex_t ifindex) +{ + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + int ipa_len; + + /* Form the request, specifying filter (rtattr) if needed. */ + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = type; /* RTM_GETNEIGH */ + req.ndm.ndm_ifindex = ifindex; + + if (IS_IPADDR_V4(ip)) { + ipa_len = IPV4_MAX_BYTELEN; + req.ndm.ndm_family = AF_INET; + + } else { + ipa_len = IPV6_MAX_BYTELEN; + req.ndm.ndm_family = AF_INET6; + } + + addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); + + return netlink_request(&zns->netlink_cmd, &req.n); +} + +int netlink_neigh_read_specific_ip(struct ipaddr *ip, + struct interface *vlan_if) +{ + int ret = 0; + struct zebra_ns *zns; + struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(vlan_if->vrf_id); + char buf[INET6_ADDRSTRLEN]; + struct zebra_dplane_info dp_info; + + zns = zvrf->zns; + + zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: neigh request IF %s(%u) IP %s vrf_id %u", + __PRETTY_FUNCTION__, vlan_if->name, + vlan_if->ifindex, + ipaddr2str(ip, buf, sizeof(buf)), + vlan_if->vrf_id); + + ret = netlink_request_specific_neigh_in_vlan(zns, RTM_GETNEIGH, ip, + vlan_if->ifindex); + if (ret < 0) + return ret; + + ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd, + &dp_info, 1, 0); + + return ret; +} + int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id) { int len; @@ -2579,12 +2700,12 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x", + zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x", nl_msg_type_to_str(cmd), nl_family_to_str(req.ndm.ndm_family), ifp->name, ifp->ifindex, ipaddr2str(ip, buf, sizeof(buf)), mac ? prefix_mac2str(mac, buf2, sizeof(buf2)) - : "null", flags); + : "null", flags, state); return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); @@ -2615,17 +2736,24 @@ int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip) return netlink_neigh_update2(ifp, ip, NULL, 0, 0, RTM_DELNEIGH); } +int kernel_upd_neigh(struct interface *ifp, struct ipaddr *ip, + struct ethaddr *mac, uint8_t flags, uint16_t state) +{ + return netlink_neigh_update2(ifp, ip, mac, flags, + state, RTM_NEWNEIGH); +} + /* - * MPLS label forwarding table change via netlink interface. + * MPLS label forwarding table change via netlink interface, using dataplane + * context information. */ -int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) +int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) { mpls_lse_t lse; zebra_nhlfe_t *nhlfe; struct nexthop *nexthop = NULL; unsigned int nexthop_num; const char *routedesc; - struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); int route_type; struct { @@ -2634,14 +2762,14 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) char buf[NL_PKT_BUF_SIZE]; } req; - memset(&req, 0, sizeof req - NL_PKT_BUF_SIZE); + memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE); /* * Count # nexthops so we can decide whether to use singlepath * or multipath case. */ nexthop_num = 0; - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + for (nhlfe = dplane_ctx_get_nhlfe(ctx); nhlfe; nhlfe = nhlfe->next) { nexthop = nhlfe->nexthop; if (!nexthop) continue; @@ -2650,8 +2778,7 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) nexthop_num++; - } else /* DEL */ - { + } else { /* DEL */ /* Count all installed NHLFEs */ if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) @@ -2659,13 +2786,14 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) } } - if ((nexthop_num == 0) || (!lsp->best_nhlfe && (cmd != RTM_DELROUTE))) + if ((nexthop_num == 0) || + (!dplane_ctx_get_best_nhlfe(ctx) && (cmd != RTM_DELROUTE))) return 0; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; req.n.nlmsg_type = cmd; - req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; + req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; req.r.rtm_family = AF_MPLS; req.r.rtm_table = RT_TABLE_MAIN; @@ -2678,23 +2806,26 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) req.n.nlmsg_flags |= NLM_F_REPLACE; /* set the protocol value if installing */ - route_type = re_type_from_lsp_type(lsp->best_nhlfe->type); + route_type = re_type_from_lsp_type( + dplane_ctx_get_best_nhlfe(ctx)->type); req.r.rtm_protocol = zebra2proto(route_type); } /* Fill destination */ - lse = mpls_lse_encode(lsp->ile.in_label, 0, 0, 1); - addattr_l(&req.n, sizeof req, RTA_DST, &lse, sizeof(mpls_lse_t)); + lse = mpls_lse_encode(dplane_ctx_get_in_label(ctx), 0, 0, 1); + addattr_l(&req.n, sizeof(req), RTA_DST, &lse, sizeof(mpls_lse_t)); /* Fill nexthops (paths) based on single-path or multipath. The paths * chosen depend on the operation. */ if (nexthop_num == 1) { routedesc = "single-path"; - _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc); + _netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx), + routedesc); nexthop_num = 0; - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + for (nhlfe = dplane_ctx_get_nhlfe(ctx); + nhlfe; nhlfe = nhlfe->next) { nexthop = nhlfe->nexthop; if (!nexthop) continue; @@ -2709,15 +2840,16 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)))) { /* Add the gateway */ - _netlink_mpls_build_singlepath(routedesc, nhlfe, - &req.n, &req.r, - sizeof req, cmd); + _netlink_mpls_build_singlepath( + routedesc, nhlfe, + &req.n, &req.r, + sizeof(req), cmd); + nexthop_num++; break; } } - } else /* Multipath case */ - { + } else { /* Multipath case */ char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *)buf; struct rtnexthop *rtnh; @@ -2728,10 +2860,12 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) rtnh = RTA_DATA(rta); routedesc = "multipath"; - _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc); + _netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx), + routedesc); nexthop_num = 0; - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + for (nhlfe = dplane_ctx_get_nhlfe(ctx); + nhlfe; nhlfe = nhlfe->next) { nexthop = nhlfe->nexthop; if (!nexthop) continue; @@ -2762,7 +2896,7 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) } /* Talk to netlink socket. */ - return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, - 0); + return netlink_talk_info(netlink_talk_filter, &req.n, + dplane_ctx_get_ns(ctx), 0); } #endif /* HAVE_NETLINK */ diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index cefd1996a..473ad98a3 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -24,6 +24,7 @@ #ifdef HAVE_NETLINK #include "zebra/zebra_mpls.h" +#include "zebra/zebra_dplane.h" #define NL_DEFAULT_ROUTE_METRIC 20 @@ -58,7 +59,8 @@ void rt_netlink_init(void); -extern int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp); +/* MPLS label forwarding table change, using dataplane context information. */ +extern int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx); extern int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int netlink_route_read(struct zebra_ns *zns); @@ -71,6 +73,11 @@ extern int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, extern int netlink_neigh_read(struct zebra_ns *zns); extern int netlink_neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if); +extern int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, + struct interface *br_if, + struct ethaddr *mac, uint16_t vid); +extern int netlink_neigh_read_specific_ip(struct ipaddr *ip, + struct interface *vlan_if); #endif /* HAVE_NETLINK */ diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 29e9bf82f..f25259f30 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -44,30 +44,6 @@ extern struct zebra_privs_t zserv_privs; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN -/* Adjust netmask socket length. Return value is a adjusted sin_len - value. */ -static int sin_masklen(struct in_addr mask) -{ - char *p, *lim; - int len; - struct sockaddr_in sin; - - if (mask.s_addr == 0) - return sizeof(long); - - sin.sin_addr = mask; - len = sizeof(struct sockaddr_in); - - lim = (char *)&sin.sin_addr; - p = lim + sizeof(sin.sin_addr); - - while (*--p == 0 && p >= lim) - len--; - return len; -} -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - #ifdef __OpenBSD__ static int kernel_rtm_add_labels(struct mpls_label_stack *nh_label, struct sockaddr_mpls *smpls) @@ -89,30 +65,6 @@ static int kernel_rtm_add_labels(struct mpls_label_stack *nh_label, } #endif -#ifdef SIN6_LEN -/* Calculate sin6_len value for netmask socket value. */ -static int sin6_masklen(struct in6_addr mask) -{ - struct sockaddr_in6 sin6; - char *p, *lim; - int len; - - if (IN6_IS_ADDR_UNSPECIFIED(&mask)) - return sizeof(long); - - sin6.sin6_addr = mask; - len = sizeof(struct sockaddr_in6); - - lim = (char *)&sin6.sin6_addr; - p = lim + sizeof(sin6.sin6_addr); - - while (*--p == 0 && p >= lim) - len--; - - return len; -} -#endif /* SIN6_LEN */ - /* Interface between zebra message and rtm message. */ static int kernel_rtm(int cmd, const struct prefix *p, const struct nexthop_group *ng, uint32_t metric) @@ -128,11 +80,11 @@ static int kernel_rtm(int cmd, const struct prefix *p, ifindex_t ifindex = 0; bool gate = false; int error; + char gate_buf[INET6_BUFSIZ]; char prefix_buf[PREFIX_STRLEN]; enum blackhole_type bh_type = BLACKHOLE_UNSPEC; - if (IS_ZEBRA_DEBUG_RIB) - prefix2str(p, prefix_buf, sizeof(prefix_buf)); + prefix2str(p, prefix_buf, sizeof(prefix_buf)); /* * We only have the ability to ADD or DELETE at this point @@ -140,10 +92,9 @@ static int kernel_rtm(int cmd, const struct prefix *p, */ if (cmd != RTM_ADD && cmd != RTM_DELETE) { if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: %s odd command %s for flags %d", + zlog_debug("%s: %s odd command %s", __func__, prefix_buf, - lookup_msg(rtm_type_str, cmd, NULL), - nexthop->flags); + lookup_msg(rtm_type_str, cmd, NULL)); return 0; } @@ -154,23 +105,21 @@ static int kernel_rtm(int cmd, const struct prefix *p, switch (p->family) { case AF_INET: sin_dest.sin.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_dest.sin.sin_len = sizeof(sin_dest); - sin_gate.sin.sin_len = sizeof(sin_gate); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ sin_dest.sin.sin_addr = p->u.prefix4; sin_gate.sin.sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + sin_dest.sin.sin_len = sizeof(struct sockaddr_in); + sin_gate.sin.sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ break; case AF_INET6: sin_dest.sin6.sin6_family = AF_INET6; -#ifdef SIN6_LEN - sin_dest.sin6.sin6_len = sizeof(sin_dest); -#endif /* SIN6_LEN */ sin_dest.sin6.sin6_addr = p->u.prefix6; sin_gate.sin6.sin6_family = AF_INET6; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_gate.sin6.sin6_len = sizeof(sin_gate); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + sin_dest.sin6.sin6_len = sizeof(struct sockaddr_in6); + sin_gate.sin6.sin6_len = sizeof(struct sockaddr_in6); +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ break; } @@ -185,13 +134,16 @@ static int kernel_rtm(int cmd, const struct prefix *p, smplsp = NULL; gate = false; - char gate_buf[INET_ADDRSTRLEN] = "NULL"; + snprintf(gate_buf, sizeof(gate_buf), "NULL"); switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: sin_gate.sin.sin_addr = nexthop->gate.ipv4; sin_gate.sin.sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + sin_gate.sin.sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ ifindex = nexthop->ifindex; gate = true; break; @@ -199,6 +151,9 @@ static int kernel_rtm(int cmd, const struct prefix *p, case NEXTHOP_TYPE_IPV6_IFINDEX: sin_gate.sin6.sin6_addr = nexthop->gate.ipv6; sin_gate.sin6.sin6_family = AF_INET6; +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + sin_gate.sin6.sin6_len = sizeof(struct sockaddr_in6); +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ ifindex = nexthop->ifindex; /* Under kame set interface index to link local address */ #ifdef KAME @@ -227,6 +182,10 @@ static int kernel_rtm(int cmd, const struct prefix *p, struct in_addr loopback; loopback.s_addr = htonl(INADDR_LOOPBACK); sin_gate.sin.sin_addr = loopback; +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + sin_gate.sin.sin_len = + sizeof(struct sockaddr_in); +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ gate = true; } break; @@ -239,26 +198,26 @@ static int kernel_rtm(int cmd, const struct prefix *p, case AF_INET: masklen2ip(p->prefixlen, &sin_mask.sin.sin_addr); sin_mask.sin.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_mask.sin.sin_len = sin_masklen( - sin_mask.sin.sin_addr); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + sin_mask.sin.sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ break; case AF_INET6: masklen2ip6(p->prefixlen, &sin_mask.sin6.sin6_addr); sin_mask.sin6.sin6_family = AF_INET6; -#ifdef SIN6_LEN - sin_mask.sin6.sin6_len = sin6_masklen( - sin_mask.sin6.sin6_addr); -#endif /* SIN6_LEN */ +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + sin_mask.sin6.sin6_len = sizeof(struct sockaddr_in6); +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ break; } #ifdef __OpenBSD__ - if (nexthop->nh_label - && !kernel_rtm_add_labels(nexthop->nh_label, &smpls)) - continue; - smplsp = (union sockunion *)&smpls; + if (nexthop->nh_label) { + if (kernel_rtm_add_labels(nexthop->nh_label, + &smpls) != 0) + continue; + smplsp = (union sockunion *)&smpls; + } #endif error = rtm_write(cmd, &sin_dest, &sin_mask, gate ? &sin_gate : NULL, smplsp, @@ -266,13 +225,29 @@ static int kernel_rtm(int cmd, const struct prefix *p, if (IS_ZEBRA_DEBUG_KERNEL) { if (!gate) { - zlog_debug("%s: %s: attention! gate not found for re", - __func__, prefix_buf); - } else - inet_ntop(p->family == AFI_IP ? AF_INET - : AF_INET6, - &sin_gate.sin.sin_addr, - gate_buf, INET_ADDRSTRLEN); + zlog_debug( + "%s: %s: attention! gate not found for re", + __func__, prefix_buf); + } else { + switch (p->family) { + case AFI_IP: + inet_ntop(AF_INET, + &sin_gate.sin.sin_addr, + gate_buf, sizeof(gate_buf)); + break; + + case AFI_IP6: + inet_ntop(AF_INET6, + &sin_gate.sin6.sin6_addr, + gate_buf, sizeof(gate_buf)); + break; + + default: + snprintf(gate_buf, sizeof(gate_buf), + "(invalid-af)"); + break; + } + } } switch (error) { /* We only flag nexthops as being in FIB if @@ -301,12 +276,11 @@ static int kernel_rtm(int cmd, const struct prefix *p, /* Note any unexpected status returns */ default: - flog_err(EC_LIB_SYSTEM_CALL, - "%s: %s: rtm_write() unexpectedly returned %d for command %s", - __func__, - prefix2str(p, prefix_buf, - sizeof(prefix_buf)), - error, lookup_msg(rtm_type_str, cmd, NULL)); + flog_err( + EC_LIB_SYSTEM_CALL, + "%s: %s: rtm_write() unexpectedly returned %d for command %s", + __func__, prefix_buf, error, + lookup_msg(rtm_type_str, cmd, NULL)); break; } } /* for (ALL_NEXTHOPS(...))*/ @@ -314,9 +288,9 @@ static int kernel_rtm(int cmd, const struct prefix *p, /* If there was no useful nexthop, then complain. */ if (nexthop_num == 0) { if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: No useful nexthops were found in RIB prefix %s", - __func__, prefix2str(p, prefix_buf, - sizeof(prefix_buf))); + zlog_debug( + "%s: No useful nexthops were found in RIB prefix %s", + __func__, prefix_buf); return 1; } @@ -333,8 +307,7 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) if (dplane_ctx_get_src(ctx) != NULL) { zlog_err("route add: IPv6 sourcedest routes unsupported!"); - res = ZEBRA_DPLANE_REQUEST_FAILURE; - goto done; + return ZEBRA_DPLANE_REQUEST_FAILURE; } frr_elevate_privs(&zserv_privs) { @@ -366,8 +339,6 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) } } /* Elevated privs */ -done: - return res; } diff --git a/zebra/rtadv.c b/zebra/rtadv.c index a22f6395c..5088e2e8e 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -66,6 +66,9 @@ extern struct zebra_privs_t zserv_privs; #define ALLNODE "ff02::1" #define ALLROUTER "ff02::2" +DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS") +DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL") + /* Order is intentional. Matches RFC4191. This array is also used for command matching, so only modify with care. */ const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0}; @@ -355,6 +358,78 @@ static void rtadv_send_packet(int sock, struct interface *ifp) len += sizeof(struct nd_opt_mtu); } + /* + * There is no limit on the number of configurable recursive DNS + * servers or search list entries. We don't want the RA message + * to exceed the link's MTU (risking fragmentation) or even + * blow the stack buffer allocated for it. + */ + size_t max_len = MIN(ifp->mtu6 - 40, sizeof(buf)); + + /* Recursive DNS servers */ + struct rtadv_rdnss *rdnss; + + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) { + size_t opt_len = + sizeof(struct nd_opt_rdnss) + sizeof(struct in6_addr); + + if (len + opt_len > max_len) { + zlog_warn( + "%s(%u): Tx RA: RDNSS option would exceed MTU, omitting it", + ifp->name, ifp->ifindex); + goto no_more_opts; + } + struct nd_opt_rdnss *opt = (struct nd_opt_rdnss *)(buf + len); + + opt->nd_opt_rdnss_type = ND_OPT_RDNSS; + opt->nd_opt_rdnss_len = opt_len / 8; + opt->nd_opt_rdnss_reserved = 0; + opt->nd_opt_rdnss_lifetime = htonl( + rdnss->lifetime_set + ? rdnss->lifetime + : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval)); + + len += sizeof(struct nd_opt_rdnss); + + IPV6_ADDR_COPY(buf + len, &rdnss->addr); + len += sizeof(struct in6_addr); + } + + /* DNS search list */ + struct rtadv_dnssl *dnssl; + + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) { + size_t opt_len = sizeof(struct nd_opt_dnssl) + + ((dnssl->encoded_len + 7) & ~7); + + if (len + opt_len > max_len) { + zlog_warn( + "%s(%u): Tx RA: DNSSL option would exceed MTU, omitting it", + ifp->name, ifp->ifindex); + goto no_more_opts; + } + struct nd_opt_dnssl *opt = (struct nd_opt_dnssl *)(buf + len); + + opt->nd_opt_dnssl_type = ND_OPT_DNSSL; + opt->nd_opt_dnssl_len = opt_len / 8; + opt->nd_opt_dnssl_reserved = 0; + opt->nd_opt_dnssl_lifetime = htonl( + dnssl->lifetime_set + ? dnssl->lifetime + : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval)); + + len += sizeof(struct nd_opt_dnssl); + + memcpy(buf + len, dnssl->encoded_name, dnssl->encoded_len); + len += dnssl->encoded_len; + + /* Zero-pad to 8-octet boundary */ + while (len % 8) + buf[len++] = '\0'; + } + +no_more_opts: + msg.msg_name = (void *)&addr; msg.msg_namelen = sizeof(struct sockaddr_in6); msg.msg_iov = &iov; @@ -1533,6 +1608,308 @@ DEFUN (no_ipv6_nd_mtu, return CMD_SUCCESS; } +static struct rtadv_rdnss *rtadv_rdnss_new(void) +{ + return XCALLOC(MTYPE_RTADV_RDNSS, sizeof(struct rtadv_rdnss)); +} + +static void rtadv_rdnss_free(struct rtadv_rdnss *rdnss) +{ + XFREE(MTYPE_RTADV_RDNSS, rdnss); +} + +static struct rtadv_rdnss *rtadv_rdnss_lookup(struct list *list, + struct rtadv_rdnss *rdnss) +{ + struct listnode *node; + struct rtadv_rdnss *p; + + for (ALL_LIST_ELEMENTS_RO(list, node, p)) + if (IPV6_ADDR_SAME(&p->addr, &rdnss->addr)) + return p; + return NULL; +} + +static struct rtadv_rdnss *rtadv_rdnss_get(struct list *list, + struct rtadv_rdnss *rdnss) +{ + struct rtadv_rdnss *p; + + p = rtadv_rdnss_lookup(list, rdnss); + if (p) + return p; + + p = rtadv_rdnss_new(); + memcpy(p, rdnss, sizeof(struct rtadv_rdnss)); + listnode_add(list, p); + + return p; +} + +static void rtadv_rdnss_set(struct zebra_if *zif, struct rtadv_rdnss *rdnss) +{ + struct rtadv_rdnss *p; + + p = rtadv_rdnss_get(zif->rtadv.AdvRDNSSList, rdnss); + p->lifetime = rdnss->lifetime; + p->lifetime_set = rdnss->lifetime_set; +} + +static int rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *rdnss) +{ + struct rtadv_rdnss *p; + + p = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rdnss); + if (p) { + listnode_delete(zif->rtadv.AdvRDNSSList, p); + rtadv_rdnss_free(p); + return 1; + } + + return 0; +} + +static struct rtadv_dnssl *rtadv_dnssl_new(void) +{ + return XCALLOC(MTYPE_RTADV_DNSSL, sizeof(struct rtadv_dnssl)); +} + +static void rtadv_dnssl_free(struct rtadv_dnssl *dnssl) +{ + XFREE(MTYPE_RTADV_DNSSL, dnssl); +} + +static struct rtadv_dnssl *rtadv_dnssl_lookup(struct list *list, + struct rtadv_dnssl *dnssl) +{ + struct listnode *node; + struct rtadv_dnssl *p; + + for (ALL_LIST_ELEMENTS_RO(list, node, p)) + if (!strcasecmp(p->name, dnssl->name)) + return p; + return NULL; +} + +static struct rtadv_dnssl *rtadv_dnssl_get(struct list *list, + struct rtadv_dnssl *dnssl) +{ + struct rtadv_dnssl *p; + + p = rtadv_dnssl_lookup(list, dnssl); + if (p) + return p; + + p = rtadv_dnssl_new(); + memcpy(p, dnssl, sizeof(struct rtadv_dnssl)); + listnode_add(list, p); + + return p; +} + +static void rtadv_dnssl_set(struct zebra_if *zif, struct rtadv_dnssl *dnssl) +{ + struct rtadv_dnssl *p; + + p = rtadv_dnssl_get(zif->rtadv.AdvDNSSLList, dnssl); + memcpy(p, dnssl, sizeof(struct rtadv_dnssl)); +} + +static int rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *dnssl) +{ + struct rtadv_dnssl *p; + + p = rtadv_dnssl_lookup(zif->rtadv.AdvDNSSLList, dnssl); + if (p) { + listnode_delete(zif->rtadv.AdvDNSSLList, p); + rtadv_dnssl_free(p); + return 1; + } + + return 0; +} + +/* + * Convert dotted domain name (with or without trailing root zone dot) to + * sequence of length-prefixed labels, as described in [RFC1035 3.1]. Write up + * to strlen(in) + 2 octets to out. + * + * Returns the number of octets written to out or -1 if in does not constitute + * a valid domain name. + */ +static int rtadv_dnssl_encode(uint8_t *out, const char *in) +{ + const char *label_start, *label_end; + size_t outp; + + outp = 0; + label_start = in; + + while (*label_start) { + size_t label_len; + + label_end = strchr(label_start, '.'); + if (label_end == NULL) + label_end = label_start + strlen(label_start); + + label_len = label_end - label_start; + if (label_len >= 64) + return -1; /* labels must be 63 octets or less */ + + out[outp++] = (uint8_t)label_len; + memcpy(out + outp, label_start, label_len); + outp += label_len; + label_start += label_len; + if (*label_start == '.') + label_start++; + } + + out[outp++] = '\0'; + return outp; +} + +DEFUN(ipv6_nd_rdnss, + ipv6_nd_rdnss_cmd, + "ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Recursive DNS server information\n" + "IPv6 address\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + struct rtadv_rdnss rdnss = {}; + + if (inet_pton(AF_INET6, argv[3]->arg, &rdnss.addr) != 1) { + vty_out(vty, "Malformed IPv6 address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (argc > 4) { + char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg + : argv[4]->text; + rdnss.lifetime = strmatch(lifetime, "infinite") + ? UINT32_MAX + : strtoll(lifetime, NULL, 10); + rdnss.lifetime_set = 1; + } + + rtadv_rdnss_set(zif, &rdnss); + + return CMD_SUCCESS; +} + +DEFUN(no_ipv6_nd_rdnss, + no_ipv6_nd_rdnss_cmd, + "no ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Recursive DNS server information\n" + "IPv6 address\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + struct rtadv_rdnss rdnss = {}; + + if (inet_pton(AF_INET6, argv[4]->arg, &rdnss.addr) != 1) { + vty_out(vty, "Malformed IPv6 address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (rtadv_rdnss_reset(zif, &rdnss) != 1) { + vty_out(vty, "Non-existant RDNSS address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return CMD_SUCCESS; +} + +DEFUN(ipv6_nd_dnssl, + ipv6_nd_dnssl_cmd, + "ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "DNS search list information\n" + "Domain name suffix\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + struct rtadv_dnssl dnssl = {}; + size_t len; + int ret; + + len = strlcpy(dnssl.name, argv[3]->arg, sizeof(dnssl.name)); + if (len == 0 || len >= sizeof(dnssl.name)) { + vty_out(vty, "Malformed DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (dnssl.name[len - 1] == '.') { + /* + * Allow, but don't require, a trailing dot signifying the root + * zone. Canonicalize by cutting it off if present. + */ + dnssl.name[len - 1] = '\0'; + len--; + } + if (argc > 4) { + char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg + : argv[4]->text; + dnssl.lifetime = strmatch(lifetime, "infinite") + ? UINT32_MAX + : strtoll(lifetime, NULL, 10); + dnssl.lifetime_set = 1; + } + + ret = rtadv_dnssl_encode(dnssl.encoded_name, dnssl.name); + if (ret < 0) { + vty_out(vty, "Malformed DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + dnssl.encoded_len = ret; + rtadv_dnssl_set(zif, &dnssl); + + return CMD_SUCCESS; +} + +DEFUN(no_ipv6_nd_dnssl, + no_ipv6_nd_dnssl_cmd, + "no ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "DNS search list information\n" + "Domain name suffix\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + struct rtadv_dnssl dnssl = {}; + size_t len; + + len = strlcpy(dnssl.name, argv[4]->arg, sizeof(dnssl.name)); + if (len == 0 || len >= sizeof(dnssl.name)) { + vty_out(vty, "Malformed DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (dnssl.name[len - 1] == '.') { + dnssl.name[len - 1] = '\0'; + len--; + } + if (rtadv_dnssl_reset(zif, &dnssl) != 1) { + vty_out(vty, "Non-existant DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return CMD_SUCCESS; +} + + /* Dump interface ND information to vty. */ static int nd_dump_vty(struct vty *vty, struct interface *ifp) { @@ -1607,6 +1984,8 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp) struct zebra_if *zif; struct listnode *node; struct rtadv_prefix *rprefix; + struct rtadv_rdnss *rdnss; + struct rtadv_dnssl *dnssl; char buf[PREFIX_STRLEN]; int interval; @@ -1688,6 +2067,29 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp) vty_out(vty, " router-address"); vty_out(vty, "\n"); } + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) { + char buf[INET6_ADDRSTRLEN]; + + vty_out(vty, " ipv6 nd rdnss %s", + inet_ntop(AF_INET6, &rdnss->addr, buf, sizeof(buf))); + if (rdnss->lifetime_set) { + if (rdnss->lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", rdnss->lifetime); + } + vty_out(vty, "\n"); + } + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) { + vty_out(vty, " ipv6 nd dnssl %s", dnssl->name); + if (dnssl->lifetime_set) { + if (dnssl->lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", dnssl->lifetime); + } + vty_out(vty, "\n"); + } return 0; } @@ -1698,9 +2100,9 @@ static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val) switch (event) { case RTADV_START: - thread_add_read(zebrad.master, rtadv_read, zns, val, + thread_add_read(zrouter.master, rtadv_read, zns, val, &rtadv->ra_read); - thread_add_event(zebrad.master, rtadv_timer, zns, 0, + thread_add_event(zrouter.master, rtadv_timer, zns, 0, &rtadv->ra_timer); break; case RTADV_STOP: @@ -1714,15 +2116,15 @@ static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val) } break; case RTADV_TIMER: - thread_add_timer(zebrad.master, rtadv_timer, zns, val, + thread_add_timer(zrouter.master, rtadv_timer, zns, val, &rtadv->ra_timer); break; case RTADV_TIMER_MSEC: - thread_add_timer_msec(zebrad.master, rtadv_timer, zns, val, + thread_add_timer_msec(zrouter.master, rtadv_timer, zns, val, &rtadv->ra_timer); break; case RTADV_READ: - thread_add_read(zebrad.master, rtadv_read, zns, val, + thread_add_read(zrouter.master, rtadv_read, zns, val, &rtadv->ra_read); break; default: @@ -1782,6 +2184,10 @@ void rtadv_cmd_init(void) install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd); install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd); install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd); + install_element(INTERFACE_NODE, &no_ipv6_nd_rdnss_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd); + install_element(INTERFACE_NODE, &no_ipv6_nd_dnssl_cmd); } static int if_join_all_router(int sock, struct interface *ifp) diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 03db13fd6..f7c27ebcb 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -91,6 +91,37 @@ struct nd_opt_homeagent_info { /* Home Agent info */ } __attribute__((__packed__)); #endif +#ifndef ND_OPT_RDNSS +#define ND_OPT_RDNSS 25 +#endif +#ifndef ND_OPT_DNSSL +#define ND_OPT_DNSSL 31 +#endif + +#ifndef HAVE_STRUCT_ND_OPT_RDNSS +struct nd_opt_rdnss { /* Recursive DNS server option [RFC8106 5.1] */ + uint8_t nd_opt_rdnss_type; + uint8_t nd_opt_rdnss_len; + uint16_t nd_opt_rdnss_reserved; + uint32_t nd_opt_rdnss_lifetime; + /* Followed by one or more IPv6 addresses */ +} __attribute__((__packed__)); +#endif + +#ifndef HAVE_STRUCT_ND_OPT_DNSSL +struct nd_opt_dnssl { /* DNS search list option [RFC8106 5.2] */ + uint8_t nd_opt_dnssl_type; + uint8_t nd_opt_dnssl_len; + uint16_t nd_opt_dnssl_reserved; + uint32_t nd_opt_dnssl_lifetime; + /* + * Followed by one or more domain names encoded as in [RFC1035 3.1]. + * Multiple domain names are concatenated after encoding. In any case, + * the result is zero-padded to a multiple of 8 octets. + */ +} __attribute__((__packed__)); +#endif + extern const char *rtadv_pref_strs[]; #endif /* HAVE_RTADV */ diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index c1bd68f9d..725bb63a0 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -261,6 +261,11 @@ void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, { } +void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, + struct ethaddr *mac, vlanid_t vid) +{ +} + void neigh_read(struct zebra_ns *zns) { } @@ -269,6 +274,10 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { } +void neigh_read_specific_ip(struct ipaddr *ip, struct interface *vlan_if) +{ +} + void kernel_read_pbr_rules(struct zebra_ns *zns) { } diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index e99204607..fbca47351 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -45,6 +45,12 @@ void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, netlink_macfdb_read_for_bridge(zns, ifp, br_if); } +void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, + struct ethaddr *mac, vlanid_t vid) +{ +netlink_macfdb_read_specific_mac(zns, br_if, mac, vid); +} + void neigh_read(struct zebra_ns *zns) { netlink_neigh_read(zns); @@ -55,6 +61,11 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) netlink_neigh_read_for_vlan(zns, vlan_if); } +void neigh_read_specific_ip(struct ipaddr *ip, struct interface *vlan_if) +{ + netlink_neigh_read_specific_ip(ip, vlan_if); +} + void kernel_read_pbr_rules(struct zebra_ns *zns) { netlink_rules_read(zns); diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index f88586a6e..4150092d4 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -88,6 +88,11 @@ void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, { } +void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, + struct ethaddr *mac, vlanid_t vid) +{ +} + void neigh_read(struct zebra_ns *zns) { } @@ -96,6 +101,10 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { } +void neigh_read_specific_ip(struct ipaddr *ip, struct interface *vlan_if) +{ +} + void kernel_read_pbr_rules(struct zebra_ns *zns) { } diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index 7686a0ac3..477549f42 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -116,10 +116,11 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule) if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "Tx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u", + "Tx %s family %s IF %s(%u) Pref %u Fwmark %u Src %s Dst %s Table %u", nl_msg_type_to_str(cmd), nl_family_to_str(family), rule->ifp ? rule->ifp->name : "Unknown", rule->ifp ? rule->ifp->ifindex : 0, rule->rule.priority, + rule->rule.filter.fwmark, prefix2str(&rule->rule.filter.src_ip, buf1, sizeof(buf1)), prefix2str(&rule->rule.filter.dst_ip, buf2, diff --git a/zebra/subdir.am b/zebra/subdir.am index 23c3cd423..1e36d020a 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -95,10 +95,15 @@ zebra_zebra_SOURCES = \ zebra/zebra_errors.c \ # end +zebra/debug_clippy.c: $(CLIPPY_DEPS) +zebra/debug.$(OBJEXT): zebra/debug_clippy.c + zebra/zebra_mlag_clippy.c: $(CLIPPY_DEPS) zebra/zebra_mlag.$(OBJEXT): zebra/zebra_mlag_clippy.c zebra/zebra_vty_clippy.c: $(CLIPPY_DEPS) +zebra/interface_clippy.c: $(CLIPPY_DEPS) +zebra/interface.$(OBJEXT): zebra/interface_clippy.c zebra/zebra_vty.$(OBJEXT): zebra/zebra_vty_clippy.c zebra/zebra_routemap_clippy.c: $(CLIPPY_DEPS) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 15f9da0cb..9f2bbcf42 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -42,6 +42,7 @@ #include "lib/libfrr.h" #include "lib/sockopt.h" +#include "zebra/zebra_router.h" #include "zebra/rib.h" #include "zebra/zebra_memory.h" #include "zebra/zebra_ns.h" @@ -208,12 +209,6 @@ int zsend_interface_link_params(struct zserv *client, struct interface *ifp) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - /* Check this client need interface information. */ - if (!client->ifinfo) { - stream_free(s); - return 0; - } - if (!ifp->link_params) { stream_free(s); return 0; @@ -365,7 +360,7 @@ static void zebra_interface_nbr_address_add_update(struct interface *ifp, p->prefixlen, ifc->ifp->name); } - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) zsend_interface_nbr_address(ZEBRA_INTERFACE_NBR_ADDRESS_ADD, client, ifp, ifc); } @@ -389,7 +384,7 @@ static void zebra_interface_nbr_address_delete_update(struct interface *ifp, p->prefixlen, ifc->ifp->name); } - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) zsend_interface_nbr_address(ZEBRA_INTERFACE_NBR_ADDRESS_DELETE, client, ifp, ifc); } @@ -530,6 +525,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, memset(&api, 0, sizeof(api)); api.vrf_id = re->vrf_id; api.type = re->type; + api.safi = SAFI_UNICAST; api.instance = re->instance; api.flags = re->flags; @@ -767,7 +763,7 @@ void zsend_rule_notify_owner(struct zebra_pbr_rule *rule, zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__, rule->rule.unique); - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { if (rule->sock == client->sock) break; } @@ -803,7 +799,7 @@ void zsend_ipset_notify_owner(struct zebra_pbr_ipset *ipset, zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__, ipset->unique); - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { if (ipset->sock == client->sock) break; } @@ -833,7 +829,7 @@ void zsend_ipset_entry_notify_owner(struct zebra_pbr_ipset_entry *ipset, zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__, ipset->unique); - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { if (ipset->sock == client->sock) break; } @@ -863,7 +859,7 @@ void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable, zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__, iptable->unique); - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { if (iptable->sock == client->sock) break; } @@ -1108,7 +1104,8 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf)); /* Anything not AF_INET/INET6 has been filtered out above */ if (!exist) - zebra_evaluate_rnh(zvrf, p.family, 1, type, &p); + zebra_evaluate_rnh(zvrf, family2afi(p.family), 1, type, + &p); } stream_failure: @@ -1314,9 +1311,6 @@ static void zread_interface_add(ZAPI_HANDLER_ARGS) struct vrf *vrf; struct interface *ifp; - /* Interface information is needed. */ - vrf_bitmap_set(client->ifinfo, zvrf_id(zvrf)); - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { FOR_ALL_INTERFACES (vrf, ifp) { /* Skip pseudo interface. */ @@ -1324,6 +1318,7 @@ static void zread_interface_add(ZAPI_HANDLER_ARGS) continue; zsend_interface_add(client, ifp); + zsend_interface_link_params(client, ifp); zsend_interface_addresses(client, ifp); } } @@ -1332,7 +1327,6 @@ static void zread_interface_add(ZAPI_HANDLER_ARGS) /* Unregister zebra server interface information. */ static void zread_interface_delete(ZAPI_HANDLER_ARGS) { - vrf_bitmap_unset(client->ifinfo, zvrf_id(zvrf)); } void zserv_nexthop_num_warn(const char *caller, const struct prefix *p, @@ -1394,147 +1388,139 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) else re->table = zvrf->table_id; + if (!CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) + || api.nexthop_num == 0) { + char buf_prefix[PREFIX_STRLEN]; + + prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix)); + flog_warn(EC_ZEBRA_RX_ROUTE_NO_NEXTHOPS, + "%s: received a route without nexthops for prefix %s", + __func__, buf_prefix); + XFREE(MTYPE_RE, re); + return; + } + /* * TBD should _all_ of the nexthop add operations use * api_nh->vrf_id instead of re->vrf_id ? I only changed * for cases NEXTHOP_TYPE_IPV4 and NEXTHOP_TYPE_IPV6. */ - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) - for (i = 0; i < api.nexthop_num; i++) { - api_nh = &api.nexthops[i]; - ifindex_t ifindex = 0; - - if (IS_ZEBRA_DEBUG_RECV) - zlog_debug("nh type %d", api_nh->type); - - switch (api_nh->type) { - case NEXTHOP_TYPE_IFINDEX: - nexthop = route_entry_nexthop_ifindex_add( - re, api_nh->ifindex, api_nh->vrf_id); - break; - case NEXTHOP_TYPE_IPV4: - if (IS_ZEBRA_DEBUG_RECV) { - char nhbuf[INET6_ADDRSTRLEN] = {0}; - - inet_ntop(AF_INET, &api_nh->gate.ipv4, - nhbuf, INET6_ADDRSTRLEN); - zlog_debug("%s: nh=%s, vrf_id=%d", - __func__, nhbuf, - api_nh->vrf_id); - } - nexthop = route_entry_nexthop_ipv4_add( - re, &api_nh->gate.ipv4, NULL, - api_nh->vrf_id); - break; - case NEXTHOP_TYPE_IPV4_IFINDEX: - - memset(&vtep_ip, 0, sizeof(struct ipaddr)); - if (CHECK_FLAG(api.flags, - ZEBRA_FLAG_EVPN_ROUTE)) { - ifindex = get_l3vni_svi_ifindex(vrf_id); - } else { - ifindex = api_nh->ifindex; - } - - if (IS_ZEBRA_DEBUG_RECV) { - char nhbuf[INET6_ADDRSTRLEN] = {0}; - - inet_ntop(AF_INET, &api_nh->gate.ipv4, - nhbuf, INET6_ADDRSTRLEN); - zlog_debug( - "%s: nh=%s, vrf_id=%d (re->vrf_id=%d), ifindex=%d", - __func__, nhbuf, api_nh->vrf_id, - re->vrf_id, ifindex); - } - nexthop = route_entry_nexthop_ipv4_ifindex_add( - re, &api_nh->gate.ipv4, NULL, ifindex, - api_nh->vrf_id); - - /* if this an EVPN route entry, - * program the nh as neigh - */ - if (CHECK_FLAG(api.flags, - ZEBRA_FLAG_EVPN_ROUTE)) { - SET_FLAG(nexthop->flags, - NEXTHOP_FLAG_EVPN_RVTEP); - vtep_ip.ipa_type = IPADDR_V4; - memcpy(&(vtep_ip.ipaddr_v4), - &(api_nh->gate.ipv4), - sizeof(struct in_addr)); - zebra_vxlan_evpn_vrf_route_add( - vrf_id, &api_nh->rmac, &vtep_ip, - &api.prefix); - } - break; - case NEXTHOP_TYPE_IPV6: - nexthop = route_entry_nexthop_ipv6_add( - re, &api_nh->gate.ipv6, api_nh->vrf_id); - break; - case NEXTHOP_TYPE_IPV6_IFINDEX: - memset(&vtep_ip, 0, sizeof(struct ipaddr)); - if (CHECK_FLAG(api.flags, - ZEBRA_FLAG_EVPN_ROUTE)) { - ifindex = get_l3vni_svi_ifindex(vrf_id); - } else { - ifindex = api_nh->ifindex; - } - - nexthop = route_entry_nexthop_ipv6_ifindex_add( - re, &api_nh->gate.ipv6, ifindex, - api_nh->vrf_id); - - /* if this an EVPN route entry, - * program the nh as neigh - */ - if (CHECK_FLAG(api.flags, - ZEBRA_FLAG_EVPN_ROUTE)) { - SET_FLAG(nexthop->flags, - NEXTHOP_FLAG_EVPN_RVTEP); - vtep_ip.ipa_type = IPADDR_V6; - memcpy(&vtep_ip.ipaddr_v6, - &(api_nh->gate.ipv6), - sizeof(struct in6_addr)); - zebra_vxlan_evpn_vrf_route_add( - vrf_id, &api_nh->rmac, &vtep_ip, - &api.prefix); - } - break; - case NEXTHOP_TYPE_BLACKHOLE: - nexthop = route_entry_nexthop_blackhole_add( - re, api_nh->bh_type); - break; + for (i = 0; i < api.nexthop_num; i++) { + api_nh = &api.nexthops[i]; + ifindex_t ifindex = 0; + + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("nh type %d", api_nh->type); + + switch (api_nh->type) { + case NEXTHOP_TYPE_IFINDEX: + nexthop = route_entry_nexthop_ifindex_add( + re, api_nh->ifindex, api_nh->vrf_id); + break; + case NEXTHOP_TYPE_IPV4: + if (IS_ZEBRA_DEBUG_RECV) { + char nhbuf[INET6_ADDRSTRLEN] = {0}; + + inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf, + INET6_ADDRSTRLEN); + zlog_debug("%s: nh=%s, vrf_id=%d", __func__, + nhbuf, api_nh->vrf_id); } + nexthop = route_entry_nexthop_ipv4_add( + re, &api_nh->gate.ipv4, NULL, api_nh->vrf_id); + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: - if (!nexthop) { - flog_warn( - EC_ZEBRA_NEXTHOP_CREATION_FAILED, - "%s: Nexthops Specified: %d but we failed to properly create one", - __PRETTY_FUNCTION__, api.nexthop_num); - nexthops_free(re->ng.nexthop); - XFREE(MTYPE_RE, re); - return; + memset(&vtep_ip, 0, sizeof(struct ipaddr)); + ifindex = api_nh->ifindex; + if (IS_ZEBRA_DEBUG_RECV) { + char nhbuf[INET6_ADDRSTRLEN] = {0}; + + inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf, + INET6_ADDRSTRLEN); + zlog_debug( + "%s: nh=%s, vrf_id=%d (re->vrf_id=%d), ifindex=%d", + __func__, nhbuf, api_nh->vrf_id, + re->vrf_id, ifindex); + } + nexthop = route_entry_nexthop_ipv4_ifindex_add( + re, &api_nh->gate.ipv4, NULL, ifindex, + api_nh->vrf_id); + + /* Special handling for IPv4 routes sourced from EVPN: + * the nexthop and associated MAC need to be installed. + */ + if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { + vtep_ip.ipa_type = IPADDR_V4; + memcpy(&(vtep_ip.ipaddr_v4), + &(api_nh->gate.ipv4), + sizeof(struct in_addr)); + zebra_vxlan_evpn_vrf_route_add( + vrf_id, &api_nh->rmac, &vtep_ip, + &api.prefix); } - /* MPLS labels for BGP-LU or Segment Routing */ - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_LABEL) - && api_nh->type != NEXTHOP_TYPE_IFINDEX - && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) { - enum lsp_types_t label_type; - - label_type = - lsp_type_from_re_type(client->proto); - - if (IS_ZEBRA_DEBUG_RECV) { - zlog_debug( - "%s: adding %d labels of type %d (1st=%u)", - __func__, api_nh->label_num, - label_type, api_nh->labels[0]); - } - - nexthop_add_labels(nexthop, label_type, - api_nh->label_num, - &api_nh->labels[0]); + break; + case NEXTHOP_TYPE_IPV6: + nexthop = route_entry_nexthop_ipv6_add( + re, &api_nh->gate.ipv6, api_nh->vrf_id); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + memset(&vtep_ip, 0, sizeof(struct ipaddr)); + ifindex = api_nh->ifindex; + nexthop = route_entry_nexthop_ipv6_ifindex_add( + re, &api_nh->gate.ipv6, ifindex, + api_nh->vrf_id); + + /* Special handling for IPv6 routes sourced from EVPN: + * the nexthop and associated MAC need to be installed. + */ + if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { + vtep_ip.ipa_type = IPADDR_V6; + memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6), + sizeof(struct in6_addr)); + zebra_vxlan_evpn_vrf_route_add( + vrf_id, &api_nh->rmac, &vtep_ip, + &api.prefix); } + break; + case NEXTHOP_TYPE_BLACKHOLE: + nexthop = route_entry_nexthop_blackhole_add( + re, api_nh->bh_type); + break; + } + + if (!nexthop) { + flog_warn( + EC_ZEBRA_NEXTHOP_CREATION_FAILED, + "%s: Nexthops Specified: %d but we failed to properly create one", + __PRETTY_FUNCTION__, api.nexthop_num); + nexthops_free(re->ng.nexthop); + XFREE(MTYPE_RE, re); + return; } + if (api_nh->onlink) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); + + /* MPLS labels for BGP-LU or Segment Routing */ + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_LABEL) + && api_nh->type != NEXTHOP_TYPE_IFINDEX + && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) { + enum lsp_types_t label_type; + + label_type = lsp_type_from_re_type(client->proto); + + if (IS_ZEBRA_DEBUG_RECV) { + zlog_debug( + "%s: adding %d labels of type %d (1st=%u)", + __func__, api_nh->label_num, label_type, + api_nh->labels[0]); + } + + nexthop_add_labels(nexthop, label_type, + api_nh->label_num, + &api_nh->labels[0]); + } + } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) re->distance = api.distance; @@ -1656,6 +1642,7 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_CAPABILITIES, zvrf->vrf->vrf_id); + stream_putl(s, vrf_get_backend()); stream_putc(s, mpls_enabled); stream_putl(s, multipath_num); stream_putc(s, zebra_mlag_get_role()); @@ -1664,6 +1651,18 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) zserv_send_message(client, s); } +void zsend_capabilities_all_clients(void) +{ + struct listnode *node, *nnode; + struct zebra_vrf *zvrf; + struct zserv *client; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + zsend_capabilities(client, zvrf); + } +} + /* Tie up route-type and client->sock */ static void zread_hello(ZAPI_HANDLER_ARGS) { @@ -1692,6 +1691,7 @@ static void zread_hello(ZAPI_HANDLER_ARGS) } zsend_capabilities(client, zvrf); + zebra_vrf_update_all(client); stream_failure: return; } @@ -1707,7 +1707,6 @@ static void zread_vrf_unregister(ZAPI_HANDLER_ARGS) vrf_bitmap_unset(client->redist[afi][i], zvrf_id(zvrf)); vrf_bitmap_unset(client->redist_default[afi], zvrf_id(zvrf)); } - vrf_bitmap_unset(client->ifinfo, zvrf_id(zvrf)); vrf_bitmap_unset(client->ridinfo, zvrf_id(zvrf)); } @@ -2444,6 +2443,7 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_FEC_REGISTER] = zread_fec_register, [ZEBRA_FEC_UNREGISTER] = zread_fec_unregister, [ZEBRA_ADVERTISE_DEFAULT_GW] = zebra_vxlan_advertise_gw_macip, + [ZEBRA_ADVERTISE_SVI_MACIP] = zebra_vxlan_advertise_svi_macip, [ZEBRA_ADVERTISE_SUBNET] = zebra_vxlan_advertise_subnet, [ZEBRA_ADVERTISE_ALL_VNI] = zebra_vxlan_advertise_all_vni, [ZEBRA_REMOTE_VTEP_ADD] = zebra_vxlan_remote_vtep_add, diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 11b469e14..b770b8e88 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -84,3 +84,5 @@ extern void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable, enum zapi_iptable_notify_owner note); extern void zserv_nexthop_num_warn(const char *caller, const struct prefix *p, const unsigned int nexthop_num); + +extern void zsend_capabilities_all_clients(void); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index feede21cd..928169a86 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -24,8 +24,9 @@ #include "lib/memory.h" #include "lib/queue.h" #include "lib/zebra.h" +#include "zebra/zebra_router.h" #include "zebra/zebra_memory.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zebra_dplane.h" #include "zebra/rt.h" #include "zebra/debug.h" @@ -62,49 +63,25 @@ const uint32_t DPLANE_DEFAULT_NEW_WORK = 100; #endif /* DPLANE_DEBUG */ /* - * The context block used to exchange info about route updates across - * the boundary between the zebra main context (and pthread) and the - * dataplane layer (and pthread). + * Route information captured for route updates. */ -struct zebra_dplane_ctx { - - /* Operation code */ - enum dplane_op_e zd_op; - - /* Status on return */ - enum zebra_dplane_result zd_status; - - /* Dplane provider id */ - uint32_t zd_provider; - - /* Flags - used by providers, e.g. */ - int zd_flags; - - /* TODO -- internal/sub-operation status? */ - enum zebra_dplane_result zd_remote_status; - enum zebra_dplane_result zd_kernel_status; +struct dplane_route_info { /* Dest and (optional) source prefixes */ struct prefix zd_dest; struct prefix zd_src; - bool zd_is_update; - - uint32_t zd_seq; - uint32_t zd_old_seq; - vrf_id_t zd_vrf_id; - uint32_t zd_table_id; + afi_t zd_afi; + safi_t zd_safi; int zd_type; int zd_old_type; - afi_t zd_afi; - safi_t zd_safi; - route_tag_t zd_tag; route_tag_t zd_old_tag; uint32_t zd_metric; uint32_t zd_old_metric; + uint16_t zd_instance; uint16_t zd_old_instance; @@ -114,9 +91,6 @@ struct zebra_dplane_ctx { uint32_t zd_mtu; uint32_t zd_nexthop_mtu; - /* Namespace info */ - struct zebra_dplane_info zd_ns_info; - /* Nexthops */ struct nexthop_group zd_ng; @@ -125,6 +99,66 @@ struct zebra_dplane_ctx { /* TODO -- use fixed array of nexthops, to avoid mallocs? */ +}; + +/* + * Pseudowire info for the dataplane + */ +struct dplane_pw_info { + char ifname[IF_NAMESIZE]; + ifindex_t ifindex; + int type; + int af; + int status; + uint32_t flags; + union g_addr nexthop; + mpls_label_t local_label; + mpls_label_t remote_label; + + union pw_protocol_fields fields; +}; + +/* + * The context block used to exchange info about route updates across + * the boundary between the zebra main context (and pthread) and the + * dataplane layer (and pthread). + */ +struct zebra_dplane_ctx { + + /* Operation code */ + enum dplane_op_e zd_op; + + /* Status on return */ + enum zebra_dplane_result zd_status; + + /* Dplane provider id */ + uint32_t zd_provider; + + /* Flags - used by providers, e.g. */ + int zd_flags; + + bool zd_is_update; + + uint32_t zd_seq; + uint32_t zd_old_seq; + + /* TODO -- internal/sub-operation status? */ + enum zebra_dplane_result zd_remote_status; + enum zebra_dplane_result zd_kernel_status; + + vrf_id_t zd_vrf_id; + uint32_t zd_table_id; + + /* Support info for either route or LSP update */ + union { + struct dplane_route_info rinfo; + zebra_lsp_t lsp; + struct dplane_pw_info pw; + } u; + + /* Namespace info, used especially for netlink kernel communication */ + struct zebra_dplane_info zd_ns_info; + /* Embedded list linkage */ TAILQ_ENTRY(zebra_dplane_ctx) zd_q_entries; }; @@ -218,6 +252,14 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_routes_queued; _Atomic uint32_t dg_routes_queued_max; _Atomic uint32_t dg_route_errors; + _Atomic uint32_t dg_other_errors; + + _Atomic uint32_t dg_lsps_in; + _Atomic uint32_t dg_lsp_errors; + + _Atomic uint32_t dg_pws_in; + _Atomic uint32_t dg_pw_errors; + _Atomic uint32_t dg_update_yields; /* Dataplane pthread */ @@ -251,6 +293,10 @@ static struct zebra_dplane_globals { static int dplane_thread_loop(struct thread *event); static void dplane_info_from_zns(struct zebra_dplane_info *ns_info, struct zebra_ns *zns); +static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp, + enum dplane_op_e op); +static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw, + enum dplane_op_e op); /* * Public APIs @@ -282,27 +328,70 @@ static struct zebra_dplane_ctx *dplane_ctx_alloc(void) */ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx) { - if (pctx) { - DPLANE_CTX_VALID(*pctx); + if (pctx == NULL) + return; - /* TODO -- just freeing memory, but would like to maintain - * a pool - */ + DPLANE_CTX_VALID(*pctx); + + /* TODO -- just freeing memory, but would like to maintain + * a pool + */ + + /* Some internal allocations may need to be freed, depending on + * the type of info captured in the ctx. + */ + switch ((*pctx)->zd_op) { + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + case DPLANE_OP_ROUTE_DELETE: - /* Free embedded nexthops */ - if ((*pctx)->zd_ng.nexthop) { + /* Free allocated nexthops */ + if ((*pctx)->u.rinfo.zd_ng.nexthop) { /* This deals with recursive nexthops too */ - nexthops_free((*pctx)->zd_ng.nexthop); + nexthops_free((*pctx)->u.rinfo.zd_ng.nexthop); + + (*pctx)->u.rinfo.zd_ng.nexthop = NULL; } - if ((*pctx)->zd_old_ng.nexthop) { + if ((*pctx)->u.rinfo.zd_old_ng.nexthop) { /* This deals with recursive nexthops too */ - nexthops_free((*pctx)->zd_old_ng.nexthop); + nexthops_free((*pctx)->u.rinfo.zd_old_ng.nexthop); + + (*pctx)->u.rinfo.zd_old_ng.nexthop = NULL; + } + + break; + + case DPLANE_OP_LSP_INSTALL: + case DPLANE_OP_LSP_UPDATE: + case DPLANE_OP_LSP_DELETE: + { + zebra_nhlfe_t *nhlfe, *next; + + /* Free allocated NHLFEs */ + for (nhlfe = (*pctx)->u.lsp.nhlfe_list; nhlfe; nhlfe = next) { + next = nhlfe->next; + + zebra_mpls_nhlfe_del(nhlfe); } - XFREE(MTYPE_DP_CTX, *pctx); - *pctx = NULL; + /* Clear pointers in lsp struct, in case we're cacheing + * free context structs. + */ + (*pctx)->u.lsp.nhlfe_list = NULL; + (*pctx)->u.lsp.best_nhlfe = NULL; + + break; + } + + case DPLANE_OP_PW_INSTALL: + case DPLANE_OP_PW_UNINSTALL: + case DPLANE_OP_NONE: + break; } + + XFREE(MTYPE_DP_CTX, *pctx); + *pctx = NULL; } /* @@ -414,6 +503,23 @@ const char *dplane_op2str(enum dplane_op_e op) ret = "ROUTE_DELETE"; break; + case DPLANE_OP_LSP_INSTALL: + ret = "LSP_INSTALL"; + break; + case DPLANE_OP_LSP_UPDATE: + ret = "LSP_UPDATE"; + break; + case DPLANE_OP_LSP_DELETE: + ret = "LSP_DELETE"; + break; + + case DPLANE_OP_PW_INSTALL: + ret = "PW_INSTALL"; + break; + case DPLANE_OP_PW_UNINSTALL: + ret = "PW_UNINSTALL"; + break; + }; return ret; @@ -442,7 +548,7 @@ const struct prefix *dplane_ctx_get_dest(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->zd_dest); + return &(ctx->u.rinfo.zd_dest); } /* Source prefix is a little special - return NULL for "no src prefix" */ @@ -450,11 +556,11 @@ const struct prefix *dplane_ctx_get_src(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - if (ctx->zd_src.prefixlen == 0 && - IN6_IS_ADDR_UNSPECIFIED(&(ctx->zd_src.u.prefix6))) { + if (ctx->u.rinfo.zd_src.prefixlen == 0 && + IN6_IS_ADDR_UNSPECIFIED(&(ctx->u.rinfo.zd_src.u.prefix6))) { return NULL; } else { - return &(ctx->zd_src); + return &(ctx->u.rinfo.zd_src); } } @@ -490,28 +596,28 @@ int dplane_ctx_get_type(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_type; + return ctx->u.rinfo.zd_type; } int dplane_ctx_get_old_type(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_old_type; + return ctx->u.rinfo.zd_old_type; } afi_t dplane_ctx_get_afi(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_afi; + return ctx->u.rinfo.zd_afi; } safi_t dplane_ctx_get_safi(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_safi; + return ctx->u.rinfo.zd_safi; } uint32_t dplane_ctx_get_table(const struct zebra_dplane_ctx *ctx) @@ -525,70 +631,70 @@ route_tag_t dplane_ctx_get_tag(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_tag; + return ctx->u.rinfo.zd_tag; } route_tag_t dplane_ctx_get_old_tag(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_old_tag; + return ctx->u.rinfo.zd_old_tag; } uint16_t dplane_ctx_get_instance(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_instance; + return ctx->u.rinfo.zd_instance; } uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_old_instance; + return ctx->u.rinfo.zd_old_instance; } uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_metric; + return ctx->u.rinfo.zd_metric; } uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_old_metric; + return ctx->u.rinfo.zd_old_metric; } uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_mtu; + return ctx->u.rinfo.zd_mtu; } uint32_t dplane_ctx_get_nh_mtu(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_nexthop_mtu; + return ctx->u.rinfo.zd_nexthop_mtu; } uint8_t dplane_ctx_get_distance(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_distance; + return ctx->u.rinfo.zd_distance; } uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->zd_old_distance; + return ctx->u.rinfo.zd_old_distance; } const struct nexthop_group *dplane_ctx_get_ng( @@ -596,7 +702,7 @@ const struct nexthop_group *dplane_ctx_get_ng( { DPLANE_CTX_VALID(ctx); - return &(ctx->zd_ng); + return &(ctx->u.rinfo.zd_ng); } const struct nexthop_group *dplane_ctx_get_old_ng( @@ -604,7 +710,7 @@ const struct nexthop_group *dplane_ctx_get_old_ng( { DPLANE_CTX_VALID(ctx); - return &(ctx->zd_old_ng); + return &(ctx->u.rinfo.zd_old_ng); } const struct zebra_dplane_info *dplane_ctx_get_ns( @@ -615,6 +721,115 @@ const struct zebra_dplane_info *dplane_ctx_get_ns( return &(ctx->zd_ns_info); } +/* Accessors for LSP information */ + +mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.lsp.ile.in_label; +} + +uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.lsp.addr_family; +} + +uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.lsp.flags; +} + +zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.lsp.nhlfe_list; +} + +zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.lsp.best_nhlfe; +} + +uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.lsp.num_ecmp; +} + +const char *dplane_ctx_get_pw_ifname(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.ifname; +} + +mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.local_label; +} + +mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.remote_label; +} + +int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.type; +} + +int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.af; +} + +uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.flags; +} + +int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.status; +} + +const union g_addr *dplane_ctx_get_pw_nexthop( + const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.pw.nexthop); +} + +const union pw_protocol_fields *dplane_ctx_get_pw_proto( + const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.pw.fields); +} + /* * End of dplane context accessors */ @@ -652,6 +867,28 @@ uint32_t dplane_get_in_queue_len(void) } /* + * Common dataplane context init with zebra namespace info. + */ +static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx, + struct zebra_ns *zns, + bool is_update) +{ + dplane_info_from_zns(&(ctx->zd_ns_info), zns); + +#if defined(HAVE_NETLINK) + /* Increment message counter after copying to context struct - may need + * two messages in some 'update' cases. + */ + if (is_update) + zns->netlink_dplane.seq += 2; + else + zns->netlink_dplane.seq++; +#endif /* HAVE_NETLINK */ + + return AOK; +} + +/* * Initialize a context block for a route update from zebra data structs. */ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, @@ -673,67 +910,56 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, ctx->zd_op = op; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; - ctx->zd_type = re->type; - ctx->zd_old_type = re->type; + ctx->u.rinfo.zd_type = re->type; + ctx->u.rinfo.zd_old_type = re->type; /* Prefixes: dest, and optional source */ srcdest_rnode_prefixes(rn, &p, &src_p); - prefix_copy(&(ctx->zd_dest), p); + prefix_copy(&(ctx->u.rinfo.zd_dest), p); if (src_p) - prefix_copy(&(ctx->zd_src), src_p); + prefix_copy(&(ctx->u.rinfo.zd_src), src_p); else - memset(&(ctx->zd_src), 0, sizeof(ctx->zd_src)); + memset(&(ctx->u.rinfo.zd_src), 0, sizeof(ctx->u.rinfo.zd_src)); ctx->zd_table_id = re->table; - ctx->zd_metric = re->metric; - ctx->zd_old_metric = re->metric; + ctx->u.rinfo.zd_metric = re->metric; + ctx->u.rinfo.zd_old_metric = re->metric; ctx->zd_vrf_id = re->vrf_id; - ctx->zd_mtu = re->mtu; - ctx->zd_nexthop_mtu = re->nexthop_mtu; - ctx->zd_instance = re->instance; - ctx->zd_tag = re->tag; - ctx->zd_old_tag = re->tag; - ctx->zd_distance = re->distance; + ctx->u.rinfo.zd_mtu = re->mtu; + ctx->u.rinfo.zd_nexthop_mtu = re->nexthop_mtu; + ctx->u.rinfo.zd_instance = re->instance; + ctx->u.rinfo.zd_tag = re->tag; + ctx->u.rinfo.zd_old_tag = re->tag; + ctx->u.rinfo.zd_distance = re->distance; table = srcdest_rnode_table(rn); info = table->info; - ctx->zd_afi = info->afi; - ctx->zd_safi = info->safi; + ctx->u.rinfo.zd_afi = info->afi; + ctx->u.rinfo.zd_safi = info->safi; /* Extract ns info - can't use pointers to 'core' structs */ zvrf = vrf_info_lookup(re->vrf_id); zns = zvrf->zns; - /* Internal copy helper */ - dplane_info_from_zns(&(ctx->zd_ns_info), zns); - -#if defined(HAVE_NETLINK) - /* Increment message counter after copying to context struct - may need - * two messages in some 'update' cases. - */ - if (op == DPLANE_OP_ROUTE_UPDATE) - zns->netlink_dplane.seq += 2; - else - zns->netlink_dplane.seq++; -#endif /* NETLINK*/ + dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE)); /* Copy nexthops; recursive info is included too */ - copy_nexthops(&(ctx->zd_ng.nexthop), re->ng.nexthop, NULL); + copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), re->ng.nexthop, NULL); /* TODO -- maybe use array of nexthops to avoid allocs? */ /* Ensure that the dplane's nexthops flags are clear. */ - for (ALL_NEXTHOPS(ctx->zd_ng, nexthop)) + for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); /* Trying out the sequence number idea, so we can try to detect * when a result is stale. */ - re->dplane_sequence++; + re->dplane_sequence = zebra_router_get_next_sequence(); ctx->zd_seq = re->dplane_sequence; ret = AOK; @@ -743,15 +969,120 @@ done: } /* + * Capture information for an LSP update in a dplane context. + */ +static int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, + enum dplane_op_e op, + zebra_lsp_t *lsp) +{ + int ret = AOK; + zebra_nhlfe_t *nhlfe, *new_nhlfe; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("init dplane ctx %s: in-label %u ecmp# %d", + dplane_op2str(op), lsp->ile.in_label, + lsp->num_ecmp); + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + /* Capture namespace info */ + dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), + (op == DPLANE_OP_LSP_UPDATE)); + + memset(&ctx->u.lsp, 0, sizeof(ctx->u.lsp)); + + ctx->u.lsp.ile = lsp->ile; + ctx->u.lsp.addr_family = lsp->addr_family; + ctx->u.lsp.num_ecmp = lsp->num_ecmp; + ctx->u.lsp.flags = lsp->flags; + + /* Copy source LSP's nhlfes, and capture 'best' nhlfe */ + for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + /* Not sure if this is meaningful... */ + if (nhlfe->nexthop == NULL) + continue; + + new_nhlfe = + zebra_mpls_lsp_add_nhlfe( + &(ctx->u.lsp), + nhlfe->type, + nhlfe->nexthop->type, + &(nhlfe->nexthop->gate), + nhlfe->nexthop->ifindex, + nhlfe->nexthop->nh_label->label[0]); + + if (new_nhlfe == NULL || new_nhlfe->nexthop == NULL) { + ret = ENOMEM; + break; + } + + /* Need to copy flags too */ + new_nhlfe->flags = nhlfe->flags; + new_nhlfe->nexthop->flags = nhlfe->nexthop->flags; + + if (nhlfe == lsp->best_nhlfe) + ctx->u.lsp.best_nhlfe = new_nhlfe; + } + + /* On error the ctx will be cleaned-up, so we don't need to + * deal with any allocated nhlfe or nexthop structs here. + */ + + return ret; +} + +/* + * Capture information for an LSP update in a dplane context. + */ +static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, + enum dplane_op_e op, + struct zebra_pw *pw) +{ + int ret = AOK; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u", + dplane_op2str(op), pw->ifname, pw->local_label, + pw->remote_label); + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + /* Capture namespace info: no netlink support as of 12/18, + * but just in case... + */ + dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); + + memset(&ctx->u.pw, 0, sizeof(ctx->u.pw)); + + /* This name appears to be c-string, so we use string copy. */ + strlcpy(ctx->u.pw.ifname, pw->ifname, sizeof(ctx->u.pw.ifname)); + ctx->zd_vrf_id = pw->vrf_id; + ctx->u.pw.ifindex = pw->ifindex; + ctx->u.pw.type = pw->type; + ctx->u.pw.af = pw->af; + ctx->u.pw.local_label = pw->local_label; + ctx->u.pw.remote_label = pw->remote_label; + ctx->u.pw.flags = pw->flags; + + ctx->u.pw.nexthop = pw->nexthop; + + ctx->u.pw.fields = pw->data; + + return ret; +} + +/* * Enqueue a new route update, - * and ensure an event is active for the dataplane thread. + * and ensure an event is active for the dataplane pthread. */ static int dplane_route_enqueue(struct zebra_dplane_ctx *ctx) { int ret = EINVAL; uint32_t high, curr; - /* Enqueue for processing by the dataplane thread */ + /* Enqueue for processing by the dataplane pthread */ DPLANE_LOCK(); { TAILQ_INSERT_TAIL(&zdplane_info.dg_route_ctx_q, ctx, @@ -818,20 +1149,21 @@ dplane_route_update_internal(struct route_node *rn, old_re && (old_re != re)) { ctx->zd_is_update = true; - old_re->dplane_sequence++; + old_re->dplane_sequence = + zebra_router_get_next_sequence(); ctx->zd_old_seq = old_re->dplane_sequence; - ctx->zd_old_tag = old_re->tag; - ctx->zd_old_type = old_re->type; - ctx->zd_old_instance = old_re->instance; - ctx->zd_old_distance = old_re->distance; - ctx->zd_old_metric = old_re->metric; + ctx->u.rinfo.zd_old_tag = old_re->tag; + ctx->u.rinfo.zd_old_type = old_re->type; + ctx->u.rinfo.zd_old_instance = old_re->instance; + ctx->u.rinfo.zd_old_distance = old_re->distance; + ctx->u.rinfo.zd_old_metric = old_re->metric; #ifndef HAVE_NETLINK /* For bsd, capture previous re's nexthops too, sigh. * We'll need these to do per-nexthop deletes. */ - copy_nexthops(&(ctx->zd_old_ng.nexthop), + copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop), old_re->ng.nexthop, NULL); #endif /* !HAVE_NETLINK */ } @@ -847,10 +1179,11 @@ done: if (ret == AOK) result = ZEBRA_DPLANE_REQUEST_QUEUED; - else if (ctx) { + else { atomic_fetch_add_explicit(&zdplane_info.dg_route_errors, 1, memory_order_relaxed); - dplane_ctx_free(&ctx); + if (ctx) + dplane_ctx_free(&ctx); } return result; @@ -911,11 +1244,140 @@ done: } /* + * Enqueue LSP add for the dataplane. + */ +enum zebra_dplane_result dplane_lsp_add(zebra_lsp_t *lsp) +{ + enum zebra_dplane_result ret = + lsp_update_internal(lsp, DPLANE_OP_LSP_INSTALL); + + return ret; +} + +/* + * Enqueue LSP update for the dataplane. + */ +enum zebra_dplane_result dplane_lsp_update(zebra_lsp_t *lsp) +{ + enum zebra_dplane_result ret = + lsp_update_internal(lsp, DPLANE_OP_LSP_UPDATE); + + return ret; +} + +/* + * Enqueue LSP delete for the dataplane. + */ +enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp) +{ + enum zebra_dplane_result ret = + lsp_update_internal(lsp, DPLANE_OP_LSP_DELETE); + + return ret; +} + +/* + * Enqueue pseudowire install for the dataplane. + */ +enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw) +{ + return pw_update_internal(pw, DPLANE_OP_PW_INSTALL); +} + +/* + * Enqueue pseudowire un-install for the dataplane. + */ +enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw) +{ + return pw_update_internal(pw, DPLANE_OP_PW_UNINSTALL); +} + +/* + * Common internal LSP update utility + */ +static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp, + enum dplane_op_e op) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + int ret = EINVAL; + struct zebra_dplane_ctx *ctx = NULL; + + /* Obtain context block */ + ctx = dplane_ctx_alloc(); + if (ctx == NULL) { + ret = ENOMEM; + goto done; + } + + ret = dplane_ctx_lsp_init(ctx, op, lsp); + if (ret != AOK) + goto done; + + ret = dplane_route_enqueue(ctx); + +done: + /* Update counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_lsps_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1, + memory_order_relaxed); + if (ctx) + dplane_ctx_free(&ctx); + } + + return result; +} + +/* + * Internal, common handler for pseudowire updates. + */ +static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw, + enum dplane_op_e op) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + int ret; + struct zebra_dplane_ctx *ctx = NULL; + + ctx = dplane_ctx_alloc(); + if (ctx == NULL) { + ret = ENOMEM; + goto done; + } + + ret = dplane_ctx_pw_init(ctx, op, pw); + if (ret != AOK) + goto done; + + ret = dplane_route_enqueue(ctx); + +done: + /* Update counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_pws_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1, + memory_order_relaxed); + if (ctx) + dplane_ctx_free(&ctx); + } + + return result; +} + +/* * Handler for 'show dplane' */ int dplane_show_helper(struct vty *vty, bool detailed) { - uint64_t queued, queue_max, limit, errs, incoming, yields; + uint64_t queued, queue_max, limit, errs, incoming, yields, + other_errs; /* Using atomics because counters are being changed in different * pthread contexts. @@ -932,14 +1394,17 @@ int dplane_show_helper(struct vty *vty, bool detailed) memory_order_relaxed); yields = atomic_load_explicit(&zdplane_info.dg_update_yields, memory_order_relaxed); + other_errs = atomic_load_explicit(&zdplane_info.dg_other_errors, + memory_order_relaxed); vty_out(vty, "Zebra dataplane:\nRoute updates: %"PRIu64"\n", incoming); vty_out(vty, "Route update errors: %"PRIu64"\n", errs); + vty_out(vty, "Other errors : %"PRIu64"\n", other_errs); vty_out(vty, "Route update queue limit: %"PRIu64"\n", limit); vty_out(vty, "Route update queue depth: %"PRIu64"\n", queued); vty_out(vty, "Route update queue max: %"PRIu64"\n", queue_max); - vty_out(vty, "Route update yields: %"PRIu64"\n", yields); + vty_out(vty, "Dplane update yields: %"PRIu64"\n", yields); return CMD_SUCCESS; } @@ -1219,6 +1684,81 @@ int dplane_provider_work_ready(void) */ /* + * Handler for kernel LSP updates + */ +static enum zebra_dplane_result +kernel_dplane_lsp_update(struct zebra_dplane_ctx *ctx) +{ + enum zebra_dplane_result res; + + /* Call into the synchronous kernel-facing code here */ + res = kernel_lsp_update(ctx); + + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit( + &zdplane_info.dg_lsp_errors, 1, + memory_order_relaxed); + + return res; +} + +/* + * Handler for kernel pseudowire updates + */ +static enum zebra_dplane_result +kernel_dplane_pw_update(struct zebra_dplane_ctx *ctx) +{ + enum zebra_dplane_result res; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("Dplane pw %s: op %s af %d loc: %u rem: %u", + dplane_ctx_get_pw_ifname(ctx), + dplane_op2str(ctx->zd_op), + dplane_ctx_get_pw_af(ctx), + dplane_ctx_get_pw_local_label(ctx), + dplane_ctx_get_pw_remote_label(ctx)); + + res = kernel_pw_update(ctx); + + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit( + &zdplane_info.dg_pw_errors, 1, + memory_order_relaxed); + + return res; +} + +/* + * Handler for kernel route updates + */ +static enum zebra_dplane_result +kernel_dplane_route_update(struct zebra_dplane_ctx *ctx) +{ + enum zebra_dplane_result res; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + char dest_str[PREFIX_STRLEN]; + + prefix2str(dplane_ctx_get_dest(ctx), + dest_str, sizeof(dest_str)); + + zlog_debug("%u:%s Dplane route update ctx %p op %s", + dplane_ctx_get_vrf(ctx), dest_str, + ctx, dplane_op2str(dplane_ctx_get_op(ctx))); + } + + /* Call into the synchronous kernel-facing code here */ + res = kernel_route_update(ctx); + + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit( + &zdplane_info.dg_route_errors, 1, + memory_order_relaxed); + + return res; +} + +/* * Kernel provider callback */ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov) @@ -1239,25 +1779,35 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov) if (ctx == NULL) break; - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { - char dest_str[PREFIX_STRLEN]; + /* Dispatch to appropriate kernel-facing apis */ + switch (dplane_ctx_get_op(ctx)) { - prefix2str(dplane_ctx_get_dest(ctx), - dest_str, sizeof(dest_str)); + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + case DPLANE_OP_ROUTE_DELETE: + res = kernel_dplane_route_update(ctx); + break; - zlog_debug("%u:%s Dplane route update ctx %p op %s", - dplane_ctx_get_vrf(ctx), dest_str, - ctx, dplane_op2str(dplane_ctx_get_op(ctx))); - } + case DPLANE_OP_LSP_INSTALL: + case DPLANE_OP_LSP_UPDATE: + case DPLANE_OP_LSP_DELETE: + res = kernel_dplane_lsp_update(ctx); + break; - /* Call into the synchronous kernel-facing code here */ - res = kernel_route_update(ctx); + case DPLANE_OP_PW_INSTALL: + case DPLANE_OP_PW_UNINSTALL: + res = kernel_dplane_pw_update(ctx); + break; - if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + default: atomic_fetch_add_explicit( - &zdplane_info.dg_route_errors, 1, + &zdplane_info.dg_other_errors, 1, memory_order_relaxed); + res = ZEBRA_DPLANE_REQUEST_FAILURE; + break; + } + dplane_ctx_set_status(ctx, res); dplane_provider_enqueue_out_ctx(prov, ctx); @@ -1474,7 +2024,7 @@ static int dplane_check_shutdown_status(struct thread *event) /* We appear to be done - schedule a final callback event * for the zebra main pthread. */ - thread_add_event(zebrad.master, zebra_finalize, NULL, 0, NULL); + thread_add_event(zrouter.master, zebra_finalize, NULL, 0, NULL); } return 0; @@ -1724,7 +2274,7 @@ void zebra_dplane_shutdown(void) /* * Initialize the dataplane module during startup, internal/private version */ -static void zebra_dplane_init_internal(struct zebra_t *zebra) +static void zebra_dplane_init_internal(void) { memset(&zdplane_info, 0, sizeof(zdplane_info)); @@ -1773,6 +2323,6 @@ void zebra_dplane_start(void) */ void zebra_dplane_init(int (*results_fp)(struct dplane_ctx_q *)) { - zebra_dplane_init_internal(&zebrad); + zebra_dplane_init_internal(); zdplane_info.dg_results_cb = results_fp; } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 1c053b85b..81226961e 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -28,6 +28,7 @@ #include "zebra/zebra_ns.h" #include "zebra/rib.h" #include "zebra/zserv.h" +#include "zebra/zebra_mpls.h" /* Key netlink info from zebra ns */ struct zebra_dplane_info { @@ -101,6 +102,14 @@ enum dplane_op_e { DPLANE_OP_ROUTE_UPDATE, DPLANE_OP_ROUTE_DELETE, + /* LSP update */ + DPLANE_OP_LSP_INSTALL, + DPLANE_OP_LSP_UPDATE, + DPLANE_OP_LSP_DELETE, + + /* Pseudowire update */ + DPLANE_OP_PW_INSTALL, + DPLANE_OP_PW_UNINSTALL, }; /* @@ -167,6 +176,8 @@ bool dplane_ctx_is_update(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_seq(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_old_seq(const struct zebra_dplane_ctx *ctx); vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx); + +/* Accessors for route update information */ int dplane_ctx_get_type(const struct zebra_dplane_ctx *ctx); int dplane_ctx_get_old_type(const struct zebra_dplane_ctx *ctx); afi_t dplane_ctx_get_afi(const struct zebra_dplane_ctx *ctx); @@ -188,6 +199,28 @@ const struct nexthop_group *dplane_ctx_get_ng( const struct nexthop_group *dplane_ctx_get_old_ng( const struct zebra_dplane_ctx *ctx); +/* Accessors for LSP information */ +mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx); +uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx); +uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx); +zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx); +zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx); +uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx); + +/* Accessors for pseudowire information */ +const char *dplane_ctx_get_pw_ifname(const struct zebra_dplane_ctx *ctx); +mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx); +mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx); +int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx); +int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx); +uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx); +int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx); +const union g_addr *dplane_ctx_get_pw_nexthop( + const struct zebra_dplane_ctx *ctx); +const union pw_protocol_fields *dplane_ctx_get_pw_proto( + const struct zebra_dplane_ctx *ctx); + +/* Namespace info - esp. for netlink communication */ const struct zebra_dplane_info *dplane_ctx_get_ns( const struct zebra_dplane_ctx *ctx); @@ -209,6 +242,19 @@ enum zebra_dplane_result dplane_route_update(struct route_node *rn, enum zebra_dplane_result dplane_route_delete(struct route_node *rn, struct route_entry *re); +/* + * Enqueue LSP change operations for the dataplane. + */ +enum zebra_dplane_result dplane_lsp_add(zebra_lsp_t *lsp); +enum zebra_dplane_result dplane_lsp_update(zebra_lsp_t *lsp); +enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp); + +/* + * Enqueue pseudowire operations for the dataplane. + */ +enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw); +enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw); + /* Retrieve the limit on the number of pending, unprocessed updates. */ uint32_t dplane_get_in_queue_limit(void); diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index d7c17829c..cb5f30df1 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -505,6 +505,15 @@ static struct log_ref ferr_zebra_err[] = { "Check configuration values for correctness. If they are correct, report this as a bug.", }, { + .code = EC_ZEBRA_RX_ROUTE_NO_NEXTHOPS, + .title = + "Zebra received an installation request for a route without nexthops", + .description = + "Zebra received a message from a client requesting a route installation, but the route is invalid since it doesn't have any nexthop address or interface.", + .suggestion = + "This is a bug; please report it.", + }, + { .code = EC_ZEBRA_RX_SRCDEST_WRONG_AFI, .title = "Zebra received sourcedest route install without IPv6 address family", diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index c3cdc4ed4..0af5f8a55 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -96,6 +96,7 @@ enum zebra_log_refs { EC_ZEBRA_VRF_NOT_FOUND, EC_ZEBRA_MORE_NH_THAN_MULTIPATH, EC_ZEBRA_NEXTHOP_CREATION_FAILED, + EC_ZEBRA_RX_ROUTE_NO_NEXTHOPS, EC_ZEBRA_RX_SRCDEST_WRONG_AFI, EC_ZEBRA_PSEUDOWIRE_EXISTS, EC_ZEBRA_PSEUDOWIRE_UNINSTALL_NOT_FOUND, diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 207cbc099..28333526a 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -276,7 +276,7 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd, if ((cmd == RTM_NEWROUTE && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE - && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))) { + && CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))) { netlink_route_info_add_nh(ri, nexthop); } } diff --git a/zebra/zebra_mlag.c b/zebra/zebra_mlag.c index 35be07c02..5012cc2a4 100644 --- a/zebra/zebra_mlag.c +++ b/zebra/zebra_mlag.c @@ -25,16 +25,17 @@ #include "hook.h" #include "zebra/zebra_mlag.h" +#include "zebra/zebra_router.h" +#include "zebra/zapi_msg.h" +#include "zebra/debug.h" #ifndef VTYSH_EXTRACT_PL #include "zebra/zebra_mlag_clippy.c" #endif -enum mlag_role role = MLAG_ROLE_NONE; - enum mlag_role zebra_mlag_get_role(void) { - return role; + return zrouter.mlag_info.role; } DEFUN_HIDDEN (show_mlag, @@ -47,7 +48,7 @@ DEFUN_HIDDEN (show_mlag, char buf[80]; vty_out(vty, "MLag is configured to: %s\n", - mlag_role2str(role, buf, sizeof(buf))); + mlag_role2str(zrouter.mlag_info.role, buf, sizeof(buf))); return CMD_SUCCESS; } @@ -62,12 +63,23 @@ DEFPY_HIDDEN (test_mlag, "Mlag is setup to be primary\n" "Mlag is setup to be the secondary\n") { + enum mlag_role orig = zrouter.mlag_info.role; + char buf1[80], buf2[80]; + if (none) - role = MLAG_ROLE_NONE; + zrouter.mlag_info.role = MLAG_ROLE_NONE; if (primary) - role = MLAG_ROLE_PRIMARY; + zrouter.mlag_info.role = MLAG_ROLE_PRIMARY; if (secondary) - role = MLAG_ROLE_SECONDARY; + zrouter.mlag_info.role = MLAG_ROLE_SECONDARY; + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("Test: Changing role from %s to %s", + mlag_role2str(orig, buf1, sizeof(buf1)), + mlag_role2str(orig, buf2, sizeof(buf2))); + + if (orig != zrouter.mlag_info.role) + zsend_capabilities_all_clients(); return CMD_SUCCESS; } diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index c0764cd4b..a06e15d90 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -40,6 +40,7 @@ #include "zebra/rt.h" #include "zebra/interface.h" #include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/zebra_memory.h" @@ -56,9 +57,6 @@ DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE_IFNAME, "MPLS static nexthop ifname") int mpls_enabled; -/* Default rtm_table for all clients */ -extern struct zebra_t zebrad; - /* static function declarations */ static void fec_evaluate(struct zebra_vrf *zvrf); @@ -87,8 +85,8 @@ static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe, static int nhlfe_nexthop_active(zebra_nhlfe_t *nhlfe); static void lsp_select_best_nhlfe(zebra_lsp_t *lsp); -static void lsp_uninstall_from_kernel(struct hash_backet *backet, void *ctxt); -static void lsp_schedule(struct hash_backet *backet, void *ctxt); +static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt); +static void lsp_schedule(struct hash_bucket *bucket, void *ctxt); static wq_item_status lsp_process(struct work_queue *wq, void *data); static void lsp_processq_del(struct work_queue *wq, void *data); static void lsp_processq_complete(struct work_queue *wq); @@ -126,7 +124,6 @@ static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp, static int snhlfe_del(zebra_snhlfe_t *snhlfe); static int snhlfe_del_all(zebra_slsp_t *slsp); static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size); -static int mpls_processq_init(struct zebra_t *zebra); /* Static functions */ @@ -856,24 +853,24 @@ static void lsp_select_best_nhlfe(zebra_lsp_t *lsp) * Delete LSP forwarding entry from kernel, if installed. Called upon * process exit. */ -static void lsp_uninstall_from_kernel(struct hash_backet *backet, void *ctxt) +static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt) { zebra_lsp_t *lsp; - lsp = (zebra_lsp_t *)backet->data; + lsp = (zebra_lsp_t *)bucket->data; if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) - (void)kernel_del_lsp(lsp); + (void)dplane_lsp_delete(lsp); } /* * Schedule LSP forwarding entry for processing. Called upon changes * that may impact LSPs such as nexthop / connected route changes. */ -static void lsp_schedule(struct hash_backet *backet, void *ctxt) +static void lsp_schedule(struct hash_bucket *bucket, void *ctxt) { zebra_lsp_t *lsp; - lsp = (zebra_lsp_t *)backet->data; + lsp = (zebra_lsp_t *)bucket->data; (void)lsp_processq_add(lsp); } @@ -887,6 +884,7 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data) zebra_nhlfe_t *oldbest, *newbest; char buf[BUFSIZ], buf2[BUFSIZ]; struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT); + enum zebra_dplane_result res; lsp = (zebra_lsp_t *)data; if (!lsp) // unexpected @@ -916,13 +914,20 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data) if (newbest) { UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED); - switch (kernel_add_lsp(lsp)) { + + switch (dplane_lsp_add(lsp)) { case ZEBRA_DPLANE_REQUEST_QUEUED: - flog_err( - EC_ZEBRA_DP_INVALID_RC, - "No current DataPlane interfaces can return this, please fix"); + /* Set 'installed' flag so we will know + * that an install is in-flight. + */ + SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED); + + zvrf->lsp_installs_queued++; break; case ZEBRA_DPLANE_REQUEST_FAILURE: + flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE, + "LSP Install Failure: %u", + lsp->ile.in_label); break; case ZEBRA_DPLANE_REQUEST_SUCCESS: zvrf->lsp_installs++; @@ -932,14 +937,22 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data) } else { /* Installed, may need an update and/or delete. */ if (!newbest) { + res = dplane_lsp_delete(lsp); - switch (kernel_del_lsp(lsp)) { + /* We do some of the lsp cleanup immediately for + * deletes. + */ + UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED); + clear_nhlfe_installed(lsp); + + switch (res) { case ZEBRA_DPLANE_REQUEST_QUEUED: - flog_err( - EC_ZEBRA_DP_INVALID_RC, - "No current DataPlane interfaces can return this, please fix"); + zvrf->lsp_removals_queued++; break; case ZEBRA_DPLANE_REQUEST_FAILURE: + flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE, + "LSP Deletion Failure: %u", + lsp->ile.in_label); break; case ZEBRA_DPLANE_REQUEST_SUCCESS: zvrf->lsp_removals++; @@ -950,7 +963,10 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data) struct nexthop *nexthop; UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED); - UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED); + + /* We leave the INSTALLED flag set here + * so we know an update in in-flight. + */ /* * Any NHLFE that was installed but is not @@ -973,13 +989,14 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data) } } - switch (kernel_upd_lsp(lsp)) { + switch (dplane_lsp_update(lsp)) { case ZEBRA_DPLANE_REQUEST_QUEUED: - flog_err( - EC_ZEBRA_DP_INVALID_RC, - "No current DataPlane interfaces can return this, please fix"); + zvrf->lsp_installs_queued++; break; case ZEBRA_DPLANE_REQUEST_FAILURE: + flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE, + "LSP Update Failure: %u", + lsp->ile.in_label); break; case ZEBRA_DPLANE_REQUEST_SUCCESS: zvrf->lsp_installs++; @@ -1054,13 +1071,13 @@ static int lsp_processq_add(zebra_lsp_t *lsp) if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) return 0; - if (zebrad.lsp_process_q == NULL) { + if (zrouter.lsp_process_q == NULL) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, "%s: work_queue does not exist!", __func__); return -1; } - work_queue_add(zebrad.lsp_process_q, lsp); + work_queue_add(zrouter.lsp_process_q, lsp); SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED); return 0; } @@ -1475,7 +1492,7 @@ static json_object *lsp_json(zebra_lsp_t *lsp) static struct list *hash_get_sorted_list(struct hash *hash, void *cmp) { unsigned int i; - struct hash_backet *hb; + struct hash_bucket *hb; struct list *sorted_list = list_new(); sorted_list->cmp = (int (*)(void *, void *))cmp; @@ -1694,21 +1711,21 @@ static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size) /* * Initialize work queue for processing changed LSPs. */ -static int mpls_processq_init(struct zebra_t *zebra) +static int mpls_processq_init(void) { - zebra->lsp_process_q = work_queue_new(zebra->master, "LSP processing"); - if (!zebra->lsp_process_q) { + zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing"); + if (!zrouter.lsp_process_q) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, "%s: could not initialise work queue!", __func__); return -1; } - zebra->lsp_process_q->spec.workfunc = &lsp_process; - zebra->lsp_process_q->spec.del_item_data = &lsp_processq_del; - zebra->lsp_process_q->spec.errorfunc = NULL; - zebra->lsp_process_q->spec.completion_func = &lsp_processq_complete; - zebra->lsp_process_q->spec.max_retries = 0; - zebra->lsp_process_q->spec.hold = 10; + zrouter.lsp_process_q->spec.workfunc = &lsp_process; + zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del; + zrouter.lsp_process_q->spec.errorfunc = NULL; + zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete; + zrouter.lsp_process_q->spec.max_retries = 0; + zrouter.lsp_process_q->spec.hold = 10; return 0; } @@ -1716,43 +1733,85 @@ static int mpls_processq_init(struct zebra_t *zebra) /* Public functions */ -void kernel_lsp_pass_fail(zebra_lsp_t *lsp, enum zebra_dplane_status res) +/* + * Process LSP update results from zebra dataplane. + */ +void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) { - struct nexthop *nexthop; + struct zebra_vrf *zvrf; + zebra_ile_t tmp_ile; + struct hash *lsp_table; + zebra_lsp_t *lsp; zebra_nhlfe_t *nhlfe; + struct nexthop *nexthop; + enum dplane_op_e op; + enum zebra_dplane_result status; + + op = dplane_ctx_get_op(ctx); + status = dplane_ctx_get_status(ctx); + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("LSP dplane ctx %p, op %s, in-label %u, result %s", + ctx, dplane_op2str(op), + dplane_ctx_get_in_label(ctx), + dplane_res2str(status)); + + switch (op) { + case DPLANE_OP_LSP_INSTALL: + case DPLANE_OP_LSP_UPDATE: + /* Look for zebra LSP object */ + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (zvrf == NULL) + break; - if (!lsp) - return; + lsp_table = zvrf->lsp_table; - switch (res) { - case ZEBRA_DPLANE_INSTALL_FAILURE: - UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED); - clear_nhlfe_installed(lsp); - flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE, - "LSP Install Failure: %u", lsp->ile.in_label); - break; - case ZEBRA_DPLANE_INSTALL_SUCCESS: - SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED); - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { - nexthop = nhlfe->nexthop; - if (!nexthop) - continue; + tmp_ile.in_label = dplane_ctx_get_in_label(ctx); + lsp = hash_lookup(lsp_table, &tmp_ile); + if (lsp == NULL) { + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("LSP ctx %p: in-label %u not found", + ctx, dplane_ctx_get_in_label(ctx)); + break; + } + + /* TODO -- Confirm that this result is still 'current' */ + + if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { + /* Update zebra object */ + SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED); + for (nhlfe = lsp->nhlfe_list; nhlfe; + nhlfe = nhlfe->next) { + nexthop = nhlfe->nexthop; + if (!nexthop) + continue; - SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED); - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED); + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + } + } else { + UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED); + clear_nhlfe_installed(lsp); + flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE, + "LSP Install Failure: in-label %u", + lsp->ile.in_label); } + break; - case ZEBRA_DPLANE_DELETE_SUCCESS: - UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED); - clear_nhlfe_installed(lsp); - break; - case ZEBRA_DPLANE_DELETE_FAILURE: - flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE, - "LSP Deletion Failure: %u", lsp->ile.in_label); + + case DPLANE_OP_LSP_DELETE: + if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) + flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE, + "LSP Deletion Failure: in-label %u", + dplane_ctx_get_in_label(ctx)); break; - case ZEBRA_DPLANE_STATUS_NONE: + + default: break; - } + + } /* Switch */ + + dplane_ctx_fini(&ctx); } /* @@ -1808,6 +1867,29 @@ int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn, } /* + * Add an NHLFE to an LSP, return the newly-added object + */ +zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp, + enum lsp_types_t lsp_type, + enum nexthop_types_t gtype, + union g_addr *gate, + ifindex_t ifindex, + mpls_label_t out_label) +{ + /* Just a public pass-through to the internal implementation */ + return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, out_label); +} + +/* + * Free an allocated NHLFE + */ +void zebra_mpls_nhlfe_del(zebra_nhlfe_t *nhlfe) +{ + /* Just a pass-through to the internal implementation */ + nhlfe_del(nhlfe); +} + +/* * Registration from a client for the label binding for a FEC. If a binding * already exists, it is informed to the client. * NOTE: If there is a manually configured label binding, that is used. @@ -2468,12 +2550,12 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, * Uninstall all LDP NHLFEs for a particular LSP forwarding entry. * If no other NHLFEs exist, the entry would be deleted. */ -void mpls_ldp_lsp_uninstall_all(struct hash_backet *backet, void *ctxt) +void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt) { zebra_lsp_t *lsp; struct hash *lsp_table; - lsp = (zebra_lsp_t *)backet->data; + lsp = (zebra_lsp_t *)bucket->data; if (!lsp->nhlfe_list) return; @@ -2978,7 +3060,7 @@ void zebra_mpls_init(void) return; } - if (!mpls_processq_init(&zebrad)) + if (!mpls_processq_init()) mpls_enabled = 1; hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client); diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index c250fc405..39f084ad2 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -191,6 +191,17 @@ int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn, int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn, struct route_entry *re); +/* Add an NHLFE to an LSP, return the newly-added object */ +zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp, + enum lsp_types_t lsp_type, + enum nexthop_types_t gtype, + union g_addr *gate, + ifindex_t ifindex, + mpls_label_t out_label); + +/* Free an allocated NHLFE */ +void zebra_mpls_nhlfe_del(zebra_nhlfe_t *nhlfe); + int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p, uint32_t label, uint32_t label_index, struct zserv *client); @@ -280,7 +291,7 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, * Uninstall all LDP NHLFEs for a particular LSP forwarding entry. * If no other NHLFEs exist, the entry would be deleted. */ -void mpls_ldp_lsp_uninstall_all(struct hash_backet *backet, void *ctxt); +void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt); /* * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family. @@ -291,7 +302,7 @@ void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi); * Uninstall all Segment Routing NHLFEs for a particular LSP forwarding entry. * If no other NHLFEs exist, the entry would be deleted. */ -void mpls_sr_lsp_uninstall_all(struct hash_backet *backet, void *ctxt); +void mpls_sr_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt); #if defined(HAVE_CUMULUS) /* @@ -331,6 +342,14 @@ int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label, ifindex_t ifindex); /* + * Process LSP update results from zebra dataplane. + */ +/* Forward ref of dplane update context type */ +struct zebra_dplane_ctx; + +void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx); + +/* * Schedule all MPLS label forwarding entries for processing. * Called upon changes that may affect one or more of them such as * interface or nexthop state changes. diff --git a/zebra/zebra_mpls_netlink.c b/zebra/zebra_mpls_netlink.c index c4ab316d0..a9233530d 100644 --- a/zebra/zebra_mpls_netlink.c +++ b/zebra/zebra_mpls_netlink.c @@ -22,83 +22,52 @@ #ifdef HAVE_NETLINK +#include "zebra/debug.h" #include "zebra/rt.h" #include "zebra/rt_netlink.h" #include "zebra/zebra_mpls.h" /* - * Install Label Forwarding entry into the kernel. + * LSP forwarding update using dataplane context information. */ -enum zebra_dplane_result kernel_add_lsp(zebra_lsp_t *lsp) +enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx) { - int ret; + int cmd, ret = -1; - if (!lsp || !lsp->best_nhlfe) { // unexpected - kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_INSTALL_FAILURE); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } + /* Call to netlink layer based on type of update */ + if (dplane_ctx_get_op(ctx) == DPLANE_OP_LSP_DELETE) { + cmd = RTM_DELROUTE; + } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_LSP_INSTALL || + dplane_ctx_get_op(ctx) == DPLANE_OP_LSP_UPDATE) { - ret = netlink_mpls_multipath(RTM_NEWROUTE, lsp); + /* Validate */ + if (dplane_ctx_get_best_nhlfe(ctx) == NULL) { + if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_MPLS) + zlog_debug("LSP in-label %u: update fails, no best NHLFE", + dplane_ctx_get_in_label(ctx)); + goto done; + } - kernel_lsp_pass_fail(lsp, - (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS - : ZEBRA_DPLANE_INSTALL_FAILURE); + cmd = RTM_NEWROUTE; + } else + /* Invalid op? */ + goto done; - return ZEBRA_DPLANE_REQUEST_SUCCESS; -} - -/* - * Update Label Forwarding entry in the kernel. This means that the Label - * forwarding entry is already installed and needs an update - either a new - * path is to be added, an installed path has changed (e.g., outgoing label) - * or an installed path (but not all paths) has to be removed. - * TODO: Performs a DEL followed by ADD now, need to change to REPLACE. Note - * that REPLACE was originally implemented for IPv4 nexthops but removed as - * it was not functioning when moving from swap to PHP as that was signaled - * through the metric field (before kernel-MPLS). This shouldn't be an issue - * any longer, so REPLACE can be reintroduced. - */ -enum zebra_dplane_result kernel_upd_lsp(zebra_lsp_t *lsp) -{ - int ret; - - if (!lsp || !lsp->best_nhlfe) { // unexpected - kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_INSTALL_FAILURE); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } + ret = netlink_mpls_multipath(cmd, ctx); - ret = netlink_mpls_multipath(RTM_NEWROUTE, lsp); +done: - kernel_lsp_pass_fail(lsp, - (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS - : ZEBRA_DPLANE_INSTALL_FAILURE); - - return ZEBRA_DPLANE_REQUEST_SUCCESS; + return (ret == 0 ? + ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE); } /* - * Delete Label Forwarding entry from the kernel. + * Pseudowire update api - not supported by netlink as of 12/18, + * but note that the default has been to report 'success' for pw updates + * on unsupported platforms. */ -enum zebra_dplane_result kernel_del_lsp(zebra_lsp_t *lsp) +enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx) { - int ret; - - if (!lsp) { // unexpected - kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_DELETE_FAILURE); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - - if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) { - kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_DELETE_FAILURE); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - - ret = netlink_mpls_multipath(RTM_DELROUTE, lsp); - - kernel_lsp_pass_fail(lsp, - (!ret) ? ZEBRA_DPLANE_DELETE_SUCCESS - : ZEBRA_DPLANE_DELETE_FAILURE); - return ZEBRA_DPLANE_REQUEST_SUCCESS; } diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c index 02ec506d8..2cc3f3b69 100644 --- a/zebra/zebra_mpls_null.c +++ b/zebra/zebra_mpls_null.c @@ -24,24 +24,23 @@ #if !defined(HAVE_NETLINK) && !defined(OPEN_BSD) -enum zebra_dplane_result kernel_add_lsp(zebra_lsp_t *lsp) +int mpls_kernel_init(void) { - return ZEBRA_DPLANE_REQUEST_SUCCESS; -} + return -1; +}; -enum zebra_dplane_result kernel_upd_lsp(zebra_lsp_t *lsp) +/* + * Pseudowire update api - note that the default has been + * to report 'success' for pw updates on unsupported platforms. + */ +enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx) { return ZEBRA_DPLANE_REQUEST_SUCCESS; } -enum zebra_dplane_result kernel_del_lsp(zebra_lsp_t *lsp) +enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx) { - return ZEBRA_DPLANE_REQUEST_SUCCESS; + return ZEBRA_DPLANE_REQUEST_FAILURE; } -int mpls_kernel_init(void) -{ - return -1; -}; - #endif /* !defined(HAVE_NETLINK) && !defined(OPEN_BSD) */ diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c index 60f944b84..72c8f7352 100644 --- a/zebra/zebra_mpls_openbsd.c +++ b/zebra/zebra_mpls_openbsd.c @@ -236,13 +236,28 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label, return ret; } -static int kernel_lsp_cmd(int action, zebra_lsp_t *lsp) +static int kernel_lsp_cmd(struct zebra_dplane_ctx *ctx) { zebra_nhlfe_t *nhlfe; struct nexthop *nexthop = NULL; unsigned int nexthop_num = 0; + int action; - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + switch (dplane_ctx_get_op(ctx)) { + case DPLANE_OP_LSP_DELETE: + action = RTM_DELETE; + break; + case DPLANE_OP_LSP_INSTALL: + action = RTM_ADD; + break; + case DPLANE_OP_LSP_UPDATE: + action = RTM_CHANGE; + break; + default: + return -1; + } + + for (nhlfe = dplane_ctx_get_nhlfe(ctx); nhlfe; nhlfe = nhlfe->next) { nexthop = nhlfe->nexthop; if (!nexthop) continue; @@ -269,12 +284,16 @@ static int kernel_lsp_cmd(int action, zebra_lsp_t *lsp) switch (NHLFE_FAMILY(nhlfe)) { case AF_INET: - kernel_send_rtmsg_v4(action, lsp->ile.in_label, - nhlfe); + kernel_send_rtmsg_v4( + action, + dplane_ctx_get_in_label(ctx), + nhlfe); break; case AF_INET6: - kernel_send_rtmsg_v6(action, lsp->ile.in_label, - nhlfe); + kernel_send_rtmsg_v6( + action, + dplane_ctx_get_in_label(ctx), + nhlfe); break; default: break; @@ -285,74 +304,27 @@ static int kernel_lsp_cmd(int action, zebra_lsp_t *lsp) return (0); } -enum zebra_dplane_result kernel_add_lsp(zebra_lsp_t *lsp) -{ - int ret; - - if (!lsp || !lsp->best_nhlfe) { // unexpected - kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_INSTALL_FAILURE); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - - ret = kernel_lsp_cmd(RTM_ADD, lsp); - - kernel_lsp_pass_fail(lsp, - (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS - : ZEBRA_DPLANE_INSTALL_FAILURE); - - return ZEBRA_DPLANE_REQUEST_SUCCESS; -} - -enum zebra_dplane_result kernel_upd_lsp(zebra_lsp_t *lsp) +enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx) { int ret; - if (!lsp || !lsp->best_nhlfe) { // unexpected - kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_INSTALL_FAILURE); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - - ret = kernel_lsp_cmd(RTM_CHANGE, lsp); - - kernel_lsp_pass_fail(lsp, - (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS - : ZEBRA_DPLANE_INSTALL_FAILURE); - return ZEBRA_DPLANE_REQUEST_SUCCESS; -} - -enum zebra_dplane_result kernel_del_lsp(zebra_lsp_t *lsp) -{ - int ret; - - if (!lsp) { // unexpected - kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_DELETE_FAILURE); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - - if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) { - kernel_lsp_pass_fail(lsp, ZEBRA_DPLANE_DELETE_FAILURE); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - - ret = kernel_lsp_cmd(RTM_DELETE, lsp); + ret = kernel_lsp_cmd(ctx); - kernel_lsp_pass_fail(lsp, - (!ret) ? ZEBRA_DPLANE_DELETE_SUCCESS - : ZEBRA_DPLANE_DELETE_FAILURE); - - return ZEBRA_DPLANE_REQUEST_SUCCESS; + return (ret == 0 ? + ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE); } -static int kmpw_install(struct zebra_pw *pw) +static enum zebra_dplane_result kmpw_install(struct zebra_dplane_ctx *ctx) { struct ifreq ifr; struct ifmpwreq imr; struct sockaddr_storage ss; struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; + const union g_addr *gaddr; memset(&imr, 0, sizeof(imr)); - switch (pw->type) { + switch (dplane_ctx_get_pw_type(ctx)) { case PW_TYPE_ETHERNET: imr.imr_type = IMR_TYPE_ETHERNET; break; @@ -361,67 +333,91 @@ static int kmpw_install(struct zebra_pw *pw) break; default: zlog_debug("%s: unhandled pseudowire type (%#X)", __func__, - pw->type); - return -1; + dplane_ctx_get_pw_type(ctx)); + return ZEBRA_DPLANE_REQUEST_FAILURE; } - if (pw->flags & F_PSEUDOWIRE_CWORD) + if (dplane_ctx_get_pw_flags(ctx) & F_PSEUDOWIRE_CWORD) imr.imr_flags |= IMR_FLAG_CONTROLWORD; /* pseudowire nexthop */ memset(&ss, 0, sizeof(ss)); - switch (pw->af) { + gaddr = dplane_ctx_get_pw_nexthop(ctx); + switch (dplane_ctx_get_pw_af(ctx)) { case AF_INET: sa_in->sin_family = AF_INET; sa_in->sin_len = sizeof(struct sockaddr_in); - sa_in->sin_addr = pw->nexthop.ipv4; + sa_in->sin_addr = gaddr->ipv4; break; case AF_INET6: sa_in6->sin6_family = AF_INET6; sa_in6->sin6_len = sizeof(struct sockaddr_in6); - sa_in6->sin6_addr = pw->nexthop.ipv6; + sa_in6->sin6_addr = gaddr->ipv6; break; default: zlog_debug("%s: unhandled pseudowire address-family (%u)", - __func__, pw->af); - return -1; + __func__, dplane_ctx_get_pw_af(ctx)); + return ZEBRA_DPLANE_REQUEST_FAILURE; } memcpy(&imr.imr_nexthop, (struct sockaddr *)&ss, sizeof(imr.imr_nexthop)); /* pseudowire local/remote labels */ - imr.imr_lshim.shim_label = pw->local_label; - imr.imr_rshim.shim_label = pw->remote_label; + imr.imr_lshim.shim_label = dplane_ctx_get_pw_local_label(ctx); + imr.imr_rshim.shim_label = dplane_ctx_get_pw_remote_label(ctx); /* ioctl */ memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, dplane_ctx_get_pw_ifname(ctx), + sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t)&imr; if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) { flog_err_sys(EC_LIB_SYSTEM_CALL, "ioctl SIOCSETMPWCFG: %s", safe_strerror(errno)); - return -1; + return ZEBRA_DPLANE_REQUEST_FAILURE; } - return 0; + return ZEBRA_DPLANE_REQUEST_SUCCESS; } -static int kmpw_uninstall(struct zebra_pw *pw) +static enum zebra_dplane_result kmpw_uninstall(struct zebra_dplane_ctx *ctx) { struct ifreq ifr; struct ifmpwreq imr; memset(&ifr, 0, sizeof(ifr)); memset(&imr, 0, sizeof(imr)); - strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, dplane_ctx_get_pw_ifname(ctx), + sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t)&imr; if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) { flog_err_sys(EC_LIB_SYSTEM_CALL, "ioctl SIOCSETMPWCFG: %s", safe_strerror(errno)); - return -1; + return ZEBRA_DPLANE_REQUEST_FAILURE; } - return 0; + return ZEBRA_DPLANE_REQUEST_SUCCESS; +} + +/* + * Pseudowire update api for openbsd. + */ +enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + + switch (dplane_ctx_get_op(ctx)) { + case DPLANE_OP_PW_INSTALL: + result = kmpw_install(ctx); + break; + case DPLANE_OP_PW_UNINSTALL: + result = kmpw_uninstall(ctx); + break; + default: + break; + }; + + return result; } #define MAX_RTSOCK_BUF 128 * 1024 @@ -460,10 +456,6 @@ int mpls_kernel_init(void) kr_state.rtseq = 1; - /* register hook to install/uninstall pseudowires */ - hook_register(pw_install, kmpw_install); - hook_register(pw_uninstall, kmpw_uninstall); - return 0; } diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index ef31fcf45..476638591 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -36,7 +36,7 @@ #include "memory.h" #include "lib_errors.h" -#include "zserv.h" +#include "zebra_router.h" #include "zebra_memory.h" #endif /* defined(HAVE_NETLINK) */ @@ -121,7 +121,7 @@ static int zebra_ns_continue_read(struct zebra_netns_info *zns_info, XFREE(MTYPE_NETNS_MISC, zns_info); return 0; } - thread_add_timer_msec(zebrad.master, zebra_ns_ready_read, + thread_add_timer_msec(zrouter.master, zebra_ns_ready_read, (void *)zns_info, ZEBRA_NS_POLLING_INTERVAL_MSEC, NULL); return 0; @@ -242,7 +242,7 @@ static int zebra_ns_notify_read(struct thread *t) ssize_t len; zebra_netns_notify_current = thread_add_read( - zebrad.master, zebra_ns_notify_read, NULL, fd_monitor, NULL); + zrouter.master, zebra_ns_notify_read, NULL, fd_monitor, NULL); len = read(fd_monitor, buf, sizeof(buf)); if (len < 0) { flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ, @@ -284,7 +284,7 @@ static int zebra_ns_notify_read(struct thread *t) sizeof(struct zebra_netns_info)); netnsinfo->retries = ZEBRA_NS_POLLING_MAX_RETRIES; netnsinfo->netnspath = netnspath; - thread_add_timer_msec(zebrad.master, zebra_ns_ready_read, + thread_add_timer_msec(zrouter.master, zebra_ns_ready_read, (void *)netnsinfo, 0, NULL); } return 0; @@ -355,7 +355,7 @@ void zebra_ns_notify_init(void) safe_strerror(errno)); } zebra_netns_notify_current = thread_add_read( - zebrad.master, zebra_ns_notify_read, NULL, fd_monitor, NULL); + zrouter.master, zebra_ns_notify_read, NULL, fd_monitor, NULL); } void zebra_ns_notify_close(void) diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 833306bcc..348bdeb9f 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -212,7 +212,7 @@ struct pbr_rule_unique_lookup { vrf_id_t vrf_id; }; -static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data) +static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data) { struct pbr_rule_unique_lookup *pul = data; struct zebra_pbr_rule *rule = b->data; @@ -461,7 +461,7 @@ void zebra_pbr_del_rule(struct zebra_pbr_rule *rule) __PRETTY_FUNCTION__); } -static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data) +static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data) { struct zebra_pbr_rule *rule = b->data; int *sock = data; @@ -473,7 +473,7 @@ static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data) } } -static void zebra_pbr_cleanup_ipset(struct hash_backet *b, void *data) +static void zebra_pbr_cleanup_ipset(struct hash_bucket *b, void *data) { struct zebra_pbr_ipset *ipset = b->data; int *sock = data; @@ -484,7 +484,7 @@ static void zebra_pbr_cleanup_ipset(struct hash_backet *b, void *data) } } -static void zebra_pbr_cleanup_ipset_entry(struct hash_backet *b, void *data) +static void zebra_pbr_cleanup_ipset_entry(struct hash_bucket *b, void *data) { struct zebra_pbr_ipset_entry *ipset = b->data; int *sock = data; @@ -495,7 +495,7 @@ static void zebra_pbr_cleanup_ipset_entry(struct hash_backet *b, void *data) } } -static void zebra_pbr_cleanup_iptable(struct hash_backet *b, void *data) +static void zebra_pbr_cleanup_iptable(struct hash_bucket *b, void *data) { struct zebra_pbr_iptable *iptable = b->data; int *sock = data; @@ -576,11 +576,11 @@ const char *zebra_pbr_ipset_type2str(uint32_t type) "Unrecognized IPset Type"); } -static int zebra_pbr_ipset_pername_walkcb(struct hash_backet *backet, void *arg) +static int zebra_pbr_ipset_pername_walkcb(struct hash_bucket *bucket, void *arg) { struct pbr_ipset_name_lookup *pinl = (struct pbr_ipset_name_lookup *)arg; - struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data; + struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data; if (!strncmp(pinl->ipset_name, zpi->ipset_name, ZEBRA_IPSET_NAME_SIZE)) { @@ -874,7 +874,7 @@ static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm, } } -static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet, +static int zebra_pbr_show_ipset_entry_walkcb(struct hash_bucket *bucket, void *arg) { struct zebra_pbr_ipset_entry_unique_display *unique = @@ -882,7 +882,7 @@ static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet, struct zebra_pbr_ipset *zpi = unique->zpi; struct vty *vty = unique->vty; struct zebra_pbr_ipset_entry *zpie = - (struct zebra_pbr_ipset_entry *)backet->data; + (struct zebra_pbr_ipset_entry *)bucket->data; uint64_t pkts = 0, bytes = 0; int ret = 0; @@ -949,11 +949,11 @@ static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet, return HASHWALK_CONTINUE; } -static int zebra_pbr_show_ipset_walkcb(struct hash_backet *backet, void *arg) +static int zebra_pbr_show_ipset_walkcb(struct hash_bucket *bucket, void *arg) { struct zebra_pbr_env_display *uniqueipset = (struct zebra_pbr_env_display *)arg; - struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data; + struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data; struct zebra_pbr_ipset_entry_unique_display unique; struct vty *vty = uniqueipset->vty; struct zebra_ns *zns = uniqueipset->zns; @@ -1026,12 +1026,12 @@ struct pbr_rule_fwmark_lookup { uint32_t fwmark; }; -static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_backet *backet, +static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_bucket *bucket, void *arg) { struct pbr_rule_fwmark_lookup *iprule = (struct pbr_rule_fwmark_lookup *)arg; - struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)backet->data; + struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)bucket->data; if (iprule->fwmark == zpr->rule.filter.fwmark) { iprule->ptr = zpr; @@ -1117,10 +1117,10 @@ static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable *iptable, } } -static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg) +static int zebra_pbr_show_iptable_walkcb(struct hash_bucket *bucket, void *arg) { struct zebra_pbr_iptable *iptable = - (struct zebra_pbr_iptable *)backet->data; + (struct zebra_pbr_iptable *)bucket->data; struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg; struct vty *vty = env->vty; struct zebra_ns *zns = env->zns; diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index e4a4adba0..1e942d643 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -41,7 +41,7 @@ #include "zebra/zebra_errors.h" #include "zebra/zebra_ptm.h" #include "zebra/zebra_ptm_redistribute.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra_vrf.h" /* @@ -187,12 +187,12 @@ static int zebra_ptm_flush_messages(struct thread *thread) ptm_cb.ptm_sock = -1; zebra_ptm_reset_status(0); ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return (-1); case BUFFER_PENDING: ptm_cb.t_write = NULL; - thread_add_write(zebrad.master, zebra_ptm_flush_messages, NULL, + thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL, ptm_cb.ptm_sock, &ptm_cb.t_write); break; case BUFFER_EMPTY: @@ -213,14 +213,14 @@ static int zebra_ptm_send_message(char *data, int size) ptm_cb.ptm_sock = -1; zebra_ptm_reset_status(0); ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return -1; case BUFFER_EMPTY: THREAD_OFF(ptm_cb.t_write); break; case BUFFER_PENDING: - thread_add_write(zebrad.master, zebra_ptm_flush_messages, NULL, + thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL, ptm_cb.ptm_sock, &ptm_cb.t_write); break; } @@ -240,7 +240,7 @@ int zebra_ptm_connect(struct thread *t) if (ptm_cb.ptm_sock != -1) { if (init) { ptm_cb.t_read = NULL; - thread_add_read(zebrad.master, zebra_ptm_sock_read, + thread_add_read(zrouter.master, zebra_ptm_sock_read, NULL, ptm_cb.ptm_sock, &ptm_cb.t_read); zebra_bfd_peer_replay_req(); } @@ -252,7 +252,7 @@ int zebra_ptm_connect(struct thread *t) ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_MAX; ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); } else if (ptm_cb.reconnect_time >= ZEBRA_PTM_RECONNECT_TIME_MAX) { ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL; @@ -657,14 +657,14 @@ int zebra_ptm_sock_read(struct thread *thread) ptm_cb.ptm_sock = -1; zebra_ptm_reset_status(0); ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return (-1); } ptm_cb.t_read = NULL; - thread_add_read(zebrad.master, zebra_ptm_sock_read, NULL, + thread_add_read(zrouter.master, zebra_ptm_sock_read, NULL, ptm_cb.ptm_sock, &ptm_cb.t_read); return 0; @@ -700,7 +700,7 @@ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS) if (ptm_cb.ptm_sock == -1) { ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return; } @@ -854,7 +854,7 @@ void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS) if (ptm_cb.ptm_sock == -1) { ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return; } @@ -981,7 +981,7 @@ void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS) if (ptm_cb.ptm_sock == -1) { ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return; } @@ -1039,7 +1039,7 @@ int zebra_ptm_bfd_client_deregister(struct zserv *client) if (ptm_cb.ptm_sock == -1) { ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return 0; } @@ -1276,7 +1276,7 @@ static void zebra_ptm_send_bfdd(struct stream *msg) } /* Send message to all running BFDd daemons. */ - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { if (client->proto != ZEBRA_ROUTE_BFD) continue; @@ -1308,7 +1308,7 @@ static void zebra_ptm_send_clients(struct stream *msg) } /* Send message to all running client daemons. */ - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { if (!IS_BFD_ENABLED_PROTOCOL(client->proto)) continue; diff --git a/zebra/zebra_ptm_redistribute.c b/zebra/zebra_ptm_redistribute.c index 420105198..01d5114b9 100644 --- a/zebra/zebra_ptm_redistribute.c +++ b/zebra/zebra_ptm_redistribute.c @@ -22,7 +22,7 @@ #include "prefix.h" #include "vty.h" #include "stream.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zapi_msg.h" #include "zebra/zebra_ptm.h" #include "zebra/zebra_ptm_redistribute.h" @@ -36,10 +36,6 @@ static int zsend_interface_bfd_update(int cmd, struct zserv *client, int blen; struct stream *s; - /* Check this client need interface information. */ - if (!client->ifinfo) - return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, vrf_id); @@ -76,7 +72,7 @@ void zebra_interface_bfd_update(struct interface *ifp, struct prefix *dp, struct listnode *node, *nnode; struct zserv *client; - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { if (!IS_BFD_ENABLED_PROTOCOL(client->proto)) continue; @@ -106,7 +102,7 @@ void zebra_bfd_peer_replay_req(void) struct listnode *node, *nnode; struct zserv *client; - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { if (!IS_BFD_ENABLED_PROTOCOL(client->proto)) continue; diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index fb9a40fe3..006c1da02 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -27,7 +27,7 @@ #include "zebra/debug.h" #include "zebra/rib.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zapi_msg.h" #include "zebra/zebra_rnh.h" #include "zebra/zebra_vrf.h" @@ -42,8 +42,6 @@ DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)) #define MPLS_NO_LABEL MPLS_INVALID_LABEL -extern struct zebra_t zebrad; - static int zebra_pw_enabled(struct zebra_pw *); static void zebra_pw_install(struct zebra_pw *); static void zebra_pw_uninstall(struct zebra_pw *); @@ -98,9 +96,10 @@ void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw) zebra_deregister_rnh_pseudowire(pw->vrf_id, pw); /* uninstall */ - if (pw->status == PW_STATUS_UP) + if (pw->status == PW_STATUS_UP) { hook_call(pw_uninstall, pw); - else if (pw->install_retry_timer) + dplane_pw_uninstall(pw); + } else if (pw->install_retry_timer) THREAD_TIMER_OFF(pw->install_retry_timer); /* unlink and release memory */ @@ -171,7 +170,8 @@ static void zebra_pw_install(struct zebra_pw *pw) pw->vrf_id, pw->ifname, zebra_route_string(pw->protocol)); - if (hook_call(pw_install, pw)) { + hook_call(pw_install, pw); + if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) { zebra_pw_install_failure(pw); return; } @@ -192,6 +192,7 @@ static void zebra_pw_uninstall(struct zebra_pw *pw) /* ignore any possible error */ hook_call(pw_uninstall, pw); + dplane_pw_uninstall(pw); if (zebra_pw_enabled(pw)) zebra_pw_update_status(pw, PW_STATUS_DOWN); @@ -213,7 +214,7 @@ void zebra_pw_install_failure(struct zebra_pw *pw) /* schedule to retry later */ THREAD_TIMER_OFF(pw->install_retry_timer); - thread_add_timer(zebrad.master, zebra_pw_install_retry, pw, + thread_add_timer(zrouter.master, zebra_pw_install_retry, pw, PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer); zebra_pw_update_status(pw, PW_STATUS_DOWN); diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h index e6e0a22c2..9692fb4d4 100644 --- a/zebra/zebra_pw.h +++ b/zebra/zebra_pw.h @@ -62,8 +62,8 @@ RB_PROTOTYPE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare); DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw)) DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)) -struct zebra_pw *zebra_pw_add(struct zebra_vrf *, const char *, uint8_t, - struct zserv *); +struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname, + uint8_t protocol, struct zserv *client); void zebra_pw_del(struct zebra_vrf *, struct zebra_pw *); void zebra_pw_change(struct zebra_pw *, ifindex_t, int, int, union g_addr *, uint32_t, uint32_t, uint8_t, union pw_protocol_fields *); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 7e4ac1ddd..de1aa7d6d 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -163,7 +163,7 @@ int is_zebra_valid_kernel_table(uint32_t table_id) int is_zebra_main_routing_table(uint32_t table_id) { if ((table_id == RT_TABLE_MAIN) - || (table_id == zebrad.rtm_table_default)) + || (table_id == zrouter.rtm_table_default)) return 1; return 0; } @@ -276,11 +276,8 @@ struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re, /*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) - if (connected_is_unnumbered(ifp) - || CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE) - || CHECK_FLAG(re->flags, ZEBRA_FLAG_ONLINK)) { + if (connected_is_unnumbered(ifp)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); - } route_entry_nexthop_add(re, nexthop); @@ -315,10 +312,6 @@ struct nexthop *route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re, nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; nexthop->gate.ipv6 = *ipv6; nexthop->ifindex = ifindex; - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE) - || CHECK_FLAG(re->flags, ZEBRA_FLAG_ONLINK)) { - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); - } route_entry_nexthop_add(re, nexthop); @@ -436,8 +429,12 @@ static int nexthop_active(afi_t afi, struct route_entry *re, re->nexthop_mtu = 0; } - /* Next hops (remote VTEPs) for EVPN routes are fully resolved. */ - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN_RVTEP)) + /* + * If the kernel has sent us a route, then + * by golly gee whiz it's a good route. + */ + if (re->type == ZEBRA_ROUTE_KERNEL || + re->type == ZEBRA_ROUTE_SYSTEM) return 1; /* Skip nexthops that have been filtered out due to route-map */ @@ -454,11 +451,21 @@ static int nexthop_active(afi_t afi, struct route_entry *re, * Check to see if we should trust the passed in information * for UNNUMBERED interfaces as that we won't find the GW * address in the routing table. + * This check should suffice to handle IPv4 or IPv6 routes + * sourced from EVPN routes which are installed with the + * next hop as the remote VTEP IP. */ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) { ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id); - if ((ifp && connected_is_unnumbered(ifp)) - || CHECK_FLAG(re->flags, ZEBRA_FLAG_ONLINK)) { + if (!ifp) { + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug( + "\t%s: Onlink and interface: %u[%u] does not exist", + __PRETTY_FUNCTION__, nexthop->ifindex, + nexthop->vrf_id); + return 0; + } + if (connected_is_unnumbered(ifp)) { if (if_is_operative(ifp)) return 1; else { @@ -468,7 +475,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re, __PRETTY_FUNCTION__, ifp->name); return 0; } - } else { + } + if (!if_is_operative(ifp)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( "\t%s: Interface %s is not unnumbered", @@ -566,8 +574,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re, } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) { resolved = 0; for (ALL_NEXTHOPS(match->ng, newhop)) { - if (!CHECK_FLAG(newhop->flags, - NEXTHOP_FLAG_FIB)) + if (!CHECK_FLAG(match->status, + ROUTE_ENTRY_INSTALLED)) continue; if (CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_RECURSIVE)) @@ -592,8 +600,11 @@ static int nexthop_active(afi_t afi, struct route_entry *re, } else if (re->type == ZEBRA_ROUTE_STATIC) { resolved = 0; for (ALL_NEXTHOPS(match->ng, newhop)) { - if (!CHECK_FLAG(newhop->flags, - NEXTHOP_FLAG_FIB)) + if (!CHECK_FLAG(match->status, + ROUTE_ENTRY_INSTALLED)) + continue; + if (CHECK_FLAG(newhop->flags, + NEXTHOP_FLAG_RECURSIVE)) continue; if (set) { @@ -637,7 +648,6 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, struct route_table *table; struct route_node *rn; struct route_entry *match = NULL; - struct nexthop *newhop; /* Lookup table. */ table = zebra_vrf_table(afi, safi, vrf_id); @@ -677,14 +687,8 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, route_lock_node(rn); } else { if (match->type != ZEBRA_ROUTE_CONNECT) { - int found = 0; - for (ALL_NEXTHOPS(match->ng, newhop)) - if (CHECK_FLAG(newhop->flags, - NEXTHOP_FLAG_FIB)) { - found = 1; - break; - } - if (!found) + if (!CHECK_FLAG(match->status, + ROUTE_ENTRY_INSTALLED)) return NULL; } @@ -774,7 +778,6 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) struct route_table *table; struct route_node *rn; struct route_entry *match = NULL; - struct nexthop *nexthop; rib_dest_t *dest; /* Lookup table. */ @@ -802,9 +805,8 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) if (match->type == ZEBRA_ROUTE_CONNECT) return match; - for (ALL_NEXTHOPS(match->ng, nexthop)) - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) - return match; + if (CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) + return match; return NULL; } @@ -1082,13 +1084,16 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, hook_call(rib_update, rn, "installing in kernel"); /* Send add or update */ - if (old && (old != re)) + if (old) ret = dplane_route_update(rn, re, old); else ret = dplane_route_add(rn, re); switch (ret) { case ZEBRA_DPLANE_REQUEST_QUEUED: + SET_FLAG(re->status, ROUTE_ENTRY_QUEUED); + if (old) + SET_FLAG(old->status, ROUTE_ENTRY_QUEUED); if (zvrf) zvrf->installs_queued++; break; @@ -1119,6 +1124,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id); if (info->safi != SAFI_UNICAST) { + UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); for (ALL_NEXTHOPS(re->ng, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; @@ -1171,6 +1177,8 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re) if (!RIB_SYSTEM_ROUTE(re)) rib_uninstall_kernel(rn, re); + else + UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); dest->selected_fib = NULL; @@ -1264,8 +1272,9 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rn, buf, sizeof(buf)); - zlog_debug("%u:%s: Adding route rn %p, re %p (type %d)", - zvrf_id(zvrf), buf, rn, new, new->type); + zlog_debug("%u:%s: Adding route rn %p, re %p (%s)", + zvrf_id(zvrf), buf, rn, new, + zebra_route_string(new->type)); } /* If labeled-unicast route, install transit LSP. */ @@ -1290,8 +1299,9 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rn, buf, sizeof(buf)); - zlog_debug("%u:%s: Deleting route rn %p, re %p (type %d)", - zvrf_id(zvrf), buf, rn, old, old->type); + zlog_debug("%u:%s: Deleting route rn %p, re %p (%s)", + zvrf_id(zvrf), buf, rn, old, + zebra_route_string(old->type)); } /* If labeled-unicast route, uninstall transit LSP. */ @@ -1301,6 +1311,7 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); else { + UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED); /* * We are setting this to NULL here * because that is what we traditionally @@ -1357,15 +1368,16 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, srcdest_rnode2str(rn, buf, sizeof(buf)); if (new != old) zlog_debug( - "%u:%s: Updating route rn %p, re %p (type %d) " - "old %p (type %d)", + "%u:%s: Updating route rn %p, re %p (%s) old %p (%s)", zvrf_id(zvrf), buf, rn, new, - new->type, old, old->type); + zebra_route_string(new->type), + old, + zebra_route_string(old->type)); else zlog_debug( - "%u:%s: Updating route rn %p, re %p (type %d)", + "%u:%s: Updating route rn %p, re %p (%s)", zvrf_id(zvrf), buf, rn, new, - new->type); + zebra_route_string(new->type)); } /* If labeled-unicast route, uninstall transit LSP. */ @@ -1381,6 +1393,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, rib_install_kernel(rn, new, old); } else { + UNSET_FLAG(new->status, ROUTE_ENTRY_INSTALLED); /* * We do not need to install the * selected route because it @@ -1400,7 +1413,13 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (RIB_SYSTEM_ROUTE(new)) { if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); + else + UNSET_FLAG( + old->status, + ROUTE_ENTRY_INSTALLED); } else { + UNSET_FLAG(old->status, + ROUTE_ENTRY_INSTALLED); for (nexthop = old->ng.nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG(nexthop->flags, @@ -1420,15 +1439,16 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, srcdest_rnode2str(rn, buf, sizeof(buf)); if (new != old) zlog_debug( - "%u:%s: Deleting route rn %p, re %p (type %d) " - "old %p (type %d) - nexthop inactive", + "%u:%s: Deleting route rn %p, re %p (%s) old %p (%s) - nexthop inactive", zvrf_id(zvrf), buf, rn, new, - new->type, old, old->type); + zebra_route_string(new->type), + old, + zebra_route_string(old->type)); else zlog_debug( - "%u:%s: Deleting route rn %p, re %p (type %d) - nexthop inactive", + "%u:%s: Deleting route rn %p, re %p (%s) - nexthop inactive", zvrf_id(zvrf), buf, rn, new, - new->type); + zebra_route_string(new->type)); } /* If labeled-unicast route, uninstall transit LSP. */ @@ -1437,8 +1457,10 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); - else + else { + UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED); dest->selected_fib = NULL; + } } } else { /* @@ -1450,18 +1472,9 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, * is ready * to add routes. */ - if (!RIB_SYSTEM_ROUTE(new)) { - bool in_fib = false; - - for (ALL_NEXTHOPS(new->ng, nexthop)) - if (CHECK_FLAG(nexthop->flags, - NEXTHOP_FLAG_FIB)) { - in_fib = true; - break; - } - if (!in_fib) - rib_install_kernel(rn, new, NULL); - } + if (!RIB_SYSTEM_ROUTE(new) + && !CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED)) + rib_install_kernel(rn, new, NULL); } /* Update prior route. */ @@ -1580,10 +1593,10 @@ static void rib_process(struct route_node *rn) RNODE_FOREACH_RE_SAFE (rn, re, next) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - "%u:%s: Examine re %p (type %d) status %x flags %x " - "dist %d metric %d", - vrf_id, buf, re, re->type, re->status, - re->flags, re->distance, re->metric); + "%u:%s: Examine re %p (%s) status %x flags %x dist %d metric %d", + vrf_id, buf, re, zebra_route_string(re->type), + re->status, re->flags, re->distance, + re->metric); UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); @@ -1811,7 +1824,7 @@ done: /* * Route-update results processing after async dataplane update. */ -static void rib_process_after(struct zebra_dplane_ctx *ctx) +static void rib_process_result(struct zebra_dplane_ctx *ctx) { struct route_table *table = NULL; struct zebra_vrf *zvrf = NULL; @@ -1902,46 +1915,57 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx) /* * Check sequence number(s) to detect stale results before continuing */ - if (re && (re->dplane_sequence != dplane_ctx_get_seq(ctx))) { - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { - zlog_debug("%u:%s Stale dplane result for re %p", - dplane_ctx_get_vrf(ctx), dest_str, re); - } - re = NULL; - } - - if (old_re && - (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx))) { - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { - zlog_debug("%u:%s Stale dplane result for old_re %p", - dplane_ctx_get_vrf(ctx), dest_str, old_re); - } - old_re = NULL; - } - - /* - * Here's sort of a tough one: the route update result is stale. - * Is it better to use the context block info to generate - * redist and owner notification, or is it better to wait - * for the up-to-date result to arrive? - */ - if (re == NULL) { - /* TODO -- for now, only expose up-to-date results */ - goto done; + if (re) { + if (re->dplane_sequence != dplane_ctx_get_seq(ctx)) { + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("%u:%s Stale dplane result for re %p", + dplane_ctx_get_vrf(ctx), + dest_str, re); + } else + UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); + } + + if (old_re) { + if (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx)) { + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("%u:%s Stale dplane result for old_re %p", + dplane_ctx_get_vrf(ctx), + dest_str, old_re); + } else + UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); } switch (op) { - case DPLANE_OP_NONE: - break; case DPLANE_OP_ROUTE_INSTALL: case DPLANE_OP_ROUTE_UPDATE: if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { + if (re) { + UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED); + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + } + /* + * On an update operation from the same route type + * context retrieval currently has no way to know + * which was the old and which was the new. + * So don't unset our flags that we just set. + * We know redistribution is ok because the + * old_re in this case is used for nothing + * more than knowing whom to contact if necessary. + */ + if (old_re && old_re != re) { + UNSET_FLAG(old_re->status, ROUTE_ENTRY_FAILED); + UNSET_FLAG(old_re->status, + ROUTE_ENTRY_INSTALLED); + } /* Update zebra nexthop FIB flag for each * nexthop that was installed. */ for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), ctx_nexthop)) { + if (!re) + continue; + for (ALL_NEXTHOPS(re->ng, nexthop)) { if (nexthop_same(ctx_nexthop, nexthop)) break; @@ -1978,15 +2002,21 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx) * 'old' context info was stale, 'old_re' will be * NULL here and that delete will not be sent. */ - redistribute_update(dest_pfx, src_pfx, re, old_re); + if (re) + redistribute_update(dest_pfx, src_pfx, + re, old_re); /* Notify route owner */ - zsend_route_notify_owner(re, dest_pfx, - ZAPI_ROUTE_INSTALLED); + zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED); } else { - zsend_route_notify_owner(re, dest_pfx, - ZAPI_ROUTE_FAIL_INSTALL); + if (re) + SET_FLAG(re->status, ROUTE_ENTRY_FAILED); + if (old_re) + SET_FLAG(old_re->status, ROUTE_ENTRY_FAILED); + if (re) + zsend_route_notify_owner(re, dest_pfx, + ZAPI_ROUTE_FAIL_INSTALL); zlog_warn("%u:%s: Route install failed", dplane_ctx_get_vrf(ctx), @@ -1995,17 +2025,25 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx) } break; case DPLANE_OP_ROUTE_DELETE: + if (re) + SET_FLAG(re->status, ROUTE_ENTRY_FAILED); /* * In the delete case, the zebra core datastructs were * updated (or removed) at the time the delete was issued, * so we're just notifying the route owner. */ if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { + if (re) { + UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED); + } zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVED); if (zvrf) zvrf->removals++; } else { + if (re) + SET_FLAG(re->status, ROUTE_ENTRY_FAILED); zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVE_FAIL); @@ -2015,9 +2053,14 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx) dest_str, sizeof(dest_str))); } break; + default: + break; } done: + if (rn) + route_unlock_node(rn); + /* Return context to dataplane module */ dplane_ctx_fini(&ctx); } @@ -2090,11 +2133,11 @@ static void do_nht_processing(void) zvrf_name(zvrf)); zvrf->flags &= ~ZEBRA_VRF_RIB_SCHEDULED; - zebra_evaluate_rnh(zvrf, AF_INET, 0, RNH_NEXTHOP_TYPE, NULL); - zebra_evaluate_rnh(zvrf, AF_INET, 0, RNH_IMPORT_CHECK_TYPE, + zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_IMPORT_CHECK_TYPE, NULL); - zebra_evaluate_rnh(zvrf, AF_INET6, 0, RNH_NEXTHOP_TYPE, NULL); - zebra_evaluate_rnh(zvrf, AF_INET6, 0, RNH_IMPORT_CHECK_TYPE, + zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_IMPORT_CHECK_TYPE, NULL); } @@ -2110,14 +2153,6 @@ static void do_nht_processing(void) } } -/* - * All meta queues have been processed. Trigger next-hop evaluation. - */ -static void meta_queue_process_complete(struct work_queue *dummy) -{ - do_nht_processing(); -} - /* Dispatch the meta queue by picking, processing and unlocking the next RN from * a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and * data @@ -2138,8 +2173,8 @@ static wq_item_status meta_queue_process(struct work_queue *dummy, void *data) queue_len, queue_limit); /* Ensure that the meta-queue is actually enqueued */ - if (work_queue_empty(zebrad.ribq)) - work_queue_add(zebrad.ribq, zebrad.mq); + if (work_queue_empty(zrouter.ribq)) + work_queue_add(zrouter.ribq, zrouter.mq); return WQ_QUEUE_BLOCKED; } @@ -2228,7 +2263,7 @@ void rib_queue_add(struct route_node *rn) return; } - if (zebrad.ribq == NULL) { + if (zrouter.ribq == NULL) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, "%s: work_queue does not exist!", __func__); return; @@ -2242,10 +2277,10 @@ void rib_queue_add(struct route_node *rn) * holder, if necessary, then push the work into it in any case. * This semantics was introduced after 0.99.9 release. */ - if (work_queue_empty(zebrad.ribq)) - work_queue_add(zebrad.ribq, zebrad.mq); + if (work_queue_empty(zrouter.ribq)) + work_queue_add(zrouter.ribq, zrouter.mq); - rib_meta_queue_add(zebrad.mq, rn); + rib_meta_queue_add(zrouter.mq, rn); return; } @@ -2279,27 +2314,25 @@ void meta_queue_free(struct meta_queue *mq) } /* initialise zebra rib work queue */ -static void rib_queue_init(struct zebra_t *zebra) +static void rib_queue_init(void) { - assert(zebra); - - if (!(zebra->ribq = - work_queue_new(zebra->master, "route_node processing"))) { + if (!(zrouter.ribq = work_queue_new(zrouter.master, + "route_node processing"))) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, "%s: could not initialise work queue!", __func__); return; } /* fill in the work queue spec */ - zebra->ribq->spec.workfunc = &meta_queue_process; - zebra->ribq->spec.errorfunc = NULL; - zebra->ribq->spec.completion_func = &meta_queue_process_complete; + zrouter.ribq->spec.workfunc = &meta_queue_process; + zrouter.ribq->spec.errorfunc = NULL; + zrouter.ribq->spec.completion_func = NULL; /* XXX: TODO: These should be runtime configurable via vty */ - zebra->ribq->spec.max_retries = 3; - zebra->ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME; - zebra->ribq->spec.retry = ZEBRA_RIB_PROCESS_RETRY_TIME; + zrouter.ribq->spec.max_retries = 3; + zrouter.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME; + zrouter.ribq->spec.retry = ZEBRA_RIB_PROCESS_RETRY_TIME; - if (!(zebra->mq = meta_queue_new())) { + if (!(zrouter.mq = meta_queue_new())) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, "%s: could not initialise meta queue!", __func__); return; @@ -2454,9 +2487,9 @@ void rib_delnode(struct route_node *rn, struct route_entry *re) if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rn, buf, sizeof(buf)); - zlog_debug( - "%u:%s: Freeing route rn %p, re %p (type %d)", - re->vrf_id, buf, rn, re, re->type); + zlog_debug("%u:%s: Freeing route rn %p, re %p (%s)", + re->vrf_id, buf, rn, re, + zebra_route_string(re->type)); } rib_unlink(rn, re); @@ -2527,7 +2560,7 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""), - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB) + (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "FIB " : ""), (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) @@ -2708,16 +2741,17 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, } /* If this route is kernel route, set FIB flag to the route. */ - if (RIB_SYSTEM_ROUTE(re)) + if (RIB_SYSTEM_ROUTE(re)) { + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + } /* Link new re to node.*/ if (IS_ZEBRA_DEBUG_RIB) { - rnode_debug( - rn, re->vrf_id, - "Inserting route rn %p, re %p (type %d) existing %p", - (void *)rn, (void *)re, re->type, (void *)same); + rnode_debug(rn, re->vrf_id, + "Inserting route rn %p, re %p (%s) existing %p", + rn, re, zebra_route_string(re->type), same); if (IS_ZEBRA_DEBUG_RIB_DETAILED) route_entry_dump(p, src_p, re); @@ -2841,12 +2875,13 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, */ if (fib && CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)) { if (IS_ZEBRA_DEBUG_RIB) { - rnode_debug( - rn, vrf_id, - "rn %p, re %p (type %d) was deleted from kernel, adding", - rn, fib, fib->type); + rnode_debug(rn, vrf_id, + "rn %p, re %p (%s) was deleted from kernel, adding", + rn, fib, + zebra_route_string(fib->type)); } if (allow_delete) { + UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED); /* Unset flags. */ for (rtnh = fib->ng.nexthop; rtnh; rtnh = rtnh->next) @@ -2897,6 +2932,10 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, return; } + /* Special handling for IPv4 or IPv6 routes sourced from + * EVPN - the nexthop (and associated MAC) need to be + * uninstalled if no more refs. + */ if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) { struct nexthop *tmp_nh; @@ -3093,6 +3132,7 @@ void rib_sweep_table(struct route_table *table) * to a different spot (ie startup ) * this decision needs to be revisited */ + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); for (ALL_NEXTHOPS(re->ng, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); @@ -3191,7 +3231,36 @@ void rib_close_table(struct route_table *table) } /* - * + * Handler for async dataplane results after a pseudowire installation + */ +static int handle_pw_result(struct zebra_dplane_ctx *ctx) +{ + int ret = 0; + struct zebra_pw *pw; + struct zebra_vrf *vrf; + + /* The pseudowire code assumes success - we act on an error + * result for installation attempts here. + */ + if (dplane_ctx_get_op(ctx) != DPLANE_OP_PW_INSTALL) + goto done; + + if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) { + vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); + pw = zebra_pw_find(vrf, dplane_ctx_get_pw_ifname(ctx)); + if (pw) + zebra_pw_install_failure(pw); + } + +done: + + return ret; +} + + +/* + * Handle results from the dataplane system. Dequeue update context + * structs, dispatch to appropriate internal handlers. */ static int rib_process_dplane_results(struct thread *thread) { @@ -3206,7 +3275,7 @@ static int rib_process_dplane_results(struct thread *thread) /* Take lock controlling queue of results */ pthread_mutex_lock(&dplane_mutex); { - /* Dequeue context block */ + /* Dequeue list of context structs */ dplane_ctx_list_append(&ctxlist, &rib_dplane_q); } pthread_mutex_unlock(&dplane_mutex); @@ -3219,7 +3288,29 @@ static int rib_process_dplane_results(struct thread *thread) break; while (ctx) { - rib_process_after(ctx); + switch (dplane_ctx_get_op(ctx)) { + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + case DPLANE_OP_ROUTE_DELETE: + rib_process_result(ctx); + break; + + case DPLANE_OP_LSP_INSTALL: + case DPLANE_OP_LSP_UPDATE: + case DPLANE_OP_LSP_DELETE: + zebra_mpls_lsp_dplane_result(ctx); + break; + + case DPLANE_OP_PW_INSTALL: + case DPLANE_OP_PW_UNINSTALL: + handle_pw_result(ctx); + break; + + default: + /* Don't expect this: just return the struct? */ + dplane_ctx_fini(&ctx); + break; + } /* Dispatch by op code */ ctx = dplane_ctx_dequeue(&ctxlist); } @@ -3248,7 +3339,7 @@ static int rib_dplane_results(struct dplane_ctx_q *ctxlist) pthread_mutex_unlock(&dplane_mutex); /* Ensure event is signalled to zebra main pthread */ - thread_add_event(zebrad.master, rib_process_dplane_results, NULL, 0, + thread_add_event(zrouter.master, rib_process_dplane_results, NULL, 0, &t_dplane); return 0; @@ -3257,7 +3348,7 @@ static int rib_dplane_results(struct dplane_ctx_q *ctxlist) /* Routing information base initialize. */ void rib_init(void) { - rib_queue_init(&zebrad); + rib_queue_init(); /* Init dataplane, and register for results */ pthread_mutex_init(&dplane_mutex, NULL); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index c3781888b..52637c606 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -54,16 +54,6 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, struct route_node *rn); static void copy_state(struct rnh *rnh, struct route_entry *re, struct route_node *rn); -#define lookup_rnh_table(v, f) \ - ({ \ - struct zebra_vrf *zvrf; \ - struct route_table *t = NULL; \ - zvrf = zebra_vrf_lookup_by_id(v); \ - if (zvrf) \ - t = zvrf->rnh_table[family2afi(f)]; \ - t; \ - }) - static int compare_state(struct route_entry *r1, struct route_entry *r2); static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, vrf_id_t vrf_id); @@ -78,7 +68,7 @@ void zebra_rnh_init(void) hook_register(zserv_client_close, zebra_client_cleanup_rnh); } -static inline struct route_table *get_rnh_table(vrf_id_t vrfid, int family, +static inline struct route_table *get_rnh_table(vrf_id_t vrfid, afi_t afi, rnh_type_t type) { struct zebra_vrf *zvrf; @@ -88,10 +78,10 @@ static inline struct route_table *get_rnh_table(vrf_id_t vrfid, int family, if (zvrf) switch (type) { case RNH_NEXTHOP_TYPE: - t = zvrf->rnh_table[family2afi(family)]; + t = zvrf->rnh_table[afi]; break; case RNH_IMPORT_CHECK_TYPE: - t = zvrf->import_check_table[family2afi(family)]; + t = zvrf->import_check_table[afi]; break; } @@ -116,7 +106,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type, prefix2str(p, buf, sizeof(buf)); zlog_debug("%u: Add RNH %s type %d", vrfid, buf, type); } - table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type); + table = get_rnh_table(vrfid, family2afi(PREFIX_FAMILY(p)), type); if (!table) { prefix2str(p, buf, sizeof(buf)); flog_warn(EC_ZEBRA_RNH_NO_TABLE, @@ -153,7 +143,7 @@ struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type) struct route_table *table; struct route_node *rn; - table = get_rnh_table(vrfid, PREFIX_FAMILY(p), type); + table = get_rnh_table(vrfid, family2afi(PREFIX_FAMILY(p)), type); if (!table) return NULL; @@ -278,7 +268,8 @@ void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw) if (rnh && !listnode_lookup(rnh->zebra_pseudowire_list, pw)) { listnode_add(rnh->zebra_pseudowire_list, pw); pw->rnh = rnh; - zebra_evaluate_rnh(zvrf, pw->af, 1, RNH_NEXTHOP_TYPE, &nh); + zebra_evaluate_rnh(zvrf, family2afi(pw->af), 1, + RNH_NEXTHOP_TYPE, &nh); } } @@ -299,22 +290,19 @@ void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw) /* Apply the NHT route-map for a client to the route (and nexthops) * resolving a NH. */ -static int zebra_rnh_apply_nht_rmap(int family, struct zebra_vrf *zvrf, +static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf, struct route_node *prn, struct route_entry *re, int proto) { int at_least_one = 0; - int rmap_family; /* Route map has diff AF family enum */ struct nexthop *nexthop; int ret; - rmap_family = (family == AF_INET) ? AFI_IP : AFI_IP6; - if (prn && re) { for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { ret = zebra_nht_route_map_check( - rmap_family, proto, &prn->p, zvrf, re, nexthop); + afi, proto, &prn->p, zvrf, re, nexthop); if (ret != RMAP_DENYMATCH) { SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); at_least_one++; /* at least one valid NH */ @@ -331,7 +319,7 @@ static int zebra_rnh_apply_nht_rmap(int family, struct zebra_vrf *zvrf, * for BGP route for import. */ static struct route_entry * -zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, int family, +zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi, struct route_node *nrn, struct rnh *rnh, struct route_node **prn) { @@ -341,7 +329,7 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, int family, *prn = NULL; - route_table = zvrf->table[family2afi(family)][SAFI_UNICAST]; + route_table = zvrf->table[afi][SAFI_UNICAST]; if (!route_table) // unexpected return NULL; @@ -373,7 +361,7 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, int family, * See if a tracked route entry for import (by BGP) has undergone any * change, and if so, notify the client. */ -static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, int family, +static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, afi_t afi, int force, struct route_node *nrn, struct rnh *rnh, struct route_entry *re) @@ -382,14 +370,10 @@ static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, int family, struct zserv *client; char bufn[INET6_ADDRSTRLEN]; struct listnode *node; - struct nexthop *nexthop; if (re && (rnh->state == NULL)) { - for (ALL_NEXTHOPS(re->ng, nexthop)) - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) { - state_changed = 1; - break; - } + if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) + state_changed = 1; } else if (!re && (rnh->state != NULL)) state_changed = 1; @@ -413,9 +397,11 @@ static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, int family, /* * Notify clients registered for this nexthop about a change. */ -static void zebra_rnh_notify_protocol_clients( - struct zebra_vrf *zvrf, int family, struct route_node *nrn, - struct rnh *rnh, struct route_node *prn, struct route_entry *re) +static void zebra_rnh_notify_protocol_clients(struct zebra_vrf *zvrf, afi_t afi, + struct route_node *nrn, + struct rnh *rnh, + struct route_node *prn, + struct route_entry *re) { struct listnode *node; struct zserv *client; @@ -441,7 +427,7 @@ static void zebra_rnh_notify_protocol_clients( * nexthop to see if it is filtered or not. */ num_resolving_nh = zebra_rnh_apply_nht_rmap( - family, zvrf, prn, re, client->proto); + afi, zvrf, prn, re, client->proto); if (num_resolving_nh) rnh->filtered[client->proto] = 0; else @@ -468,8 +454,7 @@ static void zebra_rnh_notify_protocol_clients( } } -static void zebra_rnh_process_pbr_tables(int family, - struct route_node *nrn, +static void zebra_rnh_process_pbr_tables(afi_t afi, struct route_node *nrn, struct rnh *rnh, struct route_node *prn, struct route_entry *re) @@ -479,10 +464,6 @@ static void zebra_rnh_process_pbr_tables(int family, struct route_node *o_rn; struct listnode *node; struct zserv *client; - afi_t afi = AFI_IP; - - if (family == AF_INET6) - afi = AFI_IP6; /* * We are only concerned about nexthops that change for @@ -526,9 +507,10 @@ static void zebra_rnh_process_pbr_tables(int family, * check in a couple of places, so this is a single home for the logic we * use. */ -static bool rnh_nexthop_valid(const struct nexthop *nh) +static bool rnh_nexthop_valid(const struct route_entry *re, + const struct nexthop *nh) { - return (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB) + return (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)); } @@ -537,7 +519,7 @@ static bool rnh_nexthop_valid(const struct nexthop *nh) * nexthop. */ static struct route_entry * -zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, int family, +zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, struct route_node *nrn, struct rnh *rnh, struct route_node **prn) { @@ -548,7 +530,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, int family, *prn = NULL; - route_table = zvrf->table[family2afi(family)][SAFI_UNICAST]; + route_table = zvrf->table[afi][SAFI_UNICAST]; if (!route_table) return NULL; @@ -581,7 +563,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, int family, * have an installed nexthop to be useful. */ for (ALL_NEXTHOPS(re->ng, nexthop)) { - if (rnh_nexthop_valid(nexthop)) + if (rnh_nexthop_valid(re, nexthop)) break; } @@ -635,7 +617,7 @@ static void zebra_rnh_process_pseudowires(vrf_id_t vrfid, struct rnh *rnh) * take appropriate action; this involves notifying any clients and/or * scheduling dependent static routes for processing. */ -static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, int family, +static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, int force, struct route_node *nrn, struct rnh *rnh, struct route_node *prn, @@ -665,10 +647,10 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, int family, * rnh->state. */ /* Notify registered protocol clients. */ - zebra_rnh_notify_protocol_clients(zvrf, family, nrn, rnh, prn, + zebra_rnh_notify_protocol_clients(zvrf, afi, nrn, rnh, prn, rnh->state); - zebra_rnh_process_pbr_tables(family, nrn, rnh, prn, rnh->state); + zebra_rnh_process_pbr_tables(afi, nrn, rnh, prn, rnh->state); /* Process pseudowires attached to this nexthop */ zebra_rnh_process_pseudowires(zvrf->vrf->vrf_id, rnh); @@ -676,7 +658,7 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, int family, } /* Evaluate one tracked entry */ -static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, int family, +static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, afi_t afi, int force, rnh_type_t type, struct route_node *nrn) { @@ -695,11 +677,9 @@ static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, int family, /* Identify route entry (RE) resolving this tracked entry. */ if (type == RNH_IMPORT_CHECK_TYPE) - re = zebra_rnh_resolve_import_entry(zvrf, family, nrn, rnh, - &prn); + re = zebra_rnh_resolve_import_entry(zvrf, afi, nrn, rnh, &prn); else - re = zebra_rnh_resolve_nexthop_entry(zvrf, family, nrn, rnh, - &prn); + re = zebra_rnh_resolve_nexthop_entry(zvrf, afi, nrn, rnh, &prn); /* If the entry cannot be resolved and that is also the existing state, * there is nothing further to do. @@ -709,10 +689,10 @@ static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, int family, /* Process based on type of entry. */ if (type == RNH_IMPORT_CHECK_TYPE) - zebra_rnh_eval_import_check_entry(zvrf->vrf->vrf_id, family, - force, nrn, rnh, re); + zebra_rnh_eval_import_check_entry(zvrf->vrf->vrf_id, afi, force, + nrn, rnh, re); else - zebra_rnh_eval_nexthop_entry(zvrf, family, force, nrn, rnh, prn, + zebra_rnh_eval_nexthop_entry(zvrf, afi, force, nrn, rnh, prn, re); } @@ -725,7 +705,7 @@ static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, int family, * we can have a situation where one re entry * covers multiple nexthops we are interested in. */ -static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, int family, +static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, afi_t afi, rnh_type_t type, struct route_node *nrn) { struct rnh *rnh; @@ -736,10 +716,10 @@ static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, int family, /* Identify route entry (RIB) resolving this tracked entry. */ if (type == RNH_IMPORT_CHECK_TYPE) - re = zebra_rnh_resolve_import_entry(zvrf, family, nrn, rnh, + re = zebra_rnh_resolve_import_entry(zvrf, afi, nrn, rnh, &prn); else - re = zebra_rnh_resolve_nexthop_entry(zvrf, family, nrn, rnh, + re = zebra_rnh_resolve_nexthop_entry(zvrf, afi, nrn, rnh, &prn); if (re) { @@ -751,13 +731,13 @@ static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, int family, /* Evaluate all tracked entries (nexthops or routes for import into BGP) * of a particular VRF and address-family or a specific prefix. */ -void zebra_evaluate_rnh(struct zebra_vrf *zvrf, int family, int force, +void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force, rnh_type_t type, struct prefix *p) { struct route_table *rnh_table; struct route_node *nrn; - rnh_table = get_rnh_table(zvrf->vrf->vrf_id, family, type); + rnh_table = get_rnh_table(zvrf->vrf->vrf_id, afi, type); if (!rnh_table) // unexpected return; @@ -765,8 +745,7 @@ void zebra_evaluate_rnh(struct zebra_vrf *zvrf, int family, int force, /* Evaluating a specific entry, make sure it exists. */ nrn = route_node_lookup(rnh_table, p); if (nrn && nrn->info) - zebra_rnh_evaluate_entry(zvrf, family, force, type, - nrn); + zebra_rnh_evaluate_entry(zvrf, afi, force, type, nrn); if (nrn) route_unlock_node(nrn); @@ -775,27 +754,26 @@ void zebra_evaluate_rnh(struct zebra_vrf *zvrf, int family, int force, nrn = route_top(rnh_table); while (nrn) { if (nrn->info) - zebra_rnh_evaluate_entry(zvrf, family, force, - type, nrn); + zebra_rnh_evaluate_entry(zvrf, afi, force, type, + nrn); nrn = route_next(nrn); /* this will also unlock nrn */ } nrn = route_top(rnh_table); while (nrn) { if (nrn->info) - zebra_rnh_clear_nhc_flag(zvrf, family, type, - nrn); + zebra_rnh_clear_nhc_flag(zvrf, afi, type, nrn); nrn = route_next(nrn); /* this will also unlock nrn */ } } } -void zebra_print_rnh_table(vrf_id_t vrfid, int af, struct vty *vty, +void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, rnh_type_t type) { struct route_table *table; struct route_node *rn; - table = get_rnh_table(vrfid, af, type); + table = get_rnh_table(vrfid, afi, type); if (!table) { zlog_debug("print_rnhs: rnh table not found\n"); return; @@ -839,6 +817,7 @@ static void copy_state(struct rnh *rnh, struct route_entry *re, state->distance = re->distance; state->metric = re->metric; state->vrf_id = re->vrf_id; + state->status = re->status; route_entry_copy_nexthops(state, re->ng.nexthop); rnh->state = state; @@ -914,7 +893,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, nump = stream_get_endp(s); stream_putc(s, 0); for (ALL_NEXTHOPS(re->ng, nh)) - if (rnh_nexthop_valid(nh)) { + if (rnh_nexthop_valid(re, nh)) { stream_putl(s, nh->vrf_id); stream_putc(s, nh->type); switch (nh->type) { @@ -1032,7 +1011,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty) vty_out(vty, "\n"); } -static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, int family, +static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, struct zserv *client, rnh_type_t type) { struct route_table *ntable; @@ -1040,11 +1019,11 @@ static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, int family, struct rnh *rnh; if (IS_ZEBRA_DEBUG_NHT) - zlog_debug("%u: Client %s RNH cleanup for family %d type %d", - vrf_id, zebra_route_string(client->proto), family, - type); + zlog_debug("%u: Client %s RNH cleanup for family %s type %d", + vrf_id, zebra_route_string(client->proto), + afi2str(afi), type); - ntable = get_rnh_table(vrf_id, family, type); + ntable = get_rnh_table(vrf_id, afi, type); if (!ntable) { zlog_debug("cleanup_rnh_client: rnh table not found\n"); return -1; @@ -1069,14 +1048,14 @@ static int zebra_client_cleanup_rnh(struct zserv *client) RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { zvrf = vrf->info; if (zvrf) { - zebra_cleanup_rnh_client(zvrf_id(zvrf), AF_INET, client, + zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP, client, + RNH_NEXTHOP_TYPE); + zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP6, client, RNH_NEXTHOP_TYPE); - zebra_cleanup_rnh_client(zvrf_id(zvrf), AF_INET6, - client, RNH_NEXTHOP_TYPE); - zebra_cleanup_rnh_client(zvrf_id(zvrf), AF_INET, client, + zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP, client, + RNH_IMPORT_CHECK_TYPE); + zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP6, client, RNH_IMPORT_CHECK_TYPE); - zebra_cleanup_rnh_client(zvrf_id(zvrf), AF_INET6, - client, RNH_IMPORT_CHECK_TYPE); if (client->proto == ZEBRA_ROUTE_LDP) { hash_iterate(zvrf->lsp_table, mpls_ldp_lsp_uninstall_all, diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index ed1fe9b75..00ee60dc1 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -78,9 +78,9 @@ extern void zebra_register_rnh_pseudowire(vrf_id_t, struct zebra_pw *); extern void zebra_deregister_rnh_pseudowire(vrf_id_t, struct zebra_pw *); extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, rnh_type_t type); -extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, int family, int force, +extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force, rnh_type_t type, struct prefix *p); -extern void zebra_print_rnh_table(vrf_id_t vrfid, int family, struct vty *vty, +extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, rnh_type_t); extern char *rnh_str(struct rnh *rnh, char *buf, int size); #endif /*_ZEBRA_RNH_H */ diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index c9918a788..7d72583dd 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -33,7 +33,7 @@ #include "vrf.h" #include "frrstr.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/zebra_rnh.h" @@ -327,10 +327,11 @@ static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, XFREE(MTYPE_ROUTE_MAP_NAME, PROTO_RM_NAME(zvrf, afi, rtype)); } - + route_map_counter_decrement(PROTO_RM_MAP(zvrf, afi, rtype)); PROTO_RM_NAME(zvrf, afi, rtype) = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); PROTO_RM_MAP(zvrf, afi, rtype) = route_map_lookup_by_name(PROTO_RM_NAME(zvrf, afi, rtype)); + route_map_counter_increment(PROTO_RM_MAP(zvrf, afi, rtype)); if (PROTO_RM_MAP(zvrf, afi, rtype)) { @@ -356,6 +357,8 @@ static int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap, return CMD_SUCCESS; if (!rmap || strcmp(rmap, PROTO_RM_NAME(zvrf, afi, rtype)) == 0) { + + route_map_counter_decrement(PROTO_RM_MAP(zvrf, afi, rtype)); if (PROTO_RM_MAP(zvrf, afi, rtype)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( @@ -383,13 +386,14 @@ static int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, XFREE(MTYPE_ROUTE_MAP_NAME, NHT_RM_NAME(zvrf, afi, rtype)); } - + route_map_counter_decrement(NHT_RM_MAP(zvrf, afi, rtype)); NHT_RM_NAME(zvrf, afi, rtype) = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); NHT_RM_MAP(zvrf, afi, rtype) = route_map_lookup_by_name(NHT_RM_NAME(zvrf, afi, rtype)); + route_map_counter_increment(NHT_RM_MAP(zvrf, afi, rtype)); if (NHT_RM_MAP(zvrf, afi, rtype)) - zebra_evaluate_rnh(zvrf, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -402,6 +406,7 @@ static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, return CMD_SUCCESS; if (!rmap || strcmp(rmap, NHT_RM_NAME(zvrf, afi, rtype)) == 0) { + route_map_counter_decrement(NHT_RM_MAP(zvrf, afi, rtype)); if (NHT_RM_MAP(zvrf, afi, rtype)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( @@ -409,7 +414,7 @@ static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, zvrf->vrf->vrf_id, rtype); NHT_RM_MAP(zvrf, afi, rtype) = NULL; - zebra_evaluate_rnh(zvrf, AF_INET, 1, RNH_NEXTHOP_TYPE, + zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL); } XFREE(MTYPE_ROUTE_MAP_NAME, NHT_RM_NAME(zvrf, afi, rtype)); @@ -1459,6 +1464,7 @@ static void zebra_rib_table_rm_update(const char *rmap) char *rmap_name; char afi_ip = 0; char afi_ipv6 = 0; + struct route_map *old = NULL; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { zvrf = vrf->info; @@ -1473,8 +1479,19 @@ static void zebra_rib_table_rm_update(const char *rmap) __func__, rmap, zebra_route_string(i)); + old = PROTO_RM_MAP(zvrf, AFI_IP, i); + PROTO_RM_MAP(zvrf, AFI_IP, i) = route_map_lookup_by_name(rmap_name); + /* old is NULL. i.e Route map creation event. + * So update applied_counter. + * If Old is not NULL, i.e It may be routemap + * updation or deletion. + * So no need to update the counter. + */ + if (!old) + route_map_counter_increment( + PROTO_RM_MAP(zvrf, AFI_IP, i)); /* There is single rib table for all protocols */ if (afi_ip == 0) { @@ -1497,8 +1514,13 @@ static void zebra_rib_table_rm_update(const char *rmap) __func__, rmap, zebra_route_string(i)); + old = PROTO_RM_MAP(zvrf, AFI_IP6, i); + PROTO_RM_MAP(zvrf, AFI_IP6, i) = route_map_lookup_by_name(rmap_name); + if (!old) + route_map_counter_increment( + PROTO_RM_MAP(zvrf, AFI_IP6, i)); /* There is single rib table for all protocols */ if (afi_ipv6 == 0) { @@ -1530,6 +1552,7 @@ static void zebra_nht_rm_update(const char *rmap) char *rmap_name; char afi_ip = 0; char afi_ipv6 = 0; + struct route_map *old = NULL; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { zvrf = vrf->info; @@ -1544,8 +1567,13 @@ static void zebra_nht_rm_update(const char *rmap) __func__, rmap, zebra_route_string(i)); + old = NHT_RM_MAP(zvrf, AFI_IP, i); + NHT_RM_MAP(zvrf, AFI_IP, i) = route_map_lookup_by_name(rmap_name); + if (!old) + route_map_counter_increment( + NHT_RM_MAP(zvrf, AFI_IP, i)); /* There is single rib table for all protocols */ if (afi_ip == 0) { @@ -1556,7 +1584,7 @@ static void zebra_nht_rm_update(const char *rmap) afi_ip = 1; zebra_evaluate_rnh( - zvrf, AF_INET, 1, + zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL); } } @@ -1570,8 +1598,13 @@ static void zebra_nht_rm_update(const char *rmap) __func__, rmap, zebra_route_string(i)); + old = NHT_RM_MAP(zvrf, AFI_IP6, i); + NHT_RM_MAP(zvrf, AFI_IP6, i) = route_map_lookup_by_name(rmap_name); + if (!old) + route_map_counter_increment( + NHT_RM_MAP(zvrf, AFI_IP6, i)); /* There is single rib table for all protocols */ if (afi_ipv6 == 0) { @@ -1582,7 +1615,7 @@ static void zebra_nht_rm_update(const char *rmap) afi_ipv6 = 1; zebra_evaluate_rnh( - zvrf, AF_INET, 1, + zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL); } } @@ -1713,7 +1746,7 @@ zebra_import_table_route_map_check(int family, int re_type, uint8_t instance, return (ret); } -route_map_result_t zebra_nht_route_map_check(int family, int client_proto, +route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto, const struct prefix *p, struct zebra_vrf *zvrf, struct route_entry *re, @@ -1731,9 +1764,9 @@ route_map_result_t zebra_nht_route_map_check(int family, int client_proto, nh_obj.tag = re->tag; if (client_proto >= 0 && client_proto < ZEBRA_ROUTE_MAX) - rmap = NHT_RM_MAP(zvrf, family, client_proto); - if (!rmap && NHT_RM_MAP(zvrf, family, ZEBRA_ROUTE_MAX)) - rmap = NHT_RM_MAP(zvrf, family, ZEBRA_ROUTE_MAX); + rmap = NHT_RM_MAP(zvrf, afi, client_proto); + if (!rmap && NHT_RM_MAP(zvrf, afi, ZEBRA_ROUTE_MAX)) + rmap = NHT_RM_MAP(zvrf, afi, ZEBRA_ROUTE_MAX); if (rmap) ret = route_map_apply(rmap, p, RMAP_ZEBRA, &nh_obj); @@ -1745,7 +1778,7 @@ static void zebra_route_map_mark_update(const char *rmap_name) /* rmap_update_timer of 0 means don't do route updates */ if (zebra_rmap_update_timer && !zebra_t_rmap_update) { zebra_t_rmap_update = NULL; - thread_add_timer(zebrad.master, zebra_route_map_update_timer, + thread_add_timer(zrouter.master, zebra_route_map_update_timer, NULL, zebra_rmap_update_timer, &zebra_t_rmap_update); } @@ -1831,7 +1864,7 @@ void zebra_routemap_config_write_protocol(struct vty *vty, zebra_rmap_update_timer); } -void zebra_route_map_init() +void zebra_route_map_init(void) { install_element(CONFIG_NODE, &ip_protocol_cmd); install_element(CONFIG_NODE, &no_ip_protocol_cmd); diff --git a/zebra/zebra_routemap.h b/zebra/zebra_routemap.h index a8579e7c6..abd2ad78f 100644 --- a/zebra/zebra_routemap.h +++ b/zebra/zebra_routemap.h @@ -44,7 +44,7 @@ zebra_route_map_check(int family, int rib_type, uint8_t instance, const struct prefix *p, struct nexthop *nexthop, struct zebra_vrf *zvrf, route_tag_t tag); extern route_map_result_t -zebra_nht_route_map_check(int family, int client_proto, const struct prefix *p, +zebra_nht_route_map_check(afi_t afi, int client_proto, const struct prefix *p, struct zebra_vrf *zvrf, struct route_entry *, struct nexthop *nexthop); diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index f0cc8d4fd..c3b861c24 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -21,6 +21,9 @@ */ #include "zebra.h" +#include <pthread.h> +#include "lib/frratomic.h" + #include "zebra_router.h" #include "zebra_memory.h" #include "zebra_pbr.h" @@ -169,6 +172,13 @@ static void zebra_router_free_table(struct zebra_router_table *zrt) XFREE(MTYPE_ZEBRA_NS, zrt); } +uint32_t zebra_router_get_next_sequence(void) +{ + return 1 + + atomic_fetch_add_explicit(&zrouter.sequence_num, 1, + memory_order_relaxed); +} + void zebra_router_terminate(void) { struct zebra_router_table *zrt, *tmp; @@ -178,6 +188,9 @@ void zebra_router_terminate(void) zebra_router_free_table(zrt); } + work_queue_free_and_null(&zrouter.ribq); + meta_queue_free(zrouter.mq); + zebra_vxlan_disable(); zebra_mlag_terminate(); @@ -194,6 +207,11 @@ void zebra_router_terminate(void) void zebra_router_init(void) { + zrouter.sequence_num = 0; + + zrouter.rtm_table_default = 0; + zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS; + zebra_vxlan_init(); zebra_mlag_init(); diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 1e0788d1b..fb2849591 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -22,6 +22,8 @@ #ifndef __ZEBRA_ROUTER_H__ #define __ZEBRA_ROUTER_H__ +#include "lib/mlag.h" + #include "zebra/zebra_ns.h" /* @@ -44,7 +46,24 @@ RB_HEAD(zebra_router_table_head, zebra_router_table); RB_PROTOTYPE(zebra_router_table_head, zebra_router_table, zebra_router_table_entry, zebra_router_table_entry_compare) +struct zebra_mlag_info { + /* Role this zebra router is playing */ + enum mlag_role role; + + /* The peerlink being used for mlag */ + char *peerlink; + ifindex_t peerlink_ifindex; + + /* The system mac being used */ + struct ethaddr mac; +}; + struct zebra_router { + /* Thread master */ + struct thread_master *master; + + /* Lists of clients who have connected to us */ + struct list *client_list; struct zebra_router_table_head tables; @@ -62,6 +81,29 @@ struct zebra_router { #if defined(HAVE_RTADV) struct rtadv rtadv; #endif /* HAVE_RTADV */ + + /* A sequence number used for tracking routes */ + _Atomic uint32_t sequence_num; + + /* The default table used for this router */ + uint32_t rtm_table_default; + + /* rib work queue */ +#define ZEBRA_RIB_PROCESS_HOLD_TIME 10 +#define ZEBRA_RIB_PROCESS_RETRY_TIME 1 + struct work_queue *ribq; + + /* Meta Queue Information */ + struct meta_queue *mq; + + /* LSP work queue */ + struct work_queue *lsp_process_q; + +#define ZEBRA_ZAPI_PACKETS_TO_PROCESS 1000 + _Atomic uint32_t packets_to_process; + + /* Mlag information for the router */ + struct zebra_mlag_info mlag_info; }; extern struct zebra_router zrouter; @@ -83,4 +125,6 @@ extern unsigned long zebra_router_score_proto(uint8_t proto, extern void zebra_router_sweep_route(void); extern void zebra_router_show_table_summary(struct vty *vty); + +extern uint32_t zebra_router_get_next_sequence(void); #endif diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index f1458cb13..d18305495 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -42,8 +42,6 @@ #include "zebra/zebra_netns_notify.h" #include "zebra/zebra_routemap.h" -extern struct zebra_t zebrad; - static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, safi_t safi); static void zebra_rnhtable_node_cleanup(struct route_table *table, @@ -58,7 +56,7 @@ static void zebra_vrf_add_update(struct zebra_vrf *zvrf) if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("MESSAGE: ZEBRA_VRF_ADD %s", zvrf_name(zvrf)); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) zsend_vrf_add(client, zvrf); } @@ -70,7 +68,7 @@ static void zebra_vrf_delete_update(struct zebra_vrf *zvrf) if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("MESSAGE: ZEBRA_VRF_DELETE %s", zvrf_name(zvrf)); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) zsend_vrf_delete(client, zvrf); } @@ -189,13 +187,13 @@ static int zebra_vrf_disable(struct vrf *vrf) struct route_node *rnode; rib_dest_t *dest; - for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, + for (ALL_LIST_ELEMENTS(zrouter.mq->subq[i], lnode, nnode, rnode)) { dest = rib_dest_from_rnode(rnode); if (dest && rib_dest_vrf(dest) == zvrf) { route_unlock_node(rnode); - list_delete_node(zebrad.mq->subq[i], lnode); - zebrad.mq->size--; + list_delete_node(zrouter.mq->subq[i], lnode); + zrouter.mq->size--; } } } @@ -241,13 +239,13 @@ static int zebra_vrf_delete(struct vrf *vrf) struct route_node *rnode; rib_dest_t *dest; - for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, + for (ALL_LIST_ELEMENTS(zrouter.mq->subq[i], lnode, nnode, rnode)) { dest = rib_dest_from_rnode(rnode); if (dest && rib_dest_vrf(dest) == zvrf) { route_unlock_node(rnode); - list_delete_node(zebrad.mq->subq[i], lnode); - zebrad.mq->size--; + list_delete_node(zrouter.mq->subq[i], lnode); + zrouter.mq->size--; } } } @@ -326,14 +324,14 @@ struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi, if (vrf_id == VRF_DEFAULT) { if (table_id == RT_TABLE_MAIN - || table_id == zebrad.rtm_table_default) + || table_id == zrouter.rtm_table_default) table = zebra_vrf_table(afi, safi, vrf_id); else table = zebra_vrf_other_route_table(afi, table_id, vrf_id); } else if (vrf_is_backend_netns()) { if (table_id == RT_TABLE_MAIN - || table_id == zebrad.rtm_table_default) + || table_id == zrouter.rtm_table_default) table = zebra_vrf_table(afi, safi, vrf_id); else table = zebra_vrf_other_route_table(afi, table_id, @@ -439,9 +437,9 @@ struct route_table *zebra_vrf_other_route_table(afi_t afi, uint32_t table_id, return NULL; if ((table_id != RT_TABLE_MAIN) - && (table_id != zebrad.rtm_table_default)) { + && (table_id != zrouter.rtm_table_default)) { if (zvrf->table_id == RT_TABLE_MAIN || - zvrf->table_id == zebrad.rtm_table_default) { + zvrf->table_id == zrouter.rtm_table_default) { /* this VRF use default table * so in all cases, it does not use specific table * so it is possible to configure tables in this VRF diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index c28025403..e35101d83 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -122,6 +122,8 @@ struct zebra_vrf { */ int advertise_gw_macip; + int advertise_svi_macip; + /* l3-vni info */ vni_t l3vni; @@ -137,12 +139,14 @@ struct zebra_vrf { */ enum vxlan_flood_control vxlan_flood_ctrl; - /* Route Installs */ + /* Install stats */ uint64_t installs; uint64_t removals; uint64_t installs_queued; uint64_t removals_queued; uint64_t neigh_updates; + uint64_t lsp_installs_queued; + uint64_t lsp_removals_queued; uint64_t lsp_installs; uint64_t lsp_removals; }; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index b18f0e943..537820f7e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -161,6 +161,29 @@ DEFUN (show_ip_rpf_addr, return CMD_SUCCESS; } +static char re_status_output_char(struct route_entry *re, struct nexthop *nhop) +{ + if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) { + if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) && + !CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) + return '*'; + else + return ' '; + } + + if (CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED)) { + if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)) + return 'q'; + + return 'r'; + } + + if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)) + return 'q'; + + return ' '; +} + /* New RIB. Detailed information for IPv4 route. */ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, int mcast) @@ -229,12 +252,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, char addrstr[32]; vty_out(vty, " %c%s", - CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB) - ? CHECK_FLAG(nexthop->flags, - NEXTHOP_FLAG_DUPLICATE) - ? ' ' - : '*' - : ' ', + re_status_output_char(re, nexthop), nexthop->rparent ? " " : ""); switch (nexthop->type) { @@ -389,6 +407,19 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) json_object_boolean_true_add(json_route, "selected"); + json_object_int_add(json_route, "distance", + re->distance); + json_object_int_add(json_route, "metric", re->metric); + + if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) + json_object_boolean_true_add(json_route, "installed"); + + if (CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED)) + json_object_boolean_true_add(json_route, "failed"); + + if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)) + json_object_boolean_true_add(json_route, "queued"); + if (re->type != ZEBRA_ROUTE_CONNECT) { json_object_int_add(json_route, "distance", re->distance); @@ -596,23 +627,18 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ', - CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB) - ? '*' - : ' ', + re_status_output_char(re, nexthop), srcdest_rnode2str(rn, buf, sizeof buf)); /* Distance and metric display. */ - if (re->type != ZEBRA_ROUTE_CONNECT) + if (((re->type == ZEBRA_ROUTE_CONNECT) && + (re->distance || re->metric)) || + (re->type != ZEBRA_ROUTE_CONNECT)) len += vty_out(vty, " [%u/%u]", re->distance, re->metric); } else { vty_out(vty, " %c%*c", - CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB) - ? CHECK_FLAG(nexthop->flags, - NEXTHOP_FLAG_DUPLICATE) - ? ' ' - : '*' - : ' ', + re_status_output_char(re, nexthop), len - 3 + (2 * nexthop_level(nexthop)), ' '); } @@ -930,21 +956,35 @@ DEFPY (show_route_table_vrf, return CMD_SUCCESS; } -DEFUN (show_ip_nht, +DEFPY (show_ip_nht, show_ip_nht_cmd, - "show ip nht [vrf NAME]", + "show <ip$ipv4|ipv6$ipv6> nht [vrf NAME$vrf_name|vrf all$vrf_all]", SHOW_STR IP_STR + IP6_STR "IP nexthop tracking table\n" - VRF_CMD_HELP_STR) + VRF_CMD_HELP_STR + VRF_ALL_CMD_HELP_STR) { - int idx_vrf = 4; + afi_t afi = ipv4 ? AFI_IP : AFI_IP6; vrf_id_t vrf_id = VRF_DEFAULT; - if (argc == 5) - VRF_GET_ID(vrf_id, argv[idx_vrf]->arg, false); + if (vrf_all) { + struct vrf *vrf; + struct zebra_vrf *zvrf; - zebra_print_rnh_table(vrf_id, AF_INET, vty, RNH_NEXTHOP_TYPE); + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) + if ((zvrf = vrf->info) != NULL) { + vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf)); + zebra_print_rnh_table(zvrf_id(zvrf), afi, vty, + RNH_NEXTHOP_TYPE); + } + return CMD_SUCCESS; + } + if (vrf_name) + VRF_GET_ID(vrf_id, vrf_name, false); + + zebra_print_rnh_table(vrf_id, afi, vty, RNH_NEXTHOP_TYPE); return CMD_SUCCESS; } @@ -969,9 +1009,8 @@ DEFPY (show_ip_import_check, if ((zvrf = vrf->info) != NULL) { vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf)); - zebra_print_rnh_table(zvrf_id(zvrf), - afi, vty, - RNH_NEXTHOP_TYPE); + zebra_print_rnh_table(zvrf_id(zvrf), afi, vty, + RNH_IMPORT_CHECK_TYPE); } return CMD_SUCCESS; } @@ -982,67 +1021,6 @@ DEFPY (show_ip_import_check, return CMD_SUCCESS; } -DEFUN (show_ip_nht_vrf_all, - show_ip_nht_vrf_all_cmd, - "show ip nht vrf all", - SHOW_STR - IP_STR - "IP nexthop tracking table\n" - VRF_ALL_CMD_HELP_STR) -{ - struct vrf *vrf; - struct zebra_vrf *zvrf; - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) - if ((zvrf = vrf->info) != NULL) { - vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf)); - zebra_print_rnh_table(zvrf_id(zvrf), AF_INET, vty, - RNH_NEXTHOP_TYPE); - } - - return CMD_SUCCESS; -} - -DEFUN (show_ipv6_nht, - show_ipv6_nht_cmd, - "show ipv6 nht [vrf NAME]", - SHOW_STR - IPV6_STR - "IPv6 nexthop tracking table\n" - VRF_CMD_HELP_STR) -{ - int idx_vrf = 4; - vrf_id_t vrf_id = VRF_DEFAULT; - - if (argc == 5) - VRF_GET_ID(vrf_id, argv[idx_vrf]->arg, false); - - zebra_print_rnh_table(vrf_id, AF_INET6, vty, RNH_NEXTHOP_TYPE); - return CMD_SUCCESS; -} - - -DEFUN (show_ipv6_nht_vrf_all, - show_ipv6_nht_vrf_all_cmd, - "show ipv6 nht vrf all", - SHOW_STR - IP_STR - "IPv6 nexthop tracking table\n" - VRF_ALL_CMD_HELP_STR) -{ - struct vrf *vrf; - struct zebra_vrf *zvrf; - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) - if ((zvrf = vrf->info) != NULL) { - vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf)); - zebra_print_rnh_table(zvrf_id(zvrf), AF_INET6, vty, - RNH_NEXTHOP_TYPE); - } - - return CMD_SUCCESS; -} - DEFUN (ip_nht_default_route, ip_nht_default_route_cmd, "ip nht resolve-via-default", @@ -1060,7 +1038,7 @@ DEFUN (ip_nht_default_route, zebra_rnh_ip_default_route = 1; - zebra_evaluate_rnh(zvrf, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1081,7 +1059,7 @@ DEFUN (no_ip_nht_default_route, return CMD_SUCCESS; zebra_rnh_ip_default_route = 0; - zebra_evaluate_rnh(zvrf, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1101,7 +1079,7 @@ DEFUN (ipv6_nht_default_route, return CMD_SUCCESS; zebra_rnh_ipv6_default_route = 1; - zebra_evaluate_rnh(zvrf, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf, AFI_IP6, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1123,7 +1101,7 @@ DEFUN (no_ipv6_nht_default_route, return CMD_SUCCESS; zebra_rnh_ipv6_default_route = 0; - zebra_evaluate_rnh(zvrf, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf, AFI_IP6, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1457,21 +1435,20 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, * In case of ECMP, count only once. */ cnt = 0; + if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) { + fib_cnt[ZEBRA_ROUTE_TOTAL]++; + fib_cnt[re->type]++; + } for (nexthop = re->ng.nexthop; (!cnt && nexthop); nexthop = nexthop->next) { cnt++; rib_cnt[ZEBRA_ROUTE_TOTAL]++; rib_cnt[re->type]++; - if (CHECK_FLAG(nexthop->flags, - NEXTHOP_FLAG_FIB)) { - fib_cnt[ZEBRA_ROUTE_TOTAL]++; - fib_cnt[re->type]++; - } if (re->type == ZEBRA_ROUTE_BGP && CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP)) { rib_cnt[ZEBRA_ROUTE_IBGP]++; - if (CHECK_FLAG(nexthop->flags, - NEXTHOP_FLAG_FIB)) + if (CHECK_FLAG(re->status, + ROUTE_ENTRY_INSTALLED)) fib_cnt[ZEBRA_ROUTE_IBGP]++; } } @@ -2480,7 +2457,7 @@ DEFUN_HIDDEN (zebra_packet_process, { uint32_t packets = strtoul(argv[2]->arg, NULL, 10); - atomic_store_explicit(&zebrad.packets_to_process, packets, + atomic_store_explicit(&zrouter.packets_to_process, packets, memory_order_relaxed); return CMD_SUCCESS; @@ -2494,7 +2471,7 @@ DEFUN_HIDDEN (no_zebra_packet_process, "Zapi Protocol\n" "Number of packets to process before relinquishing thread\n") { - atomic_store_explicit(&zebrad.packets_to_process, + atomic_store_explicit(&zrouter.packets_to_process, ZEBRA_ZAPI_PACKETS_TO_PROCESS, memory_order_relaxed); @@ -2509,7 +2486,7 @@ DEFUN_HIDDEN (zebra_workqueue_timer, "Time in milliseconds\n") { uint32_t timer = strtoul(argv[2]->arg, NULL, 10); - zebrad.ribq->spec.hold = timer; + zrouter.ribq->spec.hold = timer; return CMD_SUCCESS; } @@ -2522,7 +2499,7 @@ DEFUN_HIDDEN (no_zebra_workqueue_timer, "Work Queue\n" "Time in milliseconds\n") { - zebrad.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME; + zrouter.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME; return CMD_SUCCESS; } @@ -2572,12 +2549,12 @@ static int config_write_protocol(struct vty *vty) if (zebra_rnh_ipv6_default_route) vty_out(vty, "ipv6 nht resolve-via-default\n"); - if (zebrad.ribq->spec.hold != ZEBRA_RIB_PROCESS_HOLD_TIME) - vty_out(vty, "zebra work-queue %u\n", zebrad.ribq->spec.hold); + if (zrouter.ribq->spec.hold != ZEBRA_RIB_PROCESS_HOLD_TIME) + vty_out(vty, "zebra work-queue %u\n", zrouter.ribq->spec.hold); - if (zebrad.packets_to_process != ZEBRA_ZAPI_PACKETS_TO_PROCESS) + if (zrouter.packets_to_process != ZEBRA_ZAPI_PACKETS_TO_PROCESS) vty_out(vty, "zebra zapi-packets %u\n", - zebrad.packets_to_process); + zrouter.packets_to_process); enum multicast_mode ipv4_multicast_mode = multicast_mode_ipv4_get(); @@ -2605,7 +2582,7 @@ DEFUN (show_table, SHOW_STR "default routing table to use for all clients\n") { - vty_out(vty, "table %d\n", zebrad.rtm_table_default); + vty_out(vty, "table %d\n", zrouter.rtm_table_default); return CMD_SUCCESS; } @@ -2615,7 +2592,7 @@ DEFUN (config_table, "Configure target kernel routing table\n" "TABLE integer\n") { - zebrad.rtm_table_default = strtol(argv[1]->arg, (char **)0, 10); + zrouter.rtm_table_default = strtol(argv[1]->arg, (char **)0, 10); return CMD_SUCCESS; } @@ -2626,7 +2603,7 @@ DEFUN (no_config_table, "Configure target kernel routing table\n" "TABLE integer\n") { - zebrad.rtm_table_default = 0; + zrouter.rtm_table_default = 0; return CMD_SUCCESS; } #endif @@ -2874,8 +2851,8 @@ DEFUN (zebra_show_routing_tables_summary, /* Table configuration write function. */ static int config_write_table(struct vty *vty) { - if (zebrad.rtm_table_default) - vty_out(vty, "table %d\n", zebrad.rtm_table_default); + if (zrouter.rtm_table_default) + vty_out(vty, "table %d\n", zrouter.rtm_table_default); return 0; } @@ -2955,9 +2932,6 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_route_summary_cmd); install_element(VIEW_NODE, &show_ip_nht_cmd); install_element(VIEW_NODE, &show_ip_import_check_cmd); - install_element(VIEW_NODE, &show_ip_nht_vrf_all_cmd); - install_element(VIEW_NODE, &show_ipv6_nht_cmd); - install_element(VIEW_NODE, &show_ipv6_nht_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_rpf_cmd); install_element(VIEW_NODE, &show_ip_rpf_addr_cmd); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 86a781278..4cd70381c 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -50,7 +50,7 @@ #include "zebra/zebra_vrf.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_vxlan_private.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix"); DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash"); @@ -65,23 +65,23 @@ DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor"); static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, uint16_t cmd); static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json); -static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt); -static void zvni_print_dad_neigh_hash(struct hash_backet *backet, void *ctxt); -static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, +static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt); +static void zvni_print_dad_neigh_hash(struct hash_bucket *bucket, void *ctxt); +static void zvni_print_neigh_hash_all_vni(struct hash_bucket *bucket, void **args); static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty, json_object *json); static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty, json_object *json); static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json); -static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt); -static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt); +static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt); +static void zvni_print_mac_hash_all_vni(struct hash_bucket *bucket, void *ctxt); static void zvni_print(zebra_vni_t *zvni, void **ctxt); -static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]); +static void zvni_print_hash(struct hash_bucket *bucket, void *ctxt[]); static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr, struct ipaddr *ip, uint8_t flags, - uint32_t seq, uint16_t cmd); + uint32_t seq, int state, uint16_t cmd); static unsigned int neigh_hash_keymake(void *p); static void *zvni_neigh_alloc(void *p); static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip, @@ -97,9 +97,10 @@ static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip, uint8_t flags, uint32_t seq); static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip, struct ethaddr *macaddr, - uint8_t flags); + uint8_t flags, int state); static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n); static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n); +static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n); static zebra_vni_t *zvni_from_svi(struct interface *ifp, struct interface *br_if); static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if); @@ -116,7 +117,7 @@ static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); /* l3-vni rmac related APIs */ -static void zl3vni_print_rmac_hash(struct hash_backet *, void *); +static void zl3vni_print_rmac_hash(struct hash_bucket *, void *); static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni, struct ethaddr *rmac); static void *zl3vni_rmac_alloc(void *p); @@ -154,7 +155,7 @@ static zebra_vni_t *zvni_map_vlan(struct interface *ifp, struct interface *br_if, vlanid_t vid); static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac); static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac); -static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt); +static void zvni_install_mac_hash(struct hash_bucket *bucket, void *ctxt); static unsigned int vni_hash_keymake(void *p); static void *zvni_alloc(void *p); @@ -163,7 +164,7 @@ static zebra_vni_t *zvni_add(vni_t vni); static int zvni_del(zebra_vni_t *zvni); static int zvni_send_add_to_client(zebra_vni_t *zvni); static int zvni_send_del_to_client(vni_t vni); -static void zvni_build_hash_table(); +static void zvni_build_hash_table(void); static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep); static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip); static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip); @@ -179,6 +180,7 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, struct ipaddr *ip); struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp); static int advertise_gw_macip_enabled(zebra_vni_t *zvni); +static int advertise_svi_macip_enabled(zebra_vni_t *zvni); static int zebra_vxlan_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf, zebra_mac_t *old_zmac, zebra_mac_t *new_zmac, @@ -255,7 +257,7 @@ static uint32_t num_valid_macs(zebra_vni_t *zvni) unsigned int i; uint32_t num_macs = 0; struct hash *hash; - struct hash_backet *hb; + struct hash_bucket *hb; zebra_mac_t *mac; hash = zvni->mac_table; @@ -279,7 +281,7 @@ static uint32_t num_dup_detected_macs(zebra_vni_t *zvni) unsigned int i; uint32_t num_macs = 0; struct hash *hash; - struct hash_backet *hb; + struct hash_bucket *hb; zebra_mac_t *mac; hash = zvni->mac_table; @@ -301,7 +303,7 @@ static uint32_t num_dup_detected_neighs(zebra_vni_t *zvni) unsigned int i; uint32_t num_neighs = 0; struct hash *hash; - struct hash_backet *hb; + struct hash_bucket *hb; zebra_neigh_t *nbr; hash = zvni->neigh_table; @@ -332,6 +334,20 @@ static int advertise_gw_macip_enabled(zebra_vni_t *zvni) return 0; } +static int advertise_svi_macip_enabled(zebra_vni_t *zvni) +{ + struct zebra_vrf *zvrf; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (zvrf && zvrf->advertise_svi_macip) + return 1; + + if (zvni && zvni->advertise_svi_macip) + return 1; + + return 0; +} + /* As part Duplicate Address Detection (DAD) for IP mobility * MAC binding changes, ensure to inherit duplicate flag * from MAC. @@ -510,7 +526,7 @@ static void zebra_vxlan_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, sizeof(buf)), mac->flags, zvrf->dad_freeze_time); - thread_add_timer(zebrad.master, + thread_add_timer(zrouter.master, zebra_vxlan_dad_mac_auto_recovery_exp, mac, zvrf->dad_freeze_time, &mac->dad_mac_auto_recovery_timer); @@ -556,6 +572,7 @@ static void zebra_vxlan_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, if (zvrf->dad_freeze) *is_dup_detect = true; + /* warn-only action, neigh will be installed. * freeze action, it wil not be installed. */ @@ -642,7 +659,7 @@ static void zebra_vxlan_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, ipaddr2str(&nbr->ip, buf1, sizeof(buf1)), nbr->flags, zvrf->dad_freeze_time); - thread_add_timer(zebrad.master, + thread_add_timer(zrouter.master, zebra_vxlan_dad_ip_auto_recovery_exp, nbr, zvrf->dad_freeze_time, &nbr->dad_ip_auto_recovery_timer); @@ -657,14 +674,14 @@ static void zebra_vxlan_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, * display - just because we're dealing with IPv6 addresses that can * widely vary. */ -static void zvni_find_neigh_addr_width(struct hash_backet *backet, void *ctxt) +static void zvni_find_neigh_addr_width(struct hash_bucket *bucket, void *ctxt) { zebra_neigh_t *n; char buf[INET6_ADDRSTRLEN]; struct neigh_walk_ctx *wctx = ctxt; int width; - n = (zebra_neigh_t *)backet->data; + n = (zebra_neigh_t *)bucket->data; ipaddr2str(&n->ip, buf, sizeof(buf)); width = strlen(buf); @@ -750,8 +767,7 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) n->detect_start_time.tv_sec); char tmp_buf[30]; - memset(tmp_buf, 0, 30); - strncpy(tmp_buf, buf, strlen(buf) - 1); + strlcpy(tmp_buf, buf, sizeof(tmp_buf)); vty_out(vty, " Duplicate detection started at %s, detection count %u\n", tmp_buf, n->dad_count); @@ -774,7 +790,7 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) /* * Print neighbor hash entry - called for display of all neighbors. */ -static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt) +static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt) { struct vty *vty; json_object *json_vni = NULL, *json_row = NULL; @@ -786,7 +802,7 @@ static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt) vty = wctx->vty; json_vni = wctx->json; - n = (zebra_neigh_t *)backet->data; + n = (zebra_neigh_t *)bucket->data; if (json_vni) json_row = json_object_new_object(); @@ -870,7 +886,7 @@ static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt) /* * Print neighbor hash entry in detail - called for display of all neighbors. */ -static void zvni_print_neigh_hash_detail(struct hash_backet *backet, void *ctxt) +static void zvni_print_neigh_hash_detail(struct hash_bucket *bucket, void *ctxt) { struct vty *vty; json_object *json_vni = NULL, *json_row = NULL; @@ -880,7 +896,7 @@ static void zvni_print_neigh_hash_detail(struct hash_backet *backet, void *ctxt) vty = wctx->vty; json_vni = wctx->json; - n = (zebra_neigh_t *)backet->data; + n = (zebra_neigh_t *)bucket->data; if (!n) return; @@ -897,7 +913,7 @@ static void zvni_print_neigh_hash_detail(struct hash_backet *backet, void *ctxt) /* * Print neighbors for all VNI. */ -static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, +static void zvni_print_neigh_hash_all_vni(struct hash_bucket *bucket, void **args) { struct vty *vty; @@ -912,7 +928,7 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, json = (json_object *)args[1]; print_dup = (uint32_t)(uintptr_t)args[2]; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; num_neigh = hashcount(zvni->neigh_table); @@ -961,35 +977,35 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, json_object_object_add(json, vni_str, json_vni); } -static void zvni_print_dad_neigh_hash(struct hash_backet *backet, void *ctxt) +static void zvni_print_dad_neigh_hash(struct hash_bucket *bucket, void *ctxt) { zebra_neigh_t *nbr; - nbr = (zebra_neigh_t *)backet->data; + nbr = (zebra_neigh_t *)bucket->data; if (!nbr) return; if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) - zvni_print_neigh_hash(backet, ctxt); + zvni_print_neigh_hash(bucket, ctxt); } -static void zvni_print_dad_neigh_hash_detail(struct hash_backet *backet, +static void zvni_print_dad_neigh_hash_detail(struct hash_bucket *bucket, void *ctxt) { zebra_neigh_t *nbr; - nbr = (zebra_neigh_t *)backet->data; + nbr = (zebra_neigh_t *)bucket->data; if (!nbr) return; if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) - zvni_print_neigh_hash_detail(backet, ctxt); + zvni_print_neigh_hash_detail(bucket, ctxt); } /* * Print neighbors for all VNIs in detail. */ -static void zvni_print_neigh_hash_all_vni_detail(struct hash_backet *backet, +static void zvni_print_neigh_hash_all_vni_detail(struct hash_bucket *bucket, void **args) { struct vty *vty; @@ -1004,7 +1020,7 @@ static void zvni_print_neigh_hash_all_vni_detail(struct hash_backet *backet, json = (json_object *)args[1]; print_dup = (uint32_t)(uintptr_t)args[2]; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; if (!zvni) { if (json) vty_out(vty, "{}\n"); @@ -1131,7 +1147,7 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json) struct vty *vty; zebra_neigh_t *n = NULL; struct listnode *node = NULL; - char buf1[20]; + char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; struct zebra_vrf *zvrf; struct timeval detect_start_time = {0, 0}; @@ -1272,8 +1288,7 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json) mac->detect_start_time.tv_sec); char tmp_buf[30]; - memset(tmp_buf, 0, 30); - strncpy(tmp_buf, buf, strlen(buf) - 1); + strlcpy(tmp_buf, buf, sizeof(tmp_buf)); vty_out(vty, " Duplicate detection started at %s, detection count %u\n", tmp_buf, mac->dad_count); @@ -1301,17 +1316,17 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json) /* * Print MAC hash entry - called for display of all MACs. */ -static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt) +static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt) { struct vty *vty; json_object *json_mac_hdr = NULL, *json_mac = NULL; zebra_mac_t *mac; - char buf1[20]; + char buf1[ETHER_ADDR_STRLEN]; struct mac_walk_ctx *wctx = ctxt; vty = wctx->vty; json_mac_hdr = wctx->json; - mac = (zebra_mac_t *)backet->data; + mac = (zebra_mac_t *)bucket->data; prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1)); @@ -1407,32 +1422,32 @@ static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt) } /* Print Duplicate MAC */ -static void zvni_print_dad_mac_hash(struct hash_backet *backet, void *ctxt) +static void zvni_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt) { zebra_mac_t *mac; - mac = (zebra_mac_t *)backet->data; + mac = (zebra_mac_t *)bucket->data; if (!mac) return; if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) - zvni_print_mac_hash(backet, ctxt); + zvni_print_mac_hash(bucket, ctxt); } /* * Print MAC hash entry in detail - called for display of all MACs. */ -static void zvni_print_mac_hash_detail(struct hash_backet *backet, void *ctxt) +static void zvni_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt) { struct vty *vty; json_object *json_mac_hdr = NULL; zebra_mac_t *mac; struct mac_walk_ctx *wctx = ctxt; - char buf1[20]; + char buf1[ETHER_ADDR_STRLEN]; vty = wctx->vty; json_mac_hdr = wctx->json; - mac = (zebra_mac_t *)backet->data; + mac = (zebra_mac_t *)bucket->data; if (!mac) return; @@ -1443,23 +1458,23 @@ static void zvni_print_mac_hash_detail(struct hash_backet *backet, void *ctxt) } /* Print Duplicate MAC in detail */ -static void zvni_print_dad_mac_hash_detail(struct hash_backet *backet, +static void zvni_print_dad_mac_hash_detail(struct hash_bucket *bucket, void *ctxt) { zebra_mac_t *mac; - mac = (zebra_mac_t *)backet->data; + mac = (zebra_mac_t *)bucket->data; if (!mac) return; if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) - zvni_print_mac_hash_detail(backet, ctxt); + zvni_print_mac_hash_detail(bucket, ctxt); } /* * Print MACs for all VNI. */ -static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt) +static void zvni_print_mac_hash_all_vni(struct hash_bucket *bucket, void *ctxt) { struct vty *vty; json_object *json = NULL, *json_vni = NULL; @@ -1472,7 +1487,7 @@ static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt) vty = (struct vty *)wctx->vty; json = (struct json_object *)wctx->json; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; wctx->zvni = zvni; /*We are iterating over a new VNI, set the count to 0*/ @@ -1529,7 +1544,7 @@ static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt) /* * Print MACs in detail for all VNI. */ -static void zvni_print_mac_hash_all_vni_detail(struct hash_backet *backet, +static void zvni_print_mac_hash_all_vni_detail(struct hash_bucket *bucket, void *ctxt) { struct vty *vty; @@ -1543,7 +1558,7 @@ static void zvni_print_mac_hash_all_vni_detail(struct hash_backet *backet, vty = (struct vty *)wctx->vty; json = (struct json_object *)wctx->json; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; if (!zvni) { if (json) vty_out(vty, "{}\n"); @@ -1592,7 +1607,7 @@ static void zvni_print_mac_hash_all_vni_detail(struct hash_backet *backet, } } -static void zl3vni_print_nh_hash(struct hash_backet *backet, void *ctx) +static void zl3vni_print_nh_hash(struct hash_bucket *bucket, void *ctx) { struct nh_walk_ctx *wctx = NULL; struct vty *vty = NULL; @@ -1607,7 +1622,7 @@ static void zl3vni_print_nh_hash(struct hash_backet *backet, void *ctx) json_vni = wctx->json; if (json_vni) json_nh = json_object_new_object(); - n = (zebra_neigh_t *)backet->data; + n = (zebra_neigh_t *)bucket->data; if (!json_vni) { vty_out(vty, "%-15s %-17s\n", @@ -1625,7 +1640,7 @@ static void zl3vni_print_nh_hash(struct hash_backet *backet, void *ctx) } } -static void zl3vni_print_nh_hash_all_vni(struct hash_backet *backet, +static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket, void **args) { struct vty *vty = NULL; @@ -1639,7 +1654,7 @@ static void zl3vni_print_nh_hash_all_vni(struct hash_backet *backet, vty = (struct vty *)args[0]; json = (struct json_object *)args[1]; - zl3vni = (zebra_l3vni_t *)backet->data; + zl3vni = (zebra_l3vni_t *)bucket->data; num_nh = hashcount(zl3vni->nh_table); if (!num_nh) @@ -1664,7 +1679,7 @@ static void zl3vni_print_nh_hash_all_vni(struct hash_backet *backet, json_object_object_add(json, vni_str, json_vni); } -static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *backet, +static void zl3vni_print_rmac_hash_all_vni(struct hash_bucket *bucket, void **args) { struct vty *vty = NULL; @@ -1678,7 +1693,7 @@ static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *backet, vty = (struct vty *)args[0]; json = (struct json_object *)args[1]; - zl3vni = (zebra_l3vni_t *)backet->data; + zl3vni = (zebra_l3vni_t *)bucket->data; num_rmacs = hashcount(zl3vni->rmac_table); if (!num_rmacs) @@ -1707,7 +1722,7 @@ static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *backet, json_object_object_add(json, vni_str, json_vni); } -static void zl3vni_print_rmac_hash(struct hash_backet *backet, void *ctx) +static void zl3vni_print_rmac_hash(struct hash_bucket *bucket, void *ctx) { zebra_mac_t *zrmac = NULL; struct rmac_walk_ctx *wctx = NULL; @@ -1721,7 +1736,7 @@ static void zl3vni_print_rmac_hash(struct hash_backet *backet, void *ctx) json = wctx->json; if (json) json_rmac = json_object_new_object(); - zrmac = (zebra_mac_t *)backet->data; + zrmac = (zebra_mac_t *)bucket->data; if (!json) { vty_out(vty, "%-17s %-21s\n", @@ -1887,7 +1902,7 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt) } /* print a L3 VNI hash entry */ -static void zl3vni_print_hash(struct hash_backet *backet, void *ctx[]) +static void zl3vni_print_hash(struct hash_bucket *bucket, void *ctx[]) { struct vty *vty = NULL; json_object *json = NULL; @@ -1897,7 +1912,7 @@ static void zl3vni_print_hash(struct hash_backet *backet, void *ctx[]) vty = (struct vty *)ctx[0]; json = (json_object *)ctx[1]; - zl3vni = (zebra_l3vni_t *)backet->data; + zl3vni = (zebra_l3vni_t *)bucket->data; if (!json) { vty_out(vty, "%-10u %-4s %-21s %-8lu %-8lu %-15s %-37s\n", @@ -1933,7 +1948,7 @@ struct zvni_evpn_show { }; /* print a L3 VNI hash entry in detail*/ -static void zl3vni_print_hash_detail(struct hash_backet *backet, void *data) +static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data) { struct vty *vty = NULL; zebra_l3vni_t *zl3vni = NULL; @@ -1947,7 +1962,7 @@ static void zl3vni_print_hash_detail(struct hash_backet *backet, void *data) if (json) use_json = true; - zl3vni = (zebra_l3vni_t *)backet->data; + zl3vni = (zebra_l3vni_t *)bucket->data; zebra_vxlan_print_vni(vty, zes->zvrf, zl3vni->vni, use_json); vty_out(vty, "\n"); @@ -1957,7 +1972,7 @@ static void zl3vni_print_hash_detail(struct hash_backet *backet, void *data) /* * Print a VNI hash entry - called for display of all VNIs. */ -static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) +static void zvni_print_hash(struct hash_bucket *bucket, void *ctxt[]) { struct vty *vty; zebra_vni_t *zvni; @@ -1973,7 +1988,7 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) vty = ctxt[0]; json = ctxt[1]; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; zvtep = zvni->vteps; while (zvtep) { @@ -2021,7 +2036,7 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) /* * Print a VNI hash entry in detail - called for display of all VNIs. */ -static void zvni_print_hash_detail(struct hash_backet *backet, void *data) +static void zvni_print_hash_detail(struct hash_bucket *bucket, void *data) { struct vty *vty; zebra_vni_t *zvni; @@ -2035,7 +2050,7 @@ static void zvni_print_hash_detail(struct hash_backet *backet, void *data) if (json) use_json = true; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; zebra_vxlan_print_vni(vty, zes->zvrf, zvni->vni, use_json); vty_out(vty, "\n"); @@ -2046,7 +2061,7 @@ static void zvni_print_hash_detail(struct hash_backet *backet, void *data) */ static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr, struct ipaddr *ip, uint8_t flags, - uint32_t seq, uint16_t cmd) + uint32_t seq, int state, uint16_t cmd) { char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; @@ -2080,6 +2095,8 @@ static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr, if (cmd == ZEBRA_MACIP_ADD) { stream_putc(s, flags); /* sticky mac/gateway mac */ stream_putl(s, seq); /* sequence number */ + } else { + stream_putl(s, state); /* state - active/inactive */ } @@ -2205,10 +2222,10 @@ static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n) /* * Free neighbor hash entry (callback) */ -static void zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg) +static void zvni_neigh_del_hash_entry(struct hash_bucket *bucket, void *arg) { struct neigh_walk_ctx *wctx = arg; - zebra_neigh_t *n = backet->data; + zebra_neigh_t *n = bucket->data; if (((wctx->flags & DEL_LOCAL_NEIGH) && (n->flags & ZEBRA_NEIGH_LOCAL)) || ((wctx->flags & DEL_REMOTE_NEIGH) @@ -2218,7 +2235,7 @@ static void zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg) && IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) { if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL)) zvni_neigh_send_del_to_client(wctx->zvni->vni, &n->ip, - &n->emac, 0); + &n->emac, 0, n->state); if (wctx->uninstall) zvni_neigh_uninstall(wctx->zvni, n); @@ -2354,7 +2371,7 @@ static void zvni_process_neigh_on_local_mac_del(zebra_vni_t *zvni, ZEBRA_NEIGH_SET_INACTIVE(n); n->loc_seq = 0; zvni_neigh_send_del_to_client(zvni->vni, &n->ip, - &n->emac, 0); + &n->emac, 0, ZEBRA_NEIGH_ACTIVE); } } } @@ -2385,7 +2402,7 @@ static void zvni_process_neigh_on_remote_mac_add(zebra_vni_t *zvni, ZEBRA_NEIGH_SET_INACTIVE(n); n->loc_seq = 0; zvni_neigh_send_del_to_client(zvni->vni, &n->ip, - &n->emac, 0); + &n->emac, 0, ZEBRA_NEIGH_ACTIVE); } } } @@ -2401,6 +2418,18 @@ static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni, /* NOTE: Currently a NO-OP. */ } +static void zvni_probe_neigh_on_mac_add(zebra_vni_t *zvni, zebra_mac_t *zmac) +{ + zebra_neigh_t *nbr = NULL; + struct listnode *node = NULL; + + for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, nbr)) { + if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL) && + IS_ZEBRA_NEIGH_INACTIVE(nbr)) + zvni_neigh_probe(zvni, nbr); + } +} + /* * Inform BGP about local neighbor addition. */ @@ -2418,17 +2447,18 @@ static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip, SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags, - seq, ZEBRA_MACIP_ADD); + seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD); } /* * Inform BGP about local neighbor deletion. */ static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip, - struct ethaddr *macaddr, uint8_t flags) + struct ethaddr *macaddr, uint8_t flags, + int state) { return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags, - 0, ZEBRA_MACIP_DEL); + 0, state, ZEBRA_MACIP_DEL); } /* @@ -2497,14 +2527,40 @@ static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n) } /* + * Probe neighbor from the kernel. + */ +static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n) +{ + struct zebra_if *zif; + struct zebra_l2info_vxlan *vxl; + struct interface *vlan_if; + + zif = zvni->vxlan_if->info; + if (!zif) + return -1; + vxl = &zif->l2info.vxl; + + vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); + if (!vlan_if) + return -1; + +#ifdef GNU_LINUX + return kernel_upd_neigh(vlan_if, &n->ip, &n->emac, + 0, NUD_PROBE); +#else + return 0; +#endif +} + +/* * Install neighbor hash entry - called upon access VLAN change. */ -static void zvni_install_neigh_hash(struct hash_backet *backet, void *ctxt) +static void zvni_install_neigh_hash(struct hash_bucket *bucket, void *ctxt) { zebra_neigh_t *n; struct neigh_walk_ctx *wctx = ctxt; - n = (zebra_neigh_t *)backet->data; + n = (zebra_neigh_t *)bucket->data; if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) zvni_neigh_install(wctx->zvni, n); @@ -2749,7 +2805,7 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, /* Remove neighbor from BGP. */ zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, - ZEBRA_MACIP_TYPE_GW); + ZEBRA_MACIP_TYPE_GW, ZEBRA_NEIGH_ACTIVE); /* Delete this neighbor entry. */ zvni_neigh_del(zvni, n); @@ -2761,7 +2817,7 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, return 0; } -static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet, +static void zvni_gw_macip_del_for_vni_hash(struct hash_bucket *bucket, void *ctxt) { zebra_vni_t *zvni = NULL; @@ -2772,7 +2828,7 @@ static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet, struct interface *ifp; /* Add primary SVI MAC*/ - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; ifp = zvni->vxlan_if; if (!ifp) @@ -2801,7 +2857,7 @@ static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet, return; } -static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, +static void zvni_gw_macip_add_for_vni_hash(struct hash_bucket *bucket, void *ctxt) { zebra_vni_t *zvni = NULL; @@ -2811,7 +2867,7 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, struct interface *vrr_if = NULL; struct interface *ifp = NULL; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; ifp = zvni->vxlan_if; if (!ifp) @@ -2831,10 +2887,48 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, /* Add primary SVI MAC-IP */ zvni_add_macip_for_intf(vlan_if, zvni); - /* Add VRR MAC-IP - if any*/ - vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); - if (vrr_if) - zvni_add_macip_for_intf(vrr_if, zvni); + if (advertise_gw_macip_enabled(zvni)) { + /* Add VRR MAC-IP - if any*/ + vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); + if (vrr_if) + zvni_add_macip_for_intf(vrr_if, zvni); + } + + return; +} + +static void zvni_svi_macip_del_for_vni_hash(struct hash_bucket *bucket, + void *ctxt) +{ + zebra_vni_t *zvni = NULL; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan zl2_info; + struct interface *vlan_if = NULL; + struct interface *ifp; + + /* Add primary SVI MAC*/ + zvni = (zebra_vni_t *)bucket->data; + if (!zvni) + return; + + ifp = zvni->vxlan_if; + if (!ifp) + return; + zif = ifp->info; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return; + + zl2_info = zif->l2info.vxl; + + vlan_if = zvni_map_to_svi(zl2_info.access_vlan, + zif->brslave_info.br_if); + if (!vlan_if) + return; + + /* Del primary MAC-IP */ + zvni_del_macip_for_intf(vlan_if, zvni); return; } @@ -2963,7 +3057,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, */ if (IS_ZEBRA_NEIGH_ACTIVE(n)) zvni_neigh_send_del_to_client(zvni->vni, &n->ip, - &n->emac, 0); + &n->emac, 0, n->state); old_zmac = zvni_mac_lookup(zvni, &n->emac); if (old_zmac) { old_mac_seq = CHECK_FLAG(old_zmac->flags, @@ -3224,10 +3318,10 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac) /* * Free MAC hash entry (callback) */ -static void zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg) +static void zvni_mac_del_hash_entry(struct hash_bucket *bucket, void *arg) { struct mac_walk_ctx *wctx = arg; - zebra_mac_t *mac = backet->data; + zebra_mac_t *mac = bucket->data; if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) || ((wctx->flags & DEL_REMOTE_MAC) @@ -3319,7 +3413,7 @@ static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr, SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags, - seq, ZEBRA_MACIP_ADD); + seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD); } /* @@ -3328,7 +3422,7 @@ static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr, static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr) { return zvni_macip_send_msg_to_client(vni, macaddr, NULL, 0 /* flags */, - 0 /* seq */, ZEBRA_MACIP_DEL); + 0 /* seq */, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_DEL); } /* @@ -3568,12 +3662,12 @@ static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac) /* * Install MAC hash entry - called upon access VLAN change. */ -static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt) +static void zvni_install_mac_hash(struct hash_bucket *bucket, void *ctxt) { zebra_mac_t *mac; struct mac_walk_ctx *wctx = ctxt; - mac = (zebra_mac_t *)backet->data; + mac = (zebra_mac_t *)bucket->data; if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) zvni_mac_install(wctx->zvni, mac); @@ -3841,7 +3935,7 @@ static int zvni_send_del_to_client(vni_t vni) * Build the VNI hash table by going over the VxLAN interfaces. This * is called when EVPN (advertise-all-vni) is enabled. */ -static void zvni_build_hash_table() +static void zvni_build_hash_table(void) { struct zebra_ns *zns; struct route_node *rn; @@ -4046,13 +4140,13 @@ static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip) * Install or uninstall flood entries in the kernel corresponding to * remote VTEPs. This is invoked upon change to BUM handling. */ -static void zvni_handle_flooding_remote_vteps(struct hash_backet *backet, +static void zvni_handle_flooding_remote_vteps(struct hash_bucket *bucket, void *zvrf) { zebra_vni_t *zvni; zebra_vtep_t *zvtep; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; if (!zvni) return; @@ -4067,13 +4161,13 @@ static void zvni_handle_flooding_remote_vteps(struct hash_backet *backet, /* * Cleanup VNI/VTEP and update kernel */ -static void zvni_cleanup_all(struct hash_backet *backet, void *arg) +static void zvni_cleanup_all(struct hash_bucket *bucket, void *arg) { zebra_vni_t *zvni = NULL; zebra_l3vni_t *zl3vni = NULL; struct zebra_vrf *zvrf = (struct zebra_vrf *)arg; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; /* remove from l3-vni list */ if (zvrf->l3vni) @@ -4093,11 +4187,11 @@ static void zvni_cleanup_all(struct hash_backet *backet, void *arg) } /* cleanup L3VNI */ -static void zl3vni_cleanup_all(struct hash_backet *backet, void *args) +static void zl3vni_cleanup_all(struct hash_bucket *bucket, void *args) { zebra_l3vni_t *zl3vni = NULL; - zl3vni = (zebra_l3vni_t *)backet->data; + zl3vni = (zebra_l3vni_t *)bucket->data; zebra_vxlan_process_l3vni_oper_down(zl3vni); } @@ -4781,6 +4875,7 @@ static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) stream_put(s, &rmac, sizeof(struct ethaddr)); stream_put_in_addr(s, &zl3vni->local_vtep_ip); stream_put(s, &zl3vni->filter, sizeof(int)); + stream_putl(s, zl3vni->svi_if->ifindex); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -4848,9 +4943,9 @@ static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni) zl3vni_send_del_to_client(zl3vni); } -static void zvni_add_to_l3vni_list(struct hash_backet *backet, void *ctxt) +static void zvni_add_to_l3vni_list(struct hash_bucket *bucket, void *ctxt) { - zebra_vni_t *zvni = (zebra_vni_t *)backet->data; + zebra_vni_t *zvni = (zebra_vni_t *)bucket->data; zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)ctxt; if (zvni->vrf_id == zl3vni_vrf_id(zl3vni)) @@ -4911,24 +5006,24 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni, } /* delete and uninstall rmac hash entry */ -static void zl3vni_del_rmac_hash_entry(struct hash_backet *backet, void *ctx) +static void zl3vni_del_rmac_hash_entry(struct hash_bucket *bucket, void *ctx) { zebra_mac_t *zrmac = NULL; zebra_l3vni_t *zl3vni = NULL; - zrmac = (zebra_mac_t *)backet->data; + zrmac = (zebra_mac_t *)bucket->data; zl3vni = (zebra_l3vni_t *)ctx; zl3vni_rmac_uninstall(zl3vni, zrmac); zl3vni_rmac_del(zl3vni, zrmac); } /* delete and uninstall nh hash entry */ -static void zl3vni_del_nh_hash_entry(struct hash_backet *backet, void *ctx) +static void zl3vni_del_nh_hash_entry(struct hash_bucket *bucket, void *ctx) { zebra_neigh_t *n = NULL; zebra_l3vni_t *zl3vni = NULL; - n = (zebra_neigh_t *)backet->data; + n = (zebra_neigh_t *)bucket->data; zl3vni = (zebra_l3vni_t *)ctx; zl3vni_nh_uninstall(zl3vni, n); zl3vni_nh_del(zl3vni, n); @@ -5140,11 +5235,15 @@ static void process_remote_macip_add(vni_t vni, * RFC-7432: A PE/VTEP that detects a MAC mobility * event via local learning starts an M-second timer. * - * VTEP-IP or seq. change along is not considered + * VTEP-IP or seq. change alone is not considered * for dup. detection. + * + * MAC is already marked duplicate set dad, then + * is_dup_detect will be set to not install the entry. */ - if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) && - mac->dad_count) + if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && + mac->dad_count) || + CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) do_dad = true; /* Remove local MAC from BGP. */ @@ -5255,7 +5354,7 @@ static void process_remote_macip_add(vni_t vni, IS_ZEBRA_NEIGH_ACTIVE(n)) zvni_neigh_send_del_to_client( zvni->vni, &n->ip, - &n->emac, 0); + &n->emac, 0, n->state); /* update neigh list for macs */ old_mac = zvni_mac_lookup(zvni, &n->emac); @@ -5321,6 +5420,8 @@ static void process_remote_macip_add(vni_t vni, zvni_neigh_install(zvni, n); } + zvni_probe_neigh_on_mac_add(zvni, mac); + /* Update seq number. */ n->rem_seq = seq; } @@ -5337,6 +5438,9 @@ static void process_remote_macip_del(vni_t vni, zebra_neigh_t *n = NULL; struct interface *ifp = NULL; struct zebra_if *zif = NULL; + struct zebra_ns *zns; + struct zebra_l2info_vxlan *vxl; + struct zebra_vrf *zvrf; char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; @@ -5360,6 +5464,8 @@ static void process_remote_macip_del(vni_t vni, vni); return; } + zns = zebra_ns_lookup(NS_DEFAULT); + vxl = &zif->l2info.vxl; /* The remote VTEP specified is normally expected to exist, but * it is possible that the peer may delete the VTEP before deleting @@ -5386,9 +5492,10 @@ static void process_remote_macip_del(vni_t vni, if (!mac && !n) return; + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + /* Ignore the delete if this mac is a gateway mac-ip */ - if (mac - && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) { zlog_warn( "Ignore remote MACIP DEL VNI %u MAC %s%s%s as MAC is already configured as gateway MAC", @@ -5402,6 +5509,23 @@ static void process_remote_macip_del(vni_t vni, /* Uninstall remote neighbor or MAC. */ if (n) { + if (zvrf->dad_freeze && + CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE) && + CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) && + (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0)) { + struct interface *vlan_if; + + vlan_if = zvni_map_to_svi(vxl->access_vlan, + zif->brslave_info.br_if); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s: IP %s (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry", + __PRETTY_FUNCTION__, + ipaddr2str(ipaddr, buf1, + sizeof(buf1)), n->flags, + vlan_if->name); + neigh_read_specific_ip(ipaddr, vlan_if); + } + /* When the MAC changes for an IP, it is possible the * client may update the new MAC before trying to delete the * "old" neighbor (as these are two different MACIP routes). @@ -5414,6 +5538,25 @@ static void process_remote_macip_del(vni_t vni, zvni_deref_ip2mac(zvni, mac); } } else { + /* DAD: when MAC is freeze state as remote learn event, + * remote mac-ip delete event is received will result in freeze + * entry removal, first fetch kernel for the same entry present + * as LOCAL and reachable, avoid deleting this entry instead + * use kerenel local entry to update during unfreeze time. + */ + if (zvrf->dad_freeze && + CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) && + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s: MAC %s (flags 0x%x) is remote and duplicate, read kernel for local entry", + __PRETTY_FUNCTION__, + prefix_mac2str(macaddr, buf, + sizeof(buf)), + mac->flags); + macfdb_read_specific_mac(zns, zif->brslave_info.br_if, + macaddr, vxl->access_vlan); + } + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { zvni_process_neigh_on_remote_mac_del(zvni, mac); /* @@ -5626,7 +5769,7 @@ void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json) args[0] = vty; args[1] = json; hash_iterate(zrouter.l3vni_table, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))zl3vni_print_rmac_hash_all_vni, args); @@ -5743,7 +5886,7 @@ void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json) args[0] = vty; args[1] = json; hash_iterate(zrouter.l3vni_table, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))zl3vni_print_nh_hash_all_vni, args); @@ -5904,7 +6047,7 @@ void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf, args[2] = (void *)(ptrdiff_t)print_dup; hash_iterate(zvrf->vni_table, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))zvni_print_neigh_hash_all_vni, args); if (use_json) { @@ -5935,7 +6078,7 @@ void zebra_vxlan_print_neigh_all_vni_detail(struct vty *vty, args[2] = (void *)(ptrdiff_t)print_dup; hash_iterate(zvrf->vni_table, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))zvni_print_neigh_hash_all_vni_detail, args); if (use_json) { @@ -6497,7 +6640,7 @@ int zebra_vxlan_clear_dup_detect_vni_ip(struct vty *vty, return CMD_SUCCESS; } -static void zvni_clear_dup_mac_hash(struct hash_backet *backet, void *ctxt) +static void zvni_clear_dup_mac_hash(struct hash_bucket *bucket, void *ctxt) { struct mac_walk_ctx *wctx = ctxt; zebra_mac_t *mac; @@ -6505,7 +6648,7 @@ static void zvni_clear_dup_mac_hash(struct hash_backet *backet, void *ctxt) struct listnode *node = NULL; zebra_neigh_t *nbr = NULL; - mac = (zebra_mac_t *)backet->data; + mac = (zebra_mac_t *)bucket->data; if (!mac) return; @@ -6552,14 +6695,14 @@ static void zvni_clear_dup_mac_hash(struct hash_backet *backet, void *ctxt) } } -static void zvni_clear_dup_neigh_hash(struct hash_backet *backet, void *ctxt) +static void zvni_clear_dup_neigh_hash(struct hash_bucket *bucket, void *ctxt) { struct neigh_walk_ctx *wctx = ctxt; zebra_neigh_t *nbr; zebra_vni_t *zvni; char buf[INET6_ADDRSTRLEN]; - nbr = (zebra_neigh_t *)backet->data; + nbr = (zebra_neigh_t *)bucket->data; if (!nbr) return; @@ -6592,7 +6735,7 @@ static void zvni_clear_dup_neigh_hash(struct hash_backet *backet, void *ctxt) } } -static void zvni_clear_dup_detect_hash_vni_all(struct hash_backet *backet, +static void zvni_clear_dup_detect_hash_vni_all(struct hash_bucket *bucket, void **args) { struct vty *vty; @@ -6601,7 +6744,7 @@ static void zvni_clear_dup_detect_hash_vni_all(struct hash_backet *backet, struct mac_walk_ctx m_wctx; struct neigh_walk_ctx n_wctx; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; if (!zvni) return; @@ -6639,7 +6782,7 @@ int zebra_vxlan_clear_dup_detect_vni_all(struct vty *vty, args[1] = zvrf; hash_iterate(zvrf->vni_table, - (void (*)(struct hash_backet *, void *)) + (void (*)(struct hash_bucket *, void *)) zvni_clear_dup_detect_hash_vni_all, args); return CMD_SUCCESS; @@ -6818,6 +6961,8 @@ void zebra_vxlan_print_evpn(struct vty *vty, bool uj) vty_out(vty, "L3 VNIs: %u\n", num_l3vnis); vty_out(vty, "Advertise gateway mac-ip: %s\n", zvrf->advertise_gw_macip ? "Yes" : "No"); + vty_out(vty, "Advertise svi mac-ip: %s\n", + zvrf->advertise_svi_macip ? "Yes" : "No"); vty_out(vty, "Duplicate address detection: %s\n", zvrf->dup_addr_detect ? "Enable" : "Disable"); vty_out(vty, " Detection max-moves %u, time %d\n", @@ -6863,12 +7008,12 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, /* Display all L2-VNIs */ hash_iterate(zvrf->vni_table, - (void (*)(struct hash_backet *, void *))zvni_print_hash, + (void (*)(struct hash_bucket *, void *))zvni_print_hash, args); /* Display all L3-VNIs */ hash_iterate(zrouter.l3vni_table, - (void (*)(struct hash_backet *, void *))zl3vni_print_hash, + (void (*)(struct hash_bucket *, void *))zl3vni_print_hash, args); if (use_json) { @@ -6946,19 +7091,21 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, zes.zvrf = zvrf; /* Display all L2-VNIs */ - hash_iterate(zvrf->vni_table, (void (*)(struct hash_backet *, - void *))zvni_print_hash_detail, - &zes); + hash_iterate( + zvrf->vni_table, + (void (*)(struct hash_bucket *, void *))zvni_print_hash_detail, + &zes); /* Display all L3-VNIs */ hash_iterate(zrouter.l3vni_table, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))zl3vni_print_hash_detail, &zes); if (use_json) { - 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_ext( + json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); } } @@ -6979,6 +7126,7 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, zebra_vni_t *zvni = NULL; zebra_mac_t *zmac = NULL; zebra_l3vni_t *zl3vni = NULL; + struct zebra_vrf *zvrf; /* check if this is a remote neigh entry corresponding to remote * next-hop @@ -7031,9 +7179,23 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, return 0; } + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + if (!zvrf) { + zlog_debug("%s: VNI %u vrf lookup failed.", + __PRETTY_FUNCTION__, zvni->vni); + return -1; + } + + /* In case of feeze action, if local neigh is in duplicate state, + * Mark the Neigh as inactive before sending delete request to BGPd, + * If BGPd has remote entry, it will re-install + */ + if (zvrf->dad_freeze && + CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) + ZEBRA_NEIGH_SET_INACTIVE(n); + /* Remove neighbor from BGP. */ - if (IS_ZEBRA_NEIGH_ACTIVE(n)) - zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, 0); + zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, 0, n->state); /* Delete this neighbor entry. */ zvni_neigh_del(zvni, n); @@ -8606,6 +8768,102 @@ stream_failure: } /* + * Handle message from client to enable/disable advertisement of svi macip + * routes + */ +void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + int advertise; + vni_t vni = 0; + zebra_vni_t *zvni = NULL; + struct interface *ifp = NULL; + + if (zvrf_id(zvrf) != VRF_DEFAULT) { + zlog_debug("EVPN GW-MACIP Adv for non-default VRF %u", + zvrf_id(zvrf)); + return; + } + + s = msg; + STREAM_GETC(s, advertise); + STREAM_GETL(s, vni); + + if (!vni) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("EVPN gateway macip Adv %s, currently %s", + advertise ? "enabled" : "disabled", + advertise_gw_macip_enabled(NULL) + ? "enabled" + : "disabled"); + + if (zvrf->advertise_svi_macip == advertise) + return; + + + if (advertise) { + zvrf->advertise_svi_macip = advertise; + hash_iterate(zvrf->vni_table, + zvni_gw_macip_add_for_vni_hash, NULL); + } else { + hash_iterate(zvrf->vni_table, + zvni_svi_macip_del_for_vni_hash, NULL); + zvrf->advertise_svi_macip = advertise; + } + + } else { + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan zl2_info; + struct interface *vlan_if = NULL; + + zvni = zvni_lookup(vni); + if (!zvni) + return; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "EVPN SVI macip Adv %s on VNI %d , currently %s", + advertise ? "enabled" : "disabled", vni, + advertise_svi_macip_enabled(zvni) + ? "enabled" + : "disabled"); + + if (zvni->advertise_svi_macip == advertise) + return; + + ifp = zvni->vxlan_if; + if (!ifp) + return; + + zif = ifp->info; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return; + + zl2_info = zif->l2info.vxl; + + vlan_if = zvni_map_to_svi(zl2_info.access_vlan, + zif->brslave_info.br_if); + if (!vlan_if) + return; + + if (advertise) { + zvni->advertise_svi_macip = advertise; + /* Add primary SVI MAC-IP */ + zvni_add_macip_for_intf(vlan_if, zvni); + } else { + /* Del primary MAC-IP */ + zvni_del_macip_for_intf(vlan_if, zvni); + zvni->advertise_svi_macip = advertise; + } + } + +stream_failure: + return; +} + +/* * Handle message from client to enable/disable advertisement of g/w macip * routes */ diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index c50664a28..2cf21ff90 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -37,7 +37,7 @@ /* Is EVPN enabled? */ #define EVPN_ENABLED(zvrf) (zvrf)->advertise_all_vni -static inline int is_evpn_enabled() +static inline int is_evpn_enabled(void) { struct zebra_vrf *zvrf = NULL; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); @@ -45,7 +45,7 @@ static inline int is_evpn_enabled() } static inline int -is_vxlan_flooding_head_end() +is_vxlan_flooding_head_end(void) { struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); @@ -68,6 +68,7 @@ extern void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS); +extern void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS); diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index 3be7dc012..c36d15635 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -70,6 +70,9 @@ struct zebra_vni_t_ { /* Flag for advertising gw macip */ uint8_t advertise_gw_macip; + /* Flag for advertising svi macip */ + uint8_t advertise_svi_macip; + /* Flag for advertising gw macip */ uint8_t advertise_subnet; @@ -313,11 +316,9 @@ struct rmac_walk_ctx { struct json_object *json; }; -enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 }; - -#define IS_ZEBRA_NEIGH_ACTIVE(n) n->state == ZEBRA_NEIGH_ACTIVE +#define IS_ZEBRA_NEIGH_ACTIVE(n) (n->state == ZEBRA_NEIGH_ACTIVE) -#define IS_ZEBRA_NEIGH_INACTIVE(n) n->state == ZEBRA_NEIGH_INACTIVE +#define IS_ZEBRA_NEIGH_INACTIVE(n) (n->state == ZEBRA_NEIGH_INACTIVE) #define ZEBRA_NEIGH_SET_ACTIVE(n) n->state = ZEBRA_NEIGH_ACTIVE diff --git a/zebra/zserv.c b/zebra/zserv.c index 502186d22..6532491ce 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -61,12 +61,16 @@ #include "zebra/zapi_msg.h" /* for zserv_handle_commands */ #include "zebra/zebra_vrf.h" /* for zebra_vrf_lookup_by_id, zvrf */ #include "zebra/zserv.h" /* for zserv */ +#include "zebra/zebra_router.h" #include "zebra/zebra_errors.h" /* for error messages */ /* clang-format on */ /* privileges */ extern struct zebra_privs_t zserv_privs; +/* The listener socket for clients connecting to us */ +static int zsock; + /* * Client thread events. * @@ -312,7 +316,7 @@ static int zserv_read(struct thread *thread) uint32_t p2p; struct zmsghdr hdr; - p2p_orig = atomic_load_explicit(&zebrad.packets_to_process, + p2p_orig = atomic_load_explicit(&zrouter.packets_to_process, memory_order_relaxed); cache = stream_fifo_new(); p2p = p2p_orig; @@ -401,8 +405,10 @@ static int zserv_read(struct thread *thread) } /* Debug packet information. */ - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("zebra message comes from socket [%d]", + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("zebra message[%s:%u:%u] comes from socket [%d]", + zserv_command_string(hdr.command), + hdr.vrf_id, hdr.length, sock); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) @@ -438,7 +444,8 @@ static int zserv_read(struct thread *thread) } if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("Read %d packets", p2p_orig - p2p); + zlog_debug("Read %d packets from client: %s", p2p_orig - p2p, + zebra_route_string(client->proto)); /* Reschedule ourselves */ zserv_client_event(client, ZSERV_CLIENT_READ); @@ -481,9 +488,9 @@ static void zserv_client_event(struct zserv *client, * with the message is executed. This proceeds until there are no more messages, * an error occurs, or the processing limit is reached. * - * The client's I/O thread can push at most zebrad.packets_to_process messages + * The client's I/O thread can push at most zrouter.packets_to_process messages * onto the input buffer before notifying us there are packets to read. As long - * as we always process zebrad.packets_to_process messages here, then we can + * as we always process zrouter.packets_to_process messages here, then we can * rely on the read thread to handle queuing this task enough times to process * everything on the input queue. */ @@ -492,7 +499,7 @@ static int zserv_process_messages(struct thread *thread) struct zserv *client = THREAD_ARG(thread); struct stream *msg; struct stream_fifo *cache = stream_fifo_new(); - uint32_t p2p = zebrad.packets_to_process; + uint32_t p2p = zrouter.packets_to_process; bool need_resched = false; pthread_mutex_lock(&client->ibuf_mtx); @@ -622,7 +629,6 @@ static void zserv_client_free(struct zserv *client) vrf_bitmap_free(client->redist_default[afi]); } - vrf_bitmap_free(client->ifinfo); vrf_bitmap_free(client->ridinfo); XFREE(MTYPE_TMP, client); @@ -637,7 +643,7 @@ void zserv_close_client(struct zserv *client) zlog_debug("Closing client '%s'", zebra_route_string(client->proto)); - thread_cancel_event(zebrad.master, client); + thread_cancel_event(zrouter.master, client); THREAD_OFF(client->t_cleanup); THREAD_OFF(client->t_process); @@ -646,7 +652,7 @@ void zserv_close_client(struct zserv *client) client->pthread = NULL; /* remove from client list */ - listnode_delete(zebrad.client_list, client); + listnode_delete(zrouter.client_list, client); /* delete client */ zserv_client_free(client); @@ -695,7 +701,7 @@ static struct zserv *zserv_client_create(int sock) client->wb = buffer_new(0); /* Set table number. */ - client->rtm_table = zebrad.rtm_table_default; + client->rtm_table = zrouter.rtm_table_default; atomic_store_explicit(&client->connect_time, (uint32_t) monotime(NULL), memory_order_relaxed); @@ -706,14 +712,13 @@ static struct zserv *zserv_client_create(int sock) client->redist[afi][i] = vrf_bitmap_init(); client->redist_default[afi] = vrf_bitmap_init(); } - client->ifinfo = vrf_bitmap_init(); client->ridinfo = vrf_bitmap_init(); /* by default, it's not a synchronous client */ client->is_synchronous = 0; /* Add this client to linked list. */ - listnode_add(zebrad.client_list, client); + listnode_add(zrouter.client_list, client); struct frr_pthread_attr zclient_pthr_attrs = { .start = frr_pthread_attr_default.start, @@ -723,8 +728,6 @@ static struct zserv *zserv_client_create(int sock) frr_pthread_new(&zclient_pthr_attrs, "Zebra API client thread", "zebra_apic"); - zebra_vrf_update_all(client); - /* start read loop */ zserv_client_event(client, ZSERV_CLIENT_READ); @@ -785,16 +788,16 @@ void zserv_start(char *path) old_mask = umask(0077); /* Make UNIX domain socket. */ - zebrad.sock = socket(sa.ss_family, SOCK_STREAM, 0); - if (zebrad.sock < 0) { + zsock = socket(sa.ss_family, SOCK_STREAM, 0); + if (zsock < 0) { flog_err_sys(EC_LIB_SOCKET, "Can't create zserv socket: %s", safe_strerror(errno)); return; } if (sa.ss_family != AF_UNIX) { - sockopt_reuseaddr(zebrad.sock); - sockopt_reuseport(zebrad.sock); + sockopt_reuseaddr(zsock); + sockopt_reuseport(zsock); } else { struct sockaddr_un *suna = (struct sockaddr_un *)&sa; if (suna->sun_path[0]) @@ -802,28 +805,28 @@ void zserv_start(char *path) } frr_elevate_privs(&zserv_privs) { - setsockopt_so_recvbuf(zebrad.sock, 1048576); - setsockopt_so_sendbuf(zebrad.sock, 1048576); + setsockopt_so_recvbuf(zsock, 1048576); + setsockopt_so_sendbuf(zsock, 1048576); } frr_elevate_privs((sa.ss_family != AF_UNIX) ? &zserv_privs : NULL) { - ret = bind(zebrad.sock, (struct sockaddr *)&sa, sa_len); + ret = bind(zsock, (struct sockaddr *)&sa, sa_len); } if (ret < 0) { flog_err_sys(EC_LIB_SOCKET, "Can't bind zserv socket on %s: %s", path, safe_strerror(errno)); - close(zebrad.sock); - zebrad.sock = -1; + close(zsock); + zsock = -1; return; } - ret = listen(zebrad.sock, 5); + ret = listen(zsock, 5); if (ret < 0) { flog_err_sys(EC_LIB_SOCKET, "Can't listen to zserv socket %s: %s", path, safe_strerror(errno)); - close(zebrad.sock); - zebrad.sock = -1; + close(zsock); + zsock = -1; return; } @@ -836,15 +839,15 @@ void zserv_event(struct zserv *client, enum zserv_event event) { switch (event) { case ZSERV_ACCEPT: - thread_add_read(zebrad.master, zserv_accept, NULL, zebrad.sock, + thread_add_read(zrouter.master, zserv_accept, NULL, zsock, NULL); break; case ZSERV_PROCESS_MESSAGES: - thread_add_event(zebrad.master, zserv_process_messages, client, + thread_add_event(zrouter.master, zserv_process_messages, client, 0, &client->t_process); break; case ZSERV_HANDLE_CLIENT_FAIL: - thread_add_event(zebrad.master, zserv_handle_client_fail, + thread_add_event(zrouter.master, zserv_handle_client_fail, client, 0, &client->t_cleanup); } } @@ -1004,7 +1007,7 @@ struct zserv *zserv_find_client(uint8_t proto, unsigned short instance) struct listnode *node, *nnode; struct zserv *client; - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { if (client->proto == proto && client->instance == instance) return client; } @@ -1023,7 +1026,7 @@ DEFUN (show_zebra_client, struct listnode *node; struct zserv *client; - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) zebra_show_client_detail(vty, client); return CMD_SUCCESS; @@ -1046,7 +1049,7 @@ DEFUN (show_zebra_client_summary, vty_out(vty, "--------------------------------------------------------------------------------\n"); - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) zebra_show_client_brief(vty, client); vty_out(vty, "Routes column shows (added+updated)/deleted\n"); @@ -1069,10 +1072,10 @@ void zserv_read_file(char *input) void zserv_init(void) { /* Client list init. */ - zebrad.client_list = list_new(); + zrouter.client_list = list_new(); /* Misc init. */ - zebrad.sock = -1; + zsock = -1; install_element(ENABLE_NODE, &show_zebra_client_cmd); install_element(ENABLE_NODE, &show_zebra_client_summary_cmd); diff --git a/zebra/zserv.h b/zebra/zserv.h index 041485cdc..ac016e65f 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -89,9 +89,6 @@ struct zserv { /* Redistribute default route flag. */ vrf_bitmap_t redist_default[AFI_MAX]; - /* Interface information. */ - vrf_bitmap_t ifinfo; - /* Router-id information. */ vrf_bitmap_t ridinfo; @@ -173,31 +170,6 @@ struct zserv { DECLARE_HOOK(zserv_client_connect, (struct zserv *client), (client)); DECLARE_KOOH(zserv_client_close, (struct zserv *client), (client)); -/* Zebra instance */ -struct zebra_t { - /* Thread master */ - struct thread_master *master; - struct list *client_list; - - /* Socket */ - int sock; - - /* default table */ - uint32_t rtm_table_default; - -/* rib work queue */ -#define ZEBRA_RIB_PROCESS_HOLD_TIME 10 -#define ZEBRA_RIB_PROCESS_RETRY_TIME 1 - struct work_queue *ribq; - struct meta_queue *mq; - - /* LSP work queue */ - struct work_queue *lsp_process_q; - -#define ZEBRA_ZAPI_PACKETS_TO_PROCESS 1000 - _Atomic uint32_t packets_to_process; -}; -extern struct zebra_t zebrad; extern unsigned int multipath_num; /* |