提交 354ccf4d 编写于 作者: P p4u

Removed qmp-quagga package to do not conflict with the standard quagga one

上级 8c9e26c5
#
# Copyright (C) 2006-2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# Contributors:
# Simó Albert i Beltran
#
include $(TOPDIR)/rules.mk
PKG_NAME:=qmp-quagga
PKG_VERSION:=0.99.21
PKG_RELEASE:=2
PKG_MD5SUM:=99840adbe57047c90dfba6b6ed9aec7f
PKG_SOURCE:=quagga-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=http://www.quagga.net/download/ \
http://www.de.quagga.net/download/ \
http://www.uk.quagga.net/download/
PKG_BUILD_DIR:=$(BUILD_DIR)/quagga-$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
CONFIG_IPV6 \
CONFIG_PACKAGE_qmp-quagga-watchquagga \
CONFIG_PACKAGE_qmp-quagga-zebra \
CONFIG_PACKAGE_qmp-quagga-libzebra \
CONFIG_PACKAGE_qmp-quagga-libospf \
CONFIG_PACKAGE_qmp-quagga-bgpd \
CONFIG_PACKAGE_qmp-quagga-isisd \
CONFIG_PACKAGE_qmp-quagga-ospf6d \
CONFIG_PACKAGE_qmp-quagga-ripd \
CONFIG_PACKAGE_qmp-quagga-ripngd \
CONFIG_PACKAGE_qmp-quagga-babeld \
CONFIG_PACKAGE_qmp-quagga-vtysh
PKG_BUILD_PARALLEL:=1
PKG_FIXUP:=autoreconf
PKG_INSTALL:=1
include $(INCLUDE_DIR)/package.mk
define Package/qmp-quagga/Default
SECTION:=qMp
CATEGORY:=qMp
SUBMENU:=Routing and Redirection
DEPENDS:=qmp-quagga
TITLE:=The Quagga Software Routing Suite
URL:=http://www.quagga.net
MAINTAINER:=Vasilis Tsiligiannis <b_tsiligiannis@silverton.gr>
endef
define Package/qmp-quagga
$(call Package/qmp-quagga/Default)
DEPENDS:=+qmp-quagga-vtysh +qmp-quagga-bgpd
MENU:=1
endef
define Package/qmp-quagga/description
A routing software package that provides TCP/IP based routing services
with routing protocols support such as RIPv1, RIPv2, RIPng, OSPFv2,
OSPFv3, BGP-4, and BGP-4+
endef
define Package/qmp-quagga-watchquagga
$(call Package/qmp-quagga/Default)
TITLE:=Quagga watchdog
DEPENDS+=+qmp-quagga-libzebra
DEFAULT:=y if PACKAGE_qmp-quagga
endef
define Package/qmp-quagga-zebra
$(call Package/qmp-quagga/Default)
TITLE:=Zebra daemon
DEPENDS+=+qmp-quagga-libzebra
DEFAULT:=y if PACKAGE_qmp-quagga
endef
define Package/qmp-quagga-libzebra
$(call Package/qmp-quagga/Default)
DEPENDS+=+librt
TITLE:=zebra library
endef
define Package/qmp-quagga-libospf
$(call Package/qmp-quagga/Default)
TITLE:=OSPF library
endef
define Package/qmp-quagga-bgpd
$(call Package/qmp-quagga/Default)
DEPENDS+=+qmp-quagga-libzebra
TITLE:=BGPv4, BGPv4+, BGPv4- routing engine
endef
define Package/qmp-quagga-isisd
$(call Package/qmp-quagga/Default)
DEPENDS+=+qmp-quagga-libzebra
TITLE:=IS-IS routing engine
endef
define Package/qmp-quagga-ospfd
$(call Package/qmp-quagga/Default)
DEPENDS+=+qmp-quagga-libospf +qmp-quagga-libzebra
TITLE:=OSPFv2 routing engine
endef
define Package/qmp-quagga-ospf6d
$(call Package/qmp-quagga/Default)
DEPENDS+=+qmp-quagga-libospf +qmp-quagga-libzebra @IPV6
TITLE:=OSPFv3 routing engine
endef
define Package/qmp-quagga-ripd
$(call Package/qmp-quagga/Default)
DEPENDS+=+qmp-quagga-libzebra
TITLE:=RIP routing engine
endef
define Package/qmp-quagga-ripngd
$(call Package/qmp-quagga/Default)
DEPENDS+=+qmp-quagga-libzebra @IPV6
TITLE:=RIPNG routing engine
endef
define Package/qmp-quagga-babeld
$(call Package/qmp-quagga/Default)
DEPENDS+=+qmp-quagga-libzebra
TITLE:=Babel routing engine
endef
define Package/qmp-quagga-vtysh
$(call Package/qmp-quagga/Default)
DEPENDS+=+qmp-quagga-libzebra +libreadline +libncurses
TITLE:=integrated shell for Quagga routing software
endef
define Package/qmp-quagga-zebra/conffiles
/etc/quagga/zebra.conf
endef
define Package/qmp-quagga-bgpd/conffiles
/etc/quagga/bgpd.conf
endef
define Package/qmp-quagga-isisd/conffiles
/etc/quagga/isisd.conf
endef
define Package/qmp-quagga-ospfd/conffiles
/etc/quagga/ospfd.conf
endef
define Package/qmp-quagga-ospf6d/conffiles
/etc/quagga/ospf6d.conf
endef
define Package/qmp-quagga-ripd/conffiles
/etc/quagga/ripd.conf
endef
define Package/qmp-quagga-ripngd/conffiles
/etc/quagga/ripngd.conf
endef
define Package/qmp-quagga-babeld/conffiles
/etc/quagga/babeld.conf
endef
ifneq ($(SDK),)
CONFIG_PACKAGE_qmp-quagga-libzebra:=m
CONFIG_PACKAGE_qmp-quagga-libospf:=m
CONFIG_PACKAGE_qmp-quagga-watchquagga:=m
CONFIG_PACKAGE_qmp-quagga-zebra:=m
CONFIG_PACKAGE_qmp-quagga-bgpd:=m
CONFIG_PACKAGE_qmp-quagga-isisd:=m
CONFIG_PACKAGE_qmp-quagga-ospf6d:=m
CONFIG_PACKAGE_qmp-quagga-ripd:=m
CONFIG_PACKAGE_qmp-quagga-ripngd:=m
CONFIG_PACKAGE_qmp-quagga-babeld:=m
CONFIG_PACKAGE_qmp-quagga-vtysh:=m
endif
CONFIGURE_ARGS+= \
--localstatedir=/var/run/quagga \
--sysconfdir=/etc/quagga/ \
--enable-shared \
--disable-static \
--enable-user=network \
--enable-group=network \
--enable-pie=no \
--enable-multipath=8 \
--disable-ospfclient \
--disable-capabilities \
$(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-libzebra,zebra) \
$(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-libospf,ospfd) \
$(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-bgpd,bgpd) \
$(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-isisd,isisd) \
$(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-ospf6d,ospf6d) \
$(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-ripd,ripd) \
$(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-ripngd,ripngd) \
$(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-babeld,babeld) \
$(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-vtysh,vtysh) \
MAKE_FLAGS += \
CFLAGS="$(TARGET_CFLAGS) -std=gnu99"
define Package/qmp-quagga/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) ./files/quagga $(1)/usr/sbin/quagga.init
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/quagga.init $(1)/etc/init.d/quagga
endef
define Package/qmp-quagga-watchquagga/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/watchquagga $(1)/usr/sbin/
endef
define Package/qmp-quagga-zebra/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/zebra $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/quagga
chmod 0750 $(1)/etc/quagga
$(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/zebra.conf
endef
define Package/qmp-quagga-bgpd/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/bgpd $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/quagga
chmod 0750 $(1)/etc/quagga
$(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/bgpd.conf
endef
define Package/qmp-quagga-isisd/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/isisd $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/quagga
chmod 0750 $(1)/etc/quagga
$(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/isisd.conf
endef
define Package/qmp-quagga-ospfd/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ospfd $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/quagga
chmod 0750 $(1)/etc/quagga
$(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/ospfd.conf
endef
define Package/qmp-quagga-ospf6d/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ospf6d $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/quagga
chmod 0750 $(1)/etc/quagga
$(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/ospf6d.conf
endef
define Package/qmp-quagga-ripd/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ripd $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/quagga
chmod 0750 $(1)/etc/quagga
$(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/ripd.conf
endef
define Package/qmp-quagga-ripngd/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ripngd $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/quagga
chmod 0750 $(1)/etc/quagga
$(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/ripngd.conf
endef
define Package/qmp-quagga-babeld/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/babeld $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/quagga
chmod 0750 $(1)/etc/quagga
$(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/babeld.conf
endef
define Package/qmp-quagga-vtysh/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/vtysh $(1)/usr/bin/
endef
define Package/qmp-quagga-libospf/install
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libospf.so.* $(1)/usr/lib/
endef
define Package/qmp-quagga-libzebra/install
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libzebra.so.* $(1)/usr/lib/
endef
$(eval $(call BuildPackage,qmp-quagga))
$(eval $(call BuildPackage,qmp-quagga-libzebra))
$(eval $(call BuildPackage,qmp-quagga-libospf))
$(eval $(call BuildPackage,qmp-quagga-watchquagga))
$(eval $(call BuildPackage,qmp-quagga-zebra))
$(eval $(call BuildPackage,qmp-quagga-bgpd))
$(eval $(call BuildPackage,qmp-quagga-isisd))
$(eval $(call BuildPackage,qmp-quagga-ospfd))
$(eval $(call BuildPackage,qmp-quagga-ospf6d))
$(eval $(call BuildPackage,qmp-quagga-ripd))
$(eval $(call BuildPackage,qmp-quagga-ripngd))
$(eval $(call BuildPackage,qmp-quagga-babeld))
$(eval $(call BuildPackage,qmp-quagga-vtysh))
#!/bin/sh
#
# quagga Starts/stops quagga daemons and watchquagga.
# Create a daemon.conf file to have that routing daemon
# started/stopped automagically when using this script
# without any daemon names as args.
# If watchquagga is available, it will also be
# started/stopped if the script is called without
# any daemon names.
#
ME=$(basename $0)
usage() {
echo "Usage: ${ME} {start|stop|restart} [daemon ...]"
exit 2
}
if [ -z "$1" ]
then
usage
else
COMMAND=$1
fi
shift
ARG_DAEMONS=$*
BINDIR=/usr/sbin
CONFDIR=/etc/quagga
STATEDIR=/var/run/quagga
RUNUSER=network
RUNGROUP=$RUNUSER
DAEMONS="zebra ripd ripngd ospfd ospf6d bgpd"
DAEMON_FLAGS=-d
WATCHQUAGGA_FLAGS="-d -z -T 60 -R"
WATCHQUAGGA_CMD="$0 watchrestart"
if [ ${COMMAND} != "watchrestart" ]
then
DAEMONS="${DAEMONS} watchquagga"
fi
DAEMONS_STARTSEQ=${DAEMONS}
reverse()
{
local revlist r
revlist=
for r
do
revlist="$r $revlist"
done
echo $revlist
}
DAEMONS_STOPSEQ=$(reverse ${DAEMONS_STARTSEQ})
#pidof() {
# ps ax | awk 'match($5, "(^|/)'"$1"'$") > 0 { printf " %s", $1 }'
#}
quit() {
echo "${ME}: $1"
exit 0
}
die() {
echo "${ME}: $1"
exit 1
}
is_in() {
local i
for i in $2
do
[ "$1" = "$i" ] && return 0
done
return 1
}
select_subset() {
local unknown i j
unknown=
RESULT=
for i in $1
do
is_in $i "$2" || unknown="$unknown $i"
done
if [ -n "$unknown" ]
then
RESULT=$unknown
return 1
else
for j in $2
do
is_in $j "$1" && RESULT="$RESULT $j"
done
return 0
fi
}
# check command
case ${COMMAND}
in
start|stop|restart)
;;
watchrestart)
if [ -n "$ARG_DAEMONS" ]
then
echo "${ME}: watchrestart mode is only for use by watchquagga"
exit 2
fi
;;
*)
usage
;;
esac
# select daemons to start
case ${COMMAND}
in
start|restart|watchrestart)
START_DAEMONS=
for d in ${DAEMONS_STARTSEQ}
do
[ -x "${BINDIR}/${d}" -a -f "${CONFDIR}/${d}.conf" ] \
&& START_DAEMONS="${START_DAEMONS}${d} "
done
WATCHQUAGGA_DAEMONS=${START_DAEMONS}
if is_in watchquagga "${DAEMONS_STARTSEQ}"
then
START_DAEMONS="${START_DAEMONS} watchquagga"
fi
if [ -n "${ARG_DAEMONS}" ]
then
if select_subset "${ARG_DAEMONS}" "${DAEMONS}"
then
if select_subset "${ARG_DAEMONS}" "${START_DAEMONS}"
then
START_DAEMONS=${RESULT}
else
die "these daemons are not startable:${RESULT}."
fi
else
die "unknown daemons:${RESULT}; choose from: ${DAEMONS}."
fi
fi
;;
esac
# select daemons to stop
case ${COMMAND}
in
stop|restart|watchrestart)
STOP_DAEMONS=${DAEMONS_STOPSEQ}
if [ -n "${ARG_DAEMONS}" ]
then
if select_subset "${ARG_DAEMONS}" "${STOP_DAEMONS}"
then
STOP_DAEMONS=${RESULT}
else
die "unknown daemons:${RESULT}; choose from: ${DAEMONS}."
fi
fi
stop_daemons=
for d in ${STOP_DAEMONS}
do
pidfile=${STATEDIR}/${d}.pid
if [ -f "${pidfile}" -o -n "$(pidof ${d})" ]
then
stop_daemons="${stop_daemons}${d} "
elif [ -n "${ARG_DAEMONS}" ]
then
echo "${ME}: found no ${d} process running."
fi
done
STOP_DAEMONS=${stop_daemons}
;;
esac
# stop daemons
for d in $STOP_DAEMONS
do
echo -n "${ME}: Stopping ${d} ... "
pidfile=${STATEDIR}/${d}.pid
if [ -f "${pidfile}" ]
then
file_pid=$(cat ${pidfile})
if [ -z "${file_pid}" ]
then
echo -n "no pid file entry found ... "
fi
else
file_pid=
echo -n "no pid file found ... "
fi
proc_pid=$(pidof ${d})
if [ -z "${proc_pid}" ]
then
echo -n "found no ${d} process running ... "
else
count=0
notinpidfile=
for p in ${proc_pid}
do
count=$((${count}+1))
if kill ${p}
then
echo -n "killed ${p} ... "
else
echo -n "failed to kill ${p} ... "
fi
[ "${p}" = "${file_pid}" ] \
|| notinpidfile="${notinpidfile} ${p}"
done
[ ${count} -le 1 ] \
|| echo -n "WARNING: ${count} ${d} processes were found running ... "
for n in ${notinpidfile}
do
echo -n "WARNING: process ${n} was not in pid file ... "
done
fi
count=0
survivors=$(pidof ${d})
while [ -n "${survivors}" ]
do
sleep 1
count=$((${count}+1))
survivors=$(pidof ${d})
[ -z "${survivors}" -o ${count} -gt 5 ] && break
for p in ${survivors}
do
sleep 1
echo -n "${p} "
kill ${p}
done
done
survivors=$(pidof ${d})
[ -n "${survivors}" ] && \
if kill -KILL ${survivors}
then
echo -n "KILLed ${survivors} ... "
else
echo -n "failed to KILL ${survivors} ... "
fi
sleep 1
survivors=$(pidof ${d})
if [ -z "${survivors}" ]
then
echo -n "done."
if [ -f "${pidfile}" ]
then
rm -f ${pidfile} \
|| echo -n " Failed to remove pidfile."
fi
else
echo -n "failed to stop ${survivors} - giving up."
if [ "${survivors}" != "${file_pid}" ]
then
if echo "${survivors}" > ${pidfile}
then
chown ${RUNUSER}:${RUNGROUP} ${pidfile}
echo -n " Wrote ${survivors} to pidfile."
else
echo -n " Failed to write ${survivors} to pidfile."
fi
fi
fi
echo
done
# start daemons
if [ -n "$START_DAEMONS" ]
then
[ -d ${CONFDIR} ] \
|| quit "${ME}: no config directory ${CONFDIR} - exiting."
chown -R ${RUNUSER}:${RUNGROUP} ${CONFDIR}
[ -d ${STATEDIR} ] || mkdir -p ${STATEDIR} \
|| die "${ME}: could not create state directory ${STATEDIR} - exiting."
chown -R ${RUNUSER}:${RUNGROUP} ${STATEDIR}
for d in $START_DAEMONS
do
echo -n "${ME}: Starting ${d} ... "
proc_pid=$(pidof ${d})
pidfile=${STATEDIR}/${d}.pid
file_pid=
if [ -f "${pidfile}" ]
then
file_pid=$(cat ${pidfile})
if [ -n "${file_pid}" ]
then
echo -n "found old pid file entry ${file_pid} ... "
fi
fi
if [ -n "${proc_pid}" ]
then
echo -n "found ${d} running (${proc_pid}) - skipping ${d}."
if [ "${proc_pid}" != "${file_pid}" ]
then
if echo "${proc_pid}" > ${pidfile}
then
chown ${RUNUSER}:${RUNGROUP} ${pidfile}
echo -n " Wrote ${proc_pid} to pidfile."
else
echo -n " Failed to write ${proc_pid} to pidfile."
fi
fi
elif rm -f "${pidfile}"
then
if [ "${d}" = "watchquagga" ]
then
"${BINDIR}/${d}" \
${WATCHQUAGGA_FLAGS} \
"${WATCHQUAGGA_CMD}" \
${WATCHQUAGGA_DAEMONS}
status=$?
else
"${BINDIR}/${d}" ${DAEMON_FLAGS}
status=$?
fi
if [ $status -eq 0 ]
then
echo -n "done."
else
echo -n "failed."
fi
else
echo -n " failed to remove pidfile."
fi
echo
done
fi
password zebra
!
access-list vty permit 127.0.0.0/8
access-list vty deny any
!
line vty
access-class vty
#!/bin/sh /etc/rc.common
# Copyright (C) 2006 OpenWrt.org
START=60
start() {
/usr/sbin/quagga.init start
}
stop() {
/usr/sbin/quagga.init stop
}
Add definitions for IPCTL_FORWARDING and IP6CTL_FORWARDING.
Inspired from
http://svn.gnumonks.org/trunk/grouter/build/src/quagga/quagga/quagga-0.99.1-forward_sysctl-2.6.14.patch
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
--- a/zebra/ipforward_sysctl.c
+++ b/zebra/ipforward_sysctl.c
@@ -31,6 +31,15 @@
#define MIB_SIZ 4
+/* Fix for recent (2.6.14) kernel headers */
+#ifndef IPCTL_FORWARDING
+#define IPCTL_FORWARDING NET_IPV4_FORWARD
+#endif
+
+#ifndef IP6CTL_FORWARDING
+#define IP6CTL_FORWARDING NET_IPV6_FORWARDING
+#endif
+
extern struct zebra_privs_t zserv_privs;
/* IPv4 forwarding control MIB. */
--- a/lib/log.c
+++ b/lib/log.c
@@ -929,13 +929,19 @@ proto_redistnum(int afi, const char *s)
return ZEBRA_ROUTE_STATIC;
else if (strncmp (s, "r", 1) == 0)
return ZEBRA_ROUTE_RIP;
- else if (strncmp (s, "o", 1) == 0)
+ else if (strncmp (s, "os", 2) == 0)
return ZEBRA_ROUTE_OSPF;
else if (strncmp (s, "i", 1) == 0)
return ZEBRA_ROUTE_ISIS;
else if (strncmp (s, "bg", 2) == 0)
return ZEBRA_ROUTE_BGP;
- else if (strncmp (s, "ba", 2) == 0)
+ else if (strncmp (s, "h", 1) == 0)
+ return ZEBRA_ROUTE_HSLS;
+ else if (strncmp (s, "ol", 2) == 0)
+ return ZEBRA_ROUTE_OLSR;
+ else if (strncmp (s, "bat", 3) == 0)
+ return ZEBRA_ROUTE_BATMAN;
+ else if (strncmp (s, "bab", 3) == 0)
return ZEBRA_ROUTE_BABEL;
}
if (afi == AFI_IP6)
@@ -948,13 +954,19 @@ proto_redistnum(int afi, const char *s)
return ZEBRA_ROUTE_STATIC;
else if (strncmp (s, "r", 1) == 0)
return ZEBRA_ROUTE_RIPNG;
- else if (strncmp (s, "o", 1) == 0)
+ else if (strncmp (s, "os", 2) == 0)
return ZEBRA_ROUTE_OSPF6;
else if (strncmp (s, "i", 1) == 0)
return ZEBRA_ROUTE_ISIS;
else if (strncmp (s, "bg", 2) == 0)
return ZEBRA_ROUTE_BGP;
- else if (strncmp (s, "ba", 2) == 0)
+ else if (strncmp (s, "h", 1) == 0)
+ return ZEBRA_ROUTE_HSLS;
+ else if (strncmp (s, "ol", 2) == 0)
+ return ZEBRA_ROUTE_OLSR;
+ else if (strncmp (s, "bat", 3) == 0)
+ return ZEBRA_ROUTE_BATMAN;
+ else if (strncmp (s, "bab", 3) == 0)
return ZEBRA_ROUTE_BABEL;
}
return -1;
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -51,13 +51,9 @@ ZEBRA_ROUTE_OSPF, ospf, ospfd
ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, "OSPFv6"
ZEBRA_ROUTE_ISIS, isis, isisd, 'I', 1, 1, "IS-IS"
ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP"
-# HSLS and OLSR both are AFI independent (so: 1, 1), however
-# we want to disable for them for general Quagga distribution.
-# This at least makes it trivial for users of these protocols
-# to 'switch on' redist support (direct numeric entry remaining
-# possible).
-ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, "HSLS"
-ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 0, 0, "OLSR"
+ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 1, 1, "HSLS"
+ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 1, 1, "OLSR"
+ZEBRA_ROUTE_BATMAN, batman, batmand,'b', 1, 1, "BATMAN"
ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
## help strings
@@ -72,5 +68,6 @@ ZEBRA_ROUTE_OSPF6, "Open Shortest Path
ZEBRA_ROUTE_ISIS, "Intermediate System to Intermediate System (IS-IS)"
ZEBRA_ROUTE_BGP, "Border Gateway Protocol (BGP)"
ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)"
-ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)"
+ZEBRA_ROUTE_OLSR, "Optimized Link State Routing (OLSR)"
+ZEBRA_ROUTE_BATMAN, "Better Approach to Mobile Ad-Hoc Networking (BATMAN)"
ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
--- a/ripd/rip_zebra.c
+++ b/ripd/rip_zebra.c
@@ -206,9 +206,12 @@ static struct {
{ZEBRA_ROUTE_KERNEL, 1, "kernel"},
{ZEBRA_ROUTE_CONNECT, 1, "connected"},
{ZEBRA_ROUTE_STATIC, 1, "static"},
- {ZEBRA_ROUTE_OSPF, 1, "ospf"},
+ {ZEBRA_ROUTE_OSPF, 2, "ospf"},
{ZEBRA_ROUTE_BGP, 2, "bgp"},
- {ZEBRA_ROUTE_BABEL, 2, "babel"},
+ {ZEBRA_ROUTE_HSLS, 1, "hsls"},
+ {ZEBRA_ROUTE_OLSR, 2, "olsr"},
+ {ZEBRA_ROUTE_BATMAN, 3, "batman"},
+ {ZEBRA_ROUTE_BABEL, 3, "babel"},
{0, 0, NULL}
};
--- a/ripngd/ripng_zebra.c
+++ b/ripngd/ripng_zebra.c
@@ -216,9 +216,12 @@ static struct {
{ZEBRA_ROUTE_KERNEL, 1, "kernel"},
{ZEBRA_ROUTE_CONNECT, 1, "connected"},
{ZEBRA_ROUTE_STATIC, 1, "static"},
- {ZEBRA_ROUTE_OSPF6, 1, "ospf6"},
+ {ZEBRA_ROUTE_OSPF6, 2, "ospf6"},
{ZEBRA_ROUTE_BGP, 2, "bgp"},
- {ZEBRA_ROUTE_BABEL, 2, "babel"},
+ {ZEBRA_ROUTE_HSLS, 1, "hsls"},
+ {ZEBRA_ROUTE_OLSR, 2, "olsr"},
+ {ZEBRA_ROUTE_BATMAN, 3, "batman"},
+ {ZEBRA_ROUTE_BABEL, 3, "babel"},
{0, 0, NULL}
};
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -1623,6 +1623,9 @@ netlink_route_multipath (int cmd, struct
addattr_l (&req.n, sizeof req, RTA_PREFSRC,
&nexthop->src.ipv4, bytelen);
+ if (rib->type == ZEBRA_ROUTE_OLSR)
+ req.r.rtm_scope = RT_SCOPE_LINK;
+
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("netlink_route_multipath() (single hop): "
"nexthop via if %u", nexthop->ifindex);
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -67,6 +67,9 @@ static const struct
[ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110},
[ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115},
[ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */},
+ [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 0},
+ [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 0},
+ [ZEBRA_ROUTE_BATMAN] = {ZEBRA_ROUTE_BATMAN, 0},
[ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 95},
/* no entry/default: 150 */
};
@@ -403,6 +406,18 @@ nexthop_active_ipv4 (struct rib *rib, st
}
return 0;
}
+ else if (match->type == ZEBRA_ROUTE_OLSR)
+ {
+ for (newhop = match->nexthop; newhop; newhop = newhop->next)
+ if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
+ && newhop->type == NEXTHOP_TYPE_IFINDEX)
+ {
+ if (nexthop->type == NEXTHOP_TYPE_IPV4)
+ nexthop->ifindex = newhop->ifindex;
+ return 1;
+ }
+ return 0;
+ }
else
{
return 0;
@@ -507,6 +522,18 @@ nexthop_active_ipv6 (struct rib *rib, st
}
return 0;
}
+ else if (match->type == ZEBRA_ROUTE_OLSR)
+ {
+ for (newhop = match->nexthop; newhop; newhop = newhop->next)
+ if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
+ && newhop->type == NEXTHOP_TYPE_IFINDEX)
+ {
+ if (nexthop->type == NEXTHOP_TYPE_IPV6)
+ nexthop->ifindex = newhop->ifindex;
+ return 1;
+ }
+ return 0;
+ }
else
{
return 0;
@@ -1236,6 +1263,8 @@ static const u_char meta_queue_map[ZEBRA
[ZEBRA_ROUTE_ISIS] = 2,
[ZEBRA_ROUTE_BGP] = 3,
[ZEBRA_ROUTE_HSLS] = 4,
+ [ZEBRA_ROUTE_OLSR] = 4,
+ [ZEBRA_ROUTE_BATMAN] = 4,
[ZEBRA_ROUTE_BABEL] = 2,
};
--- a/zebra/zebra_snmp.c
+++ b/zebra/zebra_snmp.c
@@ -251,6 +251,12 @@ proto_trans(int type)
return 1; /* shouldn't happen */
case ZEBRA_ROUTE_BGP:
return 14; /* bgp */
+ case ZEBRA_ROUTE_HSLS:
+ return 1; /* other */
+ case ZEBRA_ROUTE_OLSR:
+ return 1; /* other */
+ case ZEBRA_ROUTE_BATMAN:
+ return 1; /* other */
default:
return 1; /* other */
}
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -558,7 +558,10 @@ vty_show_ip_route_detail (struct vty *vt
|| rib->type == ZEBRA_ROUTE_OSPF
|| rib->type == ZEBRA_ROUTE_BABEL
|| rib->type == ZEBRA_ROUTE_ISIS
- || rib->type == ZEBRA_ROUTE_BGP)
+ || rib->type == ZEBRA_ROUTE_BGP
+ || rib->type == ZEBRA_ROUTE_HSLS
+ || rib->type == ZEBRA_ROUTE_OLSR
+ || rib->type == ZEBRA_ROUTE_BATMAN)
{
time_t uptime;
struct tm *tm;
@@ -777,7 +780,10 @@ vty_show_ip_route (struct vty *vty, stru
|| rib->type == ZEBRA_ROUTE_OSPF
|| rib->type == ZEBRA_ROUTE_BABEL
|| rib->type == ZEBRA_ROUTE_ISIS
- || rib->type == ZEBRA_ROUTE_BGP)
+ || rib->type == ZEBRA_ROUTE_BGP
+ || rib->type == ZEBRA_ROUTE_HSLS
+ || rib->type == ZEBRA_ROUTE_OLSR
+ || rib->type == ZEBRA_ROUTE_BATMAN)
{
time_t uptime;
struct tm *tm;
@@ -1536,7 +1542,10 @@ vty_show_ipv6_route_detail (struct vty *
|| rib->type == ZEBRA_ROUTE_OSPF6
|| rib->type == ZEBRA_ROUTE_BABEL
|| rib->type == ZEBRA_ROUTE_ISIS
- || rib->type == ZEBRA_ROUTE_BGP)
+ || rib->type == ZEBRA_ROUTE_BGP
+ || rib->type == ZEBRA_ROUTE_HSLS
+ || rib->type == ZEBRA_ROUTE_OLSR
+ || rib->type == ZEBRA_ROUTE_BATMAN)
{
time_t uptime;
struct tm *tm;
@@ -1716,7 +1725,10 @@ vty_show_ipv6_route (struct vty *vty, st
|| rib->type == ZEBRA_ROUTE_OSPF6
|| rib->type == ZEBRA_ROUTE_BABEL
|| rib->type == ZEBRA_ROUTE_ISIS
- || rib->type == ZEBRA_ROUTE_BGP)
+ || rib->type == ZEBRA_ROUTE_BGP
+ || rib->type == ZEBRA_ROUTE_HSLS
+ || rib->type == ZEBRA_ROUTE_OLSR
+ || rib->type == ZEBRA_ROUTE_BATMAN)
{
time_t uptime;
struct tm *tm;
--- a/lib/log.c
+++ b/lib/log.c
@@ -941,6 +941,8 @@ proto_redistnum(int afi, const char *s)
return ZEBRA_ROUTE_OLSR;
else if (strncmp (s, "bat", 3) == 0)
return ZEBRA_ROUTE_BATMAN;
+ else if (strncmp (s, "bmx", 3) == 0)
+ return ZEBRA_ROUTE_BMX6;
else if (strncmp (s, "bab", 3) == 0)
return ZEBRA_ROUTE_BABEL;
}
@@ -966,6 +968,8 @@ proto_redistnum(int afi, const char *s)
return ZEBRA_ROUTE_OLSR;
else if (strncmp (s, "bat", 3) == 0)
return ZEBRA_ROUTE_BATMAN;
+ else if (strncmp (s, "bmx", 3) == 0)
+ return ZEBRA_ROUTE_BMX6;
else if (strncmp (s, "bab", 3) == 0)
return ZEBRA_ROUTE_BABEL;
}
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -54,6 +54,7 @@ ZEBRA_ROUTE_BGP, bgp, bgpd,
ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 1, 1, "HSLS"
ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 1, 1, "OLSR"
ZEBRA_ROUTE_BATMAN, batman, batmand,'b', 1, 1, "BATMAN"
+ZEBRA_ROUTE_BMX6, bmx6, bmx6, 'x', 1, 1, "BMX6"
ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
## help strings
@@ -70,4 +71,5 @@ ZEBRA_ROUTE_BGP, "Border Gateway Prot
ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)"
ZEBRA_ROUTE_OLSR, "Optimized Link State Routing (OLSR)"
ZEBRA_ROUTE_BATMAN, "Better Approach to Mobile Ad-Hoc Networking (BATMAN)"
+ZEBRA_ROUTE_BMX6, "BMX6 networking protocol"
ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
--- a/ripd/rip_zebra.c
+++ b/ripd/rip_zebra.c
@@ -211,6 +211,7 @@ static struct {
{ZEBRA_ROUTE_HSLS, 1, "hsls"},
{ZEBRA_ROUTE_OLSR, 2, "olsr"},
{ZEBRA_ROUTE_BATMAN, 3, "batman"},
+ {ZEBRA_ROUTE_BMX6, 3, "bmx6"},
{ZEBRA_ROUTE_BABEL, 3, "babel"},
{0, 0, NULL}
};
--- a/ripngd/ripng_zebra.c
+++ b/ripngd/ripng_zebra.c
@@ -221,6 +221,7 @@ static struct {
{ZEBRA_ROUTE_HSLS, 1, "hsls"},
{ZEBRA_ROUTE_OLSR, 2, "olsr"},
{ZEBRA_ROUTE_BATMAN, 3, "batman"},
+ {ZEBRA_ROUTE_BMX6, 3, "bmx6"},
{ZEBRA_ROUTE_BABEL, 3, "babel"},
{0, 0, NULL}
};
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -70,6 +70,7 @@ static const struct
[ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 0},
[ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 0},
[ZEBRA_ROUTE_BATMAN] = {ZEBRA_ROUTE_BATMAN, 0},
+ [ZEBRA_ROUTE_BMX6] = {ZEBRA_ROUTE_BMX6, 0},
[ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 95},
/* no entry/default: 150 */
};
@@ -1265,6 +1266,7 @@ static const u_char meta_queue_map[ZEBRA
[ZEBRA_ROUTE_HSLS] = 4,
[ZEBRA_ROUTE_OLSR] = 4,
[ZEBRA_ROUTE_BATMAN] = 4,
+ [ZEBRA_ROUTE_BMX6] = 4,
[ZEBRA_ROUTE_BABEL] = 2,
};
--- a/zebra/zebra_snmp.c
+++ b/zebra/zebra_snmp.c
@@ -257,6 +257,8 @@ proto_trans(int type)
return 1; /* other */
case ZEBRA_ROUTE_BATMAN:
return 1; /* other */
+ case ZEBRA_ROUTE_BMX6:
+ return 1; /* other */
default:
return 1; /* other */
}
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -561,7 +561,8 @@ vty_show_ip_route_detail (struct vty *vt
|| rib->type == ZEBRA_ROUTE_BGP
|| rib->type == ZEBRA_ROUTE_HSLS
|| rib->type == ZEBRA_ROUTE_OLSR
- || rib->type == ZEBRA_ROUTE_BATMAN)
+ || rib->type == ZEBRA_ROUTE_BATMAN
+ || rib->type == ZEBRA_ROUTE_BMX6)
{
time_t uptime;
struct tm *tm;
@@ -783,7 +784,8 @@ vty_show_ip_route (struct vty *vty, stru
|| rib->type == ZEBRA_ROUTE_BGP
|| rib->type == ZEBRA_ROUTE_HSLS
|| rib->type == ZEBRA_ROUTE_OLSR
- || rib->type == ZEBRA_ROUTE_BATMAN)
+ || rib->type == ZEBRA_ROUTE_BATMAN
+ || rib->type == ZEBRA_ROUTE_BMX6)
{
time_t uptime;
struct tm *tm;
@@ -1545,7 +1547,8 @@ vty_show_ipv6_route_detail (struct vty *
|| rib->type == ZEBRA_ROUTE_BGP
|| rib->type == ZEBRA_ROUTE_HSLS
|| rib->type == ZEBRA_ROUTE_OLSR
- || rib->type == ZEBRA_ROUTE_BATMAN)
+ || rib->type == ZEBRA_ROUTE_BATMAN
+ || rib->type == ZEBRA_ROUTE_BMX6)
{
time_t uptime;
struct tm *tm;
@@ -1728,7 +1731,8 @@ vty_show_ipv6_route (struct vty *vty, st
|| rib->type == ZEBRA_ROUTE_BGP
|| rib->type == ZEBRA_ROUTE_HSLS
|| rib->type == ZEBRA_ROUTE_OLSR
- || rib->type == ZEBRA_ROUTE_BATMAN)
+ || rib->type == ZEBRA_ROUTE_BATMAN
+ || rib->type == ZEBRA_ROUTE_BMX6)
{
time_t uptime;
struct tm *tm;
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -63,7 +63,7 @@ $ignore{'"show history"'} = "ignore";
foreach (@ARGV) {
$file = $_;
- open (FH, "cpp -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_srcdir@/isisd/topology @SNMP_INCLUDES@ @CPPFLAGS@ $file |");
+ open (FH, "@CPP@ -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_srcdir@/isisd/topology @SNMP_INCLUDES@ @CPPFLAGS@ $file |");
local $/; undef $/;
$line = <FH>;
close (FH);
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -193,8 +193,7 @@ bgp_accept (struct thread *thread)
peer->fd = bgp_sock;
peer->status = Active;
peer->local_id = peer1->local_id;
- peer->v_holdtime = peer1->v_holdtime;
- peer->v_keepalive = peer1->v_keepalive;
+ peer->v_holdtime = BGP_LARGE_HOLDTIME;
/* Make peer's address string. */
sockunion2str (&su, buf, SU_ADDRSTRLEN);
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -718,6 +718,7 @@ struct bgp_nlri
/* BGP timers default value. */
#define BGP_INIT_START_TIMER 5
#define BGP_ERROR_START_TIMER 30
+#define BGP_LARGE_HOLDTIME 240
#define BGP_DEFAULT_HOLDTIME 180
#define BGP_DEFAULT_KEEPALIVE 60
#define BGP_DEFAULT_ASORIGINATE 15
--- a/lib/command.c
+++ b/lib/command.c
@@ -2601,6 +2601,13 @@ DEFUN (config_write_file,
VTY_NEWLINE);
goto finished;
}
+
+#if 0
+ /* This code fails on UNION MOUNTs and similar filesystems if the
+ * config file is still on the RO layer. Hardlinks across layers
+ * will not work and cause quagga to fail saving the configuration...
+ * should use rename() to move files around...
+ */
if (link (config_file, config_file_sav) != 0)
{
vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
@@ -2614,7 +2621,23 @@ DEFUN (config_write_file,
VTY_NEWLINE);
goto finished;
}
+#else
+ /* And this is the code that hopefully does work */
+ if (rename (config_file, config_file_sav) != 0)
+ {
+ vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
+ VTY_NEWLINE);
+ goto finished;
+ }
+ sync ();
+#endif
+
+#if 0
+ /* same here. Please no cross-filesystem hardlinks... */
if (link (config_file_tmp, config_file) != 0)
+#else
+ if (rename (config_file_tmp, config_file) != 0)
+#endif
{
vty_out (vty, "Can't save configuration file %s.%s", config_file,
VTY_NEWLINE);
From: Josh Karlin <karlinjf@cs.unm.edu>
Date: Mon, 18 Aug 2008 13:17:21 +0000 (+0100)
Subject: [bgp] Add support for Pretty-Good BGP
X-Git-Url: http://git.ozo.com/?p=quagga-pgbg.git;a=commitdiff_plain;h=c2ee55705cad607f4b86ff143f7af92d538dc946
[bgp] Add support for Pretty-Good BGP
2008-7-7 Josh Karlin <karlinjf@cs.unm.edu>
* bgpd/bgp_pgbgp.c: Added file
* bgpd/bgp_pgbgp.h: Added file
* bgpd/Makefile.am: Added bgp_pgbgp.h and bgp_pgbgp.c
* bgpd/bgp_aspath.h: Externed the hash of as paths (ashash)
* bgpd/bgp_route.c: . Added PGBGP depref check to decision process.
. Informs PGBGP of new updates and selected routes
. Added anomaly status for show ip bgp
. Added PGBGP commands
* bgpd/bgp_route.h: Added suspicious route flags
* bgpd/bgp_table.h: Added PGBGP history pointer to struct bgp_node
* bgpd/bgpd.h: Defined BGP_CONFIG_PGBGP
* lib/hash.c: Added "hash_iterate_until" to be able to break out
* lib/hash.h: Definition for "hash_iterate_until"
* lib/memtypes.c: Added PGBGP memory types
---
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -15,14 +15,14 @@ libbgp_a_SOURCES = \
bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \
bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
- bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c
+ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c bgp_pgbgp.c
noinst_HEADERS = \
bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \
bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
- bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h
+ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_pgbgp.h
bgpd_SOURCES = bgp_main.c
bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@
--- /dev/null
+++ b/bgpd/bgp_pgbgp.c
@@ -0,0 +1,2401 @@
+/*
+ BGP Pretty Good BGP
+ Copyright (C) 2008 University of New Mexico (Josh Karlin)
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+*/
+
+/*
+ Quagga based Pretty Good BGP:
+
+ Summary
+ -------
+ Pretty Good BGP (PGBGP) is a soft security enhancement to BGP.
+ It uses independently collected (therefore completely distributed)
+ historical routing information to determine network topology and
+ prefix ownership. Abberations to the historical database are considered
+ anomalous and avoided when possible.
+
+ What PGBGP can protect against: prefix hijacks, sub-prefix hijacks, and
+ spoofed edges.
+
+ Further reading is available at http://cs.unm.edu/~karlinjf/pgbgp/
+
+ Route updates are forwarded to PGBGP, which determines if the route
+ is anomalous. Anomalous routes are flagged as suspicious and
+ avoided where feasible for 24 hours. If the anomalous
+ characteristic is still in the RIB after 24 hours, consider it valid
+ and enter it into the normal database.
+
+ Cases for anomalous routes
+ --------------------------
+ case 1) New origin AS - prefix pair (one not recently seen in the RIB):
+ response) label the route with BGP_INFO_SUSPICIOUS_O and avoid for 24 hours if possible
+
+ case 2) New edge in path (one not recently seen in the RIB):
+ response) label the route with BGP_INFO_SUSPICIOUS_E and avoid for 24 hours
+ if possible
+
+ case 3) New prefix that is a sub-prefix of a prefix in recent history
+ and that path differs from the current less-specific's path
+ response) label the sub-prefix routes with BGP_INFO_IGNORED_P and
+ prevent it from entering FIB for 24 hours
+ response) label the super-net routes from the same next-hop as BGP_INFO_SUSPICIOUS_P
+ and try to avoid it for 24 hours if possible
+ response) while no super-net route is selected, remove the BGP_INFO_IGNORED_P flags
+
+
+ Normal Database (history)
+ -------------------------
+ Recently Seen) A route characteristic (edge, prefix/origin pair, prefix)
+ that has resided within the RIB within the last X hours
+ where X is user defined for each characteristic.
+ Storage) Prefix and Origin history are stored in bgp_node structs with the
+ "hist" pointer.
+ Edge information is stored in a separate hash table, where the edge
+ is the key to the hash.
+ Updates) The history's primary function is the keep track of when each route
+ characteristic was last seen. For each route announcement, update
+ the history's 'last seen' time. Periodically run the garbage collector
+ which updates 'last seen' times for objects currently in the RIB.
+
+ Garbage Collection
+ ------------------
+ Periodically the garbage collector (gc) is called to remove stale history
+ information and update the lastSeen time of objects that reside in the RIB
+ at the time of collection. This is relatively expensive as it walks
+ the RIB as well as the list of AS paths.
+
+ What is removed) Objects that have not been seen in the RIB within a user-defined
+ time.
+ Suspicious objcets that are 24 hours old that have not been in the RIB
+ since the last collection.
+
+ Reuse Priority Queue
+ --------------------
+ After 24 hours, routes that are flagged as suspicious have the flags removed.
+ This is not run on a timer. Instead, for each update that PGBGP is informed of,
+ it checks the reuse queue to determine if any routes need to be updated.
+
+*/
+
+
+/*
+ Things that must be ensured:
+ . GC updates lastSeen so it must be called at least twice as often as the lowest BUFFER_TIME
+ . GC should be called at least twice per day
+ . Delay times must be shorter than history window lengths
+*/
+
+
+/*
+ Changes made to original PGBGP thinking
+ . Don't check for things in the RIB all of the time, periodically
+ update the lastSeen values and just use lastSeen
+*/
+
+/*
+ Changes made to original protocol
+ . sub-prefixes are only ignored while the super-net has a selected
+ route and it's non-anomalous (not to a neighbor that announced
+ the sub-prefix)
+
+ . At point of reuse, don't delete the item if it's not in the RIB.
+ delete it if it hasn't been in the RIB since the last storage.
+ This saves a lot of processing time for new edges
+
+ . Changed heuristic from "if new sub-prefix and trusted AS on path
+ then it's okay" to "if new sub-prefix and same path is used to reach
+ super-prefix, then it's okay". Might be better to change to "if old
+ path is prefix of new path, then okay"
+*/
+
+#include <zebra.h>
+#include <math.h>
+
+#include "prefix.h"
+#include "memory.h"
+#include "command.h"
+#include "log.h"
+#include "pqueue.h"
+#include "table.h"
+#include "hash.h"
+#include "str.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_pgbgp.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_advertise.h"
+
+
+#define true 1
+#define false 0
+
+struct hash * ashash;
+
+static void *edge_hash_alloc (void *arg);
+static unsigned int edge_key_make (void *p);
+static int edge_cmp (const void *arg1, const void *args);
+
+// Helper Functions
+static struct bgp_pgbgp_pathSet bgp_pgbgp_pathOrigin (struct aspath *);
+static int bgp_pgbgp_pathLength (struct aspath *asp);
+static int bgp_pgbgp_gc (struct bgp_table *);
+static int bgp_pgbgp_clean (struct bgp_table *);
+static int bgp_pgbgp_reuse (time_t);
+static struct bgp_node *findSuper (struct bgp_table *table, struct prefix *p,
+ time_t t_now);
+static int bgp_pgbgp_store (struct bgp_table *table);
+static int bgp_pgbgp_restore (void);
+static struct bgp_info *bgp_pgbgp_selected (struct bgp_node *node);
+static int originInRIB (struct bgp_node *node, struct bgp_pgbgp_origin *origin);
+static int prefixInRIB (struct bgp_node *node, struct bgp_pgbgp_prefix *prefix);
+static int edgeInRIB (struct bgp_pgbgp_edge *e);
+
+// MOAS Functions
+static void bgp_pgbgp_logOriginAnomaly (as_t asn, struct bgp_node *rn,
+ struct attr *);
+static int bgp_pgbgp_reuseOrigin (struct bgp_pgbgp_r_origin);
+static void bgp_pgbgp_cleanHistTable (struct bgp_table *);
+static int bgp_pgbgp_garbageCollectHistTable (struct bgp_table *);
+static void bgp_pgbgp_storeHistTable (struct bgp_table *table, FILE * file);
+static int bgp_pgbgp_updateOrigin (struct bgp_pgbgp_hist *, struct bgp_info *,
+ struct attr *, struct bgp_node *, time_t, int);
+
+
+// Sub-Prefix Hijack Detector Functions
+static int bgp_pgbgp_shouldIgnore (struct bgp_node *super, struct bgp_info *selected);
+static void bgp_pgbgp_logSubprefixAnomaly (as_t asn, struct bgp_node *rn,
+ struct attr *, struct bgp_node *super);
+static int bgp_pgbgp_reusePrefix (struct bgp_pgbgp_r_prefix);
+static int bgp_pgbgp_updatePrefix (struct bgp_pgbgp_hist *hist, struct bgp_node *,
+ struct bgp_info *, struct attr *,
+ struct bgp_node *, time_t, int);
+
+
+// Spoofed Edge Detector Functions
+static void bgp_pgbgp_cleanEdges (void);
+static void bgp_pgbgp_logEdgeAnomaly (struct bgp_node *rn, struct attr *,
+ struct edge *edge);
+static int bgp_pgbgp_reuseEdge (struct bgp_pgbgp_r_edge);
+static void bgp_pgbgp_storeEdges (struct bgp_table *, FILE *);
+static int bgp_pgbgp_garbageCollectEdges (struct bgp_table *);
+static int bgp_pgbgp_updateEdge (struct bgp_pgbgp_hist *hist, struct bgp_info *,
+ struct attr *, struct bgp_node *, time_t, int);
+static int bgp_pgbgp_restoreEdge (FILE * file);
+static void bgp_pgbgp_storeEdges (struct bgp_table *table, FILE * file);
+
+
+
+// New Peer Detector Functions
+static int bgp_pgbgp_updatePeer (struct bgp_info *binfo, time_t now);
+
+
+/* --------------- Global Variables ------------------ */
+struct bgp_pgbgp_config bgp_pgbgp_cfg;
+struct bgp_pgbgp_config *pgbgp = &bgp_pgbgp_cfg;
+/*! --------------- Global Variables ------------------ !*/
+
+/* --------------- VTY (others exist in bgp_route.c) ------------------ */
+
+struct nsearch
+{
+ struct vty *pvty;
+ time_t time;
+ as_t asn;
+};
+
+static void
+edge_neighbor_iterator (struct hash_backet *backet, struct nsearch *pns)
+{
+ struct bgp_pgbgp_edge *hedge = backet->data;
+ if ((hedge->e.a == pns->asn || hedge->e.b == pns->asn)
+ && hedge->e.a != hedge->e.b)
+ {
+ struct vty *vty = pns->pvty;
+ if (hedge->deprefUntil > pns->time)
+ vty_out (pns->pvty, "Untrusted: %d -- %d%s", hedge->e.a, hedge->e.b,
+ VTY_NEWLINE);
+ else
+ vty_out (pns->pvty, "Trusted: %d -- %d%s", hedge->e.a, hedge->e.b,
+ VTY_NEWLINE);
+ }
+}
+
+static int
+bgp_pgbgp_stats_neighbors (struct vty *vty, afi_t afi, safi_t safi, as_t asn)
+{
+ struct nsearch ns;
+ ns.pvty = vty;
+ ns.time = time (NULL);
+ ns.asn = asn;
+
+ hash_iterate (pgbgp->edgeT,
+ (void (*)(struct hash_backet *, void *))
+ edge_neighbor_iterator, &ns);
+ return CMD_SUCCESS;
+}
+
+static int
+bgp_pgbgp_stats_origins (struct vty *vty, afi_t afi, safi_t safi,
+ const char *prefix)
+{
+ struct bgp *bgp;
+ struct bgp_table *table;
+ time_t t_now = time (NULL);
+ bgp = bgp_get_default ();
+ if (bgp == NULL)
+ return CMD_WARNING;
+ if (bgp->rib == NULL)
+ return CMD_WARNING;
+ table = bgp->rib[afi][safi];
+ if (table == NULL)
+ return CMD_WARNING;
+
+ struct prefix p;
+ str2prefix (prefix, &p);
+ struct bgp_node *rn = bgp_node_match (table, &p);
+ vty_out (vty, "%s%s", prefix, VTY_NEWLINE);
+ if (rn)
+ {
+ if (rn->hist)
+ {
+ for (struct bgp_pgbgp_origin * cur = rn->hist->o; cur != NULL;
+ cur = cur->next)
+ {
+ if (cur->deprefUntil > t_now)
+ vty_out (vty, "Untrusted Origin AS: %d%s", cur->originAS,
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "Trusted Origin AS: %d%s", cur->originAS,
+ VTY_NEWLINE);
+ }
+ }
+ bgp_unlock_node (rn);
+ }
+ return CMD_SUCCESS;
+}
+
+static int
+bgp_pgbgp_stats (struct vty *vty, afi_t afi, safi_t safi)
+{
+ struct bgp *bgp;
+ struct bgp_table *table;
+
+
+ bgp = bgp_get_default ();
+ if (bgp == NULL)
+ return CMD_WARNING;
+ if (bgp->rib == NULL)
+ return CMD_WARNING;
+ table = bgp->rib[afi][safi];
+ if (table == NULL)
+ return CMD_WARNING;
+
+ // bgp_pgbgp_store(table);
+
+ // Print out the number of anomalous routes
+ int anomalous = 0;
+ int routes = 0;
+ int num_selected = 0;
+ int num_origin = 0;
+ int num_super = 0;
+ int num_ignored = 0;
+ int num_edge = 0;
+
+ for (struct bgp_node * rn = bgp_table_top (table); rn;
+ rn = bgp_route_next (rn))
+ {
+ for (struct bgp_info * ri = rn->info; ri; ri = ri->next)
+ {
+ routes += 1;
+ if (ANOMALOUS (ri->flags))
+ {
+ anomalous += 1;
+ if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
+ num_selected += 1;
+
+ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O))
+ num_origin += 1;
+ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_E))
+ num_edge += 1;
+ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_P))
+ num_super += 1;
+ if (CHECK_FLAG (ri->flags, BGP_INFO_IGNORED_P))
+ num_ignored += 1;
+ }
+ }
+ }
+
+ vty_out (vty, "%-30s: %10d%s", "Routes in the RIB", routes, VTY_NEWLINE);
+ vty_out (vty, "%-30s: %10d%s", "Anomalous routes in RIB", anomalous,
+ VTY_NEWLINE);
+ vty_out (vty, "%-30s: %10d%s", "Selected anomalous routes", num_selected,
+ VTY_NEWLINE);
+ vty_out (vty, "-----------------------------%s", VTY_NEWLINE);
+ vty_out (vty, "%-30s: %10d%s", "Routes with anomalous origins", num_origin,
+ VTY_NEWLINE);
+ vty_out (vty, "%-30s: %10d%s", "Routes with anomalous edges", num_edge,
+ VTY_NEWLINE);
+ vty_out (vty, "%-30s: %10d%s", "Routes ignored for sub-prefix", num_ignored,
+ VTY_NEWLINE);
+ vty_out (vty, "%-30s: %10d%s", "Less specific routes to avoid", num_super,
+ VTY_NEWLINE);
+ /*
+ vty_out (vty, "There are %d routes in the RIB.%s", routes, VTY_NEWLINE);
+ vty_out (vty, "%d are anomalous.%s", anomalous, VTY_NEWLINE);
+ vty_out (vty, "%d anomalous routes are selected.%s", num_selected, VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "Anomaly breakdown:%s", VTY_NEWLINE);
+ vty_out (vty, "%d contain anomalous origins%s", num_origin, VTY_NEWLINE);
+ vty_out (vty, "%d contain anomalous edges.%s", num_edge, VTY_NEWLINE);
+ vty_out (vty, "%d are for ignored sub-prefixes.%s", num_ignored, VTY_NEWLINE);
+ vty_out (vty, "%d are super-net routes through peers that announced anomalous sub-prefixes.%s", num_super, VTY_NEWLINE);
+ */
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (show_ip_bgp_pgbgp,
+ show_ip_bgp_pgbgp_cmd,
+ "show ip bgp pgbgp",
+ SHOW_STR IP_STR BGP_STR "Display PGBGP statistics\n")
+{
+ return bgp_pgbgp_stats (vty, AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_ip_bgp_pgbgp_neighbors,
+ show_ip_bgp_pgbgp_neighbors_cmd,
+ "show ip bgp pgbgp neighbors WORD",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "BGP pgbgp\n"
+ "BGP pgbgp neighbors\n" "ASN whos neighbors should be displayed\n")
+{
+ return bgp_pgbgp_stats_neighbors (vty, AFI_IP, SAFI_UNICAST,
+ atoi (argv[0]));
+}
+
+DEFUN (show_ip_bgp_pgbgp_origins,
+ show_ip_bgp_pgbgp_origins_cmd,
+ "show ip bgp pgbgp origins A.B.C.D/M",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "BGP pgbgp\n"
+ "BGP pgbgp neighbors\n" "Prefix to look up origin ASes of\n")
+{
+ return bgp_pgbgp_stats_origins (vty, AFI_IP, SAFI_UNICAST, argv[0]);
+}
+
+
+
+
+/*! --------------- VTY (others exist in bgp_route.c) ------------------ !*/
+
+
+
+
+
+
+
+/* --------------- Helper Functions ------------------ */
+/*
+ If the origin hasn't been seen/verified lately, look for it in the RIB
+*/
+int
+originInRIB (struct bgp_node *node, struct bgp_pgbgp_origin *origin)
+{
+ for (struct bgp_info * ri = node->info; ri; ri = ri->next)
+ {
+ struct bgp_pgbgp_pathSet pathOrigins;
+ pathOrigins = bgp_pgbgp_pathOrigin (ri->attr->aspath);
+ for (int i = 0; i < pathOrigins.length; ++i)
+ {
+ if (pathOrigins.ases[i] == origin->originAS)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+/*
+ If the prefix hasn't been seen/verified lately, look for it in the RIB
+*/
+int
+prefixInRIB (struct bgp_node *node, struct bgp_pgbgp_prefix *prefix)
+{
+ if (node->info)
+ return true;
+ return false;
+}
+
+static int
+edge_inRIB_iterator (struct hash_backet *backet, struct bgp_pgbgp_edge *hedge)
+{
+ struct aspath *p = backet->data;
+ char first = true;
+ struct edge curEdge;
+ curEdge.a = 0;
+ curEdge.b = 0;
+
+ struct assegment *seg;
+
+ for (seg = p->segments; seg; seg = seg->next)
+ {
+ for (int i = 0; i < seg->length; i++)
+ {
+ curEdge.a = curEdge.b;
+ curEdge.b = seg->as[i];
+ if (first)
+ {
+ first = false;
+ continue;
+ }
+ // Is this the edge we're looking for?
+ if (curEdge.a == hedge->e.a && curEdge.b == hedge->e.b)
+ {
+ hedge->lastSeen = time (NULL);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/*
+ If the edge hasn't been seen/verified lately, look for it in the AS path list
+ This function is expensive, use sparingly
+*/
+int
+edgeInRIB (struct bgp_pgbgp_edge *e)
+{
+ int completed;
+ completed = hash_iterate_until (ashash,
+ (int (*)(struct hash_backet *, void *))
+ edge_inRIB_iterator, e);
+ if (completed)
+ return false;
+
+ return true;
+}
+
+
+
+/*
+ Return the selected route for the given route node
+ */
+
+struct bgp_info *
+bgp_pgbgp_selected (struct bgp_node *node)
+{
+ for (struct bgp_info * ri = node->info; ri; ri = ri->next)
+ {
+ if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
+ return ri;
+ }
+ return NULL;
+}
+
+static int
+reuse_cmp (void *node1, void *node2)
+{
+ struct bgp_pgbgp_reuse *a;
+ struct bgp_pgbgp_reuse *b;
+ a = (struct bgp_pgbgp_reuse *) node1;
+ b = (struct bgp_pgbgp_reuse *) node2;
+ return a->deprefUntil - b->deprefUntil;
+}
+
+int
+bgp_pgbgp_pathLength (struct aspath *asp)
+{
+ struct assegment *seg;
+ if ((asp == NULL) || (asp->segments == NULL))
+ return 0;
+ int count = 0;
+ seg = asp->segments;
+ while (seg->next != NULL)
+ {
+ count += seg->length;
+ seg = seg->next;
+ }
+ return count;
+}
+
+
+
+/* Find the origin(s) of the path
+ All ASes in the final set are considered origins */
+static struct bgp_pgbgp_pathSet
+bgp_pgbgp_pathOrigin (struct aspath *asp)
+{
+ struct assegment *seg, *last;
+ struct bgp_pgbgp_pathSet tmp;
+ tmp.length = 0;
+ tmp.ases = NULL;
+
+ assert (asp != NULL && asp->segments != NULL);
+
+ /* if ( (asp == NULL) || (asp->segments == NULL) )
+ return tmp;
+ */
+ seg = asp->segments;
+ last = NULL;
+ while (seg->next != NULL)
+ {
+ if (seg->type != AS_SET && seg->type != AS_CONFED_SET)
+ last = seg;
+ seg = seg->next;
+ }
+
+ if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
+ seg = last;
+
+ assert (seg);
+ tmp.length = 1;
+ tmp.ases = &seg->as[seg->length - 1];
+
+ /*
+ if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
+ {
+ tmp.length = seg->length;
+ tmp.ases = seg->as;
+ }
+ else
+ {
+ tmp.length = 1;
+ tmp.ases = &seg->as[seg->length - 1];
+ }
+ */
+ assert (tmp.length >= 1);
+ return tmp;
+ // return seg->as[seg->length-1];
+}
+
+int
+bgp_pgbgp_reuse (time_t t_now)
+{
+
+ struct bgp_pgbgp_reuse *cur = NULL;
+
+ while (pgbgp->rq_size > 0)
+ {
+ cur = pqueue_dequeue (pgbgp->reuse_q);
+ pgbgp->rq_size -= 1;
+
+ // Is the next item ready to be reused?
+ if (t_now < cur->deprefUntil)
+ {
+ pqueue_enqueue (cur, pgbgp->reuse_q);
+ pgbgp->rq_size += 1;
+ break;
+ }
+
+ // Okay, it needs to be reused now
+ if (cur->type == PGBGP_REUSE_ORIGIN)
+ bgp_pgbgp_reuseOrigin (cur->data.origin);
+
+ else if (cur->type == PGBGP_REUSE_PREFIX)
+ bgp_pgbgp_reusePrefix (cur->data.prefix);
+
+ else if (cur->type == PGBGP_REUSE_EDGE)
+ bgp_pgbgp_reuseEdge (cur->data.edge);
+
+
+ XFREE (MTYPE_BGP_PGBGP_REUSE, cur);
+ }
+ return 0;
+}
+
+/* Check bit of the prefix. */
+static int
+check_bit (u_char * prefix, u_char prefixlen)
+{
+ int offset;
+ int shift;
+ u_char *p = (u_char *) prefix;
+
+ assert (prefixlen <= 128);
+
+ offset = prefixlen / 8;
+ shift = 7 - (prefixlen % 8);
+
+ return (p[offset] >> shift & 1);
+}
+
+/*
+ Find a super-net in the tree that's not currently anomalous if one exists
+*/
+struct bgp_node *
+findSuper (struct bgp_table *table, struct prefix *p, time_t t_now)
+{
+ struct bgp_node *node;
+ struct bgp_node *matched;
+
+ matched = NULL;
+ node = table->top;
+
+ while (node && node->p.prefixlen < p->prefixlen &&
+ prefix_match (&node->p, p))
+ {
+ // Node may not yet have its info set when reading in from pgbgp log files
+ if (node->hist && node->p.prefixlen >= 8)
+ {
+ if (node->hist->p != NULL && node->hist->p->ignoreUntil < t_now)
+ //if (node->hist->p != NULL && prefixInRIB (node, NULL))
+ //if (node->hist->p != NULL)
+ matched = node;
+ }
+ node = node->link[check_bit (&p->u.prefix, node->p.prefixlen)];
+ }
+ if (matched)
+ return bgp_lock_node (matched);
+ return NULL;
+}
+
+
+
+
+
+/*! --------------- Helper Functions ------------------ !*/
+
+
+
+
+
+
+
+/* --------------- Public PGBGP Interface ------------------ */
+int
+bgp_pgbgp_enable (struct bgp *bgp, afi_t afi, safi_t safi,
+ int ost, int est, int sst, int oht, int pht, int eht,
+ const char *file, const char *anoms)
+{
+
+ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP))
+ {
+ if (pgbgp->storage && pgbgp->anomalies)
+ {
+ if (pgbgp->origin_sus_time == ost
+ && pgbgp->edge_sus_time == est
+ && pgbgp->sub_sus_time == sst
+ && pgbgp->origin_hist_time == oht
+ && pgbgp->prefix_hist_time == pht
+ && pgbgp->edge_hist_time == eht
+ && strcmp (pgbgp->storage, file) == 0
+ && strcmp (pgbgp->anomalies, anoms) == 0)
+
+ return 0;
+ }
+ }
+
+ SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP);
+
+#ifndef PGBGP_DEBUG
+ time_t hour = 3600;
+ time_t day = 86400;
+#endif
+#ifdef PGBGP_DEBUG
+ time_t hour = 2;
+ time_t day = 5;
+#endif
+
+ pgbgp->origin_sus_time = ost * hour;
+ pgbgp->edge_sus_time = est * hour;
+ pgbgp->sub_sus_time = sst * hour;
+ pgbgp->origin_hist_time = oht * day;
+ pgbgp->prefix_hist_time = pht * day;
+ pgbgp->edge_hist_time = eht * day;
+ pgbgp->peer_hist_time = DEFAULT_ORIGIN_HIST;
+
+ if (file != NULL)
+ pgbgp->storage = strdup (file);
+ else
+ pgbgp->storage = NULL;
+
+ if (anoms != NULL)
+ pgbgp->anomalies = strdup (anoms);
+ else
+ pgbgp->anomalies = NULL;
+
+
+ pgbgp->reuse_q = pqueue_create ();
+ pgbgp->reuse_q->cmp = reuse_cmp;
+ pgbgp->rq_size = 0;
+ pgbgp->lastgc = time (NULL);
+ pgbgp->lastStore = time (NULL);
+ pgbgp->startTime = time (NULL);
+ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_neighbors_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_neighbors_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_origins_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_origins_cmd);
+ pgbgp->edgeT = hash_create_size (131072, edge_key_make, edge_cmp);
+ bgp_pgbgp_restore ();
+ return 0;
+}
+
+int
+bgp_pgbgp_disable (struct bgp *bgp, afi_t afi, safi_t safi)
+{
+ UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP);
+
+ // Clean the tables
+ if (bgp->rib[afi][safi] != NULL)
+ bgp_pgbgp_clean (bgp->rib[afi][safi]);
+
+ bgp_pgbgp_cleanEdges ();
+
+ if (pgbgp->storage != NULL)
+ free (pgbgp->storage);
+
+ if (pgbgp->anomalies != NULL)
+ free (pgbgp->anomalies);
+
+ struct bgp_pgbgp_peerTime *pr = pgbgp->peerLast;
+ while (pr)
+ {
+ struct bgp_pgbgp_peerTime *cur = pr;
+ pr = pr->next;
+ XFREE (MTYPE_BGP_PGBGP_PEER, cur);
+ }
+
+ return 0;
+}
+
+int
+bgp_pgbgp_clean (struct bgp_table *table)
+{
+ struct bgp_pgbgp_reuse *rnode = NULL;
+
+ while (pgbgp->rq_size > 0)
+ {
+ rnode = (struct bgp_pgbgp_reuse *) pqueue_dequeue (pgbgp->reuse_q);
+ pgbgp->rq_size -= 1;
+ XFREE (MTYPE_BGP_PGBGP_REUSE, rnode);
+ }
+ pqueue_delete (pgbgp->reuse_q);
+
+ if (table == NULL)
+ return 0;
+
+ // Clean the detectors
+ bgp_pgbgp_cleanHistTable (table);
+
+ bgp_pgbgp_cleanEdges ();
+
+
+ // Clean up the RIB nodes
+ for (struct bgp_node * rn = bgp_table_top (table); rn;
+ rn = bgp_route_next (rn))
+ {
+ int changed = 0;
+ for (struct bgp_info * ri = rn->info; ri; ri = ri->next)
+ {
+ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O
+ | BGP_INFO_SUSPICIOUS_P | BGP_INFO_SUSPICIOUS_E
+ | BGP_INFO_IGNORED_P))
+ {
+ changed = 1;
+ UNSET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O
+ | BGP_INFO_SUSPICIOUS_P | BGP_INFO_SUSPICIOUS_E
+ | BGP_INFO_IGNORED_P);
+ }
+ }
+ if (changed && rn->info)
+ {
+ struct bgp_info *ri = rn->info;
+ bgp_process (ri->peer->bgp, rn, rn->table->afi, rn->table->safi);
+ }
+ }
+
+ hash_free (pgbgp->edgeT);
+ return 0;
+}
+
+
+int
+bgp_pgbgp_gc (struct bgp_table *table)
+{
+ struct bgp *bgp = bgp_get_default ();
+ if (!bgp)
+ return 0;
+
+ // Collect each AFI/SAFI RIB
+ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi_t safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ if (!CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP))
+ continue;
+ struct bgp_table *curTable = bgp->rib[afi][safi];
+ if (!curTable)
+ continue;
+ bgp_pgbgp_garbageCollectHistTable (curTable);
+ }
+
+ bgp_pgbgp_garbageCollectEdges (table);
+
+ return 0;
+}
+
+int
+bgp_pgbgp_restore (void)
+{
+
+ if (pgbgp->storage == NULL)
+ return 0;
+ FILE *file = fopen (pgbgp->storage, "r");
+ if (!file)
+ return 0;
+
+ int type = 0;
+ struct prefix p;
+ struct bgp *bgp = bgp_get_default ();
+ struct bgp_node *curNode = NULL;
+
+ // Get the log store time
+ long long int writetime;
+ fscanf (file, "%lld", &writetime);
+ time_t swtime = writetime;
+
+ // If it's too old (more than 1 week old), start fresh
+ if (time (NULL) - swtime > 86400 * 7)
+ {
+ fclose (file);
+ return 0;
+ }
+
+
+ // Get the PGBGP init time
+ long long int stime;
+ fscanf (file, "%lld", &stime);
+ pgbgp->startTime = stime;
+
+ while (fscanf (file, "%d", &type) != EOF)
+ {
+
+ if (type == PREFIX_ID)
+ {
+ char pre[128];
+ unsigned int afi;
+ unsigned int safi;
+ long long int time;
+ fscanf (file, "%s %u %u %lld", pre, &afi, &safi, &time);
+ str2prefix (pre, &p);
+ struct bgp_table *curTable = bgp->rib[afi][safi];
+ assert (curTable != NULL);
+
+ // Create and lock the node
+ curNode = bgp_node_get (curTable, &p);
+ assert (curNode->hist == NULL);
+
+ // bgp_lock_node(curNode);
+
+ curNode->hist =
+ XCALLOC (MTYPE_BGP_PGBGP_HIST, sizeof (struct bgp_pgbgp_hist));
+ assert (curNode->hist != NULL);
+
+ curNode->hist->p =
+ XCALLOC (MTYPE_BGP_PGBGP_PREFIX,
+ sizeof (struct bgp_pgbgp_prefix));
+ assert (curNode->hist->p != NULL);
+
+ curNode->hist->p->lastSeen = time;
+ }
+ else if (type == ORIGIN_ID)
+ {
+ unsigned int ASN;
+ long long int time;
+ fscanf (file, "%u %lld", &ASN, &time);
+ struct bgp_pgbgp_origin *or = XCALLOC (MTYPE_BGP_PGBGP_ORIGIN,
+ sizeof (struct
+ bgp_pgbgp_origin));
+ or->lastSeen = time;
+ or->originAS = ASN;
+ or->next = curNode->hist->o;
+ curNode->hist->o = or;
+ }
+ else if (type == EDGE_ID)
+ {
+ bgp_pgbgp_restoreEdge (file);
+ }
+ else if (type == PEER_ID)
+ {
+ struct bgp_pgbgp_peerTime *pr;
+ long long int time;
+ union sockunion su;
+ char szsu[128];
+ fscanf (file, "%s %lld", szsu, &time);
+ str2sockunion (szsu, &su);
+ pr =
+ XCALLOC (MTYPE_BGP_PGBGP_PEER,
+ sizeof (struct bgp_pgbgp_peerTime));
+ pr->su = su;
+ pr->lastSeen = time;
+ pr->next = pgbgp->peerLast;
+ pgbgp->peerLast = pr;
+ }
+ }
+
+ fclose (file);
+ return 0;
+}
+
+int
+bgp_pgbgp_store (struct bgp_table *table)
+{
+ if (pgbgp->storage == NULL)
+ return 0;
+ char *tmpname = malloc (sizeof (char) * (1 + 4 + strlen (pgbgp->storage)));
+ strcpy (tmpname, pgbgp->storage);
+ strcat (tmpname, ".tmp");
+ FILE *file = fopen (tmpname, "w");
+
+ if (!file)
+ {
+ free (tmpname);
+ return 0;
+ }
+
+ // Store the current time
+ fprintf (file, "%lld\n", (long long int) time (NULL));
+
+ // Store the init time
+ fprintf (file, "%lld\n", (long long int) pgbgp->startTime);
+
+ // Store the peer times
+ for (struct bgp_pgbgp_peerTime * pr = pgbgp->peerLast; pr; pr = pr->next)
+ {
+ char strSock[128];
+ sockunion2str (&pr->su, strSock, sizeof (strSock));
+
+ if (pr->deprefUntil < time (NULL))
+ {
+ fprintf (file, "%d %s %lld\n", PEER_ID, strSock,
+ (long long int) pr->lastSeen);
+ }
+ }
+
+ // Store the tables
+ bgp_pgbgp_storeHistTable (table, file);
+ bgp_pgbgp_storeEdges (table, file);
+
+ fclose (file);
+
+ rename (tmpname, pgbgp->storage);
+
+ free (tmpname);
+ return 0;
+}
+
+/*
+ Check to see if we've seen the peer recently
+ If not, then we need to return true and not delay routes
+ for awhile
+*/
+int
+bgp_pgbgp_updatePeer (struct bgp_info *binfo, time_t now)
+{
+ int status = false;
+ // Find the peer
+ struct bgp_pgbgp_peerTime *pr = pgbgp->peerLast;
+ for (; pr; pr = pr->next)
+ if (sockunion_same (&pr->su, &binfo->peer->su))
+ break;
+
+ // If this is a new peer, create it
+ if (pr == NULL)
+ {
+ pr = XCALLOC (MTYPE_BGP_PGBGP_PEER, sizeof (struct bgp_pgbgp_peerTime));
+ pr->su = binfo->peer->su;
+ pr->next = pgbgp->peerLast;
+ pgbgp->peerLast = pr;
+
+ }
+ // Is it currently marked as new?
+ if (pr->deprefUntil > now)
+ goto UPPEER_DEPREF;
+
+ // Have we seen the peer recently?
+ if (pr->lastSeen + pgbgp->peer_hist_time > now)
+ goto UPPEER_CLEAN;
+
+ // It must not have been seen lately, depref it
+ pr->deprefUntil = now + PGBGP_PEER_GRACE;
+
+
+UPPEER_DEPREF:
+ status = true;
+
+UPPEER_CLEAN:
+ pr->lastSeen = now;
+
+ return status;
+}
+
+
+/*
+ Returns whether or not the sub-prefix should be ignored
+*/
+int
+bgp_pgbgp_shouldIgnore (struct bgp_node *super, struct bgp_info *selected)
+{
+ if (!selected || CHECK_FLAG (selected->flags, BGP_INFO_SUSPICIOUS_P))
+ return false;
+ return true;
+}
+
+/*
+ This is a special case function for smoothly handling sub-prefix hijacks.
+
+ It handles the following 2 events:
+
+ Event 1: The super-prefix of an anomalous prefix has a route through a non-anomalous
+
+ Event 1: An anomalous sub-prefix is ignored, but no best route for the super-prefix exists
+ Response: Announce the sub-prefix until the super-prefix comes back
+
+ Event 2: A super-prefix comes back to the RIB and its anomalous sub-prefix is in use
+ Response: Ignore the sub-prefix again
+ */
+
+
+int
+bgp_pgbgp_rib_updated (struct bgp_node *rn, struct bgp_info *old_best,
+ struct bgp_info *new_best)
+{
+ // return 0;
+ struct bgp_pgbgp_hist *hist = rn->hist;
+ if (!hist)
+ return 0;
+ if (!hist->p)
+ return 0;
+ time_t t_now = time (NULL);
+
+ /*
+ If we can't avoid the sub-prefix by routing to the super-prefix,
+ then route as normal to the sub-prefix
+ */
+ if (!bgp_pgbgp_shouldIgnore (rn, new_best))
+ {
+ for (struct bgp_pgbgp_avoid * cur = hist->p->avoid; cur;
+ cur = cur->next)
+ {
+ if (cur->avoidUntil > t_now)
+ {
+ int changed = false;
+ for (struct bgp_info * ri = cur->sub->info; ri; ri = ri->next)
+ {
+ if (CHECK_FLAG (ri->flags, BGP_INFO_IGNORED_P))
+ {
+ changed = true;
+ UNSET_FLAG (ri->flags, BGP_INFO_IGNORED_P);
+ }
+ }
+ if (changed)
+ {
+ struct bgp_info *ri = cur->sub->info;
+ if (ri && ri->peer && ri->peer->bgp)
+ bgp_process (ri->peer->bgp, cur->sub,
+ cur->sub->table->afi, cur->sub->table->safi);
+
+ }
+
+ }
+ }
+ }
+
+ /*
+ If we can avoid the sub-prefix by routing to the super-prefix,
+ then do so
+ */
+
+ else
+ {
+ for (struct bgp_pgbgp_avoid * cur = hist->p->avoid; cur;
+ cur = cur->next)
+ {
+ if (cur->avoidUntil > t_now)
+ {
+ int changed = false;
+ for (struct bgp_info * ri = cur->sub->info; ri; ri = ri->next)
+ {
+ if (!CHECK_FLAG (ri->flags, BGP_INFO_IGNORED_P))
+ {
+ changed = true;
+ SET_FLAG (ri->flags, BGP_INFO_IGNORED_P);
+ }
+ }
+ if (changed)
+ {
+ struct bgp_info *ri = cur->sub->info;
+ if (ri && ri->peer && ri->peer->bgp)
+ bgp_process (ri->peer->bgp, cur->sub,
+ cur->sub->table->afi, cur->sub->table->safi);
+ }
+ }
+ }
+ }
+
+ /*
+ if (old_best && !new_best)
+ {
+ time_t t_now = time(NULL);
+ for (struct bgp_pgbgp_avoid * cur = hist->p->avoid; cur;
+ cur = cur->next)
+ {
+ if (cur->avoidUntil > t_now)
+ {
+ for (struct bgp_info * ri = cur->sub->info; ri; ri = ri->next)
+ UNSET_FLAG (ri->flags, BGP_INFO_IGNORED_P);
+
+ struct bgp_info *ri = cur->sub->info;
+ if (ri && ri->peer && ri->peer->bgp)
+ bgp_process (ri->peer->bgp, cur->sub, cur->sub->table->afi,
+ cur->sub->table->safi);
+ }
+ }
+ }
+
+
+ else if (!old_best && new_best)
+ {
+ time_t t_now = time(NULL);
+ for (struct bgp_pgbgp_avoid * av = hist->p->avoid; av; av = av->next)
+ {
+ struct bgp_info * ri = av->sub->info;
+ if (av->avoidUntil > t_now && ri && !CHECK_FLAG(ri->flags, BGP_INFO_IGNORED_P))
+ {
+ for (; ri; ri = ri->next)
+ SET_FLAG (ri->flags, BGP_INFO_IGNORED_P);
+ ri = av->sub->info;
+ if (ri && ri->peer && ri->peer->bgp)
+ bgp_process (ri->peer->bgp, av->sub,
+ av->sub->table->afi, av->sub->table->safi);
+
+ }
+ }
+ }
+ */
+ return 0;
+}
+
+int
+bgp_pgbgp_update (struct bgp_info *binfo, struct attr *at,
+ struct bgp_node *rn)
+{
+ time_t t_now = time (NULL);
+
+ // Clean up the reuse list
+ bgp_pgbgp_reuse (t_now);
+
+
+ if (!rn->hist)
+ {
+ rn->hist =
+ XCALLOC (MTYPE_BGP_PGBGP_HIST, sizeof (struct bgp_pgbgp_hist));
+ // Get the PGBGP history lock on rn
+ bgp_lock_node (rn);
+ }
+
+ struct bgp_node *superhn = NULL;
+
+ // implicit lock from node_get
+ superhn = findSuper (rn->table, &rn->p, t_now);
+
+ int newPeer = bgp_pgbgp_updatePeer (binfo, t_now);
+ bgp_pgbgp_updateOrigin (rn->hist, binfo, at, rn, t_now, newPeer);
+ bgp_pgbgp_updatePrefix (rn->hist, superhn, binfo, at, rn, t_now, newPeer);
+ bgp_pgbgp_updateEdge (rn->hist, binfo, at, rn, t_now, newPeer);
+
+ if (superhn != NULL)
+ bgp_unlock_node (superhn);
+
+
+
+ // GC and storage must be last, as they update lastSeen values of objects
+ // which would cause new routes to be recently seen, which is undesired behavior
+ // Make sure you don't collect anything that might be in use!
+ if (t_now >= pgbgp->lastgc + PGBGP_GC_DELTA)
+ {
+ bgp_pgbgp_gc (rn->table);
+ pgbgp->lastgc = t_now;
+ }
+
+ if (t_now >= pgbgp->lastStore + PGBGP_STORE_DELTA)
+ {
+ bgp_pgbgp_store (rn->table);
+ pgbgp->lastStore = t_now;
+ }
+
+
+
+ return 0;
+}
+
+
+
+
+/*! --------------- Public PGBGP Interface ------------------ !*/
+
+
+
+
+
+
+
+
+
+/* --------------- MOAS Detection ------------------ */
+void
+bgp_pgbgp_storeHistTable (struct bgp_table *table, FILE * file)
+{
+ time_t t_now;
+ t_now = time (NULL);
+
+ struct bgp *bgp = bgp_get_default ();
+ if (!bgp)
+ return;
+
+ // Store each AFI/SAFI RIB
+ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi_t safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ if (!CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP))
+ continue;
+ struct bgp_table *curTable = bgp->rib[afi][safi];
+ if (!curTable)
+ continue;
+
+ for (struct bgp_node * rn = bgp_table_top (curTable); rn;
+ rn = bgp_route_next (rn))
+ {
+ struct bgp_pgbgp_hist *hist = rn->hist;
+ if (hist == NULL)
+ continue;
+ char szPrefix[128];
+ prefix2str (&rn->p, szPrefix, sizeof (szPrefix));
+
+
+ struct bgp_pgbgp_prefix *pre = hist->p;
+ if (pre && pre->ignoreUntil <= t_now)
+ {
+ if (pre->lastSeen + pgbgp->prefix_hist_time > t_now)
+ fprintf (file, "%d %s %u %u %lld\n", PREFIX_ID, szPrefix,
+ (unsigned int) afi, (unsigned int) safi,
+ (long long int) pre->lastSeen);
+ else
+ continue;
+ }
+ /* Need a prefix in the file before the origins,
+ if no prefix.. skip origins */
+ else
+ continue;
+
+ for (struct bgp_pgbgp_origin * cur = hist->o; cur;
+ cur = cur->next)
+ {
+ if (cur->deprefUntil > t_now)
+ continue;
+
+ if (cur->lastSeen + pgbgp->origin_hist_time > t_now)
+ fprintf (file, "%d %u %lld\n", ORIGIN_ID, cur->originAS,
+ (long long int) cur->lastSeen);
+ }
+
+ }
+ }
+}
+
+
+int
+bgp_pgbgp_garbageCollectHistTable (struct bgp_table *table)
+{
+ time_t t_now;
+ t_now = time (NULL);
+
+
+ for (struct bgp_node * rn = bgp_table_top (table); rn;
+ rn = bgp_route_next (rn))
+ {
+ int collect = false;
+ struct bgp_pgbgp_hist *hist = rn->hist;
+ if (hist == NULL)
+ continue;
+
+ struct bgp_pgbgp_origin *cur = hist->o;
+ struct bgp_pgbgp_prefix *pre = hist->p;
+ struct bgp_pgbgp_origin *parent = NULL;
+
+ int used = false;
+ if (cur != NULL || pre != NULL)
+ used = true;
+
+ while (cur != NULL)
+ {
+ // Update the lastSeen time w/ originInRIB
+ if (originInRIB (rn, cur))
+ cur->lastSeen = t_now;
+
+ collect = false;
+
+ // Collect if old
+ if (cur->lastSeen + pgbgp->origin_hist_time <= t_now)
+ collect = true;
+
+ // Collect if anomaly just became okay but not seen since last collection
+ if (cur->deprefUntil != 0 && cur->deprefUntil < t_now)
+ {
+ if (cur->lastSeen < pgbgp->lastgc)
+ collect = true;
+ cur->deprefUntil = 0;
+ }
+
+ if (collect)
+ {
+ if (parent == NULL)
+ hist->o = cur->next;
+ else
+ parent->next = cur->next;
+
+ // Delete cur, parent doesn't change
+ struct bgp_pgbgp_origin *del = cur;
+ cur = cur->next;
+ XFREE (MTYPE_BGP_PGBGP_ORIGIN, del);
+ }
+ else
+ {
+ parent = cur;
+ cur = cur->next;
+ }
+ }
+
+ // Update the lastSeen time w/ prefixInRIB
+ if (pre && prefixInRIB (rn, pre))
+ pre->lastSeen = t_now;
+
+ collect = false;
+
+ // Collect if old
+ if (pre && pre->lastSeen + pgbgp->prefix_hist_time <= t_now)
+ collect = true;
+
+ // Collect if anomaly just became okay but not seen since last collection
+ if (pre && pre->ignoreUntil != 0 && pre->ignoreUntil < t_now)
+ {
+ if (pre->lastSeen < pgbgp->lastgc)
+ collect = true;
+ pre->ignoreUntil = 0;
+ }
+
+ if (collect)
+ {
+ for (struct bgp_pgbgp_avoid * av = pre->avoid; av;)
+ {
+ struct bgp_pgbgp_avoid *del = av;
+ av = av->next;
+ bgp_unlock_node (del->sub);
+ XFREE (MTYPE_BGP_PGBGP_AVOID, del);
+ }
+
+ XFREE (MTYPE_BGP_PGBGP_PREFIX, pre);
+ hist->p = NULL;
+ }
+
+ // If the node isn't in use, remove it
+ if (used && hist->o == NULL && hist->p == NULL)
+ {
+ XFREE (MTYPE_BGP_PGBGP_HIST, hist);
+ rn->hist = NULL;
+ bgp_unlock_node (rn);
+ }
+ }
+
+ return 0;
+}
+
+void
+bgp_pgbgp_cleanHistTable (struct bgp_table *table)
+{
+ // Clean up the RIB nodes
+ for (struct bgp_node * rn = bgp_table_top (table); rn;
+ rn = bgp_route_next (rn))
+ {
+ struct bgp_pgbgp_hist *hist = rn->hist;
+ if (hist == NULL)
+ continue;
+
+ if (hist->p)
+ {
+ for (struct bgp_pgbgp_avoid * av = hist->p->avoid; av;)
+ {
+ struct bgp_pgbgp_avoid *del = av;
+ av = av->next;
+ bgp_unlock_node (del->sub);
+ XFREE (MTYPE_BGP_PGBGP_AVOID, del);
+ }
+ hist->p->avoid = NULL;
+ XFREE (MTYPE_BGP_PGBGP_PREFIX, hist->p);
+ hist->p = NULL;
+ }
+
+ for (struct bgp_pgbgp_origin * cur = hist->o; cur;)
+ {
+ struct bgp_pgbgp_origin *next = cur->next;
+ XFREE (MTYPE_BGP_PGBGP_ORIGIN, cur);
+ cur = next;
+ }
+ hist->o = NULL;
+ XFREE (MTYPE_BGP_PGBGP_HIST, hist);
+ rn->hist = NULL;
+ bgp_unlock_node (rn);
+ }
+}
+
+void
+bgp_pgbgp_logOriginAnomaly (as_t asn, struct bgp_node *rn, struct attr *at)
+{
+ assert (pgbgp);
+ if (!pgbgp->anomalies)
+ return;
+ FILE *file = fopen (pgbgp->anomalies, "a");
+ if (!file)
+ return;
+
+ char pre[256];
+ prefix2str (&rn->p, pre, sizeof (pre));
+
+ // MOAS | TIME | NEXTHOP | PREFIX | SUSPICIOUS_ORIGIN | TRUSTED_ORIGINS | PATH
+ fprintf (file, "%d|%lld|%s|%s|%d|", MOAS, (long long int) time (NULL),
+ inet_ntoa (at->nexthop), pre, asn);
+
+
+ // Print the trusted origins
+ assert (rn->hist);
+ assert (rn->hist->o);
+
+ struct bgp_pgbgp_hist *hist = rn->hist;
+
+ for (struct bgp_pgbgp_origin * cur = hist->o; cur != NULL; cur = cur->next)
+ {
+ if (cur->deprefUntil > time (NULL))
+ continue;
+ fprintf (file, "%d", cur->originAS);
+ if (cur->next != NULL)
+ fprintf (file, " ");
+ }
+
+ fprintf (file, " |%s\n", aspath_print (at->aspath));
+ fclose (file);
+}
+
+int
+bgp_pgbgp_updateOrigin (struct bgp_pgbgp_hist *hist, struct bgp_info *binfo,
+ struct attr *at, struct bgp_node *rn, time_t t_now,
+ int newPeer)
+{
+ struct bgp_pgbgp_pathSet pathOrigins;
+ struct bgp_pgbgp_origin *pi = NULL;
+ int status = 0;
+ struct bgp_pgbgp_reuse *r;
+ pathOrigins = bgp_pgbgp_pathOrigin (at->aspath);
+
+
+ for (int i = 0; i < pathOrigins.length; i++)
+ {
+ as_t pathOrigin = pathOrigins.ases[i];
+
+ /* Is the Origin AS in the history? */
+ for (pi = hist->o; pi; pi = pi->next)
+ if (pi->originAS == pathOrigin)
+ break;
+
+ if (pi == NULL)
+ {
+ pi =
+ XCALLOC (MTYPE_BGP_PGBGP_ORIGIN,
+ sizeof (struct bgp_pgbgp_origin));
+ pi->next = hist->o;
+ pi->originAS = pathOrigin;
+ hist->o = pi;
+ }
+
+ // If this is our first origin for the prefix, let the sub-prefix
+ // check take care of it
+ if (pi->next == NULL)
+ goto UPO_CLEAN;
+
+ /* Is the origin currently marked as suspicious? */
+ if (pi->deprefUntil > t_now)
+ goto UPO_DEPREF;
+
+ /* Have we seen the origin recently? */
+ if (pi->lastSeen + pgbgp->origin_hist_time > t_now)
+ goto UPO_CLEAN;
+
+#ifndef PGBGP_DEBUG
+ /* Are we within the initial grace period? */
+ if (newPeer)
+ goto UPO_CLEAN;
+#endif
+
+ /* It must not be in recent history, depref origin for first time */
+ pi->deprefUntil = t_now + pgbgp->origin_sus_time;
+ bgp_pgbgp_logOriginAnomaly (pathOrigin, rn, at);
+
+ r = XCALLOC (MTYPE_BGP_PGBGP_REUSE, sizeof (struct bgp_pgbgp_reuse));
+ r->type = PGBGP_REUSE_ORIGIN;
+ r->deprefUntil = pi->deprefUntil;
+ r->data.origin.originAS = pathOrigin;
+ r->data.origin.rn = rn;
+ bgp_lock_node (rn);
+ pqueue_enqueue (r, pgbgp->reuse_q);
+ pgbgp->rq_size += 1;
+
+
+ UPO_DEPREF:
+ SET_FLAG (binfo->flags, BGP_INFO_SUSPICIOUS_O);
+ status = BGP_INFO_SUSPICIOUS_O;
+
+ UPO_CLEAN:
+ pi->lastSeen = t_now;
+ }
+ return status;
+}
+
+int
+bgp_pgbgp_reuseOrigin (struct bgp_pgbgp_r_origin data)
+{
+ struct bgp_info *ri;
+ int numChanged = 0;
+ time_t t_now = time (NULL);
+ assert (data.rn->hist != NULL);
+
+ // Repreference paths for this prefix that are now okay
+ for (ri = data.rn->info; ri; ri = ri->next)
+ {
+ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O))
+ {
+ struct bgp_pgbgp_pathSet pathOrigins;
+ pathOrigins = bgp_pgbgp_pathOrigin (ri->attr->aspath);
+ int numOkay = 0;
+ for (int i = 0; i < pathOrigins.length; i++)
+ {
+ as_t pathOrigin = pathOrigins.ases[i];
+ // Find the origin
+ struct bgp_pgbgp_origin *o = NULL;
+ for (o = data.rn->hist->o; o != NULL; o = o->next)
+ if (o->originAS == pathOrigin)
+ break;
+ /*
+ if (o == NULL) {
+ for(struct bgp_pgbgp_origin * z = data.rn->hist->o; z != NULL; z = z->next)
+ printf("Known origin: %d\n", z->originAS);
+ char pre[128];
+ prefix2str(&data.rn->p, pre, 128);
+ printf("%s : %s : %d\n", pre, ri->attr->aspath->str, pathOrigin);
+ }
+ */
+ assert (o != NULL);
+
+ if (o->deprefUntil <= t_now)
+ numOkay += 1;
+ }
+ if (numOkay == pathOrigins.length)
+ {
+ UNSET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O);
+ numChanged += 1;
+ }
+ }
+ }
+
+ ri = data.rn->info;
+
+ // Rerun the decision process?
+ if (numChanged > 0)
+ bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi,
+ data.rn->table->safi);
+
+
+ /*
+ // Remove this (origin,prefix) pair from the normal database
+ // if it's not still in the RIB
+ struct bgp_pgbgp_hist *hist = rn->hist;
+ struct bgp_pgbgp_origin * cur = hist->o;
+ struct bgp_pgbgp_origin * parent = NULL;
+
+ // Find the origin AS node
+ while(cur != NULL)
+ {
+ if (cur->originAS == data.originAS)
+ {
+ // Delete the node if it hasn't been seen
+ // since the last storage run
+ if (cur->lastSeen < pgbgp->lastStore) {
+ // Delete this node
+ if (parent == NULL)
+ hist->o = cur->next;
+ else
+ parent->next = cur->next;
+
+ XFREE(MTYPE_BGP_PGBGP_ORIGIN, cur);
+ }
+ break;
+ }
+ parent = cur;
+ cur = cur->next;
+ }
+ */
+
+ bgp_unlock_node (data.rn);
+ return 0;
+}
+
+/*! --------------- MOAS Detection ------------------ !*/
+
+
+/* --------------- Sub-Prefix Detection ------------------ */
+
+
+
+
+
+void
+bgp_pgbgp_logSubprefixAnomaly (as_t asn, struct bgp_node *rn, struct attr *at,
+ struct bgp_node *super)
+{
+ assert (pgbgp);
+ if (!pgbgp->anomalies)
+ return;
+ FILE *file = fopen (pgbgp->anomalies, "a");
+ if (!file)
+ return;
+
+ char pre[256];
+ prefix2str (&rn->p, pre, sizeof (pre));
+
+ char superpre[256];
+ prefix2str (&super->p, superpre, sizeof (superpre));
+
+ // SUBPREFIX | TIME | NEXTHOP | PREFIX | SUPER-PREFIX | SUSPICIOUS_ORIGIN | TRUSTED_ORIGINS | PATH
+ fprintf (file, "%d|%lld|%s|%s|%s|%d|", SUBPREFIX,
+ (long long int) time (NULL), inet_ntoa (at->nexthop), pre,
+ superpre, asn);
+
+ // Print the trusted origins
+ assert (super->hist);
+ assert (super->hist->o);
+
+ struct bgp_pgbgp_hist *hist = super->hist;
+
+ for (struct bgp_pgbgp_origin * cur = hist->o; cur != NULL; cur = cur->next)
+ {
+ if (cur->deprefUntil > time (NULL))
+ continue;
+ fprintf (file, "%d", cur->originAS);
+ if (cur->next != NULL)
+ fprintf (file, " ");
+ }
+
+ fprintf (file, " |%s\n", aspath_print (at->aspath));
+ fclose (file);
+}
+
+/*
+ If the first path is a prefix of the second, then return true
+ */
+
+static int
+bgp_pgbgp_pathIsPrefix(struct aspath *trusted, struct aspath * new)
+{
+ if (trusted == new)
+ return true;
+
+ struct assegment *seg1 = trusted->segments;
+ struct assegment *seg2 = new->segments;
+
+ while (seg1 || seg2)
+ {
+ if ((!seg1 && seg2) || (seg1 && !seg2))
+ return false;
+ if (seg1->type != seg2->type)
+ return false;
+
+ if (seg1->length > seg2->length)
+ return false;
+
+ for(int i = 0; i < seg1->length; i++)
+ if (seg1->as[i] != seg2->as[i])
+ return false;
+
+ seg1 = seg1->next;
+ seg2 = seg2->next;
+ }
+
+ return true;
+}
+
+int
+bgp_pgbgp_updatePrefix (struct bgp_pgbgp_hist *hist,
+ struct bgp_node *supernode, struct bgp_info *binfo,
+ struct attr *at, struct bgp_node *rn, time_t t_now,
+ int newPeer)
+{
+ struct bgp_pgbgp_prefix *pre = NULL;
+ struct bgp_pgbgp_reuse *r = NULL;
+ int status = 0;
+ int changed = false;
+
+ pre = hist->p;
+
+
+ /* Do we have this prefix? */
+ if (pre == NULL)
+ {
+ pre =
+ XCALLOC (MTYPE_BGP_PGBGP_PREFIX, sizeof (struct bgp_pgbgp_prefix));
+ hist->p = pre;
+ }
+
+ /* Is the prefix currently marked as suspicious? */
+ if (pre->ignoreUntil > t_now)
+ {
+ goto UPP_IGNORE;
+ }
+
+ /* Should this neighbor be avoided for this prefix because it
+ sent us info. about a suspicious sub-prefix? */
+ for (struct bgp_pgbgp_avoid * av = hist->p->avoid; av; av = av->next)
+ {
+ if (binfo->peer->as == av->peerASN && av->avoidUntil > t_now)
+ {
+ SET_FLAG (binfo->flags, BGP_INFO_SUSPICIOUS_P);
+ status = BGP_INFO_SUSPICIOUS_P;
+ goto UPP_DONE;
+ }
+ }
+
+ /* Have we seen the prefix recently? */
+ if (pre->lastSeen + pgbgp->prefix_hist_time > t_now)
+ goto UPP_DONE;
+
+#ifndef PGBGP_DEBUG
+ /* Are we within the initial grace period? */
+ if (newPeer)
+ goto UPP_DONE;
+#endif
+
+ /* Is there a less specific *in recent history* that this could be hijacking? */
+ if (supernode == NULL)
+ goto UPP_DONE;
+
+ /* Does this path the super-net's non-anomalous path from this peer? If so it's okay */
+ int found = false;
+ for (struct bgp_info * ri = supernode->info; ri; ri = ri->next)
+ {
+ if (ri->peer->as == binfo->peer->as)
+ {
+ if (!ANOMALOUS(ri->flags) && bgp_pgbgp_pathIsPrefix(ri->attr->aspath, at->aspath))
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ goto UPP_DONE;
+
+ /*
+ It's not in recent history, and there is a less specific currently in use
+ Response:
+ . Ignore this prefix
+ . Make the less specific's route for this neighbor suspicious
+ */
+
+
+ pre->ignoreUntil = t_now + pgbgp->sub_sus_time;
+
+ struct bgp_pgbgp_pathSet pathOrigins;
+ pathOrigins = bgp_pgbgp_pathOrigin (at->aspath);
+ for (int i = 0; i < pathOrigins.length; i++)
+ bgp_pgbgp_logSubprefixAnomaly (pathOrigins.ases[i], rn, at, supernode);
+
+
+
+ r = XCALLOC (MTYPE_BGP_PGBGP_REUSE, sizeof (struct bgp_pgbgp_reuse));
+ r->type = PGBGP_REUSE_PREFIX;
+ r->deprefUntil = pre->ignoreUntil;
+ r->data.prefix.rn = rn;
+ r->data.prefix.rnsuper = supernode;
+ bgp_lock_node (rn);
+ bgp_lock_node (supernode);
+ pqueue_enqueue (r, pgbgp->reuse_q);
+ pgbgp->rq_size += 1;
+
+UPP_IGNORE:
+ // Sanity check
+ if (supernode == NULL)
+ goto UPP_DONE;
+
+ /* Set the less specific's route from this peer to suspicious */
+ changed = false;
+
+ for (struct bgp_info * ri = supernode->info; ri; ri = ri->next)
+ {
+ if (ri->peer->as == binfo->peer->as)
+ {
+ if (!CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_P))
+ {
+ SET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_P);
+ changed = true;
+ }
+ break;
+ }
+ }
+
+ // Make note of it in the less specific's history information
+ found = false;
+ struct bgp_pgbgp_hist *superhist = supernode->hist;
+
+ if (superhist && superhist->p)
+ {
+ for (struct bgp_pgbgp_avoid * av = superhist->p->avoid; av;
+ av = av->next)
+ {
+ if (av->peerASN == binfo->peer->as)
+ {
+ if (av->avoidUntil < pre->ignoreUntil)
+ av->avoidUntil = pre->ignoreUntil;
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ struct bgp_pgbgp_avoid *newavoid =
+ XCALLOC (MTYPE_BGP_PGBGP_AVOID, sizeof (struct bgp_pgbgp_avoid));
+ newavoid->peerASN = binfo->peer->as;
+ newavoid->avoidUntil = pre->ignoreUntil;
+ newavoid->next = superhist->p->avoid;
+ newavoid->sub = rn;
+ bgp_lock_node (rn);
+ superhist->p->avoid = newavoid;
+ }
+ }
+ /*
+ ignore this route unless the supernet's node
+ is only a placeholder from loaded pgbgp data
+ */
+ if (bgp_pgbgp_shouldIgnore (supernode, bgp_pgbgp_selected (supernode)))
+ {
+ SET_FLAG (binfo->flags, BGP_INFO_IGNORED_P);
+ status = BGP_INFO_IGNORED_P;
+ }
+ if (changed)
+ {
+ struct bgp_info *ri = supernode->info;
+ bgp_process (ri->peer->bgp, supernode, supernode->table->afi,
+ supernode->table->safi);
+ }
+
+UPP_DONE:
+ pre->lastSeen = t_now;
+
+ return status;
+}
+
+int
+bgp_pgbgp_reusePrefix (struct bgp_pgbgp_r_prefix data)
+{
+ struct bgp_info *ri = NULL;
+
+ time_t t_now = time (NULL);
+
+ // Repreference all routes for this node
+ for (ri = data.rn->info; ri; ri = ri->next)
+ UNSET_FLAG (ri->flags, BGP_INFO_IGNORED_P);
+ ri = data.rn->info;
+
+ // Rerun the decision process
+ if (ri != NULL)
+ bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi,
+ data.rn->table->safi);
+
+
+ // Remove the avoid nodes from the super
+ struct bgp_pgbgp_hist *superhist = data.rnsuper->hist;
+ if (superhist != NULL && superhist->p != NULL)
+ {
+ struct bgp_pgbgp_avoid *parent = NULL;
+ for (struct bgp_pgbgp_avoid * av = superhist->p->avoid; av;)
+ {
+ int numChanged = 0;
+ if (av->avoidUntil <= t_now)
+ {
+ struct bgp_pgbgp_avoid *del = av;
+ av = av->next;
+ if (parent == NULL)
+ superhist->p->avoid = av;
+ else
+ parent->next = av;
+
+ // Repreference any routes
+ for (ri = data.rnsuper->info; ri; ri = ri->next)
+ {
+ if (ri->peer->as == del->peerASN)
+ {
+ UNSET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_P);
+ numChanged += 1;
+ break;
+ }
+ }
+ ri = data.rnsuper->info;
+
+ if (numChanged > 0 && ri != NULL)
+ bgp_process (ri->peer->bgp, data.rnsuper,
+ data.rnsuper->table->afi,
+ data.rnsuper->table->safi);
+ bgp_unlock_node (del->sub);
+ XFREE (MTYPE_BGP_PGBGP_AVOID, del);
+ }
+ else
+ {
+ parent = av;
+ av = av->next;
+ }
+ }
+ }
+
+ // Remove this prefix from the normal database
+ // if it hasn't been seen in the RIB since the last
+ // storage run
+ /*
+ struct bgp_pgbgp_hist *hist = rn->hist;
+ struct bgp_pgbgp_prefix * pre = hist->p;
+
+ if (pre && pre->lastSeen < pgbgp->lastStore)
+ {
+ // Delete this node
+ for(struct bgp_pgbgp_avoid * av = hist->p->avoid; av;)
+ {
+ struct bgp_pgbgp_avoid *del = av;
+ av = av->next;
+ bgp_unlock_node(del->sub);
+ XFREE (MTYPE_BGP_PGBGP_AVOID, del);
+ }
+ XFREE(MTYPE_BGP_PGBGP_PREFIX, pre);
+ hist->p = NULL;
+ }
+ */
+ bgp_unlock_node (data.rn);
+ bgp_unlock_node (data.rnsuper);
+ return 0;
+}
+
+/*! --------------- Sub-Prefix Detection ------------------ !*/
+
+
+
+
+
+/* --------------- Edge Detection ------------------ */
+
+static void
+edge_store_clear_iterator (struct hash_backet *backet, void *file)
+{
+ struct bgp_pgbgp_edge *hedge = backet->data;
+}
+
+static void
+edge_store_iterator (struct hash_backet *backet, FILE * file)
+{
+ struct bgp_pgbgp_edge *hedge = backet->data;
+ time_t t_now = time (NULL);
+ if (hedge->deprefUntil > t_now)
+ return;
+ if (hedge->lastSeen + pgbgp->edge_hist_time > t_now)
+ {
+ fprintf (file, "%d %u %u %lld\n", EDGE_ID, hedge->e.a, hedge->e.b,
+ (long long int) hedge->lastSeen);
+ }
+}
+
+
+void
+bgp_pgbgp_storeEdges (struct bgp_table *table, FILE * file)
+{
+ hash_iterate (pgbgp->edgeT,
+ (void (*)(struct hash_backet *, void *))
+ edge_store_iterator, file);
+ return;
+}
+
+
+int
+bgp_pgbgp_restoreEdge (FILE * file)
+{
+ unsigned int a, b;
+ long long int lastSeen;
+ fscanf (file, "%u %u %lld", &a, &b, &lastSeen);
+ struct bgp_pgbgp_edge finder;
+ finder.e.a = a;
+ finder.e.b = b;
+ finder.lastSeen = lastSeen;
+ struct bgp_pgbgp_edge *hedge =
+ hash_get (pgbgp->edgeT, &finder, edge_hash_alloc);
+ hedge->lastSeen = finder.lastSeen;
+ return 0;
+}
+
+unsigned int
+edge_key_make (void *p)
+{
+ struct bgp_pgbgp_edge *pe = p;
+ struct edge *e = &pe->e;
+ return (e->a << 16) + e->b;
+}
+
+static int
+edge_cmp (const void *arg1, const void *arg2)
+{
+
+ const struct edge *e1 = &((const struct bgp_pgbgp_edge *) arg1)->e;
+ const struct edge *e2 = &((const struct bgp_pgbgp_edge *) arg2)->e;
+ if (e1->a == e2->a && e1->b == e2->b)
+ return 1;
+ return 0;
+}
+
+static void *
+edge_hash_alloc (void *arg)
+{
+ struct bgp_pgbgp_edge *hedge =
+ XCALLOC (MTYPE_BGP_PGBGP_EDGE, sizeof (struct bgp_pgbgp_edge));
+ struct bgp_pgbgp_edge *lookup = arg;
+ if (hedge == NULL)
+ return NULL;
+ hedge->e = lookup->e;
+ return hedge;
+}
+
+
+static void
+edge_gc_iterator (struct hash_backet *backet, time_t * time)
+{
+ time_t t_now = *time;
+ struct bgp_pgbgp_edge *hedge = backet->data;
+
+ int collect = false;
+
+ // Collect if we haven't seen it in awhile
+ if (hedge->lastSeen + pgbgp->edge_hist_time <= t_now)
+ collect = true;
+
+ // Collect if it has just gotten out of anomaly stage
+ // but hasn't been in the RIB since the last GC
+ if (hedge->deprefUntil != 0 && hedge->deprefUntil < t_now)
+ {
+ if (hedge->lastSeen < pgbgp->lastgc)
+ collect = true;
+ hedge->deprefUntil = 0;
+ }
+
+ if (collect)
+ {
+ struct bgp_pgbgp_edge *ret = hash_release (pgbgp->edgeT, hedge);
+ assert (ret != NULL);
+ XFREE (MTYPE_BGP_PGBGP_EDGE, hedge);
+ }
+}
+
+
+
+static void
+edge_update_iterator (struct hash_backet *backet, void *v)
+{
+ struct aspath *p = backet->data;
+ time_t t_now = time (NULL);
+ int first = true;
+
+ struct edge cur;
+ cur.a = 0;
+ cur.b = 0;
+ struct assegment *seg;
+ struct bgp_pgbgp_edge *hedge = NULL;
+ for (seg = p->segments; seg; seg = seg->next)
+ {
+ for (int i = 0; i < seg->length; i++)
+ {
+ cur.a = cur.b;
+ cur.b = seg->as[i];
+ if (first)
+ {
+ first = false;
+ continue;
+ }
+ if (cur.a == cur.b)
+ continue;
+ // printf("%d -- %d\n", cur.a, cur.b);
+ struct bgp_pgbgp_edge finder;
+ finder.e = cur;
+ hedge = hash_lookup (pgbgp->edgeT, &finder);
+
+ if (!hedge)
+ continue;
+ hedge->lastSeen = t_now;
+ }
+ }
+}
+
+int
+bgp_pgbgp_garbageCollectEdges (struct bgp_table *table)
+{
+ // Update the timings
+ hash_iterate (ashash,
+ (void (*)(struct hash_backet *, void *))
+ edge_update_iterator, NULL);
+
+ // Perform the collection
+ time_t t_now = time (NULL);
+ hash_iterate (pgbgp->edgeT,
+ (void (*)(struct hash_backet *, void *))
+ edge_gc_iterator, &t_now);
+ return 0;
+}
+
+static void
+edge_clean_iterator (struct hash_backet *backet, void *a1)
+{
+ struct bgp_pgbgp_edge *hedge = backet->data;
+ struct bgp_pgbgp_edge *ret = hash_release (pgbgp->edgeT, hedge);
+ assert (ret != NULL);
+ XFREE (MTYPE_BGP_PGBGP_EDGE, hedge);
+}
+
+static void
+bgp_pgbgp_cleanEdges (void)
+{
+ if (pgbgp->edgeT != NULL)
+ {
+ hash_iterate (pgbgp->edgeT,
+ (void (*)(struct hash_backet *, void *))
+ edge_clean_iterator, NULL);
+ hash_free (pgbgp->edgeT);
+ }
+ return;
+}
+
+void
+bgp_pgbgp_logEdgeAnomaly (struct bgp_node *rn, struct attr *at,
+ struct edge *edge)
+{
+ assert (pgbgp);
+ if (!pgbgp->anomalies)
+ return;
+ FILE *file = fopen (pgbgp->anomalies, "a");
+ if (!file)
+ return;
+
+ char pre[256];
+ prefix2str (&rn->p, pre, sizeof (pre));
+
+ // EDGE | TIME | NEXTHOP | PREFIX | PATH | Edge.a | Edge.b
+
+ fprintf (file, "%d|%lld|%s|%s|%s|%d|%d\n", EDGE,
+ (long long int) time (NULL), inet_ntoa (at->nexthop), pre,
+ aspath_print (at->aspath), edge->a, edge->b);
+
+ fclose (file);
+}
+
+
+int
+bgp_pgbgp_updateEdge (struct bgp_pgbgp_hist *hist, struct bgp_info *binfo,
+ struct attr *at, struct bgp_node *rn, time_t t_now,
+ int newPeer)
+{
+
+ char first = true;
+ struct edge curEdge;
+ curEdge.a = 0;
+ curEdge.b = 0;
+
+
+ if (at->aspath == NULL)
+ return 0;
+ struct assegment *seg = at->aspath->segments;
+ if (seg == NULL)
+ return 0;
+ time_t max_depref = 0;
+ for (seg = at->aspath->segments; seg; seg = seg->next)
+ {
+ for (int i = 0; i < seg->length; i++)
+ {
+ curEdge.a = curEdge.b;
+ curEdge.b = seg->as[i];
+ if (first)
+ {
+ first = false;
+ continue;
+ }
+ if (curEdge.a == curEdge.b)
+ continue;
+
+ // We have an edge to consider
+ struct bgp_pgbgp_edge finder;
+ finder.e = curEdge;
+ struct bgp_pgbgp_edge *hedge =
+ hash_get (pgbgp->edgeT, &finder, edge_hash_alloc);
+
+ // Is this edge marked as suspicious?
+ if (hedge->deprefUntil > t_now)
+ goto UPE_DEPREF;
+
+ // Have we seen the edge recently?
+ if (hedge->lastSeen + pgbgp->edge_hist_time > t_now)
+ goto UPE_CLEAN;
+#ifndef PGBGP_DEBUG
+ /* Are we within the initial grace period? */
+ if (newPeer)
+ goto UPE_CLEAN;
+#endif
+ // It must not be in recent history, depref edge for first time
+ hedge->deprefUntil = t_now + pgbgp->edge_sus_time;
+ bgp_pgbgp_logEdgeAnomaly (rn, at, &curEdge);
+
+
+ UPE_DEPREF:
+ if (hedge->deprefUntil > max_depref)
+ max_depref = hedge->deprefUntil;
+ UPE_CLEAN:
+ hedge->lastSeen = t_now;
+ }
+ }
+ if (max_depref)
+ {
+ SET_FLAG (binfo->flags, BGP_INFO_SUSPICIOUS_E);
+ if (!hist->pEdgeReuse)
+ {
+ struct bgp_pgbgp_reuse *r;
+ r =
+ XCALLOC (MTYPE_BGP_PGBGP_REUSE, sizeof (struct bgp_pgbgp_reuse));
+ r->type = PGBGP_REUSE_EDGE;
+ r->deprefUntil = max_depref;
+ r->data.edge.rn = rn;
+ bgp_lock_node (rn);
+ pqueue_enqueue (r, pgbgp->reuse_q);
+ pgbgp->rq_size += 1;
+ hist->pEdgeReuse = r;
+ }
+ return BGP_INFO_SUSPICIOUS_E;
+ }
+
+ return 0;
+}
+
+int
+bgp_pgbgp_reuseEdge (struct bgp_pgbgp_r_edge data)
+{
+
+ // Okay, go through all of the paths for the prefix
+ // and find the path that needs to be updated next and
+ // enqueue it
+ time_t minMax = 0;
+ int numChanged = 0;
+ time_t t_now = time (NULL);
+
+ for (struct bgp_info * ri = data.rn->info; ri; ri = ri->next)
+ {
+ char first = true;
+ struct edge curEdge = { 0, 0 };
+ struct assegment *seg;
+ time_t max_depref = 0;
+
+ for (seg = ri->attr->aspath->segments; seg; seg = seg->next)
+ {
+ for (int i = 0; i < seg->length; i++)
+ {
+ curEdge.a = curEdge.b;
+ curEdge.b = seg->as[i];
+ if (first)
+ {
+ first = false;
+ continue;
+ }
+ struct bgp_pgbgp_edge finder;
+ finder.e = curEdge;
+ struct bgp_pgbgp_edge *hedge =
+ hash_lookup (pgbgp->edgeT, &finder);
+ if (!hedge)
+ continue;
+ // Is this edge suspicious?
+ if (hedge->deprefUntil > t_now
+ && hedge->deprefUntil > max_depref)
+ max_depref = hedge->deprefUntil;
+ }
+ }
+
+ if (max_depref)
+ {
+ if (!minMax || max_depref < minMax)
+ minMax = max_depref;
+ }
+ else
+ {
+ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_E))
+ {
+ UNSET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_E);
+ numChanged += 1;
+ }
+ }
+ }
+ struct bgp_info *ri = data.rn->info;
+ if (numChanged > 0 && ri)
+ bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi,
+ data.rn->table->safi);
+
+ struct bgp_pgbgp_hist *hist = data.rn->hist;
+ hist->pEdgeReuse = NULL;
+
+ if (minMax)
+ {
+ struct bgp_pgbgp_reuse *r;
+ r = XCALLOC (MTYPE_BGP_PGBGP_REUSE, sizeof (struct bgp_pgbgp_reuse));
+ r->type = PGBGP_REUSE_EDGE;
+ r->deprefUntil = minMax;
+ r->data.edge.rn = data.rn;
+ pqueue_enqueue (r, pgbgp->reuse_q);
+ pgbgp->rq_size += 1;
+ hist->pEdgeReuse = r;
+ }
+ else
+ {
+ bgp_unlock_node (data.rn);
+ }
+
+ return 0;
+}
--- /dev/null
+++ b/bgpd/bgp_pgbgp.h
@@ -0,0 +1,286 @@
+/* BGP Pretty Good BGP
+ Copyright (C) 2008 University of New Mexico (Josh Karlin)
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef _QUAGGA_BGP_PGBGP_H
+#define _QUAGGA_BGP_PGBGP_H
+
+#include "bgpd.h"
+#include "bgp_route.h"
+#include "table.h"
+
+#define MOAS 0
+#define SUBPREFIX 1
+#define EDGE 2
+
+/* Global PGBGP data */
+struct bgp_pgbgp_config
+{
+ /* Depref time for a new origin AS */
+ time_t origin_sus_time;
+
+ /* Depref time for a new edge */
+ time_t edge_sus_time;
+
+ /* Depref time for a new sub-prefix */
+ time_t sub_sus_time;
+
+ /* Origin AS Mapping History Length */
+ time_t origin_hist_time;
+
+ /* Prefix Mapping History Length */
+ time_t prefix_hist_time;
+
+ /* Edge Mapping History Length */
+ time_t edge_hist_time;
+
+ /* Peer Mapping History Length */
+ time_t peer_hist_time;
+
+ /* The list of depreferenced routes */
+ struct pqueue *reuse_q;
+ int rq_size;
+
+ /* Time that the last garbage collection (gc) took place */
+ time_t lastgc;
+
+ /* History table */
+ // struct route_table *histT;
+
+ /* Edge Hash Table */
+ struct hash *edgeT;
+
+ /* File path for history storage */
+ char *storage;
+
+ /* File path for dump of anomalous routes */
+ char *anomalies;
+
+ /* The time that we last stored to disk */
+ time_t lastStore;
+
+ /* The time that PGBGP started counting */
+ time_t startTime;
+
+ /* Last time each peer was seen */
+ struct bgp_pgbgp_peerTime *peerLast;
+
+};
+
+
+struct bgp_pgbgp_peerTime
+{
+ struct bgp_pgbgp_peerTime *next;
+ time_t lastSeen;
+ union sockunion su;
+ time_t deprefUntil;
+};
+
+struct edge
+{
+ as_t a;
+ as_t b;
+};
+
+/*
+ Avoid the neighbors for the less specific that told you about
+ the more specific
+ */
+struct bgp_pgbgp_avoid
+{
+ struct bgp_pgbgp_avoid *next;
+ time_t avoidUntil;
+ as_t peerASN;
+ struct bgp_node *sub;
+};
+
+/* A list of origin ASes for a path
+ Usually it's only one but if the last AS
+ in the path is an AS set, then the whole
+ set must be returned
+*/
+struct bgp_pgbgp_pathSet
+{
+ int length;
+ as_t *ases;
+};
+
+/*
+ Avoid paths with suspicious origins
+ */
+struct bgp_pgbgp_origin
+{
+ struct bgp_pgbgp_origin *next;
+ time_t lastSeen;
+ time_t deprefUntil;
+ as_t originAS;
+};
+
+/*
+ Ignore routes for this prefix
+ */
+struct bgp_pgbgp_prefix
+{
+ time_t lastSeen;
+ time_t ignoreUntil;
+ struct bgp_pgbgp_avoid *avoid;
+};
+
+struct bgp_pgbgp_edge
+{
+ time_t lastSeen;
+ time_t deprefUntil;
+ struct edge e;
+};
+
+struct bgp_pgbgp_hist
+{
+ struct bgp_pgbgp_origin *o;
+ struct bgp_pgbgp_prefix *p;
+ struct bgp_pgbgp_reuse *pEdgeReuse;
+};
+
+struct bgp_pgbgp_r_origin
+{
+ as_t originAS;
+ struct bgp_node *rn;
+};
+
+struct bgp_pgbgp_r_prefix
+{
+ struct bgp_node *rn;
+ struct bgp_node *rnsuper;
+};
+
+/*
+ This node contained a route with a bad edge, check
+ it again for bad edges in 24 hours
+*/
+struct bgp_pgbgp_r_edge
+{
+ struct bgp_node *rn;
+};
+
+
+union reuseTypes
+{
+ struct bgp_pgbgp_r_origin origin;
+ struct bgp_pgbgp_r_prefix prefix;
+ struct bgp_pgbgp_r_edge edge;
+};
+
+struct bgp_pgbgp_reuse
+{
+ union reuseTypes data;
+ short type;
+ time_t deprefUntil;
+};
+
+#define ANOMALOUS(V) \
+(CHECK_FLAG(V, BGP_INFO_SUSPICIOUS_O | BGP_INFO_SUSPICIOUS_P \
+ | BGP_INFO_SUSPICIOUS_E | BGP_INFO_IGNORED_P))
+
+#define PGBGP_REUSE_ORIGIN 0
+#define PGBGP_REUSE_PREFIX 1
+#define PGBGP_REUSE_EDGE 2
+
+#define BGP_PGBGP_NONE 0
+#define BGP_PGBGP_DEPREFFED 1
+
+// For storage
+#define ORIGIN_ID 0
+#define PREFIX_ID 1
+#define EDGE_ID 2
+#define PEER_ID 3
+
+/* Default timing values */
+#define DEFAULT_ORIGIN_SUS (86400 * 1)
+#define DEFAULT_EDGE_SUS (86400 * 1)
+#define DEFAULT_SUB_SUS (86400 * 1)
+#define DEFAULT_ORIGIN_HIST (86400 * 30)
+#define DEFAULT_PREFIX_HIST (86400 * 10)
+#define DEFAULT_EDGE_HIST (86400 * 60)
+// Time between garbage collections
+#define PGBGP_GC_DELTA (3600)
+// Time between file stores
+#define PGBGP_STORE_DELTA (28800)
+// Time that a new peer's routes are not considered suspicious
+#define PGBGP_PEER_GRACE (86400 * 1)
+
+
+
+///////// PUBLIC PGBGP FUNCTIONS /////////
+
+/*
+ bgp_pgbgp_enable:
+ Enable PGBGP depreferencing / history tracking for this afi/safi
+
+ Arguments:
+ . ost: Depref. time of new prefix origins (in hours)
+ . est: Depref. time of new edges (in hours)
+ . sst: Depref. time of new sub-prefixes (in hours)
+ . oht: Storage time of known origins for prefixes (in days)
+ . pht: Storage time of known prefixes (in days)
+ . eht: Storage time of known edges (in days)
+ . storage: File to periodically store history in (can be /dev/null)
+ . anoms: File to store history of depreferenced routes (can be /dev/null)
+
+ Caution:
+ It is important that the storage times are longer than the depreference times
+*/
+extern int bgp_pgbgp_enable (struct bgp *, afi_t afi, safi_t safi, int ost,
+ int est, int sst, int oht, int pht, int eht,
+ const char *storage, const char *anoms);
+extern int bgp_pgbgp_disable (struct bgp *, afi_t afi, safi_t safi);
+
+/*
+ bgp_pgbgp_update:
+ Call on the event of an announcement update
+
+ Arguments:
+ bgp_info: The route
+ at: The new route's attributes
+*/
+extern int bgp_pgbgp_update (struct bgp_info *, struct attr *at,
+ struct bgp_node *);
+
+/*
+ bgp_pgbgp_rib_updated:
+ Call upon discovery of a new best path (or lack thereof)
+
+ This is a special case function for smoothly handling sub-prefix hijacks.
+
+ It handles the following 2 events:
+
+ Event 1: An anomalous sub-prefix is ignored, but no best route for the super-prefix exists
+ Response: Announce the sub-prefix until the super-prefix comes back
+
+ Event 2: A super-prefix comes back to the RIB and its anomalous sub-prefix is in use
+ Response: Ignore the sub-prefix again
+
+ Arguments:
+ rn: The route node that a new best path was found for
+ old_best: The old best route (NULL if one did not exist)
+ new_best: The current best route (NULL if one does not exist)
+ */
+extern int
+bgp_pgbgp_rib_updated (struct bgp_node *rn, struct bgp_info *old_best,
+ struct bgp_info *new_best);
+
+#endif
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -51,6 +51,7 @@ Software Foundation, Inc., 59 Temple Pla
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_damp.h"
+#include "bgpd/bgp_pgbgp.h"
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_vty.h"
@@ -339,12 +340,19 @@ bgp_info_cmp (struct bgp *bgp, struct bg
*paths_eq = 0;
+
/* 0. Null check. */
if (new == NULL)
return 0;
if (exist == NULL)
return 1;
+ /* 0.5 PGBGP Depref. Check */
+ if (ANOMALOUS(exist->flags) && !ANOMALOUS(new->flags))
+ return 1;
+ if (!ANOMALOUS(exist->flags) && ANOMALOUS(new->flags))
+ return 0;
+
/* 1. Weight check. */
if (new->attr->extra)
new_weight = new->attr->extra->weight;
@@ -1583,6 +1591,10 @@ bgp_process_main (struct work_queue *wq,
UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG);
}
+ /* PGBGP needs to know about selected routes */
+ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP))
+ bgp_pgbgp_rib_updated(rn, old_select, new_select);
+
/* Check each BGP peer. */
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
@@ -1906,6 +1918,11 @@ bgp_update_rsclient (struct peer *rsclie
/* If the update is implicit withdraw. */
if (ri)
{
+ /* Update PGBGP state, and mark the route as anomalous if necessary */
+ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP)
+ && peer_sort(peer) == BGP_PEER_EBGP)
+ bgp_pgbgp_update(ri, attr_new, rn);
+
ri->uptime = bgp_clock ();
/* Same attribute comes in. */
@@ -2337,6 +2354,11 @@ bgp_update_main (struct peer *peer, stru
/* Increment prefix */
bgp_aggregate_increment (bgp, p, new, afi, safi);
+ /* Update PGBGP state, and mark the route as anomalous if necessary */
+ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP)
+ && peer_sort(peer) == BGP_PEER_EBGP)
+ bgp_pgbgp_update(new, attr_new, rn);
+
/* Register new BGP information. */
bgp_info_add (rn, new);
@@ -5559,6 +5581,20 @@ enum bgp_display_type
static void
route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo)
{
+ if (ANOMALOUS(binfo->flags))
+ {
+ vty_out(vty, "a[");
+ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_P))
+ vty_out(vty, "i");
+ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_O))
+ vty_out(vty, "p");
+ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_E))
+ vty_out(vty, "e");
+ if (CHECK_FLAG(binfo->flags, BGP_INFO_IGNORED_P))
+ vty_out(vty, "s");
+ vty_out(vty, "] ");
+ }
+
/* Route status display. */
if (CHECK_FLAG (binfo->flags, BGP_INFO_REMOVED))
vty_out (vty, "R");
@@ -6064,6 +6100,7 @@ route_vty_out_detail (struct vty *vty, s
}
#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s r RIB-failure, S Stale, R Removed%s"
+#define BGP_SHOW_PCODE_HEADER "Status code: a (anomalous) of: [p] prefix hijack, [s] sub-prefix hijack,%s [i] informant of sub-prefix [e] new edge%s"
#define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s"
#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s"
#define BGP_SHOW_DAMP_HEADER " Network From Reuse Path%s"
@@ -6095,7 +6132,8 @@ enum bgp_show_type
bgp_show_type_flap_route_map,
bgp_show_type_flap_neighbor,
bgp_show_type_dampend_paths,
- bgp_show_type_damp_neighbor
+ bgp_show_type_damp_neighbor,
+ bgp_show_type_anomalous_paths
};
static int
@@ -6262,11 +6300,17 @@ bgp_show_table (struct vty *vty, struct
|| CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
continue;
}
+ if (type == bgp_show_type_anomalous_paths)
+ {
+ if (! ANOMALOUS(ri->flags))
+ continue;
+ }
if (header)
{
vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (*router_id), VTY_NEWLINE);
vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_PCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
if (type == bgp_show_type_dampend_paths
|| type == bgp_show_type_damp_neighbor)
@@ -6344,6 +6388,7 @@ bgp_show (struct vty *vty, struct bgp *b
return bgp_show_table (vty, table, &bgp->router_id, type, output_arg);
}
+
/* Header of detailed BGP route information */
static void
route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
@@ -11904,6 +11949,64 @@ DEFUN (bgp_damp_set,
half, reuse, suppress, max);
}
+DEFUN (bgp_pgbgp_arg,
+ bgp_pgbgp_arg_cmd,
+ "bgp pgbgp <1-100> <1-100> <1-100> <1-365> <1-365> <1-365> WORD WORD",
+ "BGP Specific commands\n"
+ "Enable Pretty Good BGP\n"
+ "New origin depref time (in hours)\n"
+ "New edge depref time (in hours)\n"
+ "New sub-prefix depref time (in hours)\n"
+ "Origin history time (in days)\n"
+ "Prefix history time (in days)\n"
+ "Edge history time (in days)\n"
+ "Log file for history data\n"
+ "Log file of anomalies\n")
+{
+ struct bgp *bgp;
+
+ int ost = DEFAULT_ORIGIN_SUS;
+ int est = DEFAULT_EDGE_SUS;
+ int sst = DEFAULT_SUB_SUS;
+ int oht = DEFAULT_ORIGIN_HIST;
+ int pht = DEFAULT_PREFIX_HIST;
+ int eht = DEFAULT_EDGE_HIST;
+ const char* path = "/var/log/quagga/pgbgp_hist";
+ const char* anoms = "/var/log/quagga/pgbgp_anomalies";
+
+ if (argc == 8)
+ {
+ VTY_GET_INTEGER("origin depref time", ost, argv[0]);
+ VTY_GET_INTEGER("edge depref time", est, argv[1]);
+ VTY_GET_INTEGER("sub-prefix depref time", sst, argv[2]);
+ VTY_GET_INTEGER("origin history time", oht, argv[3]);
+ VTY_GET_INTEGER("prefix history time", pht, argv[4]);
+ VTY_GET_INTEGER("edge history time", eht, argv[5]);
+ path = argv[6];
+ anoms = argv[7];
+ }
+
+ bgp = vty->index;
+ return bgp_pgbgp_enable(bgp, bgp_node_afi (vty), bgp_node_safi (vty),
+ ost, est, sst, oht, pht, eht, path, anoms);
+}
+
+ALIAS (bgp_pgbgp_arg,
+ bgp_pgbgp_cmd,
+ "bgp pgbgp",
+ "BGP specific commands\n"
+ "Enable Pretty Good BGP\n")
+
+DEFUN (bgp_pgbgp_unset,
+ bgp_pgbgp_unset_cmd,
+ "no bgp pgbgp\n",
+ "BGP specific commands\n")
+{
+ struct bgp *bgp;
+ bgp = vty->index;
+ return bgp_pgbgp_disable (bgp, bgp_node_afi (vty), bgp_node_safi (vty));
+}
+
ALIAS (bgp_damp_set,
bgp_damp_set2_cmd,
"bgp dampening <1-45>",
@@ -11953,6 +12056,19 @@ DEFUN (show_ip_bgp_dampened_paths,
NULL);
}
+DEFUN (show_ip_bgp_anomalous_paths,
+ show_ip_bgp_anomalous_paths_cmd,
+ "show ip bgp anomalous-paths",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display anomalous paths (less likely to be used)\n")
+{
+ return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_anomalous_paths,
+ NULL);
+}
+
+
DEFUN (show_ip_bgp_flap_statistics,
show_ip_bgp_flap_statistics_cmd,
"show ip bgp flap-statistics",
@@ -12479,6 +12595,7 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd);
install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_anomalous_paths_cmd);
install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd);
install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd);
install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd);
@@ -12612,6 +12729,7 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_anomalous_paths_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd);
@@ -13002,6 +13120,10 @@ bgp_route_init (void)
install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd);
install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd);
+ install_element (BGP_NODE, &bgp_pgbgp_cmd);
+ install_element (BGP_NODE, &bgp_pgbgp_arg_cmd);
+ install_element (BGP_NODE, &bgp_pgbgp_unset_cmd);
+
/* Deprecated AS-Pathlimit commands */
install_element (BGP_NODE, &bgp_network_ttl_cmd);
install_element (BGP_NODE, &bgp_network_mask_ttl_cmd);
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -1,3 +1,4 @@
+
/* BGP routing information base
Copyright (C) 1996, 97, 98, 2000 Kunihiro Ishiguro
@@ -68,7 +69,7 @@ struct bgp_info
int lock;
/* BGP information status. */
- u_int16_t flags;
+ u_int32_t flags;
#define BGP_INFO_IGP_CHANGED (1 << 0)
#define BGP_INFO_DAMPED (1 << 1)
#define BGP_INFO_HISTORY (1 << 2)
@@ -82,6 +83,10 @@ struct bgp_info
#define BGP_INFO_COUNTED (1 << 10)
#define BGP_INFO_MULTIPATH (1 << 11)
#define BGP_INFO_MULTIPATH_CHG (1 << 12)
+#define BGP_INFO_SUSPICIOUS_O (1 << 13)
+#define BGP_INFO_SUSPICIOUS_P (1 << 14)
+#define BGP_INFO_IGNORED_P (1 << 15)
+#define BGP_INFO_SUSPICIOUS_E (1 << 16)
/* BGP route type. This can be static, RIP, OSPF, BGP etc. */
u_char type;
@@ -126,7 +131,7 @@ struct bgp_static
/* Flags which indicate a route is unuseable in some form */
#define BGP_INFO_UNUSEABLE \
- (BGP_INFO_HISTORY|BGP_INFO_DAMPED|BGP_INFO_REMOVED)
+ (BGP_INFO_HISTORY|BGP_INFO_DAMPED|BGP_INFO_REMOVED|BGP_INFO_IGNORED_P)
/* Macro to check BGP information is alive or not. Sadly,
* not equivalent to just checking previous, because of the
* sense of the additional VALID flag.
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -65,6 +65,8 @@ struct bgp_node
int lock;
+ struct bgp_pgbgp_hist *hist;
+
u_char flags;
#define BGP_NODE_PROCESS_SCHEDULED (1 << 0)
};
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -123,6 +123,7 @@ struct bgp
/* BGP Per AF flags */
u_int16_t af_flags[AFI_MAX][SAFI_MAX];
#define BGP_CONFIG_DAMPENING (1 << 0)
+#define BGP_CONFIG_PGBGP (1 << 1)
/* Static route configuration. */
struct bgp_table *route[AFI_MAX][SAFI_MAX];
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -166,6 +166,35 @@ hash_iterate (struct hash *hash,
}
}
+/*
+ Iterates until 0 is returned or until completion
+ Return: 1 if iteration completed
+ Return: 0 if iteration was interrupted
+*/
+
+int
+hash_iterate_until(struct hash *hash,
+ int (*func) (struct hash_backet *, void *), void *arg)
+{
+ unsigned int i;
+ struct hash_backet *hb;
+ struct hash_backet *hbnext;
+ int ret;
+
+ for (i = 0; i < hash->size; i++)
+ for (hb = hash->index[i]; hb; hb = hbnext)
+ {
+ /* get pointer to next hash backet here, in case (*func)
+ * decides to delete hb by calling hash_release
+ */
+ hbnext = hb->next;
+ ret = (*func) (hb, arg);
+ if (!ret)
+ return 0;
+ }
+ return 1;
+}
+
/* Clean up hash. */
void
hash_clean (struct hash *hash, void (*free_func) (void *))
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -66,7 +66,8 @@ extern void *hash_release (struct hash *
extern void hash_iterate (struct hash *,
void (*) (struct hash_backet *, void *), void *);
-
+extern int hash_iterate_until(struct hash *,
+ int (*) (struct hash_backet *, void *), void *);
extern void hash_clean (struct hash *, void (*) (void *));
extern void hash_free (struct hash *);
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -148,6 +148,15 @@ struct memory_list memory_list_bgp[] =
{ MTYPE_PEER_UPDATE_SOURCE, "BGP peer update interface" },
{ MTYPE_BGP_DAMP_INFO, "Dampening info" },
{ MTYPE_BGP_DAMP_ARRAY, "BGP Dampening array" },
+ { 0, NULL },
+ { MTYPE_BGP_PGBGP_ORIGIN, "BGP PGBGP Origin AS Node" },
+ { MTYPE_BGP_PGBGP_PREFIX, "BGP PGBGP Prefix AS Node" },
+ { MTYPE_BGP_PGBGP_EDGE, "BGP PGBGP Edge Node" },
+ { MTYPE_BGP_PGBGP_REUSE, "BGP PGBGP Reuse Node" },
+ { MTYPE_BGP_PGBGP_HIST, "BGP PGBGP History Node" },
+ { MTYPE_BGP_PGBGP_AVOID, "BGP PGBGP Avoid Peer Node" },
+ { MTYPE_BGP_PGBGP_PEER, "BGP PGBGP Peer Timing" },
+ { 0, NULL },
{ MTYPE_BGP_REGEXP, "BGP regexp" },
{ MTYPE_BGP_AGGREGATE, "BGP aggregate" },
{ -1, NULL }
From: Paul Jakma <paul.jakma@sun.com>
Date: Thu, 4 Sep 2008 22:27:13 +0000 (+0100)
Subject: [bgp/pgbgp] Add some pgbgp commands to restricted-mode and other command tweaks
X-Git-Url: http://git.ozo.com/?p=quagga-pgbg.git;a=commitdiff_plain;h=06ac72f9f6021635e9e1e5105c3e22bf7eb0d6c3
[bgp/pgbgp] Add some pgbgp commands to restricted-mode and other command tweaks
* bgp_pgbgp.c:
(edge_neighbor_iterator) make ASN==0 mean 'iterate over all ASNs'
(bgp_pgbgp_stats_origin_one) new function, to display one origin AS status.
(bgp_pgbgp_stats_origins) adapt to use previous.
Adapt to iterate over all stats if no prefix was giving.
(show_ip_bgp_pgbgp_neighbors_cmd) recognise no ASN argument case
(show_ip_bgp_pgbgp_neighbors_all_cmd) Iterate over all
(show_ip_bgp_pgbgp_origins_cmd) similar
(show_ip_bgp_pgbgp_origins_all_cmd)
(bgp_pgbgp_enable) install the lookup commands to ther new RESTRICTED_NODE
* bgp_route.c:
(route_vty_short_status_out) only allowed to print one char for anomalous
status.
(route_vty_out_detail) Add support for printing out more detail on
PG-BGP status
---
--- a/bgpd/bgp_pgbgp.c
+++ b/bgpd/bgp_pgbgp.c
@@ -227,7 +227,7 @@ static void
edge_neighbor_iterator (struct hash_backet *backet, struct nsearch *pns)
{
struct bgp_pgbgp_edge *hedge = backet->data;
- if ((hedge->e.a == pns->asn || hedge->e.b == pns->asn)
+ if ((!pns->asn || hedge->e.a == pns->asn || hedge->e.b == pns->asn)
&& hedge->e.a != hedge->e.b)
{
struct vty *vty = pns->pvty;
@@ -254,13 +254,39 @@ bgp_pgbgp_stats_neighbors (struct vty *v
return CMD_SUCCESS;
}
+static void
+bgp_pgbgp_stats_origin_one (struct vty *vty, struct bgp_node *rn,
+ time_t t_now)
+{
+ char str[INET6_BUFSIZ];
+
+ if (!rn->hist)
+ return;
+
+ prefix2str (&rn->p, str, sizeof(str));
+ vty_out (vty, "%s%s", str, VTY_NEWLINE);
+
+ for (struct bgp_pgbgp_origin * cur = rn->hist->o; cur != NULL;
+ cur = cur->next)
+ {
+ if (cur->deprefUntil > t_now)
+ vty_out (vty, "Untrusted Origin AS: %d%s", cur->originAS,
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "Trusted Origin AS: %d%s", cur->originAS,
+ VTY_NEWLINE);
+ }
+}
+
static int
bgp_pgbgp_stats_origins (struct vty *vty, afi_t afi, safi_t safi,
const char *prefix)
{
struct bgp *bgp;
struct bgp_table *table;
+ struct bgp_node *rn;
time_t t_now = time (NULL);
+
bgp = bgp_get_default ();
if (bgp == NULL)
return CMD_WARNING;
@@ -269,28 +295,22 @@ bgp_pgbgp_stats_origins (struct vty *vty
table = bgp->rib[afi][safi];
if (table == NULL)
return CMD_WARNING;
-
- struct prefix p;
- str2prefix (prefix, &p);
- struct bgp_node *rn = bgp_node_match (table, &p);
- vty_out (vty, "%s%s", prefix, VTY_NEWLINE);
- if (rn)
+
+ if (prefix)
{
+ struct prefix p;
+ str2prefix (prefix, &p);
+ rn = bgp_node_match (table, &p);
if (rn->hist)
- {
- for (struct bgp_pgbgp_origin * cur = rn->hist->o; cur != NULL;
- cur = cur->next)
- {
- if (cur->deprefUntil > t_now)
- vty_out (vty, "Untrusted Origin AS: %d%s", cur->originAS,
- VTY_NEWLINE);
- else
- vty_out (vty, "Trusted Origin AS: %d%s", cur->originAS,
- VTY_NEWLINE);
- }
- }
+ bgp_pgbgp_stats_origin_one (vty, rn, t_now);
bgp_unlock_node (rn);
+ return CMD_SUCCESS;
}
+
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ if (rn->hist)
+ bgp_pgbgp_stats_origin_one (vty, rn, t_now);
+
return CMD_SUCCESS;
}
@@ -377,7 +397,7 @@ bgp_pgbgp_stats (struct vty *vty, afi_t
DEFUN (show_ip_bgp_pgbgp,
show_ip_bgp_pgbgp_cmd,
"show ip bgp pgbgp",
- SHOW_STR IP_STR BGP_STR "Display PGBGP statistics\n")
+ SHOW_STR IP_STR BGP_STR "Pretty-Good BGP statistics\n")
{
return bgp_pgbgp_stats (vty, AFI_IP, SAFI_UNICAST);
}
@@ -385,29 +405,46 @@ DEFUN (show_ip_bgp_pgbgp,
DEFUN (show_ip_bgp_pgbgp_neighbors,
show_ip_bgp_pgbgp_neighbors_cmd,
"show ip bgp pgbgp neighbors WORD",
- SHOW_STR
- IP_STR
- BGP_STR
- "BGP pgbgp\n"
- "BGP pgbgp neighbors\n" "ASN whos neighbors should be displayed\n")
+ SHOW_STR IP_STR BGP_STR
+ "Pretty-Good BGP statistics\n"
+ "PG-BGP neighbor information\n"
+ "AS to show neighbors of\n")
{
return bgp_pgbgp_stats_neighbors (vty, AFI_IP, SAFI_UNICAST,
- atoi (argv[0]));
+ argc == 1 ? atoi (argv[0]) : 0);
}
+ALIAS (show_ip_bgp_pgbgp_neighbors,
+ show_ip_bgp_pgbgp_neighbors_all_cmd,
+ "show ip bgp pgbgp neighbors",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Pretty-Good BGP statistics\n"
+ "PG-BGP neighbors information\n")
+
DEFUN (show_ip_bgp_pgbgp_origins,
show_ip_bgp_pgbgp_origins_cmd,
"show ip bgp pgbgp origins A.B.C.D/M",
SHOW_STR
IP_STR
BGP_STR
- "BGP pgbgp\n"
- "BGP pgbgp neighbors\n" "Prefix to look up origin ASes of\n")
+ "Pretty-Good BGP statistics\n"
+ "PG-BGP prefix origin information\n"
+ "Prefix to look up origin ASes of\n")
{
- return bgp_pgbgp_stats_origins (vty, AFI_IP, SAFI_UNICAST, argv[0]);
+ return bgp_pgbgp_stats_origins (vty, AFI_IP, SAFI_UNICAST,
+ argc == 1 ? argv[0] : NULL);
}
-
+ALIAS (show_ip_bgp_pgbgp_origins,
+ show_ip_bgp_pgbgp_origins_all_cmd,
+ "show ip bgp pgbgp origins",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Pretty-Good BGP statistics\n"
+ "PG-BGP prefixes origin information")
/*! --------------- VTY (others exist in bgp_route.c) ------------------ !*/
@@ -749,12 +786,19 @@ bgp_pgbgp_enable (struct bgp *bgp, afi_t
pgbgp->lastgc = time (NULL);
pgbgp->lastStore = time (NULL);
pgbgp->startTime = time (NULL);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_pgbgp_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_pgbgp_neighbors_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_pgbgp_origins_cmd);
install_element (VIEW_NODE, &show_ip_bgp_pgbgp_cmd);
- install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_cmd);
install_element (VIEW_NODE, &show_ip_bgp_pgbgp_neighbors_cmd);
- install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_neighbors_cmd);
install_element (VIEW_NODE, &show_ip_bgp_pgbgp_origins_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_neighbors_all_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_origins_all_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_neighbors_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_origins_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_neighbors_all_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_origins_all_cmd);
pgbgp->edgeT = hash_create_size (131072, edge_key_make, edge_cmp);
bgp_pgbgp_restore ();
return 0;
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -5581,20 +5581,6 @@ enum bgp_display_type
static void
route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo)
{
- if (ANOMALOUS(binfo->flags))
- {
- vty_out(vty, "a[");
- if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_P))
- vty_out(vty, "i");
- if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_O))
- vty_out(vty, "p");
- if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_E))
- vty_out(vty, "e");
- if (CHECK_FLAG(binfo->flags, BGP_INFO_IGNORED_P))
- vty_out(vty, "s");
- vty_out(vty, "] ");
- }
-
/* Route status display. */
if (CHECK_FLAG (binfo->flags, BGP_INFO_REMOVED))
vty_out (vty, "R");
@@ -5610,6 +5596,17 @@ route_vty_short_status_out (struct vty *
/* Selected */
if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
vty_out (vty, "h");
+ else if (ANOMALOUS(binfo->flags))
+ {
+ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_O))
+ vty_out(vty, "p");
+ else if (CHECK_FLAG(binfo->flags, BGP_INFO_IGNORED_P))
+ vty_out(vty, "P");
+ else if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_P))
+ vty_out(vty, "a");
+ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_E))
+ vty_out(vty, "a");
+ }
else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
vty_out (vty, "d");
else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
@@ -6088,7 +6085,22 @@ route_vty_out_detail (struct vty *vty, s
if (binfo->extra && binfo->extra->damp_info)
bgp_damp_info_vty (vty, binfo);
- /* Line 7 display Uptime */
+ /* 8: PGBGP status */
+ if (ANOMALOUS(binfo->flags))
+ {
+ vty_out (vty, " Anomalous:");
+ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_P))
+ vty_out (vty, " divergent sub-prefixes,");
+ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_O))
+ vty_out (vty, " origin AS (prefix hijack?),");
+ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_E))
+ vty_out (vty, " new edge in path,");
+ if (CHECK_FLAG(binfo->flags, BGP_INFO_IGNORED_P))
+ vty_out (vty, " origin AS (sub-prefix hijack?),");
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+
+ /* Line 9 display Uptime */
#ifdef HAVE_CLOCK_MONOTONIC
tbuf = time(NULL) - (bgp_clock() - binfo->uptime);
vty_out (vty, " Last update: %s", ctime(&tbuf));
@@ -6099,8 +6111,9 @@ route_vty_out_detail (struct vty *vty, s
vty_out (vty, "%s", VTY_NEWLINE);
}
-#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s r RIB-failure, S Stale, R Removed%s"
-#define BGP_SHOW_PCODE_HEADER "Status code: a (anomalous) of: [p] prefix hijack, [s] sub-prefix hijack,%s [i] informant of sub-prefix [e] new edge%s"
+#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s" \
+ " r RIB-failure, S Stale, R Removed, %s" \
+ " p prefix hijack, P sub-prefix hijack, a other anomaly%s"
#define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s"
#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s"
#define BGP_SHOW_DAMP_HEADER " Network From Reuse Path%s"
@@ -6309,8 +6322,7 @@ bgp_show_table (struct vty *vty, struct
if (header)
{
vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (*router_id), VTY_NEWLINE);
- vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
- vty_out (vty, BGP_SHOW_PCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
if (type == bgp_show_type_dampend_paths
|| type == bgp_show_type_damp_neighbor)
@@ -9842,7 +9854,7 @@ show_adj_route (struct vty *vty, struct
PEER_STATUS_DEFAULT_ORIGINATE))
{
vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
- vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
vty_out (vty, "Originating default network 0.0.0.0%s%s",
@@ -9859,7 +9871,7 @@ show_adj_route (struct vty *vty, struct
if (header1)
{
vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
- vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
header1 = 0;
}
@@ -9883,7 +9895,7 @@ show_adj_route (struct vty *vty, struct
if (header1)
{
vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
- vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
header1 = 0;
}
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -269,7 +269,7 @@ vtysh_pager_init (void)
if (pager_defined)
vtysh_pager_name = strdup (pager_defined);
else
- vtysh_pager_name = strdup ("more");
+ vtysh_pager_name = strdup ("cat");
}
/* Command execution over the vty interface. */
@@ -1885,7 +1885,7 @@ DEFUN (vtysh_terminal_length,
{
int lines;
char *endptr = NULL;
- char default_pager[10];
+ char default_pager[12];
lines = strtol (argv[0], &endptr, 10);
if (lines < 0 || lines > 512 || *endptr != '\0')
@@ -1902,7 +1902,7 @@ DEFUN (vtysh_terminal_length,
if (lines != 0)
{
- snprintf(default_pager, 10, "more -%i", lines);
+ snprintf(default_pager, 12, "head -n %i", lines);
vtysh_pager_name = strdup (default_pager);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册