**/*.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.]
python/clidef.py \
python/clippy/__init__.py \
\
- redhat/frr.init \
- redhat/frr.service \
- redhat/daemons \
redhat/frr.logrotate \
redhat/frr.pam \
redhat/frr.spec \
- redhat/README.rpm_build.md \
\
snapcraft/snapcraft.yaml \
snapcraft/README.snap_build.md \
| 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
babel_interface_allocate (void)
{
babel_interface_nfo *babel_ifp;
- babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
- if(babel_ifp == NULL)
- return NULL;
-
- /* Here are set the default values for an interface. */
- memset(babel_ifp, 0, sizeof(babel_interface_nfo));
+ babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
/* All flags are unset */
babel_ifp->bucket_time = babel_now.tv_sec;
babel_ifp->bucket = BUCKET_TOKENS_MAX;
/*
* Prototypes
*/
-static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc);
+void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
+ struct sockaddr_any *local, bool mhop, const char *ifname,
+ const char *vrfname);
static uint32_t ptm_bfd_gen_ID(void);
static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd);
static void bs_init_handler(struct bfd_session *bs, int nstate);
static void bs_up_handler(struct bfd_session *bs, int nstate);
+/* Zeroed array with the size of an IPv6 address. */
+struct in6_addr zero_addr;
/*
* Functions
*/
-static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc)
+void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
+ struct sockaddr_any *local, bool mhop, const char *ifname,
+ const char *vrfname)
{
- 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;
+ memset(key, 0, sizeof(*key));
+ switch (peer->sa_sin.sin_family) {
+ case AF_INET:
+ key->family = AF_INET;
+ memcpy(&key->peer, &peer->sa_sin.sin_addr,
+ sizeof(peer->sa_sin.sin_addr));
+ memcpy(&key->local, &local->sa_sin.sin_addr,
+ sizeof(local->sa_sin.sin_addr));
+ break;
+ case AF_INET6:
+ key->family = AF_INET6;
+ memcpy(&key->peer, &peer->sa_sin6.sin6_addr,
+ sizeof(peer->sa_sin6.sin6_addr));
+ memcpy(&key->local, &local->sa_sin6.sin6_addr,
+ sizeof(local->sa_sin6.sin6_addr));
break;
}
- if (bso == NULL)
- bs = NULL;
- return bs;
+ key->mhop = mhop;
+ if (ifname && ifname[0])
+ strlcpy(key->ifname, ifname, sizeof(key->ifname));
+ if (vrfname && vrfname[0])
+ strlcpy(key->vrfname, vrfname, sizeof(key->vrfname));
}
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;
+ struct bfd_key key;
/* Try to find label first. */
if (bpc->bpc_has_label) {
}
/* Otherwise fallback to peer/local hash lookup. */
- if (bpc->bpc_mhop) {
- memset(&mhop, 0, sizeof(mhop));
- mhop.peer = bpc->bpc_peer;
- mhop.local = bpc->bpc_local;
- if (bpc->bpc_has_vrfname) {
- vrf = vrf_lookup_by_name(bpc->bpc_vrfname);
- if (vrf == NULL)
- return NULL;
-
- mhop.vrfid = vrf->vrf_id;
- }
+ gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop,
+ bpc->bpc_localif, bpc->bpc_vrfname);
- bs = bfd_mhop_lookup(mhop);
- } else {
- memset(&shop, 0, sizeof(shop));
- shop.peer = bpc->bpc_peer;
- 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);
- }
-
- if (bs != NULL)
- return bs;
-
- /* Search for entries that are incomplete. */
- return bs_peer_waiting_find(bpc);
+ return bfd_key_lookup(key);
}
/*
*/
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 (bs->key.ifname[0]) {
+ ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
if (ifp == NULL) {
log_error(
"session-enable: specified interface doesn't exists.");
vrf = vrf_lookup_by_id(ifp->vrf_id);
if (vrf == NULL) {
- log_error("session-enable: specified VRF doesn't exists.");
+ log_error(
+ "session-enable: specified VRF doesn't exists.");
return 0;
}
}
- if (bs->vrfname[0] != 0) {
- vrf = vrf_lookup_by_name(bs->vrfname);
+ if (bs->key.vrfname[0]) {
+ vrf = vrf_lookup_by_name(bs->key.vrfname);
if (vrf == NULL) {
- log_error("session-enable: specified VRF doesn't exists.");
+ log_error(
+ "session-enable: specified VRF doesn't exists.");
return 0;
}
}
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)
+ if (bs->key.ifname[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;
+ /* Sanity check: don't leak open sockets. */
+ if (bs->sock != -1) {
+ zlog_debug("session-enable: previous socket open");
+ close(bs->sock);
+ bs->sock = -1;
}
/*
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) {
psock = bp_peer_socket(bs);
if (psock == -1)
- return -1;
+ return 0;
} else {
psock = bp_peer_socketv6(bs);
if (psock == -1)
- return -1;
+ return 0;
}
/*
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;
}
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)
if (bs == NULL)
return NULL;
- /* Remove unused fields. */
- switch (sa->sa_sin.sin_family) {
+ switch (bs->key.family) {
case AF_INET:
- sa->sa_sin.sin_port = 0;
- if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin)) == 0)
- return bs;
+ if (memcmp(&sa->sa_sin.sin_addr, &bs->key.peer,
+ sizeof(sa->sa_sin.sin_addr)))
+ return NULL;
break;
case AF_INET6:
- sa->sa_sin6.sin6_port = 0;
- if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin6)) == 0)
- return bs;
+ if (memcmp(&sa->sa_sin6.sin6_addr, &bs->key.peer,
+ sizeof(sa->sa_sin6.sin6_addr)))
+ return NULL;
break;
}
- return NULL;
+ return bs;
}
struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
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;
+ struct interface *ifp;
+ struct vrf *vrf;
+ struct bfd_key key;
/* Find our session using the ID signaled by the remote end. */
if (cp->discrs.remote_discr)
return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr));
/* Search for session without using discriminator. */
- if (is_mhop) {
- memset(&mhop, 0, sizeof(mhop));
- mhop.peer = *peer;
- mhop.local = *local;
- mhop.vrfid = vrfid;
-
- l_bfd = bfd_mhop_lookup(mhop);
- } else {
- memset(&shop, 0, sizeof(shop));
- shop.peer = *peer;
- shop.ifindex = ifindex;
+ ifp = if_lookup_by_index(ifindex, vrfid);
+ if (vrfid == VRF_DEFAULT) {
+ /*
+ * Don't use the default vrf, otherwise we won't find
+ * sessions that doesn't specify it.
+ */
+ vrf = NULL;
+ } else
+ vrf = vrf_lookup_by_id(vrfid);
- l_bfd = bfd_shop_lookup(shop);
- }
+ gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL,
+ vrf ? vrf->name : NULL);
/* XXX maybe remoteDiscr should be checked for remoteHeard cases. */
- return l_bfd;
+ return bfd_key_lookup(key);
}
int bfd_xmt_cb(struct thread *t)
struct bfd_session *bs;
bs = XCALLOC(MTYPE_BFDD_CONFIG, sizeof(*bs));
- if (bs == NULL)
- return NULL;
QOBJ_REG(bs, bfd_session);
bfd_session_disable(bs);
+ bfd_key_delete(bs->key);
+ bfd_id_delete(bs->discrs.my_discr);
+
/* Remove observer if any. */
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
if (bso->bso_bs != bs)
* start. See `bfd_session_enable` for more information.
*/
if (bpc->bpc_has_localif)
- strlcpy(bfd->ifname, bpc->bpc_localif, sizeof(bfd->ifname));
+ strlcpy(bfd->key.ifname, bpc->bpc_localif,
+ sizeof(bfd->key.ifname));
if (bpc->bpc_has_vrfname)
- strlcpy(bfd->vrfname, bpc->bpc_vrfname, sizeof(bfd->vrfname));
-
- /* Add observer if we have moving parts. */
- if (bfd->ifname[0] || bfd->vrfname[0])
- bs_observer_add(bfd);
+ strlcpy(bfd->key.vrfname, bpc->bpc_vrfname,
+ sizeof(bfd->key.vrfname));
/* 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;
- } else {
- bfd->shop.peer = bpc->bpc_peer;
+ bfd->key.family = (bpc->bpc_ipv4) ? AF_INET : AF_INET6;
+ switch (bfd->key.family) {
+ case AF_INET:
+ memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin.sin_addr,
+ sizeof(bpc->bpc_peer.sa_sin.sin_addr));
+ memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin.sin_addr,
+ sizeof(bpc->bpc_local.sa_sin.sin_addr));
+ break;
+
+ case AF_INET6:
+ memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin6.sin6_addr,
+ sizeof(bpc->bpc_peer.sa_sin6.sin6_addr));
+ memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin6.sin6_addr,
+ sizeof(bpc->bpc_local.sa_sin6.sin6_addr));
+ break;
+
+ default:
+ assert(1);
+ break;
}
- bfd->local_ip = bpc->bpc_local;
- bfd->local_address = bpc->bpc_local;
+ if (bpc->bpc_mhop)
+ BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH);
+
+ bfd->key.mhop = bpc->bpc_mhop;
+
+ /* Registrate session into data structures. */
+ bfd_key_insert(bfd);
+ bfd->discrs.my_discr = ptm_bfd_gen_ID();
+ bfd_id_insert(bfd);
/* Try to enable session and schedule for packet receive/send. */
if (bfd_session_enable(bfd) == -1) {
return NULL;
}
+ /* Add observer if we have moving parts. */
+ if (bfd->key.ifname[0] || bfd->key.vrfname[0] || bfd->sock == -1)
+ bs_observer_add(bfd);
+
/* Apply other configurations. */
_bfd_session_update(bfd, bpc);
snprintf(buf, buflen, "%u second(s)", second);
}
-const char *bs_to_string(struct bfd_session *bs)
+const char *bs_to_string(const struct bfd_session *bs)
{
static char buf[256];
+ char addr_buf[INET6_ADDRSTRLEN];
int pos;
bool is_mhop = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
pos = snprintf(buf, sizeof(buf), "mhop:%s", is_mhop ? "yes" : "no");
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- " peer:%s local:%s", satostr(&bs->mhop.peer),
- satostr(&bs->mhop.local));
-
- 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));
-
- if (bs->local_address.sa_sin.sin_family)
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- " local:%s",
- satostr(&bs->local_address));
-
- if (bs->shop.ifindex)
- snprintf(buf + pos, sizeof(buf) - pos, " ifindex:%u",
- bs->shop.ifindex);
- }
+ pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s",
+ inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
+ sizeof(addr_buf)));
+ pos += snprintf(buf + pos, sizeof(buf) - pos, " local:%s",
+ inet_ntop(bs->key.family, &bs->key.local, addr_buf,
+ sizeof(addr_buf)));
+ if (bs->key.vrfname[0])
+ pos += snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s",
+ bs->key.vrfname);
+ if (bs->key.ifname[0])
+ pos += snprintf(buf + pos, sizeof(buf) - pos, " ifname:%s",
+ bs->key.ifname);
+
+ (void)pos;
return buf;
}
{
struct bfd_session_observer *bso;
- bso = XMALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso));
+ bso = XCALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso));
+ bso->bso_isaddress = false;
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,
+ strlcpy(bso->bso_entryname, bs->key.ifname,
sizeof(bso->bso_entryname));
else
- strlcpy(bso->bso_entryname, bs->vrfname,
+ strlcpy(bso->bso_entryname, bs->key.vrfname,
sizeof(bso->bso_entryname));
+ /* Handle socket binding failures caused by missing local addresses. */
+ if (bs->sock == -1) {
+ bso->bso_isaddress = true;
+ bso->bso_addr.family = bs->key.family;
+ memcpy(&bso->bso_addr.u.prefix, &bs->key.local,
+ sizeof(bs->key.local));
+ }
+
TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry);
return 0;
XFREE(MTYPE_BFDD_SESSION_OBSERVER, bso);
}
+void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
+{
+ memset(bpc, 0, sizeof(*bpc));
+
+ bpc->bpc_ipv4 = (bs->key.family == AF_INET);
+ bpc->bpc_mhop = bs->key.mhop;
+
+ switch (bs->key.family) {
+ case AF_INET:
+ bpc->bpc_peer.sa_sin.sin_family = AF_INET;
+ memcpy(&bpc->bpc_peer.sa_sin.sin_addr, &bs->key.peer,
+ sizeof(bpc->bpc_peer.sa_sin.sin_addr));
+
+ if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) {
+ bpc->bpc_local.sa_sin.sin_family = AF_INET6;
+ memcpy(&bpc->bpc_local.sa_sin.sin_addr, &bs->key.local,
+ sizeof(bpc->bpc_local.sa_sin.sin_addr));
+ }
+ break;
+
+ case AF_INET6:
+ bpc->bpc_peer.sa_sin.sin_family = AF_INET6;
+ memcpy(&bpc->bpc_peer.sa_sin6.sin6_addr, &bs->key.peer,
+ sizeof(bpc->bpc_peer.sa_sin6.sin6_addr));
+
+ bpc->bpc_local.sa_sin6.sin6_family = AF_INET6;
+ memcpy(&bpc->bpc_local.sa_sin6.sin6_addr, &bs->key.local,
+ sizeof(bpc->bpc_local.sa_sin6.sin6_addr));
+ break;
+ }
+
+ if (bs->key.ifname[0]) {
+ bpc->bpc_has_localif = true;
+ strlcpy(bpc->bpc_localif, bs->key.ifname,
+ sizeof(bpc->bpc_localif));
+ }
+
+ if (bs->key.vrfname[0]) {
+ bpc->bpc_has_vrfname = true;
+ strlcpy(bpc->bpc_vrfname, bs->key.vrfname,
+ sizeof(bpc->bpc_vrfname));
+ }
+}
+
/*
* BFD hash data structures to find sessions.
*/
static struct hash *bfd_id_hash;
-static struct hash *bfd_shop_hash;
-static struct hash *bfd_mhop_hash;
+static struct hash *bfd_key_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 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 unsigned int bfd_key_hash_do(void *p);
static void _bfd_free(struct hash_bucket *hb,
void *arg __attribute__((__unused__)));
}
/* BFD hash for single hop. */
-static unsigned int bfd_shop_hash_do(void *p)
-{
- struct bfd_session *bs = p;
-
- return jhash(&bs->shop, sizeof(bs->shop), 0);
-}
-
-static bool bfd_shop_hash_cmp(const void *n1, const void *n2)
-{
- const struct bfd_session *bs1 = n1, *bs2 = n2;
-
- return memcmp(&bs1->shop, &bs2->shop, sizeof(bs1->shop)) == 0;
-}
-
-/* BFD hash for multi hop. */
-static unsigned int bfd_mhop_hash_do(void *p)
+static unsigned int bfd_key_hash_do(void *p)
{
struct bfd_session *bs = p;
- return jhash(&bs->mhop, sizeof(bs->mhop), 0);
+ return jhash(&bs->key, sizeof(bs->key), 0);
}
-static bool bfd_mhop_hash_cmp(const void *n1, const void *n2)
+static bool bfd_key_hash_cmp(const void *n1, const void *n2)
{
const struct bfd_session *bs1 = n1, *bs2 = n2;
- return memcmp(&bs1->mhop, &bs2->mhop, sizeof(bs1->mhop)) == 0;
+ return memcmp(&bs1->key, &bs2->key, sizeof(bs1->key)) == 0;
}
-/* Helper functions */
-static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop)
-{
- bs->shop = *shop;
-
- /* Remove unused fields. */
- switch (bs->shop.peer.sa_sin.sin_family) {
- case AF_INET:
- bs->shop.peer.sa_sin.sin_port = 0;
- break;
- case AF_INET6:
- bs->shop.peer.sa_sin6.sin6_port = 0;
- break;
- }
-}
-
-static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop)
-{
- _shop_key(bs, shop);
- bs->shop.ifindex = IFINDEX_INTERNAL;
-}
-
-static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop)
-{
- bs->mhop = *mhop;
-
- /* Remove unused fields. */
- switch (bs->mhop.peer.sa_sin.sin_family) {
- case AF_INET:
- bs->mhop.peer.sa_sin.sin_port = 0;
- bs->mhop.local.sa_sin.sin_port = 0;
- break;
- case AF_INET6:
- bs->mhop.peer.sa_sin6.sin6_port = 0;
- bs->mhop.local.sa_sin6.sin6_port = 0;
- break;
- }
-}
/*
* Hash public interface / exported functions.
return hash_lookup(bfd_id_hash, &bs);
}
-struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop)
+struct bfd_session *bfd_key_lookup(struct bfd_key key)
{
struct bfd_session bs, *bsp;
- _shop_key(&bs, &shop);
+ bs.key = key;
+ bsp = hash_lookup(bfd_key_hash, &bs);
- bsp = hash_lookup(bfd_shop_hash, &bs);
- if (bsp == NULL && bs.shop.ifindex != 0) {
- /*
- * Since the local interface spec is optional, try
- * searching the key without it as well.
- */
- _shop_key2(&bs, &shop);
- bsp = hash_lookup(bfd_shop_hash, &bs);
+ /* Handle cases where local-address is optional. */
+ if (bsp == NULL && bs.key.family == AF_INET) {
+ memset(&bs.key.local, 0, sizeof(bs.key.local));
+ bsp = hash_lookup(bfd_key_hash, &bs);
}
- return bsp;
-}
-
-struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop)
-{
- struct bfd_session bs;
+ /* Handle cases where ifname is optional. */
+ bs.key = key;
+ if (bsp == NULL && bs.key.ifname[0]) {
+ memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
+ bsp = hash_lookup(bfd_key_hash, &bs);
- _mhop_key(&bs, &mhop);
+ /* Handle cases where local-address and ifname are optional. */
+ if (bsp == NULL && bs.key.family == AF_INET) {
+ memset(&bs.key.local, 0, sizeof(bs.key.local));
+ bsp = hash_lookup(bfd_key_hash, &bs);
+ }
+ }
- return hash_lookup(bfd_mhop_hash, &bs);
+ return bsp;
}
/*
return hash_release(bfd_id_hash, &bs);
}
-struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop)
+struct bfd_session *bfd_key_delete(struct bfd_key key)
{
struct bfd_session bs, *bsp;
- _shop_key(&bs, &shop);
- bsp = hash_release(bfd_shop_hash, &bs);
- if (bsp == NULL && shop.ifindex != 0) {
- /*
- * Since the local interface spec is optional, try
- * searching the key without it as well.
- */
- _shop_key2(&bs, &shop);
- bsp = hash_release(bfd_shop_hash, &bs);
+ bs.key = key;
+ bsp = hash_lookup(bfd_key_hash, &bs);
+ if (bsp == NULL && key.ifname[0]) {
+ memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
+ bsp = hash_lookup(bfd_key_hash, &bs);
}
- return bsp;
-}
-
-struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop)
-{
- struct bfd_session bs;
-
- _mhop_key(&bs, &mhop);
-
- return hash_release(bfd_mhop_hash, &bs);
+ return hash_release(bfd_key_hash, bsp);
}
/* Iteration functions. */
hash_iterate(bfd_id_hash, hif, arg);
}
-void bfd_shop_iterate(hash_iter_func hif, void *arg)
-{
- hash_iterate(bfd_shop_hash, hif, arg);
-}
-
-void bfd_mhop_iterate(hash_iter_func hif, void *arg)
+void bfd_key_iterate(hash_iter_func hif, void *arg)
{
- hash_iterate(bfd_mhop_hash, hif, arg);
+ hash_iterate(bfd_key_hash, hif, arg);
}
/*
return (hash_get(bfd_id_hash, bs, hash_alloc_intern) == bs);
}
-bool bfd_shop_insert(struct bfd_session *bs)
-{
- return (hash_get(bfd_shop_hash, bs, hash_alloc_intern) == bs);
-}
-
-bool bfd_mhop_insert(struct bfd_session *bs)
+bool bfd_key_insert(struct bfd_session *bs)
{
- return (hash_get(bfd_mhop_hash, bs, hash_alloc_intern) == bs);
+ return (hash_get(bfd_key_hash, bs, hash_alloc_intern) == bs);
}
void bfd_initialize(void)
{
bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp,
- "BFD discriminator hash");
- bfd_shop_hash = hash_create(bfd_shop_hash_do, bfd_shop_hash_cmp,
- "BFD single hop hash");
- bfd_mhop_hash = hash_create(bfd_mhop_hash_do, bfd_mhop_hash_cmp,
- "BFD multihop hop hash");
+ "BFD session discriminator hash");
+ bfd_key_hash = hash_create(bfd_key_hash_do, bfd_key_hash_cmp,
+ "BFD session hash");
}
static void _bfd_free(struct hash_bucket *hb,
* assert() here to make sure it really happened.
*/
bfd_id_iterate(_bfd_free, NULL);
- assert(bfd_shop_hash->count == 0);
- assert(bfd_mhop_hash->count == 0);
+ assert(bfd_key_hash->count == 0);
/* Now free the hashes themselves. */
hash_free(bfd_id_hash);
- hash_free(bfd_shop_hash);
- hash_free(bfd_mhop_hash);
+ hash_free(bfd_key_hash);
}
#define BFD_CHECK_FLAG(field, flag) (field & flag)
/* BFD session hash keys */
-struct bfd_shop_key {
- struct sockaddr_any peer;
- ifindex_t ifindex;
-};
-
-struct bfd_mhop_key {
- struct sockaddr_any peer;
- struct sockaddr_any local;
- vrf_id_t vrfid;
+struct bfd_key {
+ uint16_t family;
+ uint8_t mhop;
+ struct in6_addr peer;
+ struct in6_addr local;
+ char ifname[MAXNAMELEN];
+ char vrfname[MAXNAMELEN];
};
struct bfd_session_stats {
uint8_t polling;
/* This and the localDiscr are the keys to state info */
+ struct bfd_key key;
struct peer_label *pl;
- union {
- struct bfd_shop_key shop;
- struct bfd_mhop_key mhop;
- };
- int sock;
struct sockaddr_any local_address;
- struct sockaddr_any local_ip;
struct interface *ifp;
struct vrf *vrf;
- char ifname[MAXNAMELEN];
- char vrfname[MAXNAMELEN];
+
+ int sock;
/* BFD session flags */
enum bfd_session_flags flags;
struct bfd_session_observer {
struct bfd_session *bso_bs;
bool bso_isinterface;
- char bso_entryname[MAXNAMELEN];
+ bool bso_isaddress;
+ union {
+ char bso_entryname[MAXNAMELEN];
+ struct prefix bso_addr;
+ };
TAILQ_ENTRY(bfd_session_observer) bso_entry;
};
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);
+const char *bs_to_string(const struct bfd_session *bs);
int bs_observer_add(struct bfd_session *bs);
void bs_observer_del(struct bfd_session_observer *bso);
+void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
+
/* BFD hash data structures interface */
void bfd_initialize(void);
void bfd_shutdown(void);
struct bfd_session *bfd_id_lookup(uint32_t id);
-struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop);
-struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop);
-struct bfd_vrf *bfd_vrf_lookup(int vrf_id);
-struct bfd_iface *bfd_iface_lookup(const char *ifname);
+struct bfd_session *bfd_key_lookup(struct bfd_key key);
struct bfd_session *bfd_id_delete(uint32_t id);
-struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop);
-struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop);
-struct bfd_vrf *bfd_vrf_delete(int vrf_id);
-struct bfd_iface *bfd_iface_delete(const char *ifname);
+struct bfd_session *bfd_key_delete(struct bfd_key key);
bool bfd_id_insert(struct bfd_session *bs);
-bool bfd_shop_insert(struct bfd_session *bs);
-bool bfd_mhop_insert(struct bfd_session *bs);
-bool bfd_vrf_insert(struct bfd_vrf *vrf);
-bool bfd_iface_insert(struct bfd_iface *iface);
+bool bfd_key_insert(struct bfd_session *bs);
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);
-void bfd_vrf_iterate(hash_iter_func hif, void *arg);
-void bfd_iface_iterate(hash_iter_func hif, void *arg);
+void bfd_key_iterate(hash_iter_func hif, void *arg);
/* Export callback functions for `event.c`. */
extern struct thread_master *master;
int bfd_xmt_cb(struct thread *t);
int bfd_echo_xmt_cb(struct thread *t);
+extern struct in6_addr zero_addr;
+
/*
* bfdd_vty.c
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
- sin6.sin6_addr = bs->shop.peer.sa_sin6.sin6_addr;
+ memcpy(&sin6.sin6_addr, &bs->key.peer, sizeof(sin6.sin6_addr));
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
+ sin6.sin6_scope_id = bs->ifp->ifindex;
+
sin6.sin6_port =
(port) ? *port
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
} else {
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
- sin.sin_addr = bs->shop.peer.sa_sin.sin_addr;
+ memcpy(&sin.sin_addr, &bs->key.peer, sizeof(sin.sin_addr));
sin.sin_port =
(port) ? *port
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
void ptm_bfd_echo_snd(struct bfd_session *bfd)
{
- struct sockaddr_any *sa;
+ struct sockaddr *sa;
socklen_t salen;
int sd;
struct bfd_echo_pkt bep;
bep.len = BFD_ECHO_PKT_LEN;
bep.my_discr = htonl(bfd->discrs.my_discr);
- sa = BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MH) ? &bfd->mhop.peer
- : &bfd->shop.peer;
if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
sd = bglobal.bg_echov6;
- sin6 = sa->sa_sin6;
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ memcpy(&sin6.sin6_addr, &bfd->key.peer, sizeof(sin6.sin6_addr));
+ if (bfd->ifp && IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
+ sin6.sin6_scope_id = bfd->ifp->ifindex;
+
sin6.sin6_port = htons(BFD_DEF_ECHO_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin6.sin6_len = sizeof(sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
- sa = (struct sockaddr_any *)&sin6;
+ sa = (struct sockaddr *)&sin6;
salen = sizeof(sin6);
} else {
sd = bglobal.bg_echo;
- sin = sa->sa_sin;
+ memset(&sin6, 0, sizeof(sin6));
+ sin.sin_family = AF_INET;
+ memcpy(&sin.sin_addr, &bfd->key.peer, sizeof(sin.sin_addr));
sin.sin_port = htons(BFD_DEF_ECHO_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin.sin_len = sizeof(sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
- sa = (struct sockaddr_any *)&sin;
+ sa = (struct sockaddr *)&sin;
salen = sizeof(sin);
}
- if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep),
- (struct sockaddr *)sa, salen)
+ if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep), sa,
+ salen)
== -1)
return;
}
/* Validate packet TTL. */
- if ((is_mhop == false) && (ttl != BFD_TTL_VAL)) {
+ if ((!is_mhop) && (ttl != BFD_TTL_VAL)) {
cp_debug(is_mhop, &peer, &local, ifindex, vrfid,
"invalid TTL: %d expected %d", ttl, BFD_TTL_VAL);
return 0;
bfd->mh_ttl, BFD_TTL_VAL);
return 0;
}
- } else if (bfd->local_ip.sa_sin.sin_family == AF_UNSPEC) {
- bfd->local_ip = local;
+ } else if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) {
+ bfd->local_address = local;
}
/*
return -1;
}
- if (bs->shop.ifindex != IFINDEX_INTERNAL) {
- if (bp_bind_dev(sd, bs->ifp->name) != 0) {
+ if (bs->key.ifname[0]) {
+ if (bp_bind_dev(sd, bs->key.ifname) != 0) {
close(sd);
return -1;
}
- } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
- bs->mhop.vrfid != VRF_DEFAULT) {
- if (bp_bind_dev(sd, bs->vrf->name) != 0) {
+ } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
+ && bs->key.vrfname[0]) {
+ if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
close(sd);
return -1;
}
}
/* Find an available source port in the proper range */
- sin = bs->local_ip.sa_sin;
+ memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin.sin_len = sizeof(sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr));
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
sin.sin_addr.s_addr = INADDR_ANY;
}
/* Find an available source port in the proper range */
- sin6 = bs->local_ip.sa_sin6;
+ memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin6.sin6_len = sizeof(sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ memcpy(&sin6.sin6_addr, &bs->key.local, sizeof(sin6.sin6_addr));
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
+ sin6.sin6_scope_id = bs->ifp->ifindex;
- if (bs->shop.ifindex != IFINDEX_INTERNAL) {
- if (bp_bind_dev(sd, bs->ifp->name) != 0) {
+ if (bs->key.ifname[0]) {
+ if (bp_bind_dev(sd, bs->key.ifname) != 0) {
close(sd);
return -1;
}
- } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
- bs->mhop.vrfid != VRF_DEFAULT) {
- if (bp_bind_dev(sd, bs->vrf->name) != 0) {
+ } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
+ && bs->key.vrfname[0]) {
+ if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
close(sd);
return -1;
}
const char *local_str, const char *ifname,
const char *vrfname);
-
/*
* Commands definition.
*/
*/
static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
{
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
- vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
+ char addr_buf[INET6_ADDRSTRLEN];
+
+ vty_out(vty, "\tpeer %s",
+ inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
+ sizeof(addr_buf)));
+
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
vty_out(vty, " multihop");
- vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
- 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->ifname[0])
- vty_out(vty, " interface %s", bs->ifname);
- vty_out(vty, "\n");
- }
+
+ if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
+ vty_out(vty, " local-address %s",
+ inet_ntop(bs->key.family, &bs->key.local, addr_buf,
+ sizeof(addr_buf)));
+
+ if (bs->key.vrfname[0])
+ vty_out(vty, " vrf %s", bs->key.vrfname);
+ if (bs->key.ifname[0])
+ vty_out(vty, " interface %s", bs->key.ifname);
+ vty_out(vty, "\n");
if (bs->pl)
vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
static struct json_object *_peer_json_header(struct bfd_session *bs)
{
struct json_object *jo = json_object_new_object();
+ char addr_buf[INET6_ADDRSTRLEN];
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
+ if (bs->key.mhop)
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->vrfname[0])
- json_object_string_add(jo, "vrf", bs->vrfname);
- } else {
+ 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->ifname[0])
- json_object_string_add(jo, "interface", bs->ifname);
- }
+
+ json_object_string_add(jo, "peer",
+ inet_ntop(bs->key.family, &bs->key.peer,
+ addr_buf, sizeof(addr_buf)));
+ if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
+ json_object_string_add(jo, "local",
+ inet_ntop(bs->key.family, &bs->key.local,
+ addr_buf, sizeof(addr_buf)));
+
+ if (bs->key.vrfname[0])
+ json_object_string_add(jo, "vrf", bs->key.vrfname);
+ if (bs->key.ifname[0])
+ json_object_string_add(jo, "interface", bs->key.ifname);
if (bs->pl)
json_object_string_add(jo, "label", bs->pl->pl_label);
{
struct json_object *jo;
- if (use_json == false) {
+ if (!use_json) {
vty_out(vty, "BFD Peers:\n");
bfd_id_iterate(_display_peer_iter, vty);
return;
{
struct json_object *jo;
- if (use_json == false) {
+ if (!use_json) {
vty_out(vty, "BFD Peers:\n");
bfd_id_iterate(_display_peer_counter_iter, vty);
return;
static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs)
{
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
- vty_out(vty, " peer %s", satostr(&bs->mhop.peer));
+ char addr_buf[INET6_ADDRSTRLEN];
+
+ vty_out(vty, " peer %s",
+ inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
+ sizeof(addr_buf)));
+
+ if (bs->key.mhop)
vty_out(vty, " multihop");
- vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
- 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->ifname[0])
- vty_out(vty, " interface %s", bs->ifname);
- vty_out(vty, "\n");
- }
+
+ if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
+ vty_out(vty, " local-address %s",
+ inet_ntop(bs->key.family, &bs->key.local, addr_buf,
+ sizeof(addr_buf)));
+
+ if (bs->key.vrfname[0])
+ vty_out(vty, " vrf %s", bs->key.vrfname);
+ if (bs->key.ifname[0])
+ vty_out(vty, " interface %s", bs->key.ifname);
+ vty_out(vty, "\n");
if (bs->sock == -1)
- vty_out(vty, " ! vrf or interface doesn't exist\n");
+ vty_out(vty,
+ " ! vrf, interface or local-address doesn't exist\n");
if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
vty_out(vty, " detect-multiplier %d\n", bs->detect_mult);
static int bfdd_peer_write_config(struct vty *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;
}
log_debug("\tpeer-label: %s", sval);
/* Translate the label into BFD address keys. */
- bpc->bpc_ipv4 = !BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_IPV6);
- bpc->bpc_mhop = BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_MH);
- 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.vrfid != VRF_DEFAULT) {
- bpc->bpc_has_vrfname = true;
- 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->ifname[0]) {
- bpc->bpc_has_localif = true;
- strlcpy(bpc->bpc_localif, pl->pl_bs->ifname,
- sizeof(bpc->bpc_localif));
- }
- }
+ bs_to_bpc(pl->pl_bs, bpc);
return 0;
}
static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
{
+ char addr_buf[INET6_ADDRSTRLEN];
+
/* Add peer 'key' information. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6))
json_object_boolean_true_add(jo, "ipv6");
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
json_object_boolean_true_add(jo, "multihop");
json_object_string_add(jo, "peer-address",
- satostr(&bs->mhop.peer));
+ inet_ntop(bs->key.family, &bs->key.peer,
+ addr_buf, sizeof(addr_buf)));
json_object_string_add(jo, "local-address",
- satostr(&bs->mhop.local));
- if (bs->vrfname[0])
- json_object_string_add(jo, "vrf-name", bs->vrfname);
+ inet_ntop(bs->key.family, &bs->key.local,
+ addr_buf, sizeof(addr_buf)));
+ if (bs->key.vrfname[0])
+ json_object_string_add(jo, "vrf-name", bs->key.vrfname);
} else {
json_object_boolean_false_add(jo, "multihop");
json_object_string_add(jo, "peer-address",
- satostr(&bs->shop.peer));
- if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
- json_object_string_add(jo, "local-address",
- satostr(&bs->local_address));
- if (bs->ifname[0])
+ inet_ntop(bs->key.family, &bs->key.peer,
+ addr_buf, sizeof(addr_buf)));
+ if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
+ json_object_string_add(
+ jo, "local-address",
+ inet_ntop(bs->key.family, &bs->key.local,
+ addr_buf, sizeof(addr_buf)));
+ if (bs->key.ifname[0])
json_object_string_add(jo, "local-interface",
- bs->ifname);
+ bs->key.ifname);
}
if (bs->pl)
struct peer_label *pl;
pl = XCALLOC(MTYPE_BFDD_LABEL, sizeof(*pl));
- if (pl == NULL)
- return NULL;
if (strlcpy(pl->pl_label, label, sizeof(pl->pl_label))
> sizeof(pl->pl_label))
struct bfd_control_socket *bcs;
bcs = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bcs));
- if (bcs == NULL)
- return NULL;
/* Disable notifications by default. */
bcs->bcs_notify = 0;
return bnp;
bnp = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bnp));
- if (bnp == NULL) {
- log_warning("%s: calloc: %s", __func__, strerror(errno));
- return NULL;
- }
TAILQ_INSERT_TAIL(&bcs->bcs_bnplist, bnp, bnp_entry);
bnp->bnp_bs = bs;
struct bfd_control_queue *bcq;
bcq = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*bcq));
- if (bcq == NULL) {
- log_warning("%s: calloc: %s", __func__, strerror(errno));
- return NULL;
- }
control_reset_buf(&bcq->bcq_bcb);
TAILQ_INSERT_TAIL(&bcs->bcs_bcqueue, bcq, bcq_entry);
jsonstrlen = strlen(jsonstr);
bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(struct bfd_control_msg) + jsonstrlen);
- if (bcm == NULL) {
- log_warning("%s: malloc: %s", __func__, strerror(errno));
- XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
- return;
- }
bcm->bcm_length = htonl(jsonstrlen);
bcm->bcm_ver = BMV_VERSION_1;
jsonstrlen = strlen(jsonstr);
bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(struct bfd_control_msg) + jsonstrlen);
- if (bcm == NULL) {
- log_warning("%s: malloc: %s", __func__, strerror(errno));
- XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
- return;
- }
bcm->bcm_length = htonl(jsonstrlen);
bcm->bcm_ver = BMV_VERSION_1;
jsonstrlen = strlen(jsonstr);
bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(struct bfd_control_msg) + jsonstrlen);
- if (bcm == NULL) {
- log_warning("%s: malloc: %s", __func__, strerror(errno));
- XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
- return;
- }
bcm->bcm_length = htonl(jsonstrlen);
bcm->bcm_ver = BMV_VERSION_1;
/*
* Prototypes
*/
-static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa);
+static int _ptm_msg_address(struct stream *msg, int family, const void *addr);
static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
static int _ptm_msg_read(struct stream *msg, int command,
#define DEBUG_PRINTBPC(bpc)
#endif /* BFD_DEBUG */
-static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa)
+static int _ptm_msg_address(struct stream *msg, int family, const void *addr)
{
- switch (sa->sa_sin.sin_family) {
+ stream_putc(msg, family);
+
+ switch (family) {
case AF_INET:
- stream_putc(msg, sa->sa_sin.sin_family);
- stream_put_in_addr(msg, &sa->sa_sin.sin_addr);
+ stream_put(msg, addr, sizeof(struct in_addr));
stream_putc(msg, 32);
break;
case AF_INET6:
- stream_putc(msg, sa->sa_sin6.sin6_family);
- stream_put(msg, &sa->sa_sin6.sin6_addr,
- sizeof(sa->sa_sin6.sin6_addr));
+ stream_put(msg, addr, sizeof(struct in6_addr));
stream_putc(msg, 128);
break;
default:
- return -1;
+ assert(0);
+ break;
}
return 0;
int ptm_bfd_notify(struct bfd_session *bs)
{
struct stream *msg;
- struct sockaddr_any sac;
bs->stats.znotification++;
stream_putl(msg, IFINDEX_INTERNAL);
/* BFD destination prefix information. */
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
- _ptm_msg_address(msg, &bs->mhop.peer);
- else
- _ptm_msg_address(msg, &bs->shop.peer);
+ _ptm_msg_address(msg, bs->key.family, &bs->key.peer);
/* BFD status */
switch (bs->ses_state) {
}
/* BFD source prefix information. */
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
- _ptm_msg_address(msg, &bs->mhop.local);
- } else {
- if (bs->local_address.sa_sin.sin_family)
- _ptm_msg_address(msg, &bs->local_address);
- else if (bs->local_address.sa_sin.sin_family)
- _ptm_msg_address(msg, &bs->local_ip);
- else {
- sac = bs->shop.peer;
- switch (sac.sa_sin.sin_family) {
- case AF_INET:
- memset(&sac.sa_sin.sin_addr, 0,
- sizeof(sac.sa_sin.sin_family));
- break;
- case AF_INET6:
- memset(&sac.sa_sin6.sin6_addr, 0,
- sizeof(sac.sa_sin6.sin6_family));
- break;
-
- default:
- assert(false);
- break;
- }
-
- /* No local address found yet, so send zeroes. */
- _ptm_msg_address(msg, &sac);
- }
- }
+ _ptm_msg_address(msg, bs->key.family, &bs->key.local);
/* Write packet size. */
stream_putw_at(msg, 0, stream_get_endp(msg));
static int _ptm_msg_read(struct stream *msg, int command,
struct bfd_peer_cfg *bpc, struct ptm_client **pc)
{
- struct interface *ifp;
uint32_t pid;
uint8_t ttl __attribute__((unused));
size_t ifnamelen;
if (bpc->bpc_has_localif) {
STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
bpc->bpc_localif[ifnamelen] = 0;
-
- /*
- * IPv6 link-local addresses must use scope id,
- * otherwise the session lookup will always fail
- * and we'll have multiple sessions showing up.
- *
- * This problem only happens with single hop
- * since it is not possible to have link-local
- * address for multi hop sessions.
- */
- if (bpc->bpc_ipv4 == false
- && IN6_IS_ADDR_LINKLOCAL(
- &bpc->bpc_peer.sa_sin6.sin6_addr)) {
- ifp = if_lookup_by_name_all_vrf(
- bpc->bpc_localif);
- if (ifp == NULL) {
- log_error(
- "ptm-read: interface %s doesn't exists",
- bpc->bpc_localif);
- return -1;
- }
-
- bpc->bpc_peer.sa_sin6.sin6_scope_id =
- ifp->ifindex;
- }
}
}
/* Interface name mismatch. */
bs = bso->bso_bs;
- if (strcmp(ifp->name, bs->ifname))
+ if (strcmp(ifp->name, bs->key.ifname))
continue;
/* Skip enabled sessions. */
if (bs->sock != -1)
/* Interface name mismatch. */
bs = bso->bso_bs;
- if (strcmp(ifp->name, bs->ifname))
+ if (strcmp(ifp->name, bs->key.ifname))
continue;
/* Skip disabled sessions. */
if (bs->sock == -1)
bfdd_sessions_disable_interface(ifp);
+ if_set_index(ifp, IFINDEX_INTERNAL);
+
return 0;
}
return 0;
}
+static void bfdd_sessions_enable_address(struct connected *ifc)
+{
+ struct bfd_session_observer *bso;
+ struct bfd_session *bs;
+ struct prefix prefix;
+
+ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+ if (bso->bso_isaddress == false)
+ continue;
+
+ /* Skip enabled sessions. */
+ bs = bso->bso_bs;
+ if (bs->sock != -1)
+ continue;
+
+ /* Check address. */
+ prefix = bso->bso_addr;
+ prefix.prefixlen = ifc->address->prefixlen;
+ if (prefix_cmp(&prefix, ifc->address))
+ continue;
+
+ /* Try to enable it. */
+ bfd_session_enable(bs);
+ }
+}
+
+static int bfdd_interface_address_update(int cmd, struct zclient *zc,
+ zebra_size_t len
+ __attribute__((__unused__)),
+ vrf_id_t vrfid)
+{
+ struct connected *ifc;
+
+ ifc = zebra_interface_address_read(cmd, zc->ibuf, vrfid);
+ if (ifc == NULL)
+ return 0;
+
+ bfdd_sessions_enable_address(ifc);
+
+ return 0;
+}
+
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
{
zclient = zclient_new(master, &zclient_options_default);
/* Learn about interface VRF. */
zclient->interface_vrf_update = bfdd_interface_vrf_update;
+
+ /* Learn about new addresses being registered. */
+ zclient->interface_address_add = bfdd_interface_address_update;
+ zclient->interface_address_delete = bfdd_interface_address_update;
}
void bfdd_zclient_stop(void)
/* Allocate the client data and save it. */
pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc));
- if (pc == NULL)
- return NULL;
pc->pc_pid = pid;
TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry);
/* Save the client notification data. */
pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn));
- if (pcn == NULL)
- return NULL;
TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry);
pcn->pcn_pc = pc;
}
}
- zlog_info("Resetting peer %s%s due to change in addpath config\n",
+ zlog_info("Resetting peer %s%s due to change in addpath config",
CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) ? "group " : "",
peer->host);
peer. */
struct bgp_advertise_attr *baa_new(void)
{
- return (struct bgp_advertise_attr *)XCALLOC(
- MTYPE_BGP_ADVERTISE_ATTR, sizeof(struct bgp_advertise_attr));
+ return XCALLOC(MTYPE_BGP_ADVERTISE_ATTR,
+ sizeof(struct bgp_advertise_attr));
}
static void baa_free(struct bgp_advertise_attr *baa)
information. */
struct bgp_advertise *bgp_advertise_new(void)
{
- return (struct bgp_advertise *)XCALLOC(MTYPE_BGP_ADVERTISE,
- sizeof(struct bgp_advertise));
+ return XCALLOC(MTYPE_BGP_ADVERTISE, sizeof(struct bgp_advertise));
}
void bgp_advertise_free(struct bgp_advertise *adv)
safi_t safi;
FOREACH_AFI_SAFI (afi, safi) {
- if (peer->sync[afi][safi])
- XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]);
+ XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]);
peer->sync[afi][safi] = NULL;
}
}
return;
if (aspath->segments)
assegment_free_all(aspath->segments);
- if (aspath->str)
- XFREE(MTYPE_AS_STR, aspath->str);
+ XFREE(MTYPE_AS_STR, aspath->str);
if (aspath->json) {
json_object_free(aspath->json);
void aspath_str_update(struct aspath *as, bool make_json)
{
- if (as->str)
- XFREE(MTYPE_AS_STR, as->str);
+ XFREE(MTYPE_AS_STR, as->str);
if (as->json) {
json_object_free(as->json);
#include "bgp_encap_types.h"
#include "bgp_evpn.h"
#include "bgp_flowspec_private.h"
+#include "bgp_mac.h"
/* Attribute strings for logging. */
static const struct message attr_str[] = {
static void cluster_free(struct cluster_list *cluster)
{
- if (cluster->list)
- XFREE(MTYPE_CLUSTER_VAL, cluster->list);
+ XFREE(MTYPE_CLUSTER_VAL, cluster->list);
XFREE(MTYPE_CLUSTER, cluster);
}
static void transit_free(struct transit *transit)
{
- if (transit->val)
- XFREE(MTYPE_TRANSIT_VAL, transit->val);
+ XFREE(MTYPE_TRANSIT_VAL, transit->val);
XFREE(MTYPE_TRANSIT, transit);
}
stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
if (!peer->nexthop.ifp) {
- zlog_warn("%s: interface not set appropriately to handle some attributes",
+ zlog_warn("%s: Received a V6/VPNV6 Global attribute but address is a V6 LL and we have no peer interface information, withdrawing",
peer->host);
return BGP_ATTR_PARSE_WITHDRAW;
}
stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
if (!peer->nexthop.ifp) {
- zlog_warn("%s: interface not set appropriately to handle some attributes",
+ zlog_warn("%s: Received V6/VPNV6 Global and LL attribute but global address is a V6 LL and we have no peer interface information, withdrawing",
peer->host);
return BGP_ATTR_PARSE_WITHDRAW;
}
attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
}
if (!peer->nexthop.ifp) {
- zlog_warn("%s: Interface not set appropriately to handle this some attributes",
+ zlog_warn("%s: Received a V6 LL nexthop and we have no peer interface information, withdrawing",
peer->host);
return BGP_ATTR_PARSE_WITHDRAW;
}
bgp_attr_evpn_na_flag(attr, &attr->router_flag);
/* Extract the Rmac, if any */
- bgp_attr_rmac(attr, &attr->rmac);
+ if (bgp_attr_rmac(attr, &attr->rmac)) {
+ if (bgp_debug_update(peer, NULL, NULL, 1) &&
+ bgp_mac_exist(&attr->rmac)) {
+ char buf1[ETHER_ADDR_STRLEN];
+
+ zlog_debug("%s: router mac %s is self mac",
+ __func__,
+ prefix_mac2str(&attr->rmac, buf1,
+ sizeof(buf1)));
+ }
+
+ }
return BGP_ATTR_PARSE_PROCEED;
}
return NULL;
val = id->val;
- ptr = (char *)XMALLOC(MTYPE_TMP,
- (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char));
+ ptr = XMALLOC(MTYPE_TMP,
+ (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char));
snprintf(ptr, (ESI_LEN * 2 + ESI_LEN - 1 + 1),
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", val[0],
}
/* Fetch router-mac from extended community */
-void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
+bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
{
int i = 0;
struct ecommunity *ecom;
ecom = attr->ecommunity;
if (!ecom || !ecom->size)
- return;
+ return false;
/* If there is a router mac extended community, set RMAC in attr */
for (i = 0; i < ecom->size; i++) {
continue;
memcpy(rmac, pnt, ETH_ALEN);
+ return true;
}
+ return false;
}
/*
struct ethaddr *routermac);
extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag,
struct prefix *dst);
-extern void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac);
+extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac);
extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr,
uint8_t *sticky);
extern uint8_t bgp_attr_default_gw(struct attr *attr);
case EXTCOMMUNITY_LIST_STANDARD:
/* In case of standard extcommunity-list, configuration string
is made by ecommunity_ecom2str(). */
- if (entry->config)
- XFREE(MTYPE_ECOMMUNITY_STR, entry->config);
+ XFREE(MTYPE_ECOMMUNITY_STR, entry->config);
if (entry->u.ecom)
ecommunity_free(&entry->u.ecom);
break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
case LARGE_COMMUNITY_LIST_EXPANDED:
- if (entry->config)
- XFREE(MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
+ XFREE(MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
if (entry->reg)
bgp_regex_free(entry->reg);
default:
/* Free community-list. */
static void community_list_free(struct community_list *list)
{
- if (list->name)
- XFREE(MTYPE_COMMUNITY_LIST_NAME, list->name);
+ XFREE(MTYPE_COMMUNITY_LIST_NAME, list->name);
XFREE(MTYPE_COMMUNITY_LIST, list);
}
/* Allocate a new communities value. */
static struct community *community_new(void)
{
- return (struct community *)XCALLOC(MTYPE_COMMUNITY,
- sizeof(struct community));
+ return XCALLOC(MTYPE_COMMUNITY, sizeof(struct community));
}
/* Free communities value. */
void community_free(struct community **com)
{
- if ((*com)->val)
- XFREE(MTYPE_COMMUNITY_VAL, (*com)->val);
- if ((*com)->str)
- XFREE(MTYPE_COMMUNITY_STR, (*com)->str);
+ XFREE(MTYPE_COMMUNITY_VAL, (*com)->val);
+ XFREE(MTYPE_COMMUNITY_STR, (*com)->str);
if ((*com)->json) {
json_object_free((*com)->json);
/* Allocate a new ecommunities. */
struct ecommunity *ecommunity_new(void)
{
- return (struct ecommunity *)XCALLOC(MTYPE_ECOMMUNITY,
- sizeof(struct ecommunity));
+ return XCALLOC(MTYPE_ECOMMUNITY, sizeof(struct ecommunity));
}
void ecommunity_strfree(char **s)
/* Allocate ecommunities. */
void ecommunity_free(struct ecommunity **ecom)
{
- if ((*ecom)->val)
- XFREE(MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
- if ((*ecom)->str)
- XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str);
+ XFREE(MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
+ XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str);
XFREE(MTYPE_ECOMMUNITY, *ecom);
}
if (bet == NULL || !bet->vnid)
return;
- if (attr->encap_subtlvs)
- XFREE(MTYPE_ENCAP_TLV, attr->encap_subtlvs);
+ XFREE(MTYPE_ENCAP_TLV, attr->encap_subtlvs);
tlv = XCALLOC(MTYPE_ENCAP_TLV,
sizeof(struct bgp_attr_encap_subtlv) + 12);
tlv->type = 1; /* encapsulation type */
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_addpath.h"
+#include "bgpd/bgp_mac.h"
/*
* Definitions and external declarations.
}
/*
- * Create a new vrf import_rt in default instance
+ * Create a new vrf import_rt in evpn instance
*/
static struct vrf_irt_node *vrf_import_rt_new(struct ecommunity_val *rt)
{
- struct bgp *bgp_def = NULL;
+ struct bgp *bgp_evpn = NULL;
struct vrf_irt_node *irt;
- bgp_def = bgp_get_default();
- if (!bgp_def) {
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn) {
flog_err(EC_BGP_NO_DFLT,
- "vrf import rt new - def instance not created yet");
+ "vrf import rt new - evpn instance not created yet");
return NULL;
}
irt = XCALLOC(MTYPE_BGP_EVPN_VRF_IMPORT_RT,
sizeof(struct vrf_irt_node));
- if (!irt)
- return NULL;
irt->rt = *rt;
irt->vrfs = list_new();
/* Add to hash */
- if (!hash_get(bgp_def->vrf_import_rt_hash, irt, hash_alloc_intern)) {
+ if (!hash_get(bgp_evpn->vrf_import_rt_hash, irt, hash_alloc_intern)) {
XFREE(MTYPE_BGP_EVPN_VRF_IMPORT_RT, irt);
return NULL;
}
*/
static void vrf_import_rt_free(struct vrf_irt_node *irt)
{
- struct bgp *bgp_def = NULL;
+ struct bgp *bgp_evpn = NULL;
- bgp_def = bgp_get_default();
- if (!bgp_def) {
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn) {
flog_err(EC_BGP_NO_DFLT,
- "vrf import rt free - def instance not created yet");
+ "vrf import rt free - evpn instance not created yet");
return;
}
- hash_release(bgp_def->vrf_import_rt_hash, irt);
+ hash_release(bgp_evpn->vrf_import_rt_hash, irt);
list_delete(&irt->vrfs);
XFREE(MTYPE_BGP_EVPN_VRF_IMPORT_RT, irt);
}
*/
static struct vrf_irt_node *lookup_vrf_import_rt(struct ecommunity_val *rt)
{
- struct bgp *bgp_def = NULL;
+ struct bgp *bgp_evpn = NULL;
struct vrf_irt_node *irt;
struct vrf_irt_node tmp;
- bgp_def = bgp_get_default();
- if (!bgp_def) {
- flog_err(EC_BGP_NO_DFLT,
- "vrf import rt lookup - def instance not created yet");
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn) {
+ flog_err(
+ EC_BGP_NO_DFLT,
+ "vrf import rt lookup - evpn instance not created yet");
return NULL;
}
memset(&tmp, 0, sizeof(struct vrf_irt_node));
memcpy(&tmp.rt, rt, ECOMMUNITY_SIZE);
- irt = hash_lookup(bgp_def->vrf_import_rt_hash, &tmp);
+ irt = hash_lookup(bgp_evpn->vrf_import_rt_hash, &tmp);
return irt;
}
return NULL;
irt = XCALLOC(MTYPE_BGP_EVPN_IMPORT_RT, sizeof(struct irt_node));
- if (!irt)
- return NULL;
irt->rt = *rt;
irt->vnis = list_new();
struct in_addr *ip;
ip = XCALLOC(MTYPE_BGP_EVPN_ES_VTEP, sizeof(struct in_addr));
- if (!ip)
- return NULL;
ip->s_addr = vtep.s_addr;
return ip;
return 0;
}
-static int update_evpn_type5_route_entry(struct bgp *bgp_def,
+static int update_evpn_type5_route_entry(struct bgp *bgp_evpn,
struct bgp *bgp_vrf, afi_t afi,
safi_t safi, struct bgp_node *rn,
struct attr *attr, int *route_changed)
/* locate the local route entry if any */
for (tmp_pi = bgp_node_get_bgp_path_info(rn); tmp_pi;
tmp_pi = tmp_pi->next) {
- if (tmp_pi->peer == bgp_def->peer_self
+ if (tmp_pi->peer == bgp_evpn->peer_self
&& tmp_pi->type == ZEBRA_ROUTE_BGP
&& tmp_pi->sub_type == BGP_ROUTE_STATIC)
local_pi = tmp_pi;
/* create the route info from attribute */
pi = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0,
- bgp_def->peer_self, attr_new, rn);
+ bgp_evpn->peer_self, attr_new, rn);
SET_FLAG(pi->flags, BGP_PATH_VALID);
/* Type-5 routes advertise the L3-VNI */
safi_t safi = SAFI_EVPN;
struct attr attr;
struct bgp_node *rn = NULL;
- struct bgp *bgp_def = NULL;
+ struct bgp *bgp_evpn = NULL;
int route_changed = 0;
- bgp_def = bgp_get_default();
- if (!bgp_def)
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn)
return 0;
/* Build path attribute for this route - use the source attr, if
build_evpn_type5_route_extcomm(bgp_vrf, &attr);
/* get the route node in global table */
- rn = bgp_afi_node_get(bgp_def->rib[afi][safi], afi, safi,
+ rn = bgp_afi_node_get(bgp_evpn->rib[afi][safi], afi, safi,
(struct prefix *)evp, &bgp_vrf->vrf_prd);
assert(rn);
/* create or update the route entry within the route node */
- update_evpn_type5_route_entry(bgp_def, bgp_vrf, afi, safi, rn, &attr,
+ update_evpn_type5_route_entry(bgp_evpn, bgp_vrf, afi, safi, rn, &attr,
&route_changed);
/* schedule for processing and unlock node */
if (route_changed) {
- bgp_process(bgp_def, rn, afi, safi);
+ bgp_process(bgp_evpn, rn, afi, safi);
bgp_unlock_node(rn);
}
safi_t safi = SAFI_EVPN;
struct bgp_node *rn = NULL;
struct bgp_path_info *pi = NULL;
- struct bgp *bgp_def = NULL; /* default bgp instance */
+ struct bgp *bgp_evpn = NULL; /* evpn bgp instance */
- bgp_def = bgp_get_default();
- if (!bgp_def)
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn)
return 0;
/* locate the global route entry for this type-5 prefix */
- rn = bgp_afi_node_lookup(bgp_def->rib[afi][safi], afi, safi,
+ rn = bgp_afi_node_lookup(bgp_evpn->rib[afi][safi], afi, safi,
(struct prefix *)evp, &bgp_vrf->vrf_prd);
if (!rn)
return 0;
- delete_evpn_route_entry(bgp_def, afi, safi, rn, &pi);
+ delete_evpn_route_entry(bgp_evpn, afi, safi, rn, &pi);
if (pi)
- bgp_process(bgp_def, rn, afi, safi);
+ bgp_process(bgp_evpn, rn, afi, safi);
bgp_unlock_node(rn);
return 0;
}
/* Perform route selection and update zebra, if required. */
bgp_process(bgp_vrf, rn, afi, safi);
+ /* Process for route leaking. */
+ vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi);
+
return ret;
}
if (!pi)
return 0;
+ /* Process for route leaking. */
+ vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi);
+
bgp_aggregate_decrement(bgp_vrf, &rn->p, pi, afi, safi);
/* Mark entry for deletion */
return 0;
}
+/* This API will scan evpn routes for checking attribute's rmac
+ * macthes with bgp instance router mac. It avoid installing
+ * route into bgp vrf table and remote rmac in bridge table.
+ */
+static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,
+ struct prefix_evpn *evp,
+ struct bgp_path_info *pi)
+{
+ /* evpn route could have learnt prior to L3vni has come up,
+ * perform rmac check before installing route and
+ * remote router mac.
+ * The route will be removed from global bgp table once
+ * SVI comes up with MAC and stored in hash, triggers
+ * bgp_mac_rescan_all_evpn_tables.
+ */
+ if (pi->attr &&
+ memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) {
+ if (bgp_debug_update(pi->peer, NULL, NULL, 1)) {
+ char buf1[PREFIX_STRLEN];
+ char attr_str[BUFSIZ] = {0};
+
+ bgp_dump_attr(pi->attr, attr_str, BUFSIZ);
+
+ zlog_debug("%s: bgp %u prefix %s with attr %s - DENIED due to self mac",
+ __func__, bgp_vrf->vrf_id,
+ prefix2str(evp, buf1, sizeof(buf1)),
+ attr_str);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
/*
* Install or uninstall mac-ip routes are appropriate for this
* particular VRF.
struct bgp_path_info *pi;
int ret;
char buf[PREFIX_STRLEN];
- struct bgp *bgp_def = NULL;
+ struct bgp *bgp_evpn = NULL;
afi = AFI_L2VPN;
safi = SAFI_EVPN;
- bgp_def = bgp_get_default();
- if (!bgp_def)
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn)
return -1;
/* Walk entire global routing table and evaluate routes which could be
* imported into this VRF. Note that we need to loop through all global
* routes to determine which route matches the import rt on vrf
*/
- for (rd_rn = bgp_table_top(bgp_def->rib[afi][safi]); rd_rn;
+ for (rd_rn = bgp_table_top(bgp_evpn->rib[afi][safi]); rd_rn;
rd_rn = bgp_route_next(rd_rn)) {
table = bgp_node_get_bgp_table_info(rd_rn);
if (!table)
continue;
if (is_route_matching_for_vrf(bgp_vrf, pi)) {
+ if (bgp_evpn_route_rmac_self_check(
+ bgp_vrf, evp, pi))
+ continue;
+
if (install)
ret = install_evpn_route_entry_in_vrf(
bgp_vrf, evp, pi);
*/
static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
struct attr *attr, uint8_t *pfx, int psize,
- uint32_t addpath_id, int withdraw)
+ uint32_t addpath_id)
{
struct prefix_rd prd;
struct prefix_evpn p;
*/
/* Process the route. */
- if (!withdraw)
+ if (attr)
ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
&prd, &label, 1, 0, &evpn);
*/
static void evpn_auto_rt_import_add_for_vrf(struct bgp *bgp_vrf)
{
- struct bgp *bgp_def = NULL;
+ struct bgp *bgp_evpn = NULL;
form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl);
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
/* Map RT to VRF */
- bgp_def = bgp_get_default();
- if (!bgp_def)
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn)
return;
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
}
static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf)
{
- struct bgp *bgp_def = NULL;
+ struct bgp *bgp_evpn = NULL;
struct listnode *node = NULL;
struct bgpevpn *vpn = NULL;
- bgp_def = bgp_get_default();
- if (!bgp_def)
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn)
return;
/* update all type-5 routes */
/* update all type-2 routes */
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
- update_routes_for_vni(bgp_def, vpn);
+ update_routes_for_vni(bgp_evpn, vpn);
}
/*
table = bgp_vrf->rib[afi][safi];
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
- /* Only care about "selected" routes - non-imported. */
+ /* Only care about "selected" routes. Also ensure that
+ * these are routes that are injectable into EVPN.
+ */
/* TODO: Support for AddPath for EVPN. */
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
- && (!pi->extra || !pi->extra->parent)) {
+ && is_route_injectable_into_evpn(pi)) {
bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p,
afi, safi);
break;
table = bgp_vrf->rib[afi][safi];
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
/* Need to identify the "selected" route entry to use its
- * attribute. Also, we only consider "non-imported" routes.
+ * attribute. Also, ensure that the route is injectable
+ * into EVPN.
* TODO: Support for AddPath for EVPN.
*/
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
- && (!pi->extra || !pi->extra->parent)) {
+ && is_route_injectable_into_evpn(pi)) {
/* apply the route-map */
if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
break;
case BGP_EVPN_IP_PREFIX_ROUTE:
- if (process_type5_route(peer, afi, safi, attr, pnt,
- psize, addpath_id, withdraw)) {
+ if (process_type5_route(peer, afi, safi,
+ withdraw ? NULL : attr, pnt,
+ psize, addpath_id)) {
flog_err(
EC_BGP_PKT_PROCESS,
"%u:%s - Error in processing EVPN type-5 NLRI size %d",
*/
void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp)
{
+ if (is_vrf_rd_configured(bgp))
+ return;
+
form_auto_rd(bgp->router_id, bgp->vrf_rd_id, &bgp->vrf_prd);
}
return NULL;
vpn = XCALLOC(MTYPE_BGP_EVPN, sizeof(struct bgpevpn));
- if (!vpn)
- return NULL;
/* Set values - RD and RT set to defaults. */
vpn->vni = vni;
return NULL;
es = XCALLOC(MTYPE_BGP_EVPN_ES, sizeof(struct evpnes));
- if (!es)
- return NULL;
/* set the ESI and originator_ip */
memcpy(&es->esi, esi, sizeof(esi_t));
struct bgp *bgp_vrf)
{
struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
- struct bgp *bgp_def = NULL;
+ struct bgp *bgp_evpn = NULL;
- bgp_def = bgp_get_default();
- assert(bgp_def);
+ bgp_evpn = bgp_get_evpn();
+ assert(bgp_evpn);
if (vpn->tenant_vrf_id == bgp_vrf->vrf_id)
bgpevpn_link_to_l3vni(vpn);
ifindex_t svi_ifindex)
{
struct bgp *bgp_vrf = NULL; /* bgp VRF instance */
- struct bgp *bgp_def = NULL; /* default bgp instance */
+ struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */
struct listnode *node = NULL;
struct bgpevpn *vpn = NULL;
as_t as = 0;
- /* get the default instance - required to get the AS number for VRF
+ /* get the EVPN instance - required to get the AS number for VRF
* auto-creatio
*/
- bgp_def = bgp_get_default();
- if (!bgp_def) {
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn) {
flog_err(
EC_BGP_NO_DFLT,
- "Cannot process L3VNI %u ADD - default BGP instance not yet created",
+ "Cannot process L3VNI %u ADD - EVPN BGP instance not yet created",
l3vni);
return -1;
}
- as = bgp_def->as;
+ as = bgp_evpn->as;
/* if the BGP vrf instance doesn't exist - create one */
- bgp_vrf = bgp_lookup_by_name(vrf_id_to_name(vrf_id));
+ bgp_vrf = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp_vrf) {
int ret = 0;
ret = bgp_get(&bgp_vrf, &as, vrf_id_to_name(vrf_id),
- BGP_INSTANCE_TYPE_VRF);
+ vrf_id == VRF_DEFAULT ? BGP_INSTANCE_TYPE_DEFAULT
+ : BGP_INSTANCE_TYPE_VRF);
switch (ret) {
case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET:
flog_err(EC_BGP_MULTI_INSTANCE,
bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
/* link all corresponding l2vnis */
- hash_iterate(bgp_def->vnihash,
+ hash_iterate(bgp_evpn->vnihash,
(void (*)(struct hash_bucket *,
void *))link_l2vni_hash_to_l3vni,
bgp_vrf);
*/
if (!filter)
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
- update_routes_for_vni(bgp_def, vpn);
+ update_routes_for_vni(bgp_evpn, vpn);
/* advertise type-5 routes if needed */
update_advertise_vrf_routes(bgp_vrf);
int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id)
{
struct bgp *bgp_vrf = NULL; /* bgp vrf instance */
- struct bgp *bgp_def = NULL; /* default bgp instance */
+ struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */
struct listnode *node = NULL;
struct listnode *next = NULL;
struct bgpevpn *vpn = NULL;
return -1;
}
- bgp_def = bgp_get_default();
- if (!bgp_def) {
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn) {
flog_err(
EC_BGP_NO_DFLT,
- "Cannot process L3VNI %u Del - Could not find default BGP instance",
+ "Cannot process L3VNI %u Del - Could not find EVPN BGP instance",
l3vni);
return -1;
}
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY)) {
for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn)) {
UNSET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);
- update_routes_for_vni(bgp_def, vpn);
+ update_routes_for_vni(bgp_evpn, vpn);
}
}
#define EVPN_ROUTE_STRLEN 200 /* Must be >> MAC + IPv6 strings. */
#define EVPN_AUTORT_VXLAN 0x10000000
+#define EVPN_ENABLED(bgp) (bgp)->advertise_all_vni
static inline int is_evpn_enabled(void)
{
struct bgp *bgp = NULL;
- bgp = bgp_get_default();
- return bgp ? bgp->advertise_all_vni : 0;
+ bgp = bgp_get_evpn();
+ return bgp ? EVPN_ENABLED(bgp) : 0;
}
static inline void vni2label(vni_t vni, mpls_label_t *label)
!ri->extra->parent)
return 0;
- /* See if the parent is of family L2VPN/EVPN */
- parent_ri = (struct bgp_path_info *)ri->extra->parent;
+ /* Determine parent recursively */
+ for (parent_ri = ri->extra->parent;
+ parent_ri->extra && parent_ri->extra->parent;
+ parent_ri = parent_ri->extra->parent)
+ ;
+
+ /* See if of family L2VPN/EVPN */
rn = parent_ri->net;
if (!rn)
return 0;
return 0;
}
+/* Flag if the route path's family is EVPN. */
+static inline bool is_pi_family_evpn(struct bgp_path_info *pi)
+{
+ return is_pi_family_matching(pi, AFI_L2VPN, SAFI_EVPN);
+}
+
+/* Flag if the route is injectable into EVPN. This would be either a
+ * non-imported route or a non-EVPN imported route.
+ */
+static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
+{
+ struct bgp_path_info *parent_pi;
+ struct bgp_table *table;
+ struct bgp_node *rn;
+
+ if (pi->sub_type != BGP_ROUTE_IMPORTED ||
+ !pi->extra ||
+ !pi->extra->parent)
+ return true;
+
+ parent_pi = (struct bgp_path_info *)pi->extra->parent;
+ rn = parent_pi->net;
+ if (!rn)
+ return true;
+ table = bgp_node_table(rn);
+ if (table &&
+ table->afi == AFI_L2VPN &&
+ table->safi == SAFI_EVPN)
+ return false;
+ return true;
+}
+
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
struct prefix *p,
struct attr *src_attr, afi_t afi,
#define RT_ADDRSTRLEN 28
-/* EVPN prefix lengths. This reprsent the sizeof struct prefix_evpn */
-#define EVPN_ROUTE_PREFIXLEN 224
+/* EVPN prefix lengths. This represents the sizeof struct evpn_addr
+ * in bits */
+#define EVPN_ROUTE_PREFIXLEN (sizeof(struct evpn_addr) * 8)
/* EVPN route types. */
typedef enum {
json_object *json_scode = NULL;
json_object *json_ocode = NULL;
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (bgp == NULL) {
if (!use_json)
vty_out(vty, "No BGP process is configured\n");
/*
* Display import RT mapping to VRFs (vty handler)
- * bgp_def: default bgp instance
+ * bgp_evpn: evpn bgp instance
*/
-static void evpn_show_vrf_import_rts(struct vty *vty, struct bgp *bgp_def,
+static void evpn_show_vrf_import_rts(struct vty *vty, struct bgp *bgp_evpn,
json_object *json)
{
void *args[2];
args[0] = vty;
args[1] = json;
- hash_iterate(bgp_def->vrf_import_rt_hash,
+ hash_iterate(bgp_evpn->vrf_import_rt_hash,
(void (*)(struct hash_bucket *,
void *))show_vrf_import_rt_entry,
args);
static void evpn_set_advertise_all_vni(struct bgp *bgp)
{
bgp->advertise_all_vni = 1;
+ bgp_set_evpn(bgp);
bgp_zebra_advertise_all_vni(bgp, bgp->advertise_all_vni);
}
static void evpn_unset_advertise_all_vni(struct bgp *bgp)
{
bgp->advertise_all_vni = 0;
+ bgp_set_evpn(bgp_get_default());
bgp_zebra_advertise_all_vni(bgp, bgp->advertise_all_vni);
bgp_evpn_cleanup_on_disable(bgp);
}
if (!bgp)
return CMD_WARNING;
- if (bgp->vrf_id != VRF_DEFAULT) {
+ if (!EVPN_ENABLED(bgp)) {
vty_out(vty,
- "This command is only supported under Default VRF\n");
+ "This command is only supported under the EVPN VRF\n");
return CMD_WARNING;
}
if (!bgp)
return CMD_WARNING;
- if (bgp->vrf_id != VRF_DEFAULT) {
+ if (!EVPN_ENABLED(bgp)) {
vty_out(vty,
- "This command is only supported under Default VRF\n");
+ "This command is only supported under the EVPN VRF\n");
return CMD_WARNING;
}
"Advertise All local VNIs\n")
{
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+ struct bgp *bgp_evpn = NULL;
if (!bgp)
return CMD_WARNING;
+
+ bgp_evpn = bgp_get_evpn();
+ if (bgp_evpn && bgp_evpn != bgp) {
+ vty_out(vty, "%% Please unconfigure EVPN in VRF %s\n",
+ bgp_evpn->name);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
evpn_set_advertise_all_vni(bgp);
return CMD_SUCCESS;
}
if (!bgp_vrf)
return CMD_WARNING;
- if (bgp_vrf->vrf_id != VRF_DEFAULT) {
+ if (!EVPN_ENABLED(bgp_vrf)) {
vty_out(vty,
- "This command is only supported under Default VRF\n");
+ "This command is only supported under the EVPN VRF\n");
return CMD_WARNING;
}
if (!bgp_vrf)
return CMD_WARNING;
- if (bgp_vrf->vrf_id != VRF_DEFAULT) {
+ if (!EVPN_ENABLED(bgp_vrf)) {
vty_out(vty,
- "This command is only supported under Default VRF\n");
+ "This command is only supported under the EVPN VRF\n");
return CMD_WARNING;
}
if (!bgp_vrf)
return CMD_WARNING;
- if (bgp_vrf->vrf_id != VRF_DEFAULT) {
+ if (!EVPN_ENABLED(bgp_vrf)) {
vty_out(vty,
- "This command is only supported under Default VRF\n");
+ "This command is only supported under the EVPN VRF\n");
return CMD_WARNING;
}
if (!bgp)
return CMD_WARNING;
- if (bgp->vrf_id != VRF_DEFAULT) {
+ if (!EVPN_ENABLED(bgp)) {
vty_out(vty,
- "This command is only supported under Default VRF\n");
+ "This command is only supported under EVPN VRF\n");
return CMD_WARNING;
}
}
/* advertise type-5 routes */
- bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
+ if (advertise_type5_routes(bgp_vrf, afi))
+ bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
return CMD_SUCCESS;
}
"VNI number\n"
JSON_STR)
{
- struct bgp *bgp_def;
+ struct bgp *bgp_evpn;
vni_t vni;
int idx = 0;
bool uj = false;
uj = use_json(argc, argv);
- bgp_def = bgp_get_default();
- if (!bgp_def)
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn)
return CMD_WARNING;
if (!argv_find(argv, argc, "evpn", &idx))
if ((uj && argc == ((idx + 1) + 2)) || (!uj && argc == (idx + 1) + 1)) {
- num_l2vnis = hashcount(bgp_def->vnihash);
+ num_l2vnis = hashcount(bgp_evpn->vnihash);
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) {
if (bgp_temp->l3vni)
num_vnis = num_l2vnis + num_l3vnis;
if (uj) {
json_object_string_add(json, "advertiseGatewayMacip",
- bgp_def->advertise_gw_macip
+ bgp_evpn->advertise_gw_macip
? "Enabled"
: "Disabled");
json_object_string_add(json, "advertiseAllVnis",
: "Disabled");
json_object_string_add(
json, "flooding",
- bgp_def->vxlan_flood_ctrl
+ bgp_evpn->vxlan_flood_ctrl
== VXLAN_FLOOD_HEAD_END_REPL
? "Head-end replication"
: "Disabled");
json_object_int_add(json, "numL3Vnis", num_l3vnis);
} else {
vty_out(vty, "Advertise Gateway Macip: %s\n",
- bgp_def->advertise_gw_macip ? "Enabled"
+ bgp_evpn->advertise_gw_macip ? "Enabled"
: "Disabled");
vty_out(vty, "Advertise SVI Macip: %s\n",
- bgp_def->evpn_info->advertise_svi_macip ? "Enabled"
+ bgp_evpn->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",
- bgp_def->vxlan_flood_ctrl
+ bgp_evpn->vxlan_flood_ctrl
== VXLAN_FLOOD_HEAD_END_REPL
? "Head-end replication"
: "Disabled");
vty_out(vty, "Number of L2 VNIs: %u\n", num_l2vnis);
vty_out(vty, "Number of L3 VNIs: %u\n", num_l3vnis);
}
- evpn_show_all_vnis(vty, bgp_def, json);
+ evpn_show_all_vnis(vty, bgp_evpn, json);
} else {
int vni_idx = 0;
/* Display specific VNI */
vni = strtoul(argv[vni_idx + 1]->arg, NULL, 10);
- evpn_show_vni(vty, bgp_def, vni, json);
+ evpn_show_vni(vty, bgp_evpn, vni, json);
}
if (uj) {
memset(&esi, 0, sizeof(esi));
uj = use_json(argc, argv);
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (!bgp)
return CMD_WARNING;
uj = use_json(argc, argv);
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (!bgp)
return CMD_WARNING;
bool uj = false;
json_object *json = NULL;
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (!bgp)
return CMD_WARNING;
memset(&mac, 0, sizeof(struct ethaddr));
memset(&ip, 0, sizeof(struct ipaddr));
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (!bgp)
return CMD_WARNING;
json_object *json = NULL;
memset(&esi, 0, sizeof(esi));
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (!bgp)
return CMD_WARNING;
bool uj = false;
json_object *json = NULL;
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (!bgp)
return CMD_WARNING;
bool uj = false;
json_object *json = NULL;
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (!bgp)
return CMD_WARNING;
bool uj = false;
json_object *json = NULL;
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (!bgp)
return CMD_WARNING;
bool uj = false;
json_object *json = NULL;
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (!bgp)
return CMD_WARNING;
JSON_STR)
{
bool uj = false;
- struct bgp *bgp_def = NULL;
+ struct bgp *bgp_evpn = NULL;
json_object *json = NULL;
- bgp_def = bgp_get_default();
- if (!bgp_def)
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn)
return CMD_WARNING;
uj = use_json(argc, argv);
if (uj)
json = json_object_new_object();
- evpn_show_vrf_import_rts(vty, bgp_def, json);
+ evpn_show_vrf_import_rts(vty, bgp_evpn, json);
if (uj) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
bool uj = false;
json_object *json = NULL;
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (!bgp)
return CMD_WARNING;
struct bgp *bgp;
struct ipaddr vtep_ip;
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (!bgp) {
- vty_out(vty, "%%Default BGP instance not yet created\n");
+ vty_out(vty, "%%EVPN BGP instance not yet created\n");
return CMD_WARNING;
}
struct bgp *bgp;
struct ipaddr vtep_ip;
- bgp = bgp_get_default();
+ bgp = bgp_get_evpn();
if (!bgp) {
- vty_out(vty, "%%Default BGP instance not yet created\n");
+ vty_out(vty, "%%EVPN BGP instance not yet created\n");
return CMD_WARNING;
}
if (!bgp)
return CMD_WARNING;
- if (bgp->vrf_id != VRF_DEFAULT) {
+ if (!EVPN_ENABLED(bgp)) {
vty_out(vty,
- "This command is only supported under Default VRF\n");
+ "This command is only supported under EVPN VRF\n");
return CMD_WARNING;
}
if (!bgp)
return CMD_WARNING;
- if (bgp->vrf_id != VRF_DEFAULT) {
+ if (!EVPN_ENABLED(bgp)) {
vty_out(vty,
- "This command is only supported under Default VRF\n");
+ "This command is only supported under EVPN VRF\n");
return CMD_WARNING;
}
if (!bgp)
return CMD_WARNING;
- if (bgp->vrf_id != VRF_DEFAULT) {
+ if (!EVPN_ENABLED(bgp)) {
vty_out(vty,
- "This command is only supported under Default VRF\n");
+ "This command is only supported under EVPN VRF\n");
return CMD_WARNING;
}
if (!bgp)
return CMD_WARNING;
- if (bgp->vrf_id != VRF_DEFAULT) {
+ if (!EVPN_ENABLED(bgp)) {
vty_out(vty,
- "This command is only supported under Default VRF\n");
+ "This command is only supported under EVPN VRF\n");
return CMD_WARNING;
}
if (!bgp)
return CMD_WARNING;
- if (bgp->vrf_id != VRF_DEFAULT) {
+ if (!EVPN_ENABLED(bgp)) {
vty_out(vty,
- "This command is only supported under Default VRF\n");
+ "This command is only supported under EVPN VRF\n");
return CMD_WARNING;
}
if (!bgp)
return CMD_WARNING;
- if (bgp->vrf_id != VRF_DEFAULT) {
+ if (!EVPN_ENABLED(bgp)) {
vty_out(vty,
- "This command is only supported under Default VRF\n");
+ "This command is only supported under EVPN VRF\n");
return CMD_WARNING;
}
vty_out(vty, " default-originate ipv6\n");
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
- vty_out(vty, " rd %s\n",
+ vty_out(vty, " rd %s\n",
prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1)));
/* import route-target */
{
if (asfilter->reg)
bgp_regex_free(asfilter->reg);
- if (asfilter->reg_str)
- XFREE(MTYPE_AS_FILTER_STR, asfilter->reg_str);
+ XFREE(MTYPE_AS_FILTER_STR, asfilter->reg_str);
XFREE(MTYPE_AS_FILTER, asfilter);
}
/* Run hook function. */
if (as_list_master.delete_hook)
(*as_list_master.delete_hook)(name);
- if (name)
- XFREE(MTYPE_AS_STR, name);
+ XFREE(MTYPE_AS_STR, name);
}
static int as_filter_match(struct as_filter *asfilter, struct aspath *aspath)
status start timer is on unless peer is shutdown or peer is
inactive. All other timer must be turned off */
if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer)
- || peer->bgp->vrf_id == VRF_UNKNOWN) {
+ || (peer->bgp->inst_type != BGP_INSTANCE_TYPE_VIEW &&
+ peer->bgp->vrf_id == VRF_UNKNOWN)) {
BGP_TIMER_OFF(peer->t_start);
} else {
BGP_TIMER_ON(peer->t_start, bgp_start_timer,
return 0;
}
- if (peer->bgp->vrf_id == VRF_UNKNOWN) {
+ if (peer->bgp->inst_type != BGP_INSTANCE_TYPE_VIEW &&
+ peer->bgp->vrf_id == VRF_UNKNOWN) {
if (bgp_debug_neighbor_events(peer))
flog_err(
EC_BGP_FSM,
static void lp_lcb_free(void *goner)
{
- if (goner)
- XFREE(MTYPE_BGP_LABEL_CB, goner);
+ XFREE(MTYPE_BGP_LABEL_CB, goner);
}
static void lp_chunk_free(void *goner)
{
- if (goner)
- XFREE(MTYPE_BGP_LABEL_CHUNK, goner);
+ XFREE(MTYPE_BGP_LABEL_CHUNK, goner);
}
void bgp_lp_init(struct thread_master *master, struct labelpool *pool)
/* Allocate a new lcommunities. */
static struct lcommunity *lcommunity_new(void)
{
- return (struct lcommunity *)XCALLOC(MTYPE_LCOMMUNITY,
- sizeof(struct lcommunity));
+ return XCALLOC(MTYPE_LCOMMUNITY, sizeof(struct lcommunity));
}
/* Allocate lcommunities. */
void lcommunity_free(struct lcommunity **lcom)
{
- if ((*lcom)->val)
- XFREE(MTYPE_LCOMMUNITY_VAL, (*lcom)->val);
- if ((*lcom)->str)
- XFREE(MTYPE_LCOMMUNITY_STR, (*lcom)->str);
+ XFREE(MTYPE_LCOMMUNITY_VAL, (*lcom)->val);
+ XFREE(MTYPE_LCOMMUNITY_STR, (*lcom)->str);
XFREE(MTYPE_LCOMMUNITY, *lcom);
}
{
int i;
int len;
- bool first = 1;
+ bool first = true;
char *str_buf;
char *str_pnt;
uint8_t *pnt;
for (i = 0; i < lcom->size; i++) {
if (first)
- first = 0;
+ first = false;
else
*str_pnt++ = ' ';
const struct lcommunity *lcom2 = arg2;
if (lcom1 == NULL && lcom2 == NULL)
- return 1;
+ return true;
if (lcom1 == NULL || lcom2 == NULL)
- return 0;
+ return false;
return (lcom1->size == lcom2->size
&& memcmp(lcom1->val, lcom2->val, lcom_length(lcom1)) == 0);
bgp_mac_remove_ifp_internal(bsm, ifp->name);
}
-bool bgp_mac_entry_exists(struct prefix *p)
+/* This API checks MAC address against any of local
+ * assigned (SVIs) MAC address.
+ * An example: router-mac attribute in any of evpn update
+ * requires to compare against local mac.
+ */
+bool bgp_mac_exist(struct ethaddr *mac)
{
- struct prefix_evpn *pevpn = (struct prefix_evpn *)p;
struct bgp_self_mac lookup;
struct bgp_self_mac *bsm;
+ static uint8_t tmp [ETHER_ADDR_STRLEN] = {0};
+
+ if (memcmp(mac, &tmp, ETH_ALEN) == 0)
+ return false;
+
+ memcpy(&lookup.macaddr, mac, ETH_ALEN);
+ bsm = hash_lookup(bm->self_mac_hash, &lookup);
+ if (!bsm)
+ return false;
+
+ return true;
+}
+
+/* This API checks EVPN type-2 prefix and comapares
+ * mac against any of local assigned (SVIs) MAC
+ * address.
+ */
+bool bgp_mac_entry_exists(struct prefix *p)
+{
+ struct prefix_evpn *pevpn = (struct prefix_evpn *)p;
if (pevpn->family != AF_EVPN)
return false;
if (pevpn->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
return false;
- memcpy(&lookup.macaddr, &p->u.prefix_evpn.macip_addr.mac, ETH_ALEN);
- bsm = hash_lookup(bm->self_mac_hash, &lookup);
- if (!bsm)
- return false;
+ return bgp_mac_exist(&p->u.prefix_evpn.macip_addr.mac);
return true;
}
* Function to lookup the prefix and see if we have a matching mac
*/
bool bgp_mac_entry_exists(struct prefix *p);
+bool bgp_mac_exist(struct ethaddr *mac);
#endif
*/
static __attribute__((__noreturn__)) void bgp_exit(int status)
{
- struct bgp *bgp, *bgp_default;
+ struct bgp *bgp, *bgp_default, *bgp_evpn;
struct listnode *node, *nnode;
/* it only makes sense for this to be called on a clean exit */
bgp_close();
bgp_default = bgp_get_default();
+ bgp_evpn = bgp_get_evpn();
/* reverse bgp_master_init */
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
- if (bgp_default == bgp)
+ if (bgp_default == bgp || bgp_evpn == bgp)
continue;
bgp_delete(bgp);
}
+ if (bgp_evpn && bgp_evpn != bgp_default)
+ bgp_delete(bgp_evpn);
if (bgp_default)
bgp_delete(bgp_default);
bgp_vrf_link(bgp, vrf);
bgp_handle_socket(bgp, vrf, old_vrf_id, true);
- /* Update any redistribute vrf bitmaps if the vrf_id changed */
+ /* Update any redistribution if vrf_id changed */
if (old_vrf_id != bgp->vrf_id)
- bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id);
+ bgp_redistribute_redo(bgp);
bgp_instance_up(bgp);
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
/* We have instance configured, unlink from VRF and make it
* "down". */
bgp_vrf_unlink(bgp, vrf);
- /* Update any redistribute vrf bitmaps if the vrf_id changed */
+ /* Delete any redistribute vrf bitmaps if the vrf_id changed */
if (old_vrf_id != bgp->vrf_id)
- bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id);
+ bgp_unset_redist_vrf_bitmaps(bgp, old_vrf_id);
bgp_instance_down(bgp);
}
bgp_path_info_mpath_count_set(dmed_best, 0);
UNSET_FLAG(dmed_best->flags, BGP_PATH_MULTIPATH_CHG);
- assert(bgp_path_info_mpath_first(dmed_best) == 0);
+ assert(bgp_path_info_mpath_first(dmed_best) == NULL);
}
/*
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_nht.h"
+#include "bgpd/bgp_evpn.h"
#if ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
if (bpi->extra && bpi->extra->bgp_orig)
bgp_nexthop = bpi->extra->bgp_orig;
- /* No nexthop tracking for redistributed routes */
- if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
+ /*
+ * No nexthop tracking for redistributed routes or for
+ * EVPN-imported routes that get leaked.
+ */
+ if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
+ is_pi_family_evpn(bpi_ultimate))
nh_valid = 1;
else
/*
* No nexthop tracking for redistributed routes because
* their originating protocols will do the tracking and
* withdraw those routes if the nexthops become unreachable
+ * This also holds good for EVPN-imported routes that get
+ * leaked.
*/
- if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
+ if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
+ is_pi_family_evpn(bpi_ultimate))
nh_valid = 1;
else
/*
return;
}
- /* loop check - should not be an imported route. */
- if (path_vrf->extra && path_vrf->extra->bgp_orig)
+ /* Is this route exportable into the VPN table? */
+ if (!is_route_injectable_into_vpn(path_vrf))
return;
-
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: %s skipping: %s", __func__,
path_vrf->type, path_vrf->sub_type);
}
- if (path_vrf->sub_type != BGP_ROUTE_NORMAL
- && path_vrf->sub_type != BGP_ROUTE_STATIC
- && path_vrf->sub_type != BGP_ROUTE_REDISTRIBUTE) {
-
- if (debug)
- zlog_debug("%s: wrong sub_type %d", __func__,
- path_vrf->sub_type);
- return;
- }
if (!bgp_vpn)
return;
return;
}
+ /* Is this route exportable into the VPN table? */
+ if (!is_route_injectable_into_vpn(path_vrf))
+ return;
+
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg);
== bgp_vrf) {
/* delete route */
if (debug)
- zlog_debug("%s: deleting it\n",
+ zlog_debug("%s: deleting it",
__func__);
bgp_aggregate_decrement(bgp_vpn, &bn->p,
bpi, afi, safi);
for (bpi = bgp_node_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
- if (bpi->extra && bpi->extra->bgp_orig != bgp_vrf) {
+ if (bpi->extra
+ && bpi->extra->bgp_orig != bgp_vrf
+ && bpi->extra->parent
+ && is_pi_family_vpn(bpi->extra->parent)) {
/* delete route */
bgp_aggregate_decrement(bgp_vrf, &bn->p, bpi,
}
}
+/* This API is used during router-id change, reflect VPNs
+ * auto RD and RT values and readvertise routes to VPN table.
+ */
+void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw)
+{
+ afi_t afi;
+ int debug;
+ char *vname;
+ const char *export_name;
+ char buf[RD_ADDRSTRLEN];
+ struct bgp *bgp_import;
+ struct listnode *node;
+ struct ecommunity *ecom;
+ vpn_policy_direction_t idir, edir;
+
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT
+ && bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+ return;
+
+ export_name = bgp->name ? bgp->name : VRF_DEFAULT_NAME;
+ debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
+ BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
+
+ idir = BGP_VPN_POLICY_DIR_FROMVPN;
+ edir = BGP_VPN_POLICY_DIR_TOVPN;
+
+ for (afi = 0; afi < AFI_MAX; ++afi) {
+ if (!vpn_leak_to_vpn_active(bgp, afi, NULL))
+ continue;
+
+ if (withdraw) {
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN,
+ afi, bgp_get_default(), bgp);
+ if (debug)
+ zlog_debug("%s: %s after to_vpn vpn_leak_prechange",
+ __func__, export_name);
+
+ /* Remove import RT from VRFs */
+ ecom = bgp->vpn_policy[afi].rtlist[edir];
+ for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi].
+ export_vrf, node, vname)) {
+ bgp_import = bgp_lookup_by_name(vname);
+ if (!bgp_import)
+ continue;
+
+ ecommunity_del_val(bgp_import->vpn_policy[afi].
+ rtlist[idir],
+ (struct ecommunity_val *)ecom->val);
+
+ }
+ } else {
+ /* New router-id derive auto RD and RT and export
+ * to VPN
+ */
+ form_auto_rd(bgp->router_id, bgp->vrf_rd_id,
+ &bgp->vrf_prd_auto);
+ bgp->vpn_policy[afi].tovpn_rd = bgp->vrf_prd_auto;
+ prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd, buf,
+ sizeof(buf));
+ bgp->vpn_policy[afi].rtlist[edir] =
+ ecommunity_str2com(buf,
+ ECOMMUNITY_ROUTE_TARGET, 0);
+
+ /* Update import_vrf rt_list */
+ ecom = bgp->vpn_policy[afi].rtlist[edir];
+ for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi].
+ export_vrf, node, vname)) {
+ bgp_import = bgp_lookup_by_name(vname);
+ if (!bgp_import)
+ continue;
+ if (bgp_import->vpn_policy[afi].rtlist[idir])
+ bgp_import->vpn_policy[afi].rtlist[idir]
+ = ecommunity_merge(
+ bgp_import->vpn_policy[afi]
+ .rtlist[idir], ecom);
+ else
+ bgp_import->vpn_policy[afi].rtlist[idir]
+ = ecommunity_dup(ecom);
+
+ }
+ /* Update routes to VPN */
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN,
+ afi, bgp_get_default(),
+ bgp);
+ if (debug)
+ zlog_debug("%s: %s after to_vpn vpn_leak_postchange",
+ __func__, export_name);
+ }
+ }
+}
+
void vpn_policy_routemap_event(const char *rmap_name)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT);
char buf[1000];
struct ecommunity *ecom;
bool first_export = false;
+ int debug;
export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME;
idir = BGP_VPN_POLICY_DIR_FROMVPN;
edir = BGP_VPN_POLICY_DIR_TOVPN;
+ debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
+ BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
+
/*
* Cross-ref both VRFs. Also, note if this is the first time
* any VRF is importing from "import_vrf".
to_bgp->vpn_policy[afi].rtlist[idir] = ecommunity_dup(ecom);
SET_FLAG(to_bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT);
+ if (debug) {
+ const char *from_name;
+
+ from_name = from_bgp->name ? from_bgp->name :
+ VRF_DEFAULT_NAME;
+ zlog_debug("%s from %s to %s first_export %u import-rt %s export-rt %s",
+ __func__, from_name, export_name, first_export,
+ to_bgp->vpn_policy[afi].rtlist[idir] ?
+ (ecommunity_ecom2str(to_bgp->vpn_policy[afi].
+ rtlist[idir],
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0)) : " ",
+ to_bgp->vpn_policy[afi].rtlist[edir] ?
+ (ecommunity_ecom2str(to_bgp->vpn_policy[afi].
+ rtlist[edir],
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0)) : " ");
+ }
+
/* Does "import_vrf" first need to export its routes or that
* is already done and we just need to import those routes
* from the global table?
char *vname;
struct ecommunity *ecom;
struct listnode *node;
+ int debug;
export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME;
tmp_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME;
idir = BGP_VPN_POLICY_DIR_FROMVPN;
edir = BGP_VPN_POLICY_DIR_TOVPN;
+ debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
+ BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
+
/* Were we importing from "import_vrf"? */
for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi].import_vrf, node,
vname)) {
if (!vname)
return;
+ if (debug)
+ zlog_debug("%s from %s to %s", __func__, tmp_name, export_name);
+
/* Remove "import_vrf" from our import list. */
listnode_delete(to_bgp->vpn_policy[afi].import_vrf, vname);
XFREE(MTYPE_TMP, vname);
}
}
+/* Flag if the route is injectable into VPN. This would be either a
+ * non-imported route or a non-VPN imported route.
+ */
+static inline bool is_route_injectable_into_vpn(struct bgp_path_info *pi)
+{
+ struct bgp_path_info *parent_pi;
+ struct bgp_table *table;
+ struct bgp_node *rn;
+
+ if (pi->sub_type != BGP_ROUTE_IMPORTED ||
+ !pi->extra ||
+ !pi->extra->parent)
+ return true;
+
+ parent_pi = (struct bgp_path_info *)pi->extra->parent;
+ rn = parent_pi->net;
+ if (!rn)
+ return true;
+ table = bgp_node_table(rn);
+ if (table &&
+ (table->afi == AFI_IP || table->afi == AFI_IP6) &&
+ table->safi == SAFI_MPLS_VPN)
+ return false;
+ return true;
+}
+
+/* Flag if the route path's family is VPN. */
+static inline bool is_pi_family_vpn(struct bgp_path_info *pi)
+{
+ return (is_pi_family_matching(pi, AFI_IP, SAFI_MPLS_VPN) ||
+ is_pi_family_matching(pi, AFI_IP6, SAFI_MPLS_VPN));
+}
+
extern void vpn_policy_routemap_event(const char *rmap_name);
extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey);
extern void vpn_leak_postchange_all(void);
+extern void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw);
#endif /* _QUAGGA_BGP_MPLSVPN_H */
if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) {
SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
- } else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
+ } else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED) &&
+ !is_default_host_route(&bnc->node->p))
register_zebra_rnh(bnc, is_bgp_static_route);
+
if (pi && pi->nexthop != bnc) {
/* Unlink from existing nexthop cache, if any. This will also
* free
unary_operator, and_valmask,
or_valmask, list[i].value,
type_entry);
- if (ret == false)
+ if (!ret)
return ret;
continue;
}
range->min_port = list[i].value;
exact_match = true;
}
- if (exact_match == true && i > 0)
+ if (exact_match && i > 0)
return false;
if (list[i].compare_operator ==
(OPERATOR_COMPARE_GREATER_THAN +
"too complex. ignoring.");
return 0;
} else if (api->match_icmp_type_num > 1 &&
- enumerate_icmp == false) {
+ !enumerate_icmp) {
if (BGP_DEBUG(pbr, PBR))
zlog_debug("BGP: match icmp code is enumerate"
", and icmp type is not."
out:
if (s)
stream_free(s);
- if (half)
- XFREE(MTYPE_TMP, half);
+ XFREE(MTYPE_TMP, half);
return lret;
}
/* advertise/withdraw type-5 routes */
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
- if (advertise_type5_routes(bgp, afi) && new_select &&
- (!new_select->extra || !new_select->extra->parent)) {
+ if (advertise_type5_routes(bgp, afi) &&
+ new_select &&
+ is_route_injectable_into_evpn(new_select)) {
/* apply the route-map */
if (bgp->adv_cmd_rmap[afi][safi].map) {
afi, safi);
}
- } else if (advertise_type5_routes(bgp, afi) && old_select &&
- (!old_select->extra || !old_select->extra->parent))
+ } else if (advertise_type5_routes(bgp, afi) &&
+ old_select &&
+ is_route_injectable_into_evpn(old_select))
bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
}
goto filtered;
}
- if (bgp_mac_entry_exists(p)) {
+ if (bgp_mac_entry_exists(p) || bgp_mac_exist(&attr->rmac)) {
reason = "self mac;";
goto filtered;
}
static void bgp_static_free(struct bgp_static *bgp_static)
{
- if (bgp_static->rmap.name)
- XFREE(MTYPE_ROUTE_MAP_NAME, 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_ATTR, bgp_static->eth_s_id);
XFREE(MTYPE_BGP_STATIC, bgp_static);
}
bgp_static->backdoor = backdoor;
if (rmap) {
- if (bgp_static->rmap.name)
- XFREE(MTYPE_ROUTE_MAP_NAME,
- 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 =
route_map_counter_increment(
bgp_static->rmap.map);
} else {
- if (bgp_static->rmap.name)
- XFREE(MTYPE_ROUTE_MAP_NAME,
- 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->label_index = label_index;
if (rmap) {
- if (bgp_static->rmap.name)
- XFREE(MTYPE_ROUTE_MAP_NAME,
- 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 =
bgp_static->prd = prd;
if (rmap_str) {
- if (bgp_static->rmap.name)
- XFREE(MTYPE_ROUTE_MAP_NAME,
- 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);
rmap = &bgp->table_map[afi][safi];
if (rmap_name) {
- if (rmap->name)
- XFREE(MTYPE_ROUTE_MAP_NAME, 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);
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
route_map_counter_decrement(rmap->map);
rmap->name = NULL;
rmap->map = NULL;
struct bgp_rmap *rmap;
rmap = &bgp->table_map[afi][safi];
- if (rmap->name)
- XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
route_map_counter_decrement(rmap->map);
rmap->name = NULL;
rmap->map = NULL;
}
#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(
return CMD_WARNING_CONFIG_FAILED;
}
- if (bdistance->access_list)
- XFREE(MTYPE_AS_LIST, bdistance->access_list);
+ XFREE(MTYPE_AS_LIST, bdistance->access_list);
bgp_distance_free(bdistance);
bgp_node_set_bgp_path_info(rn, NULL);
decode_label(&bgp_static->label), esi, buf2,
macrouter);
- if (macrouter)
- XFREE(MTYPE_TMP, macrouter);
- if (esi)
- XFREE(MTYPE_TMP, esi);
+ XFREE(MTYPE_TMP, macrouter);
+ XFREE(MTYPE_TMP, esi);
}
}
}
return 0;
}
+/* Flag if the route path's family matches params. */
+static inline bool is_pi_family_matching(struct bgp_path_info *pi,
+ afi_t afi, safi_t safi)
+{
+ struct bgp_table *table;
+ struct bgp_node *rn;
+
+ rn = pi->net;
+ if (!rn)
+ return false;
+ table = bgp_node_table(rn);
+ if (table &&
+ table->afi == afi &&
+ table->safi == safi)
+ return true;
+ return false;
+}
+
/* Prototypes. */
extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi,
struct peer *peer, afi_t afi, safi_t safi);
}
rv = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_value));
- if (!rv)
- return NULL;
rv->action = action;
rv->variable = var;
{
struct bgp_match_peer_compiled *pc = rule;
- if (pc->interface)
- XFREE(MTYPE_ROUTE_MAP_COMPILED, pc->interface);
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, pc->interface);
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
}
char *end = NULL;
vni = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(vni_t));
- if (!vni)
- return NULL;
*vni = strtoul(arg, &end, 10);
if (*end != '\0') {
local_pref = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
- if (!local_pref)
- return local_pref;
-
*local_pref = tmpval;
return local_pref;
}
{
struct rmap_ip_nexthop_set *rins = rule;
- if (rins->address)
- XFREE(MTYPE_ROUTE_MAP_COMPILED, rins->address);
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rins->address);
XFREE(MTYPE_ROUTE_MAP_COMPILED, rins);
}
static void *route_set_lcommunity_delete_compile(const char *arg)
{
struct rmap_community *rcom;
- char *p;
- char *str;
- int len;
rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
- p = strchr(arg, ' ');
- if (p) {
- len = p - arg;
- str = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1);
- memcpy(str, arg, len);
- } else
- str = NULL;
-
- rcom->name = str;
+ rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
rcom->name_hash = bgp_clist_hash_key(rcom->name);
+
return rcom;
}
static void *route_set_community_delete_compile(const char *arg)
{
struct rmap_community *rcom;
- char *p;
- char *str;
- int len;
rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
- p = strchr(arg, ' ');
- if (p) {
- len = p - arg;
- str = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1);
- memcpy(str, arg, len);
- } else
- str = NULL;
-
- rcom->name = str;
+ rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
rcom->name_hash = bgp_clist_hash_key(rcom->name);
+
return rcom;
}
break;
}
- if (dep_name)
- XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
- if (rmap_name)
- XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+ XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
return retval;
}
"Processing route_map %s update on advertise type5 route command",
rmap_name);
- if (route_update) {
+ if (route_update && advertise_type5_routes(bgp, afi)) {
bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
bgp_evpn_advertise_type5_routes(bgp, afi, safi);
}
"Delete matching communities\n")
{
int idx_comm_list = 2;
- char *str;
-
- str = XCALLOC(MTYPE_TMP,
- strlen(argv[idx_comm_list]->arg) + strlen(" delete") + 1);
- strcpy(str, argv[idx_comm_list]->arg);
- strcpy(str + strlen(argv[idx_comm_list]->arg), " delete");
generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), "comm-list",
- str);
+ argv[idx_comm_list]->arg);
- XFREE(MTYPE_TMP, str);
return CMD_SUCCESS;
}
"Large Community-list name\n"
"Delete matching large communities\n")
{
- char *str;
-
- str = XCALLOC(MTYPE_TMP, strlen(argv[2]->arg) + strlen(" delete") + 1);
- strcpy(str, argv[2]->arg);
- strcpy(str + strlen(argv[2]->arg), " delete");
-
generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
- "large-comm-list", str);
+ "large-comm-list", argv[2]->arg);
- XFREE(MTYPE_TMP, str);
return CMD_SUCCESS;
}
static struct cache *find_cache(const uint8_t preference);
static int add_tcp_cache(const char *host, const char *port,
const uint8_t preference);
-static void print_record(const struct pfx_record *record, void *data);
+static void print_record(const struct pfx_record *record, struct vty *vty);
static int is_synchronized(void);
static int is_running(void);
static void route_match_free(void *rule);
return NULL;
}
-static void print_record(const struct pfx_record *record, void *data)
+static void print_record(const struct pfx_record *record, struct vty *vty)
{
char ip[INET6_ADDRSTRLEN];
+
+ lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
+ vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len,
+ record->max_len, record->asn);
+}
+
+static void print_record_cb(const struct pfx_record *record, void *data)
+{
struct rpki_for_each_record_arg *arg = data;
struct vty *vty = arg->vty;
(*arg->prefix_amount)++;
- lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
- vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len,
- record->max_len, record->asn);
+ print_record(record, vty);
}
static struct rtr_mgr_group *get_groups(void)
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS");
arg.prefix_amount = &number_of_ipv4_prefixes;
- pfx_table_for_each_ipv4_record(pfx_table, print_record, &arg);
+ pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg);
arg.prefix_amount = &number_of_ipv6_prefixes;
- pfx_table_for_each_ipv6_record(pfx_table, print_record, &arg);
+ pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg);
vty_out(vty, "Number of IPv4 Prefixes: %u\n", number_of_ipv4_prefixes);
vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes);
return CMD_SUCCESS;
}
+DEFPY (show_rpki_prefix,
+ show_rpki_prefix_cmd,
+ "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)$asn]",
+ SHOW_STR
+ RPKI_OUTPUT_STRING
+ "Lookup IP prefix and optionally ASN in prefix table\n"
+ "IPv4 prefix\n"
+ "IPv6 prefix\n"
+ "AS Number\n")
+{
+
+ if (!is_synchronized()) {
+ vty_out(vty, "No Conection to RPKI cache server.\n");
+ return CMD_WARNING;
+ }
+
+ struct lrtr_ip_addr addr;
+ char addr_str[INET6_ADDRSTRLEN];
+ size_t addr_len = strchr(prefix_str, '/') - prefix_str;
+
+ memset(addr_str, 0, sizeof(addr_str));
+ memcpy(addr_str, prefix_str, addr_len);
+
+ if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) {
+ vty_out(vty, "Invalid IP prefix\n");
+ return CMD_WARNING;
+ }
+
+ struct pfx_record *matches = NULL;
+ unsigned int match_count = 0;
+ enum pfxv_state result;
+
+ if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count,
+ asn, &addr, prefix->prefixlen, &result)
+ != PFX_SUCCESS) {
+ vty_out(vty, "Prefix lookup failed");
+ return CMD_WARNING;
+ }
+
+ vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS");
+ for (size_t i = 0; i < match_count; ++i) {
+ const struct pfx_record *record = &matches[i];
+
+ if (record->max_len >= prefix->prefixlen
+ && ((asn != 0 && asn == record->asn) || asn == 0)) {
+ print_record(&matches[i], vty);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN (show_rpki_cache_server,
show_rpki_cache_server_cmd,
"show rpki cache-server",
install_default(RPKI_NODE);
overwrite_exit_commands();
install_element(CONFIG_NODE, &rpki_cmd);
- install_element(VIEW_NODE, &rpki_cmd);
+ install_element(ENABLE_NODE, &rpki_cmd);
install_element(ENABLE_NODE, &bgp_rpki_start_cmd);
install_element(ENABLE_NODE, &bgp_rpki_stop_cmd);
install_element(RPKI_NODE, &no_rpki_cache_cmd);
/* Install show commands */
- install_element(ENABLE_NODE, &show_rpki_prefix_table_cmd);
- install_element(ENABLE_NODE, &show_rpki_cache_connection_cmd);
- install_element(ENABLE_NODE, &show_rpki_cache_server_cmd);
+ install_element(VIEW_NODE, &show_rpki_prefix_table_cmd);
+ install_element(VIEW_NODE, &show_rpki_cache_connection_cmd);
+ install_element(VIEW_NODE, &show_rpki_cache_server_cmd);
+ install_element(VIEW_NODE, &show_rpki_prefix_cmd);
/* Install debug commands */
install_element(CONFIG_NODE, &debug_rpki_cmd);
oid_copy_addr(index, &addr, IN_ADDR_SIZE);
- smux_trap(bgp_variables, sizeof bgp_variables / sizeof(struct variable),
- bgp_trap_oid, sizeof bgp_trap_oid / sizeof(oid), bgp_oid,
+ smux_trap(bgp_variables, array_size(bgp_variables), bgp_trap_oid,
+ array_size(bgp_trap_oid), bgp_oid,
sizeof bgp_oid / sizeof(oid), index, IN_ADDR_SIZE,
- bgpTrapList, sizeof bgpTrapList / sizeof(struct trap_object),
- BGPESTABLISHED);
+ bgpTrapList, array_size(bgpTrapList), BGPESTABLISHED);
return 0;
}
oid_copy_addr(index, &addr, IN_ADDR_SIZE);
- smux_trap(bgp_variables, sizeof bgp_variables / sizeof(struct variable),
- bgp_trap_oid, sizeof bgp_trap_oid / sizeof(oid), bgp_oid,
+ smux_trap(bgp_variables, array_size(bgp_variables), bgp_trap_oid,
+ array_size(bgp_trap_oid), bgp_oid,
sizeof bgp_oid / sizeof(oid), index, IN_ADDR_SIZE,
- bgpTrapList, sizeof bgpTrapList / sizeof(struct trap_object),
- BGPBACKWARDTRANSITION);
+ bgpTrapList, array_size(bgpTrapList), BGPBACKWARDTRANSITION);
return 0;
}
static void sync_delete(struct update_subgroup *subgrp)
{
- if (subgrp->sync)
- XFREE(MTYPE_BGP_SYNCHRONISE, subgrp->sync);
+ XFREE(MTYPE_BGP_SYNCHRONISE, subgrp->sync);
subgrp->sync = NULL;
if (subgrp->hash)
hash_free(subgrp->hash);
dst->v_routeadv = src->v_routeadv;
dst->flags = src->flags;
dst->af_flags[afi][safi] = src->af_flags[afi][safi];
- if (dst->host)
- XFREE(MTYPE_BGP_PEER_HOST, dst->host);
+ XFREE(MTYPE_BGP_PEER_HOST, dst->host);
dst->host = XSTRDUP(MTYPE_BGP_PEER_HOST, src->host);
dst->cap = src->cap;
srcfilter = &src->filter[afi][safi];
- if (src->default_rmap[afi][safi].name)
- XFREE(MTYPE_ROUTE_MAP_NAME, src->default_rmap[afi][safi].name);
+ XFREE(MTYPE_ROUTE_MAP_NAME, src->default_rmap[afi][safi].name);
- if (srcfilter->dlist[FILTER_OUT].name)
- XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->dlist[FILTER_OUT].name);
+ XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->dlist[FILTER_OUT].name);
- if (srcfilter->plist[FILTER_OUT].name)
- XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->plist[FILTER_OUT].name);
+ XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->plist[FILTER_OUT].name);
- if (srcfilter->aslist[FILTER_OUT].name)
- XFREE(MTYPE_BGP_FILTER_NAME,
- srcfilter->aslist[FILTER_OUT].name);
+ XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->aslist[FILTER_OUT].name);
- if (srcfilter->map[RMAP_OUT].name)
- XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->map[RMAP_OUT].name);
+ XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->map[RMAP_OUT].name);
- if (srcfilter->usmap.name)
- XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->usmap.name);
+ XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->usmap.name);
- if (src->host)
- XFREE(MTYPE_BGP_PEER_HOST, src->host);
+ XFREE(MTYPE_BGP_PEER_HOST, src->host);
src->host = NULL;
}
return false;
if (pe1->addpath_type[afi][safi] != pe2->addpath_type[afi][safi])
- return 0;
+ return false;
if ((pe1->cap & PEER_UPDGRP_CAP_FLAGS)
!= (pe2->cap & PEER_UPDGRP_CAP_FLAGS))
hash_release(updgrp->bgp->update_groups[updgrp->afid], updgrp);
conf_release(updgrp->conf, updgrp->afi, updgrp->safi);
- if (updgrp->conf->host)
- XFREE(MTYPE_BGP_PEER_HOST, updgrp->conf->host);
+ XFREE(MTYPE_BGP_PEER_HOST, updgrp->conf->host);
updgrp->conf->host = NULL;
- if (updgrp->conf->ifname)
- XFREE(MTYPE_BGP_PEER_IFNAME, updgrp->conf->ifname);
+ XFREE(MTYPE_BGP_PEER_IFNAME, updgrp->conf->ifname);
XFREE(MTYPE_BGP_PEER, updgrp->conf);
XFREE(MTYPE_BGP_UPDGRP, updgrp);
{
struct bpacket *pkt;
- pkt = (struct bpacket *)XCALLOC(MTYPE_BGP_PACKET,
- sizeof(struct bpacket));
+ pkt = XCALLOC(MTYPE_BGP_PACKET, sizeof(struct bpacket));
return pkt;
}
/* 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);
}
return CMD_SUCCESS;
}
-static void bgp_redistribute_redo(struct bgp *bgp)
-{
- afi_t afi;
- int i;
- struct list *red_list;
- struct listnode *node;
- struct bgp_redist *red;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
-
- red_list = bgp->redist[afi][i];
- if (!red_list)
- continue;
-
- for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
- bgp_redistribute_resend(bgp, afi, i,
- red->instance);
- }
- }
- }
-}
-
/* "bgp graceful-shutdown" configuration */
DEFUN (bgp_graceful_shutdown,
bgp_graceful_shutdown_cmd,
as = strtoul(as_str, NULL, 10);
}
- /* If peer is peer group, call proper function. */
+ /* If peer is peer group or interface peer, call proper function. */
ret = str2sockunion(peer_str, &su);
if (ret < 0) {
- /* Check for peer by interface */
+ struct peer *peer;
+
+ /* Check if existing interface peer */
+ peer = peer_lookup_by_conf_if(bgp, peer_str);
+
ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, afi,
safi);
- if (ret < 0) {
+
+ /* if not interface peer, check peer-group settings */
+ if (ret < 0 && !peer) {
ret = peer_group_remote_as(bgp, peer_str, &as, as_type);
if (ret < 0) {
vty_out(vty,
- "%% Create the peer-group or interface first or specify \"interface\" keyword\n");
- vty_out(vty, "%% if using an unnumbered interface neighbor\n");
+ "%% Create the peer-group or interface first\n");
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
/* look up for neighbor by interface name config. */
peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg);
if (peer) {
- peer_as_change(peer, 0, AS_SPECIFIED);
+ peer_as_change(peer, 0, AS_UNSPECIFIED);
return CMD_SUCCESS;
}
json, "ribMemory",
ents * sizeof(struct bgp_node));
- ents = listcount(bgp->peer);
+ ents = bgp->af_peer_count[afi][safi];
json_object_int_add(json, "peerCount", ents);
json_object_int_add(json, "peerMemory",
ents * sizeof(struct peer));
bgp_node)));
/* Peer related usage */
- ents = listcount(bgp->peer);
+ ents = bgp->af_peer_count[afi][safi];
vty_out(vty, "Peers %ld, using %s of memory\n",
ents,
mtype_memstr(
}
/* Show BGP peer's information. */
-enum show_type { show_all, show_peer };
+enum show_type { show_all, show_peer, show_ipv4_all, show_ipv6_all, show_ipv4_peer, show_ipv6_peer };
static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
afi_t afi, safi_t safi,
struct peer *peer;
int find = 0;
bool nbr_output = false;
+ afi_t afi = AFI_MAX;
+ safi_t safi = SAFI_MAX;
+
+ if (type == show_ipv4_peer || type == show_ipv4_all) {
+ afi = AFI_IP;
+ } else if (type == show_ipv6_peer || type == show_ipv6_all) {
+ afi = AFI_IP6;
+ }
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
}
}
break;
+ case show_ipv4_peer:
+ case show_ipv6_peer:
+ FOREACH_SAFI (safi) {
+ if (peer->afc[afi][safi]) {
+ if (conf_if) {
+ if ((peer->conf_if
+ && !strcmp(peer->conf_if, conf_if))
+ || (peer->hostname
+ && !strcmp(peer->hostname, conf_if))) {
+ find = 1;
+ bgp_show_peer(vty, peer, use_json,
+ json);
+ break;
+ }
+ } else {
+ if (sockunion_same(&peer->su, su)) {
+ find = 1;
+ bgp_show_peer(vty, peer, use_json,
+ json);
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case show_ipv4_all:
+ case show_ipv6_all:
+ FOREACH_SAFI (safi) {
+ if (peer->afc[afi][safi]) {
+ bgp_show_peer(vty, peer, use_json, json);
+ nbr_output = true;
+ break;
+ }
+ }
+ break;
}
}
- if (type == show_peer && !find) {
+ if ((type == show_peer || type == show_ipv4_peer ||
+ type == show_ipv6_peer) && !find) {
if (use_json)
json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
else
vty_out(vty, "%% No such neighbor in this view/vrf\n");
}
- if (type != show_peer && !nbr_output && !use_json)
+ if (type != show_peer && type != show_ipv4_peer &&
+ type != show_ipv6_peer && !nbr_output && !use_json)
vty_out(vty, "%% No BGP neighbors found\n");
if (use_json) {
: bgp->name);
}
- if (type == show_peer) {
+ if (type == show_peer || type == show_ipv4_peer ||
+ type == show_ipv6_peer) {
ret = str2sockunion(ip_str, &su);
if (ret < 0)
bgp_show_neighbor(vty, bgp, type, NULL, ip_str,
bgp_show_neighbor(vty, bgp, type, &su, NULL,
use_json, json);
} else {
- bgp_show_neighbor(vty, bgp, show_all, NULL, NULL,
+ bgp_show_neighbor(vty, bgp, type, NULL, NULL,
use_json, json);
}
json_object_free(json);
char *vrf = NULL;
char *sh_arg = NULL;
enum show_type sh_type;
+ afi_t afi = AFI_MAX;
bool uj = use_json(argc, argv);
vrf = argv[idx + 1]->arg;
idx++;
+
+ if (argv_find(argv, argc, "ipv4", &idx)) {
+ sh_type = show_ipv4_all;
+ afi = AFI_IP;
+ } else if (argv_find(argv, argc, "ipv6", &idx)) {
+ sh_type = show_ipv6_all;
+ afi = AFI_IP6;
+ } else {
+ sh_type = show_all;
+ }
+
if (argv_find(argv, argc, "A.B.C.D", &idx)
|| argv_find(argv, argc, "X:X::X:X", &idx)
|| argv_find(argv, argc, "WORD", &idx)) {
sh_type = show_peer;
sh_arg = argv[idx]->arg;
- } else
- sh_type = show_all;
+ }
+
+ if (sh_type == show_peer && afi == AFI_IP) {
+ sh_type = show_ipv4_peer;
+ } else if (sh_type == show_peer && afi == AFI_IP6) {
+ sh_type = show_ipv6_peer;
+ }
return bgp_show_neighbor_vty(vty, vrf, sh_type, sh_arg, uj);
}
return CMD_SUCCESS;
}
-static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
- safi_t safi, bool use_json)
+static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
+ afi_t afi, safi_t safi,
+ bool use_json, json_object *json)
{
struct bgp *bgp;
struct listnode *node;
char *ecom_str;
vpn_policy_direction_t dir;
- if (use_json) {
- json_object *json = NULL;
+ if (json) {
json_object *json_import_vrfs = NULL;
json_object *json_export_vrfs = NULL;
- json = json_object_new_object();
-
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
if (!bgp) {
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
}
- vty_out(vty, "%s\n",
- json_object_to_json_string_ext(json,
+ if (use_json) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(json,
JSON_C_TO_STRING_PRETTY));
- json_object_free(json);
-
+ json_object_free(json);
+ }
} else {
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
return CMD_SUCCESS;
}
+static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi,
+ safi_t safi, bool use_json)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+ char *vrf_name = NULL;
+ json_object *json = NULL;
+ json_object *json_vrf = NULL;
+ json_object *json_vrfs = NULL;
+
+ if (use_json) {
+ json = json_object_new_object();
+ json_vrfs = json_object_new_object();
+ }
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT)
+ vrf_name = bgp->name;
+
+ if (use_json) {
+ json_vrf = json_object_new_object();
+ } else {
+ vty_out(vty, "\nInstance %s:\n",
+ (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+ ? VRF_DEFAULT_NAME : bgp->name);
+ }
+ bgp_show_route_leak_vty(vty, vrf_name, afi, safi, 0, json_vrf);
+ if (use_json) {
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+ json_object_object_add(json_vrfs,
+ VRF_DEFAULT_NAME, json_vrf);
+ else
+ json_object_object_add(json_vrfs, vrf_name,
+ json_vrf);
+ }
+ }
+
+ if (use_json) {
+ json_object_object_add(json, "vrfs", json_vrfs);
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(json,
+ JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
/* "show [ip] bgp route-leak" command. */
DEFUN (show_ip_bgp_route_leak,
show_ip_bgp_route_leak_cmd,
bool uj = use_json(argc, argv);
int idx = 0;
+ json_object *json = NULL;
/* show [ip] bgp */
if (argv_find(argv, argc, "ip", &idx)) {
return CMD_WARNING;
}
- return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj);
+ if (vrf && strmatch(vrf, "all"))
+ return bgp_show_all_instance_route_leak_vty(vty, afi, safi, uj);
+
+ if (uj)
+ json = json_object_new_object();
+
+ return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj, json);
}
static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi,
/* Free temporary community list string allocated by
argv_concat(). */
- if (str)
- XFREE(MTYPE_TMP, str);
+ XFREE(MTYPE_TMP, str);
if (ret < 0) {
community_list_perror(vty, ret);
/* Free temporary community list string allocated by
argv_concat(). */
- if (str)
- XFREE(MTYPE_TMP, str);
+ XFREE(MTYPE_TMP, str);
if (ret < 0) {
community_list_perror(vty, ret);
bgp->redist[afi][type] = list_new();
red_list = bgp->redist[afi][type];
- red = (struct bgp_redist *)XCALLOC(MTYPE_BGP_REDIST,
- sizeof(struct bgp_redist));
+ red = XCALLOC(MTYPE_BGP_REDIST, sizeof(struct bgp_redist));
red->instance = instance;
listnode_add(red_list, red);
return CMD_WARNING;
#if ENABLE_BGP_VNC
- if (bgp->vrf_id == VRF_DEFAULT
- && type == ZEBRA_ROUTE_VNC_DIRECT) {
+ if (EVPN_ENABLED(bgp) && type == ZEBRA_ROUTE_VNC_DIRECT) {
vnc_export_bgp_enable(
bgp, afi); /* only enables if mode bits cfg'd */
}
if (red->rmap.name && (strcmp(red->rmap.name, name) == 0))
return 0;
- if (red->rmap.name)
- XFREE(MTYPE_ROUTE_MAP_NAME, 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.
*/
* status. red lookup fails if there is no zebra connection.
*/
#if ENABLE_BGP_VNC
- if (bgp->vrf_id == VRF_DEFAULT && type == ZEBRA_ROUTE_VNC_DIRECT) {
+ if (EVPN_ENABLED(bgp) && type == ZEBRA_ROUTE_VNC_DIRECT) {
vnc_export_bgp_disable(bgp, afi);
}
#endif
bgp_redistribute_unreg(bgp, afi, type, instance);
/* Unset route-map. */
- if (red->rmap.name)
- XFREE(MTYPE_ROUTE_MAP_NAME, 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;
return CMD_SUCCESS;
}
-/* Update redistribute vrf bitmap during triggers like
- restart networking or delete/add VRFs */
-void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id)
+void bgp_redistribute_redo(struct bgp *bgp)
+{
+ afi_t afi;
+ int i;
+ struct list *red_list;
+ struct listnode *node;
+ struct bgp_redist *red;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+
+ red_list = bgp->redist[afi][i];
+ if (!red_list)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
+ bgp_redistribute_resend(bgp, afi, i,
+ red->instance);
+ }
+ }
+ }
+}
+
+/* Unset redistribute vrf bitmap during triggers like
+ restart networking or delete VRFs */
+void bgp_unset_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id)
{
int i;
afi_t afi;
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
- if ((old_vrf_id == VRF_UNKNOWN)
- || vrf_bitmap_check(zclient->redist[afi][i],
- old_vrf_id)) {
+ if (vrf_bitmap_check(zclient->redist[afi][i],
+ old_vrf_id))
vrf_bitmap_unset(zclient->redist[afi][i],
old_vrf_id);
- vrf_bitmap_set(zclient->redist[afi][i],
- bgp->vrf_id);
- }
return;
}
/* Register for router-id, interfaces, redistributed routes. */
zclient_send_reg_requests(zclient, bgp->vrf_id);
- /* For default instance, register to learn about VNIs, if appropriate.
- */
- if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT && is_evpn_enabled())
+ /* For EVPN instance, register to learn about VNIs, if appropriate. */
+ if (bgp->advertise_all_vni)
bgp_zebra_advertise_all_vni(bgp, 1);
bgp_nht_register_nexthops(bgp);
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Deregistering VRF %u", bgp->vrf_id);
- /* For default instance, unregister learning about VNIs, if appropriate.
- */
- if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT && is_evpn_enabled())
+ /* For EVPN instance, unregister learning about VNIs, if appropriate. */
+ if (bgp->advertise_all_vni)
bgp_zebra_advertise_all_vni(bgp, 0);
/* Deregister for router-id, interfaces, redistributed routes. */
extern void bgp_zebra_instance_register(struct bgp *);
extern void bgp_zebra_instance_deregister(struct bgp *);
+extern void bgp_redistribute_redo(struct bgp *bgp);
extern struct bgp_redist *bgp_redist_lookup(struct bgp *, afi_t, uint8_t,
unsigned short);
extern struct bgp_redist *bgp_redist_add(struct bgp *, afi_t, uint8_t,
{
static int bgp_server_main_created;
- if (create == true) {
+ if (create) {
if (bgp_server_main_created)
return 0;
if (bgp_socket(bgp, bm->port, bm->address) < 0)
if (is_evpn_enabled())
bgp_evpn_handle_router_id_update(bgp, TRUE);
+ vpn_handle_router_id_update(bgp, TRUE);
+
IPV4_ADDR_COPY(&bgp->router_id, id);
/* Set all peer's local identifier with this value. */
if (is_evpn_enabled())
bgp_evpn_handle_router_id_update(bgp, FALSE);
+ vpn_handle_router_id_update(bgp, FALSE);
+
return 0;
}
{
struct peer_af *af;
int afid;
+ struct bgp *bgp;
if (!peer)
return NULL;
if (afid >= BGP_AF_MAX)
return NULL;
+ bgp = peer->bgp;
assert(peer->peer_af_array[afid] == NULL);
/* Allocate new peer af */
af->safi = safi;
af->afid = afid;
af->peer = peer;
+ bgp->af_peer_count[afi][safi]++;
return af;
}
{
struct peer_af *af;
int afid;
+ struct bgp *bgp;
if (!peer)
return -1;
if (!af)
return -1;
+ bgp = peer->bgp;
bgp_stop_announce_route_timer(af);
if (PAF_SUBGRP(af)) {
af->subgroup->id, peer->host);
}
+
update_subgroup_remove_peer(af->subgroup, af);
+ if (bgp->af_peer_count[afi][safi])
+ bgp->af_peer_count[afi][safi]--;
+
peer->peer_af_array[afid] = NULL;
XFREE(MTYPE_BGP_PEER_AF, af);
return 0;
peer->update_if = NULL;
}
- if (peer->notify.data)
- XFREE(MTYPE_TMP, peer->notify.data);
+ XFREE(MTYPE_TMP, peer->notify.data);
memset(&peer->notify, 0, sizeof(struct bgp_notify));
if (peer->clear_node_queue)
peer_dst->update_source =
sockunion_dup(peer_src->update_source);
} else if (peer_src->update_if) {
- if (peer_dst->update_if)
- XFREE(MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
if (peer_dst->update_source) {
sockunion_free(peer_dst->update_source);
peer_dst->update_source = NULL;
}
if (peer_src->ifname) {
- if (peer_dst->ifname)
- XFREE(MTYPE_BGP_PEER_IFNAME, peer_dst->ifname);
+ XFREE(MTYPE_BGP_PEER_IFNAME, peer_dst->ifname);
peer_dst->ifname =
XSTRDUP(MTYPE_BGP_PEER_IFNAME, peer_src->ifname);
peer->su = *su;
else
bgp_peer_conf_if_to_su_update(peer);
- if (peer->host)
- XFREE(MTYPE_BGP_PEER_HOST, peer->host);
+ XFREE(MTYPE_BGP_PEER_HOST, peer->host);
peer->host = XSTRDUP(MTYPE_BGP_PEER_HOST, conf_if);
} else if (su) {
peer->su = *su;
sockunion2str(su, buf, SU_ADDRSTRLEN);
- if (peer->host)
- XFREE(MTYPE_BGP_PEER_HOST, peer->host);
+ XFREE(MTYPE_BGP_PEER_HOST, peer->host);
peer->host = XSTRDUP(MTYPE_BGP_PEER_HOST, buf);
}
peer->local_as = local_as;
/* Peer group cofiguration. */
static struct peer_group *peer_group_new(void)
{
- return (struct peer_group *)XCALLOC(MTYPE_PEER_GROUP,
- sizeof(struct peer_group));
+ return XCALLOC(MTYPE_PEER_GROUP, sizeof(struct peer_group));
}
static void peer_group_free(struct peer_group *group)
group = peer_group_new();
group->bgp = bgp;
- if (group->name)
- XFREE(MTYPE_PEER_GROUP_HOST, group->name);
+ XFREE(MTYPE_PEER_GROUP_HOST, group->name);
group->name = XSTRDUP(MTYPE_PEER_GROUP_HOST, name);
group->peer = list_new();
for (afi = AFI_IP; afi < AFI_MAX; afi++)
group->conf = peer_new(bgp);
if (!bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4))
group->conf->afc[AFI_IP][SAFI_UNICAST] = 1;
- if (group->conf->host)
- XFREE(MTYPE_BGP_PEER_HOST, group->conf->host);
+ XFREE(MTYPE_BGP_PEER_HOST, group->conf->host);
group->conf->host = XSTRDUP(MTYPE_BGP_PEER_HOST, name);
group->conf->group = group;
group->conf->as = 0;
peer->sort = group->conf->sort;
}
- if (!group->conf->as) {
+ if (!group->conf->as && peer_sort(peer)) {
if (peer_sort(group->conf) != BGP_PEER_INTERNAL
&& peer_sort(group->conf) != peer_sort(peer)) {
if (as)
name, *as);
}
+ /* Default the EVPN VRF to the default one */
+ if (inst_type == BGP_INSTANCE_TYPE_DEFAULT && !bgp_master.bgp_evpn) {
+ bgp_lock(bgp);
+ bm->bgp_evpn = bgp;
+ }
+
bgp_lock(bgp);
bgp->heuristic_coalesce = true;
bgp->inst_type = inst_type;
bgp->vrf_id = (inst_type == BGP_INSTANCE_TYPE_DEFAULT) ? VRF_DEFAULT
: VRF_UNKNOWN;
bgp->peer_self = peer_new(bgp);
- if (bgp->peer_self->host)
- XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->host);
+ XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->host);
bgp->peer_self->host =
XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement");
if (bgp->peer_self->hostname != NULL) {
return (vrf->info) ? (struct bgp *)vrf->info : NULL;
}
+/* Sets the BGP instance where EVPN is enabled */
+void bgp_set_evpn(struct bgp *bgp)
+{
+ if (bm->bgp_evpn == bgp)
+ return;
+
+ /* First, release the reference count we hold on the instance */
+ if (bm->bgp_evpn)
+ bgp_unlock(bm->bgp_evpn);
+
+ bm->bgp_evpn = bgp;
+
+ /* Increase the reference count on this new VRF */
+ if (bm->bgp_evpn)
+ bgp_lock(bm->bgp_evpn);
+}
+
+/* Returns the BGP instance where EVPN is enabled, if any */
+struct bgp *bgp_get_evpn(void)
+{
+ return bm->bgp_evpn;
+}
+
/* handle socket creation or deletion, if necessary
* this is called for all new BGP instances
*/
if (vrf)
bgp_vrf_unlink(bgp, vrf);
+ /* Update EVPN VRF pointer */
+ if (bm->bgp_evpn == bgp) {
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+ bgp_set_evpn(NULL);
+ else
+ bgp_set_evpn(bgp_get_default());
+ }
+
thread_master_free_unused(bm->master);
bgp_unlock(bgp); /* initial reference */
if (bgp->rib[afi][safi])
bgp_table_finish(&bgp->rib[afi][safi]);
rmap = &bgp->table_map[afi][safi];
- if (rmap->name)
- XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
}
bgp_scan_finish(bgp);
ecommunity_free(&bgp->vpn_policy[afi].rtlist[dir]);
}
- if (bgp->name)
- XFREE(MTYPE_BGP, bgp->name);
- if (bgp->name_pretty)
- XFREE(MTYPE_BGP, bgp->name_pretty);
+ XFREE(MTYPE_BGP, bgp->name);
+ XFREE(MTYPE_BGP, bgp->name_pretty);
XFREE(MTYPE_BGP, bgp);
}
/* Neighbor description. */
int peer_description_set(struct peer *peer, const char *desc)
{
- if (peer->desc)
- XFREE(MTYPE_PEER_DESC, peer->desc);
+ XFREE(MTYPE_PEER_DESC, peer->desc);
peer->desc = XSTRDUP(MTYPE_PEER_DESC, desc);
int peer_description_unset(struct peer *peer)
{
- if (peer->desc)
- XFREE(MTYPE_PEER_DESC, peer->desc);
+ XFREE(MTYPE_PEER_DESC, peer->desc);
peer->desc = NULL;
/* neighbor interface */
void peer_interface_set(struct peer *peer, const char *str)
{
- if (peer->ifname)
- XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
+ XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
peer->ifname = XSTRDUP(MTYPE_BGP_PEER_IFNAME, str);
}
void peer_interface_unset(struct peer *peer)
{
- if (peer->ifname)
- XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
+ XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
peer->ifname = NULL;
}
for (afi = AFI_IP; afi < AFI_MAX; afi++) \
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+#define FOREACH_SAFI(safi) \
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+
extern struct frr_pthread *bgp_pth_io;
extern struct frr_pthread *bgp_pth_ka;
/* dynamic mpls label allocation pool */
struct labelpool labelpool;
+ /* BGP-EVPN VRF ID. Defaults to default VRF (if any) */
+ struct bgp* bgp_evpn;
+
bool terminating; /* global flag that sigint terminate seen */
QOBJ_FIELDS
};
#define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 7)
#define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 8)
+ /* BGP per AF peer count */
+ uint32_t af_peer_count[AFI_MAX][SAFI_MAX];
+
/* Route table for next-hop lookup cache. */
struct bgp_table *nexthop_cache_table[AFI_MAX];
extern struct bgp *bgp_lookup(as_t, const char *);
extern struct bgp *bgp_lookup_by_name(const char *);
extern struct bgp *bgp_lookup_by_vrf_id(vrf_id_t);
+extern struct bgp *bgp_get_evpn(void);
+extern void bgp_set_evpn(struct bgp *bgp);
extern struct peer *peer_lookup(struct bgp *, union sockunion *);
extern struct peer *peer_lookup_by_conf_if(struct bgp *, const char *);
extern struct peer *peer_lookup_by_hostname(struct bgp *, const char *);
bgp->vrf_id = VRF_UNKNOWN;
}
-extern void bgp_update_redist_vrf_bitmaps(struct bgp *, vrf_id_t);
+extern void bgp_unset_redist_vrf_bitmaps(struct bgp *, vrf_id_t);
/* For benefit of rfapi */
extern struct peer *peer_new(struct bgp *bgp);
ecommunity_free(&rfg->rt_export_list);
if (rfg->labels)
list_delete(&rfg->labels);
- if (rfg->rfp_cfg)
- XFREE(MTYPE_RFAPI_RFP_GROUP_CFG, rfg->rfp_cfg);
+ XFREE(MTYPE_RFAPI_RFP_GROUP_CFG, rfg->rfp_cfg);
listnode_delete(bgp->rfapi_cfg->l2_groups, rfg);
rfapi_l2_group_del(rfg);
struct rfapi_cfg *h;
afi_t afi;
- h = (struct rfapi_cfg *)XCALLOC(MTYPE_RFAPI_CFG,
- sizeof(struct rfapi_cfg));
+ h = XCALLOC(MTYPE_RFAPI_CFG, sizeof(struct rfapi_cfg));
assert(h);
h->nve_groups_sequential = list_new();
ecommunity_free(&h->default_rt_export_list);
if (h->default_rt_import_list)
ecommunity_free(&h->default_rt_import_list);
- if (h->default_rfp_cfg)
- XFREE(MTYPE_RFAPI_RFP_GROUP_CFG, h->default_rfp_cfg);
+ XFREE(MTYPE_RFAPI_RFP_GROUP_CFG, h->default_rfp_cfg);
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
agg_table_finish(h->nve_groups_vn[afi]);
agg_table_finish(h->nve_groups_un[afi]);
assert(bgp->rfapi_cfg == NULL);
- h = (struct rfapi *)XCALLOC(MTYPE_RFAPI, sizeof(struct rfapi));
+ h = XCALLOC(MTYPE_RFAPI, sizeof(struct rfapi));
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
h->un[afi] = agg_table_init();
return CMD_WARNING_CONFIG_FAILED;
}
-#if CONFDATE > 20190402
-CPP_NOTICE("bgpd: time to remove undebug commands")
-#endif
-ALIAS_HIDDEN(no_debug_bgp_vnc,
- undebug_bgp_vnc_cmd,
- "undebug bgp vnc <rfapi-query|import-bi-attach|import-del-remote|verbose>",
- "Undebug\n"
- BGP_STR
- VNC_STR
- "rfapi query handling\n"
- "import BI atachment\n"
- "import delete remote routes\n"
- "verbose logging\n")
-
-
/***********************************************************************
* no debug bgp vnc all
***********************************************************************/
return CMD_SUCCESS;
}
-#if CONFDATE > 20190402
-CPP_NOTICE("bgpd: time to remove undebug commands")
-#endif
-ALIAS_HIDDEN (no_debug_bgp_vnc_all,
- undebug_bgp_vnc_all_cmd,
- "undebug all bgp vnc",
- "Undebug\n"
- "Disable all VNC debugging\n"
- BGP_STR
- VNC_STR)
-
/***********************************************************************
* show/save
***********************************************************************/
int write = 0;
size_t i;
- for (i = 0; i < (sizeof(vncdebug) / sizeof(struct vnc_debug)); ++i) {
+ for (i = 0; i < array_size(vncdebug); ++i) {
if (conf_vnc_debug & vncdebug[i].bit) {
vty_out(vty, "debug bgp vnc %s\n", vncdebug[i].name);
write++;
install_element(CONFIG_NODE, &debug_bgp_vnc_cmd);
install_element(ENABLE_NODE, &no_debug_bgp_vnc_cmd);
install_element(CONFIG_NODE, &no_debug_bgp_vnc_cmd);
- install_element(ENABLE_NODE, &undebug_bgp_vnc_cmd);
- install_element(CONFIG_NODE, &undebug_bgp_vnc_cmd);
install_element(ENABLE_NODE, &no_debug_bgp_vnc_all_cmd);
install_element(CONFIG_NODE, &no_debug_bgp_vnc_all_cmd);
- install_element(ENABLE_NODE, &undebug_bgp_vnc_all_cmd);
- install_element(CONFIG_NODE, &undebug_bgp_vnc_all_cmd);
}
add);
}
- if (nhp_ary)
- XFREE(MTYPE_TMP, nhp_ary);
- if (nh_ary)
- XFREE(MTYPE_TMP, nh_ary);
+ XFREE(MTYPE_TMP, nhp_ary);
+ XFREE(MTYPE_TMP, nh_ary);
}
void vnc_zebra_add_prefix(struct bgp *bgp,
}
}
}
- if (nhp_ary)
- XFREE(MTYPE_TMP, nhp_ary);
- if (nh_ary)
- XFREE(MTYPE_TMP, nh_ary);
+ XFREE(MTYPE_TMP, nhp_ary);
+ XFREE(MTYPE_TMP, nh_ary);
}
}
enable_logfile_mask=${enable_logfile_mask:-0600}
AC_DEFINE_UNQUOTED([LOGFILE_MASK], [${enable_logfile_mask}], [Mask for log files])
-MPATH_NUM=1
+MPATH_NUM=16
case "${enable_multipath}" in
0)
+.. _building-centos6:
+
CentOS 6
========================================
-(As an alternative to this installation, you may prefer to create a FRR
-rpm package yourself and install that package instead. See instructions
-in redhat/README.rpm\_build.md on how to build a rpm package)
+This document describes installation from source. If you want to build an RPM,
+see :ref:`packaging-redhat`.
Instructions are tested with ``CentOS 6.8`` on ``x86_64`` platform
PIMd is needed
- MPLS is not supported on ``CentOS 6``. MPLS requires Linux Kernel 4.5
or higher (LDP can be built, but may have limited use without MPLS)
-- Zebra is unable to detect what bridge/vrf an interface is associcated
+- Zebra is unable to detect what bridge/vrf an interface is associated
with (IFLA\_INFO\_SLAVE\_KIND does not exist in the kernel headers,
you can use a newer kernel + headers to get this functionality)
- frr\_reload.py will not work, as this requires Python 2.7, and CentOS
.. code-block:: shell
- sudo yum install git autoconf automake libtool make gawk \
+ sudo yum install git autoconf automake libtool make \
readline-devel texinfo net-snmp-devel groff pkgconfig \
json-c-devel pam-devel flex epel-release c-ares-devel
# Controls source route verification
net.ipv4.conf.default.rp_filter = 0
-Load the modifed sysctl's on the system:
+Load the modified sysctl's on the system:
.. code-block:: shell
CentOS 7
========================================
-(As an alternative to this installation, you may prefer to create a FRR
-rpm package yourself and install that package instead. See instructions
-in redhat/README.rpm\_build.md on how to build a rpm package)
+This document describes installation from source. If you want to build an RPM,
+see :ref:`packaging-redhat`.
CentOS 7 restrictions:
----------------------
::
- sudo yum install git autoconf automake libtool make gawk \
+ sudo yum install git autoconf automake libtool make \
readline-devel texinfo net-snmp-devel groff pkgconfig \
json-c-devel pam-devel bison flex pytest c-ares-devel \
python-devel systemd-devel python-sphinx
net.ipv4.conf.all.forwarding=1
net.ipv6.conf.all.forwarding=1
-Load the modifed sysctl's on the system:
+Load the modified sysctl's on the system:
::
::
- sudo apt-get install git autoconf automake libtool make gawk \
+ 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 python3-sphinx build-essential libsystemd-dev
--- /dev/null
+Fedora 24+
+==========
+
+This document describes installation from source. If you want to build an RPM,
+see :ref:`packaging-redhat`.
+
+These instructions have been tested on Fedora 24+.
+
+Installing Dependencies
+-----------------------
+
+.. code-block:: console
+
+ sudo dnf install git autoconf automake libtool make \
+ readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \
+ pam-devel pytest bison flex c-ares-devel python3-devel python2-sphinx \
+ perl-core patch
+
+.. include:: building-libyang.rst
+
+Building & Installing FRR
+-------------------------
+
+Add FRR user and groups
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+ sudo groupadd -g 92 frr
+ sudo groupadd -r -g 85 frrvty
+ sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \
+ -c "FRR FRRouting suite" -d /var/run/frr frr
+
+Compile
+^^^^^^^
+
+.. include:: include-compile.rst
+
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+ sudo install -m 775 -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 frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
+
+Tweak sysctls
+^^^^^^^^^^^^^
+
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
+
+Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the following
+content:
+
+::
+
+ #
+ # Enable packet forwarding
+ #
+ net.ipv4.conf.all.forwarding=1
+ net.ipv6.conf.all.forwarding=1
+ #
+ # Enable MPLS Label processing on all interfaces
+ #
+ #net.mpls.conf.eth0.input=1
+ #net.mpls.conf.eth1.input=1
+ #net.mpls.conf.eth2.input=1
+ #net.mpls.platform_labels=100000
+
+.. note::
+
+ MPLS must be invidividually enabled on each interface that requires it. See
+ the example in the config block above.
+
+Load the modifed sysctls on the system:
+
+.. code-block:: console
+
+ sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
+
+Create a new file ``/etc/modules-load.d/mpls.conf`` with the following content:
+
+::
+
+ # Load MPLS Kernel Modules
+ mpls-router
+ mpls-iptunnel
+
+And load the kernel modules on the running system:
+
+.. code-block:: console
+
+ sudo modprobe mpls-router mpls-iptunnel
+
+Install service files
+^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+ sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
+ sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
+ sudo systemctl enable frr
+
+Enable daemons
+^^^^^^^^^^^^^^
+
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
+as required by changing the value to ``yes``.
+
+Start FRR
+^^^^^^^^^
+
+.. code-block:: frr
+
+ sudo systemctl start frr
+++ /dev/null
-Fedora 24
-=========================================
-
-(As an alternative to this installation, you may prefer to create a FRR
-rpm package yourself and install that package instead. See instructions
-in redhat/README.rpm\_build.md on how to build a rpm package)
-
-Install required packages
--------------------------
-
-Add packages:
-
-::
-
- sudo dnf install git autoconf automake libtool make gawk \
- readline-devel texinfo net-snmp-devel groff pkgconfig \
- json-c-devel pam-devel pytest bison flex c-ares-devel \
- python3-devel python3-sphinx
-
-.. 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 -g 92 frr
- sudo groupadd -r -g 85 frrvty
- sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \
- -c "FRR FRRouting suite" -d /var/run/frr 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 \
- --bindir=/usr/bin \
- --sbindir=/usr/lib/frr \
- --sysconfdir=/etc/frr \
- --libdir=/usr/lib/frr \
- --libexecdir=/usr/lib/frr \
- --localstatedir=/var/run/frr \
- --with-moduledir=/usr/lib/frr/modules \
- --enable-snmp=agentx \
- --enable-multipath=64 \
- --enable-user=frr \
- --enable-group=frr \
- --enable-vty-group=frrvty \
- --disable-exampledir \
- --enable-fpm \
- --with-pkg-git-version \
- --with-pkg-extra-version=-MyOwnFRRVersion
- make
- make check
- sudo make install
-
-Create empty FRR configuration files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
- sudo mkdir /var/log/frr
- sudo mkdir /etc/frr
- sudo touch /etc/frr/zebra.conf
- sudo touch /etc/frr/bgpd.conf
- sudo touch /etc/frr/ospfd.conf
- sudo touch /etc/frr/ospf6d.conf
- sudo touch /etc/frr/isisd.conf
- sudo touch /etc/frr/ripd.conf
- sudo touch /etc/frr/ripngd.conf
- sudo touch /etc/frr/pimd.conf
- sudo touch /etc/frr/ldpd.conf
- sudo touch /etc/frr/nhrpd.conf
- sudo touch /etc/frr/eigrpd.conf
- sudo touch /etc/frr/babeld.conf
- sudo chown -R frr:frr /etc/frr/
- sudo touch /etc/frr/vtysh.conf
- sudo chown frr:frrvty /etc/frr/vtysh.conf
- sudo chmod 640 /etc/frr/*.conf
-
-Install daemon config file
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
- sudo install -p -m 644 redhat/daemons /etc/frr/
- sudo chown frr:frr /etc/frr/daemons
-
-Edit /etc/frr/daemons as needed to select the required daemons
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
-Enable the daemons as required by changing the value to ``yes``
-
-Enable IP & IPv6 forwarding (and MPLS)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the
-following content: (Please make sure to list all interfaces with
-required MPLS similar to ``net.mpls.conf.eth0.input=1``)
-
-::
-
- # Sysctl for routing
- #
- # Routing: We need to forward packets
- net.ipv4.conf.all.forwarding=1
- net.ipv6.conf.all.forwarding=1
- #
- # Enable MPLS Label processing on all interfaces
- net.mpls.conf.eth0.input=1
- net.mpls.conf.eth1.input=1
- net.mpls.conf.eth2.input=1
- net.mpls.platform_labels=100000
-
-Load the modifed sysctl's on the system:
-
-::
-
- sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
-
-Create a new file ``/etc/modules-load.d/mpls.conf`` with the following
-content:
-
-::
-
- # Load MPLS Kernel Modules
- mpls-router
- mpls-iptunnel
-
-And load the kernel modules on the running system:
-
-::
-
- sudo modprobe mpls-router mpls-iptunnel
-
-Install frr Service and redhat init files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
- sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
- sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
-
-Enable required frr at startup
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
- sudo systemctl enable frr
-
-Reboot or start FRR manually
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
- sudo systemctl start frr
Install required packages
-------------------------
-Add packages: (Allow the install of the package managment tool if this
+Add packages: (Allow the install of the package management tool if this
is first package install and asked)
::
- pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
+ pkg install git autoconf automake libtool gmake json-c pkgconf \
bison flex py27-pytest c-ares python3 py-sphinx
Make sure there is no /usr/bin/flex preinstalled (and use the newly
Install required packages
-------------------------
-Add packages: (Allow the install of the package managment tool if this
+Add packages: (Allow the install of the package management tool if this
is first package install and asked)
.. code-block:: shell
- pkg install git autoconf automake libtool gmake gawk json-c pkgconf \
+ pkg install git autoconf automake libtool gmake json-c pkgconf \
bison flex py27-pytest c-ares python3 py36-sphinx texinfo
Make sure there is no /usr/bin/flex preinstalled (and use the newly
Install required packages
-------------------------
-Add packages: (Allow the install of the package managment tool if this
+Add packages: (Allow the install of the package management tool if this
is first package install and asked)
::
- pkg install -y git autoconf automake libtool gmake gawk \
+ pkg install -y git autoconf automake libtool gmake \
pkgconf texinfo json-c bison flex py27-pytest c-ares \
- python3 py-sphinx
+ python3 py-sphinx libexecinfo
Make sure there is no /usr/bin/flex preinstalled (and use the newly
installed in /usr/local/bin): (FreeBSD frequently provides a older flex
::
- sudo pkg_add git autoconf automake libtool gmake gawk openssl \
+ sudo pkg_add git autoconf automake libtool gmake openssl \
pkg-config json-c python27 py27-test python35 py-sphinx
Install SSL Root Certificates (for git https access):
::
- sudo pkgin install git autoconf automake libtool gmake gawk openssl \
+ sudo pkgin install git autoconf automake libtool gmake openssl \
pkg-config json-c python27 py27-test python35 py-sphinx
Install SSL Root Certificates (for git https access):
library/idnkit/header-idnkit \
system/header \
system/library/math/header-math \
- git libtool gawk pkg-config
+ git libtool pkg-config
Add additional Solaris packages:
::
pkg_add git autoconf-2.69p2 automake-1.15.1 libtool bison
- pkg_add gmake gawk dejagnu openssl json-c py-test py-sphinx
+ pkg_add gmake json-c py-test py-sphinx libexecinfo
Select Python2.7 as default (required for pytest)
::
sudo apt-get install git build-essential libssl-dev libncurses5-dev \
- unzip gawk zlib1g-dev subversion mercurial
+ unzip zlib1g-dev subversion mercurial
For other environments, instructions can be found in the
`official documentation
-----
Edit ``/usr/sbin/frr.init`` and add/remove the daemons name in section
-``DAEMONS=`` or don't install unneded packages For example: zebra bgpd ldpd
+``DAEMONS=`` or don't install unneeded packages For example: zebra bgpd ldpd
isisd nhrpd ospfd ospf6d pimd ripd ripngd
-Enable the serivce
+Enable the service
^^^^^^^^^^^^^^^^^^
- ``service frr enable``
-Ubuntu 14.04LTS
-===============================================
+Ubuntu 14.04 LTS
+================
-- MPLS is not supported on ``Ubuntu 14.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
--------------------------
+This document describes installation from source. If you want to build a
+``deb``, see :ref:`packaging-debian`.
-Add packages:
+Installing Dependencies
+-----------------------
-::
+.. code-block:: console
+ apt-get update
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
+ git autoconf automake libtool make libreadline-dev texinfo \
+ pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
+ libc-ares-dev python3-dev python3-sphinx install-info build-essential \
+ libsnmp-dev perl
.. 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**
+Building & Installing FRR
+-------------------------
-Add frr groups and user
+Add FRR user and groups
^^^^^^^^^^^^^^^^^^^^^^^
-::
+.. code-block:: console
sudo groupadd -r -g 92 frr
sudo groupadd -r -g 85 frrvty
--gecos "FRR suite" --shell /sbin/nologin frr
sudo usermod -a -G frrvty frr
-Download Source, configure and compile it
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Compile
+^^^^^^^
-(You may prefer different options on configure statement. These are just
-an example.)
+.. include:: include-compile.rst
-::
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- 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
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. code-block:: console
+
+ sudo install -m 775 -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 frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
+
+Tweak sysctls
+^^^^^^^^^^^^^
+
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
+
+Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
+other settings):
::
- 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.
+
+Add MPLS kernel modules
+"""""""""""""""""""""""
+
+.. warning::
+
+ MPLS is not supported on Ubuntu 14.04 with the default kernel. MPLS requires
+ kernel 4.5 or higher. LDPD can be built, but may have limited use without
+ MPLS. For an updated Ubuntu Kernel, see
+ http://kernel.ubuntu.com/~kernel-ppa/mainline/
+
+Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
+enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
::
- # Uncomment the next line to enable packet forwarding for IPv4
- net.ipv4.ip_forward=1
+ # Load MPLS Kernel Modules
+ mpls_router
+ mpls_iptunnel
+
+
+And load the kernel modules on the running system:
+
+.. code-block:: console
+
+ sudo modprobe mpls-router mpls-iptunnel
+
+Enable MPLS Forwarding
+""""""""""""""""""""""
- # 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
+Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
+equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
-**Reboot** or use ``sysctl -p`` to apply the same config to the running
-system
+::
+
+ # Enable MPLS Label processing on all interfaces
+ net.mpls.conf.eth0.input=1
+ net.mpls.conf.eth1.input=1
+ net.mpls.conf.eth2.input=1
+ net.mpls.platform_labels=100000
Install the init.d service
^^^^^^^^^^^^^^^^^^^^^^^^^^
-::
+.. code-block:: console
- 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
+ sudo install -m 755 tools/frr /etc/init.d/frr
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
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
+as required by changing the value to ``yes``.
Start the init.d service
^^^^^^^^^^^^^^^^^^^^^^^^
-- /etc/init.d/frr start
-- use ``/etc/init.d/frr status`` to check its status.
+.. code-block:: console
+
+ /etc/init.d/frr start
+
+Use ``/etc/init.d/frr status`` to check its status.
-Ubuntu 16.04LTS
-===============================================
+Ubuntu 16.04 LTS
+================
-- MPLS is not supported on ``Ubuntu 16.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
--------------------------
+This document describes installation from source. If you want to build a
+``deb``, see :ref:`packaging-debian`.
-Add packages:
+Installing Dependencies
+-----------------------
-::
+.. code-block:: console
+ apt-get update
apt-get install \
- git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \
+ git autoconf automake libtool make 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 build-essential libsystemd-dev
+ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
+ install-info build-essential libsystemd-dev libsnmp-dev perl
.. 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**
+Building & Installing FRR
+-------------------------
-Add frr groups and user
+Add FRR user and groups
^^^^^^^^^^^^^^^^^^^^^^^
-::
+.. code-block:: console
- 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
+ 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
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Compile
+^^^^^^^
-(You may prefer different options on configure statement. These are just
-an example.)
+.. include:: include-compile.rst
-::
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- 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 \
- --enable-systemd=yes \
- --with-pkg-git-version \
- --with-pkg-extra-version=-MyOwnFRRVersion
- make
- make check
- sudo make install
-
-Create empty FRR configuration files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. code-block:: console
-::
+ sudo install -m 775 -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 frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
- 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 IPv4 & IPv6 forwarding
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
-other settings)
+Tweak sysctls
+^^^^^^^^^^^^^
+
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
+
+Edit :file:`/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 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
- # 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.
-Enable MPLS Forwarding (with Linux Kernel >= 4.5)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Add MPLS kernel modules
+"""""""""""""""""""""""
+
+.. warning::
+
+ MPLS is not supported on Ubuntu 16.04 with the default kernel. MPLS requires
+ kernel 4.5 or higher. LDPD can be built, but may have limited use without
+ MPLS. For an updated Ubuntu Kernel, see
+ http://kernel.ubuntu.com/~kernel-ppa/mainline/
-Edit ``/etc/sysctl.conf`` and the following lines. Make sure to add a
-line equal to ``net.mpls.conf.eth0.input`` or each interface used with
-MPLS
+Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
+enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
::
- # Enable MPLS Label processing on all interfaces
- net.mpls.conf.eth0.input=1
- net.mpls.conf.eth1.input=1
- net.mpls.conf.eth2.input=1
- net.mpls.platform_labels=100000
+ # Load MPLS Kernel Modules
+ mpls_router
+ mpls_iptunnel
-Add MPLS kernel modules
-^^^^^^^^^^^^^^^^^^^^^^^
-Add the following lines to ``/etc/modules-load.d/modules.conf``:
+And load the kernel modules on the running system:
-::
+.. code-block:: console
- # Load MPLS Kernel Modules
- mpls-router
- mpls-iptunnel
+ sudo modprobe mpls-router mpls-iptunnel
-**Reboot** or use ``sysctl -p`` to apply the same config to the running
-system
+Enable MPLS Forwarding
+""""""""""""""""""""""
-Install the systemd service (if rebooted from last step, change directory back to frr directory)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
+equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
::
- sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
- sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
- sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
- sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ # Enable MPLS Label processing on all interfaces
+ net.mpls.conf.eth0.input=1
+ net.mpls.conf.eth1.input=1
+ net.mpls.conf.eth2.input=1
+ net.mpls.platform_labels=100000
-Enable daemons
-^^^^^^^^^^^^^^
+Install service files
+^^^^^^^^^^^^^^^^^^^^^
-| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
- those daemons you want to start by systemd.
-| For example.
+.. code-block:: console
-::
+ sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
+ sudo systemctl enable frr
- zebra=yes
- bgpd=yes
- ospfd=yes
- ospf6d=yes
- ripd=yes
- ripngd=yes
- isisd=yes
+Enable daemons
+^^^^^^^^^^^^^^
-Enable the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^^
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
+as required by changing the value to ``yes``.
-- systemctl enable frr
+Start FRR
+^^^^^^^^^
-Start the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^
+.. code-block:: console
-- systemctl start frr
-- use ``systemctl status frr`` to check its status.
+ systemctl start frr
Ubuntu 18.04 LTS
================
-Install dependencies
---------------------
+This document describes installation from source. If you want to build a
+``deb``, see :ref:`packaging-debian`.
-Required packages
-^^^^^^^^^^^^^^^^^
+Installing Dependencies
+-----------------------
-::
+.. code-block:: console
+ sudo apt update
sudo apt-get install \
- git autoconf automake libtool make gawk libreadline-dev texinfo \
+ git autoconf automake libtool make 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 build-essential libsystemd-dev
+ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
+ install-info build-essential libsystemd-dev libsnmp-dev perl
.. include:: building-libyang.rst
-Optional packages
-^^^^^^^^^^^^^^^^^
-
-Dependencies for additional functionality can be installed as-desired.
-
Protobuf
-~~~~~~~~
+^^^^^^^^
-::
+.. code-block:: console
- sudo apt-get install \
- protobuf-c-compiler \
- libprotobuf-c-dev
+ sudo apt-get install protobuf-c-compiler libprotobuf-c-dev
ZeroMQ
-~~~~~~
-
-::
+^^^^^^
- sudo apt-get install \
- libzmq5 \
- libzmq3-dev
+.. code-block:: console
-Get FRR, compile it and install it (from Git)
----------------------------------------------
+ sudo apt-get install libzmq5 libzmq3-dev
-**This assumes you want to build and install FRR from source and not
-using any packages**
+Building & Installing FRR
+-------------------------
-Add frr groups and user
+Add FRR user and groups
^^^^^^^^^^^^^^^^^^^^^^^
-::
+.. code-block:: console
sudo groupadd -r -g 92 frr
sudo groupadd -r -g 85 frrvty
--gecos "FRR suite" --shell /sbin/nologin frr
sudo usermod -a -G frrvty frr
-Download source
-^^^^^^^^^^^^^^^
-
-::
-
- git clone https://github.com/frrouting/frr.git frr
-
-Configure
-^^^^^^^^^
-Options below are provided as an example.
-
-.. seealso:: *Installation* section of user guide
-
-.. code-block:: shell
-
- 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 \
- --enable-systemd=yes \
- --with-pkg-git-version \
- --with-pkg-extra-version=-MyOwnFRRVersion
-
-If optional packages were installed, the associated feature may now be
-enabled.
-
-.. option:: --enable-protobuf
-
-Enable support for protobuf transport
-
-.. option:: --enable-zeromq
-
-Enable support for ZeroMQ transport
-
Compile
^^^^^^^
-::
-
- make
- make check
- sudo make install
-
-Create empty FRR configuration files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. include:: include-compile.rst
-Although not strictly necessary, it's good practice to create empty
-configuration files _before_ starting FRR. This assures that the permissions
-are correct. If the files are not already present, FRR will create them.
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-It's also important to consider _which_ files to create. FRR supports writing
-configuration to a monolithic file, :file:`/etc/frr/frr.conf`.
+.. code-block:: console
-.. seealso:: *VTYSH* section of user guide
-
-The presence of :file:`/etc/frr/frr.conf` on startup implicitly configures FRR
-to ignore daemon-specific configuration files.
-
-Daemon-specific configuration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-::
-
- sudo install -m 755 -o frr -g frr -d /var/log/frr
+ sudo install -m 775 -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
-
-Monolithic configuration
-~~~~~~~~~~~~~~~~~~~~~~~~
+ sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+ sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
-::
+Tweak sysctls
+^^^^^^^^^^^^^
- 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/frr.conf
-
-Enable IPv4 & IPv6 forwarding
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
other settings):
# 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.
+
Add MPLS kernel modules
-^^^^^^^^^^^^^^^^^^^^^^^
+"""""""""""""""""""""""
Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
mpls_router
mpls_iptunnel
-Reboot or use ``sysctl -p`` to apply the same config to the running system.
+
+And load the kernel modules on the running system:
+
+.. code-block:: console
+
+ sudo modprobe mpls-router mpls-iptunnel
Enable MPLS Forwarding
-^^^^^^^^^^^^^^^^^^^^^^
+""""""""""""""""""""""
Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
net.mpls.conf.eth2.input=1
net.mpls.platform_labels=100000
-Install the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Install service files
+^^^^^^^^^^^^^^^^^^^^^
-::
+.. code-block:: console
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
- sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
- sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
- sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+ sudo systemctl enable frr
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
-
-Enable the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^^
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
+as required by changing the value to ``yes``.
-Enabling the systemd service causes FRR to be started upon boot. To enable it,
-use the following command:
-
-.. code-block:: shell
-
- systemctl enable frr
-
-Start the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^
+Start FRR
+^^^^^^^^^
.. code-block:: shell
systemctl start frr
-
-After starting the service, you can use ``systemctl status frr`` to check its
-status.
-The libyang library can be installed from third-party packages available `here
-<https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
+FRR depends on the relatively new ``libyang`` library to provide YANG/NETCONF
+support. Unfortunately, most distributions do not yet offer a ``libyang``
+package from their repositories. Therefore we offer two options to install this
+library.
-Note: the libyang dev/devel packages need to be installed in addition
-to the libyang core package in order to build FRR successfully.
+**Option 1: Binary Install**
+
+The FRR project builds binary ``libyang`` packages, which we offer for download
+`here <https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
.. 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:
+ ``libyang`` version 0.16.74 or newer is required to build FRR.
+
+.. note::
-.. code-block:: shell
+ The ``libyang`` development packages need to be installed in addition to the
+ libyang core package in order to build FRR successfully. Make sure to
+ download and install those from the link above alongside the binary
+ packages.
- wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/CentOS-7-x86_64-Packages/libyang-0.16.46-0.x86_64.rpm
- wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/CentOS-7-x86_64-Packages/libyang-devel-0.16.46-0.x86_64.rpm
- sudo rpm -i libyang-0.16.46-0.x86_64.rpm libyang-devel-0.16.46-0.x86_64.rpm
+ Depending on your platform, you may also need to install the PCRE
+ development package. Typically this is ``libpcre-dev`` or ``pcre-devel``.
-or Ubuntu 18.04:
+.. note::
-.. code-block:: shell
+ 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.
- wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang-dev_0.16.46_amd64.deb
- wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang_0.16.46_amd64.deb
- sudo apt install libpcre3-dev
- sudo dpkg -i libyang-dev_0.16.46_amd64.deb libyang_0.16.46_amd64.deb
+**Option 2: Source Install**
.. 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:
+ Ensure that the `libyang build requirements
+ <https://github.com/CESNET/libyang/blob/master/README.md#build-requirements>`_
+ are met before continuing. Usually this entails installing ``cmake`` and
+ ``libpcre-dev`` or ``pcre-devel``.
-.. code-block:: shell
+.. code-block:: console
- git clone https://github.com/opensourcerouting/libyang
+ git clone https://github.com/CESNET/libyang.git
cd libyang
- git checkout -b tmp origin/tmp
mkdir build; cd build
- cmake -DENABLE_LYD_PRIV=ON ..
+ cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
make
sudo make install
When building libyang on CentOS 6, it's also necessary to pass the
``-DENABLE_CACHE=OFF`` parameter to cmake.
-Note: please check the `libyang build requirements
-<https://github.com/CESNET/libyang/blob/master/README.md#build-requirements>`_
-first.
building-frr-for-centos7
building-frr-for-debian8
building-frr-for-debian9
- building-frr-for-fedora24
+ building-frr-for-fedora
building-frr-for-freebsd10
building-frr-for-freebsd11
building-frr-for-freebsd9
# 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', 'topotests-snippets.rst']
+exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst', 'include-compile.rst']
# The reST default role (used for this markup: `text`) to use for all
# documents.
Libfrr provides type-safe subscribable hook points where other pieces of
code can add one or more callback functions. "type-safe" in this case
applies to the function pointers used for subscriptions. The
-implementations checks (at compile-time) wheter a callback to be added has
+implementations checks (at compile-time) whether a callback to be added has
the appropriate function signature (parameters) for the hook.
Example:
--- /dev/null
+Clone the FRR git repo and use the included ``configure`` script to configure
+FRR's build time options to your liking. The full option listing can be
+obtained by running ``./configure -h``. The options shown below are examples.
+
+.. note::
+
+ If your platform uses ``systemd``, please make sure to add
+ ``--enable-systemd=yes`` to your configure options.
+
+.. code-block:: console
+
+ git clone https://github.com/frrouting/frr.git frr
+ cd frr
+ ./bootstrap.sh
+ ./configure \
+ --prefix=/usr \
+ --includedir=\${prefix}/include \
+ --enable-exampledir=\${prefix}/share/doc/frr/examples \
+ --bindir=\${prefix}/bin \
+ --sbindir=\${prefix}/lib/frr \
+ --libdir=\${prefix}/lib/frr \
+ --libexecdir=\${prefix}/lib/frr \
+ --localstatedir=/var/run/frr \
+ --sysconfdir=/etc/frr \
+ --with-moduledir=\${prefix}/lib/frr/modules \
+ --with-libyang-pluginsdir=\${prefix}/lib/frr/libyang_plugins \
+ --enable-configfile-mask=0640 \
+ --enable-logfile-mask=0640 \
+ --enable-snmp=agentx \
+ --enable-multipath=64 \
+ --enable-user=frr \
+ --enable-group=frr \
+ --enable-vty-group=frrvty \
+ --with-pkg-git-version \
+ --with-pkg-extra-version=-MyOwnFRRVersion
+ make
+ sudo make install
needs to get the user in the loop—and only these things—are warnings or
errors.
-Note that this doesn't neccessarily mean the user needs to fix something in
+Note that this doesn't necessarily mean the user needs to fix something in
the FRR instance. It also includes when we detect something else needs
fixing, for example another router, the system we're running on, or the
configuration. The common point is that the user should probably do
Memtypes
========
-FRR includes wrappers arround ``malloc()`` and ``free()`` that count the number
+FRR includes wrappers around ``malloc()`` and ``free()`` that count the number
of objects currently allocated, for each of a defined ``MTYPE``.
To this extent, there are *memory groups* and *memory types*. Each memory
The message type field can take one of the following values:
+-------------------------------+---------+
-| Messages to OSPF deamon | Value |
+| Messages to OSPF daemon | Value |
+===============================+=========+
| MSG\_REGISTER\_OPAQUETYPE | 1 |
+-------------------------------+---------+
+-------------------------------+---------+
+-----------------------------+---------+
-| Messages from OSPF deamon | Value |
+| Messages from OSPF daemon | Value |
+=============================+=========+
| MSG\_REPLY | 10 |
+-----------------------------+---------+
Concepts
^^^^^^^^
-Segment Routing used 3 differents OPAQUE LSA in OSPF to carry the various
+Segment Routing used 3 different OPAQUE LSA in OSPF to carry the various
information:
* **Router Information:** flood the Segment Routing capabilities of the node.
* **Extended Link:** flood the Adjaceny and Lan Adjacency Segment Identifier
* **Extended Prefix:** flood the Prefix Segment Identifier
-The implementation follow previous TE and Router Information codes. It used the
+The implementation follows previous TE and Router Information codes. It used the
OPAQUE LSA functions defined in ospf_opaque.[c,h] as well as the OSPF API. This
latter is mandatory for the implementation as it provides the Callback to
Segment Routing functions (see below) when an Extended Link / Prefix or Router
(4.0.0.0), Extended Prefix (7.0.0.X) and Link (8.0.0.X) by ospf_ri.c,
respectively ospf_ext.c.
* ospf_ri.c send back to ospf_sr.c received Router Information LSA and update
- Self Router Information LSA with paramters provided by ospf_sr.c i.e. SRGB
+ Self Router Information LSA with parameters provided by ospf_sr.c i.e. SRGB
and MSD. It use ospf_opaque.c functions to send/received these Opaque LSAs.
* ospf_ext.c send back to ospf_sr.c received Extended Prefix and Link Opaque
LSA and send self Extended Prefix and Link Opaque LSA through ospf_opaque.c
Note that incoming LSA which is already present in the LSDB will be inserted
after the old instance of this LSA remove from the LSDB. Thus, after the first
time, each incoming LSA will trigger a `delete` following by an `install`. This
-is not very helpfull to handle real LSA deletion. In fact, LSA deletion is done
-by Flushing LSA i.e. flood LSA after seting its age to MAX_AGE. Then, a garbage
+is not very helpful to handle real LSA deletion. In fact, LSA deletion is done
+by Flushing LSA i.e. flood LSA after setting its age to MAX_AGE. Then, a garbage
function has the role to remove all LSA with `age == MAX_AGE` in the LSDB. So,
to handle LSA Flush, the best is to look to the LSA age to determine if it is
an installation or a future deletion i.e. the flushed LSA is first store in the
`ospf_router_info_update_sr()` is called to indicate to Router Information
process that Segment Routing TLVs must be flood. Same function is called to
modify the Segment Routing Global Block (SRGB) and Maximum Stack Depth (MSD)
-TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possiblity
+TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possibility
to modify this TLV is offer by the code.
When Opaque LSA Tyep 4 i.e. Router Information are stored in LSDB, function
^^^^^^^^^^^^^^^^^^^^^^^^^
Like for Router Information, Segment Routing is activate at the Extended
-Link/Prefix level with new `segment-routing on` command. This trigger
-automtically the flooding of Extended Link LSA for all ospf interface where
+Link/Prefix level with new `segment-routing on` command. This triggers
+automatically the flooding of Extended Link LSA for all ospf interfaces where
adjacency is full. For Extended Prefix LSA, the new CLI command
`segment-routing prefix ...` will trigger the flooding of Prefix SID
TLV/SubTLVs.
third line the MSD and finally, set the Prefix SID index for a given prefix.
Note that only prefix of Loopback interface could be configured with a Prefix
SID. It is possible to add `no-php-flag` at the end of the prefix command to
-disbale Penultimate Hop Popping. This advertises peers that they MUST NOT pop
+disable Penultimate Hop Popping. This advertises to peers that they MUST NOT pop
the MPLS label prior to sending the packet.
Known limitations
+.. _packaging-debian:
+
Packaging Debian
================
--- /dev/null
+.. _packaging-redhat:
+
+Packaging Red Hat
+=================
+
+Tested on CentOS 6, CentOS 7 and Fedora 24.
+
+1. On CentOS 6, refer to :ref:`building-centos6` for details on installing
+ sufficiently up-to-date package versions to enable building FRR.
+
+ Newer automake/autoconf/bison is only needed to build the RPM and is **not**
+ needed to install the binary RPM package.
+
+2. Install the build dependencies for your platform. Refer to the
+ platform-specific build documentation on how to do this.
+
+3. Install the following additional packages::
+
+ yum install rpm-build net-snmp-devel pam-devel libcap-devel
+
+ If your platform uses systemd::
+
+ yum install systemd-devel
+
+ If ``yum`` is not present on your system, use ``dnf`` instead.
+
+3. Checkout FRR::
+
+ git clone https://github.com/frrouting/frr.git frr
+
+4. Run Bootstrap and make distribution tar.gz::
+
+ cd frr
+ ./bootstrap.sh
+ ./configure --with-pkg-extra-version=-MyRPMVersion SPHINXBUILD=sphinx-build2.7
+ make dist
+
+ .. note::
+
+ The only ``configure`` option respected when building RPMs is
+ ``--with-pkg-extra-version``.
+
+5. Create RPM directory structure and populate with sources::
+
+ mkdir rpmbuild
+ mkdir rpmbuild/SOURCES
+ mkdir rpmbuild/SPECS
+ cp redhat/*.spec rpmbuild/SPECS/
+ cp frr*.tar.gz rpmbuild/SOURCES/
+
+6. Edit :file:`rpm/SPECS/frr.spec` with configuration as needed.
+
+ Look at the beginning of the file and adjust the following parameters to
+ enable or disable features as required::
+
+ ############### FRRouting (FRR) configure options #################
+ # with-feature options
+ %{!?with_pam: %global with_pam 0 }
+ %{!?with_ospfclient: %global with_ospfclient 1 }
+ %{!?with_ospfapi: %global with_ospfapi 1 }
+ %{!?with_irdp: %global with_irdp 1 }
+ %{!?with_rtadv: %global with_rtadv 1 }
+ %{!?with_ldpd: %global with_ldpd 1 }
+ %{!?with_nhrpd: %global with_nhrpd 1 }
+ %{!?with_eigrp: %global with_eigrpd 1 }
+ %{!?with_shared: %global with_shared 1 }
+ %{!?with_multipath: %global with_multipath 256 }
+ %{!?frr_user: %global frr_user frr }
+ %{!?vty_group: %global vty_group frrvty }
+ %{!?with_fpm: %global with_fpm 0 }
+ %{!?with_watchfrr: %global with_watchfrr 1 }
+ %{!?with_bgp_vnc: %global with_bgp_vnc 0 }
+ %{!?with_pimd: %global with_pimd 1 }
+ %{!?with_rpki: %global with_rpki 0 }
+
+7. Build the RPM::
+
+ rpmbuild --define "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/frr.spec
+
+ If building with RPKI, then download and install the additional RPKI
+ packages from
+ https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact
+
+If all works correctly, then you should end up with the RPMs under
+:file:`rpmbuild/RPMS` and the source RPM under :file:`rpmbuild/SRPMS`.
maintainer-release-build
packaging-debian
+ packaging-redhat
dev_RSTFILES = \
doc/developer/bgp-typecodes.rst \
doc/developer/bgpd.rst \
- doc/developer/building-frr-for-openwrt.rst \
doc/developer/building-frr-for-alpine.rst \
doc/developer/building-frr-for-centos6.rst \
doc/developer/building-frr-for-centos7.rst \
doc/developer/building-frr-for-debian8.rst \
doc/developer/building-frr-for-debian9.rst \
- doc/developer/building-frr-for-fedora24.rst \
+ doc/developer/building-frr-for-fedora.rst \
doc/developer/building-frr-for-freebsd10.rst \
doc/developer/building-frr-for-freebsd11.rst \
doc/developer/building-frr-for-freebsd9.rst \
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-openwrt.rst \
doc/developer/building-frr-for-ubuntu1404.rst \
doc/developer/building-frr-for-ubuntu1604.rst \
doc/developer/building-frr-for-ubuntu1804.rst \
doc/developer/cli.rst \
doc/developer/conf.py \
doc/developer/hooks.rst \
+ doc/developer/include-compile.rst \
doc/developer/index.rst \
doc/developer/library.rst \
doc/developer/logging.rst \
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/packaging-redhat.rst
+ doc/developer/packaging.rst \
doc/developer/testing.rst \
doc/developer/topotests-snippets.rst \
doc/developer/topotests.rst \
Interacting with equipment
^^^^^^^^^^^^^^^^^^^^^^^^^^
-You might want to interact with the topology equipments during the tests and
+You might want to interact with the topology equipment 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``
+1. When using the Topogen API, all the equipment code derives 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.
+ yourself how the abstractions that will be mentioned here work.
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
+ the equipment, which is by calling the ``mininet`` API functions directly
to spawn commands.
Interacting with the Linux sandbox
.. note::
- ``vtysh_(multi)cmd`` is only available for router type of equipments.
+ ``vtysh_(multi)cmd`` is only available for router types of equipment.
Invoking mininet CLI
^^^^^^^^^^^^^^^^^^^^
Comparing JSON output
^^^^^^^^^^^^^^^^^^^^^
-After obtaining JSON output formated with Python data structures, you may use
+After obtaining JSON output formatted with Python data structures, you may use
it to assert a minimalist schema:
.. code:: py
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FRR processes have the capabilities to report remaining memory allocations upon
-exit. To enable the reporting of the memory, define an enviroment variable
+exit. To enable the reporting of the memory, define an environment variable
``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.::
export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
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.
+names of equipment, 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
Command Extraction
------------------
-When VTYSH is a built, a Perl script named :file:`extract.pl` searches the FRR
+When VTYSH is built, a Perl script named :file:`extract.pl` searches the FRR
codebase looking for ``DEFUN``'s. It extracts these ``DEFUN``'s, transforms
them into ``DEFSH``'s and appends them to ``vtysh_cmd.c``. Each ``DEFSH``
contains the name of the command plus ``_vtysh``, as well as a flag that
VTYSH communicates with FRR daemons by way of domain socket. Each daemon
creates its own socket, typically in :file:`/var/run/frr/<daemon>.vty`. The
protocol is very simple. In the VTYSH to daemon direction, messages are simply
-NULL-terminated strings, whose content are CLI commands. Here is a typical
+NUL-terminated strings, whose content are CLI commands. Here is a typical
message from VTYSH to a daemon:
::
00000010: 6c0a 00 l..
-The response format has some more data in it. First is a NULL-terminated string
+The response format has some more data in it. First is a NUL-terminated string
containing the plaintext response, which is just the output of the command that
was sent in the request. This is displayed to the user. The plaintext response
is followed by 3 null marker bytes, followed by a 1-byte status code that
``MAJOR.MINOR`` release branch is pulled. Depending on the severity of the bugs,
bugfix releases may occur sooner.
-Bugfixes are applied to the two most recent releases. Security fixes are
-backported to all releases less than or equal to at least one year old. Security
-fixes may also be backported to older releases depending on severity.
+Bugfixes are applied to the two most recent releases. However, backporting of bug
+fixes to older than the two most recent releases will not be prevented, if acked
+under the classical development workflow applying for a pull request.
+
+Security fixes are backported to all releases less than or equal to at least one
+year old. Security fixes may also be backported to older releases depending on
+severity.
+
Long term support branches ( LTS )
-----------------------------------------
must be at least one person that is in charge of the maintenance branch. The person
on people responsible for a maintenance branch must be a FRR maintainer. Note that
they may choose to abandon support for the maintenance branch at any time. If
-noone takes over the responsibility of the LTS branch, then the support will be
+no one takes over the responsibility of the LTS branch, then the support will be
discontinued.
The LTS branch duties are the following ones:
be merged by someone unaffiliated with that company.
Guidelines for code review
-""""""""""""""""""""""""""
+--------------------------
- As a rule of thumb, the depth of the review should be proportional to the
scope and / or impact of the patch.
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
-exclude_patterns = ['_build', 'common-options.rst', 'epilogue.rst', 'defines.rst']
+exclude_patterns = ['_build', 'common-options.rst', 'epilogue.rst', 'defines.rst', 'bfd-options.rst']
# The reST default role (used for this markup: `text`) to use for all
# documents.
.. |synopsis-options| replace:: [-d|-t|-dt] [-C] [-f config-file] [-i pid-file] [-z zclient-path] [-u user] [-g group] [-A vty-addr] [-P vty-port] [-M module[:options]] [-N pathspace] [--vty_socket vty-path] [--moduledir module-path]
.. |synopsis-options-hv| replace:: [-h] [-v]
-.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), mtracebis(8)
+.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), fabricd(8), mtracebis(8)
.. index:: find COMMAND...
.. clicmd:: find COMMAND...
- This commmand performs a simple substring search across all defined commands
+ This command performs a simple substring search across all defined commands
in all modes. As an example, suppose you're in enable mode and can't
remember where the command to turn OSPF segment routing on is:
in iBGP topologies. This can occur with full-mesh iBGP, but is particularly
problematic in non-full-mesh iBGP topologies that further reduce the routing
information known to each speaker. This has primarily been documented with iBGP
-route-reflection topologies. However, any route-hiding technologies potentially
-could also exacerbate oscillation with MED.
+:ref:`route-reflection <bgp-route-reflector>` topologies. However, any
+route-hiding technologies potentially could also exacerbate oscillation with MED.
This second issue occurs where speakers each have only a subset of routes, and
there are cycles in the preferences between different combinations of routes -
``graceful-shutdown`` represents well-known communities value
``GRACEFUL_SHUTDOWN`` ``0xFFFF0000`` ``65535:0``. :rfc:`8326` implements
the purpose Graceful BGP Session Shutdown to reduce the amount of
- lost traffic when taking BGP sessions down for maintainance. The use
+ lost traffic when taking BGP sessions down for maintenance. The use
of the community needs to be supported from your peers side to
actually have any effect.
``llgr-stale``
``llgr-stale`` represents well-known communities value ``LLGR_STALE``
``0xFFFF0006`` ``65535:6``.
- Assigned and intented only for use with routers supporting the
+ Assigned and intended only for use with routers supporting the
Long-lived Graceful Restart Capability as described in
[Draft-IETF-uttaro-idr-bgp-persistence]_.
- Routers recieving routes with this community may (depending on
+ Routers receiving routes with this community may (depending on
implementation) choose allow to reject or modify routes on the
presence or absence of this community.
``no-llgr``
``no-llgr`` represents well-known communities value ``NO_LLGR``
``0xFFFF0007`` ``65535:7``.
- Assigned and intented only for use with routers supporting the
+ Assigned and intended only for use with routers supporting the
Long-lived Graceful Restart Capability as described in
[Draft-IETF-uttaro-idr-bgp-persistence]_.
- Routers recieving routes with this community may (depending on
+ Routers receiving routes with this community may (depending on
implementation) choose allow to reject or modify routes on the
presence or absence of this community.
There are two types of community list:
standard
- This type accepts an explicit value for the atttribute.
+ This type accepts an explicit value for the attribute.
expanded
This type accepts a regular expression. Because the regex must be
Route Reflector
===============
-.. note:: This documentation is woefully incomplete.
+BGP routers connected inside the same AS through BGP belong to an internal
+BGP session, or IBGP. In order to prevent routing table loops, IBGP does not
+advertise IBGP-learned routes to other routers in the same session. As such,
+IBGP requires a full mesh of all peers. For large networks, this quickly becomes
+unscalable. Introducing route reflectors removes the need for the full-mesh.
-.. index:: bgp cluster-id A.B.C.D
-.. clicmd:: bgp cluster-id A.B.C.D
+When route reflectors are configured, these will reflect the routes announced
+by the peers configured as clients. A route reflector client is configured
+with:
.. index:: neighbor PEER route-reflector-client
.. clicmd:: neighbor PEER route-reflector-client
.. index:: no neighbor PEER route-reflector-client
.. clicmd:: no neighbor PEER route-reflector-client
+To avoid single points of failure, multiple route reflectors can be configured.
+
+A cluster is a collection of route reflectors and their clients, and is used
+by route reflectors to avoid looping.
+
+.. index:: bgp cluster-id A.B.C.D
+.. clicmd:: bgp cluster-id A.B.C.D
.. _routing-policy:
route-map rm-no-export permit 20
!
route-map rm-blackhole permit 10
- description blackhole, up-pref and ensure it cant escape this AS
+ description blackhole, up-pref and ensure it cannot escape this AS
set ip next-hop 127.0.0.1
set local-preference 10
set community additive no-export
depicts how Route Targets are configured and how VRFs and cross VRF
configuration is done. Note that the VRF are mapped on Linux Network
Namespaces. For data traffic to cross VRF boundaries, virtual ethernet
-interfaces are created with private IP adressing scheme.
+interfaces are created with private IP addressing scheme.
.. code-block:: frr
- The validation procedure depicted in :rfc:`5575` is not available.
This validation procedure has not been implemented, as this feature was not
- used in the existing setups you shared wih us.
+ used in the existing setups you shared with us.
- The filtering action shaper value, if positive, is not used to apply shaping.
.. option:: --enable-multipath=X
Compile FRR with up to X way ECMP supported. This number can be from 0-999.
- For backwards compatability with older configure options when setting X = 0,
+ For backwards compatibility with older configure options when setting X = 0,
we will build FRR with 64 way ECMP. This is needed because there are
hardcoded arrays that FRR builds towards, so we need to know how big to
- make these arrays at build time.
+ make these arrays at build time. Additionally if this parameter is
+ not passed in FRR will default to 16 ECMP.
.. option:: --enable-shell-access
SPF-triggering event occurs within the hold-time of the previous SPF
calculation.
- This command supercedes the *timers spf* command in previous FRR
+ This command supersedes the *timers spf* command in previous FRR
releases.
.. index:: max-metric router-lsa [on-startup|on-shutdown] (5-86400)
When a incoming packet matches the destination prefix specified, take the
packet and forward according to the nexthops specified. This command accepts
- both v4 and v6 prefixes. This command is used in conjuction of the
+ both v4 and v6 prefixes. This command is used in conjunction of the
:clicmd:`match src-ip PREFIX` command for matching.
.. clicmd:: set nexthop-group NAME
Set the IGMP version used on this interface. The default value is 3.
-.. index:: ip multicat boundary oil WORD
-.. clicmd:: ip multicat boundary oil WORD
+.. index:: ip multicast boundary oil WORD
+.. clicmd:: ip multicast boundary oil WORD
Set a pim multicast boundary, based upon the WORD prefix-list. If a pim join
or IGMP report is received on this interface and the Group is denied by the
Using SHARP
===========
-All sharp commands are under the enable node and preceeded by the ``sharp``
+All sharp commands are under the enable node and preceded by the ``sharp``
keyword. At present, no sharp commands will be preserved in the config.
.. index:: sharp install
statistics information matches the same file statistics information as
`/proc/self/ns/net` ( through stat() function). As statistics information
matches, then `vrf0` stands for the new default namespace name.
-Consequently, the VRF naming `Default` will be overriden by the new discovered
+Consequently, the VRF naming `Default` will be overridden by the new discovered
namespace name `vrf0`.
For those who don't use VRF backend with *Linux network namespace*, it is
.. index:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
.. clicmd:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
- NETWORK ans MASK stand for the IP prefix entry to be added as static
+ NETWORK and MASK stand for the IP prefix entry to be added as static
route entry.
GATEWAY is the gateway IP address to reach, in order to reach the prefix.
INTERFACE is the interface behind which the prefix is located.
-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
return "Query from Successor while in active state";
case EIGRP_FSM_EVENT_LR_FCN:
return "Last Reply Event, Feasibility not satisfied";
- };
+ }
return "Unknown";
}
if (prefix->rij->count)
return EIGRP_FSM_KEEP_STATE;
- zlog_info("All reply received\n");
+ zlog_info("All reply received");
if (head->reported_distance < prefix->fdistance) {
return EIGRP_FSM_EVENT_LR_FCS;
}
} else if (prefix->rij->count) {
return EIGRP_FSM_KEEP_STATE;
} else {
- zlog_info("All reply received\n");
+ zlog_info("All reply received");
return EIGRP_FSM_EVENT_LR;
}
} else if (msg->packet_type == EIGRP_OPC_UPDATE
if (prefix->rij->count) {
return EIGRP_FSM_KEEP_STATE;
} else {
- zlog_info("All reply received\n");
+ zlog_info("All reply received");
if (head->reported_distance
< prefix->fdistance) {
return EIGRP_FSM_EVENT_LR_FCS;
} else if (prefix->rij->count) {
return EIGRP_FSM_KEEP_STATE;
} else {
- zlog_info("All reply received\n");
+ zlog_info("All reply received");
return EIGRP_FSM_EVENT_LR;
}
} else if (msg->packet_type == EIGRP_OPC_UPDATE
static uint16_t eigrp_hello_parameter_encode(struct eigrp_interface *ei,
struct stream *s, uint8_t flags)
{
- uint16_t length = EIGRP_TLV_PARAMETER_LEN;
-
// add in the parameters TLV
stream_putw(s, EIGRP_TLV_PARAMETER);
stream_putw(s, EIGRP_TLV_PARAMETER_LEN);
// and set hold time value..
stream_putw(s, ei->params.v_wait);
- return length;
+ return EIGRP_TLV_PARAMETER_LEN;
}
/**
{
struct eigrp *eigrp;
- int write = 0;
-
eigrp = eigrp_lookup();
if (eigrp != NULL) {
/* Writes 'router eigrp' section to config */
// config_write_eigrp_distance (vty, eigrp)
}
- return write;
+ return 0;
}
void eigrp_vty_show_init(void)
baselevel = level = 1;
complete = tree[0];
- if (complete != 0) {
+ if (complete != NULL) {
tree[0] = 0;
complete->right = dictnil;
- while (tree[level] != 0) {
+ while (tree[level] != NULL) {
tree[level]->right = complete;
complete->parent = tree[level];
complete = tree[level];
complete = curr;
assert(level == baselevel);
- while (tree[level] != 0) {
+ while (tree[level] != NULL) {
tree[level]->right = complete;
complete->parent = tree[level];
complete = tree[level];
complete = dictnil;
for (i = 0; i < DICT_DEPTH_MAX; i++) {
- if (tree[i] != 0) {
+ if (tree[i] != NULL) {
tree[i]->right = complete;
complete->parent = tree[i];
complete = tree[i];
/* remove from SPF trees */
spftree_area_adj_del(adj->circuit->area, adj);
- if (adj->area_addresses)
- XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses);
- if (adj->ipv4_addresses)
- XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses);
- if (adj->ipv6_addresses)
- XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses);
+ XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses);
+ XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses);
+ XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses);
adj_mt_finish(adj);
struct strioctl sioc;
pfil.Pf_Priority = 0;
- pfil.Pf_FilterLen = sizeof(pf_filter) / sizeof(unsigned short);
+ pfil.Pf_FilterLen = array_size(pf_filter);
memcpy(pfil.Pf_Filter, pf_filter, sizeof(pf_filter));
/* pfmod does not support transparent ioctls */
sioc.ic_cmd = PFIOCSETF;
.vty_group = VTY_GROUP,
#endif
.caps_p = _caps_p,
- .cap_num_p = sizeof(_caps_p) / sizeof(*_caps_p),
+ .cap_num_p = array_size(_caps_p),
.cap_num_i = 0};
/* isisd options */
if (tw_adj) {
if (tw_adj->state > ISIS_THREEWAY_DOWN) {
if (isis->debugs & DEBUG_ADJ_PACKETS) {
- zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d\n",
+ zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d",
iih->circuit->area->area_tag,
iih->circuit->interface->name,
tw_adj->state);
|| tw_adj->neighbor_circuit_id != (uint32_t) iih->circuit->idx)) {
if (isis->debugs & DEBUG_ADJ_PACKETS) {
- zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.\n",
+ zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.",
iih->circuit->area->area_tag,
iih->circuit->interface->name);
}
}
if (fabricd_initial_sync_is_complete(circuit->area) && resync_needed)
- zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!\n");
+ zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!");
retval = ISIS_OK;
out:
* stop lsp_id in this current CSNP.
*/
memcpy(start, stop, ISIS_SYS_ID_LEN + 2);
- loop = 0;
+ loop = false;
for (int i = ISIS_SYS_ID_LEN + 1; i >= 0; --i) {
if (start[i] < (uint8_t)0xff) {
start[i] += 1;
- loop = 1;
+ loop = true;
break;
}
}
int send_l1_csnp(struct thread *thread)
{
struct isis_circuit *circuit;
- int retval = ISIS_OK;
circuit = THREAD_ARG(thread);
assert(circuit);
isis_jitter(circuit->csnp_interval[0], CSNP_JITTER),
&circuit->t_send_csnp[0]);
- return retval;
+ return ISIS_OK;
}
int send_l2_csnp(struct thread *thread)
{
struct isis_circuit *circuit;
- int retval = ISIS_OK;
circuit = THREAD_ARG(thread);
assert(circuit);
isis_jitter(circuit->csnp_interval[1], CSNP_JITTER),
&circuit->t_send_csnp[1]);
- return retval;
+ return ISIS_OK;
}
/*
{
struct isis_circuit *circuit;
- int retval = ISIS_OK;
circuit = THREAD_ARG(thread);
assert(circuit);
isis_jitter(circuit->psnp_interval[0], PSNP_JITTER),
&circuit->t_send_psnp[0]);
- return retval;
+ return ISIS_OK;
}
/*
int send_l2_psnp(struct thread *thread)
{
struct isis_circuit *circuit;
- int retval = ISIS_OK;
circuit = THREAD_ARG(thread);
assert(circuit);
isis_jitter(circuit->psnp_interval[1], PSNP_JITTER),
&circuit->t_send_psnp[1]);
- return retval;
+ return ISIS_OK;
}
/*
redist = &area->redist_settings[protocol][type]
[level];
redist->redist = 0;
- if (redist->map_name)
- XFREE(MTYPE_ISIS, redist->map_name);
+ XFREE(MTYPE_ISIS, redist->map_name);
}
route_table_finish(area->ext_reach[protocol][level]);
}
default:
sbuf_push(buf, indent, " Unknown (%" PRIu8 ")\n", auth->type);
break;
- };
+ }
}
static void free_item_auth(struct isis_item *i)
struct nlpids *nlpids)
{
tlvs->protocols_supported.count = nlpids->count;
- if (tlvs->protocols_supported.protocols)
- XFREE(MTYPE_ISIS_TLV, tlvs->protocols_supported.protocols);
+ XFREE(MTYPE_ISIS_TLV, tlvs->protocols_supported.protocols);
if (nlpids->count) {
tlvs->protocols_supported.protocols =
XCALLOC(MTYPE_ISIS_TLV, nlpids->count);
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
DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info")
-int bfd_debug = 0;
-struct bfd_gbl bfd_gbl;
+static int bfd_debug = 0;
+static struct bfd_gbl bfd_gbl;
/*
* bfd_gbl_init - Initialize the BFD global structure
hook_call(cmd_execute_done, vty, cmd_exec);
- if (cmd_out)
- XFREE(MTYPE_TMP, cmd_out);
+ XFREE(MTYPE_TMP, cmd_out);
return ret;
}
ret = zlog_set_file(fullpath, loglevel);
- if (p)
- XFREE(MTYPE_TMP, p);
+ XFREE(MTYPE_TMP, p);
if (!ret) {
if (vty)
return CMD_WARNING_CONFIG_FAILED;
}
- if (host.logfile)
- XFREE(MTYPE_HOST, host.logfile);
+ XFREE(MTYPE_HOST, host.logfile);
host.logfile = XSTRDUP(MTYPE_HOST, fname);
{
zlog_reset_file();
- if (host.logfile)
- XFREE(MTYPE_HOST, host.logfile);
+ XFREE(MTYPE_HOST, host.logfile);
host.logfile = NULL;
}
return CMD_ERR_NO_FILE;
in = strstr(rpath, SYSCONFDIR);
if (in == rpath) {
- if (host.motdfile)
- XFREE(MTYPE_HOST, host.motdfile);
+ XFREE(MTYPE_HOST, host.motdfile);
host.motdfile = XSTRDUP(MTYPE_HOST, file);
} else
success = CMD_WARNING_CONFIG_FAILED;
/* Set config filename. Called from vty.c */
void host_config_set(const char *filename)
{
- if (host.config)
- XFREE(MTYPE_HOST, host.config);
+ XFREE(MTYPE_HOST, host.config);
host.config = XSTRDUP(MTYPE_HOST, filename);
}
cmdvec = NULL;
}
- if (host.name)
- XFREE(MTYPE_HOST, host.name);
- if (host.domainname)
- XFREE(MTYPE_HOST, host.domainname);
- if (host.password)
- XFREE(MTYPE_HOST, host.password);
- if (host.password_encrypt)
- XFREE(MTYPE_HOST, host.password_encrypt);
- if (host.enable)
- XFREE(MTYPE_HOST, host.enable);
- if (host.enable_encrypt)
- XFREE(MTYPE_HOST, host.enable_encrypt);
- if (host.logfile)
- XFREE(MTYPE_HOST, host.logfile);
- if (host.motdfile)
- XFREE(MTYPE_HOST, host.motdfile);
- if (host.config)
- XFREE(MTYPE_HOST, host.config);
+ XFREE(MTYPE_HOST, host.name);
+ XFREE(MTYPE_HOST, host.domainname);
+ XFREE(MTYPE_HOST, host.password);
+ XFREE(MTYPE_HOST, host.password_encrypt);
+ XFREE(MTYPE_HOST, host.enable);
+ XFREE(MTYPE_HOST, host.enable_encrypt);
+ XFREE(MTYPE_HOST, host.logfile);
+ XFREE(MTYPE_HOST, host.motdfile);
+ XFREE(MTYPE_HOST, host.config);
list_delete(&varhandlers);
qobj_finish();
struct cmd_token *tok = gn->data;
const char *color;
- if (wasend == true) {
+ if (wasend) {
wasend = false;
return;
}
DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname")
DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name")
-struct list *dist_ctx_list;
+static struct list *dist_ctx_list;
static struct distribute *distribute_new(void)
{
{
int i = 0;
- if (dist->ifname)
- XFREE(MTYPE_DISTRIBUTE_IFNAME, dist->ifname);
+ XFREE(MTYPE_DISTRIBUTE_IFNAME, dist->ifname);
- for (i = 0; i < DISTRIBUTE_MAX; i++)
- if (dist->list[i])
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[i]);
+ for (i = 0; i < DISTRIBUTE_MAX; i++) {
+ XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[i]);
+ }
- for (i = 0; i < DISTRIBUTE_MAX; i++)
- if (dist->prefix[i])
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[i]);
+ for (i = 0; i < DISTRIBUTE_MAX; i++) {
+ XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[i]);
+ }
XFREE(MTYPE_DISTRIBUTE, dist);
}
dist = hash_lookup(ctx->disthash, &key);
- if (key.ifname)
- XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
+ XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
return dist;
}
ret = hash_get(ctx->disthash, &key,
(void *(*)(void *))distribute_hash_alloc);
- if (key.ifname)
- XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
+ XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
return ret;
}
dist = distribute_get(ctx, ifname);
- if (dist->list[type])
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
+ XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
dist->list[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
/* Apply this distribute-list to the interface. */
dist = distribute_get(ctx, ifname);
- if (dist->prefix[type])
- XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
+ XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
dist->prefix[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
/* Apply this distribute-list to the interface. */
+++ /dev/null
-/*
- * Copyright (C) 2016 Christian Franke
- *
- * This file is part of Quagga.
- *
- * 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 (including the next
- * paragraph) 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.
- *
- * Alternatively, you can use, redistribute and/or modify it under the
- * following terms:
- *
- * Quagga 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.
- *
- * Quagga 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 "event_counter.h"
-
-void event_counter_inc(struct event_counter *counter)
-{
- counter->count++;
- counter->last = time(NULL);
-}
-
-const char *event_counter_format(const struct event_counter *counter)
-{
- struct tm last_change_store;
- struct tm *last_change;
- char timebuf[sizeof("Thu, 01 Jan 1970 00:00:00 +0000")];
- static char rv[20 + sizeof(" last: ") + sizeof(timebuf)];
-
- last_change = localtime_r(&counter->last, &last_change_store);
- if (!last_change
- || strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %T %z",
- last_change)
- == 0) {
- strlcpy(timebuf, "???", sizeof(timebuf));
- }
-
- snprintf(rv, sizeof(rv), "%5llu last: %s", counter->count,
- counter->last ? timebuf : "(never)");
- return rv;
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Christian Franke
- *
- * This file is part of Quagga.
- *
- * 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 (including the next
- * paragraph) 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.
- *
- * Alternatively, you can use, redistribute and/or modify it under the
- * following terms:
- *
- * Quagga 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.
- *
- * Quagga 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 _ZEBRA_EVENT_COUNTER_H
-#define _ZEBRA_EVENT_COUNTER_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct event_counter {
- unsigned long long count;
- time_t last;
-};
-
-void event_counter_inc(struct event_counter *counter);
-const char *event_counter_format(const struct event_counter *counter);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
/*
* Global shared hash table holding reference text for all defined errors.
*/
-pthread_mutex_t refs_mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t refs_mtx = PTHREAD_MUTEX_INITIALIZER;
struct hash *refs;
static bool ferr_hash_cmp(const void *a, const void *b)
/* Allocate new filter structure. */
static struct filter *filter_new(void)
{
- return (struct filter *)XCALLOC(MTYPE_ACCESS_FILTER,
- sizeof(struct filter));
+ return XCALLOC(MTYPE_ACCESS_FILTER, sizeof(struct filter));
}
static void filter_free(struct filter *filter)
/* Allocate new access list structure. */
static struct access_list *access_list_new(void)
{
- return (struct access_list *)XCALLOC(MTYPE_ACCESS_LIST,
- sizeof(struct access_list));
+ return XCALLOC(MTYPE_ACCESS_LIST, sizeof(struct access_list));
}
/* Free allocated access_list. */
else
list->head = access->next;
- if (access->name)
- XFREE(MTYPE_ACCESS_LIST_STR, access->name);
+ XFREE(MTYPE_ACCESS_LIST_STR, access->name);
- if (access->remark)
- XFREE(MTYPE_TMP, access->remark);
+ XFREE(MTYPE_TMP, access->remark);
access_list_free(access);
}
pthread_mutex_destroy(&fpt->mtx);
pthread_mutex_destroy(fpt->running_cond_mtx);
pthread_cond_destroy(fpt->running_cond);
- if (fpt->name)
- XFREE(MTYPE_FRR_PTHREAD, fpt->name);
+ XFREE(MTYPE_FRR_PTHREAD, fpt->name);
XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond_mtx);
XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond);
XFREE(MTYPE_FRR_PTHREAD, fpt);
cb = *cbp;
else {
cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
- if (!cb)
- return -1;
cb->write.cancelled = 1;
*cbp = cb;
cb = *cbp;
else {
cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
- if (!cb)
- return -1;
cb->read.cancelled = 1;
*cbp = cb;
bool begins_with(const char *str, const char *prefix)
{
if (!str || !prefix)
- return 0;
+ return false;
size_t lenstr = strlen(str);
size_t lenprefix = strlen(prefix);
if (lenprefix > lenstr)
- return 0;
+ return false;
return strncmp(str, prefix, lenprefix) == 0;
}
void init_cmdgraph(struct vty *, struct graph **);
/** shim interface commands **/
-struct graph *nodegraph = NULL, *nodegraph_free = NULL;
+static struct graph *nodegraph = NULL, *nodegraph_free = NULL;
#define check_nodegraph() \
do { \
DEFINE_MTYPE(LIB, HASH_BACKET, "Hash Bucket")
DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index")
-pthread_mutex_t _hashes_mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t _hashes_mtx = PTHREAD_MUTEX_INITIALIZER;
static struct list *_hashes;
struct hash *hash_create_size(unsigned int size,
new_index = XCALLOC(MTYPE_HASH_INDEX,
sizeof(struct hash_bucket *) * new_size);
- if (new_index == NULL)
- return;
hash->stats.empty = new_size;
}
pthread_mutex_unlock(&_hashes_mtx);
- if (hash->name)
- XFREE(MTYPE_HASH, hash->name);
+ XFREE(MTYPE_HASH, hash->name);
XFREE(MTYPE_HASH_INDEX, hash->index);
XFREE(MTYPE_HASH, hash);
DEFINE_HOOK(if_add, (struct interface * ifp), (ifp))
DEFINE_KOOH(if_del, (struct interface * ifp), (ifp))
-/* List of interfaces in only the default VRF */
-int ptm_enable = 0;
-
/* Compare interface names, returning an integer greater than, equal to, or
* less than 0, (following the strcmp convention), according to the
* relationship between ifp1 and ifp2. Interface names consist of an
if_link_params_free(ifp);
- if (ifp->desc)
- XFREE(MTYPE_TMP, ifp->desc);
+ XFREE(MTYPE_TMP, ifp->desc);
XFREE(MTYPE_IF, ifp);
}
struct interface *ifp;
switch (vrf_get_backend()) {
+ case VRF_BACKEND_UNKNOWN:
case VRF_BACKEND_NETNS:
ifp = if_lookup_by_name(name, vrf_id);
if (ifp)
if (connected->destination)
prefix_free(connected->destination);
- if (connected->label)
- XFREE(MTYPE_CONNECTED_LABEL, connected->label);
+ XFREE(MTYPE_CONNECTED_LABEL, connected->label);
XFREE(MTYPE_CONNECTED, connected);
}
vrf->name);
return NB_ERR_VALIDATION;
}
+
+ /* if VRF is netns or not yet known - init for instance
+ * then assumption is that passed config is exact
+ * then the user intent was not to use an other iface
+ */
if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) {
ifp = if_lookup_by_name_all_vrf(ifname);
if (ifp && ifp->vrf_id != vrf->vrf_id) {
return NB_OK;
ifp = yang_dnode_get_entry(dnode, true);
- if (ifp->desc)
- XFREE(MTYPE_TMP, ifp->desc);
+ XFREE(MTYPE_TMP, ifp->desc);
description = yang_dnode_get_string(dnode, NULL);
ifp->desc = XSTRDUP(MTYPE_TMP, description);
return NB_OK;
ifp = yang_dnode_get_entry(dnode, true);
- if (ifp->desc)
- XFREE(MTYPE_TMP, ifp->desc);
+ XFREE(MTYPE_TMP, ifp->desc);
return NB_OK;
}
DEFINE_MTYPE_STATIC(LIB, IF_RMAP, "Interface route map")
DEFINE_MTYPE_STATIC(LIB, IF_RMAP_NAME, "I.f. route map name")
-struct list *if_rmap_ctx_list;
+static struct list *if_rmap_ctx_list;
static struct if_rmap *if_rmap_new(void)
{
static void if_rmap_free(struct if_rmap *if_rmap)
{
- if (if_rmap->ifname)
- XFREE(MTYPE_IF_RMAP_NAME, if_rmap->ifname);
+ XFREE(MTYPE_IF_RMAP_NAME, if_rmap->ifname);
- if (if_rmap->routemap[IF_RMAP_IN])
- XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]);
- if (if_rmap->routemap[IF_RMAP_OUT])
- XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]);
+ XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]);
+ XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]);
XFREE(MTYPE_IF_RMAP, if_rmap);
}
if_rmap = hash_lookup(ctx->ifrmaphash, &key);
- if (key.ifname)
- XFREE(MTYPE_IF_RMAP_NAME, key.ifname);
+ XFREE(MTYPE_IF_RMAP_NAME, key.ifname);
return if_rmap;
}
ret = hash_get(ctx->ifrmaphash, &key, if_rmap_hash_alloc);
- if (key.ifname)
- XFREE(MTYPE_IF_RMAP_NAME, key.ifname);
+ XFREE(MTYPE_IF_RMAP_NAME, key.ifname);
return ret;
}
if_rmap = if_rmap_get(ctx, ifname);
if (type == IF_RMAP_IN) {
- if (if_rmap->routemap[IF_RMAP_IN])
- XFREE(MTYPE_IF_RMAP_NAME,
- if_rmap->routemap[IF_RMAP_IN]);
+ XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]);
if_rmap->routemap[IF_RMAP_IN] =
XSTRDUP(MTYPE_IF_RMAP_NAME, routemap_name);
}
if (type == IF_RMAP_OUT) {
- if (if_rmap->routemap[IF_RMAP_OUT])
- XFREE(MTYPE_IF_RMAP_NAME,
- if_rmap->routemap[IF_RMAP_OUT]);
+ XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]);
if_rmap->routemap[IF_RMAP_OUT] =
XSTRDUP(MTYPE_IF_RMAP_NAME, routemap_name);
}
#include <zebra.h>
+#include "memory.h"
#include "queue.h"
#include "imsg.h"
-int imsg_fd_overhead = 0;
+static int imsg_fd_overhead = 0;
-int imsg_get_fd(struct imsgbuf *);
+static int imsg_get_fd(struct imsgbuf *);
#ifndef __OpenBSD__
/*
unsigned int i;
int ret, fds[256];
- if (n > (sizeof(fds) / sizeof(fds[0])))
+ if (n > (unsigned int)array_size(fds))
return (1);
ret = 0;
/* fallthru */
case 1:
a += k[0];
- };
+ }
__jhash_mix(a, b, c);
/* fallthru */
case 1:
a += k[0];
- };
+ }
__jhash_mix(a, b, c);
DEFINE_QOBJ_TYPE(key)
/* Master list of key chain. */
-struct list *keychain_list;
+static struct list *keychain_list;
static struct keychain *keychain_new(void)
{
static void keychain_delete(struct keychain *keychain)
{
- if (keychain->name)
- XFREE(MTYPE_KEYCHAIN, keychain->name);
+ XFREE(MTYPE_KEYCHAIN, keychain->name);
list_delete(&keychain->key);
listnode_delete(keychain_list, keychain);
{
listnode_delete(keychain->key, key);
- if (key->string)
- XFREE(MTYPE_KEY, key->string);
+ XFREE(MTYPE_KEY, key->string);
key_free(key);
}
#endif
static char vtypath_default[256];
-bool debug_memstats_at_exit = 0;
+bool debug_memstats_at_exit = false;
static bool nodetach_term, nodetach_daemon;
static char comb_optstr[256];
bool zlog_startup_stderr = true;
/* lock protecting zlog_default for mt-safe zlog */
-pthread_mutex_t loglock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t loglock = PTHREAD_MUTEX_INITIALIZER;
const char *zlog_priority[] = {
"emergencies", "alerts", "critical", "errors", "warnings",
if (zl->fp != NULL)
fclose(zl->fp);
- if (zl->filename != NULL)
- XFREE(MTYPE_ZLOG, zl->filename);
+ XFREE(MTYPE_ZLOG, zl->filename);
XFREE(MTYPE_ZLOG, zl);
zlog_default = NULL;
logfile_fd = -1;
zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
- if (zl->filename)
- XFREE(MTYPE_ZLOG, zl->filename);
+ XFREE(MTYPE_ZLOG, zl->filename);
zl->filename = NULL;
pthread_mutex_unlock(&loglock);
DESC_ENTRY(ZEBRA_ROUTER_ID_DELETE),
DESC_ENTRY(ZEBRA_ROUTER_ID_UPDATE),
DESC_ENTRY(ZEBRA_HELLO),
+ DESC_ENTRY(ZEBRA_CAPABILITIES),
DESC_ENTRY(ZEBRA_NEXTHOP_REGISTER),
DESC_ENTRY(ZEBRA_NEXTHOP_UNREGISTER),
DESC_ENTRY(ZEBRA_NEXTHOP_UPDATE),
DESC_ENTRY(ZEBRA_VRF_LABEL),
DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE),
DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER),
+ DESC_ENTRY(ZEBRA_BFD_CLIENT_DEREGISTER),
DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV),
DESC_ENTRY(ZEBRA_INTERFACE_DISABLE_RADV),
DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB),
DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC),
DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK),
DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK),
+ DESC_ENTRY(ZEBRA_FEC_REGISTER),
+ DESC_ENTRY(ZEBRA_FEC_UNREGISTER),
+ DESC_ENTRY(ZEBRA_FEC_UPDATE),
DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP),
DESC_ENTRY(ZEBRA_IPSET_DESTROY),
DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD),
DESC_ENTRY(ZEBRA_IPSET_ENTRY_DELETE),
+ DESC_ENTRY(ZEBRA_IPSET_NOTIFY_OWNER),
+ DESC_ENTRY(ZEBRA_IPSET_ENTRY_NOTIFY_OWNER),
+ DESC_ENTRY(ZEBRA_IPTABLE_ADD),
+ DESC_ENTRY(ZEBRA_IPTABLE_DELETE),
+ DESC_ENTRY(ZEBRA_IPTABLE_NOTIFY_OWNER),
DESC_ENTRY(ZEBRA_VXLAN_FLOOD_CONTROL),
};
#undef DESC_ENTRY
return rtinfo;
out_fail:
- if (rtinfo->load_args)
- XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args);
+ XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args);
XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name);
return NULL;
}
// if_terminate (&ns->iflist);
RB_REMOVE(ns_head, &ns_tree, ns);
- if (ns->name)
- XFREE(MTYPE_NS_NAME, ns->name);
+ XFREE(MTYPE_NS_NAME, ns->name);
XFREE(MTYPE_NS, ns);
}
/*
* Check if the labels match for the 2 nexthops specified.
*/
-int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2)
+int nexthop_labels_match(const struct nexthop *nh1, const struct nexthop *nh2)
{
- struct mpls_label_stack *nhl1, *nhl2;
+ const struct mpls_label_stack *nhl1, *nhl2;
nhl1 = nh1->nh_label;
nhl2 = nh2->nh_label;
+
+ /* No labels is a match */
+ if (!nhl1 && !nhl2)
+ return 1;
+
if (!nhl1 || !nhl2)
return 0;
break;
}
- return true;
+ /* Compare labels too (if present) */
+ return (!!nexthop_labels_match(nh1, nh2));
}
/* Update nexthop with label information. */
extern const char *nexthop_type_to_str(enum nexthop_types_t nh_type);
extern int nexthop_same_no_recurse(const struct nexthop *next1,
const struct nexthop *next2);
-extern int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2);
+extern int nexthop_labels_match(const struct nexthop *nh1,
+ const struct nexthop *nh2);
extern int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2);
-extern const char *nexthop2str(const struct nexthop *nexthop, char *str, int size);
+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);
RB_GENERATE(nhgc_entry_head, nexthop_group_cmd, nhgc_entry,
nexthop_group_cmd_compare)
-struct nhgc_entry_head nhgc_entries;
+static struct nhgc_entry_head nhgc_entries;
static inline int
nexthop_group_cmd_compare(const struct nexthop_group_cmd *nhgc1,
nh->next = NULL;
}
-void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
+void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
struct nexthop *rparent)
{
struct nexthop *nexthop;
- struct nexthop *nh1;
+ const struct nexthop *nh1;
for (nh1 = nh; nh1; nh1 = nh1->next) {
nexthop = nexthop_new();
return strcmp(a, b);
}
+static int nhgc_addr_cmp_helper(const union sockunion *a, const union sockunion *b)
+{
+ if (!a && !b)
+ return 0;
+
+ if (a && !b)
+ return -1;
+
+ if (!a && b)
+ return 1;
+
+ return sockunion_cmp(a, b);
+}
+
static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
{
int ret;
- ret = sockunion_cmp(&nh1->addr, &nh2->addr);
+ ret = nhgc_addr_cmp_helper(nh1->addr, nh2->addr);
if (ret)
return ret;
static void nhgl_delete(struct nexthop_hold *nh)
{
- if (nh->intf)
- XFREE(MTYPE_TMP, nh->intf);
+ XFREE(MTYPE_TMP, nh->intf);
- if (nh->nhvrf_name)
- XFREE(MTYPE_TMP, nh->nhvrf_name);
+ XFREE(MTYPE_TMP, nh->nhvrf_name);
+
+ if (nh->addr)
+ sockunion_free(nh->addr);
XFREE(MTYPE_TMP, nh);
}
nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name);
if (intf)
nh->intf = XSTRDUP(MTYPE_TMP, intf);
-
- nh->addr = *addr;
+ if (addr)
+ nh->addr = sockunion_dup(addr);
listnode_add_sort(nhgc->nhg_list, nh);
}
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&
- sockunion_cmp(addr, &nh->addr) == 0 &&
+ nhgc_addr_cmp_helper(addr, nh->addr) == 0 &&
nhgc_cmp_helper(intf, nh->intf) == 0)
break;
}
return;
list_delete_node(nhgc->nhg_list, node);
-
- if (nh->nhvrf_name)
- XFREE(MTYPE_TMP, nh->nhvrf_name);
- if (nh->intf)
- XFREE(MTYPE_TMP, nh->intf);
-
- XFREE(MTYPE_TMP, nh);
+ nhgl_delete(nh);
}
static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
nhop->vrf_id = vrf->vrf_id;
- if (addr->sa.sa_family == AF_INET) {
- nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
- if (intf) {
- nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
- nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
- if (nhop->ifindex == IFINDEX_INTERNAL)
- return false;
- } else
- nhop->type = NEXTHOP_TYPE_IPV4;
- } else {
- memcpy(&nhop->gate.ipv6, &addr->sin6.sin6_addr, 16);
- if (intf) {
- nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
- nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
- if (nhop->ifindex == IFINDEX_INTERNAL)
- return false;
- } else
- nhop->type = NEXTHOP_TYPE_IPV6;
+ if (intf) {
+ nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
+ if (nhop->ifindex == IFINDEX_INTERNAL)
+ return false;
}
+ if (addr) {
+ if (addr->sa.sa_family == AF_INET) {
+ nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
+ if (intf)
+ nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ else
+ nhop->type = NEXTHOP_TYPE_IPV4;
+ } else {
+ nhop->gate.ipv6 = addr->sin6.sin6_addr;
+ if (intf)
+ nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ else
+ nhop->type = NEXTHOP_TYPE_IPV6;
+ }
+ } else
+ nhop->type = NEXTHOP_TYPE_IFINDEX;
+
return true;
}
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
- "[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
+ "[no] nexthop\
+ <\
+ <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
+ |INTERFACE$intf\
+ >\
+ [nexthop-vrf NAME$name]",
NO_STR
"Specify one of the nexthops in this ECMP group\n"
"v4 Address\n"
"v6 Address\n"
"Interface to use\n"
+ "Interface to use\n"
"If the nexthop is in a different vrf tell us\n"
"The nexthop-vrf Name\n")
{
struct nexthop *nh;
bool legal;
- /*
- * This is impossible to happen as that the cli parser refuses
- * to let you get here without an addr, but the SA system
- * does not understand this intricacy
- */
- assert(addr);
-
legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name);
if (nhop.type == NEXTHOP_TYPE_IPV6
{
char buf[100];
- vty_out(vty, "nexthop ");
+ vty_out(vty, "nexthop");
- vty_out(vty, "%s", sockunion2str(&nh->addr, buf, sizeof(buf)));
+ if (nh->addr)
+ vty_out(vty, " %s", sockunion2str(nh->addr, buf, sizeof(buf)));
if (nh->intf)
vty_out(vty, " %s", nh->intf);
vty_out(vty, "nexthop-group %s\n", nhgc->name);
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
- vty_out(vty, " ");
+ vty_out(vty, " ");
nexthop_group_write_nexthop_internal(vty, nh);
}
struct nexthop nhop;
struct nexthop *nh;
- if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
+ if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
nhh->intf,
nhh->nhvrf_name))
continue;
struct nexthop nhop;
struct nexthop *nh;
- if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
+ if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
nhh->intf,
nhh->nhvrf_name))
continue;
struct nexthop nhop;
if (!nexthop_group_parse_nexthop(
- &nhop, &nhh->addr, nhh->intf,
+ &nhop, nhh->addr, nhh->intf,
nhh->nhvrf_name))
continue;
void nexthop_add(struct nexthop **target, struct nexthop *nexthop);
void nexthop_del(struct nexthop_group *nhg, struct nexthop *nexthop);
-void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
+void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
struct nexthop *rparent);
/* The following for loop allows to iterate over the nexthop
struct nexthop_hold {
char *nhvrf_name;
- union sockunion addr;
+ union sockunion *addr;
char *intf;
};
* configurations. Given a new subtree, calculate all new YANG data nodes,
* excluding default leafs and leaf-lists. This is a recursive function.
*/
-static void nb_config_diff_new_subtree(const struct lyd_node *dnode,
- struct nb_config_cbs *changes)
+static void nb_config_diff_created(const struct lyd_node *dnode,
+ struct nb_config_cbs *changes)
{
+ enum nb_operation operation;
struct lyd_node *child;
- LY_TREE_FOR (dnode->child, child) {
- enum nb_operation operation;
+ switch (dnode->schema->nodetype) {
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ if (lyd_wd_default((struct lyd_node_leaf_list *)dnode))
+ break;
- switch (child->schema->nodetype) {
- case LYS_LEAF:
- case LYS_LEAFLIST:
- if (lyd_wd_default((struct lyd_node_leaf_list *)child))
- break;
+ if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
+ operation = NB_OP_CREATE;
+ else if (nb_operation_is_valid(NB_OP_MODIFY, dnode->schema))
+ operation = NB_OP_MODIFY;
+ else
+ return;
- if (nb_operation_is_valid(NB_OP_CREATE, child->schema))
- operation = NB_OP_CREATE;
- else if (nb_operation_is_valid(NB_OP_MODIFY,
- child->schema))
- operation = NB_OP_MODIFY;
- else
- continue;
+ nb_config_diff_add_change(changes, operation, dnode);
+ break;
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
+ nb_config_diff_add_change(changes, NB_OP_CREATE, dnode);
- nb_config_diff_add_change(changes, operation, child);
- break;
- case LYS_CONTAINER:
- case LYS_LIST:
- if (nb_operation_is_valid(NB_OP_CREATE, child->schema))
- nb_config_diff_add_change(changes, NB_OP_CREATE,
- child);
- nb_config_diff_new_subtree(child, changes);
- break;
- default:
- break;
+ /* Process child nodes recursively. */
+ LY_TREE_FOR (dnode->child, child) {
+ nb_config_diff_created(child, changes);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void nb_config_diff_deleted(const struct lyd_node *dnode,
+ struct nb_config_cbs *changes)
+{
+ if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema))
+ nb_config_diff_add_change(changes, NB_OP_DESTROY, dnode);
+ else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) {
+ struct lyd_node *child;
+
+ /*
+ * Non-presence containers need special handling since they
+ * don't have "destroy" callbacks. In this case, what we need to
+ * do is to call the "destroy" callbacks of their child nodes
+ * when applicable (i.e. optional nodes).
+ */
+ LY_TREE_FOR (dnode->child, child) {
+ nb_config_diff_deleted(child, changes);
}
}
}
for (int i = 0; diff->type[i] != LYD_DIFF_END; i++) {
LYD_DIFFTYPE type;
struct lyd_node *dnode;
- enum nb_operation operation;
type = diff->type[i];
switch (type) {
case LYD_DIFF_CREATED:
dnode = diff->second[i];
-
- if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
- operation = NB_OP_CREATE;
- else if (nb_operation_is_valid(NB_OP_MODIFY,
- dnode->schema))
- operation = NB_OP_MODIFY;
- else
- continue;
+ nb_config_diff_created(dnode, changes);
break;
case LYD_DIFF_DELETED:
dnode = diff->first[i];
- operation = NB_OP_DESTROY;
+ nb_config_diff_deleted(dnode, changes);
break;
case LYD_DIFF_CHANGED:
dnode = diff->second[i];
- operation = NB_OP_MODIFY;
+ nb_config_diff_add_change(changes, NB_OP_MODIFY, dnode);
break;
case LYD_DIFF_MOVEDAFTER1:
case LYD_DIFF_MOVEDAFTER2:
default:
continue;
}
-
- nb_config_diff_add_change(changes, operation, dnode);
-
- if (type == LYD_DIFF_CREATED
- && CHECK_FLAG(dnode->schema->nodetype,
- LYS_CONTAINER | LYS_LIST))
- nb_config_diff_new_subtree(dnode, changes);
}
lyd_free_diff(diff);
static int frr_confd_finish(void)
{
- if (confd_connected == false)
+ if (!confd_connected)
return 0;
frr_confd_finish_cdb();
else
list->head = plist->next;
- if (plist->desc)
- XFREE(MTYPE_TMP, plist->desc);
+ XFREE(MTYPE_TMP, plist->desc);
/* Make sure master's recent changed prefix-list information is
cleared. */
if (master->delete_hook)
(*master->delete_hook)(plist);
- if (plist->name)
- XFREE(MTYPE_MPREFIX_LIST_STR, plist->name);
+ XFREE(MTYPE_MPREFIX_LIST_STR, plist->name);
XFREE(MTYPE_PREFIX_LIST_TRIE, plist->trie);
newarray =
XCALLOC(MTYPE_PQUEUE_DATA, queue->array_size * DATA_SIZE * 2);
- if (newarray == NULL)
- return 0;
memcpy(newarray, queue->array, queue->array_size * DATA_SIZE);
ret = 1;
done:
- if (cp)
- XFREE(MTYPE_TMP, cp);
+ XFREE(MTYPE_TMP, cp);
return ret;
}
if (!mac)
return NULL;
if (!buf)
- ptr = (char *)XMALLOC(MTYPE_TMP,
- ETHER_ADDR_STRLEN * sizeof(char));
+ ptr = XMALLOC(MTYPE_TMP, ETHER_ADDR_STRLEN * sizeof(char));
else {
assert(size >= ETHER_ADDR_STRLEN);
ptr = buf;
if (!esi)
return NULL;
if (!buf)
- ptr = (char *)XMALLOC(MTYPE_TMP,
- ESI_STR_LEN * sizeof(char));
+ ptr = XMALLOC(MTYPE_TMP, ESI_STR_LEN * sizeof(char));
else {
assert(size >= ESI_STR_LEN);
ptr = buf;
return 0;
}
+static inline int is_default_host_route(struct prefix *p)
+{
+ if (p->family == AF_INET) {
+ return (p->u.prefix4.s_addr == INADDR_ANY &&
+ p->prefixlen == IPV4_MAX_BITLEN);
+ } else if (p->family == AF_INET6) {
+ return ((!memcmp(&p->u.prefix6, &in6addr_any,
+ sizeof(struct in6_addr))) &&
+ p->prefixlen == IPV6_MAX_BITLEN);
+ }
+ return 0;
+}
+
#ifdef __cplusplus
}
#endif
if (!privs)
return NULL;
- errno = 0;
- if (privs->change(ZPRIVS_RAISE)) {
- zlog_err("%s: Failed to raise privileges (%s)",
- funcname, safe_strerror(errno));
+ /* If we're already elevated, just return */
+ pthread_mutex_lock(&(privs->mutex));
+ {
+ if (++(privs->refcount) == 1) {
+ errno = 0;
+ if (privs->change(ZPRIVS_RAISE)) {
+ zlog_err("%s: Failed to raise privileges (%s)",
+ funcname, safe_strerror(errno));
+ }
+ errno = save_errno;
+ privs->raised_in_funcname = funcname;
+ }
}
- errno = save_errno;
- privs->raised_in_funcname = funcname;
+ pthread_mutex_unlock(&(privs->mutex));
+
return privs;
}
if (!*privs)
return;
- errno = 0;
- if ((*privs)->change(ZPRIVS_LOWER)) {
- zlog_err("%s: Failed to lower privileges (%s)",
- (*privs)->raised_in_funcname, safe_strerror(errno));
+ /* Don't lower privs if there's another caller */
+ pthread_mutex_lock(&(*privs)->mutex);
+ {
+ if (--((*privs)->refcount) == 0) {
+ errno = 0;
+ if ((*privs)->change(ZPRIVS_LOWER)) {
+ zlog_err("%s: Failed to lower privileges (%s)",
+ (*privs)->raised_in_funcname,
+ safe_strerror(errno));
+ }
+ errno = save_errno;
+ (*privs)->raised_in_funcname = NULL;
+ }
}
- errno = save_errno;
- (*privs)->raised_in_funcname = NULL;
+ pthread_mutex_unlock(&(*privs)->mutex);
+
*privs = NULL;
}
exit(1);
}
+ pthread_mutex_init(&(zprivs->mutex), NULL);
+ zprivs->refcount = 0;
+
if (zprivs->vty_group) {
/* in a "NULL" setup, this is allowed to fail too, but still
* try. */
#ifndef _ZEBRA_PRIVS_H
#define _ZEBRA_PRIVS_H
+#include <pthread.h>
+
#ifdef __cplusplus
extern "C" {
#endif
zebra_capabilities_t *caps_i; /* caps to allow inheritance of */
int cap_num_p; /* number of caps in arrays */
int cap_num_i;
+
+ /* Mutex and counter used to avoid race conditions in multi-threaded
+ * processes. The privs elevation is process-wide, so we need to
+ * avoid changing the privilege status across threads.
+ */
+ pthread_mutex_t mutex;
+ uint32_t refcount;
+
const char *user; /* user and group to run as */
const char *group;
const char *vty_group; /* group to chown vty socket to */
break;
}
- if (dep_name)
- XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
- if (rmap_name)
- XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+ XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
return retval;
}
index->map->head = index->next;
/* Free 'char *nextrm' if not NULL */
- if (index->nextrm)
- XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
+ XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
/* Execute event hook. */
if (route_map_master.event_hook && notify) {
if (rule->cmd->func_free)
(*rule->cmd->func_free)(rule->value);
- if (rule->rule_str)
- XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
+ XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
if (rule->next)
rule->next->prev = rule->prev;
}
ret_map_name = (char *)hash_release(dep->dep_rmap_hash, rname);
- if (ret_map_name)
- XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
+ XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name);
if (!dep->dep_rmap_hash->count) {
dep = hash_release(dephash, dname);
/* master signals descriptor struct */
-struct quagga_sigevent_master_t {
+static struct quagga_sigevent_master_t {
struct thread *t;
struct quagga_signal_t *signals;
lib/csv.c \
lib/debug.c \
lib/distribute.c \
- lib/event_counter.c \
lib/ferr.c \
lib/filter.c \
lib/frr_pthread.c \
lib/db.h \
lib/debug.h \
lib/distribute.h \
- lib/event_counter.h \
lib/ferr.h \
lib/fifo.h \
lib/filter.h \
} while (0);
/* control variable for initializer */
-pthread_once_t init_once = PTHREAD_ONCE_INIT;
+static pthread_once_t init_once = PTHREAD_ONCE_INIT;
pthread_key_t thread_current;
-pthread_mutex_t masters_mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t masters_mtx = PTHREAD_MUTEX_INITIALIZER;
static struct list *masters;
static void thread_free(struct thread_master *master, struct thread *thread);
static void vty_out_cpu_thread_history(struct vty *vty,
struct cpu_thread_history *a)
{
- 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,
+ vty_out(vty, "%5zu %10zu.%03lu %9zu %8zu %9zu %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);
vty_out(vty, " %c%c%c%c%c %s\n",
a->types & (1 << THREAD_READ) ? 'R' : ' ',
pthread_once(&init_once, &initializer);
rv = XCALLOC(MTYPE_THREAD_MASTER, sizeof(struct thread_master));
- if (rv == NULL)
- return NULL;
/* Initialize master mutex */
pthread_mutex_init(&rv->mtx, NULL);
{
pthread_mutex_lock(&master->mtx);
{
- if (master->name)
- XFREE(MTYPE_THREAD_MASTER, master->name);
+ XFREE(MTYPE_THREAD_MASTER, master->name);
master->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
}
pthread_mutex_unlock(&master->mtx);
hash_free(m->cpu_record);
m->cpu_record = NULL;
- if (m->name)
- XFREE(MTYPE_THREAD_MASTER, m->name);
+ XFREE(MTYPE_THREAD_MASTER, m->name);
XFREE(MTYPE_THREAD_MASTER, m->handler.pfds);
XFREE(MTYPE_THREAD_MASTER, m->handler.copy);
XFREE(MTYPE_THREAD_MASTER, m);
struct vrf_name_head vrfs_by_name = RB_INITIALIZER(&vrfs_by_name);
static int vrf_backend;
+static int vrf_backend_configured;
static struct zebra_privs_t *vrf_daemon_privs;
static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL;
* Turn on/off debug code
* for vrf.
*/
-int debug_vrf = 0;
+static int debug_vrf = 0;
/* Holding VRF hooks */
struct vrf_master {
int vrf_get_backend(void)
{
+ if (!vrf_backend_configured)
+ return VRF_BACKEND_UNKNOWN;
return vrf_backend;
}
void vrf_configure_backend(int vrf_backend_netns)
{
vrf_backend = vrf_backend_netns;
+ vrf_backend_configured = 1;
}
int vrf_handler_create(struct vty *vty, const char *vrfname,
"VRF %u is already configured with VRF %s\n",
vrf->vrf_id, vrf->name);
else
- zlog_info("VRF %u is already configured with VRF %s\n",
+ zlog_info("VRF %u is already configured with VRF %s",
vrf->vrf_id, vrf->name);
return CMD_WARNING_CONFIG_FAILED;
}
DECLARE_QOBJ_TYPE(vrf)
/* Allow VRF with netns as backend */
-#define VRF_BACKEND_VRF_LITE 0
-#define VRF_BACKEND_NETNS 1
+#define VRF_BACKEND_VRF_LITE 0
+#define VRF_BACKEND_NETNS 1
+#define VRF_BACKEND_UNKNOWN 2
extern struct vrf_id_head vrfs_by_id;
extern struct vrf_name_head vrfs_by_name;
static int no_password_check = 0;
/* Integrated configuration file path */
-char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
+static char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
static int do_log_commands = 0;
default:
break;
}
- if (matched)
- XFREE(MTYPE_TMP, matched);
+ XFREE(MTYPE_TMP, matched);
}
static void vty_describe_fold(struct vty *vty, int cmd_width,
}
/* Insert history entry. */
- if (vty->hist[vty->hindex])
- XFREE(MTYPE_VTY_HIST, vty->hist[vty->hindex]);
+ XFREE(MTYPE_VTY_HIST, vty->hist[vty->hindex]);
vty->hist[vty->hindex] = XSTRDUP(MTYPE_VTY_HIST, vty->buf);
/* History index rotation. */
buffer_free(vty->lbuf);
/* Free command history. */
- for (i = 0; i < VTY_MAXHIST; i++)
- if (vty->hist[i])
- XFREE(MTYPE_VTY_HIST, vty->hist[i]);
+ for (i = 0; i < VTY_MAXHIST; i++) {
+ XFREE(MTYPE_VTY_HIST, vty->hist[i]);
+ }
/* Unset vector. */
if (vty->fd != -1)
if (vty->fd == STDIN_FILENO)
was_stdio = true;
- if (vty->buf)
- XFREE(MTYPE_VTY, vty->buf);
+ XFREE(MTYPE_VTY, vty->buf);
if (vty->error) {
vty->error->del = vty_error_delete;
host_config_set(fullpath);
tmp_free_and_out:
- if (tmp)
- XFREE(MTYPE_TMP, tmp);
+ XFREE(MTYPE_TMP, tmp);
return read_success;
}
void vty_terminate(void)
{
- if (vty_cwd)
- XFREE(MTYPE_TMP, vty_cwd);
+ XFREE(MTYPE_TMP, vty_cwd);
if (vtyvec && Vvty_serv_thread) {
vty_reset();
#endif
/* Exported variables */
-extern char integrate_default[];
extern struct vty *vty_exclusive_lock;
/* Prototypes. */
wq->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY;
STAILQ_FOREACH_SAFE (item, &wq->items, wq, titem) {
- assert(item && item->data);
+ assert(item->data);
/* dont run items which are past their allowed retries */
if (item->ran > wq->spec.max_retries) {
struct yang_data *yang_data_new_bool(const char *xpath, bool value)
{
- return yang_data_new(xpath, (value == true) ? "true" : "false");
+ return yang_data_new(xpath, (value) ? "true" : "false");
}
bool yang_dnode_get_bool(const struct lyd_node *dnode, const char *xpath_fmt,
/* Prototype for event manager. */
static void zclient_event(enum event, struct zclient *);
+struct zclient_options zclient_options_default = {.receive_notify = false};
+
struct sockaddr_storage zclient_addr;
socklen_t zclient_addr_len;
/* This file local debug flag. */
-int zclient_debug = 0;
-
-struct zclient_options zclient_options_default = {.receive_notify = false};
+static int zclient_debug;
/* Allocate zclient structure. */
struct zclient *zclient_new(struct thread_master *master,
/* 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],
}
if (zclient_debug)
- zlog_debug("zclient_start is called");
+ zlog_debug("scheduling zclient connection");
zclient_event(ZCLIENT_SCHEDULE, zclient);
}
length -= ZEBRA_HEADER_SIZE;
if (zclient_debug)
- zlog_debug("zclient 0x%p command 0x%x VRF %u\n",
- (void *)zclient, command, vrf_id);
+ zlog_debug("zclient 0x%p command %s VRF %u",
+ (void *)zclient, zserv_command_string(command),
+ vrf_id);
switch (command) {
case ZEBRA_CAPABILITIES:
break;
case ZEBRA_NEXTHOP_UPDATE:
if (zclient_debug)
- zlog_debug("zclient rcvd nexthop update\n");
+ zlog_debug("zclient rcvd nexthop update");
if (zclient->nexthop_update)
(*zclient->nexthop_update)(command, zclient, length,
vrf_id);
break;
case ZEBRA_IMPORT_CHECK_UPDATE:
if (zclient_debug)
- zlog_debug("zclient rcvd import check update\n");
+ zlog_debug("zclient rcvd import check update");
if (zclient->import_check_update)
(*zclient->import_check_update)(command, zclient,
length, vrf_id);
break;
case ZEBRA_FEC_UPDATE:
if (zclient_debug)
- zlog_debug("zclient rcvd fec update\n");
+ zlog_debug("zclient rcvd fec update");
if (zclient->fec_update)
(*zclient->fec_update)(command, zclient, length);
break;
{
struct ifreq ifr;
- strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
+ strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1);
if (ioctl(nhrp_socket_fd, SIOCGIFFLAGS, &ifr))
return -1;
zbuf_init(&zb, buf, sizeof(buf), 0);
while (zbuf_recv(&zb, fd) > 0) {
- while ((n = znl_nlmsg_pull(&zb, &payload)) != 0) {
+ while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) {
debugf(NHRP_DEBUG_KERNEL,
"Netlink: Received msg_type %u, msg_flags %u",
n->nlmsg_type, n->nlmsg_flags);
zbuf_init(&zb, buf, sizeof(buf), 0);
while (zbuf_recv(&zb, fd) > 0) {
- while ((n = znl_nlmsg_pull(&zb, &payload)) != 0) {
+ while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) {
debugf(NHRP_DEBUG_KERNEL,
"Netlink-log: Received msg_type %u, msg_flags %u",
n->nlmsg_type, n->nlmsg_flags);
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;
}
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
- strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
ret = connect(fd, (struct sockaddr *)&addr,
sizeof(addr.sun_family) + strlen(addr.sun_path));
if (IS_AREA_STUB(area)) {
if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
- zlog_debug("Stubbing out area for if %s\n", area->name);
+ zlog_debug("Stubbing out area for if %s", area->name);
OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
} else if (IS_AREA_ENABLED(area)) {
if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
- zlog_debug("Normal area for if %s\n", area->name);
+ zlog_debug("Normal area for if %s", area->name);
OSPF6_OPT_SET(area->options, OSPF6_OPT_E);
ospf6_asbr_send_externals_to_area(area);
}
range->path.u.cost_config = cost;
- zlog_debug("%s: for prefix %s, flag = %x\n", __func__,
+ zlog_debug("%s: for prefix %s, flag = %x", __func__,
argv[idx_ipv6_prefixlen]->arg, range->flag);
if (range->rnode == NULL) {
ospf6_route_add(range, oa->range_table);
for (ALL_LSDB(oa->ospf6->lsdb, lsa)) {
if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
- zlog_debug("%s: Flooding AS-External LSA %s\n",
+ zlog_debug("%s: Flooding AS-External LSA %s",
__func__, lsa->name);
ospf6_flood_area(NULL, lsa, oa);
}
struct ospf6_interface *oi;
unsigned int iobuflen;
- oi = (struct ospf6_interface *)XCALLOC(MTYPE_OSPF6_IF,
- sizeof(struct ospf6_interface));
+ oi = XCALLOC(MTYPE_OSPF6_IF, sizeof(struct ospf6_interface));
oi->area = (struct ospf6_area *)NULL;
oi->neighbor_list = list_new();
lsa_size = ntohs(header->length); /* XXX vulnerable */
/* allocate memory for this LSA */
- new_header = (struct ospf6_lsa_header *)XMALLOC(MTYPE_OSPF6_LSA_HEADER,
- lsa_size);
+ new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, lsa_size);
/* copy LSA from original header */
memcpy(new_header, header, lsa_size);
/* LSA information structure */
/* allocate memory */
- lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA,
- sizeof(struct ospf6_lsa));
+ lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa));
lsa->header = (struct ospf6_lsa_header *)new_header;
struct ospf6_lsa_header *new_header = NULL;
/* allocate memory for this LSA */
- new_header = (struct ospf6_lsa_header *)XMALLOC(
- MTYPE_OSPF6_LSA_HEADER, sizeof(struct ospf6_lsa_header));
+ new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER,
+ sizeof(struct ospf6_lsa_header));
/* copy LSA from original header */
memcpy(new_header, header, sizeof(struct ospf6_lsa_header));
/* LSA information structure */
/* allocate memory */
- lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA,
- sizeof(struct ospf6_lsa));
+ lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa));
lsa->header = (struct ospf6_lsa_header *)new_header;
SET_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY);
struct ospf6_lsdb *lsdb;
lsdb = XCALLOC(MTYPE_OSPF6_LSDB, sizeof(struct ospf6_lsdb));
- if (lsdb == NULL) {
- zlog_warn("Can't malloc lsdb");
- return NULL;
- }
memset(lsdb, 0, sizeof(struct ospf6_lsdb));
lsdb->data = data;
recvnew = XMALLOC(MTYPE_OSPF6_MESSAGE, size);
sendnew = XMALLOC(MTYPE_OSPF6_MESSAGE, size);
- if (recvbuf)
- XFREE(MTYPE_OSPF6_MESSAGE, recvbuf);
- if (sendbuf)
- XFREE(MTYPE_OSPF6_MESSAGE, sendbuf);
+ XFREE(MTYPE_OSPF6_MESSAGE, recvbuf);
+ XFREE(MTYPE_OSPF6_MESSAGE, sendbuf);
recvbuf = recvnew;
sendbuf = sendnew;
iobuflen = size;
struct ospf6_neighbor *on;
char buf[16];
- on = (struct ospf6_neighbor *)XMALLOC(MTYPE_OSPF6_NEIGHBOR,
- sizeof(struct ospf6_neighbor));
-
- memset(on, 0, sizeof(struct ospf6_neighbor));
+ on = XCALLOC(MTYPE_OSPF6_NEIGHBOR, sizeof(struct ospf6_neighbor));
inet_ntop(AF_INET, &router_id, buf, sizeof(buf));
snprintf(on->name, sizeof(on->name), "%s%%%s", buf,
oi->interface->name);
void ospf6_nexthop_delete(struct ospf6_nexthop *nh)
{
- if (nh)
- XFREE(MTYPE_OSPF6_NEXTHOP, nh);
+ XFREE(MTYPE_OSPF6_NEXTHOP, nh);
}
void ospf6_clear_nexthops(struct list *nh_list)
index[1] = on->ospf6_if->instance_id;
index[2] = ntohl(on->router_id);
- smux_trap(ospfv3_variables,
- sizeof ospfv3_variables / sizeof(struct variable),
- ospfv3_trap_oid, sizeof ospfv3_trap_oid / sizeof(oid),
- ospfv3_oid, sizeof ospfv3_oid / sizeof(oid), index, 3,
- ospf6NbrTrapList,
- sizeof ospf6NbrTrapList / sizeof(struct trap_object),
- NBRSTATECHANGE);
+ smux_trap(ospfv3_variables, array_size(ospfv3_variables),
+ ospfv3_trap_oid, array_size(ospfv3_trap_oid), ospfv3_oid,
+ sizeof ospfv3_oid / sizeof(oid), index, 3, ospf6NbrTrapList,
+ array_size(ospf6NbrTrapList), NBRSTATECHANGE);
return 0;
}
index[0] = oi->interface->ifindex;
index[1] = oi->instance_id;
- smux_trap(ospfv3_variables,
- sizeof ospfv3_variables / sizeof(struct variable),
- ospfv3_trap_oid, sizeof ospfv3_trap_oid / sizeof(oid),
- ospfv3_oid, sizeof ospfv3_oid / sizeof(oid), index, 2,
- ospf6IfTrapList,
- sizeof ospf6IfTrapList / sizeof(struct trap_object),
- IFSTATECHANGE);
+ smux_trap(ospfv3_variables, array_size(ospfv3_variables),
+ ospfv3_trap_oid, array_size(ospfv3_trap_oid), ospfv3_oid,
+ sizeof ospfv3_oid / sizeof(oid), index, 2, ospf6IfTrapList,
+ array_size(ospf6IfTrapList), IFSTATECHANGE);
return 0;
}
{
struct ospf6_vertex *v;
- v = (struct ospf6_vertex *)XMALLOC(MTYPE_OSPF6_VERTEX,
- sizeof(struct ospf6_vertex));
+ v = XMALLOC(MTYPE_OSPF6_VERTEX, sizeof(struct ospf6_vertex));
/* type */
if (ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) {
lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
if (lsa == NULL) {
if (IS_OSPF6_DEBUG_SPF(PROCESS))
- zlog_debug("%s: No router LSA for area %s\n", __func__,
+ zlog_debug("%s: No router LSA for area %s", __func__,
oa->name);
return;
}
new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, total_lsa_length);
/* LSA information structure */
- lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA,
- sizeof(struct ospf6_lsa));
+ lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa));
lsa->header = (struct ospf6_lsa_header *)new_header;
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;
olsa = (struct opaque_lsa *)data;
opaquelen = ntohs(data->length) - OSPF_LSA_HEADER_SIZE;
- zlog_debug("apiserver_lsa_print: opaquelen=%d\n", opaquelen);
+ zlog_debug("apiserver_lsa_print: opaquelen=%d", opaquelen);
for (i = 0; i < opaquelen; i++) {
zlog_debug("0x%x ", olsa->mydata[i]);
}
- zlog_debug("\n");
+ zlog_debug(" ");
}
/* -----------------------------------------------------------
void msg_print(struct msg *msg)
{
if (!msg) {
- zlog_debug("msg_print msg=NULL!\n");
+ zlog_debug("msg_print msg=NULL!");
return;
}
/* zlog_warn for debugging */
zlog_warn("ospf_apiserver_del_if");
- zlog_warn("ifp name=%s status=%d index=%d\n", ifp->name, ifp->status,
+ zlog_warn("ifp name=%s status=%d index=%d", ifp->name, ifp->status,
ifp->ifindex);
oi = ospf_apiserver_if_lookup_by_ifp(ifp);
for (i = 0; i < opaquelen; i++) {
zlog_debug("0x%x ", olsa->data[i]);
}
- zlog_debug("\n");
}
return;
}
{
struct external_info *new;
- new = (struct external_info *)XCALLOC(MTYPE_OSPF_EXTERNAL_INFO,
- sizeof(struct external_info));
+ new = XCALLOC(MTYPE_OSPF_EXTERNAL_INFO, sizeof(struct external_info));
new->type = type;
new->instance = instance;
static int ism_loop_ind(struct ospf_interface *oi)
{
- int ret = 0;
-
/* call ism_interface_down. */
/* ret = ism_interface_down (oi); */
- return ret;
+ return 0;
}
/* Interface down event handler. */
oi = nbr->oi;
- /* LS Request packet overflows interface MTU. */
+ /* LS Request packet overflows interface MTU
+ * delta is just number of bytes required for 1 LS Req
+ * ospf_packet_max will return the number of bytes can
+ * be accomodated without ospf header. So length+delta
+ * can be compared to ospf_packet_max
+ * to check if it can fit another lsreq in the same packet.
+ */
+
if (*length + delta > ospf_packet_max(oi))
return 0;
{
struct ospf_lsa *lsa;
uint16_t length = OSPF_LS_REQ_MIN_SIZE;
- unsigned long delta = stream_get_endp(s) + 12;
+ unsigned long delta = 12;
struct route_table *table;
struct route_node *rn;
int i;
assert(lsa->data);
- /* Will it fit? */
- if (length + delta + ntohs(lsa->data->length) > size_noauth)
+ /* Will it fit? Minimum it has to fit atleast one */
+ if ((length + delta + ntohs(lsa->data->length) > size_noauth) &&
+ (count > 0))
break;
/* Keep pointer to LS age. */
{
struct listnode *node, *nnode;
uint16_t length = OSPF_LS_ACK_MIN_SIZE;
- unsigned long delta = stream_get_endp(s) + 24;
+ unsigned long delta = OSPF_LSA_HEADER_SIZE;
struct ospf_lsa *lsa;
for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) {
assert(lsa);
- if (length + delta > ospf_packet_max(oi))
+ /* LS Ack packet overflows interface MTU
+ * delta is just number of bytes required for
+ * 1 LS Ack(1 LS Hdr) ospf_packet_max will return
+ * the number of bytes can be accomodated without
+ * ospf header. So length+delta can be compared
+ * against ospf_packet_max to check if it can fit
+ * another ls header in the same packet.
+ */
+ if ((length + delta) > ospf_packet_max(oi))
break;
stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE);
}
else {
- zlog_debug(" Segment Routing Algorithm TLV:\n");
+ zlog_debug(" Segment Routing Algorithm TLV:");
for (i = 0; i < ntohs(algo->header.length); i++)
switch (algo->value[i]) {
case 0:
- zlog_debug(" Algorithm %d: SPF\n", i);
+ zlog_debug(" Algorithm %d: SPF", i);
break;
case 1:
- zlog_debug(" Algorithm %d: Strict SPF\n", i);
+ zlog_debug(" Algorithm %d: Strict SPF", i);
break;
default:
zlog_debug(
/* Sanity check, if LSA type unknwon
merley skip any LSA */
if ((i < OSPF_MIN_LSA) || (i >= OSPF_MAX_LSA)) {
- zlog_debug("Strange request with LSA type %d\n", i);
+ zlog_debug("Strange request with LSA type %d", i);
return NULL;
}
oid_copy_addr(index, &(on->address.u.prefix4), IN_ADDR_SIZE);
index[IN_ADDR_SIZE] = 0;
- smux_trap(ospf_variables,
- sizeof ospf_variables / sizeof(struct variable),
- ospf_trap_oid, sizeof ospf_trap_oid / sizeof(oid), ospf_oid,
+ smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid,
+ array_size(ospf_trap_oid), ospf_oid,
sizeof ospf_oid / sizeof(oid), index, IN_ADDR_SIZE + 1,
- ospfNbrTrapList,
- sizeof ospfNbrTrapList / sizeof(struct trap_object),
- NBRSTATECHANGE);
+ ospfNbrTrapList, array_size(ospfNbrTrapList), NBRSTATECHANGE);
}
static void ospfTrapVirtNbrStateChange(struct ospf_neighbor *on)
oid_copy_addr(index, &(on->address.u.prefix4), IN_ADDR_SIZE);
index[IN_ADDR_SIZE] = 0;
- smux_trap(ospf_variables,
- sizeof ospf_variables / sizeof(struct variable),
- ospf_trap_oid, sizeof ospf_trap_oid / sizeof(oid), ospf_oid,
+ smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid,
+ array_size(ospf_trap_oid), ospf_oid,
sizeof ospf_oid / sizeof(oid), index, IN_ADDR_SIZE + 1,
- ospfVirtNbrTrapList,
- sizeof ospfVirtNbrTrapList / sizeof(struct trap_object),
+ ospfVirtNbrTrapList, array_size(ospfVirtNbrTrapList),
VIRTNBRSTATECHANGE);
}
oid_copy_addr(index, &(oi->address->u.prefix4), IN_ADDR_SIZE);
index[IN_ADDR_SIZE] = 0;
- smux_trap(ospf_variables,
- sizeof ospf_variables / sizeof(struct variable),
- ospf_trap_oid, sizeof ospf_trap_oid / sizeof(oid), ospf_oid,
+ smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid,
+ array_size(ospf_trap_oid), ospf_oid,
sizeof ospf_oid / sizeof(oid), index, IN_ADDR_SIZE + 1,
- ospfIfTrapList,
- sizeof ospfIfTrapList / sizeof(struct trap_object),
- IFSTATECHANGE);
+ ospfIfTrapList, array_size(ospfIfTrapList), IFSTATECHANGE);
}
static void ospfTrapVirtIfStateChange(struct ospf_interface *oi)
oid_copy_addr(index, &(oi->address->u.prefix4), IN_ADDR_SIZE);
index[IN_ADDR_SIZE] = 0;
- smux_trap(ospf_variables,
- sizeof ospf_variables / sizeof(struct variable),
- ospf_trap_oid, sizeof ospf_trap_oid / sizeof(oid), ospf_oid,
+ smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid,
+ array_size(ospf_trap_oid), ospf_oid,
sizeof ospf_oid / sizeof(oid), index, IN_ADDR_SIZE + 1,
- ospfVirtIfTrapList,
- sizeof ospfVirtIfTrapList / sizeof(struct trap_object),
+ ospfVirtIfTrapList, array_size(ospfVirtIfTrapList),
VIRTIFSTATECHANGE);
}
if (path->nexthop.s_addr == 0)
{
if (IS_DEBUG_OSPF_EVENT)
- zlog_debug (" directly attached to %s\r\n",
+ zlog_debug (" directly attached to %s\r",
ifindex2ifname (path->ifindex), VRF_DEFAULT);
}
else
{
if (IS_DEBUG_OSPF_EVENT)
- zlog_debug (" via %s, %s\r\n",
+ zlog_debug (" via %s, %s\r",
inet_ntoa (path->nexthop),
ifindex2ifname (path->ifindex), VRF_DEFAULT);
}
monotime(&stop_time);
if (IS_DEBUG_OSPF_SR)
- zlog_debug("SR (%s): SPF Processing Time(usecs): %lld\n",
+ zlog_debug("SR (%s): SPF Processing Time(usecs): %lld",
__func__,
(stop_time.tv_sec - start_time.tv_sec) * 1000000LL
+ (stop_time.tv_usec - start_time.tv_usec));
if (ospf->stub_router_startup_time
!= OSPF_STUB_ROUTER_UNCONFIGURED)
json_object_int_add(
- json_vrf, "postStartEnabledMsecs",
- ospf->stub_router_startup_time / 1000);
+ json_vrf, "postStartEnabledSecs",
+ ospf->stub_router_startup_time);
if (ospf->stub_router_shutdown_time
!= OSPF_STUB_ROUTER_UNCONFIGURED)
json_object_int_add(
- json_vrf, "preShutdownEnabledMsecs",
- ospf->stub_router_shutdown_time / 1000);
+ json_vrf, "preShutdownEnabledSecs",
+ ospf->stub_router_shutdown_time);
} else {
vty_out(vty,
" Stub router advertisement is configured\n");
json_object_int_add(json_interface_sub, "cost",
oi->output_cost);
json_object_int_add(
- json_interface_sub, "transmitDelayMsecs",
- 1000 / OSPF_IF_PARAM(oi, transmit_delay));
+ json_interface_sub, "transmitDelaySecs",
+ OSPF_IF_PARAM(oi, transmit_delay));
json_object_string_add(json_interface_sub, "state",
lookup_msg(ospf_ism_state_msg,
oi->state, NULL));
if (OSPF_IF_PARAM(oi, fast_hello) == 0)
json_object_int_add(
json_interface_sub, "timerMsecs",
- 1000 / OSPF_IF_PARAM(oi, v_hello));
+ OSPF_IF_PARAM(oi, v_hello) * 1000);
else
json_object_int_add(
json_interface_sub, "timerMsecs",
1000 / OSPF_IF_PARAM(oi, fast_hello));
json_object_int_add(json_interface_sub,
- "timerDeadMsecs",
- 1000 / OSPF_IF_PARAM(oi, v_wait));
+ "timerDeadSecs",
+ OSPF_IF_PARAM(oi, v_wait));
json_object_int_add(json_interface_sub,
- "timerWaitMsecs",
- 1000 / OSPF_IF_PARAM(oi, v_wait));
+ "timerWaitSecs",
+ OSPF_IF_PARAM(oi, v_wait));
json_object_int_add(
- json_interface_sub, "timerRetransmit",
- 1000 / OSPF_IF_PARAM(oi, retransmit_interval));
+ json_interface_sub, "timerRetransmitSecs",
+ OSPF_IF_PARAM(oi, retransmit_interval));
} else {
vty_out(vty, " Timer intervals configured,");
vty_out(vty, " Hello ");
ospf->external[type] = list_new();
ext_list = ospf->external[type];
- ext = (struct ospf_external *)XCALLOC(MTYPE_OSPF_EXTERNAL,
- sizeof(struct ospf_external));
+ ext = XCALLOC(MTYPE_OSPF_EXTERNAL, sizeof(struct ospf_external));
ext->instance = instance;
EXTERNAL_INFO(ext) = route_table_init();
ospf->redist[type] = list_new();
red_list = ospf->redist[type];
- red = (struct ospf_redist *)XCALLOC(MTYPE_OSPF_REDISTRIBUTE,
- sizeof(struct ospf_redist));
+ red = XCALLOC(MTYPE_OSPF_REDISTRIBUTE, sizeof(struct ospf_redist));
red->instance = instance;
red->dmetric.type = -1;
red->dmetric.value = -1;
static void pbr_map_sequence_delete(struct pbr_map_sequence *pbrms)
{
- if (pbrms->internal_nhg_name)
- XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
+ XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
XFREE(MTYPE_PBR_MAP_SEQNO, pbrms);
}
static void
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
struct nexthop_group nhg,
- enum nexthop_types_t nh_afi);
+ enum nexthop_types_t nh_type);
/*
* Nexthop refcount.
switch (pbrnc1->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
- return true;
+ return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex;
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV4:
return pbrnc1->nexthop->gate.ipv4.s_addr
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
pbr_map_check_nh_group_change(nhgc->name);
+
+ if (nhop->type == NEXTHOP_TYPE_IFINDEX) {
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
+ if (ifp)
+ pbr_nht_nexthop_interface_update(ifp);
+ }
}
void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
struct pbr_nexthop_group_cache *pnhgc;
struct pbr_nexthop_cache pnhc_find = {};
struct pbr_nexthop_cache *pnhc;
- enum nexthop_types_t nh_afi = nhop->type;
+ enum nexthop_types_t nh_type = nhop->type;
/* find pnhgc by name */
strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
if (pnhgc->nhh->count)
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
else
- pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_afi);
+ pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_type);
pbr_map_check_nh_group_change(nhgc->name);
}
* - AFI_MAX on error
*/
static afi_t pbr_nht_which_afi(struct nexthop_group nhg,
- enum nexthop_types_t nh_afi)
+ enum nexthop_types_t nh_type)
{
struct nexthop *nexthop;
afi_t install_afi = AFI_MAX;
bool v6, v4, bh;
+ if (nh_type) {
+ switch (nh_type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ return AFI_IP;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ return AFI_IP6;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_BLACKHOLE:
+ return AFI_MAX;
+ }
+ }
+
v6 = v4 = bh = false;
- if (!nh_afi) {
- for (ALL_NEXTHOPS(nhg, nexthop)) {
- nh_afi = nexthop->type;
+ for (ALL_NEXTHOPS(nhg, nexthop)) {
+ nh_type = nexthop->type;
+
+ switch (nh_type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ v6 = true;
+ install_afi = AFI_IP;
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ v4 = true;
+ install_afi = AFI_IP6;
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ bh = true;
break;
}
}
- switch (nh_afi) {
- case NEXTHOP_TYPE_IFINDEX:
- break;
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- v6 = true;
- install_afi = AFI_IP;
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- v4 = true;
- install_afi = AFI_IP6;
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- bh = true;
+ /* Interface and/or blackhole nexthops only. */
+ if (!v4 && !v6)
install_afi = AFI_MAX;
- break;
- }
if (!bh && v6 && v4)
DEBUGD(&pbr_dbg_nht,
struct nexthop_group nhg)
{
afi_t install_afi;
- enum nexthop_types_t nh_afi = 0;
+ enum nexthop_types_t nh_type = 0;
- install_afi = pbr_nht_which_afi(nhg, nh_afi);
+ install_afi = pbr_nht_which_afi(nhg, nh_type);
route_add(pnhgc, nhg, install_afi);
}
static void
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
struct nexthop_group nhg,
- enum nexthop_types_t nh_afi)
+ enum nexthop_types_t nh_type)
{
afi_t install_afi;
- install_afi = pbr_nht_which_afi(nhg, nh_afi);
+ install_afi = pbr_nht_which_afi(nhg, nh_type);
pnhgc->installed = false;
pnhgc->valid = false;
struct listnode *node;
struct pbr_map_interface *pmi;
struct nexthop *nh;
- enum nexthop_types_t nh_afi = 0;
+ enum nexthop_types_t nh_type = 0;
if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
pnhgc = hash_lookup(pbr_nhg_hash, &find);
nh = pbrms->nhg->nexthop;
- nh_afi = nh->type;
+ nh_type = nh->type;
lup.nexthop = nh;
pnhc = hash_lookup(pnhgc->nhh, &lup);
pnhc->parent = NULL;
hash_release(pnhgc->nhh, pnhc);
pbr_nh_delete(&pnhc);
- pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_afi);
+ pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_type);
hash_release(pbr_nhg_hash, pnhgc);
struct pbr_nht_individual {
struct zapi_route *nhr;
+ struct interface *ifp;
uint32_t valid;
};
hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr);
}
+static void
+pbr_nht_individual_nexthop_interface_update_lookup(struct hash_backet *b,
+ void *data)
+{
+ struct pbr_nexthop_cache *pnhc = b->data;
+ struct pbr_nht_individual *pnhi = data;
+ bool old_valid;
+
+ old_valid = pnhc->valid;
+
+ if (pnhc->nexthop->type == NEXTHOP_TYPE_IFINDEX
+ && pnhc->nexthop->ifindex == pnhi->ifp->ifindex)
+ pnhc->valid = !!if_is_up(pnhi->ifp);
+
+ DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name,
+ old_valid, pnhc->valid);
+
+ if (pnhc->valid)
+ pnhi->valid += 1;
+}
+
+static void pbr_nht_nexthop_interface_update_lookup(struct hash_backet *b,
+ void *data)
+{
+ struct pbr_nexthop_group_cache *pnhgc = b->data;
+ struct pbr_nht_individual pnhi;
+ bool old_valid;
+
+ old_valid = pnhgc->valid;
+
+ pnhi.ifp = data;
+ pnhi.valid = 0;
+ hash_iterate(pnhgc->nhh,
+ pbr_nht_individual_nexthop_interface_update_lookup, &pnhi);
+
+ /*
+ * If any of the specified nexthops are valid we are valid
+ */
+ pnhgc->valid = !!pnhi.valid;
+
+ if (old_valid != pnhgc->valid)
+ pbr_map_check_nh_group_change(pnhgc->name);
+}
+
+void pbr_nht_nexthop_interface_update(struct interface *ifp)
+{
+ hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_update_lookup,
+ ifp);
+}
+
static uint32_t pbr_nhg_hash_key(void *arg)
{
struct pbr_nexthop_group_cache *nhgc =
bool found = false;
for (i = pbr_nhg_low_table; i <= pbr_nhg_high_table; i++) {
- if (nhg_tableid[i] == false) {
+ if (!nhg_tableid[i]) {
found = true;
break;
}
*/
extern void pbr_nht_nexthop_update(struct zapi_route *nhr);
+/*
+ * When we get a callback from zebra about an interface status update.
+ */
+extern void pbr_nht_nexthop_interface_update(struct interface *ifp);
+
extern void pbr_nht_init(void);
#endif
}
DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
- "[no] set nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
+ "[no] set nexthop\
+ <\
+ <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
+ |INTERFACE$intf\
+ >\
+ [nexthop-vrf NAME$name]",
NO_STR
"Set for the PBR-MAP\n"
"Specify one of the nexthops in this map\n"
"v4 Address\n"
"v6 Address\n"
"Interface to use\n"
+ "Interface to use\n"
"If the nexthop is in a different vrf tell us\n"
"The nexthop-vrf Name\n")
{
memset(&nhop, 0, sizeof(nhop));
nhop.vrf_id = vrf->vrf_id;
- /*
- * Make SA happy. CLIPPY is not going to give us a NULL
- * addr.
- */
- assert(addr);
- if (addr->sa.sa_family == AF_INET) {
- nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
- if (intf) {
- nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
- nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
- if (nhop.ifindex == IFINDEX_INTERNAL) {
- vty_out(vty,
- "Specified Intf %s does not exist in vrf: %s\n",
- intf, vrf->name);
- return CMD_WARNING_CONFIG_FAILED;
- }
- } else
- nhop.type = NEXTHOP_TYPE_IPV4;
- } else {
- memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
- if (intf) {
- nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
- nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
- if (nhop.ifindex == IFINDEX_INTERNAL) {
- vty_out(vty,
- "Specified Intf %s does not exist in vrf: %s\n",
- intf, vrf->name);
- return CMD_WARNING_CONFIG_FAILED;
- }
+ if (intf) {
+ nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
+ if (nhop.ifindex == IFINDEX_INTERNAL) {
+ vty_out(vty,
+ "Specified Intf %s does not exist in vrf: %s\n",
+ intf, vrf->name);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ if (addr) {
+ if (addr->sa.sa_family == AF_INET) {
+ nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
+ if (intf)
+ nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ else
+ nhop.type = NEXTHOP_TYPE_IPV4;
} else {
- if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
- vty_out(vty,
- "Specified a v6 LL with no interface, rejecting\n");
- return CMD_WARNING_CONFIG_FAILED;
+ nhop.gate.ipv6 = addr->sin6.sin6_addr;
+ if (intf)
+ nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ else {
+ if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
+ vty_out(vty,
+ "Specified a v6 LL with no interface, rejecting\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ nhop.type = NEXTHOP_TYPE_IPV6;
}
- nhop.type = NEXTHOP_TYPE_IPV6;
}
- }
+ } else
+ nhop.type = NEXTHOP_TYPE_IFINDEX;
if (pbrms->nhg)
nh = nexthop_exists(pbrms->nhg, &nhop);
pbr_map_check(pbrms);
}
+ if (nhop.type == NEXTHOP_TYPE_IFINDEX) {
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
+ if (ifp)
+ pbr_nht_nexthop_interface_update(ifp);
+ }
+
return CMD_SUCCESS;
}
vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
if (pbrms->src)
- vty_out(vty, " match src-ip %s\n",
+ vty_out(vty, " match src-ip %s\n",
prefix2str(pbrms->src, buff, sizeof(buff)));
if (pbrms->dst)
- vty_out(vty, " match dst-ip %s\n",
+ vty_out(vty, " match dst-ip %s\n",
prefix2str(pbrms->dst, buff, sizeof(buff)));
if (pbrms->nhgrp_name)
- vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
+ vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
if (pbrms->nhg) {
- vty_out(vty, " set ");
+ vty_out(vty, " set ");
nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
}
if (!ifp->info)
pbr_if_new(ifp);
+ pbr_nht_nexthop_interface_update(ifp);
+
return 0;
}
DEBUGD(&pbr_dbg_zebra,
"%s: %s is up", __PRETTY_FUNCTION__, ifp->name);
+ pbr_nht_nexthop_interface_update(ifp);
+
return 0;
}
DEBUGD(&pbr_dbg_zebra,
"%s: %s is down", __PRETTY_FUNCTION__, ifp->name);
+ pbr_nht_nexthop_interface_update(ifp);
+
return 0;
}
switch (note) {
case ZAPI_RULE_FAIL_INSTALL:
pbrms->installed &= ~installed;
- DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_FAIL_INSTALL: %lu",
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: Received RULE_FAIL_INSTALL: %" PRIu64,
__PRETTY_FUNCTION__, pbrms->installed);
break;
case ZAPI_RULE_INSTALLED:
pbrms->installed |= installed;
- DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED: %lu",
+ DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED: %" PRIu64,
__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: %lu",
+ DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED: %" PRIu64,
__PRETTY_FUNCTION__, pbrms->installed);
break;
}
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) */
vty_out(vty, "Designated Router\n");
vty_out(vty, "-----------------\n");
vty_out(vty, "Address : %s\n", dr_str);
- vty_out(vty, "Priority : %d(%d)\n",
+ vty_out(vty, "Priority : %u(%d)\n",
pim_ifp->pim_dr_priority,
pim_ifp->pim_dr_num_nondrpri_neighbors);
vty_out(vty, "Uptime : %s\n", dr_uptime);
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];
up->t_join_timer);
/*
- * If we have a J/P timer for the neighbor display that
+ * If the upstream is not dummy and it has a J/P timer for the
+ * neighbor display that
*/
- if (!up->t_join_timer) {
+ if (!up->t_join_timer && up->rpf.source_nexthop.interface) {
struct pim_neighbor *nbr;
nbr = pim_neighbor_find(
json_row = json_object_new_object();
json_object_pim_upstream_add(json_row, up);
json_object_string_add(
- json_row, "inboundInterface",
- up->rpf.source_nexthop.interface->name);
+ json_row, "inboundInterface",
+ up->rpf.source_nexthop.interface
+ ? up->rpf.source_nexthop.interface->name
+ : "Unknown");
/*
* The RPF address we use is slightly different
json_object_object_add(json_group, src_str, json_row);
} else {
vty_out(vty,
- "%-10s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n",
- up->rpf.source_nexthop.interface->name, src_str,
- grp_str, state_str, uptime, join_timer,
+ "%-16s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n",
+ up->rpf.source_nexthop.interface
+ ? up->rpf.source_nexthop.interface->name
+ : "Unknown",
+ src_str, grp_str, state_str, uptime, join_timer,
rs_timer, ka_timer, up->ref_count);
}
}
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();
for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
++oif_vif_index) {
struct interface *ifp_out;
- char oif_uptime[10];
+ char mroute_uptime[10];
int ttl;
ttl = c_oil->oil.mfcc_ttls[oif_vif_index];
ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
pim_time_uptime(
- oif_uptime, sizeof(oif_uptime),
- now - c_oil->oif_creation[oif_vif_index]);
+ mroute_uptime, sizeof(mroute_uptime),
+ now - c_oil->mroute_creation);
found_oif = 1;
if (ifp_out)
oif_vif_index);
json_object_int_add(json_ifp_out, "ttl", ttl);
json_object_string_add(json_ifp_out, "upTime",
- oif_uptime);
+ mroute_uptime);
if (!json_oil) {
json_oil = json_object_new_object();
json_object_object_add(json_source,
}
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);
+ out_ifname, ttl, mroute_uptime);
if (first) {
src_str[0] = '\0';
}
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);
}
return CMD_WARNING;
}
- if (pim_nexthop_lookup(vrf->info, &nexthop, addr, 0)) {
+ if (!pim_nexthop_lookup(vrf->info, &nexthop, addr, 0)) {
vty_out(vty,
"Failure querying RIB nexthop for unicast address %s\n",
addr_str);
switch (pim->spt.switchover) {
case PIM_SPT_IMMEDIATE:
- if (pim->spt.plist)
- XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist);
+ XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist);
pim_upstream_add_lhr_star_pimreg(pim);
break;
case PIM_SPT_INFINITY:
pim_upstream_remove_lhr_star_pimreg(pim, plist);
- if (pim->spt.plist)
- XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist);
+ XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist);
if (plist)
pim->spt.plist =
pim_ifp->pim_dr_priority = strtol(argv[idx_number]->arg, NULL, 10);
if (old_dr_prio != pim_ifp->pim_dr_priority) {
- if (pim_if_dr_election(ifp))
- pim_hello_restart_now(ifp);
+ pim_if_dr_election(ifp);
+ pim_hello_restart_now(ifp);
}
return CMD_SUCCESS;
if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) {
pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
- if (pim_if_dr_election(ifp))
- pim_hello_restart_now(ifp);
+ pim_if_dr_election(ifp);
+ pim_hello_restart_now(ifp);
}
return CMD_SUCCESS;
return CMD_SUCCESS;
}
-#if CONFDATE > 20190402
-CPP_NOTICE("bgpd: time to remove undebug commands")
-#endif
-ALIAS_HIDDEN (no_debug_msdp,
- undebug_msdp_cmd,
- "undebug msdp",
- UNDEBUG_STR DEBUG_MSDP_STR)
-
DEFUN (debug_msdp_events,
debug_msdp_events_cmd,
"debug msdp events",
return CMD_SUCCESS;
}
-#if CONFDATE > 20190402
-CPP_NOTICE("bgpd: time to remove undebug commands")
-#endif
-ALIAS_HIDDEN (no_debug_msdp_events,
- undebug_msdp_events_cmd,
- "undebug msdp events",
- UNDEBUG_STR
- DEBUG_MSDP_STR
- DEBUG_MSDP_EVENTS_STR)
-
DEFUN (debug_msdp_packets,
debug_msdp_packets_cmd,
"debug msdp packets",
return CMD_SUCCESS;
}
-#if CONFDATE > 20190402
-CPP_NOTICE("bgpd: time to remove undebug commands")
-#endif
-ALIAS_HIDDEN (no_debug_msdp_packets,
- undebug_msdp_packets_cmd,
- "undebug msdp packets",
- UNDEBUG_STR
- DEBUG_MSDP_STR
- DEBUG_MSDP_PACKETS_STR)
-
DEFUN (debug_mtrace,
debug_mtrace_cmd,
"debug mtrace",
install_element(ENABLE_NODE, &no_debug_pim_zebra_cmd);
install_element(ENABLE_NODE, &debug_msdp_cmd);
install_element(ENABLE_NODE, &no_debug_msdp_cmd);
- install_element(ENABLE_NODE, &undebug_msdp_cmd);
install_element(ENABLE_NODE, &debug_msdp_events_cmd);
install_element(ENABLE_NODE, &no_debug_msdp_events_cmd);
- install_element(ENABLE_NODE, &undebug_msdp_events_cmd);
install_element(ENABLE_NODE, &debug_msdp_packets_cmd);
install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd);
- install_element(ENABLE_NODE, &undebug_msdp_packets_cmd);
install_element(ENABLE_NODE, &debug_mtrace_cmd);
install_element(ENABLE_NODE, &no_debug_mtrace_cmd);
install_element(CONFIG_NODE, &no_debug_pim_zebra_cmd);
install_element(CONFIG_NODE, &debug_msdp_cmd);
install_element(CONFIG_NODE, &no_debug_msdp_cmd);
- install_element(CONFIG_NODE, &undebug_msdp_cmd);
install_element(CONFIG_NODE, &debug_msdp_events_cmd);
install_element(CONFIG_NODE, &no_debug_msdp_events_cmd);
- install_element(CONFIG_NODE, &undebug_msdp_events_cmd);
install_element(CONFIG_NODE, &debug_msdp_packets_cmd);
install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd);
- install_element(CONFIG_NODE, &undebug_msdp_packets_cmd);
install_element(CONFIG_NODE, &debug_mtrace_cmd);
install_element(CONFIG_NODE, &no_debug_mtrace_cmd);
list_delete(&pim_ifp->upstream_switch_list);
list_delete(&pim_ifp->sec_addr_list);
- if (pim_ifp->boundary_oil_plist)
- XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
+ XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) {
ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
if (!ch && !(source_flags & PIM_ENCODE_RPT_BIT)) {
if (PIM_DEBUG_TRACE)
zlog_debug(
- "%s: Received prune with no relevant ifchannel %s(%s) state: %d",
+ "%s: Received prune with no relevant ifchannel %s%s state: %d",
__PRETTY_FUNCTION__, ifp->name,
pim_str_sg_dump(sg), source_flags);
return;
struct pim_nexthop nexthop;
struct interface *ifp_in;
struct in_addr nh_addr;
- int ret;
char nexthop_str[INET_ADDRSTRLEN];
nh_addr.s_addr = 0;
memset(&nexthop, 0, sizeof(nexthop));
- ret = pim_nexthop_lookup(pim, &nexthop, mtracep->src_addr, 1);
-
- if (ret != 0) {
+ if (!pim_nexthop_lookup(pim, &nexthop, mtracep->src_addr, 1)) {
if (PIM_DEBUG_MTRACE)
zlog_debug("mtrace not found neighbor");
return false;
if (!up)
return false;
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return false;
+ }
+
ifp_in = up->rpf.source_nexthop.interface;
nh_addr = up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4;
total = htonl(MTRACE_UNKNOWN_COUNT);
if (interface == NULL) {
memset(&nexthop, 0, sizeof(nexthop));
- ret = pim_nexthop_lookup(pim, &nexthop, ip_hdr->ip_dst, 0);
-
- if (ret != 0) {
+ if (!pim_nexthop_lookup(pim, &nexthop, ip_hdr->ip_dst, 0)) {
close(fd);
if (PIM_DEBUG_MTRACE)
zlog_warn(
struct igmp_mtrace *mtracep, size_t mtrace_len)
{
struct pim_nexthop nexthop;
- int ret;
mtracep->type = PIM_IGMP_MTRACE_RESPONSE;
} else {
memset(&nexthop, 0, sizeof(nexthop));
/* TODO: should use unicast rib lookup */
- ret = pim_nexthop_lookup(pim, &nexthop, mtracep->rsp_addr, 1);
-
- if (ret != 0) {
+ if (!pim_nexthop_lookup(pim, &nexthop, mtracep->rsp_addr, 1)) {
if (PIM_DEBUG_MTRACE)
zlog_warn(
"Dropped response qid=%ud, no route to "
size_t packet_size = 0;
size_t group_size = 0;
- on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface,
- rpf->rpf_addr.u.prefix4);
-
if (rpf->source_nexthop.interface)
pim_ifp = rpf->source_nexthop.interface->info;
else {
return -1;
}
+ on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface,
+ rpf->rpf_addr.u.prefix4);
+
if (!pim_ifp) {
zlog_warn("%s: multicast not enabled on interface %s",
__PRETTY_FUNCTION__,
{
#ifdef PIM_JP_AGG_DEBUG
struct interface *ifp;
- struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info;
- struct pim_instance *pim = pim_ifp->pim;
+ struct pim_interface *pim_ifp;
+ struct pim_instance *pim;
+
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
+ pim_ifp = up->rpf.source_nexthop.interface->info;
+ pim = pim_ifp->pim;
FOR_ALL_INTERFACES (pim->vrf, ifp) {
pim_ifp = ifp->info;
.vty_group = VTY_GROUP,
#endif
.caps_p = _caps_p,
- .cap_num_p = sizeof(_caps_p) / sizeof(_caps_p[0]),
+ .cap_num_p = array_size(_caps_p),
.cap_num_i = 0};
static const struct frr_yang_module_info *pimd_yang_modules[] = {
up->channel_oil->cc.pktcnt++;
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
// resolve mfcc_parent prior to mroute_add in channel_add_oif
- if (up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
+ if (up->rpf.source_nexthop.interface &&
+ up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
int vif_index = 0;
vif_index = pim_if_find_vifindex_by_ifindex(
pim_ifp->pim,
return 0;
}
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return 0;
+ }
+
pim_ifp = up->rpf.source_nexthop.interface->info;
rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
// No if channel, but upstream we are at the RP.
if (pim_nexthop_lookup(pim_ifp->pim, &source,
- up->upstream_register, 0)
- == 0) {
+ up->upstream_register, 0)) {
pim_register_stop_send(source.interface, &sg,
pim_ifp->primary_address,
up->upstream_register);
} else {
if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
if (pim_nexthop_lookup(pim_ifp->pim, &source,
- up->upstream_register, 0)
- == 0)
+ up->upstream_register,
+ 0))
pim_register_stop_send(
source.interface, &sg,
pim_ifp->primary_address,
}
c_oil->installed = 1;
+ c_oil->mroute_creation = pim_time_monotonic_sec();
+
return 0;
}
sg.grp = c_oil->oil.mfcc_mcastgrp;
if (PIM_DEBUG_MROUTE)
zlog_debug(
- "Channel(%s) is not installed no need to collect data from kernel",
+ "Channel%s is not installed no need to collect data from kernel",
pim_str_sg_dump(&sg));
}
return;
sg.grp = c_oil->oil.mfcc_mcastgrp;
zlog_warn(
- "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s): errno=%d: %s",
+ "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s",
(unsigned long)SIOCGETSGCNT,
pim_str_sg_dump(&sg), errno,
safe_strerror(errno));
if (PIM_DEBUG_MSDP_EVENTS) {
zlog_debug("MSDP mesh-group %s deleted", mg->mesh_group_name);
}
- if (mg->mesh_group_name)
- XFREE(MTYPE_PIM_MSDP_MG_NAME, mg->mesh_group_name);
+ XFREE(MTYPE_PIM_MSDP_MG_NAME, mg->mesh_group_name);
if (mg->mbr_list)
list_delete(&mg->mbr_list);
Upon PIM neighbor UP, iterate all RPs and update
nexthop cache with this neighbor.
*/
- pim_resolve_rp_nh(pim_ifp->pim);
+ pim_resolve_rp_nh(pim_ifp->pim, neigh);
pim_rp_setup(pim_ifp->pim);
#include "pim_jp_agg.h"
#include "pim_zebra.h"
#include "pim_zlookup.h"
+#include "pim_rp.h"
/**
* pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
struct pim_nexthop_cache *pnc = NULL;
struct pim_nexthop_cache lookup;
struct zclient *zclient = NULL;
+ struct listnode *upnode = NULL;
+ struct pim_upstream *upstream = NULL;
zclient = pim_zebra_zclient_get();
lookup.rpf.rpf_addr = *addr;
pnc = hash_lookup(pim->rpf_hash, &lookup);
if (pnc) {
- if (rp)
+ if (rp) {
+ /* Release the (*, G)upstream from pnc->upstream_hash,
+ * whose Group belongs to the RP getting deleted
+ */
+ for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
+ upstream)) {
+ struct prefix grp;
+ struct rp_info *trp_info;
+
+ if (upstream->sg.src.s_addr != INADDR_ANY)
+ continue;
+
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = upstream->sg.grp;
+
+ trp_info = pim_rp_find_match_group(pim, &grp);
+ if (trp_info == rp)
+ hash_release(pnc->upstream_hash,
+ upstream);
+ }
listnode_delete(pnc->rp_list, rp);
+ }
+
if (up)
hash_release(pnc->upstream_hash, up);
}
}
+void pim_rp_nexthop_del(struct rp_info *rp_info)
+{
+ rp_info->rp.source_nexthop.interface = NULL;
+ rp_info->rp.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
+ PIM_NET_INADDR_ANY;
+ rp_info->rp.source_nexthop.mrib_metric_preference =
+ router->infinite_assert_metric.metric_preference;
+ rp_info->rp.source_nexthop.mrib_route_metric =
+ router->infinite_assert_metric.route_metric;
+}
+
/* Update RP nexthop info based on Nexthop update received from Zebra.*/
static void pim_update_rp_nh(struct pim_instance *pim,
struct pim_nexthop_cache *pnc)
continue;
// Compute PIM RPF using cached nexthop
- pim_ecmp_nexthop_search(pim, pnc, &rp_info->rp.source_nexthop,
- &rp_info->rp.rpf_addr, &rp_info->group,
- 1);
- }
-}
-
-/* This API is used to traverse nexthop cache of RPF addr
- of upstream entry whose IPv4 nexthop address is in
- unresolved state and due to event like pim neighbor
- UP event if it can be resolved.
-*/
-void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p)
-{
- struct nexthop *nh_node = NULL;
- struct pim_nexthop_cache pnc;
- struct pim_neighbor *nbr = NULL;
-
- memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
- if (!pim_find_or_track_nexthop(pim, nht_p, NULL, NULL, &pnc))
- return;
-
- for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
- if (nh_node->gate.ipv4.s_addr != 0)
- continue;
-
- struct interface *ifp1 =
- if_lookup_by_index(nh_node->ifindex, pim->vrf_id);
- nbr = pim_neighbor_find_if(ifp1);
- if (!nbr)
- continue;
-
- nh_node->gate.ipv4 = nbr->source_addr;
- if (PIM_DEBUG_PIM_NHT) {
- char str[PREFIX_STRLEN];
- char str1[INET_ADDRSTRLEN];
- pim_inet4_dump("<nht_nbr?>", nbr->source_addr, str1,
- sizeof(str1));
- pim_addr_dump("<nht_addr?>", nht_p, str, sizeof(str));
- zlog_debug(
- "%s: addr %s new nexthop addr %s interface %s",
- __PRETTY_FUNCTION__, str, str1, ifp1->name);
- }
+ if (!pim_ecmp_nexthop_search(pim, pnc,
+ &rp_info->rp.source_nexthop,
+ &rp_info->rp.rpf_addr, &rp_info->group,
+ 1))
+ pim_rp_nexthop_del(rp_info);
}
}
old.source_nexthop.interface = up->rpf.source_nexthop.interface;
rpf_result = pim_rpf_update(pim, up, &old, 0);
if (rpf_result == PIM_RPF_FAILURE) {
- pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__);
+ pim_upstream_rpf_clear(pim, up);
return HASHWALK_CONTINUE;
}
/* update kernel multicast forwarding cache (MFC) */
- if (up->channel_oil) {
+ if (up->rpf.source_nexthop.interface) {
ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex;
vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
if (PIM_DEBUG_PIM_NHT) {
zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s",
- __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
- old.source_nexthop.interface->name,
- up->rpf.source_nexthop.interface->name);
+ __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
+ old.source_nexthop.interface
+ ? old.source_nexthop.interface->name : "Unknwon",
+ up->rpf.source_nexthop.interface->name);
}
return HASHWALK_CONTINUE;
struct prefix *grp, int neighbor_needed);
void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
struct pim_nexthop_cache *pnc, int command);
-void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p);
int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
struct prefix *src, struct prefix *grp);
+void pim_rp_nexthop_del(struct rp_info *rp_info);
#endif
return c_oil;
}
- ifp = pim_if_find_by_vif_index(pim, input_vif_index);
- if (!ifp) {
- /* warning only */
- zlog_warn(
- "%s: (S,G)=%s could not find input interface for input_vif_index=%d",
- __PRETTY_FUNCTION__, pim_str_sg_dump(sg),
- input_vif_index);
+ if (input_vif_index != MAXVIFS) {
+ ifp = pim_if_find_by_vif_index(pim, input_vif_index);
+ if (!ifp) {
+ /* warning only */
+ zlog_warn(
+ "%s: (S,G)=%s could not find input interface for input_vif_index=%d",
+ __PRETTY_FUNCTION__, pim_str_sg_dump(sg),
+ input_vif_index);
+ }
}
c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] =
PIM_MROUTE_MIN_TTL;
- if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
- if (PIM_DEBUG_MROUTE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>",
- channel_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- pim_inet4_dump("<source?>",
- channel_oil->oil.mfcc_origin, source_str,
- sizeof(source_str));
- zlog_debug(
- "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
- __FILE__, __PRETTY_FUNCTION__, oif->name,
- pim_ifp->mroute_vif_index, source_str,
- group_str);
- }
+ /* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not
+ * valid to get installed in kernel.
+ */
+ if (channel_oil->oil.mfcc_parent != MAXVIFS) {
+ if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
+ if (PIM_DEBUG_MROUTE) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>",
+ channel_oil->oil.mfcc_mcastgrp,
+ group_str, sizeof(group_str));
+ pim_inet4_dump("<source?>",
+ channel_oil->oil.mfcc_origin, source_str,
+ sizeof(source_str));
+ zlog_debug(
+ "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
+ __FILE__, __PRETTY_FUNCTION__, oif->name,
+ pim_ifp->mroute_vif_index, source_str,
+ group_str);
+ }
- channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
- return -5;
+ channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]
+ = old_ttl;
+ return -5;
+ }
}
channel_oil->oif_creation[pim_ifp->mroute_vif_index] =
Each channel_oil.oil is used to control an (S,G) entry in the Kernel
Multicast Forwarding Cache.
+
+ There is a case when we create a channel_oil but don't install in the kernel
+
+ Case where (S, G) entry not installed in the kernel:
+ FRR receives IGMP/PIM (*, G) join and RP is not configured or
+ not-reachable, then create a channel_oil for the group G with the incoming
+ interface(channel_oil.oil.mfcc_parent) as invalid i.e "MAXVIF" and populate
+ the outgoing interface where join is received. Keep this entry in the stack,
+ but don't install in the kernel(channel_oil.installed = 0).
+
+ Case where (S, G) entry installed in the kernel:
+ When RP is configured and is reachable for the group G, and receiving a
+ join if channel_oil is already present then populate the incoming interface
+ and install the entry in the kernel, if channel_oil not present, then create
+ a new_channel oil(channel_oil.installed = 1).
+
+ is_valid: indicate if this entry is valid to get installed in kernel.
+ installed: indicate if this entry is installed in the kernel.
+
*/
struct channel_oil {
uint32_t oif_flags[MAXVIFS];
struct channel_counts cc;
struct pim_upstream *up;
+ time_t mroute_creation;
};
extern struct list *pim_channel_oil_list;
pinfo = (struct pim_interface *)ifp->info;
if (!pinfo) {
if (PIM_DEBUG_PIM_TRACE)
- zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__);
+ zlog_debug("%s: No pinfo!", __PRETTY_FUNCTION__);
return;
}
if (pim_msg_send(pinfo->pim_sock_fd, src, originator, buffer,
#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
- if (!pim_rp_check_is_my_ip_address(pim_ifp->pim, ip_hdr->ip_dst,
- dest_addr)) {
+ if (!pim_rp_check_is_my_ip_address(pim_ifp->pim, dest_addr)) {
if (PIM_DEBUG_PIM_REG) {
char dest[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", dest_addr, dest, sizeof(dest));
zlog_debug(
- "%s: Received Register message for %s that I do not own",
+ "%s: Received Register message for destination address: %s that I do not own",
__func__, dest);
}
return 0;
char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
- zlog_debug(
- "Received Register message(%s) from %s on %s, rp: %d",
- pim_str_sg_dump(&sg), src_str, ifp->name, i_am_rp);
+ zlog_debug("Received Register message%s from %s on %s, rp: %d",
+ pim_str_sg_dump(&sg), src_str, ifp->name, i_am_rp);
}
if (i_am_rp
#include "pim_iface.h"
#include "pim_msdp.h"
#include "pim_nht.h"
-
+#include "pim_mroute.h"
+#include "pim_oil.h"
+#include "pim_zebra.h"
/* Cleanup pim->rpf_hash each node data */
void pim_rp_list_hash_clean(void *data)
static void pim_rp_info_free(struct rp_info *rp_info)
{
- if (rp_info->plist)
- XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
+ XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
XFREE(MTYPE_PIM_RP, rp_info);
}
/*
* Given a group, return the rp_info for that group
*/
-static struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
+struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
const struct prefix *group)
{
struct listnode *node;
}
}
+void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up)
+{
+ struct pim_rpf old_rpf;
+ enum pim_rpf_result rpf_result;
+ struct in_addr old_upstream_addr;
+ struct in_addr new_upstream_addr;
+ struct prefix nht_p;
+
+ old_upstream_addr = up->upstream_addr;
+ pim_rp_set_upstream_addr(pim, &new_upstream_addr, up->sg.src,
+ up->sg.grp);
+
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: pim upstream update for old upstream %s",
+ __PRETTY_FUNCTION__,
+ inet_ntoa(old_upstream_addr));
+
+ if (old_upstream_addr.s_addr == new_upstream_addr.s_addr)
+ return;
+
+ /* Lets consider a case, where a PIM upstream has a better RP as a
+ * result of a new RP configuration with more precise group range.
+ * This upstream has to be added to the upstream hash of new RP's
+ * NHT(pnc) and has to be removed from old RP's NHT upstream hash
+ */
+ if (old_upstream_addr.s_addr != INADDR_ANY) {
+ /* Deregister addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = old_upstream_addr;
+ if (PIM_DEBUG_TRACE) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&nht_p, buf, sizeof(buf));
+ zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
+ __PRETTY_FUNCTION__, up->sg_str, buf);
+ }
+ pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
+ }
+
+ /* Update the upstream address */
+ up->upstream_addr = new_upstream_addr;
+
+ old_rpf.source_nexthop.interface = up->rpf.source_nexthop.interface;
+
+ rpf_result = pim_rpf_update(pim, up, &old_rpf, 1);
+ if (rpf_result == PIM_RPF_FAILURE)
+ pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__);
+
+ /* update kernel multicast forwarding cache (MFC) */
+ if (up->rpf.source_nexthop.interface && up->channel_oil) {
+ ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex;
+ int vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
+ /* Pass Current selected NH vif index to mroute download */
+ if (vif_index)
+ pim_scan_individual_oil(up->channel_oil, vif_index);
+ else {
+ if (PIM_DEBUG_PIM_NHT)
+ zlog_debug(
+ "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
+ __PRETTY_FUNCTION__, up->sg_str,
+ up->rpf.source_nexthop.interface->name);
+ }
+ }
+
+ if (rpf_result == PIM_RPF_CHANGED)
+ pim_zebra_upstream_rpf_changed(pim, up, &old_rpf);
+
+ pim_zebra_update_all_interfaces(pim);
+}
+
int pim_rp_new(struct pim_instance *pim, const char *rp,
const char *group_range, const char *plist)
{
struct prefix temp;
struct pim_nexthop_cache pnc;
struct route_node *rn;
+ struct pim_upstream *up;
+ struct listnode *upnode;
rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
"%s: NHT Register rp_all addr %s grp %s ",
__PRETTY_FUNCTION__, buf, buf1);
}
+
+ for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
+ up)) {
+ /* Find (*, G) upstream whose RP is not
+ * configured yet
+ */
+ if ((up->upstream_addr.s_addr == INADDR_ANY)
+ && (up->sg.src.s_addr == INADDR_ANY)) {
+ struct prefix grp;
+ struct rp_info *trp_info;
+
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ trp_info = pim_rp_find_match_group(pim,
+ &grp);
+ if (trp_info == rp_all)
+ pim_upstream_update(pim, up);
+ }
+ }
+
memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all,
&pnc)) {
rn->lock);
}
+ for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ if (up->sg.src.s_addr == INADDR_ANY) {
+ struct prefix grp;
+ struct rp_info *trp_info;
+
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ trp_info = pim_rp_find_match_group(pim, &grp);
+
+ if (trp_info == rp_info)
+ pim_upstream_update(pim, up);
+ }
+ }
+
/* Register addr with Zebra NHT */
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
struct prefix nht_p;
struct route_node *rn;
bool was_plist = false;
+ struct rp_info *trp_info;
+ struct pim_upstream *up;
+ struct listnode *upnode;
if (group_range == NULL)
result = str2prefix("224.0.0.0/4", &group);
rp_all = pim_rp_find_match_group(pim, &g_all);
if (rp_all == rp_info) {
+ for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ /* Find the upstream (*, G) whose upstream address is
+ * same as the deleted RP
+ */
+ if ((up->upstream_addr.s_addr == rp_addr.s_addr) &&
+ (up->sg.src.s_addr == INADDR_ANY)) {
+ struct prefix grp;
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ trp_info = pim_rp_find_match_group(pim, &grp);
+ if (trp_info == rp_all) {
+ pim_upstream_rpf_clear(pim, up);
+ up->upstream_addr.s_addr = INADDR_ANY;
+ }
+ }
+ }
rp_all->rp.rpf_addr.family = AF_INET;
rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
rp_all->i_am_rp = 0;
pim_rp_refresh_group_to_rp_mapping(pim);
+ for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ /* Find the upstream (*, G) whose upstream address is same as
+ * the deleted RP
+ */
+ if ((up->upstream_addr.s_addr == rp_addr.s_addr) &&
+ (up->sg.src.s_addr == INADDR_ANY)) {
+ struct prefix grp;
+
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+
+ trp_info = pim_rp_find_match_group(pim, &grp);
+
+ /* RP not found for the group grp */
+ if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) {
+ pim_upstream_rpf_clear(pim, up);
+ pim_rp_set_upstream_addr(pim,
+ &up->upstream_addr,
+ up->sg.src, up->sg.grp);
+ }
+
+ /* RP found for the group grp */
+ else
+ pim_upstream_update(pim, up);
+ }
+ }
+
XFREE(MTYPE_PIM_RP, rp_info);
return PIM_SUCCESS;
}
else {
if (PIM_DEBUG_PIM_NHT_RP) {
char buf[PREFIX2STR_BUFFER];
+
prefix2str(&nht_p, buf, sizeof(buf));
zlog_debug(
"%s: NHT Local Nexthop not found for RP %s ",
* the rp configured and the source address
*
* If we have don't have a RP configured and the source address is *
- * then return failure.
+ * then set the upstream addr as INADDR_ANY and return failure.
*
*/
int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up,
if (PIM_DEBUG_PIM_NHT_RP)
zlog_debug("%s: Received a (*,G) with no RP configured",
__PRETTY_FUNCTION__);
+ up->s_addr = INADDR_ANY;
return 0;
}
return count;
}
-int pim_rp_check_is_my_ip_address(struct pim_instance *pim,
- struct in_addr group,
- struct in_addr dest_addr)
+bool pim_rp_check_is_my_ip_address(struct pim_instance *pim,
+ struct in_addr dest_addr)
{
- struct rp_info *rp_info;
- struct prefix g;
-
- memset(&g, 0, sizeof(g));
- g.family = AF_INET;
- g.prefixlen = 32;
- g.u.prefix4 = group;
-
- rp_info = pim_rp_find_match_group(pim, &g);
- /*
- * See if we can short-cut some?
- * This might not make sense if we ever leave a static RP
- * type of configuration.
- * Note - Premature optimization might bite our patooeys' here.
- */
- if (I_am_RP(pim, group)) {
- if (dest_addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
- return 1;
- }
-
if (if_lookup_exact_address(&dest_addr, AF_INET, pim->vrf_id))
- return 1;
+ return true;
- return 0;
+ return false;
}
void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj)
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");
}
}
-void pim_resolve_rp_nh(struct pim_instance *pim)
+void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr)
{
struct listnode *node = NULL;
struct rp_info *rp_info = NULL;
struct nexthop *nh_node = NULL;
struct prefix nht_p;
struct pim_nexthop_cache pnc;
- struct pim_neighbor *nbr = NULL;
for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
struct interface *ifp1 = if_lookup_by_index(
nh_node->ifindex, pim->vrf_id);
- nbr = pim_neighbor_find_if(ifp1);
- if (!nbr)
+
+ if (nbr->interface != ifp1)
continue;
nh_node->gate.ipv4 = nbr->source_addr;
void pim_rp_check_on_if_add(struct pim_interface *pim_ifp);
void pim_i_am_rp_re_evaluate(struct pim_instance *pim);
-int pim_rp_check_is_my_ip_address(struct pim_instance *pim,
- struct in_addr group,
- struct in_addr dest_addr);
+bool pim_rp_check_is_my_ip_address(struct pim_instance *pim,
+ struct in_addr dest_addr);
int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up,
struct in_addr source, struct in_addr group);
void pim_rp_show_information(struct pim_instance *pim, struct vty *vty,
bool uj);
-void pim_resolve_rp_nh(struct pim_instance *pim);
+void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr);
int pim_rp_list_cmp(void *v1, void *v2);
+struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
+ const struct prefix *group);
+void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up);
#endif
pim->last_route_change_time);
}
-int pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
- struct in_addr addr, int neighbor_needed)
+bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
+ struct in_addr addr, int neighbor_needed)
{
struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
struct pim_neighbor *nbr = NULL;
* it will never work
*/
if (addr.s_addr == INADDR_NONE)
- return -1;
+ return false;
if ((nexthop->last_lookup.s_addr == addr.s_addr)
&& (nexthop->last_lookup_time > pim->last_route_change_time)) {
pim->last_route_change_time, nexthop_str);
}
pim->nexthop_lookups_avoided++;
- return 0;
+ return true;
} else {
if (PIM_DEBUG_TRACE) {
char addr_str[INET_ADDRSTRLEN];
zlog_warn(
"%s %s: could not find nexthop ifindex for address %s",
__FILE__, __PRETTY_FUNCTION__, addr_str);
- return -1;
+ return false;
}
while (!found && (i < num_ifindex)) {
nexthop->last_lookup = addr;
nexthop->last_lookup_time = pim_time_monotonic_usec();
nexthop->nbr = nbr;
- return 0;
+ return true;
} else
- return -1;
+ return false;
}
static int nexthop_mismatch(const struct pim_nexthop *nh1,
struct prefix src, grp;
bool neigh_needed = true;
+ if (up->upstream_addr.s_addr == INADDR_ANY) {
+ zlog_debug("%s: RP is not configured yet for %s",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return PIM_RPF_OK;
+ }
+
saved.source_nexthop = rpf->source_nexthop;
saved.rpf_addr = rpf->rpf_addr;
return PIM_RPF_OK;
}
+/*
+ * In the case of RP deletion and RP unreachablity,
+ * uninstall the mroute in the kernel and clear the
+ * rpf information in the pim upstream and pim channel
+ * oil data structure.
+ */
+void pim_upstream_rpf_clear(struct pim_instance *pim,
+ struct pim_upstream *up)
+{
+ if (up->rpf.source_nexthop.interface) {
+ if (up->channel_oil) {
+ up->channel_oil->oil.mfcc_parent = MAXVIFS;
+ pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__);
+
+ }
+ pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
+ up->rpf.source_nexthop.interface = NULL;
+ up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
+ PIM_NET_INADDR_ANY;
+ up->rpf.source_nexthop.mrib_metric_preference =
+ router->infinite_assert_metric.metric_preference;
+ up->rpf.source_nexthop.mrib_route_metric =
+ router->infinite_assert_metric.route_metric;
+ up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
+ }
+}
+
/*
RFC 4601: 4.1.6. State Summarization Macros
unsigned int pim_rpf_hash_key(void *arg);
bool pim_rpf_equal(const void *arg1, const void *arg2);
-int pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
- struct in_addr addr, int neighbor_needed);
+bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
+ struct in_addr addr, int neighbor_needed);
enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
struct pim_upstream *up, struct pim_rpf *old,
uint8_t is_new);
-
+void pim_upstream_rpf_clear(struct pim_instance *pim,
+ struct pim_upstream *up);
int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf);
int pim_rpf_addr_is_inaddr_any(struct pim_rpf *rpf);
if (!ssm)
return;
- if (ssm->plist_name)
- XFREE(MTYPE_PIM_FILTER_NAME, ssm->plist_name);
+ XFREE(MTYPE_PIM_FILTER_NAME, ssm->plist_name);
XFREE(MTYPE_PIM_SSM_INFO, ssm);
}
pim_msdp_up_del(pim, &up->sg);
}
- /* Deregister addr with Zebra NHT */
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = up->upstream_addr;
- if (PIM_DEBUG_TRACE) {
- char buf[PREFIX2STR_BUFFER];
- prefix2str(&nht_p, buf, sizeof(buf));
- zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
- __PRETTY_FUNCTION__, up->sg_str, buf);
+ /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT
+ * and assign up->upstream_addr as INADDR_ANY.
+ * So before de-registering the upstream address, check if is not equal
+ * to INADDR_ANY. This is done in order to avoid de-registering for
+ * 255.255.255.255 which is maintained for some reason..
+ */
+ if (up->upstream_addr.s_addr != INADDR_ANY) {
+ /* Deregister addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = up->upstream_addr;
+ if (PIM_DEBUG_TRACE) {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str(&nht_p, buf, sizeof(buf));
+ zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
+ __PRETTY_FUNCTION__, up->sg_str, buf);
+ }
+ pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
}
- pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
XFREE(MTYPE_PIM_UPSTREAM, up);
void pim_upstream_send_join(struct pim_upstream *up)
{
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
if (PIM_DEBUG_TRACE) {
char rpf_str[PREFIX_STRLEN];
pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str,
up = THREAD_ARG(t);
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return 0;
+ }
+
/*
* In the case of a HFR we will not ahve anyone to send this to.
*/
static void join_timer_stop(struct pim_upstream *up)
{
- struct pim_neighbor *nbr;
+ struct pim_neighbor *nbr = NULL;
THREAD_OFF(up->t_join_timer);
- nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
- up->rpf.rpf_addr.u.prefix4);
+ if (up->rpf.source_nexthop.interface)
+ nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
+ up->rpf.rpf_addr.u.prefix4);
if (nbr)
pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
long t_joinsuppress_msec;
long join_timer_remain_msec;
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
t_joinsuppress_msec =
MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
1000 * holdtime);
long join_timer_remain_msec;
int t_override_msec;
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
t_override_msec =
pim_if_t_override_msec(up->rpf.source_nexthop.interface);
{
enum pim_upstream_state old_state = up->join_state;
+ if (up->upstream_addr.s_addr == INADDR_ANY) {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug("%s: RPF not configured for %s",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug("%s: RP not reachable for %s",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
if (PIM_DEBUG_PIM_EVENTS) {
zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
__PRETTY_FUNCTION__, up->sg_str,
&& !I_am_RP(pim, up->sg.grp)) {
if (PIM_DEBUG_PIM_TRACE_DETAIL)
zlog_debug(
- "%s: *,G IIF %s S,G IIF %s ",
- __PRETTY_FUNCTION__,
- up->parent->rpf.source_nexthop
- .interface->name,
- up->rpf.source_nexthop.interface->name);
+ "%s: *,G IIF %s S,G IIF %s ",
+ __PRETTY_FUNCTION__,
+ up->parent->rpf.source_nexthop.interface ?
+ up->parent->rpf.source_nexthop.interface->name
+ : "Unknown",
+ up->rpf.source_nexthop.interface ?
+ up->rpf.source_nexthop.interface->name :
+ "Unknown");
pim_jp_agg_single_upstream_send(&up->parent->rpf,
up->parent,
1 /* (W,G) Join */);
ch->upstream = up;
up = hash_get(pim->upstream_hash, up, hash_alloc_intern);
+ /* Set up->upstream_addr as INADDR_ANY, if RP is not
+ * configured and retain the upstream data structure
+ */
if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
sg->grp)) {
if (PIM_DEBUG_TRACE)
zlog_debug("%s: Received a (*,G) with no RP configured",
__PRETTY_FUNCTION__);
-
- hash_release(pim->upstream_hash, up);
- XFREE(MTYPE_PIM_UPSTREAM, up);
- return NULL;
}
up->parent = pim_upstream_find_parent(pim, up);
if (up->sg.src.s_addr != INADDR_ANY)
wheel_add_item(pim->upstream_sg_wheel, up);
- rpf_result = pim_rpf_update(pim, up, NULL, 1);
- if (rpf_result == PIM_RPF_FAILURE) {
- struct prefix nht_p;
-
- if (PIM_DEBUG_TRACE)
- zlog_debug(
- "%s: Attempting to create upstream(%s), Unable to RPF for source",
- __PRETTY_FUNCTION__, up->sg_str);
-
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = up->upstream_addr;
- pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
+ if (up->upstream_addr.s_addr == INADDR_ANY)
+ /* Create a dummmy channel oil with incoming ineterface MAXVIFS,
+ * since RP is not configured
+ */
+ up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS);
- if (up->parent) {
- listnode_delete(up->parent->sources, up);
- up->parent = NULL;
+ else {
+ rpf_result = pim_rpf_update(pim, up, NULL, 1);
+ if (rpf_result == PIM_RPF_FAILURE) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug(
+ "%s: Attempting to create upstream(%s), Unable to RPF for source",
+ __PRETTY_FUNCTION__, up->sg_str);
+ /* Create a dummmy channel oil with incoming ineterface
+ * MAXVIFS, since RP is not reachable
+ */
+ up->channel_oil = pim_channel_oil_add(
+ pim, &up->sg, MAXVIFS);
}
- if (up->sg.src.s_addr != INADDR_ANY)
- wheel_remove_item(pim->upstream_sg_wheel, up);
-
- pim_upstream_remove_children(pim, up);
- if (up->sources)
- list_delete(&up->sources);
-
- list_delete(&up->ifchannels);
-
- hash_release(pim->upstream_hash, up);
- XFREE(MTYPE_PIM_UPSTREAM, up);
- return NULL;
+ if (up->rpf.source_nexthop.interface) {
+ pim_ifp = up->rpf.source_nexthop.interface->info;
+ if (pim_ifp)
+ up->channel_oil = pim_channel_oil_add(pim,
+ &up->sg, pim_ifp->mroute_vif_index);
+ }
}
- if (up->rpf.source_nexthop.interface) {
- pim_ifp = up->rpf.source_nexthop.interface->info;
- if (pim_ifp)
- up->channel_oil = pim_channel_oil_add(
- pim, &up->sg, pim_ifp->mroute_vif_index);
- }
listnode_add_sort(pim->upstream_list, up);
if (PIM_DEBUG_TRACE) {
zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
__PRETTY_FUNCTION__, name,
up->sg_str, buf, up->rpf.source_nexthop.interface ?
- up->rpf.source_nexthop.interface->name : "NIL" ,
+ up->rpf.source_nexthop.interface->name : "Unknown" ,
found, up->ref_count);
} else
zlog_debug("%s(%s): (%s) failure to create",
PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
/* switched from false to true */
- if (is_join_desired && !was_join_desired) {
+ if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) {
pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
return;
}
(old_rpf_ifp == ch->interface) &&
/* RPF_interface(S) stopped being I */
(ch->upstream->rpf.source_nexthop
- .interface != ch->interface)) {
+ .interface) &&
+ (ch->upstream->rpf.source_nexthop
+ .interface != ch->interface)) {
assert_action_a5(ch);
}
} /* PIM_IFASSERT_I_AM_LOSER */
case PIM_REG_JOIN:
break;
case PIM_REG_PRUNE:
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return 0;
+ }
+
pim_ifp = up->rpf.source_nexthop.interface->info;
if (!pim_ifp) {
if (PIM_DEBUG_TRACE)
* Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
*/
for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
+ if (up->upstream_addr.s_addr == INADDR_ANY) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug(
+ "%s: RP not configured for Upstream %s",
+ __PRETTY_FUNCTION__, up->sg_str);
+ continue;
+ }
+
if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
if (PIM_DEBUG_TRACE)
zlog_debug(
- "Upstream %s without a path to send join, checking",
- up->sg_str);
+ "%s: Upstream %s without a path to send join, checking",
+ __PRETTY_FUNCTION__, up->sg_str);
pim_rpf_update(pim, up, NULL, 1);
}
}
/* "iif == RPF_interface(S)" check has to be done by the kernel or hw
* so we will skip that here */
- if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
+ if (up->rpf.source_nexthop.interface &&
+ pim_if_connected_to_source(up->rpf.source_nexthop.interface,
up->sg.src)) {
return true;
}
// No packet can have arrived here if this is the case
if (!up->channel_oil->installed) {
if (PIM_DEBUG_TRACE)
- zlog_debug("%s: %s[%s] is not installed in mroute",
+ zlog_debug("%s: %s%s is not installed in mroute",
__PRETTY_FUNCTION__, up->sg_str,
pim->vrf->name);
return;
} else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
- if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) {
+ if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) &&
+ (up->rpf.source_nexthop.interface)) {
pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
}
return;
/*
Upstream (S,G) channel in Joined state
-
(S,G) in the "Not Joined" state is not represented
-
See RFC 4601: 4.5.7. Sending (S,G) Join/Prune Message
+
+ upstream_addr : Who we are talking to.
+ For (*, G), upstream_addr is RP address or INADDR_ANY(if RP not configured)
+ For (S, G), upstream_addr is source address
+
+ rpf: contains the nexthop information to whom we are talking to.
+
+ join_state: JOINED/NOTJOINED
+
+ In the case when FRR receives IGMP/PIM (*, G) join for group G and RP is not
+ configured, then create a pim_upstream with the below information.
+ pim_upstream->upstream address: INADDR_ANY
+ pim_upstream->rpf: Unknown
+ pim_upstream->state: NOTJOINED
+
+ When a new RP gets configured for G, find the corresponding pim upstream (*,G)
+ entries and update the upstream address as new RP address if it the better one
+ for the group G.
+
+ When RP becomes reachable, populate the nexthop information in
+ pim_upstream->rpf and update the state to JOINED.
+
*/
struct pim_upstream {
struct pim_upstream *parent;
if (!if_is_operative(ifp))
pim_if_addr_del_all(ifp);
+ if_set_index(ifp, IFINDEX_INTERNAL);
+
return 0;
}
struct pim_upstream *up,
struct pim_rpf *old)
{
- struct pim_neighbor *nbr;
+ if (old->source_nexthop.interface) {
+ struct pim_neighbor *nbr;
- nbr = pim_neighbor_find(old->source_nexthop.interface,
- old->rpf_addr.u.prefix4);
- if (nbr)
- pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
+ nbr = pim_neighbor_find(old->source_nexthop.interface,
+ old->rpf_addr.u.prefix4);
+ if (nbr)
+ pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
- /*
- * We have detected a case where we might need
- * to rescan the inherited o_list so do it.
- */
- if (up->channel_oil->oil_inherited_rescan) {
- pim_upstream_inherited_olist_decide(pim, up);
- up->channel_oil->oil_inherited_rescan = 0;
- }
-
- if (up->join_state == PIM_UPSTREAM_JOINED) {
/*
- * If we come up real fast we can be here
- * where the mroute has not been installed
- * so install it.
+ * We have detected a case where we might need
+ * to rescan the inherited o_list so do it.
*/
- if (!up->channel_oil->installed)
- pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
+ if (up->channel_oil->oil_inherited_rescan) {
+ pim_upstream_inherited_olist_decide(pim, up);
+ up->channel_oil->oil_inherited_rescan = 0;
+ }
+
+ if (up->join_state == PIM_UPSTREAM_JOINED) {
+ /*
+ * If we come up real fast we can be here
+ * where the mroute has not been installed
+ * so install it.
+ */
+ if (!up->channel_oil->installed)
+ pim_mroute_add(up->channel_oil,
+ __PRETTY_FUNCTION__);
+
+ /*
+ * RFC 4601: 4.5.7. Sending (S,G)
+ * Join/Prune Messages
+ *
+ * Transitions from Joined State
+ *
+ * RPF'(S,G) changes not due to an Assert
+ *
+ * The upstream (S,G) state machine remains
+ * in Joined state. Send Join(S,G) to the new
+ * upstream neighbor, which is the new value
+ * of RPF'(S,G). Send Prune(S,G) to the old
+ * upstream neighbor, which is the old value
+ * of RPF'(S,G). Set the Join Timer (JT) to
+ * expire after t_periodic seconds.
+ */
+ pim_jp_agg_switch_interface(old, &up->rpf, up);
+
+ pim_upstream_join_timer_restart(up, old);
+ } /* up->join_state == PIM_UPSTREAM_JOINED */
+ }
+ else {
/*
- * RFC 4601: 4.5.7. Sending (S,G)
- * Join/Prune Messages
- *
- * Transitions from Joined State
- *
- * RPF'(S,G) changes not due to an Assert
- *
- * The upstream (S,G) state machine remains
- * in Joined state. Send Join(S,G) to the new
- * upstream neighbor, which is the new value
- * of RPF'(S,G). Send Prune(S,G) to the old
- * upstream neighbor, which is the old value
- * of RPF'(S,G). Set the Join Timer (JT) to
- * expire after t_periodic seconds.
+ * We have detected a case where we might need
+ * to rescan the inherited o_list so do it.
*/
- pim_jp_agg_switch_interface(old, &up->rpf, up);
+ if (up->channel_oil->oil_inherited_rescan) {
+ pim_upstream_inherited_olist_decide(pim, up);
+ up->channel_oil->oil_inherited_rescan = 0;
+ }
- pim_upstream_join_timer_restart(up, old);
- } /* up->join_state == PIM_UPSTREAM_JOINED */
+ if (!up->channel_oil->installed)
+ pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
+ }
- /* FIXME can join_desired actually be changed by
- pim_rpf_update()
- returning PIM_RPF_CHANGED ? */
+ /* FIXME can join_desired actually be changed by pim_rpf_update()
+ * returning PIM_RPF_CHANGED ?
+ */
pim_upstream_update_join_desired(pim, up);
}
-static void scan_upstream_rpf_cache(struct pim_instance *pim)
-{
- struct listnode *up_node;
- struct listnode *up_nextnode;
- struct pim_upstream *up;
-
- for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
- enum pim_rpf_result rpf_result;
- struct pim_rpf old;
- struct prefix nht_p;
-
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
- pim_resolve_upstream_nh(pim, &nht_p);
-
- old.source_nexthop.interface = up->rpf.source_nexthop.interface;
- old.source_nexthop.nbr = up->rpf.source_nexthop.nbr;
- rpf_result = pim_rpf_update(pim, up, &old, 0);
-
- if (rpf_result == PIM_RPF_FAILURE)
- continue;
-
- if (rpf_result == PIM_RPF_CHANGED)
- pim_zebra_upstream_rpf_changed(pim, up, &old);
-
- } /* for (qpim_upstream_list) */
-
- pim_zebra_update_all_interfaces(pim);
-}
-
void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
{
struct in_addr vif_source;
int input_iface_vif_index;
int old_vif_index;
- if (!pim_rp_set_upstream_addr(c_oil->pim, &vif_source,
+ pim_rp_set_upstream_addr(c_oil->pim, &vif_source,
c_oil->oil.mfcc_origin,
- c_oil->oil.mfcc_mcastgrp))
- return;
+ c_oil->oil.mfcc_mcastgrp);
if (in_vif_index)
input_iface_vif_index = in_vif_index;
{
struct pim_instance *pim = THREAD_ARG(t);
- /* update PIM protocol state */
- scan_upstream_rpf_cache(pim);
-
/* update kernel multicast forwarding cache (MFC) */
pim_scan_oil(pim);
struct pim_upstream *up = NULL;
if (!pim_rp_set_upstream_addr(pim, &vif_source,
- source->source_addr, sg.grp))
- return;
-
- /* Register addr with Zebra NHT */
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = vif_source;
- memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache));
+ source->source_addr, sg.grp)) {
+ /*Create a dummy channel oil */
+ source->source_channel_oil =
+ pim_channel_oil_add(pim, &sg, MAXVIFS);
- src.family = AF_INET;
- src.prefixlen = IPV4_MAX_BITLEN;
- src.u.prefix4 = vif_source; // RP or Src address
- grp.family = AF_INET;
- grp.prefixlen = IPV4_MAX_BITLEN;
- grp.u.prefix4 = sg.grp;
+ if (!source->source_channel_oil) {
+ if (PIM_DEBUG_IGMP_TRACE) {
+ zlog_debug(
+ "%s %s: could not create OIL for channel (S,G)=%s",
+ __FILE__, __PRETTY_FUNCTION__,
+ pim_str_sg_dump(&sg));
+ }
+ return;
+ }
+ }
- if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
+ else {
+ /* Register addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = vif_source;
+ memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache));
+
+ src.family = AF_INET;
+ src.prefixlen = IPV4_MAX_BITLEN;
+ src.u.prefix4 = vif_source; // RP or Src address
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = sg.grp;
+
+ if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
&out_pnc)) {
- if (out_pnc.nexthop_num) {
- up = pim_upstream_find(pim, &sg);
- memset(&nexthop, 0, sizeof(nexthop));
- if (up)
- memcpy(&nexthop,
- &up->rpf.source_nexthop,
- sizeof(struct pim_nexthop));
- pim_ecmp_nexthop_search(pim, &out_pnc, &nexthop,
- &src, &grp, 0);
- if (nexthop.interface)
- input_iface_vif_index =
+ if (out_pnc.nexthop_num) {
+ up = pim_upstream_find(pim, &sg);
+ memset(&nexthop, 0, sizeof(nexthop));
+ if (up)
+ memcpy(&nexthop,
+ &up->rpf.source_nexthop,
+ sizeof(struct pim_nexthop));
+ pim_ecmp_nexthop_search(pim, &out_pnc,
+ &nexthop,
+ &src, &grp, 0);
+ if (nexthop.interface)
+ input_iface_vif_index =
pim_if_find_vifindex_by_ifindex(
- pim,
- nexthop.interface->ifindex);
- } else {
- if (PIM_DEBUG_ZEBRA) {
- char buf1[INET_ADDRSTRLEN];
- char buf2[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>",
+ pim,
+ nexthop.interface->ifindex);
+ } else {
+ if (PIM_DEBUG_ZEBRA) {
+ char buf1[INET_ADDRSTRLEN];
+ char buf2[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<source?>",
nht_p.u.prefix4, buf1,
sizeof(buf1));
- pim_inet4_dump("<source?>",
+ pim_inet4_dump("<source?>",
grp.u.prefix4, buf2,
sizeof(buf2));
- zlog_debug(
+ zlog_debug(
"%s: NHT Nexthop not found for addr %s grp %s",
__PRETTY_FUNCTION__, buf1,
buf2);
+ }
}
- }
- } else
- input_iface_vif_index =
- pim_ecmp_fib_lookup_if_vif_index(pim, &src,
+ } else
+ input_iface_vif_index =
+ pim_ecmp_fib_lookup_if_vif_index(pim, &src,
&grp);
- if (PIM_DEBUG_ZEBRA) {
- char buf2[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", vif_source, buf2,
- sizeof(buf2));
- zlog_debug("%s: NHT %s vif_source %s vif_index:%d ",
- __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
- buf2, input_iface_vif_index);
- }
-
- if (input_iface_vif_index < 1) {
- if (PIM_DEBUG_IGMP_TRACE) {
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", source->source_addr,
- source_str, sizeof(source_str));
- zlog_debug(
- "%s %s: could not find input interface for source %s",
- __FILE__, __PRETTY_FUNCTION__,
- source_str);
- }
- return;
- }
+ if (PIM_DEBUG_ZEBRA) {
+ char buf2[INET_ADDRSTRLEN];
- /*
- Protect IGMP against adding looped MFC entries created by both
- source and receiver attached to the same interface. See TODO
- T22.
- */
- if (input_iface_vif_index == pim_oif->mroute_vif_index) {
- /* ignore request for looped MFC entry */
- if (PIM_DEBUG_IGMP_TRACE) {
- zlog_debug(
- "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
+ pim_inet4_dump("<source?>", vif_source, buf2,
+ sizeof(buf2));
+ zlog_debug("%s: NHT %s vif_source %s vif_index:%d ",
__PRETTY_FUNCTION__,
pim_str_sg_dump(&sg),
- source->source_group->group_igmp_sock
- ->fd,
- source->source_group->group_igmp_sock
- ->interface->name,
- input_iface_vif_index);
+ buf2, input_iface_vif_index);
}
- return;
- }
- source->source_channel_oil =
- pim_channel_oil_add(pim, &sg, input_iface_vif_index);
- if (!source->source_channel_oil) {
- if (PIM_DEBUG_IGMP_TRACE) {
- zlog_debug(
- "%s %s: could not create OIL for channel (S,G)=%s",
- __FILE__, __PRETTY_FUNCTION__,
- pim_str_sg_dump(&sg));
+ if (input_iface_vif_index < 1) {
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>",
+ source->source_addr,
+ source_str, sizeof(source_str));
+ zlog_debug(
+ "%s %s: could not find input interface for source %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ source_str);
+ }
+ source->source_channel_oil =
+ pim_channel_oil_add(pim, &sg, MAXVIFS);
+ }
+
+ else {
+ /*
+ * Protect IGMP against adding looped MFC
+ * entries created by both source and receiver
+ * attached to the same interface. See TODO
+ * T22.
+ */
+ if (input_iface_vif_index ==
+ pim_oif->mroute_vif_index) {
+ /* ignore request for looped MFC entry
+ */
+ if (PIM_DEBUG_IGMP_TRACE) {
+ zlog_debug(
+ "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
+ __PRETTY_FUNCTION__,
+ pim_str_sg_dump(&sg),
+ source->source_group
+ ->group_igmp_sock->fd,
+ source->source_group
+ ->group_igmp_sock
+ ->interface->name,
+ input_iface_vif_index);
+ }
+ return;
+ }
+
+ source->source_channel_oil =
+ pim_channel_oil_add(pim, &sg,
+ input_iface_vif_index);
+ if (!source->source_channel_oil) {
+ if (PIM_DEBUG_IGMP_TRACE) {
+ zlog_debug(
+ "%s %s: could not create OIL for channel (S,G)=%s",
+ __FILE__,
+ __PRETTY_FUNCTION__,
+ pim_str_sg_dump(&sg));
+ }
+ return;
+ }
}
- return;
}
}
sizeof(upstream_str));
zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)", __PRETTY_FUNCTION__,
source_str, group_str, ch->interface->name,
- upstream_str);
+ inet_ntoa(up->upstream_addr));
}
/* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS,
as part of mroute_del called by pim_forward_stop.
*/
- if (!up->channel_oil
- || (up->channel_oil
- && up->channel_oil->oil.mfcc_parent >= MAXVIFS)) {
+ if ((up->upstream_addr.s_addr != INADDR_ANY) && (!up->channel_oil)) {
struct prefix nht_p, src, grp;
struct pim_nexthop_cache out_pnc;
__FILE__, __PRETTY_FUNCTION__,
source_str);
}
- return;
+ up->channel_oil = pim_channel_oil_add(pim, &up->sg,
+ MAXVIFS);
}
+
+ else {
+ up->channel_oil = pim_channel_oil_add(pim, &up->sg,
+ input_iface_vif_index);
+ if (!up->channel_oil) {
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug(
+ "%s %s: could not create OIL for channel (S,G)=%s",
+ __FILE__, __PRETTY_FUNCTION__,
+ up->sg_str);
+ return;
+ }
+ }
+
if (PIM_DEBUG_TRACE) {
struct interface *in_intf = pim_if_find_by_vif_index(
pim, input_iface_vif_index);
zlog_debug(
"%s: Update channel_oil IIF %s VIFI %d entry %s ",
__PRETTY_FUNCTION__,
- in_intf ? in_intf->name : "NIL",
+ in_intf ? in_intf->name : "Unknown",
input_iface_vif_index, up->sg_str);
}
+
up->channel_oil = pim_channel_oil_add(pim, &up->sg,
input_iface_vif_index);
if (!up->channel_oil) {
more.src = c_oil->oil.mfcc_origin;
more.grp = c_oil->oil.mfcc_mcastgrp;
zlog_debug(
- "Sending Request for New Channel Oil Information(%s) VIIF %d(%s)",
+ "Sending Request for New Channel Oil Information%s VIIF %d(%s)",
pim_str_sg_dump(&more), c_oil->oil.mfcc_parent,
c_oil->pim->vrf->name);
}
{
struct zclient *zclient;
- pim_free();
-
/* reverse prefix_list_init */
prefix_list_add_hook(NULL);
prefix_list_delete_hook(NULL);
zclient_free(zclient);
}
+ pim_free();
pim_router_terminate();
+
frr_fini();
}
+++ /dev/null
-Building your own FRRouting RPM
-======================================
-(Tested on CentOS 6, CentOS 7 and Fedora 24.)
-
-1. On CentOS 6 (which doesn't provide a bison/automake/autoconf of a recent enough version):
- - Check out ../doc/developer/building-frr-for-centos6.rst for details on installing
- a bison/automake/autoconf to support frr building.
-
- Newer automake/autoconf/bison is only needed to build the rpm and is
- **not** needed to install the binary rpm package
-
-2. Install the build packages as documented in doc/developer/building-frr-for-xxxxx.rst and the following additional packages:
-
- yum install rpm-build net-snmp-devel pam-devel libcap-devel
-
- Additionally, on systems with systemd (CentOS 7, Fedora)
-
- yum install systemd-devel
-
- (use `dnf install` on new Fedora instead of `yum install`)
-
-3. Checkout FRR under a **unpriviledged** user account
-
- git clone https://github.com/frrouting/frr.git frr
-
-4. Run Bootstrap and make distribution tar.gz
-
- cd frr
- ./bootstrap.sh
- ./configure --with-pkg-extra-version=-MyRPMVersion \
- SPHINXBUILD=sphinx-build2.7
- make dist
-
- Note: configure parameters are not important for the RPM building - except the `with-pkg-extra-version` if you want to give the RPM a specific name to
- mark your own unoffical build
-
-5. Create RPM directory structure and populate with sources
-
- mkdir rpmbuild
- mkdir rpmbuild/SOURCES
- mkdir rpmbuild/SPECS
- cp redhat/*.spec rpmbuild/SPECS/
- cp frr*.tar.gz rpmbuild/SOURCES/
-
-6. Edit rpm/SPECS/frr.spec with configuration as needed
- Look at the beginning of the file and adjust the following parameters to enable or disable features as required:
-
- ############### FRRouting (FRR) configure options #################
- # with-feature options
- %{!?with_pam: %global with_pam 0 }
- %{!?with_ospfclient: %global with_ospfclient 1 }
- %{!?with_ospfapi: %global with_ospfapi 1 }
- %{!?with_irdp: %global with_irdp 1 }
- %{!?with_rtadv: %global with_rtadv 1 }
- %{!?with_ldpd: %global with_ldpd 1 }
- %{!?with_nhrpd: %global with_nhrpd 1 }
- %{!?with_eigrp: %global with_eigrpd 1 }
- %{!?with_shared: %global with_shared 1 }
- %{!?with_multipath: %global with_multipath 256 }
- %{!?frr_user: %global frr_user frr }
- %{!?vty_group: %global vty_group frrvty }
- %{!?with_fpm: %global with_fpm 0 }
- %{!?with_watchfrr: %global with_watchfrr 1 }
- %{!?with_bgp_vnc: %global with_bgp_vnc 0 }
- %{!?with_pimd: %global with_pimd 1 }
- %{!?with_rpki: %global with_rpki 0 }
-
-7. Build the RPM
-
- rpmbuild --define "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/frr.spec
-
- If building with RPKI, then download and install the additional RPKI
- packages from
- https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact
-
-DONE.
-
-If all works correctly, then you should end up with the RPMs under
-`rpmbuild/RPMS` and the Source RPM under `rpmbuild/SRPMS`
-
-
-Enabling daemons after installation of the package:
----------------------------------------------------
-
-### init.d based systems (ie CentOS 6):
-
-1. Edit /etc/frr/daemons and enable required routing daemons (Zebra is probably needed for most deployments, so make sure to enable it.)
-
-2. Enable the daemons as needed to run after boot (Zebra is mandatory)
-
- chkconfig frr on
-
-3. Check your firewall / IPtables to make sure the routing protocols are
-allowed.
-
-5. Start the FRR daemons (or reboot)
-
- service frr start
-
-Configuration is stored in `/etc/frr/*.conf` files and daemon selection is stored in `/etc/frr/daemons`.
-
-
-### systemd based systems (ie CentOS 7, Fedora 24)
-
-1. Edit /etc/frr/daemons and enable required routing daemons (Zebra is probably needed for most deployments, so make sure to enable it.)
-
-2. Enable the frr daemons to run after boot.
-
- systemctl enable frr
-
-2. Check your firewall / IPtables to make sure the routing protocols are
-allowed.
-
-3. Start the daemons (or reboot)
-
- systemctl start frr
-
-Configuration is stored in `/etc/frr/*.conf` files and daemon selection is stored in `/etc/frr/daemons`.
-
+++ /dev/null
-# This file tells the frr package which daemons to start.
-#
-# Entries are in the format: <daemon>=(yes|no|priority)
-# 0, "no" = disabled
-# 1, "yes" = highest priority
-# 2 .. 10 = lower priorities
-#
-# For daemons which support multiple instances, a 2nd line listing
-# the instances can be added. Eg for ospfd:
-# ospfd=yes
-# ospfd_instances="1,2"
-#
-# Priorities were suggested by Dancer <dancer@zeor.simegen.com>.
-# They're used to start the FRR daemons in more than one step
-# (for example start one or two at network initialization and the
-# rest later). The number of FRR daemons being small, priorities
-# must be between 1 and 9, inclusive (or the initscript has to be
-# changed). /etc/init.d/frr then can be started as
-#
-# /etc/init.d/frr <start|stop|restart|<priority>>
-#
-# where priority 0 is the same as 'stop', priority 10 or 'start'
-# means 'start all'
-#
-# 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.
-#
-watchfrr_enable=yes
-watchfrr_options="-r '/usr/lib/frr/frr restart %s' -s '/usr/lib/frr/frr start %s' -k '/usr/lib/frr/frr stop %s'"
-#
-zebra=no
-bgpd=no
-ospfd=no
-ospf6d=no
-ripd=no
-ripngd=no
-isisd=no
-ldpd=no
-pimd=no
-nhrpd=no
-eigrpd=no
-babeld=no
-sharpd=no
-pbrd=no
-staticd=no
-bfdd=no
-fabricd=no
-
-#
-# Command line options for the daemons
-#
-zebra_options=("-A 127.0.0.1")
-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")
-ldpd_options=("-A 127.0.0.1")
-pimd_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")
-
-#
-# If the vtysh_enable is yes, then the unified config is read
-# and applied if it exists. If no unified frr.conf exists
-# then the per-daemon <daemon>.conf files are used)
-# If vtysh_enable is no or non-existant, the frr.conf is ignored.
-# it is highly suggested to have this set to yes
-vtysh_enable=yes
-
+++ /dev/null
-#!/bin/bash
-#
-# /etc/rc.d/init.d/frr
-#
-# Start/Stop the FRR Routing daemons
-# <any general comments about this init script>
-#
-# chkconfig: 2345 15 85
-#
-# description: FRRouting (FRR) is a routing suite for IP routing protocols
-# like BGP, OSPF, RIP and others. This script contols the main
-# daemon "frr" as well as the individual protocol daemons.
-#
-### BEGIN INIT INFO
-# Provides: frr
-# Required-Start: $local_fs $network $syslog
-# Required-Stop: $local_fs $syslog
-# Should-Start: $syslog
-# Should-Stop: $network $syslog
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Start/Stop the FRR Routing daemons
-# Description: FRRouting (FRR) is a routing suite for IP routing protocols
-# like BGP, OSPF, RIP and others. This script contols the main
-# daemon "frr" as well as the individual protocol daemons.
-### END INIT INFO
-
-PATH=/bin:/usr/bin:/sbin:/usr/sbin
-D_PATH=/usr/lib/frr
-C_PATH=/etc/frr
-V_PATH=/var/run/frr
-
-# Local Daemon selection may be done by using /etc/frr/daemons.
-# See /usr/share/doc/frr/README.Debian.gz for further information.
-# Keep zebra first and do not list watchfrr!
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd pimd pbrd ldpd nhrpd eigrpd babeld staticd sharpd bfdd fabricd"
-MAX_INSTANCES=5
-RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py
-
-. /etc/init.d/functions
-
-# Print the name of the pidfile.
-pidfile()
-{
- echo "$V_PATH/$1.pid"
-}
-
-# Print the name of the vtysh.
-vtyfile()
-{
- echo "$V_PATH/$1.vty"
-}
-
-# Check if daemon is started by using the pidfile.
-started()
-{
- [ ! -e `pidfile $1` ] && return 3
- if [ -n "$2" ] && [ "$2" == "log" ]; then
- status -p `pidfile $1` $1 && return 0 || return $?
- else
- kill -0 `cat \`pidfile $1\`` 2> /dev/null || return 1
- return 0
- fi
-}
-
-# Loads the config via vtysh -b if configured to do so.
-vtysh_b ()
-{
- # Rember, that all variables have been incremented by 1 in convert_daemon_prios()
- if [ "$vtysh_enable" = 2 -a -f $C_PATH/frr.conf ]; then
- /usr/bin/vtysh -b -n
- fi
-}
-
-# Check if the daemon is activated and if its executable and config files
-# are in place.
-# params: daemon name
-# returns: 0=ok, 1=error
-check_daemon()
-{
- # If the integrated config file is used the others are not checked.
- if [ -r "$C_PATH/frr.conf" ]; then
- return 0
- fi
-
- # vtysh_enable has no config file nor binary so skip check.
- # (Not sure why vtysh_enable is in this list but does not hurt)
- if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then
- # check for daemon binary
- if [ ! -x "$D_PATH/$1" ]; then return 1; fi
-
- # check for config file
- if [ -n "$2" ]; then
- if [ ! -r "$C_PATH/$1-$2.conf" ]; then
- touch "$C_PATH/$1-$2.conf"
- chown frr:frr "$C_PATH/$1-$2.conf"
- fi
- elif [ ! -r "$C_PATH/$1.conf" ]; then
- touch "$C_PATH/$1.conf"
- chown frr:frr "$C_PATH/$1.conf"
- fi
- fi
- return 0
-}
-
-# Starts the server if it's not already running according to the pid file.
-# The Frr daemons creates the pidfile when starting.
-start()
-{
- local dmn inst
- dmn="$1"
- inst="$2"
-
- ulimit -n $MAX_FDS > /dev/null 2> /dev/null
- if [ "$dmn" = "watchfrr" ]; then
-
- # We may need to restart watchfrr if new daemons are added and/or
- # removed
- if started "$dmn" ; then
- stop watchfrr
- else
- # Echo only once. watchfrr is printed in the stop above
- echo -n " $dmn"
- fi
-
- if [ -e /var/run/frr/watchfrr.started ] ; then
- rm /var/run/frr/watchfrr.started
- fi
- # redhat /etc/init.d/functions daemon() re-expands args :(
- # eval "set - $watchfrr_options"
- daemon --pidfile=`pidfile $dmn` "$D_PATH/$dmn" -d "$watchfrr_options"
- RETVAL=$?
- [ $RETVAL -ne 0 ] && break
- for i in `seq 1 10`;
- do
- if [ -e /var/run/frr/watchfrr.started ] ; then
- RETVAL=0
- break
- else
- sleep 1
- fi
- done
- RETVAL=1
- elif [ -n "$inst" ]; then
- echo -n " $dmn-$inst"
- if ! check_daemon $dmn $inst ; then
- echo -n " (binary does not exist)"
- return;
- fi
- daemon --pidfile=`pidfile $dmn-$inst` "$D_PATH/$dmn" -d `eval echo "$""$dmn""_options"` -n "$inst"
- RETVAL=$?
- else
- echo -n " $dmn "
- if ! check_daemon $dmn; then
- echo " (binary does not exist)"
- return;
- fi
- daemon --pidfile=`pidfile $dmn` "$D_PATH/$dmn" -d `eval echo "$""$dmn""_options"`
- RETVAL=$?
- fi
- echo
- [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$dmn
- return $RETVAL
-}
-
-# Stop the daemon given in the parameter, printing its name to the terminal.
-stop()
-{
- local inst
-
- if [ -n "$2" ]; then
- inst="$1-$2"
- else
- inst="$1"
- fi
-
- if ! started "$inst" ; then
- # echo -n " ($inst)"
- return 0
- else
- echo -n " $inst"
- PIDFILE=`pidfile $inst`
- PID=`cat $PIDFILE 2>/dev/null`
- killproc -p "$PIDFILE" "$D_PATH/$1"
- RETVAL=$?
- [ $RETVAL -eq 0 ] && rm -f $lockfile
- rm -f `pidfile $inst`
- rm -f `vtyfile $inst`
- echo
- return $RETVAL
- fi
-}
-
-# Converts values from /etc/frr/daemons to all-numeric values.
-convert_daemon_prios()
-{
- for name in $DAEMONS zebra vtysh_enable watchfrr_enable; do
- # First, assign the value set by the user to $value
- eval value=\${${name}:0:3}
-
- # Daemon not activated or entry missing?
- if [ "$value" = "no" -o "$value" = "" ]; then value=0; fi
-
- # These strings parsed for backwards compatibility.
- if [ "$value" = "yes" -o "$value" = "true" ]; then
- value=1;
- fi
-
- # Zebra is threatened special. It must be between 0=off and the first
- # user assigned value "1" so we increase all other enabled daemons' values.
- if [ "$name" != "zebra" -a "$value" -gt 0 ]; then value=`expr "$value" + 1`; fi
-
- # If e.g. name is zebra then we set "zebra=yes".
- eval $name=$value
- done
-}
-
-# Starts watchfrr for all wanted daemons.
-start_watchfrr()
-{
- local daemon_name
- local daemon_prio
- local found_one
- local daemon_inst
-
- # Start the monitor daemon only if desired.
- if [ 0 -eq "$watchfrr_enable" ]; then
- return
- fi
-
- # Check variable type
- if declare -p watchfrr_options | grep -q '^declare \-a'; then
- # old array support
- watchfrr_options="${watchfrr_options[@]}"
- fi
-
- # Which daemons have been started?
- found_one=0
- for daemon_name in $DAEMONS; do
- eval daemon_prio=\$$daemon_name
- if [ "$daemon_prio" -gt 0 ]; then
- eval "daemon_inst=\${${daemon_name}_instances//,/ }"
- if [ -n "$daemon_inst" ]; then
- for inst in ${daemon_inst}; do
- eval "inst_disable=\${${daemon_name}_${inst}}"
- if [ -z ${inst_disable} ] || [ ${inst_disable} != 0 ]; then
- if check_daemon $daemon_name $inst; then
- watchfrr_options="$watchfrr_options ${daemon_name}-${inst}"
- fi
- fi
- done
- else
- if check_daemon $daemon_name; then
- watchfrr_options="$watchfrr_options $daemon_name"
- fi
- fi
- found_one=1
- fi
- done
-
- # Start if at least one daemon is activated.
- if [ $found_one -eq 1 ]; then
- echo "Starting FRRouting monitor daemon:"
- start watchfrr
- fi
-}
-
-# Stopps watchfrr.
-stop_watchfrr()
-{
- echo "Stopping FRRouting monitor daemon:"
- stop watchfrr
-}
-
-# Stops all daemons that have a lower level of priority than the given.
-# (technically if daemon_prio >= wanted_prio)
-stop_prio()
-{
- local wanted_prio
- local daemon_prio
- local daemon_list
- local daemon_inst
- local inst
-
- if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then
- daemon=${BASH_REMATCH[1]}
- inst=${BASH_REMATCH[2]}
- else
- daemon="$2"
- fi
-
- wanted_prio=$1
- daemon_list=${daemon:-$DAEMONS}
-
- echo "Stopping FRRouting daemons (prio:$wanted_prio):"
-
- for prio_i in `seq 10 -1 $wanted_prio`; do
- for daemon_name in $daemon_list; do
- eval daemon_prio=\${${daemon_name}:0:3}
- daemon_inst=""
- if [ $daemon_prio -eq $prio_i ]; then
- eval "daemon_inst=\${${daemon_name}_instances//,/ }"
- if [ -n "$daemon_inst" ]; then
- for i in ${daemon_inst}; do
- if [ -n "$inst" ] && [ "$i" == "$inst" ]; then
- stop "$daemon_name" "$inst"
- elif [ x"$inst" == x ]; then
- stop "$daemon_name" "$i"
- fi
- done
- else
- stop "$daemon_name"
- fi
- fi
- done
- done
-
- if [ -z "$inst" ]; then
- # Now stop other daemons that're prowling, coz the daemons file changed
- echo "Stopping other FRRouting daemons"
- if [ -n "$daemon" ]; then
- eval "file_list_suffix="$V_PATH"/"$daemon*""
- else
- eval "file_list_suffix="$V_PATH/*""
- fi
- for pidfile in $file_list_suffix.pid; do
- if [ -f "$pidfile" ]; then
- filename=${pidfile##*/}
- daemon=${filename%.*}
- echo -n " $daemon"
- killproc -p "$pidfile" "$daemon"
- RETVAL=$?
- [ $RETVAL -eq 0 ] && rm -f $lockfile
- rm -f "$pidfile"
- echo
- fi
- done
- echo -n "Removing remaining .vty files"
- for vtyfile in $file_list_suffix.vty; do
- rm -rf "$vtyfile"
- done
- echo
- fi
-}
-
-# Starts all daemons that have a higher level of priority than the given.
-# (technically if daemon_prio <= wanted_prio)
-start_prio()
-{
- local wanted_prio
- local daemon_prio
- local daemon_list
- local daemon_name
- local daemon_inst
- local inst
-
- if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then
- daemon=${BASH_REMATCH[1]}
- inst=${BASH_REMATCH[2]}
- else
- daemon="$2"
- fi
-
- wanted_prio=$1
- daemon_list=${daemon:-$DAEMONS}
-
- echo "Starting FRRouting daemons (prio:$wanted_prio):"
-
- for prio_i in `seq 1 $wanted_prio`; do
- for daemon_name in $daemon_list; do
- eval daemon_prio=\$${daemon_name}
- daemon_inst=""
- if [ $daemon_prio -eq $prio_i ]; then
- eval "daemon_inst=\${${daemon_name}_instances//,/ }"
- if [ -n "$daemon_inst" ]; then
- if [ `echo "$daemon_inst" | wc -w` -gt ${MAX_INSTANCES} ]; then
- echo "Max instances supported is ${MAX_INSTANCES}. Aborting"
- exit 1
- fi
- # Check if we're starting again by switching from single instance
- # to MI version
- if started "$daemon_name"; then
- PIDFILE=`pidfile $daemon_name`
- killproc -p "$PIDFILE" "$daemon_name"
- rm -f `pidfile $1`
- rm -f `vtyfile $1`
- fi
-
- for i in ${daemon_inst}; do
- if [ -n "$inst" ] && [ "$i" == "$inst" ]; then
- start "$daemon_name" "$inst"
- elif [ x"$inst" == x ]; then
- start "$daemon_name" "$i"
- fi
- done
- else
- # Check if we're starting again by switching from
- # single instance to MI version
- eval "file_list_suffix="$V_PATH"/"$daemon_name-*""
- for pidfile in $file_list_suffix.pid; do
- if [ -f "$pidfile" ]; then
- killproc -p "$pidfile" "$daemon_name"
- rm -rf "$pidfile"
- fi
- done
- for vtyfile in $file_list_suffix.vty; do
- rm -rf "$vtyfile"
- done
-
- start "$daemon_name"
- fi
- fi
- done
- done
-}
-
-check_status()
-{
- local daemon_name
- local daemon_prio
- local daemon_inst
- local failed_status=0
-
- if [ -n "$1" ] && [[ "$1" =~ (.*)-(.*) ]]; then
- daemon=${BASH_REMATCH[1]}
- inst=${BASH_REMATCH[2]}
- else
- daemon="$1"
- fi
-
- daemon_list=${daemon:-$DAEMONS}
-
- # Which daemons have been started?
- for daemon_name in $daemon_list; do
- eval daemon_prio=\$$daemon_name
- if [ "$daemon_prio" -gt 0 ]; then
- eval "daemon_inst=\${${daemon_name}_instances//,/ }"
- if [ -n "$daemon_inst" ]; then
- for i in ${daemon_inst}; do
- if [ -n "$inst" -a "$inst" = "$i" ]; then
- started "$1" "log" || failed_status=$?
- elif [ -z "$inst" ]; then
- started "$daemon_name-$i" "log" || failed_status=$?
- fi
- done
- else
- started "$daemon_name" "log" || failed_status=$?
- fi
- fi
- done
-
- # All daemons that need to have been started are up and running
- return $failed_status
-}
-
-#########################################################
-# Main program #
-#########################################################
-
-# Config broken but script must exit silently.
-[ ! -r "$C_PATH/daemons" ] && exit 0
-
-# Load configuration
-. "$C_PATH/daemons"
-
-# Read configuration variable file if it is present
-[ -r /etc/sysconfig/frr ] && . /etc/sysconfig/frr
-
-MAX_INSTANCES=${MAX_INSTANCES:=5}
-
-# Set priority of un-startable daemons to 'no' and substitute 'yes' to '0'
-convert_daemon_prios
-
-if [ ! -d $V_PATH ]; then
- echo "Creating $V_PATH"
- mkdir -p $V_PATH
- chown frr:frr $V_PATH
- chmod 755 /$V_PATH
-fi
-
-if [ -n "$3" ] && [ "$3" != "all" ]; then
- dmn="$2"-"$3"
-elif [ -n "$2" ] && [ "$2" != "all" ]; then
- dmn="$2"
-fi
-
-case "$1" in
- start)
- # Try to load this necessary (at least for 2.6) module.
- if [ -d /lib/modules/`uname -r` ] ; then
- echo "Loading capability module if not yet done."
- LC_ALL=C modprobe -a capability 2>&1 | egrep -v "(not found|Can't locate)"
- fi
-
- # Start all daemons
- cd $C_PATH/
- if [ "$2" != "watchfrr" ]; then
- start_prio 10 $dmn
- fi
- start_watchfrr
- vtysh_b
- ;;
-
- 1|2|3|4|5|6|7|8|9|10)
- # Stop/start daemons for the appropriate priority level
- stop_prio $1
- start_prio $1
- vtysh_b
- ;;
-
- stop|0)
- # Stop all daemons at level '0' or 'stop'
- stop_watchfrr
- if [ "$dmn" != "watchfrr" ]; then
- [ -n "${dmn}" ] && eval "${dmn/-/_}=0"
- stop_prio 0 $dmn
- fi
-
- if [ -z "$dmn" -o "$dmn" = "zebra" ]; then
- echo "Removing all routes made by zebra."
- ip route flush proto zebra
- # At least in CentOS/RHEL 6, iproute2 doesn't know
- # about the new protocol names, so we have to flush them
- # by number (it also doesn't support rt_protos.d
- ip route flush proto 186
- ip route flush proto 187
- ip route flush proto 188
- ip route flush proto 189
- ip route flush proto 190
- ip route flush proto 191
- ip route flush proto 192
- ip route flush proto 193
- ip route flush proto 194
- else
- [ -n "$dmn" ] && eval "${dmn/-/_}=0"
- start_watchfrr
- fi
- ;;
-
- reload)
- # Just apply the commands that have changed, no restart necessary
- if [ ! -x "$RELOAD_SCRIPT" ]; then
- echo "frr-reload - reload not supported. Use restart or install frr-pythontools package"
- exit 1
- fi
- NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}"
- if [ ! -r $NEW_CONFIG_FILE ]; then
- echo "Unable to read configuration file $NEW_CONFIG_FILE. Only supporting integrated config"
- exit 1
- fi
- echo "Applying only incremental changes to running configuration from frr.conf"
- "$RELOAD_SCRIPT" --reload /etc/frr/frr.conf
- exit $?
- ;;
-
- status)
- check_status $dmn
- exit $?
- ;;
-
- restart|force-reload)
- $0 stop $dmn
- sleep 1
- $0 start $dmn
- ;;
-
- *)
- echo "Usage: /etc/init.d/frr {start|stop|status|reload|restart|force-reload|<priority>} [daemon]"
- echo " E.g. '/etc/init.d/frr 5' would start all daemons with a prio 1-5."
- echo " reload applies only modifications from the running config to all daemons."
- echo " reload neither restarts starts any daemon nor starts any new ones."
- echo " Read /usr/share/doc/frr/README.Debian for details."
- exit 1
- ;;
-esac
-
-exit 0
+++ /dev/null
-[Unit]
-Description=FRRouting (FRR)
-Wants=network.target
-After=network-pre.target systemd-sysctl.service
-Before=network.target
-OnFailure=heartbeat-failed@%n.service
-
-[Service]
-Nice=-5
-Type=forking
-NotifyAccess=all
-StartLimitInterval=3m
-StartLimitBurst=3
-TimeoutSec=2m
-WatchdogSec=60s
-RestartSec=5
-Restart=on-abnormal
-LimitNOFILE=1024
-ExecStart=/usr/lib/frr/frr start
-ExecStop=/usr/lib/frr/frr stop
-ExecReload=/usr/lib/frr/frr reload
-
-[Install]
-WantedBy=multi-user.target
# install /etc sources
%if "%{initsystem}" == "systemd"
mkdir -p %{buildroot}%{_unitdir}
-install -m644 %{zeb_rh_src}/frr.service %{buildroot}%{_unitdir}/frr.service
-install %{zeb_rh_src}/frr.init %{buildroot}%{_sbindir}/frr
+install -m644 %{zeb_src}/tools/frr.service %{buildroot}%{_unitdir}/frr.service
%else
mkdir -p %{buildroot}%{_initddir}
-install %{zeb_rh_src}/frr.init %{buildroot}%{_sbindir}/frr
-ln -s %{_sbindir}/frr %{buildroot}%{_initddir}/frr
+ln -s %{_sbindir}/frrinit.sh %{buildroot}%{_initddir}/frr
%endif
-install %{zeb_rh_src}/daemons %{buildroot}%{_sysconfdir}/frr
+install %{zeb_src}/tools/etc/frr/daemons %{buildroot}%{_sysconfdir}/frr
# add rpki module to daemon
%if %{with_rpki}
sed -i -e 's/^\(bgpd_options=\)\(.*\)\(".*\)/\1\2 -M rpki\3/' %{buildroot}%{_sysconfdir}/frr/daemons
# Fix bad path in previous config files
# Config files won't get replaced by default, so we do this ugly hack to fix it
-%__sed -i 's|/etc/init.d/|%{_sbindir}/|g' %{configdir}/daemons 2> /dev/null || true
+%__sed -i 's|watchfrr_options=|#watchfrr_options=|g' %{configdir}/daemons 2> /dev/null || true
# With systemd, watchfrr is mandatory. Fix config to make sure it's enabled if
# we install or upgrade to a frr built with systemd
%else
%{_initddir}/frr
%endif
-%{_sbindir}/frr
%config(noreplace) %{_sysconfdir}/pam.d/frr
%config(noreplace) %{_sysconfdir}/logrotate.d/frr
%{_sbindir}/frr-reload
"Suppress routing updates on an interface\n"
"Interface name\n")
{
- nb_cli_enqueue_change(vty, "./passive-interface",
- no ? NB_OP_DESTROY : NB_OP_CREATE, ifname);
- nb_cli_enqueue_change(vty, "./non-passive-interface",
- no ? NB_OP_CREATE : NB_OP_DESTROY, ifname);
+ bool passive_default =
+ yang_dnode_get_bool(vty->candidate_config->dnode, "%s%s",
+ VTY_CURR_XPATH, "/passive-default");
+
+ if (passive_default) {
+ nb_cli_enqueue_change(vty, "./non-passive-interface",
+ no ? NB_OP_CREATE : NB_OP_DESTROY,
+ ifname);
+ } else {
+ nb_cli_enqueue_change(vty, "./passive-interface",
+ no ? NB_OP_DESTROY : NB_OP_CREATE,
+ ifname);
+ }
return nb_cli_apply_changes(vty, NULL);
}
ri->ri_receive = yang_get_default_enum("%s/version-receive", RIP_IFACE);
ri->v2_broadcast = yang_get_default_bool("%s/v2-broadcast", RIP_IFACE);
- if (ri->auth_str)
- XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
+ XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
- if (ri->key_chain)
- XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);
+ XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);
ri->list[RIP_FILTER_IN] = NULL;
ri->list[RIP_FILTER_OUT] = NULL;
ifp = yang_dnode_get_entry(dnode, true);
ri = ifp->info;
- if (ri->auth_str)
- XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
+ XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
ri->auth_str = XSTRDUP(MTYPE_RIP_INTERFACE_STRING,
yang_dnode_get_string(dnode, NULL));
ifp = yang_dnode_get_entry(dnode, true);
ri = ifp->info;
- if (ri->key_chain)
- XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);
+ XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);
ri->key_chain = XSTRDUP(MTYPE_RIP_INTERFACE_STRING,
yang_dnode_get_string(dnode, NULL));
* group on
* an interface that has just gone down.
*/
- zlog_warn("ripng join on %s EADDRINUSE (ignoring)\n",
+ zlog_warn("ripng join on %s EADDRINUSE (ignoring)",
ifp->name);
return 0; /* not an error */
}
ret = setsockopt(ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
(char *)&mreq, sizeof(mreq));
if (ret < 0)
- zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s\n",
+ zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s",
safe_strerror(errno));
if (IS_RIPNG_DEBUG_EVENT)
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;
int32_t repeat;
uint8_t inst;
+ vrf_id_t vrf_id;
struct timeval t_start;
struct timeval t_end;
#endif
DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
- "sharp watch <nexthop$n|import$import> X:X::X:X$nhop [connected$connected]",
+ "sharp watch [vrf NAME$name] <nexthop$n|import$import> X:X::X:X$nhop [connected$connected]",
"Sharp routing Protocol\n"
"Watch for changes\n"
+ "The vrf we would like to watch if non-default\n"
+ "The NAME of the vrf\n"
"Watch for nexthop changes\n"
"Watch for import check changes\n"
"The v6 nexthop to signal for watching\n"
"Should the route be connected\n")
{
+ struct vrf *vrf;
struct prefix p;
bool type_import;
+ if (!name)
+ name = VRF_DEFAULT_NAME;
+ vrf = vrf_lookup_by_name(name);
+ if (!vrf) {
+ vty_out(vty, "The vrf NAME specified: %s does not exist\n",
+ name);
+ return CMD_WARNING;
+ }
if (n)
type_import = false;
p.family = AF_INET6;
sharp_nh_tracker_get(&p);
- sharp_zebra_nexthop_watch(&p, type_import, true, !!connected);
+ sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import,
+ true, !!connected);
return CMD_SUCCESS;
}
DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
- "sharp watch <nexthop$n|import$import> A.B.C.D$nhop [connected$connected]",
+ "sharp watch [vrf NAME$name] <nexthop$n|import$import> A.B.C.D$nhop [connected$connected]",
"Sharp routing Protocol\n"
"Watch for changes\n"
+ "The vrf we would like to watch if non-default\n"
+ "The NAME of the vrf\n"
"Watch for nexthop changes\n"
"Watch for import check changes\n"
"The v4 nexthop to signal for watching\n"
"Should the route be connected\n")
{
+ struct vrf *vrf;
struct prefix p;
bool type_import;
+ if (!name)
+ name = VRF_DEFAULT_NAME;
+ vrf = vrf_lookup_by_name(name);
+ if (!vrf) {
+ vty_out(vty, "The vrf NAME specified: %s does not exist\n",
+ name);
+ return CMD_WARNING;
+ }
+
memset(&p, 0, sizeof(p));
if (n)
p.family = AF_INET;
sharp_nh_tracker_get(&p);
- sharp_zebra_nexthop_watch(&p, type_import, true, !!connected);
+ sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import,
+ true, !!connected);
return CMD_SUCCESS;
}
DEFPY (install_routes,
install_routes_cmd,
- "sharp install routes <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]",
+ "sharp install routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]",
"Sharp routing Protocol\n"
"install some routes\n"
"Routes to install\n"
+ "The vrf we would like to install into if non-default\n"
+ "The NAME of the vrf\n"
"v4 Address to start /32 generation at\n"
"v6 Address to start /32 generation at\n"
"Nexthop to use(Can be an IPv4 or IPv6 address)\n"
"Should we repeat this command\n"
"How many times to repeat this command\n")
{
+ struct vrf *vrf;
struct prefix prefix;
uint32_t rts;
}
sg.r.orig_prefix = prefix;
+ if (!name)
+ name = VRF_DEFAULT_NAME;
+
+ vrf = vrf_lookup_by_name(name);
+ if (!vrf) {
+ vty_out(vty, "The vrf NAME specified: %s does not exist\n",
+ name);
+ return CMD_WARNING;
+ }
+
if (nexthop_group) {
struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group);
if (!nhgc) {
sg.r.nhop.type = NEXTHOP_TYPE_IPV6;
}
+ sg.r.nhop.vrf_id = vrf->vrf_id;
sg.r.nhop_group.nexthop = &sg.r.nhop;
}
sg.r.inst = instance;
+ sg.r.vrf_id = vrf->vrf_id;
rts = routes;
- sharp_install_routes_helper(&prefix, sg.r.inst, &sg.r.nhop_group, rts);
+ sharp_install_routes_helper(&prefix, sg.r.vrf_id,
+ sg.r.inst, &sg.r.nhop_group, rts);
return CMD_SUCCESS;
}
DEFPY (remove_routes,
remove_routes_cmd,
- "sharp remove routes <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
+ "sharp remove routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
"Sharp Routing Protocol\n"
"Remove some routes\n"
"Routes to remove\n"
+ "The vrf we would like to remove from if non-default\n"
+ "The NAME of the vrf\n"
"v4 Starting spot\n"
"v6 Starting spot\n"
"Routes to uninstall\n"
"instance to use\n"
"Value of instance\n")
{
+ struct vrf *vrf;
struct prefix prefix;
sg.r.total_routes = routes;
prefix.u.prefix6 = start6;
}
+ vrf = vrf_lookup_by_name(name ? name : VRF_DEFAULT_NAME);
+ if (!vrf) {
+ vty_out(vty, "The vrf NAME specified: %s does not exist\n",
+ name ? name : VRF_DEFAULT_NAME);
+ return CMD_WARNING;
+ }
+
sg.r.inst = instance;
+ sg.r.vrf_id = vrf->vrf_id;
rts = routes;
- sharp_remove_routes_helper(&prefix, sg.r.inst, rts);
+ sharp_remove_routes_helper(&prefix, sg.r.vrf_id,
+ sg.r.inst, rts);
return CMD_SUCCESS;
}
return 0;
}
-void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
- struct nexthop_group *nhg,
+void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
+ uint8_t instance, struct nexthop_group *nhg,
uint32_t routes)
{
uint32_t temp, i;
monotime(&sg.r.t_start);
for (i = 0; i < routes; i++) {
- route_add(p, (uint8_t)instance, nhg);
+ route_add(p, vrf_id, (uint8_t)instance, nhg);
if (v4)
p->u.prefix4.s_addr = htonl(++temp);
else
}
}
-void sharp_remove_routes_helper(struct prefix *p, uint8_t instance,
- uint32_t routes)
+void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id,
+ uint8_t instance, uint32_t routes)
{
uint32_t temp, i;
bool v4 = false;
monotime(&sg.r.t_start);
for (i = 0; i < routes; i++) {
- route_delete(p, (uint8_t)instance);
+ route_delete(p, vrf_id, (uint8_t)instance);
if (v4)
p->u.prefix4.s_addr = htonl(++temp);
else
if (installed) {
sg.r.removed_routes = 0;
- sharp_remove_routes_helper(&p, sg.r.inst, sg.r.total_routes);
+ sharp_remove_routes_helper(&p, sg.r.vrf_id,
+ sg.r.inst, sg.r.total_routes);
}
if (installed) {
sg.r.installed_routes = 0;
- sharp_install_routes_helper(&p, sg.r.inst, &sg.r.nhop_group,
+ sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst,
+ &sg.r.nhop_group,
sg.r.total_routes);
}
}
zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP);
}
-void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg)
+void route_add(struct prefix *p, vrf_id_t vrf_id,
+ uint8_t instance, struct nexthop_group *nhg)
{
struct zapi_route api;
struct zapi_nexthop *api_nh;
int i = 0;
memset(&api, 0, sizeof(api));
- api.vrf_id = VRF_DEFAULT;
+ api.vrf_id = vrf_id;
api.type = ZEBRA_ROUTE_SHARP;
api.instance = instance;
api.safi = SAFI_UNICAST;
for (ALL_NEXTHOPS_PTR(nhg, nh)) {
api_nh = &api.nexthops[i];
- api_nh->vrf_id = VRF_DEFAULT;
+ api_nh->vrf_id = nh->vrf_id;
api_nh->type = nh->type;
switch (nh->type) {
case NEXTHOP_TYPE_IPV4:
zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
}
-void route_delete(struct prefix *p, uint8_t instance)
+void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance)
{
struct zapi_route api;
memset(&api, 0, sizeof(api));
- api.vrf_id = VRF_DEFAULT;
+ api.vrf_id = vrf_id;
api.type = ZEBRA_ROUTE_SHARP;
api.safi = SAFI_UNICAST;
api.instance = instance;
return;
}
-void sharp_zebra_nexthop_watch(struct prefix *p, bool import,
+void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import,
bool watch, bool connected)
{
int command;
command = ZEBRA_IMPORT_ROUTE_UNREGISTER;
}
- if (zclient_send_rnh(zclient, command, p, connected, VRF_DEFAULT) < 0)
+ if (zclient_send_rnh(zclient, command, p, connected, vrf_id) < 0)
zlog_warn("%s: Failure to send nexthop to zebra",
__PRETTY_FUNCTION__);
}
extern void sharp_zebra_init(void);
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,
+extern void route_add(struct prefix *p, vrf_id_t, 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 import,
- bool watch, bool connected);
+extern void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance);
+extern void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id,
+ bool import, bool watch, bool connected);
-extern void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
- struct nexthop_group *nhg,
- uint32_t routes);
-extern void sharp_remove_routes_helper(struct prefix *p, uint8_t instance,
- uint32_t routes);
+extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
+ uint8_t instance,
+ struct nexthop_group *nhg,
+ uint32_t routes);
+extern void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id,
+ uint8_t instance, uint32_t routes);
#endif
reinstall = false;
for (si = rn->info; si; si = si->next) {
if (si->nh_vrf_id != nh_vrf_id)
- return;
+ continue;
if (si->type != STATIC_IPV4_GATEWAY
&& si->type != STATIC_IPV4_GATEWAY_IFNAME
&& si->type != STATIC_IPV6_GATEWAY
&& si->type != STATIC_IPV6_GATEWAY_IFNAME)
- return;
+ continue;
orig = si->nh_valid;
if (p->family == AF_INET
static void static_list_delete(struct static_hold_route *shr)
{
- if (shr->vrf_name)
- XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
- if (shr->nhvrf_name)
- XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
- if (shr->dest_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->dest_str);
- if (shr->mask_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->mask_str);
- if (shr->src_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->src_str);
- if (shr->gate_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->gate_str);
- if (shr->ifname)
- XFREE(MTYPE_STATIC_ROUTE, shr->ifname);
- if (shr->flag_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->flag_str);
- if (shr->tag_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->tag_str);
- if (shr->distance_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->distance_str);
- if (shr->label_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->label_str);
- if (shr->table_str)
- XFREE(MTYPE_STATIC_ROUTE, shr->table_str);
+ XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
+ XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
+ XFREE(MTYPE_STATIC_ROUTE, shr->dest_str);
+ XFREE(MTYPE_STATIC_ROUTE, shr->mask_str);
+ XFREE(MTYPE_STATIC_ROUTE, shr->src_str);
+ XFREE(MTYPE_STATIC_ROUTE, shr->gate_str);
+ XFREE(MTYPE_STATIC_ROUTE, shr->ifname);
+ XFREE(MTYPE_STATIC_ROUTE, shr->flag_str);
+ XFREE(MTYPE_STATIC_ROUTE, shr->tag_str);
+ XFREE(MTYPE_STATIC_ROUTE, shr->distance_str);
+ XFREE(MTYPE_STATIC_ROUTE, shr->label_str);
+ XFREE(MTYPE_STATIC_ROUTE, shr->table_str);
XFREE(MTYPE_STATIC_ROUTE, shr);
}
"1.16.160.0/19", "1.16.32.0/20",
"1.16.32.0/21", "16.0.0.0/16"};
- int num_prefixes = sizeof(prefixes) / sizeof(prefixes[0]);
+ int num_prefixes = array_size(prefixes);
for (int i = 0; i < num_prefixes; i++)
add_node(table, prefixes[i]);
{.local_as = 1, .as = 2}, {.local_as = 1, .as = 2},
{.local_as = 1, .as = 2},
};
-int test_mp_list_peer_count = sizeof(test_mp_list_peer) / sizeof(struct peer);
+int test_mp_list_peer_count = array_size(test_mp_list_peer);
struct attr test_mp_list_attr[4];
struct bgp_path_info test_mp_list_info[] = {
{.peer = &test_mp_list_peer[0], .attr = &test_mp_list_attr[0]},
{.peer = &test_mp_list_peer[3], .attr = &test_mp_list_attr[2]},
{.peer = &test_mp_list_peer[4], .attr = &test_mp_list_attr[3]},
};
-int test_mp_list_info_count =
- sizeof(test_mp_list_info) / sizeof(struct bgp_path_info);
+int test_mp_list_info_count = array_size(test_mp_list_info);
static int setup_bgp_mp_list(testcase_t *t)
{
&test_bgp_path_info_mpath_update,
};
-int all_tests_count = (sizeof(all_tests) / sizeof(testcase_t *));
+int all_tests_count = array_size(all_tests);
/*=========================================================
* Test Driver Functions
#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"
.vty_group = VTY_GROUP,
#endif
.caps_p = _caps_p,
- .cap_num_p = sizeof(_caps_p) / sizeof(_caps_p[0]),
+ .cap_num_p = array_size(_caps_p),
.cap_num_i = 0};
struct option longopts[] = {{"help", no_argument, NULL, 'h'},
static bool log_cmp(const void *a, const void *b)
{
if (a == NULL || b == NULL)
- return 0;
+ return false;
return !memcmp(a, b, 2 * sizeof(struct prefix));
}
const char *prefixes[] = {"1.0.1.0/24", "1.0.1.0/25", "1.0.1.128/25",
"1.0.2.0/24", "2.0.0.0/8"};
- num_prefixes = sizeof(prefixes) / sizeof(prefixes[0]);
+ num_prefixes = array_size(prefixes);
printf("\n\nTesting that route_table_iter_pause() works as expected\n");
table = route_table_init();
BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0
BGP table version 1
RIB entries 1, using XXXX bytes of memory
-Peers 4, using XXXX KiB of memory
+Peers 2, using XXXX KiB of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
fc00:0:0:8::1000 4 100 0 0 0 0 0 never Active
--- /dev/null
+bfd
+ peer 2001:db8:4::1 multihop local-address 2001:db8:1::1
+ no shutdown
+ !
+!
--- /dev/null
+router bgp 101
+ bgp router-id 10.254.254.1
+ neighbor r2g peer-group
+ neighbor r2g remote-as external
+ neighbor r2g bfd
+ neighbor r1-eth0 interface peer-group r2g
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ address-family ipv6 unicast
+ neighbor r2g activate
+ exit-address-family
+!
--- /dev/null
+{
+ "10.0.3.0/24": [
+ {
+ "distance": 20,
+ "protocol": "bgp",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "10.0.3.0/24",
+ "internalStatus": 34,
+ "nexthops": [
+ {
+ "interfaceName": "r1-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true,
+ "afi": "ipv6"
+ }
+ ]
+ }
+ ],
+ "10.254.254.2/32": [
+ {
+ "distance": 20,
+ "protocol": "bgp",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "10.254.254.2/32",
+ "internalStatus": 34,
+ "nexthops": [
+ {
+ "interfaceName": "r1-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true,
+ "afi": "ipv6"
+ }
+ ]
+ }
+ ],
+ "10.254.254.1/32": [
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "10.254.254.1/32",
+ "internalStatus": 32,
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "lo",
+ "interfaceIndex": 1,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "2001:db8:4::/64": [
+ {
+ "distance": 20,
+ "protocol": "bgp",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "2001:db8:4::/64",
+ "internalStatus": 34,
+ "nexthops": [
+ {
+ "interfaceName": "r1-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true,
+ "afi": "ipv6"
+ }
+ ]
+ }
+ ],
+ "2001:db8:1::/64": [
+ {
+ "distance": 20,
+ "protocol": "bgp",
+ "internalFlags": 0,
+ "metric": 0,
+ "internalStatus": 2,
+ "prefix": "2001:db8:1::/64",
+ "nexthops": [
+ {
+ "interfaceName": "r1-eth0",
+ "interfaceIndex": 2,
+ "flags": 1,
+ "active": true,
+ "afi": "ipv6"
+ }
+ ]
+ },
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "2001:db8:1::/64",
+ "internalStatus": 32,
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "r1-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+[
+ {
+ "multihop":true,
+ "peer":"2001:db8:4::1",
+ "local":"2001:db8:1::1",
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":300,
+ "transmit-interval":300,
+ "echo-interval":0,
+ "remote-receive-interval":300,
+ "remote-transmit-interval":300,
+ "remote-echo-interval":50
+ },
+ {
+ "multihop":false,
+ "interface":"r1-eth0",
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":300,
+ "transmit-interval":300,
+ "echo-interval":0,
+ "remote-receive-interval":300,
+ "remote-transmit-interval":300,
+ "remote-echo-interval":50
+ }
+]
--- /dev/null
+interface lo
+ ip address 10.254.254.1/32
+!
+interface r1-eth0
+ ipv6 address 2001:db8:1::1/64
+!
--- /dev/null
+router bgp 102
+ bgp router-id 10.254.254.2
+ neighbor r2g peer-group
+ neighbor r2g remote-as external
+ neighbor r2g bfd
+ neighbor r2-eth0 interface peer-group r2g
+ !
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ redistribute connected
+ neighbor r2g activate
+ exit-address-family
+!
--- /dev/null
+{
+ "10.0.3.0/24": [
+ {
+ "distance": 110,
+ "protocol": "ospf",
+ "internalFlags": 0,
+ "metric": 10,
+ "internalStatus": 2,
+ "prefix": "10.0.3.0/24",
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "flags": 1,
+ "interfaceIndex": 3,
+ "interfaceName": "r2-eth1"
+ }
+ ]
+ },
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "10.0.3.0/24",
+ "internalStatus": 32,
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "r2-eth1",
+ "interfaceIndex": 3,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ],
+ "10.254.254.3/32": [
+ {
+ "distance": 110,
+ "protocol": "ospf",
+ "internalFlags": 8,
+ "metric": 20,
+ "selected": true,
+ "installed": true,
+ "prefix": "10.254.254.3/32",
+ "internalStatus": 34,
+ "nexthops": [
+ {
+ "interfaceName": "r2-eth1",
+ "ip": "10.0.3.1",
+ "interfaceIndex": 3,
+ "fib": true,
+ "flags": 3,
+ "active": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.2/32": [
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "10.254.254.2/32",
+ "internalStatus": 32,
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "lo",
+ "interfaceIndex": 1,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ],
+ "10.254.254.1/32": [
+ {
+ "distance": 20,
+ "protocol": "bgp",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "10.254.254.1/32",
+ "internalStatus": 34,
+ "nexthops": [
+ {
+ "interfaceName": "r2-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true,
+ "afi": "ipv6"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "2001:db8:4::/64": [
+ {
+ "distance": 110,
+ "protocol": "ospf6",
+ "internalFlags": 0,
+ "metric": 10,
+ "internalStatus": 2,
+ "prefix": "2001:db8:4::/64",
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "flags": 1,
+ "interfaceIndex": 4,
+ "interfaceName": "r2-eth2"
+ }
+ ]
+ },
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "2001:db8:4::/64",
+ "internalStatus": 32,
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "r2-eth2",
+ "interfaceIndex": 4,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1::/64": [
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "2001:db8:1::/64",
+ "internalStatus": 32,
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "r2-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+interface r2-eth2
+ ipv6 ospf6 bfd
+!
+router ospf6
+ ospf6 router-id 10.254.254.2
+ redistribute connected
+ redistribute bgp
+ interface r2-eth2 area 0.0.0.1
+!
--- /dev/null
+interface r2-eth1
+ ip ospf area 0.0.0.1
+ ip ospf bfd
+!
+router ospf
+ ospf router-id 10.254.254.2
+ redistribute connected
+ redistribute bgp
+!
--- /dev/null
+[
+ {
+ "status": "up",
+ "transmit-interval": 300,
+ "remote-receive-interval": 300,
+ "echo-interval": 0,
+ "diagnostic": "ok",
+ "multihop": false,
+ "interface": "r2-eth0",
+ "remote-transmit-interval": 300,
+ "receive-interval": 300,
+ "remote-echo-interval": 50,
+ "remote-diagnostic": "ok"
+ },
+ {
+ "status": "up",
+ "transmit-interval": 300,
+ "remote-receive-interval": 300,
+ "echo-interval": 0,
+ "diagnostic": "ok",
+ "multihop": false,
+ "interface": "r2-eth2",
+ "remote-transmit-interval": 300,
+ "receive-interval": 300,
+ "remote-echo-interval": 50,
+ "remote-diagnostic": "ok"
+ },
+ {
+ "status": "up",
+ "transmit-interval": 300,
+ "remote-receive-interval": 300,
+ "echo-interval": 0,
+ "diagnostic": "ok",
+ "multihop": false,
+ "interface": "r2-eth1",
+ "remote-transmit-interval": 300,
+ "receive-interval": 300,
+ "remote-echo-interval": 50,
+ "remote-diagnostic": "ok",
+ "peer": "10.0.3.1"
+ }
+]
--- /dev/null
+ip forwarding
+ipv6 forwarding
+!
+interface lo
+ ip address 10.254.254.2/32
+!
+interface r2-eth0
+ ipv6 address 2001:db8:1::2/64
+!
+interface r2-eth1
+ ip address 10.0.3.2/24
+!
+interface r2-eth2
+ ipv6 address 2001:db8:4::2/64
+!
--- /dev/null
+{
+ "10.0.3.0/24": [
+ {
+ "distance": 110,
+ "protocol": "ospf",
+ "internalFlags": 0,
+ "metric": 10,
+ "internalStatus": 0,
+ "prefix": "10.0.3.0/24",
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "flags": 1,
+ "interfaceIndex": 2,
+ "interfaceName": "r3-eth0"
+ }
+ ]
+ },
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "10.0.3.0/24",
+ "internalStatus": 32,
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "r3-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ],
+ "10.254.254.3/32": [
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "10.254.254.3/32",
+ "internalStatus": 32,
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "lo",
+ "interfaceIndex": 1,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ],
+ "10.254.254.2/32": [
+ {
+ "distance": 110,
+ "protocol": "ospf",
+ "internalFlags": 8,
+ "metric": 20,
+ "selected": true,
+ "installed": true,
+ "prefix": "10.254.254.2/32",
+ "internalStatus": 34,
+ "nexthops": [
+ {
+ "interfaceName": "r3-eth0",
+ "ip": "10.0.3.2",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ],
+ "10.254.254.1/32": [
+ {
+ "distance": 110,
+ "protocol": "ospf",
+ "internalFlags": 8,
+ "metric": 20,
+ "selected": true,
+ "installed": true,
+ "prefix": "10.254.254.1/32",
+ "internalStatus": 34,
+ "nexthops": [
+ {
+ "interfaceName": "r3-eth0",
+ "ip": "10.0.3.2",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true,
+ "afi": "ipv4"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+interface r3-eth0
+ ip ospf area 0.0.0.1
+ ip ospf bfd
+!
+router ospf
+ ospf router-id 10.254.254.3
+ redistribute connected
+!
--- /dev/null
+[
+ {
+ "status": "up",
+ "transmit-interval": 300,
+ "remote-receive-interval": 300,
+ "echo-interval": 0,
+ "diagnostic": "ok",
+ "multihop": false,
+ "interface": "r3-eth0",
+ "remote-transmit-interval": 300,
+ "receive-interval": 300,
+ "remote-echo-interval": 50,
+ "remote-diagnostic": "ok",
+ "peer": "10.0.3.2"
+ }
+]
--- /dev/null
+interface lo
+ ip address 10.254.254.3/32
+!
+interface r3-eth0
+ ip address 10.0.3.1/24
+!
--- /dev/null
+bfd
+ peer 2001:db8:1::1 multihop local-address 2001:db8:4::1
+ no shutdown
+ !
+!
--- /dev/null
+{
+ "10.254.254.4/32": [
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "10.254.254.4/32",
+ "internalStatus": 32,
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "lo",
+ "interfaceIndex": 1,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "2001:db8:4::/64": [
+ {
+ "distance": 110,
+ "protocol": "ospf6",
+ "internalFlags": 0,
+ "metric": 10,
+ "internalStatus": 2,
+ "prefix": "2001:db8:4::/64",
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "flags": 1,
+ "interfaceIndex": 2,
+ "interfaceName": "r4-eth0"
+ }
+ ]
+ },
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "installed": true,
+ "prefix": "2001:db8:4::/64",
+ "internalStatus": 32,
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "r4-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1::/64": [
+ {
+ "distance": 110,
+ "protocol": "ospf6",
+ "internalFlags": 8,
+ "metric": 10,
+ "selected": true,
+ "installed": true,
+ "prefix": "2001:db8:1::/64",
+ "internalStatus": 34,
+ "nexthops": [
+ {
+ "interfaceName": "r4-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true,
+ "afi": "ipv6"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+interface r4-eth0
+ ipv6 ospf6 bfd
+!
+router ospf6
+ ospf6 router-id 10.254.254.4
+ redistribute connected
+ interface r4-eth0 area 0.0.0.1
+!
--- /dev/null
+[
+ {
+ "multihop":true,
+ "peer":"2001:db8:1::1",
+ "local":"2001:db8:4::1",
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":300,
+ "transmit-interval":300,
+ "echo-interval":0,
+ "remote-receive-interval":300,
+ "remote-transmit-interval":300,
+ "remote-echo-interval":50
+ },
+ {
+ "multihop":false,
+ "interface":"r4-eth0",
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":300,
+ "transmit-interval":300,
+ "echo-interval":0,
+ "remote-receive-interval":300,
+ "remote-transmit-interval":300,
+ "remote-echo-interval":50
+ }
+]
--- /dev/null
+interface lo
+ ip address 10.254.254.4/32
+!
+interface r4-eth0
+ ipv6 address 2001:db8:4::1/64
+!
--- /dev/null
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="bfd-topo2";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r4 [
+ shape=doubleoctagon
+ label="r4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n2001:db8:1::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n10.0.3.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw3 [
+ shape=oval,
+ label="sw3\n2001:db8:4::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- sw1 [label="eth0"];
+ r2 -- sw1 [label="eth0"];
+
+ r2 -- sw2 [label="eth1"];
+ r3 -- sw2 [label="eth0"];
+
+ r2 -- sw3 [label="eth2"];
+ r4 -- sw3 [label="eth0"];
+}
--- /dev/null
+#!/usr/bin/env python
+
+#
+# test_bfd_topo2.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bfd_topo2.py: Test the FRR/Quagga BFD daemon with multihop and BGP
+unnumbered.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+
+class BFDTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 4 routers.
+ for routern in range(1, 5):
+ tgen.add_router('r{}'.format(routern))
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+ switch = tgen.add_switch('s2')
+ switch.add_link(tgen.gears['r2'])
+ switch.add_link(tgen.gears['r3'])
+
+ switch = tgen.add_switch('s3')
+ switch.add_link(tgen.gears['r2'])
+ switch.add_link(tgen.gears['r4'])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(BFDTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BFD,
+ os.path.join(CWD, '{}/bfdd.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF,
+ os.path.join(CWD, '{}/ospfd.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF6,
+ os.path.join(CWD, '{}/ospf6d.conf'.format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+ # Verify that we are using the proper version and that the BFD
+ # daemon exists.
+ for router in router_list.values():
+ # Check for Version
+ if router.has_version('<', '5.1'):
+ tgen.set_error('Unsupported FRR version')
+ break
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_protocols_convergence():
+ """
+ Assert that all protocols have converged before checking for the BFD
+ statuses as they depend on it.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Check IPv4 routing tables.
+ logger.info("Checking IPv4 routes for convergence")
+ for router in tgen.routers().values():
+ json_file = '{}/{}/ipv4_routes.json'.format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info('skipping file {}'.format(json_file))
+ continue
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip route json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=160,
+ wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ # Check IPv6 routing tables.
+ logger.info("Checking IPv6 routes for convergence")
+ for router in tgen.routers().values():
+ json_file = '{}/{}/ipv6_routes.json'.format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info('skipping file {}'.format(json_file))
+ continue
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ipv6 route json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=160,
+ wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+
+def test_bfd_connection():
+ "Assert that the BFD peers can find themselves."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('waiting for bfd peers to go up')
+
+ for router in tgen.routers().values():
+ json_file = '{}/{}/peers.json'.format(CWD, router.name)
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show bfd peers json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip('Memory leak test/report is disabled')
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
exec docker build --pull \
--compress \
- -t frrouting/frr:topotests-latest \
+ -t frrouting/topotests:latest \
.
fi
if [ "${TOPOTEST_PULL:-1}" = "1" ]; then
- docker pull frrouting/frr:topotests-latest
+ docker pull frrouting/topotests:latest
fi
set -- --rm -i \
-e "TOPOTEST_SANITIZER=$TOPOTEST_SANITIZER" \
--privileged \
$TOPOTEST_OPTIONS \
- frrouting/frr:topotests-latest "$@"
+ frrouting/topotests:latest "$@"
if [ -t 0 ]; then
set -- -t "$@"
!
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'
--- /dev/null
+#!/usr/bin/env python
+#
+# mcast-rx.py
+#
+# Copyright (c) 2018 Cumulus Networks, Inc.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND Cumulus Networks DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+"""
+Subscribe to a multicast group so that the kernel sends an IGMP JOIN
+for the multicast group we subscribed to.
+"""
+
+import argparse
+import logging
+import re
+import os
+import socket
+import subprocess
+import struct
+import sys
+import time
+
+
+def ifname_to_ifindex(ifname):
+ output = subprocess.check_output("ip link show %s" % ifname, shell=True)
+ first_line = output.split('\n')[0]
+ re_index = re.search('^(\d+):', first_line)
+
+ if re_index:
+ return int(re_index.group(1))
+
+ log.error("Could not parse the ifindex for %s out of\n%s" % (ifname, first_line))
+ return None
+
+
+# Thou shalt be root
+if os.geteuid() != 0:
+ sys.stderr.write('ERROR: You must have root privileges\n')
+ sys.exit(1)
+
+
+logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)5s: %(message)s')
+
+# Color the errors and warnings in red
+logging.addLevelName(logging.ERROR, "\033[91m %s\033[0m" % logging.getLevelName(logging.ERROR))
+logging.addLevelName(logging.WARNING, "\033[91m%s\033[0m" % logging.getLevelName(logging.WARNING))
+log = logging.getLogger(__name__)
+
+parser = argparse.ArgumentParser(description='Multicast RX utility',
+ version='1.0.0')
+parser.add_argument('group', help='Multicast IP')
+parser.add_argument('ifname', help='Interface name')
+parser.add_argument('--port', help='UDP port', default=1000)
+parser.add_argument('--sleep', help='Time to sleep before we stop waiting',
+ default = 5)
+args = parser.parse_args()
+
+# Create the datagram socket
+sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+sock.bind((args.group, args.port))
+
+newpid = os.fork()
+
+if newpid == 0:
+ ifindex = ifname_to_ifindex(args.ifname)
+ mreq = struct.pack("=4sLL", socket.inet_aton(args.group), socket.INADDR_ANY, ifindex)
+ sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
+ time.sleep(float(args.sleep))
+ sock.close()
--- /dev/null
+#!/usr/bin/env python
+#
+# mcast-tx.py
+#
+# Copyright (c) 2018 Cumulus Networks, Inc.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND Cumulus Networks DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+import argparse
+import logging
+import socket
+import struct
+import time
+
+
+logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)5s: %(message)s')
+
+# Color the errors and warnings in red
+logging.addLevelName(logging.ERROR, "\033[91m %s\033[0m" % logging.getLevelName(logging.ERROR))
+logging.addLevelName(logging.WARNING, "\033[91m%s\033[0m" % logging.getLevelName(logging.WARNING))
+log = logging.getLogger(__name__)
+
+parser = argparse.ArgumentParser(description='Multicast packet generator', version='1.0.0')
+parser.add_argument('group', help='Multicast IP')
+parser.add_argument('ifname', help='Interface name')
+parser.add_argument('--port', type=int, help='UDP port number', default=1000)
+parser.add_argument('--ttl', type=int, help='time-to-live', default=20)
+parser.add_argument('--count', type=int, help='Packets to send', default=1)
+parser.add_argument('--interval', type=int, help='ms between packets', default=100)
+args = parser.parse_args()
+
+# Create the datagram socket
+sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+# IN.SO_BINDTODEVICE is not defined in some releases of python but it is 25
+# https://github.com/sivel/bonding/issues/10
+#
+# Bind our socket to ifname
+sock.setsockopt(socket.SOL_SOCKET,
+ 25,
+ struct.pack("%ds" % len(args.ifname), args.ifname))
+
+# We need to make sure our sendto() finishes before we close the socket
+sock.setblocking(1)
+
+# Set the time-to-live
+sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, struct.pack('b', args.ttl))
+
+ms = args.interval / 1000.0
+
+# Send data to the multicast group
+for x in xrange(args.count):
+ log.info('TX multicast UDP packet to %s:%d on %s' % (args.group, args.port, args.ifname))
+ sent = sock.sendto('foobar %d' % x, (args.group, args.port))
+
+ if args.count > 1 and ms:
+ time.sleep(ms)
+
+sock.close()
--- /dev/null
+hostname r1
+!
+interface r1-eth0
+ ip igmp
+ ip pim sm
+!
+interface lo
+ ip pim sm
+!
+ip pim rp 10.254.0.1
--- /dev/null
+hostname r1
+!
+interface r1-eth0
+ ip address 10.0.20.1/24
+!
+interface lo
+ ip address 10.254.0.1/32
+!
--- /dev/null
+hostname r2
--- /dev/null
+hostname r2
+!
+interface r2-eth0
+ ip address 10.0.20.2/24
+!
+interface lo
+ ip address 10.254.0.2/32
+!
--- /dev/null
+#!/usr/bin/env python
+
+#
+# test_pim.py
+#
+# Copyright (c) 2018 Cumulus Networks, Inc.
+# Donald Sharp
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND Cumulus Networks DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_pim.py: Test pim
+"""
+
+import os
+import sys
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+from mininet.topo import Topo
+
+class PIMTopo(Topo):
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ for routern in range(1, 3):
+ tgen.add_router('r{}'.format(routern))
+
+ # r1 <- sw1 -> r2
+ sw = tgen.add_switch('sw1')
+ sw.add_link(tgen.gears['r1'])
+ sw.add_link(tgen.gears['r2'])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(PIMTopo, mod.__name__)
+ tgen.start_topology()
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in tgen.routers().iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_PIM,
+ os.path.join(CWD, '{}/pimd.conf'.format(rname))
+ )
+
+ # After loading the configurations, this function loads configured daemons.
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+def test_pim_send_mcast_stream():
+ "Establish a Multicast stream from r2 -> r1 and then ensure S,G is created as appropriate"
+ logger.info("Establish a Mcast stream from r2->r1 and then ensure S,G created")
+
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r2 = tgen.gears['r2']
+ r1 = tgen.gears['r1']
+
+ # Let's establish a S,G stream from r2 -> r1
+ CWD = os.path.dirname(os.path.realpath(__file__))
+ r2.run("{}/mcast-tx.py --ttl 5 --count 5 --interval 10 229.1.1.1 r2-eth0 > /tmp/bar".format(CWD))
+
+ # Let's see that it shows up and we have established some basic state
+ out = r1.vtysh_cmd("show ip pim upstream json", isjson=True)
+ expected = {
+ '229.1.1.1': {
+ '10.0.20.2': {
+ 'firstHopRouter': 1,
+ 'joinState': 'NotJoined',
+ 'regState': 'RegPrune',
+ 'inboundInterface': 'r1-eth0',
+ }
+ }
+ }
+
+ assert topotest.json_cmp(out, expected) is None, 'failed to converge pim'
+
+
+def test_pim_igmp_report():
+ "Send a igmp report from r2->r1 and ensure that the *,G state is created on r1"
+ logger.info("Send a igmp report from r2-r1 and ensure *,G created")
+
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r2 = tgen.gears['r2']
+ r1 = tgen.gears['r1']
+
+ # Let's send a igmp report from r2->r1
+ CWD = os.path.dirname(os.path.realpath(__file__))
+ r2.run("{}/mcast-rx.py 229.1.1.2 r2-eth0 &".format(CWD))
+
+ out = r1.vtysh_cmd("show ip pim upstream json", isjson=True)
+ expected = {
+ '229.1.1.2': {
+ '*': {
+ 'sourceIgmp': 1,
+ 'joinState': 'Joined',
+ 'regState': 'RegNoInfo',
+ 'sptBit': 0,
+ }
+ }
+ }
+
+ assert topotest.json_cmp(out, expected) is None, 'failed to converge pim'
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip('Memory leak test/report is disabled')
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
--- /dev/null
+/// Remove casting the values returned by memory allocation functions
+/// like XMALLOC and XCALLOC.
+///
+// This makes an effort to find cases of casting of values returned by #
+// XMALLOC and XCALLOC and removes the casting as it is not required. The
+// result in the patch case may need some reformatting.
+//
+// Confidence: High
+// Copyright: (C) 2014 Himangi Saraogi GPLv2.
+// Copyright: (C) 2017 Himanshu Jha GPLv2.
+// Copyright: (C) 2019 Quentin Young GPLv2.
+// Comments:
+// Options: --no-includes --include-headers
+//
+
+virtual context
+virtual patch
+virtual org
+virtual report
+
+@initialize:python@
+@@
+import re
+pattern = '__'
+m = re.compile(pattern)
+
+@r1 depends on context || patch@
+type T;
+@@
+
+ (T *)
+ \(XMALLOC\|XCALLOC\)(...)
+
+//----------------------------------------------------------
+// For context mode
+//----------------------------------------------------------
+
+@script:python depends on context@
+t << r1.T;
+@@
+
+if m.search(t) != None:
+ cocci.include_match(False)
+
+@depends on context && r1@
+type r1.T;
+@@
+
+* (T *)
+ \(XMALLOC\|XCALLOC\)(...)
+
+//----------------------------------------------------------
+// For patch mode
+//----------------------------------------------------------
+
+@script:python depends on patch@
+t << r1.T;
+@@
+
+if m.search(t) != None:
+ cocci.include_match(False)
+
+@depends on patch && r1@
+type r1.T;
+@@
+
+- (T *)
+ \(XMALLOC\|XCALLOC\)(...)
+
+//----------------------------------------------------------
+// For org and report mode
+//----------------------------------------------------------
+
+@r2 depends on org || report@
+type T;
+position p;
+@@
+
+ (T@p *)
+ \(XMALLOC\|XCALLOC\)(...)
+
+@script:python depends on org@
+p << r2.p;
+t << r2.T;
+@@
+
+if m.search(t) != None:
+ cocci.include_match(False)
+else:
+ coccilib.org.print_safe_todo(p[0], t)
+
+@script:python depends on report@
+p << r2.p;
+t << r2.T;
+@@
+
+if m.search(t) != None:
+ cocci.include_match(False)
+else:
+ msg="WARNING: casting value returned by memory allocation function to (%s *) is useless." % (t)
+ coccilib.report.print_report(p[0], msg)
--- /dev/null
+/// Use array_size instead of dividing sizeof array with sizeof an element
+///
+//# This makes an effort to find cases where array_size can be used such as
+//# where there is a division of sizeof the array by the sizeof its first
+//# element or by any indexed element or the element type. It replaces the
+//# division of the two sizeofs by array_size.
+//
+// Confidence: High
+// Copyright: (C) 2014 Himangi Saraogi. GPLv2.
+// Copyright: (C) 2019 Quentin Young. GPLv2.
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+//----------------------------------------------------------
+// For context mode
+//----------------------------------------------------------
+
+@depends on context@
+type T;
+T[] E;
+@@
+(
+* (sizeof(E)/sizeof(*E))
+|
+* (sizeof(E)/sizeof(E[...]))
+|
+* (sizeof(E)/sizeof(T))
+)
+
+//----------------------------------------------------------
+// For patch mode
+//----------------------------------------------------------
+
+@depends on patch@
+type T;
+T[] E;
+@@
+(
+- (sizeof(E)/sizeof(*E))
++ array_size(E)
+|
+- (sizeof(E)/sizeof(E[...]))
++ array_size(E)
+|
+- (sizeof(E)/sizeof(T))
++ array_size(E)
+)
+
+//----------------------------------------------------------
+// For org and report mode
+//----------------------------------------------------------
+
+@r depends on (org || report)@
+type T;
+T[] E;
+position p;
+@@
+(
+ (sizeof(E)@p /sizeof(*E))
+|
+ (sizeof(E)@p /sizeof(E[...]))
+|
+ (sizeof(E)@p /sizeof(T))
+)
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING should use array_size")
+
+@script:python depends on report@
+p << r.p;
+@@
+
+msg="WARNING: Use array_size"
+coccilib.report.print_report(p[0], msg)
+
--- /dev/null
+/// Use ARRAY_SIZE instead of dividing sizeof array with sizeof an element
+///
+//# This makes an effort to find cases where the argument to sizeof is wrong
+//# in memory allocation functions by checking the type of the allocated memory
+//# when it is a double pointer and ensuring the sizeof argument takes a pointer
+//# to the the memory being allocated. There are false positives in cases the
+//# sizeof argument is not used in constructing the return value. The result
+//# may need some reformatting.
+//
+// Confidence: Moderate
+// Copyright: (C) 2014 Himangi Saraogi. GPLv2.
+// Comments:
+// Options:
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+//----------------------------------------------------------
+// For context mode
+//----------------------------------------------------------
+
+@depends on context disable sizeof_type_expr@
+type T;
+T **x;
+@@
+
+ x =
+ <+...sizeof(
+* T
+ )...+>
+
+//----------------------------------------------------------
+// For patch mode
+//----------------------------------------------------------
+
+@depends on patch disable sizeof_type_expr@
+type T;
+T **x;
+@@
+
+ x =
+ <+...sizeof(
+- T
++ *x
+ )...+>
+
+//----------------------------------------------------------
+// For org and report mode
+//----------------------------------------------------------
+
+@r depends on (org || report) disable sizeof_type_expr@
+type T;
+T **x;
+position p;
+@@
+
+ x =
+ <+...sizeof(
+ T@p
+ )...+>
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING sizeof argument should be pointer type, not structure type")
+
+@script:python depends on report@
+p << r.p;
+@@
+
+msg="WARNING: Use correct pointer type argument for sizeof"
+coccilib.report.print_report(p[0], msg)
+
--- /dev/null
+/// Compare pointer-typed values to NULL rather than 0
+///
+//# This makes an effort to choose between !x and x == NULL. !x is used
+//# if it has previously been used with the function used to initialize x.
+//# This relies on type information. More type information can be obtained
+//# using the option -all_includes and the option -I to specify an
+//# include path.
+//
+// Confidence: High
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Requires: 1.0.0
+// Options:
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@initialize:ocaml@
+@@
+let negtable = Hashtbl.create 101
+
+@depends on patch@
+expression *E;
+identifier f;
+@@
+
+(
+ (E = f(...)) ==
+- 0
++ NULL
+|
+ (E = f(...)) !=
+- 0
++ NULL
+|
+- 0
++ NULL
+ == (E = f(...))
+|
+- 0
++ NULL
+ != (E = f(...))
+)
+
+
+@t1 depends on !patch@
+expression *E;
+identifier f;
+position p;
+@@
+
+(
+ (E = f(...)) ==
+* 0@p
+|
+ (E = f(...)) !=
+* 0@p
+|
+* 0@p
+ == (E = f(...))
+|
+* 0@p
+ != (E = f(...))
+)
+
+@script:python depends on org@
+p << t1.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0")
+
+@script:python depends on report@
+p << t1.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING comparing pointer to 0")
+
+// Tests of returned values
+
+@s@
+identifier f;
+expression E,E1;
+@@
+
+ E = f(...)
+ ... when != E = E1
+ !E
+
+@script:ocaml depends on s@
+f << s.f;
+@@
+
+try let _ = Hashtbl.find negtable f in ()
+with Not_found -> Hashtbl.add negtable f ()
+
+@ r disable is_zero,isnt_zero exists @
+expression *E;
+identifier f;
+@@
+
+E = f(...)
+...
+(E == 0
+|E != 0
+|0 == E
+|0 != E
+)
+
+@script:ocaml@
+f << r.f;
+@@
+
+try let _ = Hashtbl.find negtable f in ()
+with Not_found -> include_match false
+
+// This rule may lead to inconsistent path problems, if E is defined in two
+// places
+@ depends on patch disable is_zero,isnt_zero @
+expression *E;
+expression E1;
+identifier r.f;
+@@
+
+E = f(...)
+<...
+(
+- E == 0
++ !E
+|
+- E != 0
++ E
+|
+- 0 == E
++ !E
+|
+- 0 != E
++ E
+)
+...>
+?E = E1
+
+@t2 depends on !patch disable is_zero,isnt_zero @
+expression *E;
+expression E1;
+identifier r.f;
+position p1;
+position p2;
+@@
+
+E = f(...)
+<...
+(
+* E == 0@p1
+|
+* E != 0@p2
+|
+* 0@p1 == E
+|
+* 0@p1 != E
+)
+...>
+?E = E1
+
+@script:python depends on org@
+p << t2.p1;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0, suggest !E")
+
+@script:python depends on org@
+p << t2.p2;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0")
+
+@script:python depends on report@
+p << t2.p1;
+@@
+
+coccilib.report.print_report(p[0], "WARNING comparing pointer to 0, suggest !E")
+
+@script:python depends on report@
+p << t2.p2;
+@@
+
+coccilib.report.print_report(p[0], "WARNING comparing pointer to 0")
+
+@ depends on patch disable is_zero,isnt_zero @
+expression *E;
+@@
+
+(
+ E ==
+- 0
++ NULL
+|
+ E !=
+- 0
++ NULL
+|
+- 0
++ NULL
+ == E
+|
+- 0
++ NULL
+ != E
+)
+
+@ t3 depends on !patch disable is_zero,isnt_zero @
+expression *E;
+position p;
+@@
+
+(
+* E == 0@p
+|
+* E != 0@p
+|
+* 0@p == E
+|
+* 0@p != E
+)
+
+@script:python depends on org@
+p << t3.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0")
+
+@script:python depends on report@
+p << t3.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING comparing pointer to 0")
--- /dev/null
+/// Remove unneeded conversion to bool
+///
+//# Relational and logical operators evaluate to bool,
+//# explicit conversion is overly verbose and unneeded.
+//
+// Copyright: (C) 2016 Andrew F. Davis <afd@ti.com> GPLv2.
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+//----------------------------------------------------------
+// For patch mode
+//----------------------------------------------------------
+
+@depends on patch@
+expression A, B;
+symbol true, false;
+@@
+
+(
+ A == B
+|
+ A != B
+|
+ A > B
+|
+ A < B
+|
+ A >= B
+|
+ A <= B
+|
+ A && B
+|
+ A || B
+)
+- ? true : false
+
+//----------------------------------------------------------
+// For context mode
+//----------------------------------------------------------
+
+@r depends on !patch@
+expression A, B;
+symbol true, false;
+position p;
+@@
+
+(
+ A == B
+|
+ A != B
+|
+ A > B
+|
+ A < B
+|
+ A >= B
+|
+ A <= B
+|
+ A && B
+|
+ A || B
+)
+* ? true : false@p
+
+//----------------------------------------------------------
+// For org mode
+//----------------------------------------------------------
+
+@script:python depends on r&&org@
+p << r.p;
+@@
+
+msg = "WARNING: conversion to bool not needed here"
+coccilib.org.print_todo(p[0], msg)
+
+//----------------------------------------------------------
+// For report mode
+//----------------------------------------------------------
+
+@script:python depends on r&&report@
+p << r.p;
+@@
+
+msg = "WARNING: conversion to bool not needed here"
+coccilib.report.print_report(p[0], msg)
--- /dev/null
+/// Bool initializations should use true and false. Bool tests don't need
+/// comparisons. Based on contributions from Joe Perches, Rusty Russell
+/// and Bruce W Allan.
+///
+// Confidence: High
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Options: --include-headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@boolok@
+symbol true,false;
+@@
+(
+true
+|
+false
+)
+
+@depends on patch@
+bool t;
+@@
+
+(
+- t == true
++ t
+|
+- true == t
++ t
+|
+- t != true
++ !t
+|
+- true != t
++ !t
+|
+- t == false
++ !t
+|
+- false == t
++ !t
+|
+- t != false
++ t
+|
+- false != t
++ t
+)
+
+@depends on patch disable is_zero, isnt_zero@
+bool t;
+@@
+
+(
+- t == 1
++ t
+|
+- t != 1
++ !t
+|
+- t == 0
++ !t
+|
+- t != 0
++ t
+)
+
+@depends on patch && boolok@
+bool b;
+@@
+(
+ b =
+- 0
++ false
+|
+ b =
+- 1
++ true
+)
+
+// ---------------------------------------------------------------------
+
+@r1 depends on !patch@
+bool t;
+position p;
+@@
+
+(
+* t@p == true
+|
+* true == t@p
+|
+* t@p != true
+|
+* true != t@p
+|
+* t@p == false
+|
+* false == t@p
+|
+* t@p != false
+|
+* false != t@p
+)
+
+@r2 depends on !patch disable is_zero, isnt_zero@
+bool t;
+position p;
+@@
+
+(
+* t@p == 1
+|
+* t@p != 1
+|
+* t@p == 0
+|
+* t@p != 0
+)
+
+@r3 depends on !patch && boolok@
+bool b;
+position p1;
+@@
+(
+*b@p1 = 0
+|
+*b@p1 = 1
+)
+
+@r4 depends on !patch@
+bool b;
+position p2;
+identifier i;
+constant c != {0,1};
+@@
+(
+ b = i
+|
+*b@p2 = c
+)
+
+@script:python depends on org@
+p << r1.p;
+@@
+
+cocci.print_main("WARNING: Comparison to bool",p)
+
+@script:python depends on org@
+p << r2.p;
+@@
+
+cocci.print_main("WARNING: Comparison of 0/1 to bool variable",p)
+
+@script:python depends on org@
+p1 << r3.p1;
+@@
+
+cocci.print_main("WARNING: Assignment of 0/1 to bool variable",p1)
+
+@script:python depends on org@
+p2 << r4.p2;
+@@
+
+cocci.print_main("ERROR: Assignment of non-0/1 constant to bool variable",p2)
+
+@script:python depends on report@
+p << r1.p;
+@@
+
+coccilib.report.print_report(p[0],"WARNING: Comparison to bool")
+
+@script:python depends on report@
+p << r2.p;
+@@
+
+coccilib.report.print_report(p[0],"WARNING: Comparison of 0/1 to bool variable")
+
+@script:python depends on report@
+p1 << r3.p1;
+@@
+
+coccilib.report.print_report(p1[0],"WARNING: Assignment of 0/1 to bool variable")
+
+@script:python depends on report@
+p2 << r4.p2;
+@@
+
+coccilib.report.print_report(p2[0],"ERROR: Assignment of non-0/1 constant to bool variable")
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/// Return statements in functions returning bool should use
+/// true/false instead of 1/0.
+//
+// Confidence: High
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual report
+virtual context
+
+@r1 depends on patch@
+identifier fn;
+typedef bool;
+symbol false;
+symbol true;
+@@
+
+bool fn ( ... )
+{
+<...
+return
+(
+- 0
++ false
+|
+- 1
++ true
+)
+ ;
+...>
+}
+
+@r2 depends on report || context@
+identifier fn;
+position p;
+@@
+
+bool fn ( ... )
+{
+<...
+return
+(
+* 0@p
+|
+* 1@p
+)
+ ;
+...>
+}
+
+
+@script:python depends on report@
+p << r2.p;
+fn << r2.fn;
+@@
+
+msg = "WARNING: return of 0/1 in function '%s' with return type bool" % fn
+coccilib.report.print_report(p[0], msg)
--- /dev/null
+///Find conditions where if and else branch are functionally
+// identical.
+//
+// There can be false positives in cases where the positional
+// information is used (as with lockdep) or where the identity
+// is a placeholder for not yet handled cases.
+// Unfortunately there also seems to be a tendency to use
+// the last if else/else as a "default behavior" - which some
+// might consider a legitimate coding pattern. From discussion
+// on kernelnewbies though it seems that this is not really an
+// accepted pattern and if at all it would need to be commented
+//
+// In the Linux kernel it does not seem to actually report
+// false positives except for those that were documented as
+// being intentional.
+// the two known cases are:
+// arch/sh/kernel/traps_64.c:read_opcode()
+// } else if ((pc & 1) == 0) {
+// /* SHcompact */
+// /* TODO : provide handling for this. We don't really support
+// user-mode SHcompact yet, and for a kernel fault, this would
+// have to come from a module built for SHcompact. */
+// return -EFAULT;
+// } else {
+// /* misaligned */
+// return -EFAULT;
+// }
+// fs/kernfs/file.c:kernfs_fop_open()
+// * Both paths of the branch look the same. They're supposed to
+// * look that way and give @of->mutex different static lockdep keys.
+// */
+// if (has_mmap)
+// mutex_init(&of->mutex);
+// else
+// mutex_init(&of->mutex);
+//
+// All other cases look like bugs or at least lack of documentation
+//
+// Confidence: Moderate
+// Copyright: (C) 2016 Nicholas Mc Guire, OSADL. GPLv2.
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual org
+virtual report
+
+@cond@
+statement S1;
+position p;
+@@
+
+* if@p (...) S1 else S1
+
+@script:python depends on org@
+p << cond.p;
+@@
+
+cocci.print_main("WARNING: possible condition with no effect (if == else)",p)
+
+@script:python depends on report@
+p << cond.p;
+@@
+
+coccilib.report.print_report(p[0],"WARNING: possible condition with no effect (if == else)")
--- /dev/null
+///
+/// A variable is dereferenced under a NULL test.
+/// Even though it is known to be NULL.
+///
+// Confidence: Moderate
+// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
+// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
+// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments: -I ... -all_includes can give more complete results
+// Options:
+
+virtual context
+virtual org
+virtual report
+
+// The following two rules are separate, because both can match a single
+// expression in different ways
+@pr1 expression@
+expression E;
+identifier f;
+position p1;
+@@
+
+ (E != NULL && ...) ? <+...E->f@p1...+> : ...
+
+@pr2 expression@
+expression E;
+identifier f;
+position p2;
+@@
+
+(
+ (E != NULL) && ... && <+...E->f@p2...+>
+|
+ (E == NULL) || ... || <+...E->f@p2...+>
+|
+ sizeof(<+...E->f@p2...+>)
+)
+
+@ifm@
+expression *E;
+statement S1,S2;
+position p1;
+@@
+
+if@p1 ((E == NULL && ...) || ...) S1 else S2
+
+// For org and report modes
+
+@r depends on !context && (org || report) exists@
+expression subE <= ifm.E;
+expression *ifm.E;
+expression E1,E2;
+identifier f;
+statement S1,S2,S3,S4;
+iterator iter;
+position p!={pr1.p1,pr2.p2};
+position ifm.p1;
+@@
+
+if@p1 ((E == NULL && ...) || ...)
+{
+ ... when != if (...) S1 else S2
+(
+ iter(subE,...) S4 // no use
+|
+ list_remove_head(E2,subE,...)
+|
+ subE = E1
+|
+ for(subE = E1;...;...) S4
+|
+ subE++
+|
+ ++subE
+|
+ --subE
+|
+ subE--
+|
+ &subE
+|
+ E->f@p // bad use
+)
+ ... when any
+ return ...;
+}
+else S3
+
+@script:python depends on !context && !org && report@
+p << r.p;
+p1 << ifm.p1;
+x << ifm.E;
+@@
+
+msg="ERROR: %s is NULL but dereferenced." % (x)
+coccilib.report.print_report(p[0], msg)
+cocci.include_match(False)
+
+@script:python depends on !context && org && !report@
+p << r.p;
+p1 << ifm.p1;
+x << ifm.E;
+@@
+
+msg="ERROR: %s is NULL but dereferenced." % (x)
+msg_safe=msg.replace("[","@(").replace("]",")")
+cocci.print_main(msg_safe,p)
+cocci.include_match(False)
+
+@s depends on !context && (org || report) exists@
+expression subE <= ifm.E;
+expression *ifm.E;
+expression E1,E2;
+identifier f;
+statement S1,S2,S3,S4;
+iterator iter;
+position p!={pr1.p1,pr2.p2};
+position ifm.p1;
+@@
+
+if@p1 ((E == NULL && ...) || ...)
+{
+ ... when != if (...) S1 else S2
+(
+ iter(subE,...) S4 // no use
+|
+ list_remove_head(E2,subE,...)
+|
+ subE = E1
+|
+ for(subE = E1;...;...) S4
+|
+ subE++
+|
+ ++subE
+|
+ --subE
+|
+ subE--
+|
+ &subE
+|
+ E->f@p // bad use
+)
+ ... when any
+}
+else S3
+
+@script:python depends on !context && !org && report@
+p << s.p;
+p1 << ifm.p1;
+x << ifm.E;
+@@
+
+msg="ERROR: %s is NULL but dereferenced." % (x)
+coccilib.report.print_report(p[0], msg)
+
+@script:python depends on !context && org && !report@
+p << s.p;
+p1 << ifm.p1;
+x << ifm.E;
+@@
+
+msg="ERROR: %s is NULL but dereferenced." % (x)
+msg_safe=msg.replace("[","@(").replace("]",")")
+cocci.print_main(msg_safe,p)
+
+// For context mode
+
+@depends on context && !org && !report exists@
+expression subE <= ifm.E;
+expression *ifm.E;
+expression E1,E2;
+identifier f;
+statement S1,S2,S3,S4;
+iterator iter;
+position p!={pr1.p1,pr2.p2};
+position ifm.p1;
+@@
+
+if@p1 ((E == NULL && ...) || ...)
+{
+ ... when != if (...) S1 else S2
+(
+ iter(subE,...) S4 // no use
+|
+ list_remove_head(E2,subE,...)
+|
+ subE = E1
+|
+ for(subE = E1;...;...) S4
+|
+ subE++
+|
+ ++subE
+|
+ --subE
+|
+ subE--
+|
+ &subE
+|
+* E->f@p // bad use
+)
+ ... when any
+ return ...;
+}
+else S3
+
+// The following three rules are duplicates of ifm, pr1 and pr2 respectively.
+// It is need because the previous rule as already made a "change".
+
+@pr11 depends on context && !org && !report expression@
+expression E;
+identifier f;
+position p1;
+@@
+
+ (E != NULL && ...) ? <+...E->f@p1...+> : ...
+
+@pr12 depends on context && !org && !report expression@
+expression E;
+identifier f;
+position p2;
+@@
+
+(
+ (E != NULL) && ... && <+...E->f@p2...+>
+|
+ (E == NULL) || ... || <+...E->f@p2...+>
+|
+ sizeof(<+...E->f@p2...+>)
+)
+
+@ifm1 depends on context && !org && !report@
+expression *E;
+statement S1,S2;
+position p1;
+@@
+
+if@p1 ((E == NULL && ...) || ...) S1 else S2
+
+@depends on context && !org && !report exists@
+expression subE <= ifm1.E;
+expression *ifm1.E;
+expression E1,E2;
+identifier f;
+statement S1,S2,S3,S4;
+iterator iter;
+position p!={pr11.p1,pr12.p2};
+position ifm1.p1;
+@@
+
+if@p1 ((E == NULL && ...) || ...)
+{
+ ... when != if (...) S1 else S2
+(
+ iter(subE,...) S4 // no use
+|
+ list_remove_head(E2,subE,...)
+|
+ subE = E1
+|
+ for(subE = E1;...;...) S4
+|
+ subE++
+|
+ ++subE
+|
+ --subE
+|
+ subE--
+|
+ &subE
+|
+* E->f@p // bad use
+)
+ ... when any
+}
+else S3
--- /dev/null
+/// Find double locks. False positives may occur when some paths cannot
+/// occur at execution, due to the values of variables, and when there is
+/// an intervening function call that releases the lock.
+///
+// Confidence: Moderate
+// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
+// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
+// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual org
+virtual report
+
+@locked@
+position p1;
+expression E1;
+position p;
+@@
+
+(
+mutex_lock@p1
+|
+mutex_trylock@p1
+|
+spin_lock@p1
+|
+spin_trylock@p1
+|
+read_lock@p1
+|
+read_trylock@p1
+|
+write_lock@p1
+|
+write_trylock@p1
+) (E1@p,...);
+
+@balanced@
+position p1 != locked.p1;
+position locked.p;
+identifier lock,unlock;
+expression x <= locked.E1;
+expression E,locked.E1;
+expression E2;
+@@
+
+if (E) {
+ <+... when != E1
+ lock(E1@p,...)
+ ...+>
+}
+... when != E1
+ when != \(x = E2\|&x\)
+ when forall
+if (E) {
+ <+... when != E1
+ unlock@p1(E1,...)
+ ...+>
+}
+
+@r depends on !balanced exists@
+expression x <= locked.E1;
+expression locked.E1;
+expression E2;
+identifier lock;
+position locked.p,p1,p2;
+@@
+
+lock@p1 (E1@p,...);
+... when != E1
+ when != \(x = E2\|&x\)
+lock@p2 (E1,...);
+
+@script:python depends on org@
+p1 << r.p1;
+p2 << r.p2;
+lock << r.lock;
+@@
+
+cocci.print_main(lock,p1)
+cocci.print_secs("second lock",p2)
+
+@script:python depends on report@
+p1 << r.p1;
+p2 << r.p2;
+lock << r.lock;
+@@
+
+msg = "second lock on line %s" % (p2[0].line)
+coccilib.report.print_report(p1[0],msg)
--- /dev/null
+/// Find bit operations that include the same argument more than once
+//# One source of false positives is when the argument performs a side
+//# effect. Another source of false positives is when a neutral value
+//# such as 0 for | is used to indicate no information, to maintain the
+//# same structure as other similar expressions
+///
+// Confidence: Moderate
+// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
+// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
+// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual context
+virtual org
+virtual report
+
+@r expression@
+expression E;
+position p;
+@@
+
+(
+* E@p
+ & ... & E
+|
+* E@p
+ | ... | E
+|
+* E@p
+ & ... & !E
+|
+* E@p
+ | ... | !E
+|
+* !E@p
+ & ... & E
+|
+* !E@p
+ | ... | E
+)
+
+@script:python depends on org@
+p << r.p;
+@@
+
+cocci.print_main("duplicated argument to & or |",p)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0],"duplicated argument to & or |")
--- /dev/null
+/// Find duplicate field initializations. This has a high rate of false
+/// positives due to #ifdefs, which Coccinelle is not aware of in a structure
+/// initialization.
+///
+// Confidence: Low
+// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments: requires at least Coccinelle 0.2.4, lex or parse error otherwise
+// Options: --no-includes --include-headers
+
+virtual org
+virtual report
+
+@r@
+identifier I, s, fld;
+position p0,p;
+expression E;
+@@
+
+struct I s =@p0 { ..., .fld@p = E, ...};
+
+@s@
+identifier I, s, r.fld;
+position r.p0,p;
+expression E;
+@@
+
+struct I s =@p0 { ..., .fld@p = E, ...};
+
+@script:python depends on org@
+p0 << r.p0;
+fld << r.fld;
+ps << s.p;
+pr << r.p;
+@@
+
+if int(ps[0].line) < int(pr[0].line) or (int(ps[0].line) == int(pr[0].line) and int(ps[0].column) < int(pr[0].column)):
+ cocci.print_main(fld,p0)
+ cocci.print_secs("s",ps)
+ cocci.print_secs("r",pr)
+
+@script:python depends on report@
+p0 << r.p0;
+fld << r.fld;
+ps << s.p;
+pr << r.p;
+@@
+
+if int(ps[0].line) < int(pr[0].line) or (int(ps[0].line) == int(pr[0].line) and int(ps[0].column) < int(pr[0].column)):
+ msg = "%s: first occurrence line %s, second occurrence line %s" % (fld,ps[0].line,pr[0].line)
+ coccilib.report.print_report(p0[0],msg)
--- /dev/null
+/// Find &&/|| operations that include the same argument more than once
+//# A common source of false positives is when the expression, or
+//# another expresssion in the same && or || operation, performs a
+//# side effect.
+///
+// Confidence: Moderate
+// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
+// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
+// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual context
+virtual org
+virtual report
+
+@r expression@
+expression E;
+position p;
+@@
+
+(
+ E@p || ... || E
+|
+ E@p && ... && E
+)
+
+@bad@
+expression r.E,e1,e2,fn;
+position r.p;
+assignment operator op;
+@@
+
+(
+E@p
+&
+ <+... \(fn(...)\|e1 op e2\|e1++\|e1--\|++e1\|--e1\) ...+>
+)
+
+@depends on context && !bad@
+expression r.E;
+position r.p;
+@@
+
+*E@p
+
+@script:python depends on org && !bad@
+p << r.p;
+@@
+
+cocci.print_main("duplicated argument to && or ||",p)
+
+@script:python depends on report && !bad@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0],"duplicated argument to && or ||")
--- /dev/null
+/// The address of a variable or field is likely always to be non-zero.
+///
+// Confidence: High
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual org
+virtual report
+virtual context
+
+@r@
+expression x;
+statement S1,S2;
+position p;
+@@
+
+*if@p (&x)
+ S1 else S2
+
+@script:python depends on org@
+p << r.p;
+@@
+
+cocci.print_main("test of a variable/field address",p)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+msg = "ERROR: test of a variable/field address"
+coccilib.report.print_report(p[0],msg)
--- /dev/null
+/// NULL check before some freeing functions is not needed.
+///
+// Copyright: (C) 2014 Fabian Frederick. GPLv2.
+// Copyright: (C) 2019 Quentin Young. GPLv2.
+// Comments: -
+// Options: --no-includes --include-headers
+
+virtual patch
+
+@r2 depends on patch@
+expression E;
+expression Y;
+@@
+- if (E != NULL)
+XFREE(Y, E);
--- /dev/null
+/// Many iterators have the property that the first argument is always bound
+/// to a real list element, never NULL.
+//# False positives arise for some iterators that do not have this property,
+//# or in cases when the loop cursor is reassigned. The latter should only
+//# happen when the matched code is on the way to a loop exit (break, goto,
+//# or return).
+///
+// Confidence: Moderate
+// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@depends on patch@
+iterator I;
+expression x,E,E1,E2;
+statement S,S1,S2;
+@@
+
+I(x,...) { <...
+(
+- if (x == NULL && ...) S
+|
+- if (x != NULL || ...)
+ S
+|
+- (x == NULL) ||
+ E
+|
+- (x != NULL) &&
+ E
+|
+- (x == NULL && ...) ? E1 :
+ E2
+|
+- (x != NULL || ...) ?
+ E1
+- : E2
+|
+- if (x == NULL && ...) S1 else
+ S2
+|
+- if (x != NULL || ...)
+ S1
+- else S2
+|
++ BAD(
+ x == NULL
++ )
+|
++ BAD(
+ x != NULL
++ )
+)
+ ...> }
+
+@r depends on !patch exists@
+iterator I;
+expression x,E;
+position p1,p2;
+@@
+
+*I@p1(x,...)
+{ ... when != x = E
+(
+* x@p2 == NULL
+|
+* x@p2 != NULL
+)
+ ... when any
+}
+
+@script:python depends on org@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+cocci.print_main("iterator-bound variable",p1)
+cocci.print_secs("useless NULL test",p2)
+
+@script:python depends on report@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+msg = "ERROR: iterator variable bound on line %s cannot be NULL" % (p1[0].line)
+coccilib.report.print_report(p2[0], msg)
--- /dev/null
+/// Find missing unlocks. This semantic match considers the specific case
+/// where the unlock is missing from an if branch, and there is a lock
+/// before the if and an unlock after the if. False positives are due to
+/// cases where the if branch represents a case where the function is
+/// supposed to exit with the lock held, or where there is some preceding
+/// function call that releases the lock.
+///
+// Confidence: Moderate
+// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual context
+virtual org
+virtual report
+
+@prelocked@
+position p1,p;
+expression E1;
+@@
+
+(
+mutex_lock@p1
+|
+mutex_trylock@p1
+|
+spin_lock@p1
+|
+spin_trylock@p1
+|
+read_lock@p1
+|
+read_trylock@p1
+|
+write_lock@p1
+|
+write_trylock@p1
+|
+read_lock_irq@p1
+|
+write_lock_irq@p1
+|
+read_lock_irqsave@p1
+|
+write_lock_irqsave@p1
+|
+spin_lock_irq@p1
+|
+spin_lock_irqsave@p1
+) (E1@p,...);
+
+@looped@
+position r;
+@@
+
+for(...;...;...) { <+... return@r ...; ...+> }
+
+@err exists@
+expression E1;
+position prelocked.p;
+position up != prelocked.p1;
+position r!=looped.r;
+identifier lock,unlock;
+@@
+
+*lock(E1@p,...);
+... when != E1
+ when any
+if (...) {
+ ... when != E1
+* return@r ...;
+}
+... when != E1
+ when any
+*unlock@up(E1,...);
+
+@script:python depends on org@
+p << prelocked.p1;
+lock << err.lock;
+unlock << err.unlock;
+p2 << err.r;
+@@
+
+cocci.print_main(lock,p)
+cocci.print_secs(unlock,p2)
+
+@script:python depends on report@
+p << prelocked.p1;
+lock << err.lock;
+unlock << err.unlock;
+p2 << err.r;
+@@
+
+msg = "preceding lock on line %s" % (p[0].line)
+coccilib.report.print_report(p2[0],msg)
--- /dev/null
+/// sizeof when applied to a pointer typed expression gives the size of
+/// the pointer
+///
+// Confidence: High
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual org
+virtual report
+virtual context
+virtual patch
+
+@depends on patch@
+expression *x;
+expression f;
+expression i;
+type T;
+@@
+
+(
+x = <+... sizeof(
+- x
++ *x
+ ) ...+>
+|
+f(...,(T)(x),...,sizeof(
+- x
++ *x
+ ),...)
+|
+f(...,sizeof(
+- x
++ *x
+ ),...,(T)(x),...)
+|
+f(...,(T)(x),...,i*sizeof(
+- x
++ *x
+ ),...)
+|
+f(...,i*sizeof(
+- x
++ *x
+ ),...,(T)(x),...)
+)
+
+@r depends on !patch@
+expression *x;
+expression f;
+expression i;
+position p;
+type T;
+@@
+
+(
+*x = <+... sizeof@p(x) ...+>
+|
+*f(...,(T)(x),...,sizeof@p(x),...)
+|
+*f(...,sizeof@p(x),...,(T)(x),...)
+|
+*f(...,(T)(x),...,i*sizeof@p(x),...)
+|
+*f(...,i*sizeof@p(x),...,(T)(x),...)
+)
+
+@script:python depends on org@
+p << r.p;
+@@
+
+cocci.print_main("application of sizeof to pointer",p)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+msg = "ERROR: application of sizeof to pointer"
+coccilib.report.print_report(p[0],msg)<Paste>
--- /dev/null
+@@
+type T;
+T[] E;
+expression buf, srclen;
+@@
+
+- strncpy(E, src, srclen)
++ strlcpy(E, src, sizeof(E))
--- /dev/null
+///
+/// Remove unneeded variable used to store return value.
+///
+// Confidence: Moderate
+// Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments: Comments on code can be deleted if near code that is removed.
+// "when strict" can be removed to get more hits, but adds false
+// positives
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual report
+virtual context
+virtual org
+
+@depends on patch@
+type T;
+constant C;
+identifier ret;
+@@
+- T ret = C;
+... when != ret
+ when strict
+return
+- ret
++ C
+;
+
+@depends on context@
+type T;
+constant C;
+identifier ret;
+@@
+* T ret = C;
+... when != ret
+ when strict
+* return ret;
+
+@r1 depends on report || org@
+type T;
+constant C;
+identifier ret;
+position p1, p2;
+@@
+T ret@p1 = C;
+... when != ret
+ when strict
+return ret@p2;
+
+@script:python depends on report@
+p1 << r1.p1;
+p2 << r1.p2;
+C << r1.C;
+ret << r1.ret;
+@@
+coccilib.report.print_report(p1[0], "Unneeded variable: \"" + ret + "\". Return \"" + C + "\" on line " + p2[0].line)
+
+@script:python depends on org@
+p1 << r1.p1;
+p2 << r1.p2;
+C << r1.C;
+ret << r1.ret;
+@@
+cocci.print_main("unneeded \"" + ret + "\" variable", p1)
+cocci.print_sec("return " + C + " here", p2)
--- /dev/null
+///
+/// Remove unneeded semicolon.
+///
+// Confidence: Moderate
+// Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments: Some false positives on empty default cases in switch statements.
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual report
+virtual context
+virtual org
+
+@r_default@
+position p;
+@@
+switch (...)
+{
+default: ...;@p
+}
+
+@r_case@
+position p;
+@@
+(
+switch (...)
+{
+case ...:;@p
+}
+|
+switch (...)
+{
+case ...:...
+case ...:;@p
+}
+|
+switch (...)
+{
+case ...:...
+case ...:
+case ...:;@p
+}
+)
+
+@r1@
+statement S;
+position p1;
+position p != {r_default.p, r_case.p};
+identifier label;
+@@
+(
+label:;
+|
+S@p1;@p
+)
+
+@script:python@
+p << r1.p;
+p1 << r1.p1;
+@@
+if p[0].line != p1[0].line_end:
+ cocci.include_match(False)
+
+@depends on patch@
+position r1.p;
+@@
+-;@p
+
+@script:python depends on report@
+p << r1.p;
+@@
+coccilib.report.print_report(p[0],"Unneeded semicolon")
+
+@depends on context@
+position r1.p;
+@@
+*;@p
+
+@script:python depends on org@
+p << r1.p;
+@@
+cocci.print_main("Unneeded semicolon",p)
--- /dev/null
+/// Use strlcpy rather than strncpy(dest,..,sz) + dest[sz-1] = '\0'
+///
+// Confidence: High
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual context
+virtual report
+virtual org
+
+@r@
+expression dest, src, sz;
+position p;
+@@
+
+strncpy@p(dest, src, sz);
+dest[sz - 1] = '\0';
+
+@script:python depends on org@
+p << r.p;
+@@
+
+cocci.print_main("strncpy followed by truncation can be strlcpy",p)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+msg = "SUGGESTION: strncpy followed by truncation can be strlcpy"
+coccilib.report.print_report(p[0],msg)
+
+@ok depends on patch@
+expression r.dest, r.src, r.sz;
+position r.p;
+@@
+
+-strncpy@p(
++strlcpy(
+ dest, src, sz);
+-dest[sz - 1] = '\0';
--- /dev/null
+/// Unsigned expressions cannot be lesser than zero. Presence of
+/// comparisons 'unsigned (<|<=|>|>=) 0' often indicates a bug,
+/// usually wrong type of variable.
+///
+/// To reduce number of false positives following tests have been added:
+/// - parts of range checks are skipped, eg. "if (u < 0 || u > 15) ...",
+/// developers prefer to keep such code,
+/// - comparisons "<= 0" and "> 0" are performed only on results of
+/// signed functions/macros,
+/// - hardcoded list of signed functions/macros with always non-negative
+/// result is used to avoid false positives difficult to detect by other ways
+///
+// Confidence: Average
+// Copyright: (C) 2015 Andrzej Hajda, Samsung Electronics Co., Ltd. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Options: --all-includes
+
+virtual context
+virtual org
+virtual report
+
+@r_cmp@
+position p;
+typedef bool, u8, u16, u32, u64;
+{unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long,
+ size_t, bool, u8, u16, u32, u64} v;
+expression e;
+@@
+
+ \( v = e \| &v \)
+ ...
+ (\( v@p < 0 \| v@p <= 0 \| v@p >= 0 \| v@p > 0 \))
+
+@r@
+position r_cmp.p;
+typedef s8, s16, s32, s64;
+{char, short, int, long, long long, ssize_t, s8, s16, s32, s64} vs;
+expression c, e, v;
+identifier f !~ "^(ata_id_queue_depth|btrfs_copy_from_user|dma_map_sg|dma_map_sg_attrs|fls|fls64|gameport_time|get_write_extents|nla_len|ntoh24|of_flat_dt_match|of_get_child_count|uart_circ_chars_pending|[A-Z0-9_]+)$";
+@@
+
+(
+ v = f(...)@vs;
+ ... when != v = e;
+* (\( v@p <=@e 0 \| v@p >@e 0 \))
+ ... when any
+|
+(
+ (\( v@p < 0 \| v@p <= 0 \)) || ... || (\( v >= c \| v > c \))
+|
+ (\( v >= c \| v > c \)) || ... || (\( v@p < 0 \| v@p <= 0 \))
+|
+ (\( v@p >= 0 \| v@p > 0 \)) && ... && (\( v < c \| v <= c \))
+|
+ ((\( v < c \| v <= c \) && ... && \( v@p >= 0 \| v@p > 0 \)))
+|
+* (\( v@p <@e 0 \| v@p >=@e 0 \))
+)
+)
+
+@script:python depends on org@
+p << r_cmp.p;
+e << r.e;
+@@
+
+msg = "WARNING: Unsigned expression compared with zero: %s" % (e)
+coccilib.org.print_todo(p[0], msg)
+
+@script:python depends on report@
+p << r_cmp.p;
+e << r.e;
+@@
+
+msg = "WARNING: Unsigned expression compared with zero: %s" % (e)
+coccilib.report.print_report(p[0], msg)
--- /dev/null
+/*
+ * VTY_DECLVAR_CONTEXT contains a built-in "if (!var) return;"
+ */
+@@
+identifier var, typ;
+statement S;
+@@
+
+ {
+ ...
+ \(
+ VTY_DECLVAR_CONTEXT(typ, var);
+ \|
+ VTY_DECLVAR_CONTEXT_SUB(typ, var);
+ \)
+ ...
+- if (
+- \( !var \| var == NULL \)
+- )
+- S
+ ...
+ }
--- /dev/null
+/*
+ * prep: strip off casts, they cause things to fail matching later.
+ */
+
+@@
+identifier casttarget;
+symbol vty;
+@@
+
+- (struct casttarget *)vty->index
++ vty->index
+
+/*
+ * variant 1: local variable assigned from vty->index
+ */
+
+@@
+identifier sn, nn;
+identifier fn;
+@@
+
+ int fn(...)
+ {
++ VTY_DECLVAR_CONTEXT (sn, nn);
+ ...
+ \(
+- struct sn *nn;
+ ...
+- nn = vty->index;
+ \|
+- struct sn *nn = vty->index;
+ \|
+- struct sn *nn = vty->index;
+ ...
+- nn = vty->index;
+ \)
+ ...
+ }
+
+@@
+identifier sn, nn;
+identifier fn;
+type Tr;
+@@
+
+ Tr *fn(...)
+ {
++ struct sn *nn = VTY_GET_CONTEXT(sn);
+ ...
+ \(
+- struct sn *nn;
+ ...
+- nn = vty->index;
++ if (!nn) {
++ return NULL;
++ }
+ \|
+- struct sn *nn = vty->index;
++ if (!nn) {
++ return NULL;
++ }
+ \|
+- struct sn *nn = vty->index;
+ ...
+- nn = vty->index;
++ if (!nn) {
++ return NULL;
++ }
+ \)
+ ...
+ }
+
+/*
+ * variant 2: vty wrapper func with (vty, vty->index, ...) signature
+ */
+
+/* find calls of this pattern first; arg will be dropped in rule3 */
+@rule1@
+identifier fn !~ "generic_(set|match)_";
+expression arg;
+@@
+
+ fn(arg, arg->index, ...)
+
+@ script:python @
+fn << rule1.fn;
+arg << rule1.arg;
+@@
+print "R01 removing vty-index argument on %s(%s, ...)" % (fn, arg)
+
+#/* strip arg on the vty wrapper func, add local handling */
+@ rule2 @
+identifier rule1.fn;
+identifier arg;
+identifier T;
+@@
+
+ static int fn (struct vty *vty,
+- struct T * arg,
+ ...)
+ {
++ VTY_DECLVAR_CONTEXT (T, arg);
+ ...
+ }
+
+/* drop argument on call sites identified earlier */
+@ rule3 @
+identifier rule1.fn;
+expression arg;
+@@
+
+ fn(arg,
+- arg->index,
+ ...)
+
+
+/*
+ * variant 3: function calls with "vty->index" argument (but no vty)
+ *
+ * a bit more complicated since we need to find the type from the header.
+ */
+
+/* find call sites first
+ * remember function name for later declvar insertion
+ */
+@ rule11 exists@
+identifier fn;
+identifier fparent;
+type Tr;
+@@
+
+ Tr fparent (...)
+ {
+ ...
+ fn(vty->index, ...)
+ ...
+ }
+
+@ script:python @
+fn << rule11.fn;
+@@
+print "R11 removing vty-index argument on %s(...)" % (fn)
+
+#/* find type of the argument - note args are mostly unnamed in FRR :( */
+@ rule12 @
+identifier rule11.fn;
+identifier T, argname;
+type Tr;
+@@
+
+(
+ Tr fn(struct T *, ...);
+|
+ Tr fn(struct T * argname, ...);
+)
+
+@ script:python @
+fn << rule11.fn;
+T << rule12.T;
+@@
+print "R12 removing vty-index type is %s for %s(...)" % (T, fn)
+
+#/* add declvar
+# * this is split from rule14 so we support multiple calls in one func */
+@ rule13a @
+identifier rule11.fparent;
+identifier rule12.T;
+@@
+
+ int fparent (...)
+ {
++ VTY_DECLVAR_CONTEXT(T, T);
+ ...
+ }
+
+@ rule13b @
+identifier rule11.fparent;
+identifier rule12.T;
+type Tr;
+@@
+
+ Tr *fparent (...)
+ {
++ struct T *T = VTY_GET_CONTEXT(T);
++ if (!T) {
++ return NULL;
++ }
+ ...
+ }
+
+/* now replace the argument in the call */
+@ rule14 exists @
+identifier rule11.fn;
+identifier rule12.T;
+@@
+
+ {
+ ...
+ \(
+ fn(
+- vty->index,
++ T,
+ ...)
+ \|
+ fn(
+- vty->index
++ T
+ )
+ \)
+ ...
+ }
+
+/* special case ... */
+@rule30@
+identifier fn =~ "generic_(set|match)_";
+expression arg;
+@@
+
+ fn(arg,
+- arg->index,
++ VTY_GET_CONTEXT(route_map_index),
+ ...)
+
+/* and finally - PUSH_CONTEXT */
+@ rule99a exists @
+identifier tnode;
+identifier vexpr =~ "NULL";
+@@
+
+- vty->node = tnode;
+ ...
+- vty->index = vexpr;
++ VTY_PUSH_CONTEXT_NULL(tnode);
+
+@ rule99b exists @
+identifier tnode;
+expression vexpr;
+@@
+
+- vty->node = tnode;
+ ...
+- vty->index = vexpr;
++ VTY_PUSH_CONTEXT(tnode, vexpr);
+
--- /dev/null
+///
+/// Use zeroing allocator rather than allocator followed by memset with 0
+///
+/// This considers some simple cases that are common and easy to validate
+/// Note in particular that there are no ...s in the rule, so all of the
+/// matched code has to be contiguous
+///
+// Confidence: High
+// Copyright: (C) 2009-2010 Julia Lawall, Nicolas Palix, DIKU. GPLv2.
+// Copyright: (C) 2009-2010 Gilles Muller, INRIA/LiP6. GPLv2.
+// Copyright: (C) 2017 Himanshu Jha GPLv2.
+// Copyright: (C) 2019 Quentin Young. GPLv2.
+// URL: http://coccinelle.lip6.fr/rules/kzalloc.html
+// Options: --no-includes --include-headers
+//
+// Keywords: XMALLOC, XCALLOC
+// Version min: < 2.6.12 kmalloc
+// Version min: 2.6.14 kzalloc
+//
+
+virtual context
+virtual patch
+
+//----------------------------------------------------------
+// For context mode
+//----------------------------------------------------------
+
+@depends on context@
+type T, T2;
+expression x;
+expression E1;
+expression t;
+@@
+
+* x = (T)XMALLOC(t, E1);
+* memset((T2)x,0,E1);
+
+//----------------------------------------------------------
+// For patch mode
+//----------------------------------------------------------
+
+@depends on patch@
+type T, T2;
+expression x;
+expression E1;
+expression t;
+@@
+
+- x = (T)XMALLOC(t, E1);
++ x = (T)XCALLOC(t, E1);
+- memset((T2)x,0,E1);
+
--- /dev/null
+/// Find a use after free.
+//# Values of variables may imply that some
+//# execution paths are not possible, resulting in false positives.
+//# Another source of false positives are macros such as
+//# SCTP_DBG_OBJCNT_DEC that do not actually evaluate their argument
+///
+// Confidence: Moderate
+// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2.
+// Copyright: (C) 2019 Quentin Young. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual org
+virtual report
+
+@free@
+expression E, t;
+position p1;
+@@
+
+* XFREE@p1(t, E)
+
+@print expression@
+constant char [] c;
+expression free.E,E2;
+type T;
+position p;
+identifier f;
+@@
+
+(
+ f(...,c,...,(T)E@p,...)
+|
+ E@p == E2
+|
+ E@p != E2
+|
+ E2 == E@p
+|
+ E2 != E@p
+|
+ !E@p
+|
+ E@p || ...
+)
+
+@sz@
+expression free.E;
+position p;
+@@
+
+ sizeof(<+...E@p...+>)
+
+@loop exists@
+expression E, t;
+identifier l;
+position ok;
+@@
+
+while (1) { ...
+* XFREE@ok(t, E)
+ ... when != break;
+ when != goto l;
+ when forall
+}
+
+@r exists@
+expression free.E, subE<=free.E, E2;
+expression E1;
+iterator iter;
+statement S;
+position free.p1!=loop.ok,p2!={print.p,sz.p};
+@@
+
+* XFREE@p1(t, E)
+...
+(
+ iter(...,subE,...) S // no use
+|
+ list_remove_head(E1,subE,...)
+|
+ subE = E2
+|
+ subE++
+|
+ ++subE
+|
+ --subE
+|
+ subE--
+|
+ &subE
+|
+ BUG(...)
+|
+ BUG_ON(...)
+|
+ return_VALUE(...)
+|
+ return_ACPI_STATUS(...)
+|
+ E@p2 // bad use
+)
+
+@script:python depends on org@
+p1 << free.p1;
+p2 << r.p2;
+@@
+
+cocci.print_main("kfree",p1)
+cocci.print_secs("ref",p2)
+
+@script:python depends on report@
+p1 << free.p1;
+p2 << r.p2;
+@@
+
+msg = "ERROR: reference preceded by free on line %s" % (p1[0].line)
+coccilib.report.print_report(p2[0],msg)
--- /dev/null
+/// Free of a structure field
+///
+// Confidence: High
+// Copyright: (C) 2013 Julia Lawall, INRIA/LIP6. GPLv2.
+// Copyright: (C) 2019 Quentin Young. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual org
+virtual report
+virtual context
+
+@r depends on context || report || org @
+expression e, t;
+identifier f;
+position p;
+@@
+
+* XFREE@p(t, &e->f)
+
+@script:python depends on org@
+p << r.p;
+@@
+
+cocci.print_main("XFREE",p)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+msg = "ERROR: invalid free of structure field"
+coccilib.report.print_report(p[0],msg)
--- /dev/null
+/// XMALLOC, XCALLOC etc either return non-null, or abort the program.
+/// Never nullcheck these.
+//
+// Copyright: (C) 2019 Quentin Young. GPLv2.
+
+virtual patch
+
+//----------------------------------------------------------
+// For patch mode
+//----------------------------------------------------------
+
+@depends on patch@
+identifier alloc;
+@@
+
+alloc = XMALLOC(...);
+
+...
+
+- if (alloc == NULL)
+- {
+- ...
+- }
+
+@depends on patch@
+identifier alloc;
+@@
+
+alloc = XCALLOC(...);
+
+...
+
+- if (alloc == NULL)
+- {
+- ...
+- }
+
--- /dev/null
+@@
+identifier change;
+identifier end;
+expression E, f, g;
+iterator name frr_elevate_privs;
+@@
+
+- if (E.change(ZPRIVS_RAISE))
+- f;
++ frr_elevate_privs(&E) {
+ <+...
+- goto end;
++ break;
+ ...+>
+- end:
+- if (E.change(ZPRIVS_LOWER))
+- g;
++ }
+
+@@
+identifier change, errno, safe_strerror, exit;
+expression E, f1, f2, f3, ret, fn;
+iterator name frr_elevate_privs;
+@@
+
+ if (E.change(ZPRIVS_RAISE))
+ f1;
+ ...
+ if (...) {
+- int save_errno = errno;
+ ...
+- if (E.change(ZPRIVS_LOWER))
+- f2;
+ ...
+- safe_strerror(save_errno)
++ safe_strerror(errno)
+ ...
+ \( return ret; \| exit(ret); \)
+ }
+ ...
+ if (E.change(ZPRIVS_LOWER))
+ f3;
+
+@@
+identifier change;
+expression E, f1, f2, f3, ret;
+iterator name frr_elevate_privs;
+@@
+
+ if (E.change(ZPRIVS_RAISE))
+ f1;
+ ...
+ if (...) {
+ ...
+- if (E.change(ZPRIVS_LOWER))
+- f2;
+ ...
+ return ret;
+ }
+ ...
+ if (E.change(ZPRIVS_LOWER))
+ f3;
+
+@@
+identifier change;
+expression E, f, g;
+iterator name frr_elevate_privs;
+@@
+
+- if (E.change(ZPRIVS_RAISE))
+- f;
++ frr_elevate_privs(&E) {
+ ...
+- if (E.change(ZPRIVS_LOWER))
+- g;
++ }
#
# ATTENTION:
#
-# When activation a daemon at the first time, a config file, even if it is
+# When activating a daemon for 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=.
--- /dev/null
+# FRR Support Bundle Command List
+# Do Not modify the lines that start with
+# PROC_NAME, CMD_LIST_START and CMD_LIST_END
+# Add the new command for each process between
+# CMD_LIST_START and CMD_LIST_END lines
+
+# BGP Support Bundle Command List
+PROC_NAME:bgp
+CMD_LIST_START
+show bgp summary
+show ip bgp
+show ip bgp neighbors
+show ip bgp summary
+show ip bgp statistics
+
+show ip bgp update-groups advertise-queue
+show ip bgp update-groups advertised-routes
+show ip bgp update-groups packet-queue
+show ip bgp update-groups statistics
+show ip bgp peer-group
+show ip bgp memory
+
+show bgp ipv6
+show bgp ipv6 neighbors
+show bgp ipv6 summary
+show bgp ipv6 update-groups advertise-queue
+show bgp ipv6 update-groups advertised-routes
+show bgp ipv6 update-groups packet-queue
+show bgp ipv6 update-groups statistics
+show ip bgp statistics
+
+show bgp evpn route
+CMD_LIST_END
+
+# Zebra Support Bundle Command List
+PROC_NAME:zebra
+CMD_LIST_START
+show zebra
+show zebra client summary
+show ip route
+
+show route-map
+show memory
+show interface
+show vrf
+show error all
+show work-queues
+show running-config
+show thread cpu
+show thread poll
+show daemons
+show version
+CMD_LIST_END
+
+# OSPF Support Bundle Command List
+# PROC_NAME:ospf
+# CMD_LIST_START
+# CMD_LIST_END
+
+# RIP Support Bundle Command List
+# PROC_NAME:rip
+# CMD_LIST_START
+# CMD_LIST_END
+
+# ISIS Support Bundle Command List
+# PROC_NAME:isis
+# CMD_LIST_START
+# CMD_LIST_END
+
+# BFD Support Bundle Command List
+# PROC_NAME:bfd
+# CMD_LIST_START
+# CMD_LIST_END
+
+# STATIC Support Bundle Command List
+# PROC_NAME:static
+# CMD_LIST_START
+# CMD_LIST_END
+
+# PIM Support Bundle Command List
+# PROC_NAME:pim
+# CMD_LIST_START
+# CMD_LIST_END
# Load configuration
. "$C_PATH/daemons"
-. "$C_PATH/daemons.conf"
+if [ -e "$C_PATH/daemons.conf" ]; then
+ . "$C_PATH/daemons.conf"
+fi
# Read configuration variable file if it is present
[ -r /etc/default/frr ] && . /etc/default/frr
load_old_config "/etc/default/frr"
load_old_config "/etc/sysconfig/frr"
-if declare -p watchfrr_options | grep -q '^declare \-a'; then
+if { declare -p watchfrr_options 2>/dev/null || true; } | 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."
--- /dev/null
+########################################################
+### Python Script to generate the FRR support bundle ###
+########################################################
+import os
+import subprocess
+import datetime
+
+TOOLS_DIR="tools/"
+ETC_DIR="/etc/frr/"
+LOG_DIR="/var/log/frr/"
+SUCCESS = 1
+FAIL = 0
+
+inputFile = ETC_DIR + "support_bundle_commands.conf"
+
+# Open support bundle configuration file
+def openConfFile(i_file):
+ try:
+ with open(i_file) as supportBundleConfFile:
+ lines = filter(None, (line.rstrip() for line in supportBundleConfFile))
+ return lines
+ except IOError:
+ return ([])
+
+# Create the output file name
+def createOutputFile(procName):
+ fileName = procName + "_support_bundle.log"
+ oldFile = LOG_DIR + fileName
+ cpFileCmd = "cp " + oldFile + " " + oldFile + ".prev"
+ rmFileCmd = "rm -rf " + oldFile
+ print "Making backup of " + oldFile
+ os.system(cpFileCmd)
+ print "Removing " + oldFile
+ os.system(rmFileCmd)
+ return fileName
+
+# Open the output file for this process
+def openOutputFile(fileName):
+ crt_file_cmd = LOG_DIR + fileName
+ print crt_file_cmd
+ try:
+ outputFile = open(crt_file_cmd, "w")
+ return outputFile
+ except IOError:
+ return ()
+
+# Close the output file for this process
+def closeOutputFile(file):
+ try:
+ file.close()
+ return SUCCESS
+ except IOError:
+ return FAIL
+
+# Execute the command over vtysh and store in the
+# output file
+def executeCommand(cmd, outputFile):
+ cmd_exec_str = "vtysh -c \"" + cmd + "\" "
+ try:
+ cmd_output = subprocess.check_output(cmd_exec_str, shell=True)
+ try:
+ dateTime = datetime.datetime.now()
+ outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n")
+ outputFile.write(cmd_output)
+ outputFile.write("########################################################\n")
+ outputFile.write('\n')
+ except:
+ print "Writing to ouptut file Failed"
+ except subprocess.CalledProcessError as e:
+ dateTime = datetime.datetime.now()
+ outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n")
+ outputFile.write(e.output)
+ outputFile.write("########################################################\n")
+ outputFile.write('\n')
+ print "Error:" + e.output
+
+
+# Process the support bundle configuration file
+# and call appropriate functions
+def processConfFile(lines):
+ for line in lines:
+ if line[0][0] == '#':
+ continue
+ cmd_line = line.split(':')
+ if cmd_line[0] == "PROC_NAME":
+ outputFileName = createOutputFile(cmd_line[1])
+ if outputFileName:
+ print outputFileName, "created for", cmd_line[1]
+ elif cmd_line[0] == "CMD_LIST_START":
+ outputFile = openOutputFile(outputFileName)
+ if outputFile:
+ print outputFileName, "opened"
+ else:
+ print outputFileName, "open failed"
+ return FAIL
+ elif cmd_line[0] == "CMD_LIST_END":
+ if closeOutputFile(outputFile):
+ print outputFileName, "closed"
+ else:
+ print outputFileName, "close failed"
+ else:
+ print "Execute:" , cmd_line[0]
+ executeCommand(cmd_line[0], outputFile)
+
+# Main Function
+lines = openConfFile(inputFile)
+if not lines:
+ print "File support_bundle_commands.conf not present in /etc/frr/ directory"
+else:
+ processConfFile(lines)
+++ /dev/null
-/*
- * VTY_DECLVAR_CONTEXT contains a built-in "if (!var) return;"
- */
-@@
-identifier var, typ;
-statement S;
-@@
-
- {
- ...
- \(
- VTY_DECLVAR_CONTEXT(typ, var);
- \|
- VTY_DECLVAR_CONTEXT_SUB(typ, var);
- \)
- ...
-- if (
-- \( !var \| var == NULL \)
-- )
-- S
- ...
- }
+++ /dev/null
-/*
- * prep: strip off casts, they cause things to fail matching later.
- */
-
-@@
-identifier casttarget;
-symbol vty;
-@@
-
-- (struct casttarget *)vty->index
-+ vty->index
-
-/*
- * variant 1: local variable assigned from vty->index
- */
-
-@@
-identifier sn, nn;
-identifier fn;
-@@
-
- int fn(...)
- {
-+ VTY_DECLVAR_CONTEXT (sn, nn);
- ...
- \(
-- struct sn *nn;
- ...
-- nn = vty->index;
- \|
-- struct sn *nn = vty->index;
- \|
-- struct sn *nn = vty->index;
- ...
-- nn = vty->index;
- \)
- ...
- }
-
-@@
-identifier sn, nn;
-identifier fn;
-type Tr;
-@@
-
- Tr *fn(...)
- {
-+ struct sn *nn = VTY_GET_CONTEXT(sn);
- ...
- \(
-- struct sn *nn;
- ...
-- nn = vty->index;
-+ if (!nn) {
-+ return NULL;
-+ }
- \|
-- struct sn *nn = vty->index;
-+ if (!nn) {
-+ return NULL;
-+ }
- \|
-- struct sn *nn = vty->index;
- ...
-- nn = vty->index;
-+ if (!nn) {
-+ return NULL;
-+ }
- \)
- ...
- }
-
-/*
- * variant 2: vty wrapper func with (vty, vty->index, ...) signature
- */
-
-/* find calls of this pattern first; arg will be dropped in rule3 */
-@rule1@
-identifier fn !~ "generic_(set|match)_";
-expression arg;
-@@
-
- fn(arg, arg->index, ...)
-
-@ script:python @
-fn << rule1.fn;
-arg << rule1.arg;
-@@
-print "R01 removing vty-index argument on %s(%s, ...)" % (fn, arg)
-
-#/* strip arg on the vty wrapper func, add local handling */
-@ rule2 @
-identifier rule1.fn;
-identifier arg;
-identifier T;
-@@
-
- static int fn (struct vty *vty,
-- struct T * arg,
- ...)
- {
-+ VTY_DECLVAR_CONTEXT (T, arg);
- ...
- }
-
-/* drop argument on call sites identified earlier */
-@ rule3 @
-identifier rule1.fn;
-expression arg;
-@@
-
- fn(arg,
-- arg->index,
- ...)
-
-
-/*
- * variant 3: function calls with "vty->index" argument (but no vty)
- *
- * a bit more complicated since we need to find the type from the header.
- */
-
-/* find call sites first
- * remember function name for later declvar insertion
- */
-@ rule11 exists@
-identifier fn;
-identifier fparent;
-type Tr;
-@@
-
- Tr fparent (...)
- {
- ...
- fn(vty->index, ...)
- ...
- }
-
-@ script:python @
-fn << rule11.fn;
-@@
-print "R11 removing vty-index argument on %s(...)" % (fn)
-
-#/* find type of the argument - note args are mostly unnamed in FRR :( */
-@ rule12 @
-identifier rule11.fn;
-identifier T, argname;
-type Tr;
-@@
-
-(
- Tr fn(struct T *, ...);
-|
- Tr fn(struct T * argname, ...);
-)
-
-@ script:python @
-fn << rule11.fn;
-T << rule12.T;
-@@
-print "R12 removing vty-index type is %s for %s(...)" % (T, fn)
-
-#/* add declvar
-# * this is split from rule14 so we support multiple calls in one func */
-@ rule13a @
-identifier rule11.fparent;
-identifier rule12.T;
-@@
-
- int fparent (...)
- {
-+ VTY_DECLVAR_CONTEXT(T, T);
- ...
- }
-
-@ rule13b @
-identifier rule11.fparent;
-identifier rule12.T;
-type Tr;
-@@
-
- Tr *fparent (...)
- {
-+ struct T *T = VTY_GET_CONTEXT(T);
-+ if (!T) {
-+ return NULL;
-+ }
- ...
- }
-
-/* now replace the argument in the call */
-@ rule14 exists @
-identifier rule11.fn;
-identifier rule12.T;
-@@
-
- {
- ...
- \(
- fn(
-- vty->index,
-+ T,
- ...)
- \|
- fn(
-- vty->index
-+ T
- )
- \)
- ...
- }
-
-/* special case ... */
-@rule30@
-identifier fn =~ "generic_(set|match)_";
-expression arg;
-@@
-
- fn(arg,
-- arg->index,
-+ VTY_GET_CONTEXT(route_map_index),
- ...)
-
-/* and finally - PUSH_CONTEXT */
-@ rule99a exists @
-identifier tnode;
-identifier vexpr =~ "NULL";
-@@
-
-- vty->node = tnode;
- ...
-- vty->index = vexpr;
-+ VTY_PUSH_CONTEXT_NULL(tnode);
-
-@ rule99b exists @
-identifier tnode;
-expression vexpr;
-@@
-
-- vty->node = tnode;
- ...
-- vty->index = vexpr;
-+ VTY_PUSH_CONTEXT(tnode, vexpr);
-
+++ /dev/null
-@@
-identifier change;
-identifier end;
-expression E, f, g;
-iterator name frr_elevate_privs;
-@@
-
-- if (E.change(ZPRIVS_RAISE))
-- f;
-+ frr_elevate_privs(&E) {
- <+...
-- goto end;
-+ break;
- ...+>
-- end:
-- if (E.change(ZPRIVS_LOWER))
-- g;
-+ }
-
-@@
-identifier change, errno, safe_strerror, exit;
-expression E, f1, f2, f3, ret, fn;
-iterator name frr_elevate_privs;
-@@
-
- if (E.change(ZPRIVS_RAISE))
- f1;
- ...
- if (...) {
-- int save_errno = errno;
- ...
-- if (E.change(ZPRIVS_LOWER))
-- f2;
- ...
-- safe_strerror(save_errno)
-+ safe_strerror(errno)
- ...
- \( return ret; \| exit(ret); \)
- }
- ...
- if (E.change(ZPRIVS_LOWER))
- f3;
-
-@@
-identifier change;
-expression E, f1, f2, f3, ret;
-iterator name frr_elevate_privs;
-@@
-
- if (E.change(ZPRIVS_RAISE))
- f1;
- ...
- if (...) {
- ...
-- if (E.change(ZPRIVS_LOWER))
-- f2;
- ...
- return ret;
- }
- ...
- if (E.change(ZPRIVS_LOWER))
- f3;
-
-@@
-identifier change;
-expression E, f, g;
-iterator name frr_elevate_privs;
-@@
-
-- if (E.change(ZPRIVS_RAISE))
-- f;
-+ frr_elevate_privs(&E) {
- ...
-- if (E.change(ZPRIVS_LOWER))
-- g;
-+ }
static void config_del(struct config *config)
{
list_delete(&config->line);
- if (config->name)
- XFREE(MTYPE_VTYSH_CONFIG_LINE, config->name);
+ XFREE(MTYPE_VTYSH_CONFIG_LINE, config->name);
XFREE(MTYPE_VTYSH_CONFIG, config);
}
struct passwd *passwd;
char *homedir;
- if ((homedir = getenv("HOME")) != 0)
+ if ((homedir = getenv("HOME")) != NULL)
return homedir;
/* Fallback if HOME is undefined */
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);
}
}
return CHECK_FLAG(connected->flags,
ZEBRA_IFA_UNNUMBERED);
}
- return 0;
+ return 1;
}
#include "lib/if.h"
#include "lib/prefix.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern struct connected *connected_check(struct interface *ifp,
union prefixconstptr p);
extern struct connected *connected_check_ptp(struct interface *ifp,
extern int connected_is_unnumbered(struct interface *);
+#ifdef __cplusplus
+}
+#endif
#endif /*_ZEBRA_CONNECTED_H */
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);
#include "lib/vty.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Debug flags. */
#define ZEBRA_DEBUG_EVENT 0x01
#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)
DECLARE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty));
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_DEBUG_H */
ifp = if_lookup_by_name_per_ns(zns, name);
if (ifp) {
- if (ifp->desc)
- XFREE(MTYPE_TMP, ifp->desc);
+ XFREE(MTYPE_TMP, ifp->desc);
if (desc)
ifp->desc = XSTRDUP(MTYPE_TMP, desc);
}
#ifdef HAVE_NETLINK
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id,
int startup);
extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int interface_lookup_netlink(struct zebra_ns *zns);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* HAVE_NETLINK */
#endif /* _ZEBRA_IF_NETLINK_H */
#include "zebra/zebra_l2.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* For interface multicast configuration. */
#define IF_ZEBRA_MULTICAST_UNSPEC 0
#define IF_ZEBRA_MULTICAST_ON 1
extern int ifaddr_proc_ipv6(void);
#endif /* HAVE_PROC_NET_IF_INET6 */
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_INTERFACE_H */
#ifndef _ZEBRA_IOCTL_H
#define _ZEBRA_IOCTL_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Prototypes. */
extern void ifreq_set_name(struct ifreq *, struct interface *);
extern int if_ioctl(unsigned long, caddr_t);
#endif /* SOLARIS_IPV6 */
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_IOCTL_H */
#ifndef _ZEBRA_IF_IOCTL_SOLARIS_H
#define _ZEBRA_IF_IOCTL_SOLARIS_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void lifreq_set_name(struct lifreq *, const char *);
int if_get_flags_direct(const char *, uint64_t *, unsigned int af);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_IF_IOCTL_SOLARIS_H */
#ifndef _ZEBRA_IPFORWARD_H
#define _ZEBRA_IPFORWARD_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern int ipforward(void);
extern int ipforward_on(void);
extern int ipforward_off(void);
extern int ipforward_ipv6_on(void);
extern int ipforward_ipv6_off(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_IPFORWARD_H */
#include "lib/vty.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define TRUE 1
#define FALSE 0
extern void send_packet(struct interface *ifp, struct stream *s, uint32_t dst,
struct prefix *p, uint32_t ttl);
+#ifdef __cplusplus
+}
+#endif
#endif /* _IRDP_H */
timer = MAX_INITIAL_ADVERT_INTERVAL;
if (irdp->flags & IF_DEBUG_MISC)
- zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name,
+ zlog_debug("IRDP: New timer for %s set to %u", ifp->name,
timer);
irdp->t_advertise = NULL;
case ICMP_ROUTERSOLICIT:
if (irdp->flags & IF_DEBUG_MESSAGES)
- zlog_debug("IRDP: RX Solicit on %s from %s\n",
+ zlog_debug("IRDP: RX Solicit on %s from %s",
ifp->name, inet_ntoa(src));
process_solicit(ifp);
if (!(irdp->flags & IF_ACTIVE)) {
if (irdp->flags & IF_DEBUG_MISC)
- zlog_debug("IRDP: RX ICMP for disabled interface %s\n",
+ zlog_debug("IRDP: RX ICMP for disabled interface %s",
ifp->name);
return 0;
}
return lookup_msg(rttype_str, rttype, "");
}
-#define NL_OK(nla, len) \
+#define NLA_OK(nla, len) \
((len) >= (int)sizeof(struct nlattr) \
&& (nla)->nla_len >= sizeof(struct nlattr) \
&& (nla)->nla_len <= (len))
-#define NL_NEXT(nla, attrlen) \
- ((attrlen) -= RTA_ALIGN((nla)->nla_len), \
- (struct nlattr *)(((char *)(nla)) + RTA_ALIGN((nla)->nla_len)))
-#define NL_RTA(r) \
- ((struct nlattr *)(((char *)(r)) \
- + NLMSG_ALIGN(sizeof(struct nlmsgerr))))
+#define NLA_NEXT(nla, attrlen) \
+ ((attrlen) -= NLA_ALIGN((nla)->nla_len), \
+ (struct nlattr *)(((char *)(nla)) + NLA_ALIGN((nla)->nla_len)))
+#define NLA_LENGTH(len) (NLA_ALIGN(sizeof(struct nlattr)) + (len))
+#define NLA_DATA(nla) ((struct nlattr *)(((char *)(nla)) + NLA_LENGTH(0)))
+
+#define ERR_NLA(err, inner_len) \
+ ((struct nlattr *)(((char *)(err)) \
+ + NLMSG_ALIGN(sizeof(struct nlmsgerr)) \
+ + NLMSG_ALIGN((inner_len))))
static void netlink_parse_nlattr(struct nlattr **tb, int max,
struct nlattr *nla, int len)
{
- while (NL_OK(nla, len)) {
+ while (NLA_OK(nla, len)) {
if (nla->nla_type <= max)
tb[nla->nla_type] = nla;
- nla = NL_NEXT(nla, len);
+ nla = NLA_NEXT(nla, len);
}
}
static void netlink_parse_extended_ack(struct nlmsghdr *h)
{
- struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
- const struct nlmsgerr *err =
- (const struct nlmsgerr *)((uint8_t *)h
- + NLMSG_ALIGN(
- sizeof(struct nlmsghdr)));
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
+ const struct nlmsgerr *err = (const struct nlmsgerr *)NLMSG_DATA(h);
const struct nlmsghdr *err_nlh = NULL;
- uint32_t hlen = sizeof(*err);
+ /* Length not including nlmsghdr */
+ uint32_t len = 0;
+ /* Inner error netlink message length */
+ uint32_t inner_len = 0;
const char *msg = NULL;
uint32_t off = 0;
if (!(h->nlmsg_flags & NLM_F_CAPPED))
- hlen += h->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+ inner_len = (uint32_t)NLMSG_PAYLOAD(&err->msg, 0);
+
+ len = (uint32_t)(NLMSG_PAYLOAD(h, sizeof(struct nlmsgerr)) - inner_len);
- memset(tb, 0, sizeof(tb));
- netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, NL_RTA(h), hlen);
+ netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, ERR_NLA(err, inner_len),
+ len);
if (tb[NLMSGERR_ATTR_MSG])
- msg = (const char *)RTA_DATA(tb[NLMSGERR_ATTR_MSG]);
+ msg = (const char *)NLA_DATA(tb[NLMSGERR_ATTR_MSG]);
if (tb[NLMSGERR_ATTR_OFFS]) {
- off = *(uint32_t *)RTA_DATA(tb[NLMSGERR_ATTR_OFFS]);
+ off = *(uint32_t *)NLA_DATA(tb[NLMSGERR_ATTR_OFFS]);
if (off > h->nlmsg_len) {
- zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS\n");
+ zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS");
} else if (!(h->nlmsg_flags & NLM_F_CAPPED)) {
/*
* Header of failed message
#ifndef _ZEBRA_KERNEL_NETLINK_H
#define _ZEBRA_KERNEL_NETLINK_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifdef HAVE_NETLINK
#define NL_RCV_PKT_BUF_SIZE 32768
#endif /* HAVE_NETLINK */
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_KERNEL_NETLINK_H */
#ifdef RTM_OLDDEL
{RTM_OLDDEL, "RTM_OLDDEL"},
#endif /* RTM_OLDDEL */
+#ifdef RTM_RESOLVE
{RTM_RESOLVE, "RTM_RESOLVE"},
+#endif /* RTM_RESOLVE */
{RTM_NEWADDR, "RTM_NEWADDR"},
{RTM_DELADDR, "RTM_DELADDR"},
{RTM_IFINFO, "RTM_IFINFO"},
}
if (copylen > destlen) {
- zlog_warn("%s: destination buffer too small (%lu vs %lu)",
- __func__, copylen, destlen);
+ zlog_warn(
+ "%s: destination buffer too small (%zu vs %zu)",
+ __func__, copylen, destlen);
memcpy(dest, sap, destlen);
} else
memcpy(dest, sap, copylen);
if (copylen > 0 && dest != NULL && sdl->sdl_family == AF_LINK) {
if (copylen > IFNAMSIZ) {
- zlog_warn("%s: destination buffer too small (%lu vs %d)",
- __func__, copylen, IFNAMSIZ);
+ zlog_warn(
+ "%s: destination buffer too small (%zu vs %d)",
+ __func__, copylen, IFNAMSIZ);
memcpy(dest, sdl->sdl_data, IFNAMSIZ);
dest[IFNAMSIZ] = 0;
*destlen = IFNAMSIZ;
* RTA_IFP) is required.
*/
if (!ifnlen) {
- zlog_debug("Interface index %d (new) missing ifname\n",
+ zlog_debug("Interface index %d (new) missing ifname",
ifm->ifm_index);
return -1;
}
#ifndef __ZEBRA_KERNEL_SOCKET_H
#define __ZEBRA_KERNEL_SOCKET_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Error codes of zebra. */
#define ZEBRA_ERR_NOERROR 0
#define ZEBRA_ERR_RTEXIST -1
enum blackhole_type, int);
extern const struct message rtm_type_str[];
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __ZEBRA_KERNEL_SOCKET_H */
#include "zebra/zserv.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define NO_PROTO 0
/*
int release_daemon_label_chunks(struct zserv *client);
void label_manager_close(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _LABEL_MANAGER_H */
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)
#include "zebra/zserv.h"
#include "zebra/rib.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* ZAPI command handlers */
extern void zebra_redistribute_add(ZAPI_HANDLER_ARGS);
extern void zebra_redistribute_delete(ZAPI_HANDLER_ARGS);
extern int zebra_import_table_config(struct vty *);
extern void zebra_import_table_rm_update(const char *rmap);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_REDISTRIBUTE_H */
#include "mpls.h"
#include "srcdest_table.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define DISTANCE_INFINITY 255
#define ZEBRA_KERNEL_TABLE_MAX 252 /* support for no more than this rt tables */
*/
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 pid_t pid;
extern bool v6_rr_semantics;
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /*_ZEBRA_RIB_H */
#include "zclient.h"
#include "if.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern void router_id_add_address(struct connected *);
extern void router_id_del_address(struct connected *);
extern void router_id_init(struct zebra_vrf *);
extern void router_id_write(struct vty *);
extern void router_id_get(struct prefix *, vrf_id_t);
+#ifdef __cplusplus
+}
+#endif
+
#endif
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_dplane.h"
+#ifdef __cplusplus
+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.
struct interface *vlan_if);
extern void route_read(struct zebra_ns *zns);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_RT_H */
if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) {
/* If this is not route add/delete message print warning. */
- zlog_debug("Kernel message: %s NS %u\n",
+ zlog_debug("Kernel message: %s NS %u",
nl_msg_type_to_str(h->nlmsg_type), ns_id);
return 0;
}
uint8_t gw_family,
struct nlmsghdr *nlmsg,
size_t req_size, int bytelen,
- struct nexthop *nexthop)
+ const struct nexthop *nexthop)
{
if (route_family == AF_MPLS) {
struct gw_family_t gw_fam;
struct rtattr *rta,
struct rtnexthop *rtnh,
size_t req_size, int bytelen,
- struct nexthop *nexthop)
+ const struct nexthop *nexthop)
{
if (route_family == AF_MPLS) {
struct gw_family_t gw_fam;
* @param req_size: The size allocated for the message.
*/
static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
- struct nexthop *nexthop,
+ const struct nexthop *nexthop,
struct nlmsghdr *nlmsg,
struct rtmsg *rtmsg,
size_t req_size, int cmd)
label_buf[0] = '\0';
assert(nexthop);
- for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
+ for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
char label_buf1[20];
nh_label = nh->nh_label;
* the prefsrc should be stored.
*/
static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
- struct nexthop *nexthop,
+ const struct nexthop *nexthop,
struct rtattr *rta,
struct rtnexthop *rtnh,
struct rtmsg *rtmsg,
- union g_addr **src)
+ const union g_addr **src)
{
struct mpls_label_stack *nh_label;
mpls_lse_t out_lse[MPLS_MAX_LABELS];
label_buf[0] = '\0';
assert(nexthop);
- for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
+ for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
char label_buf1[20];
nh_label = nh->nh_label;
}
static inline void _netlink_mpls_build_singlepath(const char *routedesc,
- zebra_nhlfe_t *nhlfe,
+ const zebra_nhlfe_t *nhlfe,
struct nlmsghdr *nlmsg,
struct rtmsg *rtmsg,
size_t req_size, int cmd)
static inline void
-_netlink_mpls_build_multipath(const char *routedesc, zebra_nhlfe_t *nhlfe,
+_netlink_mpls_build_multipath(const char *routedesc, const zebra_nhlfe_t *nhlfe,
struct rtattr *rta, struct rtnexthop *rtnh,
- struct rtmsg *rtmsg, union g_addr **src)
+ struct rtmsg *rtmsg, const union g_addr **src)
{
int bytelen;
uint8_t family;
static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
{
int bytelen;
- struct sockaddr_nl snl;
struct nexthop *nexthop = NULL;
unsigned int nexthop_num;
int family;
char buf[NL_PKT_BUF_SIZE];
struct rtattr *rta = (void *)buf;
struct rtnexthop *rtnh;
- union g_addr *src1 = NULL;
+ const union g_addr *src1 = NULL;
rta->rta_type = RTA_MULTIPATH;
rta->rta_len = RTA_LENGTH(0);
}
skip:
-
- /* Destination netlink address. */
- memset(&snl, 0, sizeof(snl));
- snl.nl_family = AF_NETLINK;
-
/* Talk to netlink socket. */
return netlink_talk_info(netlink_talk_filter, &req.n,
dplane_ctx_get_ns(ctx), 0);
* 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.
/* The interface should exist. */
ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
ndm->ndm_ifindex);
- if (!ifp || !ifp->info)
+ if (!ifp || !ifp->info) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("\t%s without associated interface: %u",
+ __PRETTY_FUNCTION__, ndm->ndm_ifindex);
return 0;
+ }
/* The interface should be something we're interested in. */
- if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
+ if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("\t%s Not interested in %s, not a slave",
+ __PRETTY_FUNCTION__, ifp->name);
return 0;
+ }
/* Drop "permanent" entries. */
- if (ndm->ndm_state & NUD_PERMANENT)
+ if (ndm->ndm_state & NUD_PERMANENT) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("\t%s Entry is PERMANENT, dropping",
+ __PRETTY_FUNCTION__);
return 0;
+ }
zif = (struct zebra_if *)ifp->info;
if ((br_if = zif->brslave_info.br_if) == NULL) {
- zlog_debug("%s family %s IF %s(%u) brIF %u - no bridge master",
- nl_msg_type_to_str(h->nlmsg_type),
- nl_family_to_str(ndm->ndm_family), ifp->name,
- ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex);
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "%s family %s IF %s(%u) brIF %u - no bridge master",
+ nl_msg_type_to_str(h->nlmsg_type),
+ nl_family_to_str(ndm->ndm_family), ifp->name,
+ ndm->ndm_ifindex,
+ zif->brslave_info.bridge_ifindex);
return 0;
}
netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
if (!tb[NDA_LLADDR]) {
- zlog_debug("%s family %s IF %s(%u) brIF %u - no LLADDR",
- nl_msg_type_to_str(h->nlmsg_type),
- nl_family_to_str(ndm->ndm_family), ifp->name,
- ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex);
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s family %s IF %s(%u) brIF %u - no LLADDR",
+ nl_msg_type_to_str(h->nlmsg_type),
+ nl_family_to_str(ndm->ndm_family), ifp->name,
+ ndm->ndm_ifindex,
+ zif->brslave_info.bridge_ifindex);
return 0;
}
if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {
- zlog_debug(
- "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %lu",
- nl_msg_type_to_str(h->nlmsg_type),
- nl_family_to_str(ndm->ndm_family), ifp->name,
- ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex,
- (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR]));
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %lu",
+ nl_msg_type_to_str(h->nlmsg_type),
+ nl_family_to_str(ndm->ndm_family), ifp->name,
+ ndm->ndm_ifindex,
+ zif->brslave_info.bridge_ifindex,
+ (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR]));
return 0;
}
prefix_mac2str(&mac, buf, sizeof(buf)),
dst_present ? dst_buf : "");
- if (filter_vlan && vid != filter_vlan)
+ if (filter_vlan && vid != filter_vlan) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("\tFiltered due to filter vlan: %d",
+ filter_vlan);
return 0;
+ }
/* If add or update, do accordingly if learnt on a "local" interface; if
* the notification is over VxLAN, this has to be related to
* so perform an implicit delete of any local entry (if it exists).
*/
if (h->nlmsg_type == RTM_NEWNEIGH) {
- /* Drop "permanent" entries. */
- if (ndm->ndm_state & NUD_PERMANENT)
- return 0;
-
if (IS_ZEBRA_IF_VXLAN(ifp))
return zebra_vxlan_check_del_local_mac(ifp, br_if, &mac,
vid);
* Ignore the notification from VxLan driver as it is also generated
* when mac moves from remote to local.
*/
- if (dst_present)
+ if (dst_present) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("\tNo Destination Present");
return 0;
+ }
if (IS_ZEBRA_IF_VXLAN(ifp))
return zebra_vxlan_check_readd_remote_mac(ifp, br_if, &mac,
/* if kernel deletes our rfc5549 neighbor entry, re-install it */
if (h->nlmsg_type == RTM_DELNEIGH && (ndm->ndm_state & NUD_PERMANENT)) {
netlink_handle_5549(ndm, zif, ifp, &ip);
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "\tNeighbor Entry Received is a 5549 entry, finished");
return 0;
}
return 0;
} else if (IS_ZEBRA_IF_BRIDGE(ifp))
link_if = ifp;
- else
+ else {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "\tNeighbor Entry received is not on a VLAN or a BRIDGE, ignoring");
return 0;
+ }
memset(&mac, 0, sizeof(struct ethaddr));
if (h->nlmsg_type == RTM_NEWNEIGH) {
if (tb[NDA_LLADDR]) {
if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {
- zlog_debug(
- "%s family %s IF %s(%u) - LLADDR is not MAC, len %lu",
- nl_msg_type_to_str(h->nlmsg_type),
- nl_family_to_str(ndm->ndm_family),
- ifp->name, ndm->ndm_ifindex,
- (unsigned long)RTA_PAYLOAD(
- tb[NDA_LLADDR]));
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "%s family %s IF %s(%u) - LLADDR is not MAC, len %lu",
+ nl_msg_type_to_str(
+ h->nlmsg_type),
+ nl_family_to_str(
+ ndm->ndm_family),
+ ifp->name, ndm->ndm_ifindex,
+ (unsigned long)RTA_PAYLOAD(
+ tb[NDA_LLADDR]));
return 0;
}
int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
{
mpls_lse_t lse;
- zebra_nhlfe_t *nhlfe;
+ const zebra_nhlfe_t *nhlfe;
struct nexthop *nexthop = NULL;
unsigned int nexthop_num;
const char *routedesc;
char buf[NL_PKT_BUF_SIZE];
struct rtattr *rta = (void *)buf;
struct rtnexthop *rtnh;
- union g_addr *src1 = NULL;
+ const union g_addr *src1 = NULL;
rta->rta_type = RTA_MULTIPATH;
rta->rta_len = RTA_LENGTH(0);
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_dplane.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define NL_DEFAULT_ROUTE_METRIC 20
/*
extern int netlink_neigh_read_specific_ip(struct ipaddr *ip,
struct interface *vlan_if);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* HAVE_NETLINK */
#endif /* _ZEBRA_RT_NETLINK_H */
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;
}
#include "vty.h"
#include "zebra/interface.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* NB: RTADV is defined in zebra/interface.h above */
#if defined(HAVE_RTADV)
extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS);
extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS);
+#ifdef __cplusplus
+}
+#endif
#endif /* _ZEBRA_RTADV_H */
#ifdef HAVE_NETLINK
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* Handle netlink notification informing a rule add or delete.
*/
*/
extern int netlink_rules_read(struct zebra_ns *zns);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* HAVE_NETLINK */
#endif /* _ZEBRA_RULE_NETLINK_H */
#include "zebra/zserv.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* Table chunk struct
* Client daemon which the chunk belongs to can be identified by either
int release_daemon_table_chunks(struct zserv *client);
void table_manager_disable(ns_id_t ns_id);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _TABLE_MANAGER_H */
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);
}
&(api_nh->gate.ipv4),
sizeof(struct in_addr));
zebra_vxlan_evpn_vrf_route_add(
- vrf_id, &api_nh->rmac, &vtep_ip,
- &api.prefix);
+ api_nh->vrf_id, &api_nh->rmac,
+ &vtep_ip, &api.prefix);
}
break;
case NEXTHOP_TYPE_IPV6:
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);
+ api_nh->vrf_id, &api_nh->rmac,
+ &vtep_ip, &api.prefix);
}
break;
case NEXTHOP_TYPE_BLACKHOLE:
#include "zebra/zebra_pbr.h"
#include "zebra/zebra_errors.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* This is called to process inbound ZAPI messages.
*
const unsigned int nexthop_num);
extern void zsend_capabilities_all_clients(void);
+
+#ifdef __cplusplus
+}
+#endif
int af;
int status;
uint32_t flags;
- union g_addr nexthop;
+ union g_addr dest;
mpls_label_t local_label;
mpls_label_t remote_label;
+ /* Nexthops */
+ struct nexthop_group nhg;
+
union pw_protocol_fields fields;
};
case DPLANE_OP_PW_INSTALL:
case DPLANE_OP_PW_UNINSTALL:
+ /* Free allocated nexthops */
+ if ((*pctx)->u.pw.nhg.nexthop) {
+ /* This deals with recursive nexthops too */
+ nexthops_free((*pctx)->u.pw.nhg.nexthop);
+
+ (*pctx)->u.pw.nhg.nexthop = NULL;
+ }
+ break;
+
case DPLANE_OP_NONE:
break;
}
ret = "PW_UNINSTALL";
break;
- };
+ }
return ret;
}
case ZEBRA_DPLANE_REQUEST_SUCCESS:
ret = "SUCCESS";
break;
- };
+ }
return ret;
}
return ctx->u.lsp.flags;
}
-zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx)
+const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const 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)
+const zebra_nhlfe_t *
+dplane_ctx_get_best_nhlfe(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 union g_addr *dplane_ctx_get_pw_dest(
const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return &(ctx->u.pw.nexthop);
+ return &(ctx->u.pw.dest);
}
const union pw_protocol_fields *dplane_ctx_get_pw_proto(
return &(ctx->u.pw.fields);
}
+const struct nexthop_group *
+dplane_ctx_get_pw_nhg(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.pw.nhg);
+}
+
/*
* End of dplane context accessors
*/
enum dplane_op_e op,
struct zebra_pw *pw)
{
- int ret = AOK;
+ struct prefix p;
+ afi_t afi;
+ struct route_table *table;
+ struct route_node *rn;
+ struct route_entry *re;
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u",
/* 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.remote_label = pw->remote_label;
ctx->u.pw.flags = pw->flags;
- ctx->u.pw.nexthop = pw->nexthop;
+ ctx->u.pw.dest = pw->nexthop;
ctx->u.pw.fields = pw->data;
- return ret;
+ /* Capture nexthop info for the pw destination. We need to look
+ * up and use zebra datastructs, but we're running in the zebra
+ * pthread here so that should be ok.
+ */
+ memcpy(&p.u, &pw->nexthop, sizeof(pw->nexthop));
+ p.family = pw->af;
+ p.prefixlen = ((pw->af == AF_INET) ?
+ IPV4_MAX_PREFIXLEN : IPV6_MAX_PREFIXLEN);
+
+ afi = (pw->af == AF_INET) ? AFI_IP : AFI_IP6;
+ table = zebra_vrf_table(afi, SAFI_UNICAST, pw->vrf_id);
+ if (table) {
+ rn = route_node_match(table, &p);
+ if (rn) {
+ RNODE_FOREACH_RE(rn, re) {
+ if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
+ break;
+ }
+
+ if (re)
+ copy_nexthops(&(ctx->u.pw.nhg.nexthop),
+ re->ng.nexthop, NULL);
+
+ route_unlock_node(rn);
+ }
+ }
+
+ return AOK;
}
/*
/* Allocate and init new provider struct */
p = XCALLOC(MTYPE_DP_PROV, sizeof(struct zebra_dplane_provider));
- if (p == NULL) {
- ret = ENOMEM;
- goto done;
- }
pthread_mutex_init(&(p->dp_mutex), NULL);
TAILQ_INIT(&(p->dp_ctx_in_q));
if (ctx == NULL)
break;
+ /* A previous provider plugin may have asked to skip the
+ * kernel update.
+ */
+ if (dplane_ctx_is_skip_kernel(ctx)) {
+ res = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ goto skip_one;
+ }
+
/* Dispatch to appropriate kernel-facing apis */
switch (dplane_ctx_get_op(ctx)) {
break;
}
+skip_one:
dplane_ctx_set_status(ctx, res);
dplane_provider_enqueue_out_ctx(prov, ctx);
#include "zebra/zserv.h"
#include "zebra/zebra_mpls.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Key netlink info from zebra ns */
struct zebra_dplane_info {
ns_id_t ns_id;
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);
+const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const struct zebra_dplane_ctx *ctx);
+const zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(
+ const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx);
/* Accessors for pseudowire information */
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 union g_addr *dplane_ctx_get_pw_dest(
const struct zebra_dplane_ctx *ctx);
const union pw_protocol_fields *dplane_ctx_get_pw_proto(
const struct zebra_dplane_ctx *ctx);
+const struct nexthop_group *dplane_ctx_get_pw_nhg(
+ const struct zebra_dplane_ctx *ctx);
/* Namespace info - esp. for netlink communication */
const struct zebra_dplane_info *dplane_ctx_get_ns(
void zebra_dplane_finish(void);
void zebra_dplane_shutdown(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_DPLANE_H */
#include "lib/ferr.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
enum zebra_log_refs {
EC_ZEBRA_LM_RESPONSE = ZEBRA_FERR_START,
EC_ZEBRA_LM_NO_SUCH_CLIENT,
void zebra_error_init(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __EC_ZEBRAORS_H__ */
#include "zebra/debug.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
#define zfpm_debug(...) \
uint8_t *in_buf, size_t in_buf_len);
extern struct route_entry *zfpm_route_for_update(rib_dest_t *dest);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_FPM_PRIVATE_H */
#include "vlan.h"
#include "vxlan.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* zebra L2 interface information - bridge slave (linkage to bridge) */
struct zebra_l2info_brslave {
ifindex_t bridge_ifindex; /* Bridge Master */
extern void zebra_l2if_update_bond_slave(struct interface *ifp,
ifindex_t bond_ifindex);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_L2_H */
#include "memory.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
DECLARE_MGROUP(ZEBRA)
DECLARE_MTYPE(RTADV_PREFIX)
DECLARE_MTYPE(ZEBRA_NS)
DECLARE_MTYPE(DP_CTX)
DECLARE_MTYPE(DP_PROV)
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _QUAGGA_ZEBRA_MEMORY_H */
#include "mlag.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void zebra_mlag_init(void);
void zebra_mlag_terminate(void);
enum mlag_role zebra_mlag_get_role(void);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
lsp->ile.in_label, lsp->flags);
lsp = hash_release(lsp_table, &lsp->ile);
- if (lsp)
- XFREE(MTYPE_LSP, lsp);
+ XFREE(MTYPE_LSP, lsp);
}
return 0;
lsp->ile.in_label, lsp->flags);
lsp = hash_release(lsp_table, &lsp->ile);
- if (lsp)
- XFREE(MTYPE_LSP, lsp);
+ XFREE(MTYPE_LSP, lsp);
}
return 0;
lsp->ile.in_label, lsp->flags);
lsp = hash_release(lsp_table, &lsp->ile);
- if (lsp)
- XFREE(MTYPE_LSP, lsp);
+ XFREE(MTYPE_LSP, lsp);
}
}
lsp->ile.in_label, lsp->flags);
lsp = hash_release(lsp_table, &lsp->ile);
- if (lsp)
- XFREE(MTYPE_LSP, lsp);
+ XFREE(MTYPE_LSP, lsp);
}
return 0;
slsp->snhlfe_list = snhlfe->next;
snhlfe->prev = snhlfe->next = NULL;
- if (snhlfe->ifname)
- XFREE(MTYPE_SNHLFE_IFNAME, snhlfe->ifname);
+ XFREE(MTYPE_SNHLFE_IFNAME, snhlfe->ifname);
XFREE(MTYPE_SNHLFE, snhlfe);
return 0;
lsp->ile.in_label, lsp->flags);
lsp = hash_release(lsp_table, &lsp->ile);
- if (lsp)
- XFREE(MTYPE_LSP, lsp);
+ XFREE(MTYPE_LSP, lsp);
}
}
return 0;
* above. */
if (!slsp->snhlfe_list) {
slsp = hash_release(slsp_table, &tmp_ile);
- if (slsp)
- XFREE(MTYPE_SLSP, slsp);
+ XFREE(MTYPE_SLSP, slsp);
}
return 0;
#include "zebra/zserv.h"
#include "zebra/zebra_vrf.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
/* Definitions and macros. */
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. */
extern int mpls_enabled;
+#ifdef __cplusplus
+}
+#endif
+
#endif /*_ZEBRA_MPLS_H */
} kr_state;
static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label,
- zebra_nhlfe_t *nhlfe)
+ const zebra_nhlfe_t *nhlfe)
{
struct iovec iov[5];
struct rt_msghdr hdr;
#endif
static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label,
- zebra_nhlfe_t *nhlfe)
+ const zebra_nhlfe_t *nhlfe)
{
struct iovec iov[5];
struct rt_msghdr hdr;
static int kernel_lsp_cmd(struct zebra_dplane_ctx *ctx)
{
- zebra_nhlfe_t *nhlfe;
+ const zebra_nhlfe_t *nhlfe;
struct nexthop *nexthop = NULL;
unsigned int nexthop_num = 0;
int action;
/* pseudowire nexthop */
memset(&ss, 0, sizeof(ss));
- gaddr = dplane_ctx_get_pw_nexthop(ctx);
+ gaddr = dplane_ctx_get_pw_dest(ctx);
switch (dplane_ctx_get_pw_af(ctx)) {
case AF_INET:
sa_in->sin_family = AF_INET;
break;
default:
break;
- };
+ }
return result;
}
#include "zebra/zserv.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct mcast_route_data {
struct prefix_sg sg;
unsigned int ifindex;
void zebra_ipmr_route_stats(ZAPI_HANDLER_ARGS);
+#ifdef __cplusplus
+}
+#endif
+
#endif
#include "zebra.h"
#include "ns.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern ns_id_t zebra_ns_id_get(const char *netnspath);
extern ns_id_t zebra_ns_id_get_default(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __ZEBRA_NS_ID_H__ */
#ifndef _NETNS_NOTIFY_H
#define _NETNS_NOTIFY_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern void zebra_ns_notify_init(void);
extern void zebra_ns_notify_parse(void);
extern void zebra_ns_notify_close(void);
extern struct zebra_privs_t zserv_privs;
+#ifdef __cplusplus
+}
+#endif
+
#endif /* NETNS_NOTIFY_H */
#include "zebra/rib.h"
#include "zebra/zebra_vrf.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifdef HAVE_NETLINK
/* Socket interface to kernel */
struct nlsock {
int zebra_ns_config_write(struct vty *vty, struct ns *ns);
+#ifdef __cplusplus
+}
+#endif
+
#endif
r2 = (const struct zebra_pbr_iptable *)arg2;
if (r1->vrf_id != r2->vrf_id)
- return 0;
+ return false;
if (r1->type != r2->type)
return false;
if (r1->unique != r2->unique)
#include "rt.h"
#include "pbr.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct zebra_pbr_rule {
int sock;
DECLARE_HOOK(zebra_pbr_ipset_update,
(int cmd, struct zebra_pbr_ipset *ipset), (cmd, ipset));
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_PBR_H */
if (!old_ptm_enable && ptm_cb.ptm_enable) {
if (!if_is_operative(ifp) && send_linkdown) {
if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("%s: Bringing down interface %s\n",
+ zlog_debug("%s: Bringing down interface %s",
__func__, ifp->name);
if_down(ifp);
}
ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
if (if_is_no_ptm_operative(ifp) && send_linkup) {
if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("%s: Bringing up interface %s\n",
+ zlog_debug("%s: Bringing up interface %s",
__func__, ifp->name);
if_up(ifp);
}
/* Allocate and register new process. */
pp = XCALLOC(MTYPE_ZEBRA_PTM_BFD_PROCESS, sizeof(*pp));
- if (pp == NULL)
- return NULL;
pp->pp_pid = pid;
pp->pp_zs = zs;
#include "zebra/zserv.h"
#include "zebra/interface.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Zebra ptm context block */
struct zebra_ptm_cb {
int ptm_sock; /* ptm file descriptor. */
void zebra_ptm_if_set_ptm_state(struct interface *ifp,
struct zebra_if *zebra_ifp);
void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
#ifndef _ZEBRA_PTM_REDISTRIBUTE_H
#define _ZEBRA_PTM_REDISTRIBUTE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern void zebra_interface_bfd_update(struct interface *, struct prefix *,
struct prefix *, int, vrf_id_t);
extern void zebra_bfd_peer_replay_req(void);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_PTM_REDISTRIBUTE_H */
#include "zebra/zebra_vrf.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define PW_INSTALL_RETRY_INTERVAL 30
struct zebra_pw {
void zebra_pw_exit(struct zebra_vrf *);
void zebra_pw_vty_init(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* ZEBRA_PW_H_ */
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 = NULL;
- }
- /* 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;
}
}
}
*/
static int handle_pw_result(struct zebra_dplane_ctx *ctx)
{
- int ret = 0;
struct zebra_pw *pw;
struct zebra_vrf *vrf;
done:
- return ret;
+ return 0;
}
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\n", 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);
table = get_rnh_table(vrfid, afi, type);
if (!table) {
- zlog_debug("print_rnhs: rnh table not found\n");
+ zlog_debug("print_rnhs: rnh table not found");
return;
}
static void free_state(vrf_id_t vrf_id, struct route_entry *re,
struct route_node *rn)
{
-
if (!re)
return;
ntable = get_rnh_table(vrf_id, afi, type);
if (!ntable) {
- zlog_debug("cleanup_rnh_client: rnh table not found\n");
+ zlog_debug("cleanup_rnh_client: rnh table not found");
return -1;
}
#include "prefix.h"
#include "vty.h"
+#ifdef __cplusplus
+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;
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);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /*_ZEBRA_RNH_H */
break;
}
- if (dep_name)
- XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
- if (rmap_name)
- XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
+ XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
+ XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
return retval;
}
#include "lib/routemap.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern void zebra_route_map_init(void);
extern void zebra_routemap_config_write_protocol(struct vty *vty,
struct zebra_vrf *vrf);
struct zebra_vrf *zvrf, struct route_entry *,
struct nexthop *nexthop);
+#ifdef __cplusplus
+}
+#endif
+
#endif
{
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);
+
XFREE(MTYPE_RIB_TABLE_INFO, table_info);
XFREE(MTYPE_ZEBRA_NS, zrt);
}
+void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid,
+ afi_t afi, safi_t safi)
+{
+ struct zebra_router_table finder;
+ struct zebra_router_table *zrt;
+
+ memset(&finder, 0, sizeof(finder));
+ finder.afi = afi;
+ finder.safi = safi;
+ finder.tableid = tableid;
+ finder.ns_id = zvrf->zns->ns_id;
+ zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder);
+
+ if (!zrt)
+ return;
+
+ zebra_router_free_table(zrt);
+}
+
uint32_t zebra_router_get_next_sequence(void)
{
return 1
#include "zebra/zebra_ns.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* This header file contains the idea of a router and as such
* owns data that is associated with a router from zebra's
/* Mlag information for the router */
struct zebra_mlag_info mlag_info;
+
+ /*
+ * The EVPN instance, if any
+ */
+ struct zebra_vrf *evpn_vrf;
};
extern struct zebra_router zrouter;
extern struct route_table *zebra_router_get_table(struct zebra_vrf *zvrf,
uint32_t tableid, afi_t afi,
safi_t safi);
+extern void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid,
+ afi_t afi, safi_t safi);
extern int zebra_router_config_write(struct vty *vty);
extern void zebra_router_show_table_summary(struct vty *vty);
extern uint32_t zebra_router_get_next_sequence(void);
+
+static inline vrf_id_t zebra_vrf_get_evpn_id(void)
+{
+ return zrouter.evpn_vrf ? zvrf_id(zrouter.evpn_vrf) : VRF_DEFAULT;
+}
+static inline struct zebra_vrf *zebra_vrf_get_evpn(void)
+{
+ return zrouter.evpn_vrf ? zrouter.evpn_vrf
+ : zebra_vrf_lookup_by_id(VRF_DEFAULT);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
/* Remove all routes. */
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+ route_table_finish(zvrf->rnh_table[afi]);
+ zvrf->rnh_table[afi] = NULL;
+ route_table_finish(zvrf->import_check_table[afi]);
+ zvrf->import_check_table[afi] = NULL;
+
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
rib_close_table(zvrf->table[afi][safi]);
}
* table, see rib_close_table above
* we no-longer need this pointer.
*/
- for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
+ for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
+ zebra_router_release_table(zvrf, zvrf->table_id, afi,
+ safi);
zvrf->table[afi][safi] = NULL;
-
- route_table_finish(zvrf->rnh_table[afi]);
- zvrf->rnh_table[afi] = NULL;
- route_table_finish(zvrf->import_check_table[afi]);
- zvrf->import_check_table[afi] = NULL;
+ }
}
return 0;
/* release allocated memory */
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
- void *table_info;
-
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
table = zvrf->table[afi][safi];
if (table) {
- table_info = route_table_get_info(table);
- route_table_finish(table);
- XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+ zebra_router_release_table(zvrf, zvrf->table_id,
+ afi, safi);
+ zvrf->table[afi][safi] = NULL;
}
}
- route_table_finish(zvrf->rnh_table[afi]);
- route_table_finish(zvrf->import_check_table[afi]);
+ if (zvrf->rnh_table[afi])
+ route_table_finish(zvrf->rnh_table[afi]);
+ if (zvrf->import_check_table[afi])
+ route_table_finish(zvrf->import_check_table[afi]);
}
/* Cleanup EVPN states for vrf */
rib_unlink(node, re);
}
- if (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. */
#include <zebra/zebra_pw.h>
#include <lib/vxlan.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* MPLS (Segment Routing) global block */
typedef struct mpls_srgb_t_ {
uint32_t start_label;
#define MPLS_FLAG_SCHEDULE_LSPS (1 << 0)
/*
- * VNI hash table (for EVPN). Only in default instance.
+ * VNI hash table (for EVPN). Only in the EVPN instance.
*/
struct hash *vni_table;
/*
- * Whether EVPN is enabled or not. Only in default instance.
+ * Whether EVPN is enabled or not. Only in the EVPN instance.
*/
int advertise_all_vni;
/*
* Whether we are advertising g/w macip in EVPN or not.
- * Only in default instance.
+ * Only in the EVPN instance.
*/
int advertise_gw_macip;
extern void zebra_rtable_node_cleanup(struct route_table *table,
struct route_node *node);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* ZEBRA_VRF_H */
json_object *json_labels = NULL;
time_t uptime;
struct tm *tm;
+ rib_dest_t *dest = rib_dest_from_rnode(rn);
uptime = time(NULL);
uptime -= re->uptime;
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
json_object_boolean_true_add(json_route, "selected");
+ if (dest->selected_fib == re)
+ json_object_boolean_true_add(json_route,
+ "destSelected");
+
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_QUEUED))
json_object_boolean_true_add(json_route, "queued");
- if (re->type != ZEBRA_ROUTE_CONNECT) {
- json_object_int_add(json_route, "distance",
- re->distance);
- json_object_int_add(json_route, "metric", re->metric);
- }
-
if (re->tag)
json_object_int_add(json_route, "tag", re->tag);
else
rib_cnt[re->type]++;
- if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
fib_cnt[ZEBRA_ROUTE_TOTAL]++;
if (is_ibgp)
return CMD_SUCCESS;
}
-DEFUN_HIDDEN (default_vrf_vni_mapping,
+DEFUN (default_vrf_vni_mapping,
default_vrf_vni_mapping_cmd,
"vni " CMD_VNI_RANGE "[prefix-routes-only]",
"VNI corresponding to the DEFAULT VRF\n"
return CMD_SUCCESS;
}
-DEFUN_HIDDEN (no_default_vrf_vni_mapping,
+DEFUN (no_default_vrf_vni_mapping,
no_default_vrf_vni_mapping_cmd,
"no vni " CMD_VNI_RANGE,
NO_STR
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_vnis(vty, zvrf, uj);
return CMD_SUCCESS;
}
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_vnis_detail(vty, zvrf, uj);
return CMD_SUCCESS;
}
bool uj = use_json(argc, argv);
vni = strtoul(argv[3]->arg, NULL, 10);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_vni(vty, zvrf, vni, uj);
return CMD_SUCCESS;
}
bool uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_vni(vty, zvrf, vni, uj);
return CMD_SUCCESS;
}
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_all_vni(vty, zvrf, false, uj);
return CMD_SUCCESS;
}
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_all_vni_detail(vty, zvrf, false, uj);
return CMD_SUCCESS;
}
vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_all_vni_vtep(vty, zvrf, vtep_ip, uj);
return CMD_SUCCESS;
vty_out(vty, "%% Malformed MAC address");
return CMD_WARNING;
}
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_specific_mac_vni(vty, zvrf, vni, &mac, uj);
return CMD_SUCCESS;
}
return CMD_WARNING;
}
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_vni_vtep(vty, zvrf, vni, vtep_ip, uj);
return CMD_SUCCESS;
}
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_all_vni(vty, zvrf, true, uj);
return CMD_SUCCESS;
}
bool uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_vni_dad(vty, zvrf, vni, uj);
bool uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_neigh_vni_dad(vty, zvrf, vni, uj);
return CMD_SUCCESS;
}
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_neigh_all_vni(vty, zvrf, true, uj);
return CMD_SUCCESS;
}
bool uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_neigh_vni(vty, zvrf, vni, uj);
return CMD_SUCCESS;
}
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_neigh_all_vni(vty, zvrf, false, uj);
return CMD_SUCCESS;
}
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_neigh_all_vni_detail(vty, zvrf, false, uj);
return CMD_SUCCESS;
}
vty_out(vty, "%% Malformed Neighbor address\n");
return CMD_WARNING;
}
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_specific_neigh_vni(vty, zvrf, vni, &ip, uj);
return CMD_SUCCESS;
}
return CMD_WARNING;
}
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_neigh_vni_vtep(vty, zvrf, vni, vtep_ip, uj);
return CMD_SUCCESS;
}
struct ethaddr mac_addr;
int ret = CMD_SUCCESS;
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
if (vni_val) {
vni = strtoul(vni_val, NULL, 10);
{
struct zebra_vrf *zvrf;
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
if (zvrf && zvrf->advertise_gw_macip)
return 1;
{
struct zebra_vrf *zvrf;
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
if (zvrf && zvrf->advertise_svi_macip)
return 1;
SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
/* Capture Duplicate detection time */
nbr->dad_dup_detect_time = monotime(NULL);
+ /* Mark neigh inactive */
+ ZEBRA_NEIGH_SET_INACTIVE(nbr);
+
return 1;
} else if (is_old_mac_dup && !is_new_mac_dup) {
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
struct zebra_vrf *zvrf = NULL;
struct timeval detect_start_time = {0, 0};
- zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
if (!zvrf)
return;
- zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
ipaddr2str(&n->ip, buf2, sizeof(buf2));
prefix_mac2str(&n->emac, buf1, sizeof(buf1));
type_str = CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) ?
struct zebra_vrf *zvrf;
struct timeval detect_start_time = {0, 0};
- zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
+ if (!zvrf)
+ return;
vty = (struct vty *)ctxt;
prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
- zclient_create_header(s, cmd, VRF_DEFAULT);
+ zclient_create_header(s, cmd, zebra_vrf_get_evpn_id());
stream_putl(s, vni);
stream_put(s, macaddr->octet, ETH_ALEN);
if (ip) {
memcpy(&n->emac, mac, ETH_ALEN);
n->state = ZEBRA_NEIGH_INACTIVE;
+ n->zvni = zvni;
+ n->dad_ip_auto_recovery_timer = NULL;
/* Associate the neigh to mac */
zmac = zvni_mac_lookup(zvni, mac);
if (zmac)
listnode_delete(zmac->neigh_list, n);
+ /* Cancel auto recovery */
+ THREAD_OFF(n->dad_ip_auto_recovery_timer);
+
/* Free the VNI hash entry and allocated memory. */
tmp_n = hash_release(zvni->neigh_table, n);
- if (tmp_n)
- XFREE(MTYPE_NEIGH, tmp_n);
+ XFREE(MTYPE_NEIGH, tmp_n);
return 0;
}
}
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
- if (!zvrf)
+ if (!zvrf) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("\tUnable to find vrf for: %d",
+ zvni->vxlan_if->vrf_id);
return -1;
+ }
/* Check if the neighbor exists. */
n = zvni_neigh_lookup(zvni, ip);
cur_is_router = !!CHECK_FLAG(n->flags,
ZEBRA_NEIGH_ROUTER_FLAG);
if (!mac_different && is_router == cur_is_router) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "\tIgnoring entry mac is the same and is_router == cur_is_router");
n->ifindex = ifp->ifindex;
return 0;
}
return zvni_neigh_send_add_to_client(
zvni->vni, ip, macaddr,
n->flags, n->loc_seq);
+ else {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "\tNeighbor active and frozen");
+ }
return 0;
}
return 0;
}
- ZEBRA_NEIGH_SET_ACTIVE(n);
n->loc_seq = zmac->loc_seq;
- if (!neigh_on_hold)
+ if (!neigh_on_hold) {
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+
return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
n->flags, n->loc_seq);
+ } else {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("\tNeighbor on hold not sending");
+ }
return 0;
}
mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc);
assert(mac);
+ mac->zvni = zvni;
+ mac->dad_mac_auto_recovery_timer = NULL;
+
mac->neigh_list = list_new();
mac->neigh_list->cmp = neigh_list_cmp;
{
zebra_mac_t *tmp_mac;
+ /* Cancel auto recovery */
+ THREAD_OFF(mac->dad_mac_auto_recovery_timer);
+
list_delete(&mac->neigh_list);
/* Free the VNI hash entry and allocated memory. */
tmp_mac = hash_release(zvni->mac_table, mac);
- if (tmp_mac)
- XFREE(MTYPE_MAC, tmp_mac);
+ XFREE(MTYPE_MAC, tmp_mac);
return 0;
}
zebra_vni_t tmp_vni;
zebra_vni_t *zvni = NULL;
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
assert(zvrf);
memset(&tmp_vni, 0, sizeof(zebra_vni_t));
tmp_vni.vni = vni;
zebra_vni_t tmp_zvni;
zebra_vni_t *zvni = NULL;
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
assert(zvrf);
memset(&tmp_zvni, 0, sizeof(zebra_vni_t));
tmp_zvni.vni = vni;
struct zebra_vrf *zvrf;
zebra_vni_t *tmp_zvni;
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
assert(zvrf);
zvni->vxlan_if = NULL;
/* Free the VNI hash entry and allocated memory. */
tmp_zvni = hash_release(zvrf->vni_table, zvni);
- if (tmp_zvni)
- XFREE(MTYPE_ZVNI, tmp_zvni);
+ XFREE(MTYPE_ZVNI, tmp_zvni);
return 0;
}
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
- zclient_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT);
+ zclient_create_header(s, ZEBRA_VNI_ADD, zebra_vrf_get_evpn_id());
stream_putl(s, zvni->vni);
stream_put_in_addr(s, &zvni->local_vtep_ip);
stream_put(s, &zvni->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
stream_reset(s);
- zclient_create_header(s, ZEBRA_VNI_DEL, VRF_DEFAULT);
+ zclient_create_header(s, ZEBRA_VNI_DEL, zebra_vrf_get_evpn_id());
stream_putl(s, vni);
/* Write packet size. */
}
tmp_rmac = hash_release(zl3vni->rmac_table, zrmac);
- if (tmp_rmac)
- XFREE(MTYPE_MAC, tmp_rmac);
+ XFREE(MTYPE_MAC, tmp_rmac);
return 0;
}
}
tmp_n = hash_release(zl3vni->nh_table, n);
- if (tmp_n)
- XFREE(MTYPE_NEIGH, tmp_n);
+ XFREE(MTYPE_NEIGH, tmp_n);
return 0;
}
/* Free the VNI hash entry and allocated memory. */
tmp_zl3vni = hash_release(zrouter.l3vni_table, zl3vni);
- if (tmp_zl3vni)
- XFREE(MTYPE_ZL3VNI, tmp_zl3vni);
+ XFREE(MTYPE_ZL3VNI, tmp_zl3vni);
return 0;
}
if (!is_evpn_enabled())
return;
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_get_evpn();
if (!zvrf)
return;
if (!zvni) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Add/Update %sMAC %s intf %s(%u) VID %u, could not find VNI",
+ "\tAdd/Update %sMAC %s intf %s(%u) VID %u, could not find VNI",
sticky ? "sticky " : "",
prefix_mac2str(macaddr, buf, sizeof(buf)),
ifp->name, ifp->ifindex, vid);
}
if (!zvni->vxlan_if) {
- zlog_debug(
- "VNI %u hash %p doesn't have intf upon local MAC ADD",
- zvni->vni, zvni);
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "\tVNI %u hash %p doesn't have intf upon local MAC ADD",
+ zvni->vni, zvni);
return -1;
}
zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
- if (!zvrf)
+ if (!zvrf) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("\tNo Vrf found for vrf_id: %d",
+ zvni->vxlan_if->vrf_id);
return -1;
+ }
/* Check if we need to create or update or it is a NO-OP. */
mac = zvni_mac_lookup(zvni, macaddr);
&& mac->fwd_info.local.vid == vid) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, "
+ "\tAdd/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, "
"entry exists and has not changed ",
sticky ? "sticky " : "",
prefix_mac2str(macaddr, buf,
return;
}
- if (zvrf_id(zvrf) != VRF_DEFAULT) {
- zlog_debug("Recv MACIP DEL for non-default VRF %u",
- zvrf_id(zvrf));
+ if (!EVPN_ENABLED(zvrf)) {
+ zlog_debug("Recv MACIP DEL for non-EVPN VRF %u",
+ zvrf_id(zvrf));
return;
}
return;
}
- if (zvrf_id(zvrf) != VRF_DEFAULT) {
- zlog_debug("Recv MACIP ADD for non-default VRF %u",
- zvrf_id(zvrf));
+ if (!EVPN_ENABLED(zvrf)) {
+ zlog_debug("Recv MACIP ADD for non-EVPN VRF %u",
+ zvrf_id(zvrf));
return;
}
int add)
{
zebra_l3vni_t *zl3vni = NULL;
- struct zebra_vrf *zvrf_default = NULL;
+ struct zebra_vrf *zvrf_evpn = NULL;
- zvrf_default = zebra_vrf_lookup_by_id(VRF_DEFAULT);
- if (!zvrf_default)
+ zvrf_evpn = zebra_vrf_get_evpn();
+ if (!zvrf_evpn)
return -1;
if (IS_ZEBRA_DEBUG_VXLAN)
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
/* formulate l2vni list */
- hash_iterate(zvrf_default->vni_table, zvni_add_to_l3vni_list,
+ hash_iterate(zvrf_evpn->vni_table, zvni_add_to_l3vni_list,
zl3vni);
if (is_l3vni_oper_up(zl3vni))
struct stream *s;
enum vxlan_flood_control flood_ctrl;
- if (zvrf_id(zvrf) != VRF_DEFAULT) {
- zlog_err("EVPN flood control for non-default VRF %u",
+ if (!EVPN_ENABLED(zvrf)) {
+ zlog_err("EVPN flood control for non-EVPN VRF %u",
zvrf_id(zvrf));
return;
}
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));
+ if (!EVPN_ENABLED(zvrf)) {
+ zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u",
+ zvrf_id(zvrf));
return;
}
struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
- if (zvrf_id(zvrf) != VRF_DEFAULT) {
- zlog_debug("EVPN GW-MACIP Adv for non-default VRF %u",
- zvrf_id(zvrf));
+ if (!EVPN_ENABLED(zvrf)) {
+ zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u",
+ zvrf_id(zvrf));
return;
}
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",
+ if (!EVPN_ENABLED(zvrf)) {
+ zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u",
zvrf_id(zvrf));
return;
}
int advertise = 0;
enum vxlan_flood_control flood_ctrl;
- if (zvrf_id(zvrf) != VRF_DEFAULT) {
- zlog_debug("EVPN VNI Adv for non-default VRF %u",
- zvrf_id(zvrf));
+ /* Mismatch between EVPN VRF and current VRF (should be prevented by
+ * bgpd's cli) */
+ if (is_evpn_enabled() && !EVPN_ENABLED(zvrf))
return;
- }
s = msg;
STREAM_GETC(s, advertise);
STREAM_GETC(s, flood_ctrl);
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("EVPN VNI Adv %s, currently %s, flood control %u",
+ zlog_debug("EVPN VRF %s(%u) VNI Adv %s, currently %s, flood control %u",
+ zvrf_name(zvrf), zvrf_id(zvrf),
advertise ? "enabled" : "disabled",
is_evpn_enabled() ? "enabled" : "disabled",
flood_ctrl);
return;
zvrf->advertise_all_vni = advertise;
- if (is_evpn_enabled()) {
+ if (EVPN_ENABLED(zvrf)) {
+ zrouter.evpn_vrf = zvrf;
+
/* Note BUM handling */
zvrf->vxlan_flood_ctrl = flood_ctrl;
/* cleanup all l3vnis */
hash_iterate(zrouter.l3vni_table, zl3vni_cleanup_all, NULL);
+
+ /* Mark as "no EVPN VRF" */
+ zrouter.evpn_vrf = NULL;
}
stream_failure:
{
zrouter.l3vni_table = hash_create(l3vni_hash_keymake, l3vni_hash_cmp,
"Zebra VRF L3 VNI table");
+ zrouter.evpn_vrf = NULL;
}
/* free l3vni table */
nbr = THREAD_ARG(t);
/* since this is asynchronous we need sanity checks*/
- nbr = zvni_neigh_lookup(zvni, &nbr->ip);
- if (!nbr)
+ zvrf = vrf_info_lookup(nbr->zvni->vrf_id);
+ if (!zvrf)
return 0;
zvni = zvni_lookup(nbr->zvni->vni);
if (!zvni)
return 0;
- zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
- if (!zvrf)
+ nbr = zvni_neigh_lookup(zvni, &nbr->ip);
+ if (!nbr)
return 0;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("%s: duplicate addr MAC %s IP %s flags 0x%x learn count %u vni %u auto recovery expired",
__PRETTY_FUNCTION__,
- prefix_mac2str(&nbr->emac, buf1, sizeof(buf1)),
- ipaddr2str(&nbr->ip, buf2, sizeof(buf2)),
+ prefix_mac2str(&nbr->emac, buf2, sizeof(buf2)),
+ ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
nbr->flags,
nbr->dad_count, zvni->vni);
nbr->detect_start_time.tv_usec = 0;
nbr->dad_dup_detect_time = 0;
nbr->dad_ip_auto_recovery_timer = NULL;
+ ZEBRA_NEIGH_SET_ACTIVE(nbr);
/* Send to BGP */
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
mac = THREAD_ARG(t);
/* since this is asynchronous we need sanity checks*/
- mac = zvni_mac_lookup(zvni, &mac->macaddr);
- if (!mac)
+ zvrf = vrf_info_lookup(mac->zvni->vrf_id);
+ if (!zvrf)
return 0;
zvni = zvni_lookup(mac->zvni->vni);
if (!zvni)
return 0;
- zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
- if (!zvrf)
+ mac = zvni_mac_lookup(zvni, &mac->macaddr);
+ if (!mac)
return 0;
if (IS_ZEBRA_DEBUG_VXLAN)
#define _ZEBRA_VXLAN_H
#include <zebra.h>
+#include <zebra/zebra_router.h>
#include "linklist.h"
#include "if.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zserv.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Is EVPN enabled? */
#define EVPN_ENABLED(zvrf) (zvrf)->advertise_all_vni
static inline int is_evpn_enabled(void)
{
struct zebra_vrf *zvrf = NULL;
- zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
- return zvrf ? zvrf->advertise_all_vni : 0;
+ zvrf = zebra_vrf_get_evpn();
+ return zvrf ? EVPN_ENABLED(zvrf) : 0;
}
static inline int
is_vxlan_flooding_head_end(void)
{
- struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
+ struct zebra_vrf *zvrf = zebra_vrf_get_evpn();
if (!zvrf)
return 0;
struct zebra_vrf *zvrf,
vni_t vni);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_VXLAN_H */
#include <zebra.h>
-#include <zebra.h>
-
#include "if.h"
#include "linklist.h"
#include "zebra_vxlan.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define ERR_STR_SZ 256
/* definitions */
struct json_object *json;
};
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_VXLAN_PRIVATE_H */
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;
#include "zebra/zebra_vrf.h" /* for zebra_vrf */
/* clang-format on */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Default port information. */
#define ZEBRA_VTY_PORT 2601
*/
extern void zserv_init(void);
+/*
+ * Stop the Zebra API server.
+ *
+ * closes the socket
+ */
+extern void zserv_close(void);
+
/*
* Start Zebra API server.
*
/* TODO */
int zebra_finalize(struct thread *event);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_ZEBRA_H */