mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-16 02:30:52 +00:00
Merge branch 'master' into evpn-session-vrf
This commit is contained in:
commit
d074383c62
@ -5,3 +5,4 @@
|
|||||||
**/*.lo
|
**/*.lo
|
||||||
**/*.so
|
**/*.so
|
||||||
**/.libs
|
**/.libs
|
||||||
|
docker/alpine/pkgs
|
||||||
|
@ -175,13 +175,9 @@ EXTRA_DIST += \
|
|||||||
python/clidef.py \
|
python/clidef.py \
|
||||||
python/clippy/__init__.py \
|
python/clippy/__init__.py \
|
||||||
\
|
\
|
||||||
redhat/frr.init \
|
|
||||||
redhat/frr.service \
|
|
||||||
redhat/daemons \
|
|
||||||
redhat/frr.logrotate \
|
redhat/frr.logrotate \
|
||||||
redhat/frr.pam \
|
redhat/frr.pam \
|
||||||
redhat/frr.spec \
|
redhat/frr.spec \
|
||||||
redhat/README.rpm_build.md \
|
|
||||||
\
|
\
|
||||||
snapcraft/snapcraft.yaml \
|
snapcraft/snapcraft.yaml \
|
||||||
snapcraft/README.snap_build.md \
|
snapcraft/README.snap_build.md \
|
||||||
|
@ -9,13 +9,13 @@ license="GPL-2.0"
|
|||||||
depends="json-c c-ares ipsec-tools iproute2 python py-ipaddr bash"
|
depends="json-c c-ares ipsec-tools iproute2 python py-ipaddr bash"
|
||||||
makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
|
makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
|
||||||
acct autoconf automake bash
|
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
|
c-ares c-ares-dev ca-certificates cryptsetup-libs curl
|
||||||
device-mapper-libs expat fakeroot flex fortify-headers gdbm
|
device-mapper-libs expat fakeroot flex fortify-headers gdbm
|
||||||
git gmp isl json-c-dev kmod lddtree libacl libatomic libattr
|
git gmp isl json-c-dev kmod lddtree libacl libatomic libattr
|
||||||
libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc
|
libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc
|
||||||
libgomp libisoburn libisofs libltdl libressl libssh2
|
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
|
mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base
|
||||||
patch pax-utils pcre perl pkgconf python2 python2-dev readline
|
patch pax-utils pcre perl pkgconf python2 python2-dev readline
|
||||||
readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs
|
readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs
|
||||||
@ -23,7 +23,7 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
|
|||||||
checkdepends="pytest py-setuptools"
|
checkdepends="pytest py-setuptools"
|
||||||
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
|
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
|
||||||
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
|
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
|
||||||
source="$pkgname-$pkgver.tar.gz docker-start daemons"
|
source="$pkgname-$pkgver.tar.gz"
|
||||||
|
|
||||||
builddir="$srcdir"/$pkgname-$pkgver
|
builddir="$srcdir"/$pkgname-$pkgver
|
||||||
|
|
||||||
@ -60,8 +60,7 @@ package() {
|
|||||||
cd "$builddir"
|
cd "$builddir"
|
||||||
make DESTDIR="$pkgdir" install
|
make DESTDIR="$pkgdir" install
|
||||||
|
|
||||||
install -Dm755 "$srcdir"/docker-start "$pkgdir"$_sbindir
|
install -Dm644 "$builddir"/tools/etc/frr/daemons "$pkgdir"$_sysconfdir
|
||||||
install -Dm644 "$srcdir"/daemons "$pkgdir"$_sysconfdir
|
|
||||||
install -d "$pkgdir"/etc/init.d
|
install -d "$pkgdir"/etc/init.d
|
||||||
ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr
|
ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr
|
||||||
}
|
}
|
||||||
|
544
bfdd/bfd.c
544
bfdd/bfd.c
@ -36,7 +36,9 @@ DEFINE_QOBJ_TYPE(bfd_session);
|
|||||||
/*
|
/*
|
||||||
* Prototypes
|
* 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 uint32_t ptm_bfd_gen_ID(void);
|
||||||
static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd);
|
static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd);
|
||||||
@ -52,66 +54,47 @@ static void bs_down_handler(struct bfd_session *bs, int nstate);
|
|||||||
static void bs_init_handler(struct bfd_session *bs, int nstate);
|
static void bs_init_handler(struct bfd_session *bs, int nstate);
|
||||||
static void bs_up_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
|
* 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;
|
memset(key, 0, sizeof(*key));
|
||||||
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;
|
|
||||||
|
|
||||||
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(bs->vrfname, bpc->bpc_vrfname))
|
key->mhop = mhop;
|
||||||
continue;
|
if (ifname && ifname[0])
|
||||||
if (memcmp(&bs->mhop.peer, &bpc->bpc_peer,
|
strlcpy(key->ifname, ifname, sizeof(key->ifname));
|
||||||
sizeof(bs->mhop.peer)))
|
if (vrfname && vrfname[0])
|
||||||
continue;
|
strlcpy(key->vrfname, vrfname, sizeof(key->vrfname));
|
||||||
if (memcmp(&bs->mhop.local, &bpc->bpc_local,
|
|
||||||
sizeof(bs->mhop.local)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (bso == NULL)
|
|
||||||
bs = NULL;
|
|
||||||
|
|
||||||
return bs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
|
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
|
||||||
{
|
{
|
||||||
struct bfd_session *bs;
|
struct bfd_session *bs;
|
||||||
struct peer_label *pl;
|
struct peer_label *pl;
|
||||||
struct interface *ifp;
|
struct bfd_key key;
|
||||||
struct vrf *vrf;
|
|
||||||
struct bfd_mhop_key mhop;
|
|
||||||
struct bfd_shop_key shop;
|
|
||||||
|
|
||||||
/* Try to find label first. */
|
/* Try to find label first. */
|
||||||
if (bpc->bpc_has_label) {
|
if (bpc->bpc_has_label) {
|
||||||
@ -123,38 +106,10 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise fallback to peer/local hash lookup. */
|
/* Otherwise fallback to peer/local hash lookup. */
|
||||||
if (bpc->bpc_mhop) {
|
gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop,
|
||||||
memset(&mhop, 0, sizeof(mhop));
|
bpc->bpc_localif, bpc->bpc_vrfname);
|
||||||
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;
|
return bfd_key_lookup(key);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -165,7 +120,6 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
|
|||||||
*/
|
*/
|
||||||
int bfd_session_enable(struct bfd_session *bs)
|
int bfd_session_enable(struct bfd_session *bs)
|
||||||
{
|
{
|
||||||
struct sockaddr_in6 *sin6;
|
|
||||||
struct interface *ifp = NULL;
|
struct interface *ifp = NULL;
|
||||||
struct vrf *vrf = NULL;
|
struct vrf *vrf = NULL;
|
||||||
int psock;
|
int psock;
|
||||||
@ -174,8 +128,8 @@ int bfd_session_enable(struct bfd_session *bs)
|
|||||||
* If the interface or VRF doesn't exist, then we must register
|
* If the interface or VRF doesn't exist, then we must register
|
||||||
* the session but delay its start.
|
* the session but delay its start.
|
||||||
*/
|
*/
|
||||||
if (bs->ifname[0] != 0) {
|
if (bs->key.ifname[0]) {
|
||||||
ifp = if_lookup_by_name_all_vrf(bs->ifname);
|
ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
|
||||||
if (ifp == NULL) {
|
if (ifp == NULL) {
|
||||||
log_error(
|
log_error(
|
||||||
"session-enable: specified interface doesn't exists.");
|
"session-enable: specified interface doesn't exists.");
|
||||||
@ -184,15 +138,17 @@ int bfd_session_enable(struct bfd_session *bs)
|
|||||||
|
|
||||||
vrf = vrf_lookup_by_id(ifp->vrf_id);
|
vrf = vrf_lookup_by_id(ifp->vrf_id);
|
||||||
if (vrf == NULL) {
|
if (vrf == NULL) {
|
||||||
log_error("session-enable: specified VRF doesn't exists.");
|
log_error(
|
||||||
|
"session-enable: specified VRF doesn't exists.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->vrfname[0] != 0) {
|
if (bs->key.vrfname[0]) {
|
||||||
vrf = vrf_lookup_by_name(bs->vrfname);
|
vrf = vrf_lookup_by_name(bs->key.vrfname);
|
||||||
if (vrf == NULL) {
|
if (vrf == NULL) {
|
||||||
log_error("session-enable: specified VRF doesn't exists.");
|
log_error(
|
||||||
|
"session-enable: specified VRF doesn't exists.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,26 +158,15 @@ int bfd_session_enable(struct bfd_session *bs)
|
|||||||
if (bs->vrf == NULL)
|
if (bs->vrf == NULL)
|
||||||
bs->vrf = vrf_lookup_by_id(VRF_DEFAULT);
|
bs->vrf = vrf_lookup_by_id(VRF_DEFAULT);
|
||||||
|
|
||||||
if (bs->ifname[0] != 0 &&
|
if (bs->key.ifname[0]
|
||||||
BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
|
&& BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
|
||||||
bs->ifp = ifp;
|
bs->ifp = ifp;
|
||||||
|
|
||||||
/* Set the IPv6 scope id for link-local addresses. */
|
/* Sanity check: don't leak open sockets. */
|
||||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
|
if (bs->sock != -1) {
|
||||||
sin6 = &bs->mhop.peer.sa_sin6;
|
zlog_debug("session-enable: previous socket open");
|
||||||
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
|
close(bs->sock);
|
||||||
sin6->sin6_scope_id = bs->ifp != NULL
|
bs->sock = -1;
|
||||||
? 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -232,11 +177,11 @@ int bfd_session_enable(struct bfd_session *bs)
|
|||||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) {
|
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) {
|
||||||
psock = bp_peer_socket(bs);
|
psock = bp_peer_socket(bs);
|
||||||
if (psock == -1)
|
if (psock == -1)
|
||||||
return -1;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
psock = bp_peer_socketv6(bs);
|
psock = bp_peer_socketv6(bs);
|
||||||
if (psock == -1)
|
if (psock == -1)
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -247,25 +192,6 @@ int bfd_session_enable(struct bfd_session *bs)
|
|||||||
bfd_recvtimer_update(bs);
|
bfd_recvtimer_update(bs);
|
||||||
ptm_bfd_start_xmt_timer(bs, false);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,13 +214,6 @@ void bfd_session_disable(struct bfd_session *bs)
|
|||||||
bfd_echo_recvtimer_delete(bs);
|
bfd_echo_recvtimer_delete(bs);
|
||||||
bfd_xmttimer_delete(bs);
|
bfd_xmttimer_delete(bs);
|
||||||
bfd_echo_xmttimer_delete(bs);
|
bfd_echo_xmttimer_delete(bs);
|
||||||
|
|
||||||
/* Unregister session from hashes to avoid unwanted activation. */
|
|
||||||
bfd_id_delete(bs->discrs.my_discr);
|
|
||||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
|
|
||||||
bfd_mhop_delete(bs->mhop);
|
|
||||||
else
|
|
||||||
bfd_shop_delete(bs->shop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t ptm_bfd_gen_ID(void)
|
static uint32_t ptm_bfd_gen_ID(void)
|
||||||
@ -438,21 +357,20 @@ static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
|
|||||||
if (bs == NULL)
|
if (bs == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Remove unused fields. */
|
switch (bs->key.family) {
|
||||||
switch (sa->sa_sin.sin_family) {
|
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
sa->sa_sin.sin_port = 0;
|
if (memcmp(&sa->sa_sin.sin_addr, &bs->key.peer,
|
||||||
if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin)) == 0)
|
sizeof(sa->sa_sin.sin_addr)))
|
||||||
return bs;
|
return NULL;
|
||||||
break;
|
break;
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
sa->sa_sin6.sin6_port = 0;
|
if (memcmp(&sa->sa_sin6.sin6_addr, &bs->key.peer,
|
||||||
if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin6)) == 0)
|
sizeof(sa->sa_sin6.sin6_addr)))
|
||||||
return bs;
|
return NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
|
struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
|
||||||
@ -461,32 +379,30 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
|
|||||||
ifindex_t ifindex, vrf_id_t vrfid,
|
ifindex_t ifindex, vrf_id_t vrfid,
|
||||||
bool is_mhop)
|
bool is_mhop)
|
||||||
{
|
{
|
||||||
struct bfd_session *l_bfd = NULL;
|
struct interface *ifp;
|
||||||
struct bfd_mhop_key mhop;
|
struct vrf *vrf;
|
||||||
struct bfd_shop_key shop;
|
struct bfd_key key;
|
||||||
|
|
||||||
/* Find our session using the ID signaled by the remote end. */
|
/* Find our session using the ID signaled by the remote end. */
|
||||||
if (cp->discrs.remote_discr)
|
if (cp->discrs.remote_discr)
|
||||||
return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr));
|
return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr));
|
||||||
|
|
||||||
/* Search for session without using discriminator. */
|
/* Search for session without using discriminator. */
|
||||||
if (is_mhop) {
|
ifp = if_lookup_by_index(ifindex, vrfid);
|
||||||
memset(&mhop, 0, sizeof(mhop));
|
if (vrfid == VRF_DEFAULT) {
|
||||||
mhop.peer = *peer;
|
/*
|
||||||
mhop.local = *local;
|
* Don't use the default vrf, otherwise we won't find
|
||||||
mhop.vrfid = vrfid;
|
* sessions that doesn't specify it.
|
||||||
|
*/
|
||||||
|
vrf = NULL;
|
||||||
|
} else
|
||||||
|
vrf = vrf_lookup_by_id(vrfid);
|
||||||
|
|
||||||
l_bfd = bfd_mhop_lookup(mhop);
|
gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL,
|
||||||
} else {
|
vrf ? vrf->name : NULL);
|
||||||
memset(&shop, 0, sizeof(shop));
|
|
||||||
shop.peer = *peer;
|
|
||||||
shop.ifindex = ifindex;
|
|
||||||
|
|
||||||
l_bfd = bfd_shop_lookup(shop);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX maybe remoteDiscr should be checked for remoteHeard cases. */
|
/* XXX maybe remoteDiscr should be checked for remoteHeard cases. */
|
||||||
return l_bfd;
|
return bfd_key_lookup(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bfd_xmt_cb(struct thread *t)
|
int bfd_xmt_cb(struct thread *t)
|
||||||
@ -701,6 +617,9 @@ static void bfd_session_free(struct bfd_session *bs)
|
|||||||
|
|
||||||
bfd_session_disable(bs);
|
bfd_session_disable(bs);
|
||||||
|
|
||||||
|
bfd_key_delete(bs->key);
|
||||||
|
bfd_id_delete(bs->discrs.my_discr);
|
||||||
|
|
||||||
/* Remove observer if any. */
|
/* Remove observer if any. */
|
||||||
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
|
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
|
||||||
if (bso->bso_bs != bs)
|
if (bso->bso_bs != bs)
|
||||||
@ -743,29 +662,47 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
|
|||||||
* start. See `bfd_session_enable` for more information.
|
* start. See `bfd_session_enable` for more information.
|
||||||
*/
|
*/
|
||||||
if (bpc->bpc_has_localif)
|
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)
|
if (bpc->bpc_has_vrfname)
|
||||||
strlcpy(bfd->vrfname, bpc->bpc_vrfname, sizeof(bfd->vrfname));
|
strlcpy(bfd->key.vrfname, bpc->bpc_vrfname,
|
||||||
|
sizeof(bfd->key.vrfname));
|
||||||
/* Add observer if we have moving parts. */
|
|
||||||
if (bfd->ifname[0] || bfd->vrfname[0])
|
|
||||||
bs_observer_add(bfd);
|
|
||||||
|
|
||||||
/* Copy remaining data. */
|
/* Copy remaining data. */
|
||||||
if (bpc->bpc_ipv4 == false)
|
if (bpc->bpc_ipv4 == false)
|
||||||
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
|
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
|
||||||
|
|
||||||
if (bpc->bpc_mhop) {
|
bfd->key.family = (bpc->bpc_ipv4) ? AF_INET : AF_INET6;
|
||||||
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH);
|
switch (bfd->key.family) {
|
||||||
bfd->mhop.peer = bpc->bpc_peer;
|
case AF_INET:
|
||||||
bfd->mhop.local = bpc->bpc_local;
|
memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin.sin_addr,
|
||||||
} else {
|
sizeof(bpc->bpc_peer.sa_sin.sin_addr));
|
||||||
bfd->shop.peer = bpc->bpc_peer;
|
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;
|
if (bpc->bpc_mhop)
|
||||||
bfd->local_address = bpc->bpc_local;
|
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. */
|
/* Try to enable session and schedule for packet receive/send. */
|
||||||
if (bfd_session_enable(bfd) == -1) {
|
if (bfd_session_enable(bfd) == -1) {
|
||||||
@ -774,6 +711,10 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
|
|||||||
return NULL;
|
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. */
|
/* Apply other configurations. */
|
||||||
_bfd_session_update(bfd, bpc);
|
_bfd_session_update(bfd, bpc);
|
||||||
|
|
||||||
@ -1219,35 +1160,26 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen)
|
|||||||
snprintf(buf, buflen, "%u second(s)", second);
|
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];
|
static char buf[256];
|
||||||
|
char addr_buf[INET6_ADDRSTRLEN];
|
||||||
int pos;
|
int pos;
|
||||||
bool is_mhop = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
|
bool is_mhop = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
|
||||||
|
|
||||||
pos = snprintf(buf, sizeof(buf), "mhop:%s", is_mhop ? "yes" : "no");
|
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",
|
pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s",
|
||||||
satostr(&bs->shop.peer));
|
inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
|
||||||
|
sizeof(addr_buf)));
|
||||||
if (bs->local_address.sa_sin.sin_family)
|
pos += snprintf(buf + pos, sizeof(buf) - pos, " local:%s",
|
||||||
pos += snprintf(buf + pos, sizeof(buf) - pos,
|
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
|
||||||
" local:%s",
|
sizeof(addr_buf)));
|
||||||
satostr(&bs->local_address));
|
if (bs->key.vrfname[0])
|
||||||
|
pos += snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s",
|
||||||
if (bs->shop.ifindex)
|
bs->key.vrfname);
|
||||||
snprintf(buf + pos, sizeof(buf) - pos, " ifindex:%u",
|
if (bs->key.ifname[0])
|
||||||
bs->shop.ifindex);
|
pos += snprintf(buf + pos, sizeof(buf) - pos, " ifname:%s",
|
||||||
}
|
bs->key.ifname);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1255,16 +1187,25 @@ int bs_observer_add(struct bfd_session *bs)
|
|||||||
{
|
{
|
||||||
struct bfd_session_observer *bso;
|
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_bs = bs;
|
||||||
bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
|
bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
|
||||||
if (bso->bso_isinterface)
|
if (bso->bso_isinterface)
|
||||||
strlcpy(bso->bso_entryname, bs->ifname,
|
strlcpy(bso->bso_entryname, bs->key.ifname,
|
||||||
sizeof(bso->bso_entryname));
|
sizeof(bso->bso_entryname));
|
||||||
else
|
else
|
||||||
strlcpy(bso->bso_entryname, bs->vrfname,
|
strlcpy(bso->bso_entryname, bs->key.vrfname,
|
||||||
sizeof(bso->bso_entryname));
|
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);
|
TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1276,21 +1217,59 @@ void bs_observer_del(struct bfd_session_observer *bso)
|
|||||||
XFREE(MTYPE_BFDD_SESSION_OBSERVER, bso);
|
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.
|
* BFD hash data structures to find sessions.
|
||||||
*/
|
*/
|
||||||
static struct hash *bfd_id_hash;
|
static struct hash *bfd_id_hash;
|
||||||
static struct hash *bfd_shop_hash;
|
static struct hash *bfd_key_hash;
|
||||||
static struct hash *bfd_mhop_hash;
|
|
||||||
|
|
||||||
static unsigned int bfd_id_hash_do(void *p);
|
static unsigned int bfd_id_hash_do(void *p);
|
||||||
static unsigned int bfd_shop_hash_do(void *p);
|
static unsigned int bfd_key_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 void _bfd_free(struct hash_bucket *hb,
|
static void _bfd_free(struct hash_bucket *hb,
|
||||||
void *arg __attribute__((__unused__)));
|
void *arg __attribute__((__unused__)));
|
||||||
@ -1311,73 +1290,20 @@ static bool bfd_id_hash_cmp(const void *n1, const void *n2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* BFD hash for single hop. */
|
/* BFD hash for single hop. */
|
||||||
static unsigned int bfd_shop_hash_do(void *p)
|
static unsigned int bfd_key_hash_do(void *p)
|
||||||
{
|
{
|
||||||
struct bfd_session *bs = p;
|
struct bfd_session *bs = p;
|
||||||
|
|
||||||
return jhash(&bs->shop, sizeof(bs->shop), 0);
|
return jhash(&bs->key, sizeof(bs->key), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bfd_shop_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;
|
const struct bfd_session *bs1 = n1, *bs2 = n2;
|
||||||
|
|
||||||
return memcmp(&bs1->shop, &bs2->shop, sizeof(bs1->shop)) == 0;
|
return memcmp(&bs1->key, &bs2->key, sizeof(bs1->key)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BFD hash for multi hop. */
|
|
||||||
static unsigned int bfd_mhop_hash_do(void *p)
|
|
||||||
{
|
|
||||||
struct bfd_session *bs = p;
|
|
||||||
|
|
||||||
return jhash(&bs->mhop, sizeof(bs->mhop), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool bfd_mhop_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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.
|
* Hash public interface / exported functions.
|
||||||
@ -1393,34 +1319,35 @@ struct bfd_session *bfd_id_lookup(uint32_t id)
|
|||||||
return hash_lookup(bfd_id_hash, &bs);
|
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;
|
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);
|
/* Handle cases where local-address is optional. */
|
||||||
if (bsp == NULL && bs.shop.ifindex != 0) {
|
if (bsp == NULL && bs.key.family == AF_INET) {
|
||||||
/*
|
memset(&bs.key.local, 0, sizeof(bs.key.local));
|
||||||
* Since the local interface spec is optional, try
|
bsp = hash_lookup(bfd_key_hash, &bs);
|
||||||
* searching the key without it as well.
|
}
|
||||||
*/
|
|
||||||
_shop_key2(&bs, &shop);
|
/* Handle cases where ifname is optional. */
|
||||||
bsp = hash_lookup(bfd_shop_hash, &bs);
|
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);
|
||||||
|
|
||||||
|
/* 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 bsp;
|
return bsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop)
|
|
||||||
{
|
|
||||||
struct bfd_session bs;
|
|
||||||
|
|
||||||
_mhop_key(&bs, &mhop);
|
|
||||||
|
|
||||||
return hash_lookup(bfd_mhop_hash, &bs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delete functions.
|
* Delete functions.
|
||||||
*
|
*
|
||||||
@ -1440,31 +1367,18 @@ struct bfd_session *bfd_id_delete(uint32_t id)
|
|||||||
return hash_release(bfd_id_hash, &bs);
|
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;
|
struct bfd_session bs, *bsp;
|
||||||
|
|
||||||
_shop_key(&bs, &shop);
|
bs.key = key;
|
||||||
bsp = hash_release(bfd_shop_hash, &bs);
|
bsp = hash_lookup(bfd_key_hash, &bs);
|
||||||
if (bsp == NULL && shop.ifindex != 0) {
|
if (bsp == NULL && key.ifname[0]) {
|
||||||
/*
|
memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
|
||||||
* Since the local interface spec is optional, try
|
bsp = hash_lookup(bfd_key_hash, &bs);
|
||||||
* searching the key without it as well.
|
|
||||||
*/
|
|
||||||
_shop_key2(&bs, &shop);
|
|
||||||
bsp = hash_release(bfd_shop_hash, &bs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return bsp;
|
return hash_release(bfd_key_hash, 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iteration functions. */
|
/* Iteration functions. */
|
||||||
@ -1473,14 +1387,9 @@ void bfd_id_iterate(hash_iter_func hif, void *arg)
|
|||||||
hash_iterate(bfd_id_hash, hif, arg);
|
hash_iterate(bfd_id_hash, hif, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bfd_shop_iterate(hash_iter_func hif, void *arg)
|
void bfd_key_iterate(hash_iter_func hif, void *arg)
|
||||||
{
|
{
|
||||||
hash_iterate(bfd_shop_hash, hif, arg);
|
hash_iterate(bfd_key_hash, hif, arg);
|
||||||
}
|
|
||||||
|
|
||||||
void bfd_mhop_iterate(hash_iter_func hif, void *arg)
|
|
||||||
{
|
|
||||||
hash_iterate(bfd_mhop_hash, hif, arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1494,24 +1403,17 @@ bool bfd_id_insert(struct bfd_session *bs)
|
|||||||
return (hash_get(bfd_id_hash, bs, hash_alloc_intern) == bs);
|
return (hash_get(bfd_id_hash, bs, hash_alloc_intern) == bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bfd_shop_insert(struct bfd_session *bs)
|
bool bfd_key_insert(struct bfd_session *bs)
|
||||||
{
|
{
|
||||||
return (hash_get(bfd_shop_hash, bs, hash_alloc_intern) == bs);
|
return (hash_get(bfd_key_hash, bs, hash_alloc_intern) == bs);
|
||||||
}
|
|
||||||
|
|
||||||
bool bfd_mhop_insert(struct bfd_session *bs)
|
|
||||||
{
|
|
||||||
return (hash_get(bfd_mhop_hash, bs, hash_alloc_intern) == bs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bfd_initialize(void)
|
void bfd_initialize(void)
|
||||||
{
|
{
|
||||||
bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp,
|
bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp,
|
||||||
"BFD discriminator hash");
|
"BFD session discriminator hash");
|
||||||
bfd_shop_hash = hash_create(bfd_shop_hash_do, bfd_shop_hash_cmp,
|
bfd_key_hash = hash_create(bfd_key_hash_do, bfd_key_hash_cmp,
|
||||||
"BFD single hop hash");
|
"BFD session hash");
|
||||||
bfd_mhop_hash = hash_create(bfd_mhop_hash_do, bfd_mhop_hash_cmp,
|
|
||||||
"BFD multihop hop hash");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _bfd_free(struct hash_bucket *hb,
|
static void _bfd_free(struct hash_bucket *hb,
|
||||||
@ -1532,11 +1434,9 @@ void bfd_shutdown(void)
|
|||||||
* assert() here to make sure it really happened.
|
* assert() here to make sure it really happened.
|
||||||
*/
|
*/
|
||||||
bfd_id_iterate(_bfd_free, NULL);
|
bfd_id_iterate(_bfd_free, NULL);
|
||||||
assert(bfd_shop_hash->count == 0);
|
assert(bfd_key_hash->count == 0);
|
||||||
assert(bfd_mhop_hash->count == 0);
|
|
||||||
|
|
||||||
/* Now free the hashes themselves. */
|
/* Now free the hashes themselves. */
|
||||||
hash_free(bfd_id_hash);
|
hash_free(bfd_id_hash);
|
||||||
hash_free(bfd_shop_hash);
|
hash_free(bfd_key_hash);
|
||||||
hash_free(bfd_mhop_hash);
|
|
||||||
}
|
}
|
||||||
|
57
bfdd/bfd.h
57
bfdd/bfd.h
@ -173,15 +173,13 @@ enum bfd_session_flags {
|
|||||||
#define BFD_CHECK_FLAG(field, flag) (field & flag)
|
#define BFD_CHECK_FLAG(field, flag) (field & flag)
|
||||||
|
|
||||||
/* BFD session hash keys */
|
/* BFD session hash keys */
|
||||||
struct bfd_shop_key {
|
struct bfd_key {
|
||||||
struct sockaddr_any peer;
|
uint16_t family;
|
||||||
ifindex_t ifindex;
|
uint8_t mhop;
|
||||||
};
|
struct in6_addr peer;
|
||||||
|
struct in6_addr local;
|
||||||
struct bfd_mhop_key {
|
char ifname[MAXNAMELEN];
|
||||||
struct sockaddr_any peer;
|
char vrfname[MAXNAMELEN];
|
||||||
struct sockaddr_any local;
|
|
||||||
vrf_id_t vrfid;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bfd_session_stats {
|
struct bfd_session_stats {
|
||||||
@ -227,19 +225,14 @@ struct bfd_session {
|
|||||||
uint8_t polling;
|
uint8_t polling;
|
||||||
|
|
||||||
/* This and the localDiscr are the keys to state info */
|
/* This and the localDiscr are the keys to state info */
|
||||||
|
struct bfd_key key;
|
||||||
struct peer_label *pl;
|
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_address;
|
||||||
struct sockaddr_any local_ip;
|
|
||||||
struct interface *ifp;
|
struct interface *ifp;
|
||||||
struct vrf *vrf;
|
struct vrf *vrf;
|
||||||
char ifname[MAXNAMELEN];
|
|
||||||
char vrfname[MAXNAMELEN];
|
int sock;
|
||||||
|
|
||||||
/* BFD session flags */
|
/* BFD session flags */
|
||||||
enum bfd_session_flags flags;
|
enum bfd_session_flags flags;
|
||||||
@ -281,7 +274,11 @@ struct bfd_state_str_list {
|
|||||||
struct bfd_session_observer {
|
struct bfd_session_observer {
|
||||||
struct bfd_session *bso_bs;
|
struct bfd_session *bso_bs;
|
||||||
bool bso_isinterface;
|
bool bso_isinterface;
|
||||||
|
bool bso_isaddress;
|
||||||
|
union {
|
||||||
char bso_entryname[MAXNAMELEN];
|
char bso_entryname[MAXNAMELEN];
|
||||||
|
struct prefix bso_addr;
|
||||||
|
};
|
||||||
|
|
||||||
TAILQ_ENTRY(bfd_session_observer) bso_entry;
|
TAILQ_ENTRY(bfd_session_observer) bso_entry;
|
||||||
};
|
};
|
||||||
@ -531,38 +528,28 @@ const char *satostr(struct sockaddr_any *sa);
|
|||||||
const char *diag2str(uint8_t diag);
|
const char *diag2str(uint8_t diag);
|
||||||
int strtosa(const char *addr, struct sockaddr_any *sa);
|
int strtosa(const char *addr, struct sockaddr_any *sa);
|
||||||
void integer2timestr(uint64_t time, char *buf, size_t buflen);
|
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);
|
int bs_observer_add(struct bfd_session *bs);
|
||||||
void bs_observer_del(struct bfd_session_observer *bso);
|
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 */
|
/* BFD hash data structures interface */
|
||||||
void bfd_initialize(void);
|
void bfd_initialize(void);
|
||||||
void bfd_shutdown(void);
|
void bfd_shutdown(void);
|
||||||
struct bfd_session *bfd_id_lookup(uint32_t id);
|
struct bfd_session *bfd_id_lookup(uint32_t id);
|
||||||
struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop);
|
struct bfd_session *bfd_key_lookup(struct bfd_key key);
|
||||||
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_id_delete(uint32_t id);
|
struct bfd_session *bfd_id_delete(uint32_t id);
|
||||||
struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop);
|
struct bfd_session *bfd_key_delete(struct bfd_key key);
|
||||||
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);
|
|
||||||
|
|
||||||
bool bfd_id_insert(struct bfd_session *bs);
|
bool bfd_id_insert(struct bfd_session *bs);
|
||||||
bool bfd_shop_insert(struct bfd_session *bs);
|
bool bfd_key_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);
|
|
||||||
|
|
||||||
typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg);
|
typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg);
|
||||||
void bfd_id_iterate(hash_iter_func hif, void *arg);
|
void bfd_id_iterate(hash_iter_func hif, void *arg);
|
||||||
void bfd_shop_iterate(hash_iter_func hif, void *arg);
|
void bfd_key_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);
|
|
||||||
|
|
||||||
/* Export callback functions for `event.c`. */
|
/* Export callback functions for `event.c`. */
|
||||||
extern struct thread_master *master;
|
extern struct thread_master *master;
|
||||||
@ -572,6 +559,8 @@ int bfd_echo_recvtimer_cb(struct thread *t);
|
|||||||
int bfd_xmt_cb(struct thread *t);
|
int bfd_xmt_cb(struct thread *t);
|
||||||
int bfd_echo_xmt_cb(struct thread *t);
|
int bfd_echo_xmt_cb(struct thread *t);
|
||||||
|
|
||||||
|
extern struct in6_addr zero_addr;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bfdd_vty.c
|
* bfdd_vty.c
|
||||||
|
@ -79,7 +79,10 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
|
|||||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
|
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
|
||||||
memset(&sin6, 0, sizeof(sin6));
|
memset(&sin6, 0, sizeof(sin6));
|
||||||
sin6.sin6_family = AF_INET6;
|
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 =
|
sin6.sin6_port =
|
||||||
(port) ? *port
|
(port) ? *port
|
||||||
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
|
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
|
||||||
@ -92,7 +95,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
|
|||||||
} else {
|
} else {
|
||||||
memset(&sin, 0, sizeof(sin));
|
memset(&sin, 0, sizeof(sin));
|
||||||
sin.sin_family = AF_INET;
|
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 =
|
sin.sin_port =
|
||||||
(port) ? *port
|
(port) ? *port
|
||||||
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
|
: (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
|
||||||
@ -120,7 +123,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
|
|||||||
|
|
||||||
void ptm_bfd_echo_snd(struct bfd_session *bfd)
|
void ptm_bfd_echo_snd(struct bfd_session *bfd)
|
||||||
{
|
{
|
||||||
struct sockaddr_any *sa;
|
struct sockaddr *sa;
|
||||||
socklen_t salen;
|
socklen_t salen;
|
||||||
int sd;
|
int sd;
|
||||||
struct bfd_echo_pkt bep;
|
struct bfd_echo_pkt bep;
|
||||||
@ -135,31 +138,36 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
|
|||||||
bep.len = BFD_ECHO_PKT_LEN;
|
bep.len = BFD_ECHO_PKT_LEN;
|
||||||
bep.my_discr = htonl(bfd->discrs.my_discr);
|
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)) {
|
if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
|
||||||
sd = bglobal.bg_echov6;
|
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);
|
sin6.sin6_port = htons(BFD_DEF_ECHO_PORT);
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||||
sin6.sin6_len = sizeof(sin6);
|
sin6.sin6_len = sizeof(sin6);
|
||||||
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
|
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
|
||||||
|
|
||||||
sa = (struct sockaddr_any *)&sin6;
|
sa = (struct sockaddr *)&sin6;
|
||||||
salen = sizeof(sin6);
|
salen = sizeof(sin6);
|
||||||
} else {
|
} else {
|
||||||
sd = bglobal.bg_echo;
|
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);
|
sin.sin_port = htons(BFD_DEF_ECHO_PORT);
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||||
sin.sin_len = sizeof(sin);
|
sin.sin_len = sizeof(sin);
|
||||||
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
|
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
|
||||||
|
|
||||||
sa = (struct sockaddr_any *)&sin;
|
sa = (struct sockaddr *)&sin;
|
||||||
salen = sizeof(sin);
|
salen = sizeof(sin);
|
||||||
}
|
}
|
||||||
if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep),
|
if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep), sa,
|
||||||
(struct sockaddr *)sa, salen)
|
salen)
|
||||||
== -1)
|
== -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -602,8 +610,8 @@ int bfd_recv_cb(struct thread *t)
|
|||||||
bfd->mh_ttl, BFD_TTL_VAL);
|
bfd->mh_ttl, BFD_TTL_VAL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (bfd->local_ip.sa_sin.sin_family == AF_UNSPEC) {
|
} else if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) {
|
||||||
bfd->local_ip = local;
|
bfd->local_address = local;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -917,25 +925,26 @@ int bp_peer_socket(const struct bfd_session *bs)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->shop.ifindex != IFINDEX_INTERNAL) {
|
if (bs->key.ifname[0]) {
|
||||||
if (bp_bind_dev(sd, bs->ifp->name) != 0) {
|
if (bp_bind_dev(sd, bs->key.ifname) != 0) {
|
||||||
close(sd);
|
close(sd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
|
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
|
||||||
bs->mhop.vrfid != VRF_DEFAULT) {
|
&& bs->key.vrfname[0]) {
|
||||||
if (bp_bind_dev(sd, bs->vrf->name) != 0) {
|
if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
|
||||||
close(sd);
|
close(sd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find an available source port in the proper range */
|
/* 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;
|
sin.sin_family = AF_INET;
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||||
sin.sin_len = sizeof(sin);
|
sin.sin_len = sizeof(sin);
|
||||||
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
|
#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)
|
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
|
||||||
sin.sin_addr.s_addr = INADDR_ANY;
|
sin.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
@ -987,20 +996,23 @@ int bp_peer_socketv6(const struct bfd_session *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Find an available source port in the proper range */
|
/* 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;
|
sin6.sin6_family = AF_INET6;
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||||
sin6.sin6_len = sizeof(sin6);
|
sin6.sin6_len = sizeof(sin6);
|
||||||
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
|
#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 (bs->key.ifname[0]) {
|
||||||
if (bp_bind_dev(sd, bs->ifp->name) != 0) {
|
if (bp_bind_dev(sd, bs->key.ifname) != 0) {
|
||||||
close(sd);
|
close(sd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
|
} else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
|
||||||
bs->mhop.vrfid != VRF_DEFAULT) {
|
&& bs->key.vrfname[0]) {
|
||||||
if (bp_bind_dev(sd, bs->vrf->name) != 0) {
|
if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
|
||||||
close(sd);
|
close(sd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,6 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
|
|||||||
const char *local_str, const char *ifname,
|
const char *local_str, const char *ifname,
|
||||||
const char *vrfname);
|
const char *vrfname);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Commands definition.
|
* Commands definition.
|
||||||
*/
|
*/
|
||||||
@ -369,22 +368,25 @@ DEFPY(bfd_no_peer, bfd_no_peer_cmd,
|
|||||||
*/
|
*/
|
||||||
static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
|
static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
|
||||||
{
|
{
|
||||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
char addr_buf[INET6_ADDRSTRLEN];
|
||||||
vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
|
|
||||||
|
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, " multihop");
|
||||||
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
|
|
||||||
if (bs->vrfname[0])
|
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
|
||||||
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",
|
vty_out(vty, " local-address %s",
|
||||||
satostr(&bs->local_address));
|
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
|
||||||
if (bs->ifname[0])
|
sizeof(addr_buf)));
|
||||||
vty_out(vty, " interface %s", bs->ifname);
|
|
||||||
|
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");
|
vty_out(vty, "\n");
|
||||||
}
|
|
||||||
|
|
||||||
if (bs->pl)
|
if (bs->pl)
|
||||||
vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
|
vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
|
||||||
@ -453,22 +455,25 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs)
|
|||||||
static struct json_object *_peer_json_header(struct bfd_session *bs)
|
static struct json_object *_peer_json_header(struct bfd_session *bs)
|
||||||
{
|
{
|
||||||
struct json_object *jo = json_object_new_object();
|
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_boolean_true_add(jo, "multihop");
|
||||||
json_object_string_add(jo, "peer", satostr(&bs->mhop.peer));
|
else
|
||||||
json_object_string_add(jo, "local", satostr(&bs->mhop.local));
|
|
||||||
if (bs->vrfname[0])
|
|
||||||
json_object_string_add(jo, "vrf", bs->vrfname);
|
|
||||||
} else {
|
|
||||||
json_object_boolean_false_add(jo, "multihop");
|
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, "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",
|
json_object_string_add(jo, "local",
|
||||||
satostr(&bs->local_address));
|
inet_ntop(bs->key.family, &bs->key.local,
|
||||||
if (bs->ifname[0])
|
addr_buf, sizeof(addr_buf)));
|
||||||
json_object_string_add(jo, "interface", bs->ifname);
|
|
||||||
}
|
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)
|
if (bs->pl)
|
||||||
json_object_string_add(jo, "label", bs->pl->pl_label);
|
json_object_string_add(jo, "label", bs->pl->pl_label);
|
||||||
@ -916,25 +921,29 @@ static int bfdd_write_config(struct vty *vty)
|
|||||||
|
|
||||||
static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs)
|
static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs)
|
||||||
{
|
{
|
||||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
char addr_buf[INET6_ADDRSTRLEN];
|
||||||
vty_out(vty, " peer %s", satostr(&bs->mhop.peer));
|
|
||||||
|
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, " multihop");
|
||||||
vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
|
|
||||||
if (bs->vrfname[0])
|
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
|
||||||
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",
|
vty_out(vty, " local-address %s",
|
||||||
satostr(&bs->local_address));
|
inet_ntop(bs->key.family, &bs->key.local, addr_buf,
|
||||||
if (bs->ifname[0])
|
sizeof(addr_buf)));
|
||||||
vty_out(vty, " interface %s", bs->ifname);
|
|
||||||
|
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");
|
vty_out(vty, "\n");
|
||||||
}
|
|
||||||
|
|
||||||
if (bs->sock == -1)
|
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)
|
if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
|
||||||
vty_out(vty, " detect-multiplier %d\n", bs->detect_mult);
|
vty_out(vty, " detect-multiplier %d\n", bs->detect_mult);
|
||||||
@ -980,16 +989,7 @@ static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg)
|
|||||||
|
|
||||||
static int bfdd_peer_write_config(struct vty *vty)
|
static int bfdd_peer_write_config(struct vty *vty)
|
||||||
{
|
{
|
||||||
struct bfd_session_observer *bso;
|
|
||||||
|
|
||||||
bfd_id_iterate(_bfdd_peer_write_config_iter, vty);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -309,24 +309,7 @@ static int parse_peer_label_config(struct json_object *jo,
|
|||||||
log_debug("\tpeer-label: %s", sval);
|
log_debug("\tpeer-label: %s", sval);
|
||||||
|
|
||||||
/* Translate the label into BFD address keys. */
|
/* Translate the label into BFD address keys. */
|
||||||
bpc->bpc_ipv4 = !BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_IPV6);
|
bs_to_bpc(pl->pl_bs, bpc);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -519,6 +502,8 @@ int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr,
|
|||||||
|
|
||||||
static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
|
static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
|
||||||
{
|
{
|
||||||
|
char addr_buf[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
/* Add peer 'key' information. */
|
/* Add peer 'key' information. */
|
||||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6))
|
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6))
|
||||||
json_object_boolean_true_add(jo, "ipv6");
|
json_object_boolean_true_add(jo, "ipv6");
|
||||||
@ -528,21 +513,26 @@ static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
|
|||||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
||||||
json_object_boolean_true_add(jo, "multihop");
|
json_object_boolean_true_add(jo, "multihop");
|
||||||
json_object_string_add(jo, "peer-address",
|
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",
|
json_object_string_add(jo, "local-address",
|
||||||
satostr(&bs->mhop.local));
|
inet_ntop(bs->key.family, &bs->key.local,
|
||||||
if (bs->vrfname[0])
|
addr_buf, sizeof(addr_buf)));
|
||||||
json_object_string_add(jo, "vrf-name", bs->vrfname);
|
if (bs->key.vrfname[0])
|
||||||
|
json_object_string_add(jo, "vrf-name", bs->key.vrfname);
|
||||||
} else {
|
} else {
|
||||||
json_object_boolean_false_add(jo, "multihop");
|
json_object_boolean_false_add(jo, "multihop");
|
||||||
json_object_string_add(jo, "peer-address",
|
json_object_string_add(jo, "peer-address",
|
||||||
satostr(&bs->shop.peer));
|
inet_ntop(bs->key.family, &bs->key.peer,
|
||||||
if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
|
addr_buf, sizeof(addr_buf)));
|
||||||
json_object_string_add(jo, "local-address",
|
if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
|
||||||
satostr(&bs->local_address));
|
json_object_string_add(
|
||||||
if (bs->ifname[0])
|
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",
|
json_object_string_add(jo, "local-interface",
|
||||||
bs->ifname);
|
bs->key.ifname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->pl)
|
if (bs->pl)
|
||||||
|
@ -55,7 +55,7 @@ static struct zclient *zclient;
|
|||||||
/*
|
/*
|
||||||
* Prototypes
|
* 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 void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
|
||||||
static int _ptm_msg_read(struct stream *msg, int command,
|
static int _ptm_msg_read(struct stream *msg, int command,
|
||||||
@ -127,24 +127,24 @@ static void debug_printbpc(const char *func, unsigned int line,
|
|||||||
#define DEBUG_PRINTBPC(bpc)
|
#define DEBUG_PRINTBPC(bpc)
|
||||||
#endif /* BFD_DEBUG */
|
#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:
|
case AF_INET:
|
||||||
stream_putc(msg, sa->sa_sin.sin_family);
|
stream_put(msg, addr, sizeof(struct in_addr));
|
||||||
stream_put_in_addr(msg, &sa->sa_sin.sin_addr);
|
|
||||||
stream_putc(msg, 32);
|
stream_putc(msg, 32);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
stream_putc(msg, sa->sa_sin6.sin6_family);
|
stream_put(msg, addr, sizeof(struct in6_addr));
|
||||||
stream_put(msg, &sa->sa_sin6.sin6_addr,
|
|
||||||
sizeof(sa->sa_sin6.sin6_addr));
|
|
||||||
stream_putc(msg, 128);
|
stream_putc(msg, 128);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -1;
|
assert(0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -153,7 +153,6 @@ static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa)
|
|||||||
int ptm_bfd_notify(struct bfd_session *bs)
|
int ptm_bfd_notify(struct bfd_session *bs)
|
||||||
{
|
{
|
||||||
struct stream *msg;
|
struct stream *msg;
|
||||||
struct sockaddr_any sac;
|
|
||||||
|
|
||||||
bs->stats.znotification++;
|
bs->stats.znotification++;
|
||||||
|
|
||||||
@ -195,10 +194,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
|
|||||||
stream_putl(msg, IFINDEX_INTERNAL);
|
stream_putl(msg, IFINDEX_INTERNAL);
|
||||||
|
|
||||||
/* BFD destination prefix information. */
|
/* BFD destination prefix information. */
|
||||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
|
_ptm_msg_address(msg, bs->key.family, &bs->key.peer);
|
||||||
_ptm_msg_address(msg, &bs->mhop.peer);
|
|
||||||
else
|
|
||||||
_ptm_msg_address(msg, &bs->shop.peer);
|
|
||||||
|
|
||||||
/* BFD status */
|
/* BFD status */
|
||||||
switch (bs->ses_state) {
|
switch (bs->ses_state) {
|
||||||
@ -218,34 +214,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* BFD source prefix information. */
|
/* BFD source prefix information. */
|
||||||
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
|
_ptm_msg_address(msg, bs->key.family, &bs->key.local);
|
||||||
_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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write packet size. */
|
/* Write packet size. */
|
||||||
stream_putw_at(msg, 0, stream_get_endp(msg));
|
stream_putw_at(msg, 0, stream_get_endp(msg));
|
||||||
@ -290,7 +259,6 @@ stream_failure:
|
|||||||
static int _ptm_msg_read(struct stream *msg, int command,
|
static int _ptm_msg_read(struct stream *msg, int command,
|
||||||
struct bfd_peer_cfg *bpc, struct ptm_client **pc)
|
struct bfd_peer_cfg *bpc, struct ptm_client **pc)
|
||||||
{
|
{
|
||||||
struct interface *ifp;
|
|
||||||
uint32_t pid;
|
uint32_t pid;
|
||||||
uint8_t ttl __attribute__((unused));
|
uint8_t ttl __attribute__((unused));
|
||||||
size_t ifnamelen;
|
size_t ifnamelen;
|
||||||
@ -385,31 +353,6 @@ static int _ptm_msg_read(struct stream *msg, int command,
|
|||||||
if (bpc->bpc_has_localif) {
|
if (bpc->bpc_has_localif) {
|
||||||
STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
|
STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
|
||||||
bpc->bpc_localif[ifnamelen] = 0;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,7 +551,7 @@ static void bfdd_sessions_enable_interface(struct interface *ifp)
|
|||||||
|
|
||||||
/* Interface name mismatch. */
|
/* Interface name mismatch. */
|
||||||
bs = bso->bso_bs;
|
bs = bso->bso_bs;
|
||||||
if (strcmp(ifp->name, bs->ifname))
|
if (strcmp(ifp->name, bs->key.ifname))
|
||||||
continue;
|
continue;
|
||||||
/* Skip enabled sessions. */
|
/* Skip enabled sessions. */
|
||||||
if (bs->sock != -1)
|
if (bs->sock != -1)
|
||||||
@ -630,7 +573,7 @@ static void bfdd_sessions_disable_interface(struct interface *ifp)
|
|||||||
|
|
||||||
/* Interface name mismatch. */
|
/* Interface name mismatch. */
|
||||||
bs = bso->bso_bs;
|
bs = bso->bso_bs;
|
||||||
if (strcmp(ifp->name, bs->ifname))
|
if (strcmp(ifp->name, bs->key.ifname))
|
||||||
continue;
|
continue;
|
||||||
/* Skip disabled sessions. */
|
/* Skip disabled sessions. */
|
||||||
if (bs->sock == -1)
|
if (bs->sock == -1)
|
||||||
@ -691,6 +634,48 @@ static int bfdd_interface_vrf_update(int command __attribute__((__unused__)),
|
|||||||
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)
|
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
|
||||||
{
|
{
|
||||||
zclient = zclient_new(master, &zclient_options_default);
|
zclient = zclient_new(master, &zclient_options_default);
|
||||||
@ -713,6 +698,10 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
|
|||||||
|
|
||||||
/* Learn about interface VRF. */
|
/* Learn about interface VRF. */
|
||||||
zclient->interface_vrf_update = bfdd_interface_vrf_update;
|
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)
|
void bfdd_zclient_stop(void)
|
||||||
|
@ -384,7 +384,7 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 " : "",
|
CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) ? "group " : "",
|
||||||
peer->host);
|
peer->host);
|
||||||
|
|
||||||
|
@ -1715,7 +1715,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
|
|||||||
stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
|
stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
|
||||||
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
|
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
|
||||||
if (!peer->nexthop.ifp) {
|
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);
|
peer->host);
|
||||||
return BGP_ATTR_PARSE_WITHDRAW;
|
return BGP_ATTR_PARSE_WITHDRAW;
|
||||||
}
|
}
|
||||||
@ -1732,7 +1732,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
|
|||||||
stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
|
stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
|
||||||
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
|
if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
|
||||||
if (!peer->nexthop.ifp) {
|
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);
|
peer->host);
|
||||||
return BGP_ATTR_PARSE_WITHDRAW;
|
return BGP_ATTR_PARSE_WITHDRAW;
|
||||||
}
|
}
|
||||||
@ -1762,7 +1762,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
|
|||||||
attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
|
attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
|
||||||
}
|
}
|
||||||
if (!peer->nexthop.ifp) {
|
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);
|
peer->host);
|
||||||
return BGP_ATTR_PARSE_WITHDRAW;
|
return BGP_ATTR_PARSE_WITHDRAW;
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include "bgpd/bgp_zebra.h"
|
#include "bgpd/bgp_zebra.h"
|
||||||
#include "bgpd/bgp_nexthop.h"
|
#include "bgpd/bgp_nexthop.h"
|
||||||
#include "bgpd/bgp_addpath.h"
|
#include "bgpd/bgp_addpath.h"
|
||||||
|
#include "bgpd/bgp_mac.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Definitions and external declarations.
|
* Definitions and external declarations.
|
||||||
@ -2503,6 +2504,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
|||||||
/* Perform route selection and update zebra, if required. */
|
/* Perform route selection and update zebra, if required. */
|
||||||
bgp_process(bgp_vrf, rn, afi, safi);
|
bgp_process(bgp_vrf, rn, afi, safi);
|
||||||
|
|
||||||
|
/* Process for route leaking. */
|
||||||
|
vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2668,6 +2672,9 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
|||||||
if (!pi)
|
if (!pi)
|
||||||
return 0;
|
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);
|
bgp_aggregate_decrement(bgp_vrf, &rn->p, pi, afi, safi);
|
||||||
|
|
||||||
/* Mark entry for deletion */
|
/* Mark entry for deletion */
|
||||||
@ -2940,6 +2947,41 @@ static int install_uninstall_routes_for_es(struct bgp *bgp,
|
|||||||
return 0;
|
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
|
* Install or uninstall mac-ip routes are appropriate for this
|
||||||
* particular VRF.
|
* particular VRF.
|
||||||
@ -2996,6 +3038,10 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (is_route_matching_for_vrf(bgp_vrf, pi)) {
|
if (is_route_matching_for_vrf(bgp_vrf, pi)) {
|
||||||
|
if (bgp_evpn_route_rmac_self_check(
|
||||||
|
bgp_vrf, evp, pi))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (install)
|
if (install)
|
||||||
ret = install_evpn_route_entry_in_vrf(
|
ret = install_evpn_route_entry_in_vrf(
|
||||||
bgp_vrf, evp, pi);
|
bgp_vrf, evp, pi);
|
||||||
@ -4223,11 +4269,13 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi)
|
|||||||
|
|
||||||
table = bgp_vrf->rib[afi][safi];
|
table = bgp_vrf->rib[afi][safi];
|
||||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
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. */
|
/* TODO: Support for AddPath for EVPN. */
|
||||||
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
|
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
|
||||||
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
|
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,
|
bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p,
|
||||||
afi, safi);
|
afi, safi);
|
||||||
break;
|
break;
|
||||||
@ -4294,12 +4342,13 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
|
|||||||
table = bgp_vrf->rib[afi][safi];
|
table = bgp_vrf->rib[afi][safi];
|
||||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
||||||
/* Need to identify the "selected" route entry to use its
|
/* 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.
|
* TODO: Support for AddPath for EVPN.
|
||||||
*/
|
*/
|
||||||
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
|
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
|
||||||
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
|
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
|
||||||
&& (!pi->extra || !pi->extra->parent)) {
|
&& is_route_injectable_into_evpn(pi)) {
|
||||||
|
|
||||||
/* apply the route-map */
|
/* apply the route-map */
|
||||||
if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
|
if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
|
||||||
@ -5033,6 +5082,9 @@ void bgp_evpn_derive_auto_rt_export(struct bgp *bgp, struct bgpevpn *vpn)
|
|||||||
*/
|
*/
|
||||||
void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp)
|
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);
|
form_auto_rd(bgp->router_id, bgp->vrf_rd_id, &bgp->vrf_prd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,8 +89,13 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
|
|||||||
!ri->extra->parent)
|
!ri->extra->parent)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* See if the parent is of family L2VPN/EVPN */
|
/* Determine parent recursively */
|
||||||
parent_ri = (struct bgp_path_info *)ri->extra->parent;
|
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;
|
rn = parent_ri->net;
|
||||||
if (!rn)
|
if (!rn)
|
||||||
return 0;
|
return 0;
|
||||||
@ -102,6 +107,38 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
|
|||||||
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,
|
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
|
||||||
struct prefix *p,
|
struct prefix *p,
|
||||||
struct attr *src_attr, afi_t afi,
|
struct attr *src_attr, afi_t afi,
|
||||||
|
@ -30,8 +30,9 @@
|
|||||||
|
|
||||||
#define RT_ADDRSTRLEN 28
|
#define RT_ADDRSTRLEN 28
|
||||||
|
|
||||||
/* EVPN prefix lengths. This reprsent the sizeof struct prefix_evpn */
|
/* EVPN prefix lengths. This represents the sizeof struct evpn_addr
|
||||||
#define EVPN_ROUTE_PREFIXLEN 224
|
* in bits */
|
||||||
|
#define EVPN_ROUTE_PREFIXLEN (sizeof(struct evpn_addr) * 8)
|
||||||
|
|
||||||
/* EVPN route types. */
|
/* EVPN route types. */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -3369,6 +3369,7 @@ DEFUN (bgp_evpn_advertise_type5,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* advertise type-5 routes */
|
/* advertise type-5 routes */
|
||||||
|
if (advertise_type5_routes(bgp_vrf, afi))
|
||||||
bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
|
bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -310,7 +310,8 @@ void bgp_timer_set(struct peer *peer)
|
|||||||
status start timer is on unless peer is shutdown or peer is
|
status start timer is on unless peer is shutdown or peer is
|
||||||
inactive. All other timer must be turned off */
|
inactive. All other timer must be turned off */
|
||||||
if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer)
|
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);
|
BGP_TIMER_OFF(peer->t_start);
|
||||||
} else {
|
} else {
|
||||||
BGP_TIMER_ON(peer->t_start, bgp_start_timer,
|
BGP_TIMER_ON(peer->t_start, bgp_start_timer,
|
||||||
@ -1422,7 +1423,8 @@ int bgp_start(struct peer *peer)
|
|||||||
return 0;
|
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))
|
if (bgp_debug_neighbor_events(peer))
|
||||||
flog_err(
|
flog_err(
|
||||||
EC_BGP_FSM,
|
EC_BGP_FSM,
|
||||||
|
@ -284,9 +284,9 @@ static int bgp_vrf_enable(struct vrf *vrf)
|
|||||||
bgp_vrf_link(bgp, vrf);
|
bgp_vrf_link(bgp, vrf);
|
||||||
|
|
||||||
bgp_handle_socket(bgp, vrf, old_vrf_id, true);
|
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)
|
if (old_vrf_id != bgp->vrf_id)
|
||||||
bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id);
|
bgp_redistribute_redo(bgp);
|
||||||
bgp_instance_up(bgp);
|
bgp_instance_up(bgp);
|
||||||
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
|
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
|
||||||
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
|
vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
|
||||||
@ -333,9 +333,9 @@ static int bgp_vrf_disable(struct vrf *vrf)
|
|||||||
/* We have instance configured, unlink from VRF and make it
|
/* We have instance configured, unlink from VRF and make it
|
||||||
* "down". */
|
* "down". */
|
||||||
bgp_vrf_unlink(bgp, vrf);
|
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)
|
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_instance_down(bgp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "bgpd/bgp_zebra.h"
|
#include "bgpd/bgp_zebra.h"
|
||||||
#include "bgpd/bgp_nexthop.h"
|
#include "bgpd/bgp_nexthop.h"
|
||||||
#include "bgpd/bgp_nht.h"
|
#include "bgpd/bgp_nht.h"
|
||||||
|
#include "bgpd/bgp_evpn.h"
|
||||||
|
|
||||||
#if ENABLE_BGP_VNC
|
#if ENABLE_BGP_VNC
|
||||||
#include "bgpd/rfapi/rfapi_backend.h"
|
#include "bgpd/rfapi/rfapi_backend.h"
|
||||||
@ -552,8 +553,12 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
|
|||||||
if (bpi->extra && bpi->extra->bgp_orig)
|
if (bpi->extra && bpi->extra->bgp_orig)
|
||||||
bgp_nexthop = 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;
|
nh_valid = 1;
|
||||||
else
|
else
|
||||||
/*
|
/*
|
||||||
@ -614,8 +619,11 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
|
|||||||
* No nexthop tracking for redistributed routes because
|
* No nexthop tracking for redistributed routes because
|
||||||
* their originating protocols will do the tracking and
|
* their originating protocols will do the tracking and
|
||||||
* withdraw those routes if the nexthops become unreachable
|
* 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;
|
nh_valid = 1;
|
||||||
else
|
else
|
||||||
/*
|
/*
|
||||||
@ -683,11 +691,10 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* loop check - should not be an imported route. */
|
/* Is this route exportable into the VPN table? */
|
||||||
if (path_vrf->extra && path_vrf->extra->bgp_orig)
|
if (!is_route_injectable_into_vpn(path_vrf))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
|
if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
|
||||||
if (debug)
|
if (debug)
|
||||||
zlog_debug("%s: %s skipping: %s", __func__,
|
zlog_debug("%s: %s skipping: %s", __func__,
|
||||||
@ -894,15 +901,6 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
|
|||||||
path_vrf->type, path_vrf->sub_type);
|
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)
|
if (!bgp_vpn)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -912,6 +910,10 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
|
|||||||
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 (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
|
||||||
if (debug)
|
if (debug)
|
||||||
zlog_debug("%s: skipping: %s", __func__, debugmsg);
|
zlog_debug("%s: skipping: %s", __func__, debugmsg);
|
||||||
@ -995,7 +997,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */
|
|||||||
== bgp_vrf) {
|
== bgp_vrf) {
|
||||||
/* delete route */
|
/* delete route */
|
||||||
if (debug)
|
if (debug)
|
||||||
zlog_debug("%s: deleting it\n",
|
zlog_debug("%s: deleting it",
|
||||||
__func__);
|
__func__);
|
||||||
bgp_aggregate_decrement(bgp_vpn, &bn->p,
|
bgp_aggregate_decrement(bgp_vpn, &bn->p,
|
||||||
bpi, afi, safi);
|
bpi, afi, safi);
|
||||||
@ -1352,7 +1354,10 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */
|
|||||||
|
|
||||||
for (bpi = bgp_node_get_bgp_path_info(bn); bpi;
|
for (bpi = bgp_node_get_bgp_path_info(bn); bpi;
|
||||||
bpi = bpi->next) {
|
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 */
|
/* delete route */
|
||||||
bgp_aggregate_decrement(bgp_vrf, &bn->p, bpi,
|
bgp_aggregate_decrement(bgp_vrf, &bn->p, bpi,
|
||||||
|
@ -226,6 +226,39 @@ static inline void vpn_leak_postchange(vpn_policy_direction_t direction,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 void vpn_policy_routemap_event(const char *rmap_name);
|
||||||
|
|
||||||
extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey);
|
extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey);
|
||||||
|
@ -2476,8 +2476,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
|||||||
|
|
||||||
/* advertise/withdraw type-5 routes */
|
/* advertise/withdraw type-5 routes */
|
||||||
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
|
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
|
||||||
if (advertise_type5_routes(bgp, afi) && new_select &&
|
if (advertise_type5_routes(bgp, afi) &&
|
||||||
(!new_select->extra || !new_select->extra->parent)) {
|
new_select &&
|
||||||
|
is_route_injectable_into_evpn(new_select)) {
|
||||||
|
|
||||||
/* apply the route-map */
|
/* apply the route-map */
|
||||||
if (bgp->adv_cmd_rmap[afi][safi].map) {
|
if (bgp->adv_cmd_rmap[afi][safi].map) {
|
||||||
@ -2500,8 +2501,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
|||||||
afi, safi);
|
afi, safi);
|
||||||
|
|
||||||
}
|
}
|
||||||
} else if (advertise_type5_routes(bgp, afi) && old_select &&
|
} else if (advertise_type5_routes(bgp, afi) &&
|
||||||
(!old_select->extra || !old_select->extra->parent))
|
old_select &&
|
||||||
|
is_route_injectable_into_evpn(old_select))
|
||||||
bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
|
bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,6 +409,24 @@ static inline int bgp_fibupd_safi(safi_t safi)
|
|||||||
return 0;
|
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. */
|
/* Prototypes. */
|
||||||
extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi,
|
extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi,
|
||||||
struct peer *peer, afi_t afi, safi_t safi);
|
struct peer *peer, afi_t afi, safi_t safi);
|
||||||
|
@ -3368,7 +3368,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
|
|||||||
"Processing route_map %s update on advertise type5 route command",
|
"Processing route_map %s update on advertise type5 route command",
|
||||||
rmap_name);
|
rmap_name);
|
||||||
|
|
||||||
if (route_update) {
|
if (route_update && advertise_type5_routes(bgp, afi)) {
|
||||||
bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
|
bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
|
||||||
bgp_evpn_advertise_type5_routes(bgp, afi, safi);
|
bgp_evpn_advertise_type5_routes(bgp, afi, safi);
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket);
|
|||||||
static struct cache *find_cache(const uint8_t preference);
|
static struct cache *find_cache(const uint8_t preference);
|
||||||
static int add_tcp_cache(const char *host, const char *port,
|
static int add_tcp_cache(const char *host, const char *port,
|
||||||
const uint8_t preference);
|
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_synchronized(void);
|
||||||
static int is_running(void);
|
static int is_running(void);
|
||||||
static void route_match_free(void *rule);
|
static void route_match_free(void *rule);
|
||||||
@ -271,17 +271,23 @@ static struct cache *find_cache(const uint8_t preference)
|
|||||||
return NULL;
|
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];
|
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 rpki_for_each_record_arg *arg = data;
|
||||||
struct vty *vty = arg->vty;
|
struct vty *vty = arg->vty;
|
||||||
|
|
||||||
(*arg->prefix_amount)++;
|
(*arg->prefix_amount)++;
|
||||||
|
|
||||||
lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
|
print_record(record, vty);
|
||||||
vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len,
|
|
||||||
record->max_len, record->asn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rtr_mgr_group *get_groups(void)
|
static struct rtr_mgr_group *get_groups(void)
|
||||||
@ -663,10 +669,10 @@ static void print_prefix_table(struct vty *vty)
|
|||||||
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS");
|
vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS");
|
||||||
|
|
||||||
arg.prefix_amount = &number_of_ipv4_prefixes;
|
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;
|
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 IPv4 Prefixes: %u\n", number_of_ipv4_prefixes);
|
||||||
vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes);
|
vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes);
|
||||||
@ -1179,6 +1185,58 @@ DEFUN (show_rpki_prefix_table,
|
|||||||
return CMD_SUCCESS;
|
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,
|
DEFUN (show_rpki_cache_server,
|
||||||
show_rpki_cache_server_cmd,
|
show_rpki_cache_server_cmd,
|
||||||
"show rpki cache-server",
|
"show rpki cache-server",
|
||||||
@ -1450,6 +1508,7 @@ static void install_cli_commands(void)
|
|||||||
install_element(ENABLE_NODE, &show_rpki_prefix_table_cmd);
|
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_connection_cmd);
|
||||||
install_element(ENABLE_NODE, &show_rpki_cache_server_cmd);
|
install_element(ENABLE_NODE, &show_rpki_cache_server_cmd);
|
||||||
|
install_element(ENABLE_NODE, &show_rpki_prefix_cmd);
|
||||||
|
|
||||||
/* Install debug commands */
|
/* Install debug commands */
|
||||||
install_element(CONFIG_NODE, &debug_rpki_cmd);
|
install_element(CONFIG_NODE, &debug_rpki_cmd);
|
||||||
|
191
bgpd/bgp_vty.c
191
bgpd/bgp_vty.c
@ -2055,29 +2055,6 @@ DEFUN (no_bgp_graceful_restart_preserve_fw,
|
|||||||
return CMD_SUCCESS;
|
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 */
|
/* "bgp graceful-shutdown" configuration */
|
||||||
DEFUN (bgp_graceful_shutdown,
|
DEFUN (bgp_graceful_shutdown,
|
||||||
bgp_graceful_shutdown_cmd,
|
bgp_graceful_shutdown_cmd,
|
||||||
@ -2841,18 +2818,23 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
|
|||||||
as = strtoul(as_str, NULL, 10);
|
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);
|
ret = str2sockunion(peer_str, &su);
|
||||||
if (ret < 0) {
|
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,
|
ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, afi,
|
||||||
safi);
|
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);
|
ret = peer_group_remote_as(bgp, peer_str, &as, as_type);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"%% Create the peer-group or interface first or specify \"interface\" keyword\n");
|
"%% Create the peer-group or interface first\n");
|
||||||
vty_out(vty, "%% if using an unnumbered interface neighbor\n");
|
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
}
|
}
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
@ -3251,7 +3233,7 @@ DEFUN (no_neighbor_interface_peer_group_remote_as,
|
|||||||
/* look up for neighbor by interface name config. */
|
/* look up for neighbor by interface name config. */
|
||||||
peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg);
|
peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg);
|
||||||
if (peer) {
|
if (peer) {
|
||||||
peer_as_change(peer, 0, AS_SPECIFIED);
|
peer_as_change(peer, 0, AS_UNSPECIFIED);
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8031,7 +8013,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
|
|||||||
json, "ribMemory",
|
json, "ribMemory",
|
||||||
ents * sizeof(struct bgp_node));
|
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, "peerCount", ents);
|
||||||
json_object_int_add(json, "peerMemory",
|
json_object_int_add(json, "peerMemory",
|
||||||
ents * sizeof(struct peer));
|
ents * sizeof(struct peer));
|
||||||
@ -8071,7 +8053,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
|
|||||||
bgp_node)));
|
bgp_node)));
|
||||||
|
|
||||||
/* Peer related usage */
|
/* Peer related usage */
|
||||||
ents = listcount(bgp->peer);
|
ents = bgp->af_peer_count[afi][safi];
|
||||||
vty_out(vty, "Peers %ld, using %s of memory\n",
|
vty_out(vty, "Peers %ld, using %s of memory\n",
|
||||||
ents,
|
ents,
|
||||||
mtype_memstr(
|
mtype_memstr(
|
||||||
@ -8522,7 +8504,7 @@ const char *afi_safi_json(afi_t afi, safi_t safi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Show BGP peer's information. */
|
/* 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,
|
static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
|
||||||
afi_t afi, safi_t safi,
|
afi_t afi, safi_t safi,
|
||||||
@ -10945,6 +10927,14 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
|
|||||||
struct peer *peer;
|
struct peer *peer;
|
||||||
int find = 0;
|
int find = 0;
|
||||||
bool nbr_output = false;
|
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)) {
|
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
|
||||||
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
|
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
|
||||||
@ -10973,17 +10963,54 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
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)
|
if (use_json)
|
||||||
json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
|
json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
|
||||||
else
|
else
|
||||||
vty_out(vty, "%% No such neighbor in this view/vrf\n");
|
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");
|
vty_out(vty, "%% No BGP neighbors found\n");
|
||||||
|
|
||||||
if (use_json) {
|
if (use_json) {
|
||||||
@ -11049,7 +11076,8 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
|
|||||||
: bgp->name);
|
: bgp->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == show_peer) {
|
if (type == show_peer || type == show_ipv4_peer ||
|
||||||
|
type == show_ipv6_peer) {
|
||||||
ret = str2sockunion(ip_str, &su);
|
ret = str2sockunion(ip_str, &su);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
bgp_show_neighbor(vty, bgp, type, NULL, ip_str,
|
bgp_show_neighbor(vty, bgp, type, NULL, ip_str,
|
||||||
@ -11058,7 +11086,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
|
|||||||
bgp_show_neighbor(vty, bgp, type, &su, NULL,
|
bgp_show_neighbor(vty, bgp, type, &su, NULL,
|
||||||
use_json, json);
|
use_json, json);
|
||||||
} else {
|
} else {
|
||||||
bgp_show_neighbor(vty, bgp, show_all, NULL, NULL,
|
bgp_show_neighbor(vty, bgp, type, NULL, NULL,
|
||||||
use_json, json);
|
use_json, json);
|
||||||
}
|
}
|
||||||
json_object_free(json);
|
json_object_free(json);
|
||||||
@ -11151,6 +11179,7 @@ DEFUN (show_ip_bgp_neighbors,
|
|||||||
char *vrf = NULL;
|
char *vrf = NULL;
|
||||||
char *sh_arg = NULL;
|
char *sh_arg = NULL;
|
||||||
enum show_type sh_type;
|
enum show_type sh_type;
|
||||||
|
afi_t afi = AFI_MAX;
|
||||||
|
|
||||||
bool uj = use_json(argc, argv);
|
bool uj = use_json(argc, argv);
|
||||||
|
|
||||||
@ -11166,13 +11195,29 @@ DEFUN (show_ip_bgp_neighbors,
|
|||||||
vrf = argv[idx + 1]->arg;
|
vrf = argv[idx + 1]->arg;
|
||||||
|
|
||||||
idx++;
|
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)
|
if (argv_find(argv, argc, "A.B.C.D", &idx)
|
||||||
|| argv_find(argv, argc, "X:X::X:X", &idx)
|
|| argv_find(argv, argc, "X:X::X:X", &idx)
|
||||||
|| argv_find(argv, argc, "WORD", &idx)) {
|
|| argv_find(argv, argc, "WORD", &idx)) {
|
||||||
sh_type = show_peer;
|
sh_type = show_peer;
|
||||||
sh_arg = argv[idx]->arg;
|
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 bgp_show_neighbor_vty(vty, vrf, sh_type, sh_arg, uj);
|
||||||
}
|
}
|
||||||
@ -11267,8 +11312,9 @@ DEFUN (show_ip_bgp_attr_info,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
|
static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
|
||||||
safi_t safi, bool use_json)
|
afi_t afi, safi_t safi,
|
||||||
|
bool use_json, json_object *json)
|
||||||
{
|
{
|
||||||
struct bgp *bgp;
|
struct bgp *bgp;
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
@ -11277,13 +11323,10 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
|
|||||||
char *ecom_str;
|
char *ecom_str;
|
||||||
vpn_policy_direction_t dir;
|
vpn_policy_direction_t dir;
|
||||||
|
|
||||||
if (use_json) {
|
if (json) {
|
||||||
json_object *json = NULL;
|
|
||||||
json_object *json_import_vrfs = NULL;
|
json_object *json_import_vrfs = NULL;
|
||||||
json_object *json_export_vrfs = NULL;
|
json_object *json_export_vrfs = NULL;
|
||||||
|
|
||||||
json = json_object_new_object();
|
|
||||||
|
|
||||||
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
|
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
|
||||||
|
|
||||||
if (!bgp) {
|
if (!bgp) {
|
||||||
@ -11354,11 +11397,12 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
|
|||||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (use_json) {
|
||||||
vty_out(vty, "%s\n",
|
vty_out(vty, "%s\n",
|
||||||
json_object_to_json_string_ext(json,
|
json_object_to_json_string_ext(json,
|
||||||
JSON_C_TO_STRING_PRETTY));
|
JSON_C_TO_STRING_PRETTY));
|
||||||
json_object_free(json);
|
json_object_free(json);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
|
bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
|
||||||
|
|
||||||
@ -11422,6 +11466,54 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
|
|||||||
return CMD_SUCCESS;
|
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. */
|
/* "show [ip] bgp route-leak" command. */
|
||||||
DEFUN (show_ip_bgp_route_leak,
|
DEFUN (show_ip_bgp_route_leak,
|
||||||
show_ip_bgp_route_leak_cmd,
|
show_ip_bgp_route_leak_cmd,
|
||||||
@ -11441,6 +11533,7 @@ DEFUN (show_ip_bgp_route_leak,
|
|||||||
|
|
||||||
bool uj = use_json(argc, argv);
|
bool uj = use_json(argc, argv);
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
|
json_object *json = NULL;
|
||||||
|
|
||||||
/* show [ip] bgp */
|
/* show [ip] bgp */
|
||||||
if (argv_find(argv, argc, "ip", &idx)) {
|
if (argv_find(argv, argc, "ip", &idx)) {
|
||||||
@ -11470,7 +11563,13 @@ DEFUN (show_ip_bgp_route_leak,
|
|||||||
return CMD_WARNING;
|
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,
|
static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi,
|
||||||
|
@ -1819,23 +1819,42 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update redistribute vrf bitmap during triggers like
|
void bgp_redistribute_redo(struct bgp *bgp)
|
||||||
restart networking or delete/add VRFs */
|
{
|
||||||
void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id)
|
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;
|
int i;
|
||||||
afi_t afi;
|
afi_t afi;
|
||||||
|
|
||||||
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
||||||
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
|
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
|
||||||
if ((old_vrf_id == VRF_UNKNOWN)
|
if (vrf_bitmap_check(zclient->redist[afi][i],
|
||||||
|| vrf_bitmap_check(zclient->redist[afi][i],
|
old_vrf_id))
|
||||||
old_vrf_id)) {
|
|
||||||
vrf_bitmap_unset(zclient->redist[afi][i],
|
vrf_bitmap_unset(zclient->redist[afi][i],
|
||||||
old_vrf_id);
|
old_vrf_id);
|
||||||
vrf_bitmap_set(zclient->redist[afi][i],
|
|
||||||
bgp->vrf_id);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ extern void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer);
|
|||||||
extern void bgp_zebra_instance_register(struct bgp *);
|
extern void bgp_zebra_instance_register(struct bgp *);
|
||||||
extern void bgp_zebra_instance_deregister(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,
|
extern struct bgp_redist *bgp_redist_lookup(struct bgp *, afi_t, uint8_t,
|
||||||
unsigned short);
|
unsigned short);
|
||||||
extern struct bgp_redist *bgp_redist_add(struct bgp *, afi_t, uint8_t,
|
extern struct bgp_redist *bgp_redist_add(struct bgp *, afi_t, uint8_t,
|
||||||
|
11
bgpd/bgpd.c
11
bgpd/bgpd.c
@ -707,6 +707,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
|
|||||||
{
|
{
|
||||||
struct peer_af *af;
|
struct peer_af *af;
|
||||||
int afid;
|
int afid;
|
||||||
|
struct bgp *bgp;
|
||||||
|
|
||||||
if (!peer)
|
if (!peer)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -715,6 +716,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
|
|||||||
if (afid >= BGP_AF_MAX)
|
if (afid >= BGP_AF_MAX)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
bgp = peer->bgp;
|
||||||
assert(peer->peer_af_array[afid] == NULL);
|
assert(peer->peer_af_array[afid] == NULL);
|
||||||
|
|
||||||
/* Allocate new peer af */
|
/* Allocate new peer af */
|
||||||
@ -725,6 +727,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
|
|||||||
af->safi = safi;
|
af->safi = safi;
|
||||||
af->afid = afid;
|
af->afid = afid;
|
||||||
af->peer = peer;
|
af->peer = peer;
|
||||||
|
bgp->af_peer_count[afi][safi]++;
|
||||||
|
|
||||||
return af;
|
return af;
|
||||||
}
|
}
|
||||||
@ -747,6 +750,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
|
|||||||
{
|
{
|
||||||
struct peer_af *af;
|
struct peer_af *af;
|
||||||
int afid;
|
int afid;
|
||||||
|
struct bgp *bgp;
|
||||||
|
|
||||||
if (!peer)
|
if (!peer)
|
||||||
return -1;
|
return -1;
|
||||||
@ -759,6 +763,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
|
|||||||
if (!af)
|
if (!af)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
bgp = peer->bgp;
|
||||||
bgp_stop_announce_route_timer(af);
|
bgp_stop_announce_route_timer(af);
|
||||||
|
|
||||||
if (PAF_SUBGRP(af)) {
|
if (PAF_SUBGRP(af)) {
|
||||||
@ -768,8 +773,12 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
|
|||||||
af->subgroup->id, peer->host);
|
af->subgroup->id, peer->host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
update_subgroup_remove_peer(af->subgroup, af);
|
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;
|
peer->peer_af_array[afid] = NULL;
|
||||||
XFREE(MTYPE_BGP_PEER_AF, af);
|
XFREE(MTYPE_BGP_PEER_AF, af);
|
||||||
return 0;
|
return 0;
|
||||||
@ -2714,7 +2723,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
|
|||||||
peer->sort = group->conf->sort;
|
peer->sort = group->conf->sort;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!group->conf->as) {
|
if (!group->conf->as && peer_sort(peer)) {
|
||||||
if (peer_sort(group->conf) != BGP_PEER_INTERNAL
|
if (peer_sort(group->conf) != BGP_PEER_INTERNAL
|
||||||
&& peer_sort(group->conf) != peer_sort(peer)) {
|
&& peer_sort(group->conf) != peer_sort(peer)) {
|
||||||
if (as)
|
if (as)
|
||||||
|
@ -99,6 +99,9 @@ enum bgp_af_index {
|
|||||||
for (afi = AFI_IP; afi < AFI_MAX; afi++) \
|
for (afi = AFI_IP; afi < AFI_MAX; afi++) \
|
||||||
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
|
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_io;
|
||||||
extern struct frr_pthread *bgp_pth_ka;
|
extern struct frr_pthread *bgp_pth_ka;
|
||||||
|
|
||||||
@ -377,6 +380,9 @@ struct bgp {
|
|||||||
#define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 7)
|
#define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 7)
|
||||||
#define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 8)
|
#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. */
|
/* Route table for next-hop lookup cache. */
|
||||||
struct bgp_table *nexthop_cache_table[AFI_MAX];
|
struct bgp_table *nexthop_cache_table[AFI_MAX];
|
||||||
|
|
||||||
@ -1906,7 +1912,7 @@ static inline void bgp_vrf_unlink(struct bgp *bgp, struct vrf *vrf)
|
|||||||
bgp->vrf_id = VRF_UNKNOWN;
|
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 */
|
/* For benefit of rfapi */
|
||||||
extern struct peer *peer_new(struct bgp *bgp);
|
extern struct peer *peer_new(struct bgp *bgp);
|
||||||
|
@ -765,7 +765,7 @@ AC_DEFINE_UNQUOTED([CONFIGFILE_MASK], [${enable_configfile_mask}], [Mask for con
|
|||||||
enable_logfile_mask=${enable_logfile_mask:-0600}
|
enable_logfile_mask=${enable_logfile_mask:-0600}
|
||||||
AC_DEFINE_UNQUOTED([LOGFILE_MASK], [${enable_logfile_mask}], [Mask for log files])
|
AC_DEFINE_UNQUOTED([LOGFILE_MASK], [${enable_logfile_mask}], [Mask for log files])
|
||||||
|
|
||||||
MPATH_NUM=1
|
MPATH_NUM=16
|
||||||
|
|
||||||
case "${enable_multipath}" in
|
case "${enable_multipath}" in
|
||||||
0)
|
0)
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
.. _building-centos6:
|
||||||
|
|
||||||
CentOS 6
|
CentOS 6
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
(As an alternative to this installation, you may prefer to create a FRR
|
This document describes installation from source. If you want to build an RPM,
|
||||||
rpm package yourself and install that package instead. See instructions
|
see :ref:`packaging-redhat`.
|
||||||
in redhat/README.rpm\_build.md on how to build a rpm package)
|
|
||||||
|
|
||||||
Instructions are tested with ``CentOS 6.8`` on ``x86_64`` platform
|
Instructions are tested with ``CentOS 6.8`` on ``x86_64`` platform
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ CentOS 6 restrictions:
|
|||||||
PIMd is needed
|
PIMd is needed
|
||||||
- MPLS is not supported on ``CentOS 6``. MPLS requires Linux Kernel 4.5
|
- 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)
|
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,
|
with (IFLA\_INFO\_SLAVE\_KIND does not exist in the kernel headers,
|
||||||
you can use a newer kernel + headers to get this functionality)
|
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
|
- frr\_reload.py will not work, as this requires Python 2.7, and CentOS
|
||||||
@ -235,7 +236,7 @@ settings)::
|
|||||||
# Controls source route verification
|
# Controls source route verification
|
||||||
net.ipv4.conf.default.rp_filter = 0
|
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
|
.. code-block:: shell
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
CentOS 7
|
CentOS 7
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
(As an alternative to this installation, you may prefer to create a FRR
|
This document describes installation from source. If you want to build an RPM,
|
||||||
rpm package yourself and install that package instead. See instructions
|
see :ref:`packaging-redhat`.
|
||||||
in redhat/README.rpm\_build.md on how to build a rpm package)
|
|
||||||
|
|
||||||
CentOS 7 restrictions:
|
CentOS 7 restrictions:
|
||||||
----------------------
|
----------------------
|
||||||
@ -127,7 +126,7 @@ following content:
|
|||||||
net.ipv4.conf.all.forwarding=1
|
net.ipv4.conf.all.forwarding=1
|
||||||
net.ipv6.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:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
122
doc/developer/building-frr-for-fedora.rst
Normal file
122
doc/developer/building-frr-for-fedora.rst
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
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 gawk \
|
||||||
|
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
|
@ -1,170 +0,0 @@
|
|||||||
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
|
|
@ -11,7 +11,7 @@ FreeBSD 10 restrictions:
|
|||||||
Install required packages
|
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)
|
is first package install and asked)
|
||||||
|
|
||||||
::
|
::
|
||||||
|
@ -11,7 +11,7 @@ FreeBSD 11 restrictions:
|
|||||||
Install required packages
|
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)
|
is first package install and asked)
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
@ -11,7 +11,7 @@ FreeBSD 9 restrictions:
|
|||||||
Install required packages
|
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)
|
is first package install and asked)
|
||||||
|
|
||||||
::
|
::
|
||||||
|
@ -63,10 +63,10 @@ Usage
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
Edit ``/usr/sbin/frr.init`` and add/remove the daemons name in section
|
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
|
isisd nhrpd ospfd ospf6d pimd ripd ripngd
|
||||||
|
|
||||||
Enable the serivce
|
Enable the service
|
||||||
^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
- ``service frr enable``
|
- ``service frr enable``
|
||||||
|
@ -1,35 +1,30 @@
|
|||||||
Ubuntu 14.04 LTS
|
Ubuntu 14.04 LTS
|
||||||
===============================================
|
================
|
||||||
|
|
||||||
- MPLS is not supported on ``Ubuntu 14.04`` with default kernel. MPLS
|
This document describes installation from source. If you want to build a
|
||||||
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
``deb``, see :ref:`packaging-debian`.
|
||||||
limited use without MPLS) For an updated Ubuntu Kernel, see
|
|
||||||
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
|
||||||
|
|
||||||
Install required packages
|
Installing Dependencies
|
||||||
-------------------------
|
-----------------------
|
||||||
|
|
||||||
Add packages:
|
.. code-block:: console
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
|
apt-get update
|
||||||
apt-get install \
|
apt-get install \
|
||||||
git autoconf automake libtool make gawk libreadline-dev texinfo \
|
git autoconf automake libtool make gawk libreadline-dev texinfo \
|
||||||
dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
|
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
|
||||||
libc-ares-dev python3-dev python3-sphinx install-info build-essential
|
libc-ares-dev python3-dev python3-sphinx install-info build-essential \
|
||||||
|
libsnmp-dev perl
|
||||||
|
|
||||||
.. include:: building-libyang.rst
|
.. include:: building-libyang.rst
|
||||||
|
|
||||||
Get FRR, compile it and install it (from Git)
|
Building & Installing FRR
|
||||||
---------------------------------------------
|
-------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not
|
Add FRR user and groups
|
||||||
using any packages**
|
|
||||||
|
|
||||||
Add frr groups and user
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
::
|
.. code-block:: console
|
||||||
|
|
||||||
sudo groupadd -r -g 92 frr
|
sudo groupadd -r -g 92 frr
|
||||||
sudo groupadd -r -g 85 frrvty
|
sudo groupadd -r -g 85 frrvty
|
||||||
@ -37,60 +32,32 @@ Add frr groups and user
|
|||||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||||
sudo usermod -a -G frrvty 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
|
.. include:: include-compile.rst
|
||||||
an example.)
|
|
||||||
|
|
||||||
::
|
Install FRR configuration files
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
.. code-block:: console
|
||||||
cd frr
|
|
||||||
./bootstrap.sh
|
|
||||||
./configure \
|
|
||||||
--prefix=/usr \
|
|
||||||
--enable-exampledir=/usr/share/doc/frr/examples/ \
|
|
||||||
--localstatedir=/var/run/frr \
|
|
||||||
--sbindir=/usr/lib/frr \
|
|
||||||
--sysconfdir=/etc/frr \
|
|
||||||
--enable-multipath=64 \
|
|
||||||
--enable-user=frr \
|
|
||||||
--enable-group=frr \
|
|
||||||
--enable-vty-group=frrvty \
|
|
||||||
--enable-configfile-mask=0640 \
|
|
||||||
--enable-logfile-mask=0640 \
|
|
||||||
--enable-fpm \
|
|
||||||
--with-pkg-git-version \
|
|
||||||
--with-pkg-extra-version=-MyOwnFRRVersion
|
|
||||||
make
|
|
||||||
make check
|
|
||||||
sudo make install
|
|
||||||
|
|
||||||
Create empty FRR configuration files
|
sudo install -m 775 -o frr -g frr -d /var/log/frr
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
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 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 frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
||||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.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 /dev/null /etc/frr/ospfd.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 /dev/null /etc/frr/ospf6d.conf
|
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
|
||||||
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
|
Tweak sysctls
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
|
Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
|
||||||
other settings)
|
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):
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -102,37 +69,67 @@ other settings)
|
|||||||
# based on Router Advertisements for this host
|
# based on Router Advertisements for this host
|
||||||
net.ipv6.conf.all.forwarding=1
|
net.ipv6.conf.all.forwarding=1
|
||||||
|
|
||||||
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
Reboot or use ``sysctl -p`` to apply the same config to the running system.
|
||||||
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`:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# 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
|
||||||
|
""""""""""""""""""""""
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# 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
|
Install the init.d service
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
::
|
.. code-block:: console
|
||||||
|
|
||||||
sudo install -m 755 tools/frr /etc/init.d/frr
|
sudo install -m 755 tools/frr /etc/init.d/frr
|
||||||
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
|
|
||||||
sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
|
||||||
|
|
||||||
Enable daemons
|
Enable daemons
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
|
Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
|
||||||
those daemons you want to start by systemd.
|
section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
|
||||||
| For example.
|
as required by changing the value to ``yes``.
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
zebra=yes
|
|
||||||
bgpd=yes
|
|
||||||
ospfd=yes
|
|
||||||
ospf6d=yes
|
|
||||||
ripd=yes
|
|
||||||
ripngd=yes
|
|
||||||
isisd=yes
|
|
||||||
|
|
||||||
Start the init.d service
|
Start the init.d service
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
- /etc/init.d/frr start
|
.. code-block:: console
|
||||||
- use ``/etc/init.d/frr status`` to check its status.
|
|
||||||
|
/etc/init.d/frr start
|
||||||
|
|
||||||
|
Use ``/etc/init.d/frr status`` to check its status.
|
||||||
|
@ -1,36 +1,30 @@
|
|||||||
Ubuntu 16.04 LTS
|
Ubuntu 16.04 LTS
|
||||||
===============================================
|
================
|
||||||
|
|
||||||
- MPLS is not supported on ``Ubuntu 16.04`` with default kernel. MPLS
|
This document describes installation from source. If you want to build a
|
||||||
requires Linux Kernel 4.5 or higher (LDP can be built, but may have
|
``deb``, see :ref:`packaging-debian`.
|
||||||
limited use without MPLS) For an updated Ubuntu Kernel, see
|
|
||||||
http://kernel.ubuntu.com/~kernel-ppa/mainline/
|
|
||||||
|
|
||||||
Install required packages
|
Installing Dependencies
|
||||||
-------------------------
|
-----------------------
|
||||||
|
|
||||||
Add packages:
|
.. code-block:: console
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
|
apt-get update
|
||||||
apt-get install \
|
apt-get install \
|
||||||
git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \
|
git autoconf automake libtool make gawk libreadline-dev texinfo \
|
||||||
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
|
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
|
||||||
libc-ares-dev python3-dev libsystemd-dev python-ipaddress \
|
libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
|
||||||
python3-sphinx install-info build-essential libsystemd-dev
|
install-info build-essential libsystemd-dev libsnmp-dev perl
|
||||||
|
|
||||||
.. include:: building-libyang.rst
|
.. include:: building-libyang.rst
|
||||||
|
|
||||||
Get FRR, compile it and install it (from Git)
|
Building & Installing FRR
|
||||||
---------------------------------------------
|
-------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not
|
Add FRR user and groups
|
||||||
using any packages**
|
|
||||||
|
|
||||||
Add frr groups and user
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
::
|
.. code-block:: console
|
||||||
|
|
||||||
sudo groupadd -r -g 92 frr
|
sudo groupadd -r -g 92 frr
|
||||||
sudo groupadd -r -g 85 frrvty
|
sudo groupadd -r -g 85 frrvty
|
||||||
@ -38,61 +32,32 @@ Add frr groups and user
|
|||||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||||
sudo usermod -a -G frrvty 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
|
.. include:: include-compile.rst
|
||||||
an example.)
|
|
||||||
|
|
||||||
::
|
Install FRR configuration files
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
git clone https://github.com/frrouting/frr.git frr
|
.. code-block:: console
|
||||||
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
|
sudo install -m 775 -o frr -g frr -d /var/log/frr
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
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 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 frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
||||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.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 /dev/null /etc/frr/ospfd.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 /dev/null /etc/frr/ospf6d.conf
|
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
|
||||||
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
|
Tweak sysctls
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
|
Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
|
||||||
other settings)
|
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):
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -104,12 +69,39 @@ other settings)
|
|||||||
# based on Router Advertisements for this host
|
# based on Router Advertisements for this host
|
||||||
net.ipv6.conf.all.forwarding=1
|
net.ipv6.conf.all.forwarding=1
|
||||||
|
|
||||||
Enable MPLS Forwarding (with Linux Kernel >= 4.5)
|
Reboot or use ``sysctl -p`` to apply the same config to the running system.
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Edit ``/etc/sysctl.conf`` and the following lines. Make sure to add a
|
Add MPLS kernel modules
|
||||||
line equal to ``net.mpls.conf.eth0.input`` or each interface used with
|
"""""""""""""""""""""""
|
||||||
MPLS
|
|
||||||
|
.. 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/
|
||||||
|
|
||||||
|
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`:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# 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
|
||||||
|
""""""""""""""""""""""
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -119,54 +111,24 @@ MPLS
|
|||||||
net.mpls.conf.eth2.input=1
|
net.mpls.conf.eth2.input=1
|
||||||
net.mpls.platform_labels=100000
|
net.mpls.platform_labels=100000
|
||||||
|
|
||||||
Add MPLS kernel modules
|
Install service files
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Add the following lines to ``/etc/modules-load.d/modules.conf``:
|
.. code-block:: console
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
# Load MPLS Kernel Modules
|
|
||||||
mpls-router
|
|
||||||
mpls-iptunnel
|
|
||||||
|
|
||||||
**Reboot** or use ``sysctl -p`` to apply the same config to the running
|
|
||||||
system
|
|
||||||
|
|
||||||
Install the systemd service (if rebooted from last step, change directory back to frr directory)
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
|
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
|
||||||
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
|
sudo systemctl enable frr
|
||||||
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 daemons
|
Enable daemons
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
|
Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
|
||||||
those daemons you want to start by systemd.
|
section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
|
||||||
| For example.
|
as required by changing the value to ``yes``.
|
||||||
|
|
||||||
::
|
Start FRR
|
||||||
|
^^^^^^^^^
|
||||||
|
|
||||||
zebra=yes
|
.. code-block:: console
|
||||||
bgpd=yes
|
|
||||||
ospfd=yes
|
|
||||||
ospf6d=yes
|
|
||||||
ripd=yes
|
|
||||||
ripngd=yes
|
|
||||||
isisd=yes
|
|
||||||
|
|
||||||
Enable the systemd service
|
systemctl start frr
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
- systemctl enable frr
|
|
||||||
|
|
||||||
Start the systemd service
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
- systemctl start frr
|
|
||||||
- use ``systemctl status frr`` to check its status.
|
|
||||||
|
@ -1,55 +1,44 @@
|
|||||||
Ubuntu 18.04 LTS
|
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 \
|
sudo apt-get install \
|
||||||
git autoconf automake libtool make gawk libreadline-dev texinfo \
|
git autoconf automake libtool make gawk libreadline-dev texinfo \
|
||||||
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
|
pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
|
||||||
libc-ares-dev python3-dev libsystemd-dev python-ipaddress \
|
libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
|
||||||
python3-sphinx install-info build-essential libsystemd-dev
|
install-info build-essential libsystemd-dev libsnmp-dev perl
|
||||||
|
|
||||||
.. include:: building-libyang.rst
|
.. include:: building-libyang.rst
|
||||||
|
|
||||||
Optional packages
|
|
||||||
^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Dependencies for additional functionality can be installed as-desired.
|
|
||||||
|
|
||||||
Protobuf
|
Protobuf
|
||||||
~~~~~~~~
|
^^^^^^^^
|
||||||
|
|
||||||
::
|
.. code-block:: console
|
||||||
|
|
||||||
sudo apt-get install \
|
sudo apt-get install protobuf-c-compiler libprotobuf-c-dev
|
||||||
protobuf-c-compiler \
|
|
||||||
libprotobuf-c-dev
|
|
||||||
|
|
||||||
ZeroMQ
|
ZeroMQ
|
||||||
~~~~~~
|
^^^^^^
|
||||||
|
|
||||||
::
|
.. code-block:: console
|
||||||
|
|
||||||
sudo apt-get install \
|
sudo apt-get install libzmq5 libzmq3-dev
|
||||||
libzmq5 \
|
|
||||||
libzmq3-dev
|
|
||||||
|
|
||||||
Get FRR, compile it and install it (from Git)
|
Building & Installing FRR
|
||||||
---------------------------------------------
|
-------------------------
|
||||||
|
|
||||||
**This assumes you want to build and install FRR from source and not
|
Add FRR user and groups
|
||||||
using any packages**
|
|
||||||
|
|
||||||
Add frr groups and user
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
::
|
.. code-block:: console
|
||||||
|
|
||||||
sudo groupadd -r -g 92 frr
|
sudo groupadd -r -g 92 frr
|
||||||
sudo groupadd -r -g 85 frrvty
|
sudo groupadd -r -g 85 frrvty
|
||||||
@ -57,104 +46,29 @@ Add frr groups and user
|
|||||||
--gecos "FRR suite" --shell /sbin/nologin frr
|
--gecos "FRR suite" --shell /sbin/nologin frr
|
||||||
sudo usermod -a -G frrvty 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
|
Compile
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
|
|
||||||
::
|
.. include:: include-compile.rst
|
||||||
|
|
||||||
make
|
Install FRR configuration files
|
||||||
make check
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
sudo make install
|
|
||||||
|
|
||||||
Create empty FRR configuration files
|
.. code-block:: console
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Although not strictly necessary, it's good practice to create empty
|
sudo install -m 775 -o frr -g frr -d /var/log/frr
|
||||||
configuration files _before_ starting FRR. This assures that the permissions
|
|
||||||
are correct. If the files are not already present, FRR will create them.
|
|
||||||
|
|
||||||
It's also important to consider _which_ files to create. FRR supports writing
|
|
||||||
configuration to a monolithic file, :file:`/etc/frr/frr.conf`.
|
|
||||||
|
|
||||||
.. 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 frrvty -d /etc/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 frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
|
||||||
sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.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 /dev/null /etc/frr/ospfd.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 /dev/null /etc/frr/ospf6d.conf
|
sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
|
||||||
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
|
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,
|
||||||
sudo install -m 755 -o frr -g frr -d /var/log/frr
|
skip the MPLS related configuration in this section.
|
||||||
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
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
|
Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
|
||||||
other settings):
|
other settings):
|
||||||
@ -169,8 +83,10 @@ other settings):
|
|||||||
# based on Router Advertisements for this host
|
# based on Router Advertisements for this host
|
||||||
net.ipv6.conf.all.forwarding=1
|
net.ipv6.conf.all.forwarding=1
|
||||||
|
|
||||||
|
Reboot or use ``sysctl -p`` to apply the same config to the running system.
|
||||||
|
|
||||||
Add MPLS kernel modules
|
Add MPLS kernel modules
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
"""""""""""""""""""""""
|
||||||
|
|
||||||
Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To
|
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, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
|
||||||
@ -181,10 +97,15 @@ enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
|
|||||||
mpls_router
|
mpls_router
|
||||||
mpls_iptunnel
|
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
|
Enable MPLS Forwarding
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
""""""""""""""""""""""
|
||||||
|
|
||||||
Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
|
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.
|
equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
|
||||||
@ -197,48 +118,24 @@ equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
|
|||||||
net.mpls.conf.eth2.input=1
|
net.mpls.conf.eth2.input=1
|
||||||
net.mpls.platform_labels=100000
|
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/frr.service /etc/systemd/system/frr.service
|
||||||
sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
|
sudo systemctl enable frr
|
||||||
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 daemons
|
Enable daemons
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for those
|
Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
|
||||||
daemons you want to start by systemd. For example:
|
section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons
|
||||||
|
as required by changing the value to ``yes``.
|
||||||
|
|
||||||
::
|
Start FRR
|
||||||
|
^^^^^^^^^
|
||||||
zebra=yes
|
|
||||||
bgpd=yes
|
|
||||||
ospfd=yes
|
|
||||||
ospf6d=yes
|
|
||||||
ripd=yes
|
|
||||||
ripngd=yes
|
|
||||||
isisd=yes
|
|
||||||
|
|
||||||
Enable the systemd service
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
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
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
systemctl start frr
|
systemctl start frr
|
||||||
|
|
||||||
After starting the service, you can use ``systemctl status frr`` to check its
|
|
||||||
status.
|
|
||||||
|
@ -1,57 +1,55 @@
|
|||||||
The libyang library can be installed from third-party packages available `here
|
FRR depends on the relatively new ``libyang`` library to provide YANG/NETCONF
|
||||||
<https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
|
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
|
**Option 1: Binary Install**
|
||||||
to the libyang core package in order to build FRR successfully.
|
|
||||||
|
The FRR project builds binary ``libyang`` packages, which we offer for download
|
||||||
|
`here <https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
|
||||||
|
|
||||||
.. warning::
|
.. 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.
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
or Ubuntu 18.04:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
.. note::
|
.. 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 ``libyang`` development packages need to be installed in addition to the
|
||||||
the steps below:
|
libyang core package in order to build FRR successfully. Make sure to
|
||||||
|
download and install those from the link above alongside the binary
|
||||||
|
packages.
|
||||||
|
|
||||||
.. code-block:: shell
|
Depending on your platform, you may also need to install the PCRE
|
||||||
|
development package. Typically this is ``libpcre-dev`` or ``pcre-devel``.
|
||||||
|
|
||||||
git clone https://github.com/opensourcerouting/libyang
|
.. 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.
|
||||||
|
|
||||||
|
**Option 2: Source Install**
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
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:: console
|
||||||
|
|
||||||
|
git clone https://github.com/CESNET/libyang.git
|
||||||
cd libyang
|
cd libyang
|
||||||
git checkout -b tmp origin/tmp
|
|
||||||
mkdir build; cd build
|
mkdir build; cd build
|
||||||
cmake -DENABLE_LYD_PRIV=ON ..
|
cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
When building libyang on CentOS 6, it's also necessary to pass the
|
When building libyang on CentOS 6, it's also necessary to pass the
|
||||||
``-DENABLE_CACHE=OFF`` parameter to cmake.
|
``-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.
|
|
||||||
|
@ -12,7 +12,7 @@ Building FRR
|
|||||||
building-frr-for-centos7
|
building-frr-for-centos7
|
||||||
building-frr-for-debian8
|
building-frr-for-debian8
|
||||||
building-frr-for-debian9
|
building-frr-for-debian9
|
||||||
building-frr-for-fedora24
|
building-frr-for-fedora
|
||||||
building-frr-for-freebsd10
|
building-frr-for-freebsd10
|
||||||
building-frr-for-freebsd11
|
building-frr-for-freebsd11
|
||||||
building-frr-for-freebsd9
|
building-frr-for-freebsd9
|
||||||
|
@ -131,7 +131,7 @@ language = None
|
|||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# 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
|
# The reST default role (used for this markup: `text`) to use for all
|
||||||
# documents.
|
# documents.
|
||||||
|
@ -6,7 +6,7 @@ Hooks
|
|||||||
Libfrr provides type-safe subscribable hook points where other pieces of
|
Libfrr provides type-safe subscribable hook points where other pieces of
|
||||||
code can add one or more callback functions. "type-safe" in this case
|
code can add one or more callback functions. "type-safe" in this case
|
||||||
applies to the function pointers used for subscriptions. The
|
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.
|
the appropriate function signature (parameters) for the hook.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
37
doc/developer/include-compile.rst
Normal file
37
doc/developer/include-compile.rst
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
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
|
@ -18,7 +18,7 @@ maybe by a syslog collector from all routers.) Therefore, anything that
|
|||||||
needs to get the user in the loop—and only these things—are warnings or
|
needs to get the user in the loop—and only these things—are warnings or
|
||||||
errors.
|
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
|
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
|
fixing, for example another router, the system we're running on, or the
|
||||||
configuration. The common point is that the user should probably do
|
configuration. The common point is that the user should probably do
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
Memtypes
|
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``.
|
of objects currently allocated, for each of a defined ``MTYPE``.
|
||||||
|
|
||||||
To this extent, there are *memory groups* and *memory types*. Each memory
|
To this extent, there are *memory groups* and *memory types*. Each memory
|
||||||
|
@ -284,7 +284,7 @@ Each message begins with the following header:
|
|||||||
The message type field can take one of the following values:
|
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 |
|
| MSG\_REGISTER\_OPAQUETYPE | 1 |
|
||||||
+-------------------------------+---------+
|
+-------------------------------+---------+
|
||||||
@ -300,7 +300,7 @@ The message type field can take one of the following values:
|
|||||||
+-------------------------------+---------+
|
+-------------------------------+---------+
|
||||||
|
|
||||||
+-----------------------------+---------+
|
+-----------------------------+---------+
|
||||||
| Messages from OSPF deamon | Value |
|
| Messages from OSPF daemon | Value |
|
||||||
+=============================+=========+
|
+=============================+=========+
|
||||||
| MSG\_REPLY | 10 |
|
| MSG\_REPLY | 10 |
|
||||||
+-----------------------------+---------+
|
+-----------------------------+---------+
|
||||||
|
@ -31,7 +31,7 @@ Implementation details
|
|||||||
Concepts
|
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:
|
information:
|
||||||
|
|
||||||
* **Router Information:** flood the Segment Routing capabilities of the node.
|
* **Router Information:** flood the Segment Routing capabilities of the node.
|
||||||
@ -40,7 +40,7 @@ information:
|
|||||||
* **Extended Link:** flood the Adjaceny and Lan Adjacency Segment Identifier
|
* **Extended Link:** flood the Adjaceny and Lan Adjacency Segment Identifier
|
||||||
* **Extended Prefix:** flood the Prefix 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
|
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
|
latter is mandatory for the implementation as it provides the Callback to
|
||||||
Segment Routing functions (see below) when an Extended Link / Prefix or Router
|
Segment Routing functions (see below) when an Extended Link / Prefix or Router
|
||||||
@ -71,7 +71,7 @@ The figure below shows the relation between the various files:
|
|||||||
(4.0.0.0), Extended Prefix (7.0.0.X) and Link (8.0.0.X) by ospf_ri.c,
|
(4.0.0.0), Extended Prefix (7.0.0.X) and Link (8.0.0.X) by ospf_ri.c,
|
||||||
respectively ospf_ext.c.
|
respectively ospf_ext.c.
|
||||||
* ospf_ri.c send back to ospf_sr.c received Router Information LSA and update
|
* 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.
|
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
|
* 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
|
LSA and send self Extended Prefix and Link Opaque LSA through ospf_opaque.c
|
||||||
@ -129,8 +129,8 @@ Opaque LSA it is the `ospf_opaque_lsa_install_hook()`. For deletion, it is
|
|||||||
Note that incoming LSA which is already present in the LSDB will be inserted
|
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
|
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
|
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
|
is not very helpful 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
|
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,
|
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
|
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
|
an installation or a future deletion i.e. the flushed LSA is first store in the
|
||||||
@ -144,7 +144,7 @@ introduced. When this command is activated, function
|
|||||||
`ospf_router_info_update_sr()` is called to indicate to Router Information
|
`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
|
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)
|
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.
|
to modify this TLV is offer by the code.
|
||||||
|
|
||||||
When Opaque LSA Tyep 4 i.e. Router Information are stored in LSDB, function
|
When Opaque LSA Tyep 4 i.e. Router Information are stored in LSDB, function
|
||||||
@ -159,8 +159,8 @@ Extended Link Prefix LSAs
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Like for Router Information, Segment Routing is activate at the Extended
|
Like for Router Information, Segment Routing is activate at the Extended
|
||||||
Link/Prefix level with new `segment-routing on` command. This trigger
|
Link/Prefix level with new `segment-routing on` command. This triggers
|
||||||
automtically the flooding of Extended Link LSA for all ospf interface where
|
automatically the flooding of Extended Link LSA for all ospf interfaces where
|
||||||
adjacency is full. For Extended Prefix LSA, the new CLI command
|
adjacency is full. For Extended Prefix LSA, the new CLI command
|
||||||
`segment-routing prefix ...` will trigger the flooding of Prefix SID
|
`segment-routing prefix ...` will trigger the flooding of Prefix SID
|
||||||
TLV/SubTLVs.
|
TLV/SubTLVs.
|
||||||
@ -255,7 +255,7 @@ The first segment-routing statement enable it. The Second one set the SRGB,
|
|||||||
third line the MSD and finally, set the Prefix SID index for a given prefix.
|
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
|
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
|
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.
|
the MPLS label prior to sending the packet.
|
||||||
|
|
||||||
Known limitations
|
Known limitations
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
.. _packaging-debian:
|
||||||
|
|
||||||
Packaging Debian
|
Packaging Debian
|
||||||
================
|
================
|
||||||
|
|
||||||
|
85
doc/developer/packaging-redhat.rst
Normal file
85
doc/developer/packaging-redhat.rst
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
.. _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`.
|
@ -7,3 +7,4 @@ Packaging
|
|||||||
|
|
||||||
maintainer-release-build
|
maintainer-release-build
|
||||||
packaging-debian
|
packaging-debian
|
||||||
|
packaging-redhat
|
||||||
|
@ -5,13 +5,12 @@
|
|||||||
dev_RSTFILES = \
|
dev_RSTFILES = \
|
||||||
doc/developer/bgp-typecodes.rst \
|
doc/developer/bgp-typecodes.rst \
|
||||||
doc/developer/bgpd.rst \
|
doc/developer/bgpd.rst \
|
||||||
doc/developer/building-frr-for-openwrt.rst \
|
|
||||||
doc/developer/building-frr-for-alpine.rst \
|
doc/developer/building-frr-for-alpine.rst \
|
||||||
doc/developer/building-frr-for-centos6.rst \
|
doc/developer/building-frr-for-centos6.rst \
|
||||||
doc/developer/building-frr-for-centos7.rst \
|
doc/developer/building-frr-for-centos7.rst \
|
||||||
doc/developer/building-frr-for-debian8.rst \
|
doc/developer/building-frr-for-debian8.rst \
|
||||||
doc/developer/building-frr-for-debian9.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-freebsd10.rst \
|
||||||
doc/developer/building-frr-for-freebsd11.rst \
|
doc/developer/building-frr-for-freebsd11.rst \
|
||||||
doc/developer/building-frr-for-freebsd9.rst \
|
doc/developer/building-frr-for-freebsd9.rst \
|
||||||
@ -19,6 +18,7 @@ dev_RSTFILES = \
|
|||||||
doc/developer/building-frr-for-netbsd7.rst \
|
doc/developer/building-frr-for-netbsd7.rst \
|
||||||
doc/developer/building-frr-for-omnios.rst \
|
doc/developer/building-frr-for-omnios.rst \
|
||||||
doc/developer/building-frr-for-openbsd6.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-ubuntu1404.rst \
|
||||||
doc/developer/building-frr-for-ubuntu1604.rst \
|
doc/developer/building-frr-for-ubuntu1604.rst \
|
||||||
doc/developer/building-frr-for-ubuntu1804.rst \
|
doc/developer/building-frr-for-ubuntu1804.rst \
|
||||||
@ -27,6 +27,7 @@ dev_RSTFILES = \
|
|||||||
doc/developer/cli.rst \
|
doc/developer/cli.rst \
|
||||||
doc/developer/conf.py \
|
doc/developer/conf.py \
|
||||||
doc/developer/hooks.rst \
|
doc/developer/hooks.rst \
|
||||||
|
doc/developer/include-compile.rst \
|
||||||
doc/developer/index.rst \
|
doc/developer/index.rst \
|
||||||
doc/developer/library.rst \
|
doc/developer/library.rst \
|
||||||
doc/developer/logging.rst \
|
doc/developer/logging.rst \
|
||||||
@ -37,8 +38,9 @@ dev_RSTFILES = \
|
|||||||
doc/developer/ospf-api.rst \
|
doc/developer/ospf-api.rst \
|
||||||
doc/developer/ospf-sr.rst \
|
doc/developer/ospf-sr.rst \
|
||||||
doc/developer/ospf.rst \
|
doc/developer/ospf.rst \
|
||||||
doc/developer/packaging.rst \
|
|
||||||
doc/developer/packaging-debian.rst \
|
doc/developer/packaging-debian.rst \
|
||||||
|
doc/developer/packaging-redhat.rst
|
||||||
|
doc/developer/packaging.rst \
|
||||||
doc/developer/testing.rst \
|
doc/developer/testing.rst \
|
||||||
doc/developer/topotests-snippets.rst \
|
doc/developer/topotests-snippets.rst \
|
||||||
doc/developer/topotests.rst \
|
doc/developer/topotests.rst \
|
||||||
|
@ -48,17 +48,17 @@ A sample of this snippet in a test can be found `here
|
|||||||
Interacting with equipment
|
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.
|
there are different ways to do so.
|
||||||
|
|
||||||
Notes:
|
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
|
(`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
|
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.
|
to spawn commands.
|
||||||
|
|
||||||
Interacting with the Linux sandbox
|
Interacting with the Linux sandbox
|
||||||
@ -149,7 +149,7 @@ Translating vtysh JSON output into Python structures:
|
|||||||
|
|
||||||
.. note::
|
.. 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
|
Invoking mininet CLI
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -195,7 +195,7 @@ Loading JSON from a file:
|
|||||||
Comparing JSON output
|
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:
|
it to assert a minimalist schema:
|
||||||
|
|
||||||
.. code:: py
|
.. code:: py
|
||||||
|
@ -151,7 +151,7 @@ Collect Memory Leak Information
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
FRR processes have the capabilities to report remaining memory allocations upon
|
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.::
|
``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.::
|
||||||
|
|
||||||
export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
|
export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
|
||||||
@ -410,7 +410,7 @@ Defining the Topology
|
|||||||
The first step to write a new test is to define the topology. This step can be
|
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
|
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
|
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
|
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
|
:file:`tests/topotests/example-test/test_template.dot` (the inlined code might
|
||||||
|
@ -43,7 +43,7 @@ simplifying the output. This is discussed in :ref:`vtysh-configuration`.
|
|||||||
Command Extraction
|
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
|
codebase looking for ``DEFUN``'s. It extracts these ``DEFUN``'s, transforms
|
||||||
them into ``DEFSH``'s and appends them to ``vtysh_cmd.c``. Each ``DEFSH``
|
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
|
contains the name of the command plus ``_vtysh``, as well as a flag that
|
||||||
@ -167,7 +167,7 @@ Protocol
|
|||||||
VTYSH communicates with FRR daemons by way of domain socket. Each daemon
|
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
|
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
|
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:
|
message from VTYSH to a daemon:
|
||||||
|
|
||||||
::
|
::
|
||||||
@ -178,7 +178,7 @@ message from VTYSH to a daemon:
|
|||||||
00000010: 6c0a 00 l..
|
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
|
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
|
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
|
is followed by 3 null marker bytes, followed by a 1-byte status code that
|
||||||
|
@ -99,9 +99,14 @@ Bugfix releases are made as needed at 1 month intervals until the next
|
|||||||
``MAJOR.MINOR`` release branch is pulled. Depending on the severity of the bugs,
|
``MAJOR.MINOR`` release branch is pulled. Depending on the severity of the bugs,
|
||||||
bugfix releases may occur sooner.
|
bugfix releases may occur sooner.
|
||||||
|
|
||||||
Bugfixes are applied to the two most recent releases. Security fixes are
|
Bugfixes are applied to the two most recent releases. However, backporting of bug
|
||||||
backported to all releases less than or equal to at least one year old. Security
|
fixes to older than the two most recent releases will not be prevented, if acked
|
||||||
fixes may also be backported to older releases depending on severity.
|
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 )
|
Long term support branches ( LTS )
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
@ -371,7 +376,7 @@ system in which submissions from an individual representing one company should
|
|||||||
be merged by someone unaffiliated with that company.
|
be merged by someone unaffiliated with that company.
|
||||||
|
|
||||||
Guidelines for code review
|
Guidelines for code review
|
||||||
""""""""""""""""""""""""""
|
--------------------------
|
||||||
|
|
||||||
- As a rule of thumb, the depth of the review should be proportional to the
|
- As a rule of thumb, the depth of the review should be proportional to the
|
||||||
scope and / or impact of the patch.
|
scope and / or impact of the patch.
|
||||||
|
@ -129,7 +129,7 @@ language = None
|
|||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# 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
|
# The reST default role (used for this markup: `text`) to use for all
|
||||||
# documents.
|
# documents.
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
.. |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| 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]
|
.. |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)
|
||||||
|
@ -390,7 +390,7 @@ Terminal Mode Commands
|
|||||||
.. index:: find COMMAND...
|
.. index:: find COMMAND...
|
||||||
.. clicmd:: 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
|
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:
|
remember where the command to turn OSPF segment routing on is:
|
||||||
|
|
||||||
|
@ -511,8 +511,8 @@ cause may lead to routing instability or oscillation across multiple speakers
|
|||||||
in iBGP topologies. This can occur with full-mesh iBGP, but is particularly
|
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
|
problematic in non-full-mesh iBGP topologies that further reduce the routing
|
||||||
information known to each speaker. This has primarily been documented with iBGP
|
information known to each speaker. This has primarily been documented with iBGP
|
||||||
route-reflection topologies. However, any route-hiding technologies potentially
|
:ref:`route-reflection <bgp-route-reflector>` topologies. However, any
|
||||||
could also exacerbate oscillation with MED.
|
route-hiding technologies potentially could also exacerbate oscillation with MED.
|
||||||
|
|
||||||
This second issue occurs where speakers each have only a subset of routes, and
|
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 -
|
there are cycles in the preferences between different combinations of routes -
|
||||||
@ -1145,7 +1145,7 @@ is 4 octet long. The following format is used to define the community value.
|
|||||||
``graceful-shutdown`` represents well-known communities value
|
``graceful-shutdown`` represents well-known communities value
|
||||||
``GRACEFUL_SHUTDOWN`` ``0xFFFF0000`` ``65535:0``. :rfc:`8326` implements
|
``GRACEFUL_SHUTDOWN`` ``0xFFFF0000`` ``65535:0``. :rfc:`8326` implements
|
||||||
the purpose Graceful BGP Session Shutdown to reduce the amount of
|
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
|
of the community needs to be supported from your peers side to
|
||||||
actually have any effect.
|
actually have any effect.
|
||||||
|
|
||||||
@ -1176,20 +1176,20 @@ is 4 octet long. The following format is used to define the community value.
|
|||||||
``llgr-stale``
|
``llgr-stale``
|
||||||
``llgr-stale`` represents well-known communities value ``LLGR_STALE``
|
``llgr-stale`` represents well-known communities value ``LLGR_STALE``
|
||||||
``0xFFFF0006`` ``65535:6``.
|
``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
|
Long-lived Graceful Restart Capability as described in
|
||||||
[Draft-IETF-uttaro-idr-bgp-persistence]_.
|
[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
|
implementation) choose allow to reject or modify routes on the
|
||||||
presence or absence of this community.
|
presence or absence of this community.
|
||||||
|
|
||||||
``no-llgr``
|
``no-llgr``
|
||||||
``no-llgr`` represents well-known communities value ``NO_LLGR``
|
``no-llgr`` represents well-known communities value ``NO_LLGR``
|
||||||
``0xFFFF0007`` ``65535:7``.
|
``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
|
Long-lived Graceful Restart Capability as described in
|
||||||
[Draft-IETF-uttaro-idr-bgp-persistence]_.
|
[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
|
implementation) choose allow to reject or modify routes on the
|
||||||
presence or absence of this community.
|
presence or absence of this community.
|
||||||
|
|
||||||
@ -1251,7 +1251,7 @@ UPDATE messages.
|
|||||||
There are two types of community list:
|
There are two types of community list:
|
||||||
|
|
||||||
standard
|
standard
|
||||||
This type accepts an explicit value for the atttribute.
|
This type accepts an explicit value for the attribute.
|
||||||
|
|
||||||
expanded
|
expanded
|
||||||
This type accepts a regular expression. Because the regex must be
|
This type accepts a regular expression. Because the regex must be
|
||||||
@ -2240,10 +2240,15 @@ Displaying Routes by AS Path
|
|||||||
Route Reflector
|
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
|
When route reflectors are configured, these will reflect the routes announced
|
||||||
.. clicmd:: bgp cluster-id A.B.C.D
|
by the peers configured as clients. A route reflector client is configured
|
||||||
|
with:
|
||||||
|
|
||||||
.. index:: neighbor PEER route-reflector-client
|
.. index:: neighbor PEER route-reflector-client
|
||||||
.. clicmd:: neighbor PEER route-reflector-client
|
.. clicmd:: neighbor PEER route-reflector-client
|
||||||
@ -2251,6 +2256,13 @@ Route Reflector
|
|||||||
.. index:: no neighbor PEER route-reflector-client
|
.. index:: no neighbor PEER route-reflector-client
|
||||||
.. clicmd:: 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:
|
.. _routing-policy:
|
||||||
|
|
||||||
@ -2469,7 +2481,7 @@ certainly contains silly mistakes, if not serious flaws.
|
|||||||
route-map rm-no-export permit 20
|
route-map rm-no-export permit 20
|
||||||
!
|
!
|
||||||
route-map rm-blackhole permit 10
|
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 ip next-hop 127.0.0.1
|
||||||
set local-preference 10
|
set local-preference 10
|
||||||
set community additive no-export
|
set community additive no-export
|
||||||
|
@ -167,7 +167,7 @@ set. That VRF will then be selected. The below full configuration example
|
|||||||
depicts how Route Targets are configured and how VRFs and cross VRF
|
depicts how Route Targets are configured and how VRFs and cross VRF
|
||||||
configuration is done. Note that the VRF are mapped on Linux Network
|
configuration is done. Note that the VRF are mapped on Linux Network
|
||||||
Namespaces. For data traffic to cross VRF boundaries, virtual ethernet
|
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
|
.. code-block:: frr
|
||||||
|
|
||||||
@ -322,7 +322,7 @@ There are some other known issues:
|
|||||||
- The validation procedure depicted in :rfc:`5575` is not available.
|
- The validation procedure depicted in :rfc:`5575` is not available.
|
||||||
|
|
||||||
This validation procedure has not been implemented, as this feature was not
|
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.
|
- The filtering action shaper value, if positive, is not used to apply shaping.
|
||||||
|
|
||||||
|
@ -272,10 +272,11 @@ options from the list below.
|
|||||||
.. option:: --enable-multipath=X
|
.. option:: --enable-multipath=X
|
||||||
|
|
||||||
Compile FRR with up to X way ECMP supported. This number can be from 0-999.
|
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
|
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
|
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
|
.. option:: --enable-shell-access
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ To start OSPF process you have to specify the OSPF router.
|
|||||||
SPF-triggering event occurs within the hold-time of the previous SPF
|
SPF-triggering event occurs within the hold-time of the previous SPF
|
||||||
calculation.
|
calculation.
|
||||||
|
|
||||||
This command supercedes the *timers spf* command in previous FRR
|
This command supersedes the *timers spf* command in previous FRR
|
||||||
releases.
|
releases.
|
||||||
|
|
||||||
.. index:: max-metric router-lsa [on-startup|on-shutdown] (5-86400)
|
.. index:: max-metric router-lsa [on-startup|on-shutdown] (5-86400)
|
||||||
|
@ -88,7 +88,7 @@ end destination.
|
|||||||
|
|
||||||
When a incoming packet matches the destination prefix specified, take the
|
When a incoming packet matches the destination prefix specified, take the
|
||||||
packet and forward according to the nexthops specified. This command accepts
|
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:`match src-ip PREFIX` command for matching.
|
||||||
|
|
||||||
.. clicmd:: set nexthop-group NAME
|
.. clicmd:: set nexthop-group NAME
|
||||||
|
@ -210,8 +210,8 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
|
|||||||
|
|
||||||
Set the IGMP version used on this interface. The default value is 3.
|
Set the IGMP version used on this interface. The default value is 3.
|
||||||
|
|
||||||
.. index:: ip multicat boundary oil WORD
|
.. index:: ip multicast boundary oil WORD
|
||||||
.. clicmd:: ip multicat boundary oil WORD
|
.. clicmd:: ip multicast boundary oil WORD
|
||||||
|
|
||||||
Set a pim multicast boundary, based upon the WORD prefix-list. If a pim join
|
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
|
or IGMP report is received on this interface and the Group is denied by the
|
||||||
|
@ -29,7 +29,7 @@ documented elsewhere.
|
|||||||
Using SHARP
|
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.
|
keyword. At present, no sharp commands will be preserved in the config.
|
||||||
|
|
||||||
.. index:: sharp install
|
.. index:: sharp install
|
||||||
|
@ -380,7 +380,7 @@ At startup, FRR detects the presence of that file. It detects that the file
|
|||||||
statistics information matches the same file statistics information as
|
statistics information matches the same file statistics information as
|
||||||
`/proc/self/ns/net` ( through stat() function). As statistics information
|
`/proc/self/ns/net` ( through stat() function). As statistics information
|
||||||
matches, then `vrf0` stands for the new default namespace name.
|
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`.
|
namespace name `vrf0`.
|
||||||
|
|
||||||
For those who don't use VRF backend with *Linux network namespace*, it is
|
For those who don't use VRF backend with *Linux network namespace*, it is
|
||||||
@ -422,7 +422,7 @@ in routing entry, and can be configured like a route:
|
|||||||
.. index:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
|
.. index:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
|
||||||
.. clicmd:: [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.
|
route entry.
|
||||||
GATEWAY is the gateway IP address to reach, in order to reach the prefix.
|
GATEWAY is the gateway IP address to reach, in order to reach the prefix.
|
||||||
INTERFACE is the interface behind which the prefix is located.
|
INTERFACE is the interface behind which the prefix is located.
|
||||||
|
@ -1,35 +1,58 @@
|
|||||||
FROM alpine:3.7 as source-builder
|
# This stage builds a dist tarball from the source
|
||||||
ARG commit
|
FROM alpine:edge as source-builder
|
||||||
RUN apk add --no-cache abuild acct alpine-sdk attr autoconf automake bash \
|
|
||||||
binutils binutils-libs bison bsd-compat-headers build-base \
|
RUN mkdir -p /src/alpine
|
||||||
c-ares c-ares-dev ca-certificates cryptsetup-libs curl \
|
COPY alpine/APKBUILD.in /src/alpine
|
||||||
device-mapper-libs expat fakeroot flex fortify-headers g++ gcc gdbm \
|
RUN source /src/alpine/APKBUILD.in \
|
||||||
git gmp isl json-c json-c-dev kmod lddtree libacl libatomic libattr \
|
&& echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
|
||||||
libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc \
|
&& apk add \
|
||||||
libgomp libisoburn libisofs libltdl libressl libssh2 \
|
--no-cache \
|
||||||
libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1 \
|
--update-cache \
|
||||||
mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base \
|
$makedepends \
|
||||||
patch pax-utils pcre perl pkgconf python2 python2-dev readline \
|
gzip
|
||||||
readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs \
|
|
||||||
groff gzip bc py-sphinx
|
COPY . /src
|
||||||
ADD . /src
|
ARG PKGVER
|
||||||
RUN (cd /src && \
|
RUN cd /src \
|
||||||
./bootstrap.sh && \
|
&& ./bootstrap.sh \
|
||||||
./configure \
|
&& ./configure \
|
||||||
--enable-numeric-version \
|
--enable-numeric-version \
|
||||||
--with-pkg-extra-version=_git$commit && \
|
--with-pkg-extra-version="_git$PKGVER" \
|
||||||
make dist)
|
&& make dist
|
||||||
FROM alpine:3.7 as alpine-builder
|
|
||||||
RUN apk add --no-cache abuild alpine-sdk && mkdir -p /pkgs/apk
|
# This stage builds an apk from the dist tarball
|
||||||
ADD docker/alpine/alpine-build.sh /usr/bin/
|
FROM alpine:edge as alpine-builder
|
||||||
ADD docker/alpine/builder /etc/sudoers.d
|
# Don't use nocache here so that abuild can use the cache
|
||||||
COPY --from=source-builder /src/*.tar.gz /src/alpine/* /src/tools/etc/frr/daemons* /dist/
|
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
|
RUN adduser -D -G abuild builder && chown -R builder /dist /pkgs
|
||||||
USER builder
|
USER builder
|
||||||
RUN /usr/bin/alpine-build.sh
|
RUN cd /dist \
|
||||||
FROM alpine:3.7
|
&& 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
|
RUN mkdir -p /pkgs/apk
|
||||||
COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/
|
COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/
|
||||||
RUN apk add --no-cache tini
|
RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
|
||||||
RUN apk add --no-cache --allow-untrusted /pkgs/apk/x86_64/*.apk
|
&& 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" ]
|
ENTRYPOINT [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ]
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
#!/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
|
|
@ -1,17 +1,30 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
set -v
|
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
##
|
##
|
||||||
# commit must be converted to decimal
|
# Package version needs to be decimal
|
||||||
##
|
##
|
||||||
c=`git rev-parse --short=10 HEAD`
|
GITREV="$(git rev-parse --short=10 HEAD)"
|
||||||
commit=`printf '%u\n' 0x$c`
|
PKGVER="$(printf '%u\n' 0x$GITREV)"
|
||||||
docker build -f docker/alpine/Dockerfile \
|
|
||||||
--build-arg commit=$commit -t frr:alpine-$c .
|
docker build \
|
||||||
id=`docker create frr:alpine-$c`
|
--pull \
|
||||||
docker cp ${id}:/pkgs/ docker
|
--file=docker/alpine/Dockerfile \
|
||||||
docker rm $id
|
--build-arg="PKGVER=$PKGVER" \
|
||||||
docker rmi frr:alpine-$c
|
--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"
|
||||||
|
@ -1 +0,0 @@
|
|||||||
builder ALL=(ALL) NOPASSWD:ALL
|
|
@ -6,5 +6,7 @@ set -e
|
|||||||
# For volume mounts...
|
# For volume mounts...
|
||||||
##
|
##
|
||||||
chown -R frr:frr /etc/frr
|
chown -R frr:frr /etc/frr
|
||||||
/etc/init.d/frr start
|
/usr/lib/frr/frrinit.sh start
|
||||||
exec sleep 10000d
|
|
||||||
|
# Sleep forever
|
||||||
|
exec tail -f /dev/null
|
@ -314,7 +314,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
|
|||||||
if (prefix->rij->count)
|
if (prefix->rij->count)
|
||||||
return EIGRP_FSM_KEEP_STATE;
|
return EIGRP_FSM_KEEP_STATE;
|
||||||
|
|
||||||
zlog_info("All reply received\n");
|
zlog_info("All reply received");
|
||||||
if (head->reported_distance < prefix->fdistance) {
|
if (head->reported_distance < prefix->fdistance) {
|
||||||
return EIGRP_FSM_EVENT_LR_FCS;
|
return EIGRP_FSM_EVENT_LR_FCS;
|
||||||
}
|
}
|
||||||
@ -344,7 +344,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
|
|||||||
} else if (prefix->rij->count) {
|
} else if (prefix->rij->count) {
|
||||||
return EIGRP_FSM_KEEP_STATE;
|
return EIGRP_FSM_KEEP_STATE;
|
||||||
} else {
|
} else {
|
||||||
zlog_info("All reply received\n");
|
zlog_info("All reply received");
|
||||||
return EIGRP_FSM_EVENT_LR;
|
return EIGRP_FSM_EVENT_LR;
|
||||||
}
|
}
|
||||||
} else if (msg->packet_type == EIGRP_OPC_UPDATE
|
} else if (msg->packet_type == EIGRP_OPC_UPDATE
|
||||||
@ -366,7 +366,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
|
|||||||
if (prefix->rij->count) {
|
if (prefix->rij->count) {
|
||||||
return EIGRP_FSM_KEEP_STATE;
|
return EIGRP_FSM_KEEP_STATE;
|
||||||
} else {
|
} else {
|
||||||
zlog_info("All reply received\n");
|
zlog_info("All reply received");
|
||||||
if (head->reported_distance
|
if (head->reported_distance
|
||||||
< prefix->fdistance) {
|
< prefix->fdistance) {
|
||||||
return EIGRP_FSM_EVENT_LR_FCS;
|
return EIGRP_FSM_EVENT_LR_FCS;
|
||||||
@ -390,7 +390,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
|
|||||||
} else if (prefix->rij->count) {
|
} else if (prefix->rij->count) {
|
||||||
return EIGRP_FSM_KEEP_STATE;
|
return EIGRP_FSM_KEEP_STATE;
|
||||||
} else {
|
} else {
|
||||||
zlog_info("All reply received\n");
|
zlog_info("All reply received");
|
||||||
return EIGRP_FSM_EVENT_LR;
|
return EIGRP_FSM_EVENT_LR;
|
||||||
}
|
}
|
||||||
} else if (msg->packet_type == EIGRP_OPC_UPDATE
|
} else if (msg->packet_type == EIGRP_OPC_UPDATE
|
||||||
|
@ -131,7 +131,7 @@ static int process_p2p_hello(struct iih_info *iih)
|
|||||||
if (tw_adj) {
|
if (tw_adj) {
|
||||||
if (tw_adj->state > ISIS_THREEWAY_DOWN) {
|
if (tw_adj->state > ISIS_THREEWAY_DOWN) {
|
||||||
if (isis->debugs & DEBUG_ADJ_PACKETS) {
|
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->area->area_tag,
|
||||||
iih->circuit->interface->name,
|
iih->circuit->interface->name,
|
||||||
tw_adj->state);
|
tw_adj->state);
|
||||||
@ -144,7 +144,7 @@ static int process_p2p_hello(struct iih_info *iih)
|
|||||||
|| tw_adj->neighbor_circuit_id != (uint32_t) iih->circuit->idx)) {
|
|| tw_adj->neighbor_circuit_id != (uint32_t) iih->circuit->idx)) {
|
||||||
|
|
||||||
if (isis->debugs & DEBUG_ADJ_PACKETS) {
|
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->area->area_tag,
|
||||||
iih->circuit->interface->name);
|
iih->circuit->interface->name);
|
||||||
}
|
}
|
||||||
@ -1523,7 +1523,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fabricd_initial_sync_is_complete(circuit->area) && resync_needed)
|
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;
|
retval = ISIS_OK;
|
||||||
out:
|
out:
|
||||||
|
@ -362,6 +362,10 @@ static int isis_zebra_read(int command, struct zclient *zclient,
|
|||||||
if (zapi_route_decode(zclient->ibuf, &api) < 0)
|
if (zapi_route_decode(zclient->ibuf, &api) < 0)
|
||||||
return -1;
|
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
|
* Avoid advertising a false default reachability. (A default
|
||||||
* route installed by IS-IS gets redistributed from zebra back
|
* route installed by IS-IS gets redistributed from zebra back
|
||||||
|
6
lib/if.c
6
lib/if.c
@ -396,6 +396,7 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id)
|
|||||||
struct interface *ifp;
|
struct interface *ifp;
|
||||||
|
|
||||||
switch (vrf_get_backend()) {
|
switch (vrf_get_backend()) {
|
||||||
|
case VRF_BACKEND_UNKNOWN:
|
||||||
case VRF_BACKEND_NETNS:
|
case VRF_BACKEND_NETNS:
|
||||||
ifp = if_lookup_by_name(name, vrf_id);
|
ifp = if_lookup_by_name(name, vrf_id);
|
||||||
if (ifp)
|
if (ifp)
|
||||||
@ -1279,6 +1280,11 @@ static int lib_interface_create(enum nb_event event,
|
|||||||
vrf->name);
|
vrf->name);
|
||||||
return NB_ERR_VALIDATION;
|
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) {
|
if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) {
|
||||||
ifp = if_lookup_by_name_all_vrf(ifname);
|
ifp = if_lookup_by_name_all_vrf(ifname);
|
||||||
if (ifp && ifp->vrf_id != vrf->vrf_id) {
|
if (ifp && ifp->vrf_id != vrf->vrf_id) {
|
||||||
|
10
lib/log.c
10
lib/log.c
@ -991,6 +991,7 @@ static const struct zebra_desc_table command_types[] = {
|
|||||||
DESC_ENTRY(ZEBRA_ROUTER_ID_DELETE),
|
DESC_ENTRY(ZEBRA_ROUTER_ID_DELETE),
|
||||||
DESC_ENTRY(ZEBRA_ROUTER_ID_UPDATE),
|
DESC_ENTRY(ZEBRA_ROUTER_ID_UPDATE),
|
||||||
DESC_ENTRY(ZEBRA_HELLO),
|
DESC_ENTRY(ZEBRA_HELLO),
|
||||||
|
DESC_ENTRY(ZEBRA_CAPABILITIES),
|
||||||
DESC_ENTRY(ZEBRA_NEXTHOP_REGISTER),
|
DESC_ENTRY(ZEBRA_NEXTHOP_REGISTER),
|
||||||
DESC_ENTRY(ZEBRA_NEXTHOP_UNREGISTER),
|
DESC_ENTRY(ZEBRA_NEXTHOP_UNREGISTER),
|
||||||
DESC_ENTRY(ZEBRA_NEXTHOP_UPDATE),
|
DESC_ENTRY(ZEBRA_NEXTHOP_UPDATE),
|
||||||
@ -1012,6 +1013,7 @@ static const struct zebra_desc_table command_types[] = {
|
|||||||
DESC_ENTRY(ZEBRA_VRF_LABEL),
|
DESC_ENTRY(ZEBRA_VRF_LABEL),
|
||||||
DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE),
|
DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE),
|
||||||
DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER),
|
DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER),
|
||||||
|
DESC_ENTRY(ZEBRA_BFD_CLIENT_DEREGISTER),
|
||||||
DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV),
|
DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV),
|
||||||
DESC_ENTRY(ZEBRA_INTERFACE_DISABLE_RADV),
|
DESC_ENTRY(ZEBRA_INTERFACE_DISABLE_RADV),
|
||||||
DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB),
|
DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB),
|
||||||
@ -1023,6 +1025,9 @@ static const struct zebra_desc_table command_types[] = {
|
|||||||
DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC),
|
DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC),
|
||||||
DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK),
|
DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK),
|
||||||
DESC_ENTRY(ZEBRA_RELEASE_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_ALL_VNI),
|
||||||
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
|
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
|
||||||
DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP),
|
DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP),
|
||||||
@ -1057,6 +1062,11 @@ static const struct zebra_desc_table command_types[] = {
|
|||||||
DESC_ENTRY(ZEBRA_IPSET_DESTROY),
|
DESC_ENTRY(ZEBRA_IPSET_DESTROY),
|
||||||
DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD),
|
DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD),
|
||||||
DESC_ENTRY(ZEBRA_IPSET_ENTRY_DELETE),
|
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),
|
DESC_ENTRY(ZEBRA_VXLAN_FLOOD_CONTROL),
|
||||||
};
|
};
|
||||||
#undef DESC_ENTRY
|
#undef DESC_ENTRY
|
||||||
|
@ -188,11 +188,25 @@ static int nhgc_cmp_helper(const char *a, const char *b)
|
|||||||
return strcmp(a, b);
|
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)
|
static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = sockunion_cmp(&nh1->addr, &nh2->addr);
|
ret = nhgc_addr_cmp_helper(nh1->addr, nh2->addr);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -209,6 +223,9 @@ static void nhgl_delete(struct nexthop_hold *nh)
|
|||||||
|
|
||||||
XFREE(MTYPE_TMP, nh->nhvrf_name);
|
XFREE(MTYPE_TMP, nh->nhvrf_name);
|
||||||
|
|
||||||
|
if (nh->addr)
|
||||||
|
sockunion_free(nh->addr);
|
||||||
|
|
||||||
XFREE(MTYPE_TMP, nh);
|
XFREE(MTYPE_TMP, nh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,8 +309,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
|
|||||||
nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name);
|
nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name);
|
||||||
if (intf)
|
if (intf)
|
||||||
nh->intf = XSTRDUP(MTYPE_TMP, intf);
|
nh->intf = XSTRDUP(MTYPE_TMP, intf);
|
||||||
|
if (addr)
|
||||||
nh->addr = *addr;
|
nh->addr = sockunion_dup(addr);
|
||||||
|
|
||||||
listnode_add_sort(nhgc->nhg_list, nh);
|
listnode_add_sort(nhgc->nhg_list, nh);
|
||||||
}
|
}
|
||||||
@ -308,7 +325,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
|
|||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
|
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
|
||||||
if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&
|
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)
|
nhgc_cmp_helper(intf, nh->intf) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -320,13 +337,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
list_delete_node(nhgc->nhg_list, node);
|
list_delete_node(nhgc->nhg_list, node);
|
||||||
|
nhgl_delete(nh);
|
||||||
if (nh->nhvrf_name)
|
|
||||||
XFREE(MTYPE_TMP, nh->nhvrf_name);
|
|
||||||
if (nh->intf)
|
|
||||||
XFREE(MTYPE_TMP, nh->intf);
|
|
||||||
|
|
||||||
XFREE(MTYPE_TMP, nh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
|
static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
|
||||||
@ -347,36 +358,45 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
|
|||||||
|
|
||||||
nhop->vrf_id = vrf->vrf_id;
|
nhop->vrf_id = vrf->vrf_id;
|
||||||
|
|
||||||
|
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) {
|
if (addr->sa.sa_family == AF_INET) {
|
||||||
nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
|
nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
|
||||||
if (intf) {
|
if (intf)
|
||||||
nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
||||||
nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
else
|
||||||
if (nhop->ifindex == IFINDEX_INTERNAL)
|
|
||||||
return false;
|
|
||||||
} else
|
|
||||||
nhop->type = NEXTHOP_TYPE_IPV4;
|
nhop->type = NEXTHOP_TYPE_IPV4;
|
||||||
} else {
|
} else {
|
||||||
memcpy(&nhop->gate.ipv6, &addr->sin6.sin6_addr, 16);
|
nhop->gate.ipv6 = addr->sin6.sin6_addr;
|
||||||
if (intf) {
|
if (intf)
|
||||||
nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
||||||
nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
else
|
||||||
if (nhop->ifindex == IFINDEX_INTERNAL)
|
|
||||||
return false;
|
|
||||||
} else
|
|
||||||
nhop->type = NEXTHOP_TYPE_IPV6;
|
nhop->type = NEXTHOP_TYPE_IPV6;
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
|
nhop->type = NEXTHOP_TYPE_IFINDEX;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
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
|
NO_STR
|
||||||
"Specify one of the nexthops in this ECMP group\n"
|
"Specify one of the nexthops in this ECMP group\n"
|
||||||
"v4 Address\n"
|
"v4 Address\n"
|
||||||
"v6 Address\n"
|
"v6 Address\n"
|
||||||
"Interface to use\n"
|
"Interface to use\n"
|
||||||
|
"Interface to use\n"
|
||||||
"If the nexthop is in a different vrf tell us\n"
|
"If the nexthop is in a different vrf tell us\n"
|
||||||
"The nexthop-vrf Name\n")
|
"The nexthop-vrf Name\n")
|
||||||
{
|
{
|
||||||
@ -385,13 +405,6 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
|||||||
struct nexthop *nh;
|
struct nexthop *nh;
|
||||||
bool legal;
|
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);
|
legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name);
|
||||||
|
|
||||||
if (nhop.type == NEXTHOP_TYPE_IPV6
|
if (nhop.type == NEXTHOP_TYPE_IPV6
|
||||||
@ -482,7 +495,8 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
|
|||||||
|
|
||||||
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)
|
if (nh->intf)
|
||||||
vty_out(vty, " %s", nh->intf);
|
vty_out(vty, " %s", nh->intf);
|
||||||
@ -526,7 +540,7 @@ void nexthop_group_enable_vrf(struct vrf *vrf)
|
|||||||
struct nexthop nhop;
|
struct nexthop nhop;
|
||||||
struct nexthop *nh;
|
struct nexthop *nh;
|
||||||
|
|
||||||
if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
|
if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
|
||||||
nhh->intf,
|
nhh->intf,
|
||||||
nhh->nhvrf_name))
|
nhh->nhvrf_name))
|
||||||
continue;
|
continue;
|
||||||
@ -562,7 +576,7 @@ void nexthop_group_disable_vrf(struct vrf *vrf)
|
|||||||
struct nexthop nhop;
|
struct nexthop nhop;
|
||||||
struct nexthop *nh;
|
struct nexthop *nh;
|
||||||
|
|
||||||
if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
|
if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
|
||||||
nhh->intf,
|
nhh->intf,
|
||||||
nhh->nhvrf_name))
|
nhh->nhvrf_name))
|
||||||
continue;
|
continue;
|
||||||
@ -600,7 +614,7 @@ void nexthop_group_interface_state_change(struct interface *ifp,
|
|||||||
struct nexthop nhop;
|
struct nexthop nhop;
|
||||||
|
|
||||||
if (!nexthop_group_parse_nexthop(
|
if (!nexthop_group_parse_nexthop(
|
||||||
&nhop, &nhh->addr, nhh->intf,
|
&nhop, nhh->addr, nhh->intf,
|
||||||
nhh->nhvrf_name))
|
nhh->nhvrf_name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
|
|||||||
|
|
||||||
struct nexthop_hold {
|
struct nexthop_hold {
|
||||||
char *nhvrf_name;
|
char *nhvrf_name;
|
||||||
union sockunion addr;
|
union sockunion *addr;
|
||||||
char *intf;
|
char *intf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -348,41 +348,60 @@ static void nb_config_diff_del_changes(struct nb_config_cbs *changes)
|
|||||||
* configurations. Given a new subtree, calculate all new YANG data nodes,
|
* configurations. Given a new subtree, calculate all new YANG data nodes,
|
||||||
* excluding default leafs and leaf-lists. This is a recursive function.
|
* excluding default leafs and leaf-lists. This is a recursive function.
|
||||||
*/
|
*/
|
||||||
static void nb_config_diff_new_subtree(const struct lyd_node *dnode,
|
static void nb_config_diff_created(const struct lyd_node *dnode,
|
||||||
struct nb_config_cbs *changes)
|
struct nb_config_cbs *changes)
|
||||||
{
|
{
|
||||||
|
enum nb_operation operation;
|
||||||
struct lyd_node *child;
|
struct lyd_node *child;
|
||||||
|
|
||||||
LY_TREE_FOR (dnode->child, child) {
|
switch (dnode->schema->nodetype) {
|
||||||
enum nb_operation operation;
|
|
||||||
|
|
||||||
switch (child->schema->nodetype) {
|
|
||||||
case LYS_LEAF:
|
case LYS_LEAF:
|
||||||
case LYS_LEAFLIST:
|
case LYS_LEAFLIST:
|
||||||
if (lyd_wd_default((struct lyd_node_leaf_list *)child))
|
if (lyd_wd_default((struct lyd_node_leaf_list *)dnode))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (nb_operation_is_valid(NB_OP_CREATE, child->schema))
|
if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
|
||||||
operation = NB_OP_CREATE;
|
operation = NB_OP_CREATE;
|
||||||
else if (nb_operation_is_valid(NB_OP_MODIFY,
|
else if (nb_operation_is_valid(NB_OP_MODIFY, dnode->schema))
|
||||||
child->schema))
|
|
||||||
operation = NB_OP_MODIFY;
|
operation = NB_OP_MODIFY;
|
||||||
else
|
else
|
||||||
continue;
|
return;
|
||||||
|
|
||||||
nb_config_diff_add_change(changes, operation, child);
|
nb_config_diff_add_change(changes, operation, dnode);
|
||||||
break;
|
break;
|
||||||
case LYS_CONTAINER:
|
case LYS_CONTAINER:
|
||||||
case LYS_LIST:
|
case LYS_LIST:
|
||||||
if (nb_operation_is_valid(NB_OP_CREATE, child->schema))
|
if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
|
||||||
nb_config_diff_add_change(changes, NB_OP_CREATE,
|
nb_config_diff_add_change(changes, NB_OP_CREATE, dnode);
|
||||||
child);
|
|
||||||
nb_config_diff_new_subtree(child, changes);
|
/* Process child nodes recursively. */
|
||||||
|
LY_TREE_FOR (dnode->child, child) {
|
||||||
|
nb_config_diff_created(child, changes);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the delta between two different configurations. */
|
/* Calculate the delta between two different configurations. */
|
||||||
@ -399,42 +418,27 @@ static void nb_config_diff(const struct nb_config *config1,
|
|||||||
for (int i = 0; diff->type[i] != LYD_DIFF_END; i++) {
|
for (int i = 0; diff->type[i] != LYD_DIFF_END; i++) {
|
||||||
LYD_DIFFTYPE type;
|
LYD_DIFFTYPE type;
|
||||||
struct lyd_node *dnode;
|
struct lyd_node *dnode;
|
||||||
enum nb_operation operation;
|
|
||||||
|
|
||||||
type = diff->type[i];
|
type = diff->type[i];
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LYD_DIFF_CREATED:
|
case LYD_DIFF_CREATED:
|
||||||
dnode = diff->second[i];
|
dnode = diff->second[i];
|
||||||
|
nb_config_diff_created(dnode, changes);
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
case LYD_DIFF_DELETED:
|
case LYD_DIFF_DELETED:
|
||||||
dnode = diff->first[i];
|
dnode = diff->first[i];
|
||||||
operation = NB_OP_DESTROY;
|
nb_config_diff_deleted(dnode, changes);
|
||||||
break;
|
break;
|
||||||
case LYD_DIFF_CHANGED:
|
case LYD_DIFF_CHANGED:
|
||||||
dnode = diff->second[i];
|
dnode = diff->second[i];
|
||||||
operation = NB_OP_MODIFY;
|
nb_config_diff_add_change(changes, NB_OP_MODIFY, dnode);
|
||||||
break;
|
break;
|
||||||
case LYD_DIFF_MOVEDAFTER1:
|
case LYD_DIFF_MOVEDAFTER1:
|
||||||
case LYD_DIFF_MOVEDAFTER2:
|
case LYD_DIFF_MOVEDAFTER2:
|
||||||
default:
|
default:
|
||||||
continue;
|
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);
|
lyd_free_diff(diff);
|
||||||
|
27
lib/privs.c
27
lib/privs.c
@ -708,12 +708,8 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
|
|||||||
|
|
||||||
/* If we're already elevated, just return */
|
/* If we're already elevated, just return */
|
||||||
pthread_mutex_lock(&(privs->mutex));
|
pthread_mutex_lock(&(privs->mutex));
|
||||||
if (++privs->refcount > 1) {
|
{
|
||||||
pthread_mutex_unlock(&(privs->mutex));
|
if (++(privs->refcount) == 1) {
|
||||||
return privs;
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&(privs->mutex));
|
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (privs->change(ZPRIVS_RAISE)) {
|
if (privs->change(ZPRIVS_RAISE)) {
|
||||||
zlog_err("%s: Failed to raise privileges (%s)",
|
zlog_err("%s: Failed to raise privileges (%s)",
|
||||||
@ -721,6 +717,10 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
|
|||||||
}
|
}
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
privs->raised_in_funcname = funcname;
|
privs->raised_in_funcname = funcname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&(privs->mutex));
|
||||||
|
|
||||||
return privs;
|
return privs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -733,19 +733,20 @@ void _zprivs_lower(struct zebra_privs_t **privs)
|
|||||||
|
|
||||||
/* Don't lower privs if there's another caller */
|
/* Don't lower privs if there's another caller */
|
||||||
pthread_mutex_lock(&(*privs)->mutex);
|
pthread_mutex_lock(&(*privs)->mutex);
|
||||||
if (--((*privs)->refcount) > 0) {
|
{
|
||||||
pthread_mutex_unlock(&(*privs)->mutex);
|
if (--((*privs)->refcount) == 0) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&(*privs)->mutex);
|
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if ((*privs)->change(ZPRIVS_LOWER)) {
|
if ((*privs)->change(ZPRIVS_LOWER)) {
|
||||||
zlog_err("%s: Failed to lower privileges (%s)",
|
zlog_err("%s: Failed to lower privileges (%s)",
|
||||||
(*privs)->raised_in_funcname, safe_strerror(errno));
|
(*privs)->raised_in_funcname,
|
||||||
|
safe_strerror(errno));
|
||||||
}
|
}
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
(*privs)->raised_in_funcname = NULL;
|
(*privs)->raised_in_funcname = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&(*privs)->mutex);
|
||||||
|
|
||||||
*privs = NULL;
|
*privs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ struct vrf_id_head vrfs_by_id = RB_INITIALIZER(&vrfs_by_id);
|
|||||||
struct vrf_name_head vrfs_by_name = RB_INITIALIZER(&vrfs_by_name);
|
struct vrf_name_head vrfs_by_name = RB_INITIALIZER(&vrfs_by_name);
|
||||||
|
|
||||||
static int vrf_backend;
|
static int vrf_backend;
|
||||||
|
static int vrf_backend_configured;
|
||||||
static struct zebra_privs_t *vrf_daemon_privs;
|
static struct zebra_privs_t *vrf_daemon_privs;
|
||||||
static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL;
|
static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL;
|
||||||
|
|
||||||
@ -613,12 +614,15 @@ int vrf_is_backend_netns(void)
|
|||||||
|
|
||||||
int vrf_get_backend(void)
|
int vrf_get_backend(void)
|
||||||
{
|
{
|
||||||
|
if (!vrf_backend_configured)
|
||||||
|
return VRF_BACKEND_UNKNOWN;
|
||||||
return vrf_backend;
|
return vrf_backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vrf_configure_backend(int vrf_backend_netns)
|
void vrf_configure_backend(int vrf_backend_netns)
|
||||||
{
|
{
|
||||||
vrf_backend = vrf_backend_netns;
|
vrf_backend = vrf_backend_netns;
|
||||||
|
vrf_backend_configured = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vrf_handler_create(struct vty *vty, const char *vrfname,
|
int vrf_handler_create(struct vty *vty, const char *vrfname,
|
||||||
@ -662,7 +666,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
|
|||||||
"VRF %u is already configured with VRF %s\n",
|
"VRF %u is already configured with VRF %s\n",
|
||||||
vrf->vrf_id, vrf->name);
|
vrf->vrf_id, vrf->name);
|
||||||
else
|
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);
|
vrf->vrf_id, vrf->name);
|
||||||
return CMD_WARNING_CONFIG_FAILED;
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,7 @@ DECLARE_QOBJ_TYPE(vrf)
|
|||||||
/* Allow VRF with netns as backend */
|
/* Allow VRF with netns as backend */
|
||||||
#define VRF_BACKEND_VRF_LITE 0
|
#define VRF_BACKEND_VRF_LITE 0
|
||||||
#define VRF_BACKEND_NETNS 1
|
#define VRF_BACKEND_NETNS 1
|
||||||
|
#define VRF_BACKEND_UNKNOWN 2
|
||||||
|
|
||||||
extern struct vrf_id_head vrfs_by_id;
|
extern struct vrf_id_head vrfs_by_id;
|
||||||
extern struct vrf_name_head vrfs_by_name;
|
extern struct vrf_name_head vrfs_by_name;
|
||||||
|
@ -629,7 +629,7 @@ void zclient_init(struct zclient *zclient, int redist_default,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (zclient_debug)
|
if (zclient_debug)
|
||||||
zlog_debug("zclient_start is called");
|
zlog_debug("scheduling zclient connection");
|
||||||
|
|
||||||
zclient_event(ZCLIENT_SCHEDULE, zclient);
|
zclient_event(ZCLIENT_SCHEDULE, zclient);
|
||||||
}
|
}
|
||||||
@ -2504,8 +2504,9 @@ static int zclient_read(struct thread *thread)
|
|||||||
length -= ZEBRA_HEADER_SIZE;
|
length -= ZEBRA_HEADER_SIZE;
|
||||||
|
|
||||||
if (zclient_debug)
|
if (zclient_debug)
|
||||||
zlog_debug("zclient 0x%p command 0x%x VRF %u\n",
|
zlog_debug("zclient 0x%p command %s VRF %u",
|
||||||
(void *)zclient, command, vrf_id);
|
(void *)zclient, zserv_command_string(command),
|
||||||
|
vrf_id);
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case ZEBRA_CAPABILITIES:
|
case ZEBRA_CAPABILITIES:
|
||||||
@ -2574,14 +2575,14 @@ static int zclient_read(struct thread *thread)
|
|||||||
break;
|
break;
|
||||||
case ZEBRA_NEXTHOP_UPDATE:
|
case ZEBRA_NEXTHOP_UPDATE:
|
||||||
if (zclient_debug)
|
if (zclient_debug)
|
||||||
zlog_debug("zclient rcvd nexthop update\n");
|
zlog_debug("zclient rcvd nexthop update");
|
||||||
if (zclient->nexthop_update)
|
if (zclient->nexthop_update)
|
||||||
(*zclient->nexthop_update)(command, zclient, length,
|
(*zclient->nexthop_update)(command, zclient, length,
|
||||||
vrf_id);
|
vrf_id);
|
||||||
break;
|
break;
|
||||||
case ZEBRA_IMPORT_CHECK_UPDATE:
|
case ZEBRA_IMPORT_CHECK_UPDATE:
|
||||||
if (zclient_debug)
|
if (zclient_debug)
|
||||||
zlog_debug("zclient rcvd import check update\n");
|
zlog_debug("zclient rcvd import check update");
|
||||||
if (zclient->import_check_update)
|
if (zclient->import_check_update)
|
||||||
(*zclient->import_check_update)(command, zclient,
|
(*zclient->import_check_update)(command, zclient,
|
||||||
length, vrf_id);
|
length, vrf_id);
|
||||||
@ -2608,7 +2609,7 @@ static int zclient_read(struct thread *thread)
|
|||||||
break;
|
break;
|
||||||
case ZEBRA_FEC_UPDATE:
|
case ZEBRA_FEC_UPDATE:
|
||||||
if (zclient_debug)
|
if (zclient_debug)
|
||||||
zlog_debug("zclient rcvd fec update\n");
|
zlog_debug("zclient rcvd fec update");
|
||||||
if (zclient->fec_update)
|
if (zclient->fec_update)
|
||||||
(*zclient->fec_update)(command, zclient, length);
|
(*zclient->fec_update)(command, zclient, length);
|
||||||
break;
|
break;
|
||||||
|
@ -138,11 +138,11 @@ static void ospf6_area_stub_update(struct ospf6_area *area)
|
|||||||
|
|
||||||
if (IS_AREA_STUB(area)) {
|
if (IS_AREA_STUB(area)) {
|
||||||
if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
|
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);
|
OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
|
||||||
} else if (IS_AREA_ENABLED(area)) {
|
} else if (IS_AREA_ENABLED(area)) {
|
||||||
if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
|
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_OPT_SET(area->options, OSPF6_OPT_E);
|
||||||
ospf6_asbr_send_externals_to_area(area);
|
ospf6_asbr_send_externals_to_area(area);
|
||||||
}
|
}
|
||||||
@ -450,7 +450,7 @@ DEFUN (area_range,
|
|||||||
|
|
||||||
range->path.u.cost_config = cost;
|
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);
|
argv[idx_ipv6_prefixlen]->arg, range->flag);
|
||||||
if (range->rnode == NULL) {
|
if (range->rnode == NULL) {
|
||||||
ospf6_route_add(range, oa->range_table);
|
ospf6_route_add(range, oa->range_table);
|
||||||
|
@ -1006,7 +1006,7 @@ void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa)
|
|||||||
|
|
||||||
for (ALL_LSDB(oa->ospf6->lsdb, lsa)) {
|
for (ALL_LSDB(oa->ospf6->lsdb, lsa)) {
|
||||||
if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
|
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);
|
__func__, lsa->name);
|
||||||
ospf6_flood_area(NULL, lsa, oa);
|
ospf6_flood_area(NULL, lsa, oa);
|
||||||
}
|
}
|
||||||
|
@ -475,7 +475,7 @@ void ospf6_spf_calculation(uint32_t router_id,
|
|||||||
lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
|
lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
|
||||||
if (lsa == NULL) {
|
if (lsa == NULL) {
|
||||||
if (IS_OSPF6_DEBUG_SPF(PROCESS))
|
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);
|
oa->name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -226,6 +226,9 @@ static int ospf6_zebra_read_route(int command, struct zclient *zclient,
|
|||||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
|
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
|
||||||
|
return 0;
|
||||||
|
|
||||||
ifindex = api.nexthops[0].ifindex;
|
ifindex = api.nexthops[0].ifindex;
|
||||||
nexthop = &api.nexthops[0].gate.ipv6;
|
nexthop = &api.nexthops[0].gate.ipv6;
|
||||||
|
|
||||||
|
@ -74,12 +74,12 @@ void api_opaque_lsa_print(struct lsa_header *data)
|
|||||||
olsa = (struct opaque_lsa *)data;
|
olsa = (struct opaque_lsa *)data;
|
||||||
|
|
||||||
opaquelen = ntohs(data->length) - OSPF_LSA_HEADER_SIZE;
|
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++) {
|
for (i = 0; i < opaquelen; i++) {
|
||||||
zlog_debug("0x%x ", olsa->mydata[i]);
|
zlog_debug("0x%x ", olsa->mydata[i]);
|
||||||
}
|
}
|
||||||
zlog_debug("\n");
|
zlog_debug(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -----------------------------------------------------------
|
/* -----------------------------------------------------------
|
||||||
@ -242,7 +242,7 @@ const char *ospf_api_errname(int errcode)
|
|||||||
void msg_print(struct msg *msg)
|
void msg_print(struct msg *msg)
|
||||||
{
|
{
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
zlog_debug("msg_print msg=NULL!\n");
|
zlog_debug("msg_print msg=NULL!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2024,7 +2024,7 @@ int ospf_apiserver_del_if(struct interface *ifp)
|
|||||||
|
|
||||||
/* zlog_warn for debugging */
|
/* zlog_warn for debugging */
|
||||||
zlog_warn("ospf_apiserver_del_if");
|
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);
|
ifp->ifindex);
|
||||||
|
|
||||||
oi = ospf_apiserver_if_lookup_by_ifp(ifp);
|
oi = ospf_apiserver_if_lookup_by_ifp(ifp);
|
||||||
@ -2110,7 +2110,6 @@ void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa)
|
|||||||
for (i = 0; i < opaquelen; i++) {
|
for (i = 0; i < opaquelen; i++) {
|
||||||
zlog_debug("0x%x ", olsa->data[i]);
|
zlog_debug("0x%x ", olsa->data[i]);
|
||||||
}
|
}
|
||||||
zlog_debug("\n");
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3447,7 +3447,14 @@ static int ospf_make_ls_req_func(struct stream *s, uint16_t *length,
|
|||||||
|
|
||||||
oi = nbr->oi;
|
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))
|
if (*length + delta > ospf_packet_max(oi))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -3466,7 +3473,7 @@ static int ospf_make_ls_req(struct ospf_neighbor *nbr, struct stream *s)
|
|||||||
{
|
{
|
||||||
struct ospf_lsa *lsa;
|
struct ospf_lsa *lsa;
|
||||||
uint16_t length = OSPF_LS_REQ_MIN_SIZE;
|
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_table *table;
|
||||||
struct route_node *rn;
|
struct route_node *rn;
|
||||||
int i;
|
int i;
|
||||||
@ -3530,8 +3537,9 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update,
|
|||||||
|
|
||||||
assert(lsa->data);
|
assert(lsa->data);
|
||||||
|
|
||||||
/* Will it fit? */
|
/* Will it fit? Minimum it has to fit atleast one */
|
||||||
if (length + delta + ntohs(lsa->data->length) > size_noauth)
|
if ((length + delta + ntohs(lsa->data->length) > size_noauth) &&
|
||||||
|
(count > 0))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Keep pointer to LS age. */
|
/* Keep pointer to LS age. */
|
||||||
@ -3568,13 +3576,21 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack,
|
|||||||
{
|
{
|
||||||
struct listnode *node, *nnode;
|
struct listnode *node, *nnode;
|
||||||
uint16_t length = OSPF_LS_ACK_MIN_SIZE;
|
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;
|
struct ospf_lsa *lsa;
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) {
|
for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) {
|
||||||
assert(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;
|
break;
|
||||||
|
|
||||||
stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE);
|
stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE);
|
||||||
|
@ -1372,14 +1372,14 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
zlog_debug(" Segment Routing Algorithm TLV:\n");
|
zlog_debug(" Segment Routing Algorithm TLV:");
|
||||||
for (i = 0; i < ntohs(algo->header.length); i++)
|
for (i = 0; i < ntohs(algo->header.length); i++)
|
||||||
switch (algo->value[i]) {
|
switch (algo->value[i]) {
|
||||||
case 0:
|
case 0:
|
||||||
zlog_debug(" Algorithm %d: SPF\n", i);
|
zlog_debug(" Algorithm %d: SPF", i);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
zlog_debug(" Algorithm %d: Strict SPF\n", i);
|
zlog_debug(" Algorithm %d: Strict SPF", i);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
|
@ -901,7 +901,7 @@ static struct ospf_lsa *lsdb_lookup_next(struct ospf_area *area, uint8_t *type,
|
|||||||
/* Sanity check, if LSA type unknwon
|
/* Sanity check, if LSA type unknwon
|
||||||
merley skip any LSA */
|
merley skip any LSA */
|
||||||
if ((i < OSPF_MIN_LSA) || (i >= OSPF_MAX_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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1140,13 +1140,13 @@ ospf_rtrs_print (struct route_table *rtrs)
|
|||||||
if (path->nexthop.s_addr == 0)
|
if (path->nexthop.s_addr == 0)
|
||||||
{
|
{
|
||||||
if (IS_DEBUG_OSPF_EVENT)
|
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);
|
ifindex2ifname (path->ifindex), VRF_DEFAULT);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (IS_DEBUG_OSPF_EVENT)
|
if (IS_DEBUG_OSPF_EVENT)
|
||||||
zlog_debug (" via %s, %s\r\n",
|
zlog_debug (" via %s, %s\r",
|
||||||
inet_ntoa (path->nexthop),
|
inet_ntoa (path->nexthop),
|
||||||
ifindex2ifname (path->ifindex), VRF_DEFAULT);
|
ifindex2ifname (path->ifindex), VRF_DEFAULT);
|
||||||
}
|
}
|
||||||
|
@ -1600,7 +1600,7 @@ static int ospf_sr_update_schedule(struct thread *t)
|
|||||||
monotime(&stop_time);
|
monotime(&stop_time);
|
||||||
|
|
||||||
if (IS_DEBUG_OSPF_SR)
|
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__,
|
__func__,
|
||||||
(stop_time.tv_sec - start_time.tv_sec) * 1000000LL
|
(stop_time.tv_sec - start_time.tv_sec) * 1000000LL
|
||||||
+ (stop_time.tv_usec - start_time.tv_usec));
|
+ (stop_time.tv_usec - start_time.tv_usec));
|
||||||
|
@ -3029,13 +3029,13 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf,
|
|||||||
if (ospf->stub_router_startup_time
|
if (ospf->stub_router_startup_time
|
||||||
!= OSPF_STUB_ROUTER_UNCONFIGURED)
|
!= OSPF_STUB_ROUTER_UNCONFIGURED)
|
||||||
json_object_int_add(
|
json_object_int_add(
|
||||||
json_vrf, "postStartEnabledMsecs",
|
json_vrf, "postStartEnabledSecs",
|
||||||
ospf->stub_router_startup_time / 1000);
|
ospf->stub_router_startup_time);
|
||||||
if (ospf->stub_router_shutdown_time
|
if (ospf->stub_router_shutdown_time
|
||||||
!= OSPF_STUB_ROUTER_UNCONFIGURED)
|
!= OSPF_STUB_ROUTER_UNCONFIGURED)
|
||||||
json_object_int_add(
|
json_object_int_add(
|
||||||
json_vrf, "preShutdownEnabledMsecs",
|
json_vrf, "preShutdownEnabledSecs",
|
||||||
ospf->stub_router_shutdown_time / 1000);
|
ospf->stub_router_shutdown_time);
|
||||||
} else {
|
} else {
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
" Stub router advertisement is configured\n");
|
" Stub router advertisement is configured\n");
|
||||||
@ -3511,8 +3511,8 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
|
|||||||
json_object_int_add(json_interface_sub, "cost",
|
json_object_int_add(json_interface_sub, "cost",
|
||||||
oi->output_cost);
|
oi->output_cost);
|
||||||
json_object_int_add(
|
json_object_int_add(
|
||||||
json_interface_sub, "transmitDelayMsecs",
|
json_interface_sub, "transmitDelaySecs",
|
||||||
1000 / OSPF_IF_PARAM(oi, transmit_delay));
|
OSPF_IF_PARAM(oi, transmit_delay));
|
||||||
json_object_string_add(json_interface_sub, "state",
|
json_object_string_add(json_interface_sub, "state",
|
||||||
lookup_msg(ospf_ism_state_msg,
|
lookup_msg(ospf_ism_state_msg,
|
||||||
oi->state, NULL));
|
oi->state, NULL));
|
||||||
@ -3616,20 +3616,20 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
|
|||||||
if (OSPF_IF_PARAM(oi, fast_hello) == 0)
|
if (OSPF_IF_PARAM(oi, fast_hello) == 0)
|
||||||
json_object_int_add(
|
json_object_int_add(
|
||||||
json_interface_sub, "timerMsecs",
|
json_interface_sub, "timerMsecs",
|
||||||
1000 / OSPF_IF_PARAM(oi, v_hello));
|
OSPF_IF_PARAM(oi, v_hello) * 1000);
|
||||||
else
|
else
|
||||||
json_object_int_add(
|
json_object_int_add(
|
||||||
json_interface_sub, "timerMsecs",
|
json_interface_sub, "timerMsecs",
|
||||||
1000 / OSPF_IF_PARAM(oi, fast_hello));
|
1000 / OSPF_IF_PARAM(oi, fast_hello));
|
||||||
json_object_int_add(json_interface_sub,
|
json_object_int_add(json_interface_sub,
|
||||||
"timerDeadMsecs",
|
"timerDeadSecs",
|
||||||
1000 / OSPF_IF_PARAM(oi, v_wait));
|
OSPF_IF_PARAM(oi, v_wait));
|
||||||
json_object_int_add(json_interface_sub,
|
json_object_int_add(json_interface_sub,
|
||||||
"timerWaitMsecs",
|
"timerWaitSecs",
|
||||||
1000 / OSPF_IF_PARAM(oi, v_wait));
|
OSPF_IF_PARAM(oi, v_wait));
|
||||||
json_object_int_add(
|
json_object_int_add(
|
||||||
json_interface_sub, "timerRetransmit",
|
json_interface_sub, "timerRetransmitSecs",
|
||||||
1000 / OSPF_IF_PARAM(oi, retransmit_interval));
|
OSPF_IF_PARAM(oi, retransmit_interval));
|
||||||
} else {
|
} else {
|
||||||
vty_out(vty, " Timer intervals configured,");
|
vty_out(vty, " Timer intervals configured,");
|
||||||
vty_out(vty, " Hello ");
|
vty_out(vty, " Hello ");
|
||||||
|
111
pbrd/pbr_nht.c
111
pbrd/pbr_nht.c
@ -50,7 +50,7 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
|||||||
static void
|
static void
|
||||||
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
||||||
struct nexthop_group nhg,
|
struct nexthop_group nhg,
|
||||||
enum nexthop_types_t nh_afi);
|
enum nexthop_types_t nh_type);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Nexthop refcount.
|
* Nexthop refcount.
|
||||||
@ -157,7 +157,7 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2)
|
|||||||
|
|
||||||
switch (pbrnc1->nexthop->type) {
|
switch (pbrnc1->nexthop->type) {
|
||||||
case NEXTHOP_TYPE_IFINDEX:
|
case NEXTHOP_TYPE_IFINDEX:
|
||||||
return true;
|
return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex;
|
||||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||||
case NEXTHOP_TYPE_IPV4:
|
case NEXTHOP_TYPE_IPV4:
|
||||||
return pbrnc1->nexthop->gate.ipv4.s_addr
|
return pbrnc1->nexthop->gate.ipv4.s_addr
|
||||||
@ -264,6 +264,14 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
|
|||||||
|
|
||||||
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
|
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
|
||||||
pbr_map_check_nh_group_change(nhgc->name);
|
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,
|
void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
|
||||||
@ -274,7 +282,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
|
|||||||
struct pbr_nexthop_group_cache *pnhgc;
|
struct pbr_nexthop_group_cache *pnhgc;
|
||||||
struct pbr_nexthop_cache pnhc_find = {};
|
struct pbr_nexthop_cache pnhc_find = {};
|
||||||
struct pbr_nexthop_cache *pnhc;
|
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 */
|
/* find pnhgc by name */
|
||||||
strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
|
strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
|
||||||
@ -296,7 +304,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
|
|||||||
if (pnhgc->nhh->count)
|
if (pnhgc->nhh->count)
|
||||||
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
|
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
|
||||||
else
|
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);
|
pbr_map_check_nh_group_change(nhgc->name);
|
||||||
}
|
}
|
||||||
@ -372,22 +380,32 @@ void pbr_nht_route_removed_for_table(uint32_t table_id)
|
|||||||
* - AFI_MAX on error
|
* - AFI_MAX on error
|
||||||
*/
|
*/
|
||||||
static afi_t pbr_nht_which_afi(struct nexthop_group nhg,
|
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;
|
struct nexthop *nexthop;
|
||||||
afi_t install_afi = AFI_MAX;
|
afi_t install_afi = AFI_MAX;
|
||||||
bool v6, v4, bh;
|
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;
|
v6 = v4 = bh = false;
|
||||||
|
|
||||||
if (!nh_afi) {
|
|
||||||
for (ALL_NEXTHOPS(nhg, nexthop)) {
|
for (ALL_NEXTHOPS(nhg, nexthop)) {
|
||||||
nh_afi = nexthop->type;
|
nh_type = nexthop->type;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (nh_afi) {
|
switch (nh_type) {
|
||||||
case NEXTHOP_TYPE_IFINDEX:
|
case NEXTHOP_TYPE_IFINDEX:
|
||||||
break;
|
break;
|
||||||
case NEXTHOP_TYPE_IPV4:
|
case NEXTHOP_TYPE_IPV4:
|
||||||
@ -402,9 +420,13 @@ static afi_t pbr_nht_which_afi(struct nexthop_group nhg,
|
|||||||
break;
|
break;
|
||||||
case NEXTHOP_TYPE_BLACKHOLE:
|
case NEXTHOP_TYPE_BLACKHOLE:
|
||||||
bh = true;
|
bh = true;
|
||||||
install_afi = AFI_MAX;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interface and/or blackhole nexthops only. */
|
||||||
|
if (!v4 && !v6)
|
||||||
|
install_afi = AFI_MAX;
|
||||||
|
|
||||||
if (!bh && v6 && v4)
|
if (!bh && v6 && v4)
|
||||||
DEBUGD(&pbr_dbg_nht,
|
DEBUGD(&pbr_dbg_nht,
|
||||||
@ -423,9 +445,9 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
|||||||
struct nexthop_group nhg)
|
struct nexthop_group nhg)
|
||||||
{
|
{
|
||||||
afi_t install_afi;
|
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);
|
route_add(pnhgc, nhg, install_afi);
|
||||||
}
|
}
|
||||||
@ -433,11 +455,11 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
|||||||
static void
|
static void
|
||||||
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
||||||
struct nexthop_group nhg,
|
struct nexthop_group nhg,
|
||||||
enum nexthop_types_t nh_afi)
|
enum nexthop_types_t nh_type)
|
||||||
{
|
{
|
||||||
afi_t install_afi;
|
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->installed = false;
|
||||||
pnhgc->valid = false;
|
pnhgc->valid = false;
|
||||||
@ -526,7 +548,7 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
|
|||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
struct pbr_map_interface *pmi;
|
struct pbr_map_interface *pmi;
|
||||||
struct nexthop *nh;
|
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) {
|
if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
|
||||||
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
|
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
|
||||||
@ -542,13 +564,13 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
|
|||||||
pnhgc = hash_lookup(pbr_nhg_hash, &find);
|
pnhgc = hash_lookup(pbr_nhg_hash, &find);
|
||||||
|
|
||||||
nh = pbrms->nhg->nexthop;
|
nh = pbrms->nhg->nexthop;
|
||||||
nh_afi = nh->type;
|
nh_type = nh->type;
|
||||||
lup.nexthop = nh;
|
lup.nexthop = nh;
|
||||||
pnhc = hash_lookup(pnhgc->nhh, &lup);
|
pnhc = hash_lookup(pnhgc->nhh, &lup);
|
||||||
pnhc->parent = NULL;
|
pnhc->parent = NULL;
|
||||||
hash_release(pnhgc->nhh, pnhc);
|
hash_release(pnhgc->nhh, pnhc);
|
||||||
pbr_nh_delete(&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);
|
hash_release(pbr_nhg_hash, pnhgc);
|
||||||
|
|
||||||
@ -653,6 +675,7 @@ bool pbr_nht_nexthop_group_valid(const char *name)
|
|||||||
|
|
||||||
struct pbr_nht_individual {
|
struct pbr_nht_individual {
|
||||||
struct zapi_route *nhr;
|
struct zapi_route *nhr;
|
||||||
|
struct interface *ifp;
|
||||||
|
|
||||||
uint32_t valid;
|
uint32_t valid;
|
||||||
};
|
};
|
||||||
@ -716,6 +739,56 @@ void pbr_nht_nexthop_update(struct zapi_route *nhr)
|
|||||||
hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr);
|
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)
|
static uint32_t pbr_nhg_hash_key(void *arg)
|
||||||
{
|
{
|
||||||
struct pbr_nexthop_group_cache *nhgc =
|
struct pbr_nexthop_group_cache *nhgc =
|
||||||
|
@ -117,5 +117,10 @@ extern void pbr_nht_show_nexthop_group(struct vty *vty, const char *name);
|
|||||||
*/
|
*/
|
||||||
extern void pbr_nht_nexthop_update(struct zapi_route *nhr);
|
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);
|
extern void pbr_nht_init(void);
|
||||||
#endif
|
#endif
|
||||||
|
@ -221,13 +221,19 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
|
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
|
NO_STR
|
||||||
"Set for the PBR-MAP\n"
|
"Set for the PBR-MAP\n"
|
||||||
"Specify one of the nexthops in this map\n"
|
"Specify one of the nexthops in this map\n"
|
||||||
"v4 Address\n"
|
"v4 Address\n"
|
||||||
"v6 Address\n"
|
"v6 Address\n"
|
||||||
"Interface to use\n"
|
"Interface to use\n"
|
||||||
|
"Interface to use\n"
|
||||||
"If the nexthop is in a different vrf tell us\n"
|
"If the nexthop is in a different vrf tell us\n"
|
||||||
"The nexthop-vrf Name\n")
|
"The nexthop-vrf Name\n")
|
||||||
{
|
{
|
||||||
@ -255,36 +261,28 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
|
|||||||
memset(&nhop, 0, sizeof(nhop));
|
memset(&nhop, 0, sizeof(nhop));
|
||||||
nhop.vrf_id = vrf->vrf_id;
|
nhop.vrf_id = vrf->vrf_id;
|
||||||
|
|
||||||
/*
|
if (intf) {
|
||||||
* Make SA happy. CLIPPY is not going to give us a NULL
|
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
||||||
* addr.
|
if (nhop.ifindex == IFINDEX_INTERNAL) {
|
||||||
*/
|
vty_out(vty,
|
||||||
assert(addr);
|
"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) {
|
if (addr->sa.sa_family == AF_INET) {
|
||||||
nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
|
nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
|
||||||
if (intf) {
|
if (intf)
|
||||||
nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
||||||
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
else
|
||||||
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;
|
nhop.type = NEXTHOP_TYPE_IPV4;
|
||||||
} else {
|
} else {
|
||||||
memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
|
nhop.gate.ipv6 = addr->sin6.sin6_addr;
|
||||||
if (intf) {
|
if (intf)
|
||||||
nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
||||||
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
else {
|
||||||
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 {
|
|
||||||
if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
|
if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"Specified a v6 LL with no interface, rejecting\n");
|
"Specified a v6 LL with no interface, rejecting\n");
|
||||||
@ -293,6 +291,8 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
|
|||||||
nhop.type = NEXTHOP_TYPE_IPV6;
|
nhop.type = NEXTHOP_TYPE_IPV6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
|
nhop.type = NEXTHOP_TYPE_IFINDEX;
|
||||||
|
|
||||||
if (pbrms->nhg)
|
if (pbrms->nhg)
|
||||||
nh = nexthop_exists(pbrms->nhg, &nhop);
|
nh = nexthop_exists(pbrms->nhg, &nhop);
|
||||||
@ -335,6 +335,14 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
|
|||||||
pbr_map_check(pbrms);
|
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;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user