**/*.lo
**/*.so
**/.libs
+docker/alpine/pkgs
+++ /dev/null
-# HOW TO GET YOUR ISSUE ADDRESSED FASTER
-
-* When reporting a crash provide a backtrace
-* When pasting configs, logs, shell output, backtraces, and other large chunks
- of text [use Markdown code blocks](https://github.github.com/gfm/#fenced-code-blocks)
-* Include the FRR version; if you built from Git, please provide the commit
- hash
-* Write your issue in English
-
-### How to submit an issue
-Please use this text as a template and replace text in the sections or remove
-the entire section if it does not apply to your issue. For example in case of
-a question or feature request, just a description with some example is probably
-fine. Also remember to use GitHub Flavored Markdown properly, especially if
-posting output or code listings.
-
-### Things you may try first
-(put "x" in "[ ]" if you already tried following)
-* [ ] Did you check if this is a duplicate issue?
-* [ ] Did you test it on the latest FRRouting/frr master branch?
-
-**Related Issue:**
-[fill here if applicable]
-
-### Description
-[Description of the bug or feature]
-
-### Steps to Reproduce
-1. [First Step]
-2. [Second Step]
-3. [and so on...]
-
-**Expected behavior:**
-[What you expected to happen]
-
-**Actual behavior:**
-[What actually happened]
-
-### Components
-[bgpd, build, doc, isisd, ospfd, etc.]
-
-### Versions
-* OS: [name] [version]
-* Kernel: [Linux/BSD] [version]
-* FRR: [version]
-
-### Attachments
-[Attach if applicable. For example log-files, log-lines. etc. etc.]
-
-You're also welcomed to provide us with any other data you think may be useful.
-
-Thanks!
--- /dev/null
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: triage
+assignees: ''
+
+---
+
+- When reporting a crash, provide a backtrace
+- When pasting configs, logs, shell output, backtraces, and other large chunks of text use Markdown code blocks
+- Include the FRR version; if you built from Git, please provide the commit hash
+- Write your issue in English
+
+---------------
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+(put "x" in "[ ]" if you already tried following)
+[ ] Did you check if this is a duplicate issue?
+[ ] Did you test it on the latest FRRouting/frr master branch?
+
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Versions**
+ - OS Kernel: [e.g. Linux, OpenBSD, etc] [version]
+ - FRR Version [version]
+
+**Additional context**
+Add any other context about the problem here.
+++ /dev/null
-### Summary
-[fill here]
-
-### Related Issue
-[fill here if applicable]
-
-### Components
-[bgpd, build, doc, ripd, ospfd, eigrpd, isisd, etc. etc.]
--- /dev/null
+### Summary
+[fill here]
+
+### Related Issue
+[fill here if applicable]
+
+### Components
+[bgpd, build, doc, ripd, ospfd, eigrpd, isisd, etc. etc.]
| Users & Operators | frog@lists.frrouting.org |
| Announcements | announce@lists.frrouting.org |
-For chat, we currently use [Slack](https://frrouting.slack.com). Please email
-the mailing list to request an invite as we do not issue automatic invites.
+For chat, we currently use [Slack](https://frrouting.slack.com). You can join
+by clicking the "Slack" link under the
+[Participate](https://frrouting.org/#participate) section of our website.
Contributing
depends="json-c c-ares ipsec-tools iproute2 python py-ipaddr bash"
makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
acct autoconf automake bash
- binutils binutils-libs bison bsd-compat-headers build-base
+ binutils bison bsd-compat-headers build-base
c-ares c-ares-dev ca-certificates cryptsetup-libs curl
device-mapper-libs expat fakeroot flex fortify-headers gdbm
git gmp isl json-c-dev kmod lddtree libacl libatomic libattr
libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc
libgomp libisoburn libisofs libltdl libressl libssh2
- libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1
+ libstdc++ libtool libuuid libyang-dev linux-headers lzip lzo m4 make mkinitfs mpc1
mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base
patch pax-utils pcre perl pkgconf python2 python2-dev readline
readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs
checkdepends="pytest py-setuptools"
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
-source="$pkgname-$pkgver.tar.gz docker-start daemons"
+source="$pkgname-$pkgver.tar.gz"
builddir="$srcdir"/$pkgname-$pkgver
cd "$builddir"
make DESTDIR="$pkgdir" install
- install -Dm755 "$srcdir"/docker-start "$pkgdir"$_sbindir
- install -Dm644 "$srcdir"/daemons "$pkgdir"$_sysconfdir
+ install -Dm644 "$builddir"/tools/etc/frr/daemons "$pkgdir"$_sysconfdir
install -d "$pkgdir"/etc/init.d
ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr
}
+++ /dev/null
-#!/bin/sh
-
-set -e
-
-##
-# For volume mounts...
-##
-chown -R frr:frr /etc/frr
-/etc/init.d/frr start
-exec sleep 10000d
if (bs->key.ifname[0])
pos += snprintf(buf + pos, sizeof(buf) - pos, " ifname:%s",
bs->key.ifname);
+
+ (void)pos;
+
return buf;
}
bfdd_sessions_disable_interface(ifp);
+ if_set_index(ifp, IFINDEX_INTERNAL);
+
return 0;
}
}
#endif
-static int bgp_table_stats_walker(struct thread *t)
+static void bgp_table_stats_rn(struct bgp_node *rn, struct bgp_node *top,
+ struct bgp_table_stats *ts, unsigned int space)
{
- struct bgp_node *rn;
- struct bgp_node *top;
- struct bgp_table_stats *ts = THREAD_ARG(t);
- unsigned int space = 0;
-
- if (!(top = bgp_table_top(ts->table)))
- return 0;
-
- switch (top->p.family) {
- case AF_INET:
- space = IPV4_MAX_BITLEN;
- break;
- case AF_INET6:
- space = IPV6_MAX_BITLEN;
- break;
- }
-
- ts->counts[BGP_STATS_MAXBITLEN] = space;
-
- for (rn = top; rn; rn = bgp_route_next(rn)) {
- struct bgp_path_info *pi;
- struct bgp_node *prn = bgp_node_parent_nolock(rn);
- unsigned int pinum = 0;
+ struct bgp_node *prn = bgp_node_parent_nolock(rn);
+ struct bgp_path_info *pi;
- if (rn == top)
- continue;
+ if (rn == top)
+ return;
- if (!bgp_node_has_bgp_path_info_data(rn))
- continue;
+ if (!bgp_node_has_bgp_path_info_data(rn))
+ return;
- ts->counts[BGP_STATS_PREFIXES]++;
- ts->counts[BGP_STATS_TOTPLEN] += rn->p.prefixlen;
+ ts->counts[BGP_STATS_PREFIXES]++;
+ ts->counts[BGP_STATS_TOTPLEN] += rn->p.prefixlen;
#if 0
ts->counts[BGP_STATS_AVGPLEN]
rn->p.prefixlen);
#endif
- /* check if the prefix is included by any other announcements */
- while (prn && !bgp_node_has_bgp_path_info_data(prn))
- prn = bgp_node_parent_nolock(prn);
+ /* check if the prefix is included by any other announcements */
+ while (prn && !bgp_node_has_bgp_path_info_data(prn))
+ prn = bgp_node_parent_nolock(prn);
- if (prn == NULL || prn == top) {
- ts->counts[BGP_STATS_UNAGGREGATEABLE]++;
- /* announced address space */
- if (space)
- ts->total_space +=
- pow(2.0, space - rn->p.prefixlen);
- } else if (bgp_node_has_bgp_path_info_data(prn))
- ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++;
+ if (prn == NULL || prn == top) {
+ ts->counts[BGP_STATS_UNAGGREGATEABLE]++;
+ /* announced address space */
+ if (space)
+ ts->total_space += pow(2.0, space - rn->p.prefixlen);
+ } else if (bgp_node_has_bgp_path_info_data(prn))
+ ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++;
- for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
- pinum++;
- ts->counts[BGP_STATS_RIB]++;
-
- if (pi->attr
- && (CHECK_FLAG(pi->attr->flag,
- ATTR_FLAG_BIT(
- BGP_ATTR_ATOMIC_AGGREGATE))))
- ts->counts[BGP_STATS_AGGREGATES]++;
-
- /* as-path stats */
- if (pi->attr && pi->attr->aspath) {
- unsigned int hops =
- aspath_count_hops(pi->attr->aspath);
- unsigned int size =
- aspath_size(pi->attr->aspath);
- as_t highest = aspath_highest(pi->attr->aspath);
-
- ts->counts[BGP_STATS_ASPATH_COUNT]++;
-
- if (hops > ts->counts[BGP_STATS_ASPATH_MAXHOPS])
- ts->counts[BGP_STATS_ASPATH_MAXHOPS] =
- hops;
-
- if (size > ts->counts[BGP_STATS_ASPATH_MAXSIZE])
- ts->counts[BGP_STATS_ASPATH_MAXSIZE] =
- size;
-
- ts->counts[BGP_STATS_ASPATH_TOTHOPS] += hops;
- ts->counts[BGP_STATS_ASPATH_TOTSIZE] += size;
+
+ for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
+ ts->counts[BGP_STATS_RIB]++;
+
+ if (pi->attr
+ && (CHECK_FLAG(pi->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))))
+ ts->counts[BGP_STATS_AGGREGATES]++;
+
+ /* as-path stats */
+ if (pi->attr && pi->attr->aspath) {
+ unsigned int hops = aspath_count_hops(pi->attr->aspath);
+ unsigned int size = aspath_size(pi->attr->aspath);
+ as_t highest = aspath_highest(pi->attr->aspath);
+
+ ts->counts[BGP_STATS_ASPATH_COUNT]++;
+
+ if (hops > ts->counts[BGP_STATS_ASPATH_MAXHOPS])
+ ts->counts[BGP_STATS_ASPATH_MAXHOPS] = hops;
+
+ if (size > ts->counts[BGP_STATS_ASPATH_MAXSIZE])
+ ts->counts[BGP_STATS_ASPATH_MAXSIZE] = size;
+
+ ts->counts[BGP_STATS_ASPATH_TOTHOPS] += hops;
+ ts->counts[BGP_STATS_ASPATH_TOTSIZE] += size;
#if 0
ts->counts[BGP_STATS_ASPATH_AVGHOPS]
= ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT],
ts->counts[BGP_STATS_ASPATH_AVGSIZE],
size);
#endif
- if (highest > ts->counts[BGP_STATS_ASN_HIGHEST])
- ts->counts[BGP_STATS_ASN_HIGHEST] =
- highest;
- }
+ if (highest > ts->counts[BGP_STATS_ASN_HIGHEST])
+ ts->counts[BGP_STATS_ASN_HIGHEST] = highest;
}
}
+}
+
+static int bgp_table_stats_walker(struct thread *t)
+{
+ struct bgp_node *rn, *nrn;
+ struct bgp_node *top;
+ struct bgp_table_stats *ts = THREAD_ARG(t);
+ unsigned int space = 0;
+
+ if (!(top = bgp_table_top(ts->table)))
+ return 0;
+
+ switch (ts->table->afi) {
+ case AFI_IP:
+ space = IPV4_MAX_BITLEN;
+ break;
+ case AFI_IP6:
+ space = IPV6_MAX_BITLEN;
+ break;
+ default:
+ return 0;
+ }
+
+ ts->counts[BGP_STATS_MAXBITLEN] = space;
+
+ for (rn = top; rn; rn = bgp_route_next(rn)) {
+ if (ts->table->safi == SAFI_MPLS_VPN) {
+ struct bgp_table *table;
+
+ table = bgp_node_get_bgp_table_info(rn);
+ if (!table)
+ continue;
+
+ top = bgp_table_top(table);
+ for (nrn = bgp_table_top(table); nrn;
+ nrn = bgp_route_next(nrn))
+ bgp_table_stats_rn(nrn, top, ts, space);
+ } else {
+ bgp_table_stats_rn(rn, top, ts, space);
+ }
+ }
+
return 0;
}
return;
}
- table = bgp->rib[afi][safi];
+ /* labeled-unicast routes live in the unicast table */
+ if (safi == SAFI_LABELED_UNICAST)
+ table = bgp->rib[afi][SAFI_UNICAST];
+ else
+ table = bgp->rib[afi][safi];
output_count = filtered_count = 0;
subgrp = peer_subgroup(peer, afi, safi);
if (use_json)
json = json_object_new_object();
- /* labeled-unicast routes live in the unicast table */
- if (safi == SAFI_LABELED_UNICAST)
- safi = SAFI_UNICAST;
-
if (!peer || !peer->afc[afi][safi]) {
if (use_json) {
json_object_string_add(
/* clear soft inbound */
static void bgp_clear_star_soft_in(struct vty *vty, const char *name)
{
- bgp_clear_vty(vty, name, AFI_IP, SAFI_UNICAST, clear_all,
- BGP_CLEAR_SOFT_IN, NULL);
- bgp_clear_vty(vty, name, AFI_IP6, SAFI_UNICAST, clear_all,
- BGP_CLEAR_SOFT_IN, NULL);
+ afi_t afi;
+ safi_t safi;
+
+ FOREACH_AFI_SAFI (afi, safi)
+ bgp_clear_vty(vty, name, afi, safi, clear_all,
+ BGP_CLEAR_SOFT_IN, NULL);
}
/* clear soft outbound */
static void bgp_clear_star_soft_out(struct vty *vty, const char *name)
{
- bgp_clear_vty(vty, name, AFI_IP, SAFI_UNICAST, clear_all,
- BGP_CLEAR_SOFT_OUT, NULL);
- bgp_clear_vty(vty, name, AFI_IP6, SAFI_UNICAST, clear_all,
- BGP_CLEAR_SOFT_OUT, NULL);
+ afi_t afi;
+ safi_t safi;
+
+ FOREACH_AFI_SAFI (afi, safi)
+ bgp_clear_vty(vty, name, afi, safi, clear_all,
+ BGP_CLEAR_SOFT_OUT, NULL);
}
-FROM alpine:3.7 as source-builder
-ARG commit
-RUN apk add --no-cache abuild acct alpine-sdk attr autoconf automake bash \
- binutils binutils-libs bison bsd-compat-headers build-base \
- c-ares c-ares-dev ca-certificates cryptsetup-libs curl \
- device-mapper-libs expat fakeroot flex fortify-headers g++ gcc gdbm \
- git gmp isl json-c json-c-dev kmod lddtree libacl libatomic libattr \
- libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc \
- libgomp libisoburn libisofs libltdl libressl libssh2 \
- libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1 \
- mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base \
- patch pax-utils pcre perl pkgconf python2 python2-dev readline \
- readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs \
- groff gzip bc py-sphinx
-ADD . /src
-RUN (cd /src && \
- ./bootstrap.sh && \
- ./configure \
+# This stage builds a dist tarball from the source
+FROM alpine:edge as source-builder
+
+RUN mkdir -p /src/alpine
+COPY alpine/APKBUILD.in /src/alpine
+RUN source /src/alpine/APKBUILD.in \
+ && echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
+ && apk add \
+ --no-cache \
+ --update-cache \
+ $makedepends \
+ gzip
+
+COPY . /src
+ARG PKGVER
+RUN cd /src \
+ && ./bootstrap.sh \
+ && ./configure \
--enable-numeric-version \
- --with-pkg-extra-version=_git$commit && \
- make dist)
-FROM alpine:3.7 as alpine-builder
-RUN apk add --no-cache abuild alpine-sdk && mkdir -p /pkgs/apk
-ADD docker/alpine/alpine-build.sh /usr/bin/
-ADD docker/alpine/builder /etc/sudoers.d
-COPY --from=source-builder /src/*.tar.gz /src/alpine/* /src/tools/etc/frr/daemons* /dist/
+ --with-pkg-extra-version="_git$PKGVER" \
+ && make dist
+
+# This stage builds an apk from the dist tarball
+FROM alpine:edge as alpine-builder
+# Don't use nocache here so that abuild can use the cache
+RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
+ && apk add \
+ --update-cache \
+ abuild \
+ alpine-conf \
+ alpine-sdk \
+ && setup-apkcache /var/cache/apk \
+ && mkdir -p /pkgs/apk \
+ && echo 'builder ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
+
+COPY --from=source-builder /src/frr-*.tar.gz /src/alpine/* /dist/
RUN adduser -D -G abuild builder && chown -R builder /dist /pkgs
USER builder
-RUN /usr/bin/alpine-build.sh
-FROM alpine:3.7
+RUN cd /dist \
+ && abuild-keygen -a -n \
+ && abuild checksum \
+ && abuild -r -P /pkgs/apk
+
+# This stage installs frr from the apk
+FROM alpine:edge
RUN mkdir -p /pkgs/apk
COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/
-RUN apk add --no-cache tini
-RUN apk add --no-cache --allow-untrusted /pkgs/apk/x86_64/*.apk
+RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
+ && apk add \
+ --no-cache \
+ --update-cache \
+ tini \
+ && apk add \
+ --no-cache \
+ --allow-untrusted /pkgs/apk/*/*.apk \
+ && rm -rf /pkgs
+COPY docker/alpine/docker-start /usr/lib/frr/docker-start
ENTRYPOINT [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ]
+++ /dev/null
-#!/bin/sh
-
-set -e
-
-cd /dist
-
-sudo apk --update add alpine-conf
-sudo setup-apkcache /var/cache/apk
-abuild-keygen -a -n
-abuild checksum
-abuild -r -P /pkgs/apk
#!/bin/sh
set -e
-set -v
set -x
##
-# commit must be converted to decimal
+# Package version needs to be decimal
##
-c=`git rev-parse --short=10 HEAD`
-commit=`printf '%u\n' 0x$c`
-docker build -f docker/alpine/Dockerfile \
- --build-arg commit=$commit -t frr:alpine-$c .
-id=`docker create frr:alpine-$c`
-docker cp ${id}:/pkgs/ docker
-docker rm $id
-docker rmi frr:alpine-$c
+GITREV="$(git rev-parse --short=10 HEAD)"
+PKGVER="$(printf '%u\n' 0x$GITREV)"
+
+docker build \
+ --pull \
+ --file=docker/alpine/Dockerfile \
+ --build-arg="PKGVER=$PKGVER" \
+ --tag="frr:alpine-builder-$GITREV" \
+ --target=alpine-builder \
+ .
+
+CONTAINER_ID="$(docker create "frr:alpine-builder-$GITREV")"
+docker cp "${CONTAINER_ID}:/pkgs/" docker/alpine
+docker rm "${CONTAINER_ID}"
+
+docker build \
+ --file=docker/alpine/Dockerfile \
+ --build-arg="PKGVER=$PKGVER" \
+ --tag="frr:alpine-$GITREV" \
+ .
+
+docker rmi "frr:alpine-builder-$GITREV"
+++ /dev/null
-builder ALL=(ALL) NOPASSWD:ALL
--- /dev/null
+#!/bin/sh
+
+set -e
+
+##
+# For volume mounts...
+##
+chown -R frr:frr /etc/frr
+/usr/lib/frr/frrinit.sh start
+
+# Sleep forever
+exec tail -f /dev/null
if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1;
+ if (api.prefix.family == AF_INET6
+ && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
+ return 0;
+
/*
* Avoid advertising a false default reachability. (A default
* route installed by IS-IS gets redistributed from zebra back
/* 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],
/* We need router-id information. */
zebra_message_send(zclient, ZEBRA_ROUTER_ID_DELETE, vrf_id);
+ 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],
return 0;
debugf(NHRP_DEBUG_IF, "if-delete: %s", ifp->name);
- if_set_index(ifp, ifp->ifindex);
+
nhrp_interface_update(ifp);
- /* if_delete(ifp); */
+
+ if_set_index(ifp, IFINDEX_INTERNAL);
+
return 0;
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
return 0;
+ if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
+ return 0;
+
ifindex = api.nexthops[0].ifindex;
nexthop = &api.nexthops[0].gate.ipv6;
pim_time_uptime(uptime, sizeof(uptime), now - ch->ifassert_creation);
pim_time_timer_to_mmss(timer, sizeof(timer), ch->t_ifassert_timer);
- vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %-15s %-8s %-5s\n",
+ vty_out(vty, "%-16s %-15s %-15s %-15s %-6s %-15s %-8s %-5s\n",
ch->interface->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str,
pim_ifchannel_ifassert_name(ch->ifassert_state), winner_str,
uptime, timer);
now = pim_time_monotonic_sec();
vty_out(vty,
- "Interface Address Source Group State Winner Uptime Timer\n");
+ "Interface Address Source Group State Winner Uptime Timer\n");
FOR_ALL_INTERFACES (pim->vrf, ifp) {
pim_ifp = ifp->info;
pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, sizeof(ch_src_str));
pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str));
- vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-3s %-3s %-4s\n",
+ vty_out(vty, "%-16s %-15s %-15s %-15s %-3s %-3s %-3s %-4s\n",
ch->interface->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str,
PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no",
pim_macro_ch_could_assert_eval(ch) ? "yes" : "no",
"eATD: Evaluate AssertTrackingDesired\n\n");
vty_out(vty,
- "Interface Address Source Group CA eCA ATD eATD\n");
+ "Interface Address Source Group CA eCA ATD eATD\n");
FOR_ALL_INTERFACES (pim->vrf, ifp) {
pim_ifp = ifp->info;
if (!pim_ifp)
pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str));
pim_inet4_dump("<addr?>", am.ip_address, addr_str, sizeof(addr_str));
- vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %4u %6u %-15s\n",
+ vty_out(vty, "%-16s %-15s %-15s %-15s %-3s %4u %6u %-15s\n",
ch->interface->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str,
am.rpt_bit_flag ? "yes" : "no", am.metric_preference,
am.route_metric, addr_str);
struct interface *ifp;
vty_out(vty,
- "Interface Address Source Group RPT Pref Metric Address \n");
+ "Interface Address Source Group RPT Pref Metric Address \n");
FOR_ALL_INTERFACES (pim->vrf, ifp) {
pim_ifp = ifp->info;
else
snprintf(metr_str, sizeof(metr_str), "%6u", am->route_metric);
- vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-4s %-6s %-15s\n",
+ vty_out(vty, "%-16s %-15s %-15s %-15s %-3s %-4s %-6s %-15s\n",
ch->interface->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str,
am->rpt_bit_flag ? "yes" : "no", pref_str, metr_str, addr_str);
}
struct interface *ifp;
vty_out(vty,
- "Interface Address Source Group RPT Pref Metric Address \n");
+ "Interface Address Source Group RPT Pref Metric Address \n");
FOR_ALL_INTERFACES (pim->vrf, ifp) {
pim_ifp = ifp->info;
json, JSON_C_TO_STRING_PRETTY));
} else {
vty_out(vty,
- "Interface Address Source Group Membership\n");
+ "Interface Address Source Group Membership\n");
/*
* Example of the json data we are traversing
type = json_object_get_type(if_field_val);
if (type == json_type_object) {
- vty_out(vty, "%-9s ", key);
+ vty_out(vty, "%-16s ", key);
json_object_object_get_ex(
val, "address", &json_tmp);
json = json_object_new_object();
else
vty_out(vty,
- "Interface State Address V Querier Query Timer Uptime\n");
+ "Interface State Address V Querier Query Timer Uptime\n");
FOR_ALL_INTERFACES (pim->vrf, ifp) {
struct pim_interface *pim_ifp;
}
} else {
vty_out(vty,
- "%-9s %5s %15s %d %7s %11s %8s\n",
+ "%-16s %5s %15s %d %7s %11s %8s\n",
ifp->name,
if_is_up(ifp)
? (igmp->mtrace_only ? "mtrc"
now = pim_time_monotonic_sec();
vty_out(vty,
- "Interface Address Source Group Socket Uptime \n");
+ "Interface Address Source Group Socket Uptime \n");
FOR_ALL_INTERFACES (pim->vrf, ifp) {
struct pim_interface *pim_ifp;
pim_inet4_dump("<src?>", ij->source_addr, source_str,
sizeof(source_str));
- vty_out(vty, "%-9s %-15s %-15s %-15s %6d %8s\n",
+ vty_out(vty, "%-16s %-15s %-15s %-15s %6d %8s\n",
ifp->name, pri_addr_str, source_str, group_str,
ij->sock_fd, uptime);
} /* for (pim_ifp->igmp_join_list) */
json, JSON_C_TO_STRING_PRETTY));
} else {
vty_out(vty,
- "Interface State Address PIM Nbrs PIM DR FHR IfChannels\n");
+ "Interface State Address PIM Nbrs PIM DR FHR IfChannels\n");
json_object_object_foreach(json, key, val)
{
- vty_out(vty, "%-9s ", key);
+ vty_out(vty, "%-16s ", key);
json_object_object_get_ex(val, "state", &json_tmp);
vty_out(vty, "%5s ", json_object_get_string(json_tmp));
json = json_object_new_object();
else {
vty_out(vty, "\n");
- vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s%-17s\n",
- "Interface", " HELLO", " JOIN", " PRUNE",
- " REGISTER", " REGISTER-STOP", " ASSERT");
- vty_out(vty, "%-10s%-18s%-17s%-17s%-17s%-17s%-17s\n", "",
- " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx",
- " Rx/Tx", " Rx/Tx");
+ vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s\n",
+ "Interface", " HELLO", " JOIN",
+ " PRUNE", " REGISTER", "REGISTER-STOP",
+ " ASSERT");
+ vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
+ " Rx/Tx", " Rx/Tx", " Rx/Tx",
+ " Rx/Tx", " Rx/Tx", " Rx/Tx");
vty_out(vty,
"---------------------------------------------------------------------------------------------------------------\n");
}
json_object_object_add(json, ifp->name, json_row);
} else {
vty_out(vty,
- "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u \n",
+ "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u \n",
ifp->name, pim_ifp->pim_ifstat_hello_recv,
pim_ifp->pim_ifstat_hello_sent,
pim_ifp->pim_ifstat_join_recv,
json = json_object_new_object();
else {
vty_out(vty, "\n");
- vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s%-17s\n",
+ vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s\n",
"Interface", " HELLO", " JOIN", " PRUNE",
" REGISTER", " REGISTER-STOP", " ASSERT");
- vty_out(vty, "%-10s%-18s%-17s%-17s%-17s%-17s%-17s\n", "",
+ vty_out(vty, "%-14s%-18s%-17s%-17s%-17s%-17s%-17s\n", "",
" Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx",
" Rx/Tx", " Rx/Tx");
vty_out(vty,
- "---------------------------------------------------------------------------------------------------------------\n");
+ "---------------------------------------------------------------------------------------------------------------------\n");
}
FOR_ALL_INTERFACES (pim->vrf, ifp) {
json_object_object_add(json, ifp->name, json_row);
} else {
vty_out(vty,
- "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u \n",
+ "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u \n",
ifp->name, pim_ifp->pim_ifstat_hello_recv,
pim_ifp->pim_ifstat_hello_sent,
pim_ifp->pim_ifstat_join_recv,
} else
json_object_object_add(json_grp, ch_src_str, json_row);
} else {
- vty_out(vty, "%-9s %-15s %-15s %-15s %-10s %8s %-6s %5s\n",
+ vty_out(vty, "%-16s %-15s %-15s %-15s %-10s %8s %-6s %5s\n",
ch->interface->name, inet_ntoa(ifaddr), ch_src_str,
ch_grp_str,
pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
json = json_object_new_object();
else
vty_out(vty,
- "Interface Address Source Group State Uptime Expire Prune\n");
+ "Interface Address Source Group State Uptime Expire Prune\n");
FOR_ALL_INTERFACES (pim->vrf, ifp) {
pim_ifp = ifp->info;
vty_out(vty,
"Codes: J -> Pim Join, I -> IGMP Report, S -> Source, * -> Inherited from (*,G)");
vty_out(vty,
- "\nInstalled Source Group IIF OIL\n");
+ "\nInstalled Source Group IIF OIL\n");
}
for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
c_oil->cc.wrong_if);
}
} else {
- vty_out(vty, "%-9d %-15s %-15s %-7s ",
- c_oil->installed, src_str, grp_str,
- in_ifname);
+ vty_out(vty, "%-9d %-15s %-15s %-16s ",
+ c_oil->installed, src_str, grp_str, in_ifname);
}
for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
json = json_object_new_object();
} else {
vty_out(vty,
- "Interface Neighbor Uptime Holdtime DR Pri\n");
+ "Interface Neighbor Uptime Holdtime DR Pri\n");
}
FOR_ALL_INTERFACES (pim->vrf, ifp) {
neigh_src_str, json_row);
} else {
- vty_out(vty, "%-9s %15s %8s %8s %6d\n",
+ vty_out(vty, "%-16s %15s %8s %8s %6d\n",
ifp->name, neigh_src_str, uptime,
expire, neigh->dr_priority);
}
struct interface *ifp;
vty_out(vty,
- "Interface Address Neighbor Secondary \n");
+ "Interface Address Neighbor Secondary \n");
FOR_ALL_INTERFACES (pim->vrf, ifp) {
struct pim_interface *pim_ifp;
prefix2str(p, neigh_sec_str,
sizeof(neigh_sec_str));
- vty_out(vty, "%-9s %-15s %-15s %-15s\n",
+ vty_out(vty, "%-16s %-15s %-15s %-15s\n",
ifp->name, inet_ntoa(ifaddr),
neigh_src_str, neigh_sec_str);
}
json = json_object_new_object();
else
vty_out(vty,
- "Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n");
+ "Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n");
for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
char src_str[INET_ADDRSTRLEN];
json_object_object_add(json_group, src_str, json_row);
} else {
vty_out(vty,
- "%-10s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n",
+ "%-16s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n",
up->rpf.source_nexthop.interface
? up->rpf.source_nexthop.interface->name
: "Unknown",
json_object_object_add(json_group, src_str, json_row);
} else {
- vty_out(vty, "%-9s %-15s %-15s %-10s %-5s %-10s %-11s %-6s\n",
+ vty_out(vty, "%-16s %-15s %-15s %-10s %-5s %-10s %-11s %-6s\n",
ch->interface->name, src_str, grp_str,
pim_macro_ch_lost_assert(ch) ? "yes" : "no",
pim_macro_chisin_joins(ch) ? "yes" : "no",
json = json_object_new_object();
else
vty_out(vty,
- "Interface Source Group LostAssert Joins PimInclude JoinDesired EvalJD\n");
+ "Interface Source Group LostAssert Joins PimInclude JoinDesired EvalJD\n");
/* scan per-interface (S,G) state */
FOR_ALL_INTERFACES (pim->vrf, ifp) {
json = json_object_new_object();
else
vty_out(vty,
- "Source Group RpfIface RibNextHop RpfAddress \n");
+ "Source Group RpfIface RibNextHop RpfAddress \n");
for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
char src_str[INET_ADDRSTRLEN];
rpf_addr_str);
json_object_object_add(json_group, src_str, json_row);
} else {
- vty_out(vty, "%-15s %-15s %-8s %-15s %-15s\n", src_str,
+ vty_out(vty, "%-15s %-15s %-16s %-15s %-15s\n", src_str,
grp_str, rpf_ifname, rpf_nexthop_str,
rpf_addr_str);
}
show_rpf_refresh_stats(vty, pim, now, json);
vty_out(vty, "\n");
vty_out(vty,
- "Source Group RpfIface RpfAddress RibNextHop Metric Pref\n");
+ "Source Group RpfIface RpfAddress RibNextHop Metric Pref\n");
}
for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, up_node, up)) {
json_object_object_add(json_group, src_str, json_row);
} else {
- vty_out(vty, "%-15s %-15s %-8s %-15s %-15s %6d %4d\n",
+ vty_out(vty, "%-15s %-15s %-16s %-15s %-15s %6d %4d\n",
src_str, grp_str, rpf_ifname, rpf_addr_str,
rib_nexthop_str,
rpf->source_nexthop.mrib_route_metric,
ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
vty_out(vty, "%-15s ", inet_ntoa(pnc->rpf.rpf_addr.u.prefix4));
- vty_out(vty, "%-14s ", ifp ? ifp->name : "NULL");
+ vty_out(vty, "%-16s ", ifp ? ifp->name : "NULL");
vty_out(vty, "%s ", inet_ntoa(nh_node->gate.ipv4));
vty_out(vty, "\n");
}
cwd.pim = pim;
vty_out(vty, "Number of registered addresses: %lu\n",
pim->rpf_hash->count);
- vty_out(vty, "Address Interface Nexthop\n");
- vty_out(vty, "-------------------------------------------\n");
+ vty_out(vty, "Address Interface Nexthop\n");
+ vty_out(vty, "---------------------------------------------\n");
hash_walk(pim->rpf_hash, pim_print_pnc_cache_walkcb, &cwd);
}
json = json_object_new_object();
else
vty_out(vty,
- "Interface Address Group Mode Timer Srcs V Uptime \n");
+ "Interface Address Group Mode Timer Srcs V Uptime \n");
/* scan interfaces */
FOR_ALL_INTERFACES (pim->vrf, ifp) {
} else {
vty_out(vty,
- "%-9s %-15s %-15s %4s %8s %4d %d %8s\n",
+ "%-16s %-15s %-15s %4s %8s %4d %d %8s\n",
ifp->name, ifaddr_str,
group_str,
grp->igmp_version == 3
struct interface *ifp;
vty_out(vty,
- "Interface Address Group RetTimer Counter RetSrcs\n");
+ "Interface Address Group RetTimer Counter RetSrcs\n");
/* scan interfaces */
FOR_ALL_INTERFACES (pim->vrf, ifp) {
}
}
- vty_out(vty, "%-9s %-15s %-15s %-8s %7d %7d\n",
+ vty_out(vty, "%-16s %-15s %-15s %-8s %7d %7d\n",
ifp->name, ifaddr_str, group_str,
grp_retr_mmss,
grp->group_specific_query_retransmit_count,
now = pim_time_monotonic_sec();
vty_out(vty,
- "Interface Address Group Source Timer Fwd Uptime \n");
+ "Interface Address Group Source Timer Fwd Uptime \n");
/* scan interfaces */
FOR_ALL_INTERFACES (pim->vrf, ifp) {
now - src->source_creation);
vty_out(vty,
- "%-9s %-15s %-15s %-15s %5s %3s %8s\n",
+ "%-16s %-15s %-15s %-15s %5s %3s %8s\n",
ifp->name, ifaddr_str,
group_str, source_str, mmss,
IGMP_SOURCE_TEST_FORWARDING(
struct interface *ifp;
vty_out(vty,
- "Interface Address Group Source Counter\n");
+ "Interface Address Group Source Counter\n");
/* scan interfaces */
FOR_ALL_INTERFACES (pim->vrf, ifp) {
source_str, sizeof(source_str));
vty_out(vty,
- "%-9s %-15s %-15s %-15s %7d\n",
+ "%-16s %-15s %-15s %-15s %7d\n",
ifp->name, ifaddr_str,
group_str, source_str,
src->source_query_retransmit_count);
vty_out(vty, "\n");
vty_out(vty,
- "Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut\n");
+ "Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut\n");
FOR_ALL_INTERFACES (pim->vrf, ifp) {
struct pim_interface *pim_ifp;
ifaddr = pim_ifp->primary_address;
- vty_out(vty, "%-12s %-15s %3d %3d %7lu %7lu %10lu %10lu\n",
+ vty_out(vty, "%-16s %-15s %3d %3d %7lu %7lu %10lu %10lu\n",
ifp->name, inet_ntoa(ifaddr), ifp->ifindex,
pim_ifp->mroute_vif_index, (unsigned long)vreq.icount,
(unsigned long)vreq.ocount, (unsigned long)vreq.ibytes,
json = json_object_new_object();
} else {
vty_out(vty,
- "Source Group Proto Input Output TTL Uptime\n");
+ "Source Group Proto Input Output TTL Uptime\n");
}
now = pim_time_monotonic_sec();
}
vty_out(vty,
- "%-15s %-15s %-6s %-10s %-10s %-3d %8s\n",
+ "%-15s %-15s %-6s %-16s %-16s %-3d %8s\n",
src_str, grp_str, proto, in_ifname,
out_ifname, ttl, oif_uptime);
}
if (!uj && !found_oif) {
- vty_out(vty, "%-15s %-15s %-6s %-10s %-10s %-3d %8s\n",
+ vty_out(vty, "%-15s %-15s %-6s %-16s %-16s %-3d %8s\n",
src_str, grp_str, "none", in_ifname, "none", 0,
"--:--:--");
}
json_ifp_out);
} else {
vty_out(vty,
- "%-15s %-15s %-6s %-10s %-10s %-3d %8s %s\n",
+ "%-15s %-15s %-6s %-16s %-16s %-3d %8s %s\n",
src_str, grp_str, proto, in_ifname,
out_ifname, ttl, oif_uptime,
pim->vrf->name);
if (!uj && !found_oif) {
vty_out(vty,
- "%-15s %-15s %-6s %-10s %-10s %-3d %8s %s\n",
+ "%-15s %-15s %-6s %-16s %-16s %-3d %8s %s\n",
src_str, grp_str, proto, in_ifname, "none", 0,
"--:--:--", pim->vrf->name);
}
json = json_object_new_object();
else
vty_out(vty,
- "RP address group/prefix-list OIF I am RP\n");
+ "RP address group/prefix-list OIF I am RP\n");
for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
if (!pim_rpf_addr_is_inaddr_none(&rp_info->rp)) {
48));
if (rp_info->rp.source_nexthop.interface)
- vty_out(vty, "%-10s ",
+ vty_out(vty, "%-16s ",
rp_info->rp.source_nexthop
.interface->name);
else
- vty_out(vty, "%-10s ", "(Unknown)");
+ vty_out(vty, "%-16s ", "(Unknown)");
if (rp_info->i_am_rp)
vty_out(vty, "yes\n");
if (!if_is_operative(ifp))
pim_if_addr_del_all(ifp);
+ if_set_index(ifp, IFINDEX_INTERNAL);
+
return 0;
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
return 0;
+ if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
+ return 0;
+
nexthop = api.nexthops[0].gate.ipv6;
ifindex = api.nexthops[0].ifindex;
!
hostname r1
!
-debug zebra rib
+debug zebra kernel
+debug zebra rib detailed
+debug zebra dplane detailed
debug zebra nht
debug zebra pseudowires
-debug zebra packet
+debug zebra mpls
!
interface lo
ip address 1.1.1.1/32
!
hostname r2
!
-debug zebra rib
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
debug zebra nht
debug zebra pseudowires
-debug zebra packet
!
interface lo
ip address 2.2.2.2/32
!
hostname r3
!
-debug zebra rib
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
debug zebra nht
debug zebra pseudowires
-debug zebra packet
!
interface lo
ip address 3.3.3.3/32
os.system('chmod -R go+rw /tmp/topotests')
# Open router log file
- logfile = '{0}/{1}.log'.format(dir, name)
-
+ logfile = '{0}/{1}.log'.format(self.logdir, name)
self.logger = logger_config.get_logger(name=name, target=logfile)
+
self.tgen.topo.addNode(self.name, cls=self.cls, **params)
def __str__(self):
def __str__(self):
return '\n'.join(self.errors)
-def get_test_logdir(node=None, init=False):
- """
- Return the current test log directory based on PYTEST_CURRENT_TEST
- environment variable.
- Optional paramters:
- node: when set, adds the node specific log directory to the init dir
- init: when set, initializes the log directory and fixes path permissions
- """
- cur_test = os.environ['PYTEST_CURRENT_TEST']
-
- ret = '/tmp/topotests/' + cur_test[0:cur_test.find(".py")].replace('/','.')
- if node != None:
- dir = ret + "/" + node
- if init:
- os.system('mkdir -p ' + dir)
- os.system('chmod -R go+rw /tmp/topotests')
- return ret
def json_diff(d1, d2):
"""
def __init__(self, name, **params):
super(Router, self).__init__(name, **params)
- self.logdir = params.get('logdir', get_test_logdir(name, True))
+ self.logdir = params.get('logdir')
+
+ # If this topology is using old API and doesn't have logdir
+ # specified, then attempt to generate an unique logdir.
+ if self.logdir is None:
+ cur_test = os.environ['PYTEST_CURRENT_TEST']
+ self.logdir = ('/tmp/topotests/' +
+ cur_test[0:cur_test.find(".py")].replace('/', '.'))
+
+ # If the logdir is not created, then create it and set the
+ # appropriated permissions.
+ if not os.path.isdir(self.logdir):
+ os.system('mkdir -p ' + self.logdir + '/' + name)
+ os.system('chmod -R go+rw /tmp/topotests')
+
self.daemondir = None
self.hasmpls = False
self.routertype = 'frr'
ifp->vrf_id, ifp->name,
prefix2str(&p, buf, sizeof(buf)));
}
- mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id));
+ mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), &p);
}
}
ifp->vrf_id, ifp->name,
prefix2str(&p, buf, sizeof(buf)));
}
- mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id));
+ mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), &p);
}
}
ifp->vrf_id, ifp->name,
prefix2str(p, buf, sizeof(buf)));
}
- mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id));
+ mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), p);
}
}
if (IS_ZEBRA_DEBUG_FPM)
vty_out(vty, " Zebra FPM debugging is on\n");
- if (IS_ZEBRA_DEBUG_NHT)
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ vty_out(vty, " Zebra detailed next-hop tracking debugging is on\n");
+ else if (IS_ZEBRA_DEBUG_NHT)
vty_out(vty, " Zebra next-hop tracking debugging is on\n");
if (IS_ZEBRA_DEBUG_MPLS)
vty_out(vty, " Zebra MPLS debugging is on\n");
DEFUN (debug_zebra_nht,
debug_zebra_nht_cmd,
- "debug zebra nht",
+ "debug zebra nht [detailed]",
DEBUG_STR
"Zebra configuration\n"
- "Debug option set for zebra next hop tracking\n")
+ "Debug option set for zebra next hop tracking\n"
+ "Debug option set for detailed info\n")
{
+ int idx = 0;
+
zebra_debug_nht = ZEBRA_DEBUG_NHT;
+
+ if (argv_find(argv, argc, "detailed", &idx))
+ zebra_debug_nht |= ZEBRA_DEBUG_NHT_DETAILED;
+
return CMD_SUCCESS;
}
DEFUN (no_debug_zebra_nht,
no_debug_zebra_nht_cmd,
- "no debug zebra nht",
+ "no debug zebra nht [detailed]",
NO_STR
DEBUG_STR
"Zebra configuration\n"
- "Debug option set for zebra next hop tracking\n")
+ "Debug option set for zebra next hop tracking\n"
+ "Debug option set for detailed info\n")
{
zebra_debug_nht = 0;
return CMD_SUCCESS;
vty_out(vty, "debug zebra fpm\n");
write++;
}
- if (IS_ZEBRA_DEBUG_NHT) {
+
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ vty_out(vty, "debug zebra nht detailed\n");
+ write++;
+ } else if (IS_ZEBRA_DEBUG_NHT) {
vty_out(vty, "debug zebra nht\n");
write++;
}
+
if (IS_ZEBRA_DEBUG_MPLS) {
vty_out(vty, "debug zebra mpls\n");
write++;
zebra_debug_pw = 0;
zebra_debug_dplane = 0;
zebra_debug_mlag = 0;
+ zebra_debug_nht = 0;
install_node(&debug_node, config_write_debug);
#define ZEBRA_DEBUG_RIB_DETAILED 0x02
#define ZEBRA_DEBUG_FPM 0x01
-#define ZEBRA_DEBUG_NHT 0x01
+
+#define ZEBRA_DEBUG_NHT 0x01
+#define ZEBRA_DEBUG_NHT_DETAILED 0x02
#define ZEBRA_DEBUG_MPLS 0x01
#define IS_ZEBRA_DEBUG_RIB_DETAILED (zebra_debug_rib & ZEBRA_DEBUG_RIB_DETAILED)
#define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM)
+
#define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT)
+#define IS_ZEBRA_DEBUG_NHT_DETAILED (zebra_debug_nht & ZEBRA_DEBUG_NHT_DETAILED)
+
#define IS_ZEBRA_DEBUG_MPLS (zebra_debug_mpls & ZEBRA_DEBUG_MPLS)
#define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN)
#define IS_ZEBRA_DEBUG_PW (zebra_debug_pw & ZEBRA_DEBUG_PW)
for (ALL_LIST_ELEMENTS(zrouter.client_list, ln, nn, client))
zserv_close_client(client);
+ zserv_close();
list_delete_all_node(zrouter.client_list);
+
zebra_ptm_finish();
if (retain_mode)
*/
uint32_t flags;
+ /*
+ * The list of nht prefixes that have ended up
+ * depending on this route node.
+ * After route processing is returned from
+ * the data plane we will run evaluate_rnh
+ * on these prefixes.
+ */
+ struct list *nht;
+
/*
* Linkage to put dest on the FPM processing queue.
*/
*/
#define RIB_DEST_UPDATE_FPM (1 << (ZEBRA_MAX_QINDEX + 2))
+#define RIB_DEST_UPDATE_LSPS (1 << (ZEBRA_MAX_QINDEX + 3))
+
/*
* Macro to iterate over each route for a destination (prefix).
*/
extern uint8_t route_distance(int type);
+extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq);
+
/*
* Inline functions.
*/
return rib_table_info(rib_dest_table(dest))->zvrf;
}
+/*
+ * Create the rib_dest_t and attach it to the specified node
+ */
+extern rib_dest_t *zebra_rib_create_dest(struct route_node *rn);
+
/*
* rib_tables_iter_init
*/
extern "C" {
#endif
+#define RSYSTEM_ROUTE(type) \
+ ((type) == ZEBRA_ROUTE_KERNEL || (type) == ZEBRA_ROUTE_CONNECT)
+
/*
* Update or delete a route, LSP, or pseudowire from the kernel,
* using info from a dataplane context.
* of the route delete. If that happens yeah we're
* screwed.
*/
- (void)netlink_route_multipath(RTM_DELROUTE, ctx);
+ if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
+ (void)netlink_route_multipath(RTM_DELROUTE,
+ ctx);
cmd = RTM_NEWROUTE;
}
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
- ret = netlink_route_multipath(cmd, ctx);
+ if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)))
+ ret = netlink_route_multipath(cmd, ctx);
+ else
+ ret = 0;
if ((cmd == RTM_NEWROUTE) && (ret == 0)) {
/* Update installed nexthops to signal which have been
* installed.
enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
{
enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ uint32_t type, old_type;
if (dplane_ctx_get_src(ctx) != NULL) {
zlog_err("route add: IPv6 sourcedest routes unsupported!");
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
+ type = dplane_ctx_get_type(ctx);
+ old_type = dplane_ctx_get_old_type(ctx);
+
frr_elevate_privs(&zserv_privs) {
- if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE)
- kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
- dplane_ctx_get_ng(ctx),
- dplane_ctx_get_metric(ctx));
- else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL)
- kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
- dplane_ctx_get_ng(ctx),
- dplane_ctx_get_metric(ctx));
- else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) {
+ if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
+ if (!RSYSTEM_ROUTE(type))
+ kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
+ dplane_ctx_get_ng(ctx),
+ dplane_ctx_get_metric(ctx));
+ } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) {
+ if (!RSYSTEM_ROUTE(type))
+ kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
+ dplane_ctx_get_ng(ctx),
+ dplane_ctx_get_metric(ctx));
+ } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) {
/* Must do delete and add separately -
* no update available
*/
- kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
- dplane_ctx_get_old_ng(ctx),
- dplane_ctx_get_old_metric(ctx));
-
- kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
- dplane_ctx_get_ng(ctx),
- dplane_ctx_get_metric(ctx));
+ if (!RSYSTEM_ROUTE(old_type))
+ kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
+ dplane_ctx_get_old_ng(ctx),
+ dplane_ctx_get_old_metric(ctx));
+
+ if (!RSYSTEM_ROUTE(type))
+ kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
+ dplane_ctx_get_ng(ctx),
+ dplane_ctx_get_metric(ctx));
} else {
zlog_err("Invalid routing socket update op %s (%u)",
dplane_op2str(dplane_ctx_get_op(ctx)),
}
} /* Elevated privs */
+ if (RSYSTEM_ROUTE(type)
+ && dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE) {
+ struct nexthop *nexthop;
+
+ for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ continue;
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
+ }
+ }
+
return res;
}
uint8_t flags = 0;
uint16_t type = cmd2type[hdr->command];
bool exist;
+ bool flag_changed = false;
+ uint8_t orig_flags;
if (IS_ZEBRA_DEBUG_NHT)
zlog_debug(
if (!rnh)
return;
+ orig_flags = rnh->flags;
if (type == RNH_NEXTHOP_TYPE) {
if (flags
&& !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
UNSET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH);
}
+ if (orig_flags != rnh->flags)
+ flag_changed = true;
+
zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf));
/* Anything not AF_INET/INET6 has been filtered out above */
- if (!exist)
+ if (!exist || flag_changed)
zebra_evaluate_rnh(zvrf, family2afi(p.family), 1, type,
&p);
}
return "Unknown";
}
-static inline void mpls_mark_lsps_for_processing(struct zebra_vrf *zvrf)
+static inline void mpls_mark_lsps_for_processing(struct zebra_vrf *zvrf,
+ struct prefix *p)
{
+ struct route_table *table;
+ struct route_node *rn;
+ rib_dest_t *dest;
+
if (!zvrf)
return;
- zvrf->mpls_flags |= MPLS_FLAG_SCHEDULE_LSPS;
+ table = zvrf->table[family2afi(p->family)][SAFI_UNICAST];
+ if (!table)
+ return;
+
+ rn = route_node_match(table, p);
+ if (!rn)
+ return;
+
+
+ dest = rib_dest_from_rnode(rn);
+ SET_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS);
}
-static inline void mpls_unmark_lsps_for_processing(struct zebra_vrf *zvrf)
+static inline void mpls_unmark_lsps_for_processing(struct route_node *rn)
{
- if (!zvrf)
- return;
+ rib_dest_t *dest = rib_dest_from_rnode(rn);
- zvrf->mpls_flags &= ~MPLS_FLAG_SCHEDULE_LSPS;
+ UNSET_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS);
}
-static inline int mpls_should_lsps_be_processed(struct zebra_vrf *zvrf)
+static inline int mpls_should_lsps_be_processed(struct route_node *rn)
{
- if (!zvrf)
- return 0;
+ rib_dest_t *dest = rib_dest_from_rnode(rn);
- return ((zvrf->mpls_flags & MPLS_FLAG_SCHEDULE_LSPS) ? 1 : 0);
+ return !!CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS);
}
/* Global variables. */
if (zebra_rib_labeled_unicast(re))
zebra_mpls_lsp_uninstall(info->zvrf, rn, re);
- if (!RIB_SYSTEM_ROUTE(re))
- rib_uninstall_kernel(rn, re);
- else
- UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+ rib_uninstall_kernel(rn, re);
dest->selected_fib = NULL;
return 0;
}
+ /*
+ * Unresolved rnh's are stored on the default route's list
+ *
+ * dest->rnode can also be the source prefix node in an
+ * ipv6 sourcedest table. Fortunately the prefix of a
+ * source prefix node can never be the default prefix.
+ */
+ if (is_default_prefix(&dest->rnode->p))
+ return 0;
+
/*
* Don't delete the dest if we have to update the FPM about this
* prefix.
return 1;
}
+void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq)
+{
+ rib_dest_t *dest = rib_dest_from_rnode(rn);
+ struct listnode *node, *nnode;
+ struct rnh *rnh;
+
+ /*
+ * We are storing the rnh's associated withb
+ * the tracked nexthop as a list of the rn's.
+ * Unresolved rnh's are placed at the top
+ * of the tree list.( 0.0.0.0/0 for v4 and 0::0/0 for v6 )
+ * As such for each rn we need to walk up the tree
+ * and see if any rnh's need to see if they
+ * would match a more specific route
+ */
+ while (rn) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ char buf[PREFIX_STRLEN];
+
+ zlog_debug("%s: %s Being examined for Nexthop Tracking",
+ __PRETTY_FUNCTION__,
+ srcdest_rnode2str(rn, buf, sizeof(buf)));
+ }
+ if (!dest) {
+ rn = rn->parent;
+ if (rn)
+ dest = rib_dest_from_rnode(rn);
+ continue;
+ }
+ /*
+ * If we have any rnh's stored in the nht list
+ * then we know that this route node was used for
+ * nht resolution and as such we need to call the
+ * nexthop tracking evaluation code
+ */
+ for (ALL_LIST_ELEMENTS(dest->nht, node, nnode, rnh)) {
+ struct zebra_vrf *zvrf =
+ zebra_vrf_lookup_by_id(rnh->vrf_id);
+ struct prefix *p = &rnh->node->p;
+
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ char buf1[PREFIX_STRLEN];
+ char buf2[PREFIX_STRLEN];
+
+ zlog_debug("%u:%s has Nexthop(%s) depending on it, evaluating %u:%u",
+ zvrf->vrf->vrf_id,
+ srcdest_rnode2str(rn, buf1,
+ sizeof(buf1)),
+ prefix2str(p, buf2, sizeof(buf2)),
+ seq, rnh->seqno);
+ }
+
+ /*
+ * If we have evaluated this node on this pass
+ * already, due to following the tree up
+ * then we know that we can move onto the next
+ * rnh to process.
+ *
+ * Additionally we call zebra_evaluate_rnh
+ * when we gc the dest. In this case we know
+ * that there must be no other re's where
+ * we were originally as such we know that
+ * that sequence number is ok to respect.
+ */
+ if (rnh->seqno == seq) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tNode processed and moved already");
+ continue;
+ }
+
+ rnh->seqno = seq;
+ zebra_evaluate_rnh(zvrf, family2afi(p->family), 0,
+ rnh->type, p);
+ }
+
+ rn = rn->parent;
+ if (rn)
+ dest = rib_dest_from_rnode(rn);
+ }
+}
+
/*
* rib_gc_dest
*
rnode_debug(rn, zvrf_id(zvrf), "removing dest from table");
}
+ zebra_rib_evaluate_rn_nexthops(rn, zebra_router_get_next_sequence());
+
dest->rnode = NULL;
+ list_delete(&dest->nht);
XFREE(MTYPE_RIB_DEST, dest);
rn->info = NULL;
static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
struct route_entry *new)
{
- rib_dest_t *dest = rib_dest_from_rnode(rn);
-
hook_call(rib_update, rn, "new route selected");
/* Update real nexthop. This may actually determine if nexthop is active
if (zebra_rib_labeled_unicast(new))
zebra_mpls_lsp_install(zvrf, rn, new);
- if (!RIB_SYSTEM_ROUTE(new))
- rib_install_kernel(rn, new, NULL);
- else
- dest->selected_fib = new;
+ rib_install_kernel(rn, new, NULL);
UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED);
}
static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
struct route_entry *old)
{
- rib_dest_t *dest = rib_dest_from_rnode(rn);
hook_call(rib_update, rn, "removing existing route");
/* Uninstall from kernel. */
if (zebra_rib_labeled_unicast(old))
zebra_mpls_lsp_uninstall(zvrf, rn, old);
- 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
- * have been doing. I am not positive
- * that this is the right thing to do
- * but let's leave the code alone
- * for the RIB_SYSTEM_ROUTE case
- */
- dest->selected_fib = NULL;
- }
+ rib_uninstall_kernel(rn, old);
/* Update nexthop for route, reset changed flag. */
/* Note: this code also handles the Linux case when an interface goes
struct route_entry *old,
struct route_entry *new)
{
- struct nexthop *nexthop = NULL;
int nh_active = 0;
- rib_dest_t *dest = rib_dest_from_rnode(rn);
/*
* We have to install or update if a new route has been selected or
if (zebra_rib_labeled_unicast(old))
zebra_mpls_lsp_uninstall(zvrf, rn, old);
- /* Non-system route should be installed. */
- if (!RIB_SYSTEM_ROUTE(new)) {
- /* If labeled-unicast route, install transit
- * LSP. */
- if (zebra_rib_labeled_unicast(new))
- zebra_mpls_lsp_install(zvrf, rn, new);
+ /*
+ * Non-system route should be installed.
+ * If labeled-unicast route, install transit
+ * LSP.
+ */
+ if (zebra_rib_labeled_unicast(new))
+ zebra_mpls_lsp_install(zvrf, rn, new);
- 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
- * is already isntalled by
- * the system( ie not us )
- * so just mark it as winning
- * we do need to ensure that
- * if we uninstall a route
- * from ourselves we don't
- * over write this pointer
- */
- dest->selected_fib = new;
- }
- /* If install succeeded or system route, cleanup flags
- * for prior route. */
- if (new != old) {
- 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,
- NEXTHOP_FLAG_FIB);
- }
- }
+ rib_install_kernel(rn, new, old);
}
/*
if (zebra_rib_labeled_unicast(old))
zebra_mpls_lsp_uninstall(zvrf, rn, old);
- if (!RIB_SYSTEM_ROUTE(old))
- rib_uninstall_kernel(rn, old);
- else {
- UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED);
- dest->selected_fib = NULL;
- }
+ rib_uninstall_kernel(rn, old);
}
} else {
/*
* Same route selected; check if in the FIB and if not,
- * re-install. This
- * is housekeeping code to deal with race conditions in kernel
- * with linux
- * netlink reporting interface up before IPv4 or IPv6 protocol
- * is ready
+ * re-install. This is housekeeping code to deal with
+ * race conditions in kernel with linux netlink reporting
+ * interface up before IPv4 or IPv6 protocol is ready
* to add routes.
*/
- if (!RIB_SYSTEM_ROUTE(new)
- && !CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED))
+ if (!CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED) ||
+ RIB_SYSTEM_ROUTE(new))
rib_install_kernel(rn, new, NULL);
}
UNSET_FLAG(new_selected->status, ROUTE_ENTRY_CHANGED);
}
- if (new_selected) {
+ if (new_selected)
SET_FLAG(new_selected->flags, ZEBRA_FLAG_SELECTED);
- /* Special case: new route is system route, so
- * dataplane update will not be done - ensure we
- * redistribute the route.
- */
- if (RIB_SYSTEM_ROUTE(new_selected))
- redistribute_update(p, src_p, new_selected,
- old_selected);
- }
-
if (old_selected) {
if (!new_selected)
redistribute_delete(p, src_p, old_selected);
rib_gc_dest(rn);
}
+static void zebra_rib_evaluate_mpls(struct route_node *rn)
+{
+ rib_dest_t *dest = rib_dest_from_rnode(rn);
+ struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
+
+ if (!dest)
+ return;
+
+ if (CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS)) {
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug(
+ "%u: Scheduling all LSPs upon RIB completion",
+ zvrf_id(zvrf));
+ zebra_mpls_lsp_schedule(zvrf);
+ mpls_unmark_lsps_for_processing(rn);
+ }
+}
+
/*
* Utility to match route with dplane context data
*/
return (result);
}
+static void zebra_rib_fixup_system(struct route_node *rn)
+{
+ struct route_entry *re;
+
+ RNODE_FOREACH_RE(rn, re) {
+ struct nexthop *nhop;
+
+ if (!RIB_SYSTEM_ROUTE(re))
+ continue;
+
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
+ continue;
+
+ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+
+ for (ALL_NEXTHOPS(re->ng, nhop)) {
+ if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE))
+ continue;
+
+ SET_FLAG(nhop->flags, NEXTHOP_FLAG_FIB);
+ }
+ }
+}
+
/*
* Route-update results processing after async dataplane update.
*/
enum dplane_op_e op;
enum zebra_dplane_result status;
const struct prefix *dest_pfx, *src_pfx;
+ uint32_t seq;
/* Locate rn and re(s) from ctx */
break;
}
+ seq = dplane_ctx_get_seq(ctx);
+
/*
* Check sequence number(s) to detect stale results before continuing
*/
if (re) {
- if (re->dplane_sequence != dplane_ctx_get_seq(ctx)) {
+ if (re->dplane_sequence != seq) {
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
zlog_debug("%u:%s Stale dplane result for re %p",
dplane_ctx_get_vrf(ctx),
dplane_ctx_get_vrf(ctx),
dest_str, old_re);
} else
- UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+ UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED);
}
switch (op) {
NEXTHOP_FLAG_FIB);
}
+ /*
+ * System routes are weird in that they
+ * allow multiple to be installed that match
+ * to the same prefix, so after we get the
+ * result we need to clean them up so that
+ * we can actually use them.
+ */
+ if ((re && RIB_SYSTEM_ROUTE(re)) ||
+ (old_re && RIB_SYSTEM_ROUTE(old_re)))
+ zebra_rib_fixup_system(rn);
+
if (zvrf) {
zvrf->installs++;
/* Set flag for nexthop tracking processing */
zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED);
} else {
- if (re)
+ if (re) {
SET_FLAG(re->status, ROUTE_ENTRY_FAILED);
- if (old_re)
+ UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+ } if (old_re)
SET_FLAG(old_re->status, ROUTE_ENTRY_FAILED);
if (re)
zsend_route_notify_owner(re, dest_pfx,
prefix2str(dest_pfx,
dest_str, sizeof(dest_str)));
}
+
+ /*
+ * System routes are weird in that they
+ * allow multiple to be installed that match
+ * to the same prefix, so after we get the
+ * result we need to clean them up so that
+ * we can actually use them.
+ */
+ if ((re && RIB_SYSTEM_ROUTE(re)) ||
+ (old_re && RIB_SYSTEM_ROUTE(old_re)))
+ zebra_rib_fixup_system(rn);
break;
default:
break;
}
+
+ zebra_rib_evaluate_rn_nexthops(rn, seq);
+ zebra_rib_evaluate_mpls(rn);
done:
if (rn)
return 1;
}
+
/*
* Perform next-hop tracking processing after RIB updates.
*/
static void do_nht_processing(void)
{
- struct vrf *vrf;
- struct zebra_vrf *zvrf;
-
- /* Evaluate nexthops for those VRFs which underwent route processing.
- * This
- * should limit the evaluation to the necessary VRFs in most common
- * situations.
- */
- RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
- zvrf = vrf->info;
- if (zvrf == NULL || !(zvrf->flags & ZEBRA_VRF_RIB_SCHEDULED))
- continue;
-
- if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHT)
- zlog_debug("NHT processing check for zvrf %s",
- zvrf_name(zvrf));
-
- zvrf->flags &= ~ZEBRA_VRF_RIB_SCHEDULED;
- 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, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL);
- zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_IMPORT_CHECK_TYPE,
- NULL);
- }
-
- /* Schedule LSPs for processing, if needed. */
- zvrf = vrf_info_lookup(VRF_DEFAULT);
- if (mpls_should_lsps_be_processed(zvrf)) {
- if (IS_ZEBRA_DEBUG_MPLS)
- zlog_debug(
- "%u: Scheduling all LSPs upon RIB completion",
- zvrf_id(zvrf));
- zebra_mpls_lsp_schedule(zvrf);
- mpls_unmark_lsps_for_processing(zvrf);
- }
}
/* Dispatch the meta queue by picking, processing and unlocking the next RN from
return;
}
+rib_dest_t *zebra_rib_create_dest(struct route_node *rn)
+{
+ rib_dest_t *dest;
+
+ dest = XCALLOC(MTYPE_RIB_DEST, sizeof(rib_dest_t));
+ dest->nht = list_new();
+ route_lock_node(rn); /* rn route table reference */
+ rn->info = dest;
+ dest->rnode = rn;
+
+ return dest;
+}
+
/* RIB updates are processed via a queue of pointers to route_nodes.
*
* The queue length is bounded by the maximal size of the routing table,
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
rnode_debug(rn, re->vrf_id, "rn %p adding dest", rn);
- dest = XCALLOC(MTYPE_RIB_DEST, sizeof(rib_dest_t));
- route_lock_node(rn); /* rn route table reference */
- rn->info = dest;
- dest->rnode = rn;
+ dest = zebra_rib_create_dest(rn);
}
head = dest->routes;
* revalidation
* of the rest of the RE.
*/
- if (dest->selected_fib && !RIB_SYSTEM_ROUTE(dest->selected_fib)) {
+ if (dest->selected_fib) {
changed = 1;
if (IS_ZEBRA_DEBUG_RIB) {
char buf[PREFIX_STRLEN];
struct route_table *table;
struct route_node *rn;
struct route_entry *same = NULL;
- struct nexthop *nexthop;
int ret = 0;
if (!re)
break;
}
- /* If this route is kernel route, set FIB flag to the route. */
- 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,
if (info->safi == SAFI_UNICAST)
hook_call(rib_update, rn, NULL);
- if (!RIB_SYSTEM_ROUTE(dest->selected_fib)) {
- rib_uninstall_kernel(rn, dest->selected_fib);
- dest->selected_fib = NULL;
- }
+ rib_uninstall_kernel(rn, dest->selected_fib);
+ dest->selected_fib = NULL;
}
}
}
return buf;
}
+static void zebra_rnh_remove_from_routing_table(struct rnh *rnh)
+{
+ struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id);
+ struct route_table *table = zvrf->table[rnh->afi][SAFI_UNICAST];
+ struct route_node *rn;
+ rib_dest_t *dest;
+
+ if (!table)
+ return;
+
+ rn = route_node_match(table, &rnh->resolved_route);
+ if (!rn)
+ return;
+
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ char buf[PREFIX_STRLEN];
+ char buf1[PREFIX_STRLEN];
+
+ zlog_debug("%s: %u:%s removed from tracking on %s",
+ __PRETTY_FUNCTION__, rnh->vrf_id,
+ prefix2str(&rnh->node->p, buf, sizeof(buf)),
+ srcdest_rnode2str(rn, buf1, sizeof(buf)));
+ }
+
+ dest = rib_dest_from_rnode(rn);
+ listnode_delete(dest->nht, rnh);
+ route_unlock_node(rn);
+}
+
+static void zebra_rnh_store_in_routing_table(struct rnh *rnh)
+{
+ struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id);
+ struct route_table *table = zvrf->table[rnh->afi][SAFI_UNICAST];
+ struct route_node *rn;
+ rib_dest_t *dest;
+
+ rn = route_node_match(table, &rnh->resolved_route);
+ if (!rn)
+ return;
+
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ char buf[PREFIX_STRLEN];
+ char buf1[PREFIX_STRLEN];
+
+ zlog_debug("%s: %u:%s added for tracking on %s",
+ __PRETTY_FUNCTION__, rnh->vrf_id,
+ prefix2str(&rnh->node->p, buf, sizeof(buf)),
+ srcdest_rnode2str(rn, buf1, sizeof(buf)));
+ }
+
+ dest = rib_dest_from_rnode(rn);
+ listnode_add(dest->nht, rnh);
+ route_unlock_node(rn);
+}
+
struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
bool *exists)
{
struct route_node *rn;
struct rnh *rnh = NULL;
char buf[PREFIX2STR_BUFFER];
+ afi_t afi = family2afi(p->family);
if (IS_ZEBRA_DEBUG_NHT) {
prefix2str(p, buf, sizeof(buf));
zlog_debug("%u: Add RNH %s type %d", vrfid, buf, type);
}
- table = get_rnh_table(vrfid, family2afi(PREFIX_FAMILY(p)), type);
+ table = get_rnh_table(vrfid, afi, type);
if (!table) {
prefix2str(p, buf, sizeof(buf));
flog_warn(EC_ZEBRA_RNH_NO_TABLE,
if (!rn->info) {
rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
+
+ /*
+ * The resolved route is already 0.0.0.0/0 or
+ * 0::0/0 due to the calloc right above, but
+ * we should set the family so that future
+ * comparisons can just be done
+ */
+ rnh->resolved_route.family = p->family;
rnh->client_list = list_new();
rnh->vrf_id = vrfid;
+ rnh->type = type;
+ rnh->seqno = 0;
+ rnh->afi = afi;
rnh->zebra_pseudowire_list = list_new();
route_lock_node(rn);
rn->info = rnh;
rnh->node = rn;
*exists = false;
+
+ zebra_rnh_store_in_routing_table(rnh);
} else
*exists = true;
void zebra_free_rnh(struct rnh *rnh)
{
+ struct zebra_vrf *zvrf;
+ struct route_table *table;
+
+ zebra_rnh_remove_from_routing_table(rnh);
rnh->flags |= ZEBRA_NHT_DELETED;
list_delete(&rnh->client_list);
list_delete(&rnh->zebra_pseudowire_list);
+
+ zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id);
+ table = zvrf->table[family2afi(rnh->resolved_route.family)][SAFI_UNICAST];
+
+ if (table) {
+ struct route_node *rern;
+
+ rern = route_node_match(table, &rnh->resolved_route);
+ if (rern) {
+ rib_dest_t *dest;
+
+ route_unlock_node(rern);
+
+ dest = rib_dest_from_rnode(rern);
+ listnode_delete(dest->nht, rnh);
+ }
+ }
free_state(rnh->vrf_id, rnh->state, rnh->node);
XFREE(MTYPE_RNH, rnh);
}
&& !prefix_same(&nrn->p, &rn->p))
return NULL;
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ char buf[PREFIX_STRLEN];
+ char buf1[PREFIX_STRLEN];
+
+ zlog_debug("%s: %u:%s Resolved Import Entry to %s",
+ __PRETTY_FUNCTION__, rnh->vrf_id,
+ prefix2str(&rnh->node->p, buf, sizeof(buf)),
+ srcdest_rnode2str(rn, buf1, sizeof(buf)));
+ }
+
/* Identify appropriate route entry. */
RNODE_FOREACH_RE (rn, re) {
if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)
if (re)
*prn = rn;
+
+ if (!re && IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug("\tRejected due to removed or is a bgp route");
+
return re;
}
* 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, afi_t afi,
+static void zebra_rnh_eval_import_check_entry(struct zebra_vrf *zvrf, afi_t afi,
int force, struct route_node *nrn,
struct rnh *rnh,
+ struct route_node *prn,
struct route_entry *re)
{
int state_changed = 0;
char bufn[INET6_ADDRSTRLEN];
struct listnode *node;
+ zebra_rnh_remove_from_routing_table(rnh);
+ if (prn) {
+ prefix_copy(&rnh->resolved_route, &prn->p);
+ } else {
+ int family = rnh->resolved_route.family;
+
+ memset(&rnh->resolved_route.family, 0, sizeof(struct prefix));
+ rnh->resolved_route.family = family;
+ }
+ zebra_rnh_store_in_routing_table(rnh);
+
if (re && (rnh->state == NULL)) {
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
state_changed = 1;
} else if (!re && (rnh->state != NULL))
state_changed = 1;
- if (compare_state(re, rnh->state))
+ if (compare_state(re, rnh->state)) {
copy_state(rnh, re, nrn);
+ state_changed = 1;
+ }
if (state_changed || force) {
if (IS_ZEBRA_DEBUG_NHT) {
prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
- zlog_debug("%u:%s: Route import check %s %s", vrfid,
+ zlog_debug("%u:%s: Route import check %s %s",
+ zvrf->vrf->vrf_id,
bufn, rnh->state ? "passed" : "failed",
state_changed ? "(state changed)" : "");
}
/* state changed, notify clients */
for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
- send_client(rnh, client, RNH_IMPORT_CHECK_TYPE, vrfid);
+ send_client(rnh, client,
+ RNH_IMPORT_CHECK_TYPE, zvrf->vrf->vrf_id);
}
}
}
if (IS_ZEBRA_DEBUG_NHT) {
prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
if (prn && re) {
- prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
+ srcdest_rnode2str(prn, bufp, INET6_ADDRSTRLEN);
zlog_debug("%u:%s: NH resolved over route %s",
zvrf->vrf->vrf_id, bufn, bufp);
} else
* most-specific match. Do similar logic as in zebra_rib.c
*/
while (rn) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+ char buf[PREFIX_STRLEN];
+ char buf1[PREFIX_STRLEN];
+
+ zlog_debug("%s: %u:%s Possible Match to %s",
+ __PRETTY_FUNCTION__, rnh->vrf_id,
+ prefix2str(&rnh->node->p, buf, sizeof(buf)),
+ srcdest_rnode2str(rn, buf1, sizeof(buf)));
+ }
+
/* Do not resolve over default route unless allowed &&
* match route to be exact if so specified
*/
if (is_default_prefix(&rn->p)
- && !rnh_resolve_via_default(rn->p.family))
+ && !rnh_resolve_via_default(rn->p.family)) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tNot allowed to resolve through default prefix");
return NULL;
+ }
/* Identify appropriate route entry. */
RNODE_FOREACH_RE (rn, re) {
- if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tRoute Entry %s removed",
+ zebra_route_string(re->type));
continue;
- if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
+ }
+ if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tRoute Entry %s !selected",
+ zebra_route_string(re->type));
continue;
+ }
/* Just being SELECTED isn't quite enough - must
* have an installed nexthop to be useful.
break;
}
- if (nexthop == NULL)
+ if (nexthop == NULL) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tRoute Entry %s no nexthops",
+ zebra_route_string(re->type));
continue;
+ }
if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) {
if ((re->type == ZEBRA_ROUTE_CONNECT)
return re;
}
- if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
+ if (!CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
rn = rn->parent;
- else
+ else {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tNexthop must be connected, cannot recurse up");
return NULL;
+ }
}
return NULL;
* the resolving route has some change (e.g., metric), there is a state
* change.
*/
- if (!prefix_same(&rnh->resolved_route, &prn->p)) {
+ zebra_rnh_remove_from_routing_table(rnh);
+ if (!prefix_same(&rnh->resolved_route, prn ? NULL : &prn->p)) {
if (prn)
prefix_copy(&rnh->resolved_route, &prn->p);
- else
+ else {
+ /*
+ * Just quickly store the family of the resolved
+ * route so that we can reset it in a second here
+ */
+ int family = rnh->resolved_route.family;
+
memset(&rnh->resolved_route, 0, sizeof(struct prefix));
+ rnh->resolved_route.family = family;
+ }
copy_state(rnh, re, nrn);
state_changed = 1;
copy_state(rnh, re, nrn);
state_changed = 1;
}
+ zebra_rnh_store_in_routing_table(rnh);
if (state_changed || force) {
/* NOTE: Use the "copy" of resolving route stored in 'rnh' i.e.,
/* Process based on type of entry. */
if (type == RNH_IMPORT_CHECK_TYPE)
- zebra_rnh_eval_import_check_entry(zvrf->vrf->vrf_id, afi, force,
- nrn, rnh, re);
+ zebra_rnh_eval_import_check_entry(zvrf, afi, force, nrn, rnh,
+ prn, re);
else
zebra_rnh_eval_nexthop_entry(zvrf, afi, force, nrn, rnh, prn,
re);
static void free_state(vrf_id_t vrf_id, struct route_entry *re,
struct route_node *rn)
{
-
if (!re)
return;
extern "C" {
#endif
+typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t;
+
/* Nexthop structure. */
struct rnh {
uint8_t flags;
/* VRF identifier. */
vrf_id_t vrf_id;
+ afi_t afi;
+
+ rnh_type_t type;
+
+ uint32_t seqno;
+
struct route_entry *state;
struct prefix resolved_route;
struct list *client_list;
int filtered[ZEBRA_ROUTE_MAX];
};
-typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t;
-
extern int zebra_rnh_ip_default_route;
extern int zebra_rnh_ipv6_default_route;
{
void *table_info;
- rib_close_table(zrt->table);
-
table_info = route_table_get_info(zrt->table);
route_table_finish(zrt->table);
RB_REMOVE(zebra_router_table_head, &zrouter.tables, zrt);
rib_unlink(node, re);
}
- XFREE(MTYPE_RIB_DEST, node->info);
+ if (node->info) {
+ rib_dest_t *dest = node->info;
+
+ list_delete(&dest->nht);
+ XFREE(MTYPE_RIB_DEST, node->info);
+ }
}
static void zebra_rnhtable_node_cleanup(struct route_table *table,
static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
safi_t safi)
{
+ struct route_node *rn;
+ struct prefix p;
+
assert(!zvrf->table[afi][safi]);
zvrf->table[afi][safi] =
zebra_router_get_table(zvrf, zvrf->table_id, afi, safi);
+
+ memset(&p, 0, sizeof(p));
+ p.family = afi2family(afi);
+
+ rn = srcdest_rnode_get(zvrf->table[afi][safi], &p, NULL);
+ zebra_rib_create_dest(rn);
}
/* Allocate new zebra VRF. */
return 0;
}
+void zserv_close(void)
+{
+ /*
+ * On shutdown, let's close the socket down
+ * so that long running processes of killing the
+ * routing table doesn't leave us in a bad
+ * state where a client tries to reconnect
+ */
+ close(zsock);
+ zsock = -1;
+}
+
void zserv_start(char *path)
{
int ret;
*/
extern void zserv_init(void);
+/*
+ * Stop the Zebra API server.
+ *
+ * closes the socket
+ */
+extern void zserv_close(void);
+
/*
* Start Zebra API server.
*