DEP_FINDPARAMS := -x "*/.svn*" -x ".*" -x "*:*" -x "*\!*" -x "* *" -x "*\\\#*" -x "*/.*_check"
-find_md5=find $(1) -type f $(patsubst -x,-and -not -path,$(DEP_FINDPARAMS) $(2)) | md5s
+find_md5=$(SH_FUNC) find $(1) -type f $(patsubst -x,-and -not -path,$(DEP_FINDPARAMS) $(2)) | md5s
define rdep
.PRECIOUS: $(2)
define BuildIPKGVariable
ifdef Package/$(1)/$(2)
$(call shexport,Package/$(1)/$(2))
- $(1)_COMMANDS += var2file "$(call shvar,Package/$(1)/$(2))" $(2);
+ $(1)_COMMANDS += $(SH_FUNC) var2file "$(call shvar,Package/$(1)/$(2))" $(2);
endif
endef
$(call $(hook),$(TMP_DIR)/stage-$(PKG_NAME),$(TMP_DIR)/stage-$(PKG_NAME)/host)$(sep)\
)
if [ -d $(TMP_DIR)/stage-$(PKG_NAME) ]; then \
- (cd $(TMP_DIR)/stage-$(PKG_NAME); find ./ > $(STAGING_DIR)/packages/$(STAGING_FILES_LIST)); \
+ (cd $(TMP_DIR)/stage-$(PKG_NAME); $(SH_FUNC) find ./ > $(STAGING_DIR)/packages/$(STAGING_FILES_LIST)); \
$(CP) $(TMP_DIR)/stage-$(PKG_NAME)/* $(STAGING_DIR)/; \
fi
rm -rf $(TMP_DIR)/stage-$(PKG_NAME)
echo "Target-Profile-Kconfig: yes"; \
fi; \
echo "Target-Profile-Config: "; \
- getvar "$(call shvar,Profile/$(1)/Config)"; \
+ $(SH_FUNC) getvar "$(call shvar,Profile/$(1)/Config)"; \
echo "@@"; \
echo "Target-Profile-Description:"; \
- getvar "$(call shvar,Profile/$(1)/Description)"; \
+ $(SH_FUNC) getvar "$(call shvar,Profile/$(1)/Description)"; \
echo "@@"; \
echo;
ifeq ($(CONFIG_TARGET_$(call target_conf,$(BOARD)_$(if $(SUBTARGET),$(SUBTARGET)_)$(1))),y)
echo 'Linux-Release: $(LINUX_RELEASE)'; \
echo 'Linux-Kernel-Arch: $(LINUX_KARCH)'; \
echo 'Target-Description:'; \
- getvar $(call shvar,Target/Description); \
+ $(SH_FUNC) getvar $(call shvar,Target/Description); \
echo '@@'; \
echo 'Default-Packages: $(DEFAULT_PACKAGES)'; \
$(DUMPINFO)
--- /dev/null
+#
+# Copyright (C) 2009-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=bird
+PKG_VERSION:=1.6.0
+PKG_RELEASE:=1
+
+PKG_SOURCE:=bird-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=ftp://bird.network.cz/pub/bird
+PKG_MD5SUM:=4c92ec3548a2a120243879b6ef7046dd
+PKG_BUILD_DEPENDS:=libncurses libreadline
+PKG_MAINTAINER:=Álvaro Fernández Rojas <noltari@gmail.com>
+
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/bird/Default
+ TITLE:=The BIRD Internet Routing Daemon
+ URL:=http://bird.network.cz/
+ DEPENDS:=+libpthread
+endef
+
+define Package/birdc/Default
+ TITLE:=The BIRD command-line client
+ URL:=http://bird.network.cz/
+ DEPENDS:= +libreadline +libncurses
+endef
+
+define Package/birdcl/Default
+ TITLE:=The BIRD lightweight command-line client
+ URL:=http://bird.network.cz/
+endef
+
+define Package/bird/Default/description1
+BIRD is an internet routing daemon which manages TCP/IP routing tables
+with support of modern routing protocols, easy to use configuration
+interface and powerful route filtering language. It is lightweight and
+efficient and therefore appropriate for small embedded routers.
+
+endef
+
+define Package/bird/Default/description2
+In BGP, BIRD supports communities, multiprotocol extensions, MD5
+authentication, 32bit AS numbers and could act as a route server or a
+route reflector. BIRD also supports multiple RIBs, multiple kernel
+routing tables and redistribution between the protocols with a powerful
+configuration syntax.
+
+endef
+
+define Package/bird/Default/description3
+This is a BIRD command-line client. It is used to send commands to BIRD,
+commands can perform simple actions such as enabling/disabling of
+protocols, telling BIRD to show various information, telling it to show
+a routing table filtered by a filter, or asking BIRD to reconfigure.
+
+Unless you can't afford dependency on ncurses and readline, you
+should install BIRD command-line client together with BIRD.
+
+endef
+
+define Package/bird/Default/description4
+This is a BIRD lightweight command-line client. It is used to send commands to BIRD,
+commands can perform simple actions such as enabling/disabling of
+protocols, telling BIRD to show various information, telling it to show
+a routing table filtered by a filter, or asking BIRD to reconfigure.
+
+endef
+
+define Package/bird4
+$(call Package/bird/Default)
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=Routing and Redirection
+ TITLE+= (IPv4)
+endef
+
+define Package/birdc4
+$(call Package/birdc/Default)
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=Routing and Redirection
+ TITLE+= (IPv4)
+ DEPENDS+= +bird4
+endef
+
+define Package/birdcl4
+$(call Package/birdcl/Default)
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=Routing and Redirection
+ TITLE+= (IPv4)
+ DEPENDS+= +bird4
+endef
+
+define Package/bird6
+$(call Package/bird/Default)
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=Routing and Redirection
+ TITLE+= (IPv6)
+endef
+
+define Package/birdc6
+$(call Package/birdc/Default)
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=Routing and Redirection
+ TITLE+= (IPv6)
+ DEPENDS+= +bird6
+endef
+
+define Package/birdcl6
+$(call Package/birdcl/Default)
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=Routing and Redirection
+ TITLE+= (IPv6)
+ DEPENDS+= +bird6
+endef
+
+define Package/bird4/description
+$(call Package/bird/Default/description1)
+This is IPv4 version of BIRD, it supports OSPFv2, RIPv2 and BGP
+protocols.
+
+$(call Package/bird/Default/description2)
+endef
+
+define Package/birdc4/description
+$(call Package/bird/Default/description1)
+$(call Package/bird/Default/description3)
+endef
+
+define Package/birdcl4/description
+$(call Package/bird/Default/description1)
+$(call Package/bird/Default/description4)
+endef
+
+define Package/bird6/description
+$(call Package/bird/Default/description1)
+This is IPv6 version of BIRD, it supports OSPFv3, RIPng and BGP
+protocols.
+
+$(call Package/bird/Default/description2)
+endef
+
+define Package/birdc6/description
+$(call Package/bird/Default/description1)
+$(call Package/bird/Default/description3)
+endef
+
+define Package/birdcl6/description
+$(call Package/bird/Default/description1)
+$(call Package/bird/Default/description4)
+endef
+
+CONFIGURE_ARGS += --with-linux-headers="$(LINUX_DIR)"
+
+TARGET_CFLAGS+=-std=gnu89
+
+define Build/Template
+
+$(STAMP_BUILT)-$(2): $(STAMP_PREPARED)
+ $(call Build/Configure/Default,$(3))
+ $(call Build/Compile/Default,)
+ ( cd $(PKG_BUILD_DIR); mv -f bird bird$(2); mv -f birdc birdc$(2); mv -f birdcl birdcl$(2) )
+ -$(MAKE) -C $(PKG_BUILD_DIR) clean
+ touch $$@
+
+$(STAMP_BUILT): $(STAMP_BUILT)-$(2)
+
+define Package/bird$(2)/install
+ $(INSTALL_DIR) $$(1)/usr/sbin
+ $(INSTALL_BIN) $$(PKG_BUILD_DIR)/bird$(2) $$(1)/usr/sbin/
+ $(INSTALL_DIR) $$(1)/etc
+ $(INSTALL_DATA) ./files/bird$(2).conf $$(1)/etc/
+ $(INSTALL_DIR) $$(1)/etc/init.d
+ $(INSTALL_BIN) ./files/bird$(2).init $$(1)/etc/init.d/bird$(2)
+
+endef
+
+define Package/bird$(2)/conffiles
+/etc/bird$(2).conf
+endef
+
+define Package/birdc$(2)/install
+ $(INSTALL_DIR) $$(1)/usr/sbin
+ $(INSTALL_BIN) $$(PKG_BUILD_DIR)/birdc$(2) $$(1)/usr/sbin/
+endef
+
+define Package/birdcl$(2)/install
+ $(INSTALL_DIR) $$(1)/usr/sbin
+ $(INSTALL_BIN) $$(PKG_BUILD_DIR)/birdcl$(2) $$(1)/usr/sbin/
+endef
+
+endef
+
+
+$(eval $(call Build/Template,bird4,4, --disable-ipv6))
+$(eval $(call Build/Template,bird6,6, --enable-ipv6))
+
+$(eval $(call BuildPackage,bird4))
+$(eval $(call BuildPackage,birdc4))
+$(eval $(call BuildPackage,birdcl4))
+$(eval $(call BuildPackage,bird6))
+$(eval $(call BuildPackage,birdc6))
+$(eval $(call BuildPackage,birdcl6))
--- /dev/null
+
+# THIS CONFIG FILE IS NOT A COMPLETE DOCUMENTATION
+# PLEASE LOOK IN THE BIRD DOCUMENTATION FOR MORE INFO
+
+# However, most of options used here are just for example
+# and will be removed in real-life configs.
+
+log syslog all;
+
+# Override router ID
+#router id 192.168.0.1;
+
+# Turn on global debugging of all protocols
+#debug protocols all;
+
+
+# Define a route filter...
+# filter test_filter {
+# if net ~ 10.0.0.0/16 then accept;
+# else reject;
+# }
+
+# The direct protocol automatically generates device routes to all network
+# interfaces. Can exist in as many instances as you wish if you want to
+# populate multiple routing tables with device routes. Because device routes
+# are handled by Linux kernel, this protocol is usually not needed.
+# protocol direct {
+# interface "*"; # Restrict network interfaces it works with
+# }
+
+# This pseudo-protocol performs synchronization between BIRD's routing
+# tables and the kernel. You can run multiple instances of the kernel
+# protocol and synchronize different kernel tables with different BIRD tables.
+protocol kernel {
+# learn; # Learn all alien routes from the kernel
+# persist; # Don't remove routes on bird shutdown
+ scan time 20; # Scan kernel routing table every 20 seconds
+# import none; # Default is import all
+# export all; # Default is export none
+}
+
+# This pseudo-protocol watches all interface up/down events.
+protocol device {
+ scan time 10; # Scan interfaces every 10 seconds
+}
+
+# Static routes (again, there can be multiple instances, so that you
+# can disable/enable various groups of static routes on the fly).
+protocol static {
+# export all; # Default is export none
+# route 0.0.0.0/0 via 62.168.0.13;
+# route 10.0.0.0/8 reject;
+# route 192.168.0.0/16 reject;
+}
+
+
+#protocol rip {
+# disabled;
+# import all;
+# export all;
+# export filter test_filter;
+
+# port 1520;
+# period 7;
+# infinity 16;
+# garbage time 60;
+# interface "*" { mode broadcast; };
+# honor neighbor;
+# honor always;
+# honor never;
+# authentication none;
+#}
+
+
+#protocol ospf {
+# disabled;
+# import all;
+# export all;
+# export where source = RTS_STATIC;
+
+# area 0 {
+# interface "eth*" {
+# cost 10;
+# hello 3;
+# retransmit 2;
+# wait 5;
+# dead 20;
+# type broadcast;
+# authentication simple;
+# password "pass";
+# };
+# };
+#}
+
+
+#protocol bgp {
+# disabled;
+# import all;
+# export all;
+# export where source = RTS_STATIC;
+
+# local as 65000;
+# neighbor 192.168.1.1 as 65001;
+# multihop 20 via 192.168.2.1;
+
+# hold time 240;
+# startup hold time 240;
+# connect retry time 120;
+# keepalive time 80; # defaults to hold time / 3
+# start delay time 5; # How long do we wait before initial connect
+# error wait time 60, 300;# Minimum and maximum time we wait after an error (when consecutive
+# # errors occur, we increase the delay exponentially ...
+# error forget time 300; # ... until this timeout expires)
+# disable after error; # Disable the protocol automatically when an error occurs
+# next hop self; # Disable next hop processing and always advertise our local address as nexthop
+# source address 62.168.0.14; # What local address we use for the TCP connection
+# password "secret" # Password used for MD5 authentication
+# rr client; # I am a route reflector and the neighor is my client
+# rr cluster id 1.0.0.1 # Use this value for cluster id instead of my router id
+# };
+#}
--- /dev/null
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2010-2011 OpenWrt.org
+
+START=50
+
+SERVICE_DAEMONIZE=1
+SERVICE_WRITE_PID=1
+
+start() {
+ service_start /usr/sbin/bird4 -d
+# ( SERVICE_MATCH_NAME=1 service_start /usr/sbin/bird4loop )
+}
+
+stop() {
+# ( SERVICE_MATCH_NAME=1 service_stop /usr/sbin/bird4loop )
+ service_stop /usr/sbin/bird4
+}
+
+reload() {
+ service_reload /usr/sbin/bird4
+}
--- /dev/null
+#!/bin/sh
+
+BIRD=/usr/sbin/bird4
+
+$BIRD -p || return 1
+
+. /lib/functions.sh
+. /lib/functions/service.sh
+
+SERVICE_DAEMONIZE=1
+SERVICE_WRITE_PID=1
+
+sig_handler() {
+ running=0
+ service_stop $BIRD
+}
+
+running=1
+trap sig_handler INT
+trap sig_handler TERM
+while [ $running -gt 0 ]; do
+ service_check $BIRD || service_start $BIRD -d "$@"
+ sleep 3
+done
--- /dev/null
+
+# THIS CONFIG FILE IS NOT A COMPLETE DOCUMENTATION
+# PLEASE LOOK IN THE BIRD DOCUMENTATION FOR MORE INFO
+
+# However, most of options used here are just for example
+# and will be removed in real-life configs.
+
+log syslog all;
+
+# Override router ID
+#router id 192.168.0.1;
+
+# Turn on global debugging of all protocols
+#debug protocols all;
+
+
+# Define a route filter...
+# filter test_filter {
+# if net ~ 10.0.0.0/16 then accept;
+# else reject;
+# }
+
+# The direct protocol automatically generates device routes to all network
+# interfaces. Can exist in as many instances as you wish if you want to
+# populate multiple routing tables with device routes. Because device routes
+# are handled by Linux kernel, this protocol is usually not needed.
+# protocol direct {
+# interface "*"; # Restrict network interfaces it works with
+# }
+
+# This pseudo-protocol performs synchronization between BIRD's routing
+# tables and the kernel. You can run multiple instances of the kernel
+# protocol and synchronize different kernel tables with different BIRD tables.
+protocol kernel {
+# learn; # Learn all alien routes from the kernel
+# persist; # Don't remove routes on bird shutdown
+ scan time 20; # Scan kernel routing table every 20 seconds
+# import none; # Default is import all
+# export all; # Default is export none
+}
+
+# This pseudo-protocol watches all interface up/down events.
+protocol device {
+ scan time 10; # Scan interfaces every 10 seconds
+}
+
+# Static routes (again, there can be multiple instances, so that you
+# can disable/enable various groups of static routes on the fly).
+protocol static {
+# export all; # Default is export none
+# route 0.0.0.0/0 via 62.168.0.13;
+# route 10.0.0.0/8 reject;
+# route 192.168.0.0/16 reject;
+}
+
+
+#protocol rip {
+# disabled;
+# import all;
+# export all;
+# export filter test_filter;
+
+# port 1520;
+# period 7;
+# infinity 16;
+# garbage time 60;
+# interface "*" { mode broadcast; };
+# honor neighbor;
+# honor always;
+# honor never;
+# authentication none;
+#}
+
+
+#protocol ospf {
+# disabled;
+# import all;
+# export all;
+# export where source = RTS_STATIC;
+
+# area 0 {
+# interface "eth*" {
+# cost 10;
+# hello 3;
+# retransmit 2;
+# wait 5;
+# dead 20;
+# type broadcast;
+# authentication simple;
+# password "pass";
+# };
+# };
+#}
+
+
+#protocol bgp {
+# disabled;
+# import all;
+# export all;
+# export where source = RTS_STATIC;
+
+# local as 65000;
+# neighbor 192.168.1.1 as 65001;
+# multihop 20 via 192.168.2.1;
+
+# hold time 240;
+# startup hold time 240;
+# connect retry time 120;
+# keepalive time 80; # defaults to hold time / 3
+# start delay time 5; # How long do we wait before initial connect
+# error wait time 60, 300;# Minimum and maximum time we wait after an error (when consecutive
+# # errors occur, we increase the delay exponentially ...
+# error forget time 300; # ... until this timeout expires)
+# disable after error; # Disable the protocol automatically when an error occurs
+# next hop self; # Disable next hop processing and always advertise our local address as nexthop
+# source address 62.168.0.14; # What local address we use for the TCP connection
+# password "secret" # Password used for MD5 authentication
+# rr client; # I am a route reflector and the neighor is my client
+# rr cluster id 1.0.0.1 # Use this value for cluster id instead of my router id
+# };
+#}
--- /dev/null
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2010-2011 OpenWrt.org
+
+START=50
+
+SERVICE_DAEMONIZE=1
+SERVICE_WRITE_PID=1
+
+start() {
+ service_start /usr/sbin/bird6 -d
+# ( SERVICE_MATCH_NAME=1 service_start /usr/sbin/bird6loop )
+}
+
+stop() {
+# ( SERVICE_MATCH_NAME=1 service_stop /usr/sbin/bird6loop )
+ service_stop /usr/sbin/bird6
+}
+
+reload() {
+ service_reload /usr/sbin/bird6
+}
--- /dev/null
+#!/bin/sh
+
+BIRD=/usr/sbin/bird6
+
+$BIRD -p || return 1
+
+. /lib/functions.sh
+. /lib/functions/service.sh
+
+SERVICE_DAEMONIZE=1
+SERVICE_WRITE_PID=1
+
+sig_handler() {
+ running=0
+ service_stop $BIRD
+}
+
+running=1
+trap sig_handler INT
+trap sig_handler TERM
+while [ $running -gt 0 ]; do
+ service_check $BIRD || service_start $BIRD -d "$@"
+ sleep 3
+done
include $(INCLUDE_DIR)/package.mk
ifeq ($(DUMP),)
- STAMP_CONFIGURED:=$(strip $(STAMP_CONFIGURED))_$(shell grep '^CONFIG_BUSYBOX_' $(TOPDIR)/.config | md5s)
+ STAMP_CONFIGURED:=$(strip $(STAMP_CONFIGURED))_$(shell $(SH_FUNC) grep '^CONFIG_BUSYBOX_' $(TOPDIR)/.config | md5s)
endif
init-y :=
config BUSYBOX_CONFIG_LFS
bool
- default y
+ default n
select BUSYBOX_CONFIG_FDISK_SUPPORT_LARGE_DISKS
help
If you want to build BusyBox with large file support, then enable
include $(TOPDIR)/rules.mk
PKG_NAME:=dnsmasq
-PKG_VERSION:=2.55
-PKG_RELEASE:=6.1
+PKG_VERSION:=2.76
+PKG_RELEASE:=3
-PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq
-PKG_MD5SUM:=b093d7c6bc7f97ae6fd35d048529232a
+PKG_MD5SUM:=00f5ee66b4e4b7f14538bf62ae3c9461
include $(INCLUDE_DIR)/package.mk
+TARGET_CFLAGS += -ffunction-sections -fdata-sections
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+COPTS = -DNO_IPV6 -DNO_DHCP6 -DNO_AUTH -DNO_IPSET -DNO_LARGEFILE -DNO_INOTIFY
+
+MAKE_FLAGS := \
+ $(TARGET_CONFIGURE_OPTS) \
+ CFLAGS="$(TARGET_CFLAGS)" \
+ LDFLAGS="$(TARGET_LDFLAGS)" \
+ COPTS="$(COPTS)" \
+ PREFIX="/usr"
+
define Package/dnsmasq
SECTION:=net
CATEGORY:=Base system
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
+ $(MAKE_FLAGS) \
$(TARGET_CONFIGURE_OPTS) \
CFLAGS="$(TARGET_CFLAGS)" \
BINDIR="/usr/sbin" MANDIR="/usr/man" \
--- /dev/null
+--- a/src/dhcp.c
++++ b/src/dhcp.c
+@@ -147,7 +147,7 @@ void dhcp_packet(time_t now, int pxe_fd)
+ ssize_t sz;
+ int iface_index = 0, unicast_dest = 0, is_inform = 0;
+ int rcvd_iface_index;
+- struct in_addr iface_addr;
++ struct in_addr iface_addr, *addrp = NULL;
+ struct iface_param parm;
+ #ifdef HAVE_LINUX_NETWORK
+ struct arpreq arp_req;
+@@ -277,11 +277,9 @@ void dhcp_packet(time_t now, int pxe_fd)
+ {
+ ifr.ifr_addr.sa_family = AF_INET;
+ if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
+- iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
+- else
+ {
+- my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
+- return;
++ addrp = &iface_addr;
++ iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
+ }
+
+ for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
+@@ -300,7 +298,7 @@ void dhcp_packet(time_t now, int pxe_fd)
+ parm.relay_local.s_addr = 0;
+ parm.ind = iface_index;
+
+- if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
++ if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, NULL))
+ {
+ /* If we failed to match the primary address of the interface, see if we've got a --listen-address
+ for a secondary */
+@@ -320,6 +318,12 @@ void dhcp_packet(time_t now, int pxe_fd)
+ complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
+ }
+
++ if (!addrp)
++ {
++ my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
++ return;
++ }
++
+ if (!iface_enumerate(AF_INET, &parm, complete_context))
+ return;
+
+++ /dev/null
---- a/src/config.h
-+++ b/src/config.h
-@@ -269,8 +269,9 @@ NOTES:
- /* We assume that systems which don't have IPv6
- headers don't have ntop and pton either */
-
--#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY) && !defined(NO_IPV6)
-+#if defined(INET6_ADDRSTRLEN) && !defined(NO_IPV6)
- # define HAVE_IPV6
-+# define IPV6_V6ONLY 26
- # define ADDRSTRLEN INET6_ADDRSTRLEN
- # if defined(SOL_IPV6)
- # define IPV6_LEVEL SOL_IPV6
--- /dev/null
+--- a/src/ipset.c
++++ b/src/ipset.c
+@@ -22,7 +22,6 @@
+ #include <errno.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+-#include <sys/utsname.h>
+ #include <arpa/inet.h>
+ #include <linux/version.h>
+ #include <linux/netlink.h>
+@@ -72,7 +71,7 @@ struct my_nfgenmsg {
+
+ #define NL_ALIGN(len) (((len)+3) & ~(3))
+ static const struct sockaddr_nl snl = { .nl_family = AF_NETLINK };
+-static int ipset_sock, old_kernel;
++static int ipset_sock;
+ static char *buffer;
+
+ static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
+@@ -87,25 +86,7 @@ static inline void add_attr(struct nlmsg
+
+ void ipset_init(void)
+ {
+- struct utsname utsname;
+- int version;
+- char *split;
+-
+- if (uname(&utsname) < 0)
+- die(_("failed to find kernel version: %s"), NULL, EC_MISC);
+-
+- split = strtok(utsname.release, ".");
+- version = (split ? atoi(split) : 0);
+- split = strtok(NULL, ".");
+- version = version * 256 + (split ? atoi(split) : 0);
+- split = strtok(NULL, ".");
+- version = version * 256 + (split ? atoi(split) : 0);
+- old_kernel = (version < KERNEL_VERSION(2,6,32));
+-
+- if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1)
+- return;
+-
+- if (!old_kernel &&
++ if (
+ (buffer = safe_malloc(BUFF_SZ)) &&
+ (ipset_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER)) != -1 &&
+ (bind(ipset_sock, (struct sockaddr *)&snl, sizeof(snl)) != -1))
+@@ -168,62 +149,16 @@ static int new_add_to_ipset(const char *
+ }
+
+
+-static int old_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int remove)
+-{
+- socklen_t size;
+- struct ip_set_req_adt_get {
+- unsigned op;
+- unsigned version;
+- union {
+- char name[IPSET_MAXNAMELEN];
+- uint16_t index;
+- } set;
+- char typename[IPSET_MAXNAMELEN];
+- } req_adt_get;
+- struct ip_set_req_adt {
+- unsigned op;
+- uint16_t index;
+- uint32_t ip;
+- } req_adt;
+-
+- if (strlen(setname) >= sizeof(req_adt_get.set.name))
+- {
+- errno = ENAMETOOLONG;
+- return -1;
+- }
+-
+- req_adt_get.op = 0x10;
+- req_adt_get.version = 3;
+- strcpy(req_adt_get.set.name, setname);
+- size = sizeof(req_adt_get);
+- if (getsockopt(ipset_sock, SOL_IP, 83, &req_adt_get, &size) < 0)
+- return -1;
+- req_adt.op = remove ? 0x102 : 0x101;
+- req_adt.index = req_adt_get.set.index;
+- req_adt.ip = ntohl(ipaddr->addr.addr4.s_addr);
+- if (setsockopt(ipset_sock, SOL_IP, 83, &req_adt, sizeof(req_adt)) < 0)
+- return -1;
+-
+- return 0;
+-}
+-
+-
+-
+ int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove)
+ {
+ int af = AF_INET;
+
+ #ifdef HAVE_IPV6
+ if (flags & F_IPV6)
+- {
+ af = AF_INET6;
+- /* old method only supports IPv4 */
+- if (old_kernel)
+- return -1;
+- }
+ #endif
+
+- return old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove);
++ return new_add_to_ipset(setname, ipaddr, af, remove);
+ }
+
+ #endif
--- /dev/null
+From 79e60e145f8a595bca5a784c00b437216d51de68 Mon Sep 17 00:00:00 2001
+From: Steven Barth <steven@midlink.org>
+Date: Mon, 13 Apr 2015 09:45:20 +0200
+Subject: [PATCH] dnssec: improve timestamp heuristic
+
+Signed-off-by: Steven Barth <steven@midlink.org>
+---
+ src/dnssec.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -462,17 +462,24 @@ static time_t timestamp_time;
+ int setup_timestamp(void)
+ {
+ struct stat statbuf;
++ time_t now;
++ time_t base = 1420070400; /* 1-1-2015 */
+
+ daemon->back_to_the_future = 0;
+
+ if (!daemon->timestamp_file)
+ return 0;
++
++ now = time(NULL);
++
++ if (!stat("/proc/self/exe", &statbuf) && difftime(statbuf.st_mtime, base) > 0)
++ base = statbuf.st_mtime;
+
+ if (stat(daemon->timestamp_file, &statbuf) != -1)
+ {
+ timestamp_time = statbuf.st_mtime;
+ check_and_exit:
+- if (difftime(timestamp_time, time(0)) <= 0)
++ if (difftime(now, base) >= 0 && difftime(timestamp_time, now) <= 0)
+ {
+ /* time already OK, update timestamp, and do key checking from the start. */
+ if (utime(daemon->timestamp_file, NULL) == -1)
+@@ -493,7 +500,7 @@ int setup_timestamp(void)
+
+ close(fd);
+
+- timestamp_time = timbuf.actime = timbuf.modtime = 1420070400; /* 1-1-2015 */
++ timestamp_time = timbuf.actime = timbuf.modtime = base;
+ if (utime(daemon->timestamp_file, &timbuf) == 0)
+ goto check_and_exit;
+ }
--- /dev/null
+dnsmasq: fix warning with poll.h include on musl
+
+Warning is:
+ #warning redirecting incorrect #include <sys/poll.h> to <poll.h>
+
+Signed-off-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
+
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -82,7 +82,7 @@ typedef unsigned long long u64;
+ #if defined(HAVE_SOLARIS_NETWORK)
+ # include <sys/sockio.h>
+ #endif
+-#include <sys/poll.h>
++#include <poll.h>
+ #include <sys/wait.h>
+ #include <sys/time.h>
+ #include <sys/un.h>
#
-# Copyright (C) 2006-2009 OpenWrt.org
+# Copyright (C) 2006-2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=mtd
-PKG_RELEASE:=13
+PKG_RELEASE:=18.1
PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)
STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
endef
define Package/mtd/description
- This package contains an utility useful to upgrade from other firmware or
+ This package contains an utility useful to upgrade from other firmware or
older OpenWrt releases.
endef
target=$(firstword $(subst -, ,$(BOARD)))
MAKE_FLAGS += TARGET="$(target)"
-TARGET_CFLAGS += -Dtarget_$(target)=1 -Wall
+TARGET_CFLAGS := -I$(LINUX_DIR)/include $(TARGET_CFLAGS) -Dtarget_$(target)=1 -Wall
ifdef CONFIG_MTD_REDBOOT_PARTS
MAKE_FLAGS += FIS_SUPPORT=1
CFLAGS += -Wall
obj = mtd.o jffs2.o crc32.o
+obj.seama = seama.o md5.o
+obj.ar71xx = trx.o
obj.brcm = trx.o
obj.brcm47xx = $(obj.brcm)
+obj.brcm63xx = imagetag.o
+obj.ramips = $(obj.seama)
ifdef FIS_SUPPORT
obj += fis.o
mtd: $(obj) $(obj.$(TARGET))
clean:
- rm -f *.o jffs2
+ rm -f *.o jffs2
--- /dev/null
+../../../target/linux/brcm63xx/files/arch/mips/include/asm/mach-bcm63xx/bcm_tag.h
\ No newline at end of file
struct fis_image_desc *redboot = NULL;
struct fis_image_desc *first = NULL;
struct fis_image_desc *last = NULL;
+ struct fis_image_desc *first_fb = NULL;
+ struct fis_image_desc *last_fb = NULL;
struct fis_image_desc *desc;
struct fis_part *part;
uint32_t offset = 0, size = 0;
}
desc--;
+ first_fb = first;
+ last_fb = last;
+
+ if (first_fb->hdr.flash_base > last_fb->hdr.flash_base) {
+ first_fb = last;
+ last_fb = first;
+ }
+
/* determine size of available space */
desc = (struct fis_image_desc *) start;
while ((char *) desc < end) {
if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
break;
- if (desc->hdr.flash_base > last->hdr.flash_base &&
+ if (desc->hdr.flash_base > last_fb->hdr.flash_base &&
desc->hdr.flash_base < offset)
offset = desc->hdr.flash_base;
}
desc--;
- size = offset - first->hdr.flash_base;
+ size = offset - first_fb->hdr.flash_base;
#ifdef notyet
desc = first - 1;
last++;
desc = first + n_new;
- offset = first->hdr.flash_base;
+ offset = first_fb->hdr.flash_base;
if (desc != last) {
if (desc > last)
--- /dev/null
+/*
+ * imagetag.c
+ *
+ * Copyright (C) 2005 Mike Baker
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ * Copyrigth (C) 2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+#include "mtd.h"
+#include "crc32.h"
+#include "bcm_tag.h"
+
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+
+#define CRC_START 0xFFFFFFFF
+
+static uint32_t strntoul(char *str, char **endptr, int base, size_t len) {
+ char *newstr;
+ uint32_t res = 0;
+
+ newstr = calloc(len + 1, sizeof(char));
+ if (newstr) {
+ strncpy(newstr, str, len);
+ res = strtoul(newstr, endptr, base);
+ free(newstr);
+ }
+ return res;
+}
+
+uint32_t compute_crc32(uint32_t crc, off_t start, size_t compute_len, int fd)
+{
+ uint8_t readbuf[1024];
+ ssize_t res;
+ off_t offset = start;
+
+ /* Read a buffer's worth of bytes */
+ while (fd && (compute_len >= sizeof(readbuf))) {
+ res = pread(fd, readbuf, sizeof(readbuf), offset);
+ crc = crc32(crc, readbuf, res);
+ compute_len = compute_len - res;
+ offset += res;
+ }
+
+ /* Less than buffer-size bytes remains, read compute_len bytes */
+ if (fd && (compute_len > 0)) {
+ res = pread(fd, readbuf, compute_len, offset);
+ crc = crc32(crc, readbuf, res);
+ }
+
+ return crc;
+}
+
+int
+trx_fixup(int fd, const char *name)
+{
+ struct mtd_info_user mtdInfo;
+ unsigned long len;
+ void *ptr, *scan;
+ int bfd;
+ struct bcm_tag *tag;
+ ssize_t res;
+ uint32_t cfelen, imagelen, imagestart, rootfslen;
+ uint32_t imagecrc, rootfscrc, headercrc;
+ uint32_t offset = 0;
+ cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0;
+
+
+ if (ioctl(fd, MEMGETINFO, &mtdInfo) < 0) {
+ fprintf(stderr, "Failed to get mtd info\n");
+ goto err;
+ }
+
+ len = mtdInfo.size;
+ if (mtdInfo.size <= 0) {
+ fprintf(stderr, "Invalid MTD device size\n");
+ goto err;
+ }
+
+ bfd = mtd_open(name, true);
+ ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, bfd, 0);
+ if (!ptr || (ptr == (void *) -1)) {
+ perror("mmap");
+ goto err1;
+ }
+
+ tag = (struct bcm_tag *) (ptr);
+
+ cfelen = strntoul(&tag->cfeLength[0], NULL, 10, IMAGE_LEN);
+ if (cfelen) {
+ fprintf(stderr, "Non-zero CFE length. This is currently unsupported.\n");
+ exit(1);
+ }
+
+ headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, headerCRC), fd);
+ if (headercrc != *(uint32_t *)(&tag->headerCRC[0])) {
+ fprintf(stderr, "Tag verify failed. This may not be a valid image.\n");
+ exit(1);
+ }
+
+ sprintf(&tag->flashRootLength[0], "%lu", 0);
+ strncpy(&tag->totalLength[0], &tag->kernelLength[0], IMAGE_LEN);
+
+ imagestart = sizeof(tag);
+ memcpy(&tag->imageCRC[0], &tag->kernelCRC[0], CRC_LEN);
+ memcpy(&tag->fskernelCRC[0], &tag->kernelCRC[0], CRC_LEN);
+ rootfscrc = CRC_START;
+ memcpy(&tag->rootfsCRC[0], &rootfscrc, sizeof(uint32_t));
+ headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, headerCRC));
+ memcpy(&tag->headerCRC[0], &headercrc, sizeof(uint32_t));
+
+ msync(ptr, sizeof(struct bcm_tag), MS_SYNC|MS_INVALIDATE);
+ munmap(ptr, len);
+ close(bfd);
+ return 0;
+
+err1:
+ close(bfd);
+err:
+ fprintf(stderr, "Error fixing up imagetag header\n");
+ return -1;
+}
+
+
+int
+trx_check(int imagefd, const char *mtd, char *buf, int *len)
+{
+ struct bcm_tag *tag = (const struct bcm_tag *) buf;
+ int fd;
+ uint32_t headerCRC;
+ uint32_t imageLen;
+
+ if (strcmp(mtd, "linux") != 0)
+ return 1;
+
+ *len = read(imagefd, buf, sizeof(struct bcm_tag));
+ if (*len < sizeof(struct bcm_tag)) {
+ fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", *len);
+ return 0;
+ }
+ headerCRC = crc32buf(buf, offsetof(struct bcm_tag, headerCRC));
+ if (*(uint32_t *)(&tag->headerCRC[0]) != headerCRC) {
+
+ if (quiet < 2) {
+ fprintf(stderr, "Bad header CRC got %08lx, calculated %08lx\n",
+ *(uint32_t *)(&tag->headerCRC[0]), headerCRC);
+ fprintf(stderr, "This is not the correct file format; refusing to flash.\n"
+ "Please specify the correct file or use -f to force.\n");
+ }
+ return 0;
+ }
+
+ /* check if image fits to mtd device */
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ exit(1);
+ }
+
+ imageLen = strntoul(&tag->totalLength[0], NULL, 10, IMAGE_LEN);
+
+ if(mtdsize < imageLen) {
+ fprintf(stderr, "Image too big for partition: %s\n", mtd);
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+ return 1;
+}
+
+int
+mtd_fixtrx(const char *mtd, size_t offset)
+{
+ int fd;
+ struct bcm_tag *tag;
+ char *buf;
+ ssize_t res;
+ size_t block_offset;
+ uint32_t cfelen, imagelen, imagestart, rootfslen;
+ uint32_t imagecrc, rootfscrc, headercrc;
+ cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0;
+
+ if (quiet < 2)
+ fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset);
+
+ block_offset = offset & ~(erasesize - 1);
+ offset -= block_offset;
+
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ exit(1);
+ }
+
+ if (block_offset + erasesize > mtdsize) {
+ fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize);
+ exit(1);
+ }
+
+ buf = malloc(erasesize);
+ if (!buf) {
+ perror("malloc");
+ exit(1);
+ }
+
+ res = pread(fd, buf, erasesize, block_offset);
+ if (res != erasesize) {
+ perror("pread");
+ exit(1);
+ }
+
+ tag = (struct bcm_tag *) (buf + offset);
+
+ cfelen = strntoul(&tag->cfeLength[0], NULL, 10, IMAGE_LEN);
+ if (cfelen) {
+ fprintf(stderr, "Non-zero CFE length. This is currently unsupported.\n");
+ exit(1);
+ }
+
+ if (quiet < 2) {
+ fprintf(stderr, "Verifying we actually have an imagetag.\n");
+ }
+
+ headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, headerCRC), fd);
+ if (headercrc != *(uint32_t *)(&tag->headerCRC[0])) {
+ fprintf(stderr, "Tag verify failed. This may not be a valid image.\n");
+ exit(1);
+ }
+
+ if (quiet < 2) {
+ fprintf(stderr, "Checking current fixed status.\n");
+ }
+
+ rootfslen = strntoul(&tag->flashRootLength[0], NULL, 10, IMAGE_LEN);
+ if (rootfslen == 0) {
+ if (quiet < 2)
+ fprintf(stderr, "Header already fixed, exiting\n");
+ close(fd);
+ return 0;
+ }
+
+ if (quiet < 2) {
+ fprintf(stderr, "Setting root length to 0.\n");
+ }
+
+ sprintf(&tag->flashRootLength[0], "%lu", 0);
+ strncpy(&tag->totalLength[0], &tag->kernelLength[0], IMAGE_LEN);
+
+ if (quiet < 2) {
+ fprintf(stderr, "Recalculating CRCs.\n");
+ }
+
+ imagestart = sizeof(tag);
+ memcpy(&tag->imageCRC[0], &tag->kernelCRC[0], CRC_LEN);
+ memcpy(&tag->fskernelCRC[0], &tag->kernelCRC[0], CRC_LEN);
+ rootfscrc = CRC_START;
+ memcpy(&tag->rootfsCRC[0], &rootfscrc, sizeof(uint32_t));
+ headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, headerCRC));
+ memcpy(&tag->headerCRC[0], &headercrc, sizeof(uint32_t));
+
+ if (quiet < 2) {
+ fprintf(stderr, "Erasing imagetag block\n");
+ }
+
+ if (mtd_erase_block(fd, block_offset)) {
+ fprintf(stderr, "Can't erase block at 0x%x (%s)\n", block_offset, strerror(errno));
+ exit(1);
+ }
+
+ if (quiet < 2) {
+ fprintf(stderr, "New image crc32: 0x%x, rewriting block\n",
+ *(uint32_t *)(&tag->imageCRC[0]));
+ fprintf(stderr, "New header crc32: 0x%x, rewriting block\n", headercrc);
+ }
+
+ if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
+ fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
+ exit(1);
+ }
+
+ if (quiet < 2)
+ fprintf(stderr, "Done.\n");
+
+ close (fd);
+ sync();
+ return 0;
+
+}
pad(erasesize);
free(buf);
-#ifdef target_brcm
- trx_fixup(outfd, mtd);
-#endif
- return 0;
+ return (mtdofs - ofs);
}
void mtd_parse_jffs2data(const char *buf, const char *dir)
err = 0;
-#ifdef target_brcm
- trx_fixup(outfd, mtd);
-#endif
+ if (trx_fixup) {
+ trx_fixup(outfd, mtd);
+ }
done:
close(outfd);
--- /dev/null
+
+
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#include <string.h>
+#include "md5.h"
+
+/*
+ ***********************************************************************
+ ** Message-digest routines: **
+ ** To form the message digest for a message M **
+ ** (1) Initialize a context buffer mdContext using MD5_Init **
+ ** (2) Call MD5_Update on mdContext and M **
+ ** (3) Call MD5_Final on mdContext **
+ ** The message digest is now in mdContext->digest[0...15] **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform ();
+
+static unsigned char PADDING[64] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+ {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) \
+ {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) \
+ {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) \
+ {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+#ifdef __STDC__
+#define UL(x) x##U
+#else
+#define UL(x) x
+#endif
+
+/* The routine MD5_Init initializes the message-digest context
+ mdContext. All fields are set to zero.
+ */
+void MD5_Init (mdContext)
+MD5_CTX *mdContext;
+{
+ mdContext->i[0] = mdContext->i[1] = (UINT4)0;
+
+ /* Load magic initialization constants.
+ */
+ mdContext->buf[0] = (UINT4)0x67452301;
+ mdContext->buf[1] = (UINT4)0xefcdab89;
+ mdContext->buf[2] = (UINT4)0x98badcfe;
+ mdContext->buf[3] = (UINT4)0x10325476;
+}
+
+/* The routine MD5Update updates the message-digest context to
+ account for the presence of each of the characters inBuf[0..inLen-1]
+ in the message whose digest is being computed.
+ */
+void MD5_Update (mdContext, inBuf, inLen)
+MD5_CTX *mdContext;
+unsigned char *inBuf;
+unsigned int inLen;
+{
+ UINT4 in[16];
+ int mdi;
+ unsigned int i, ii;
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* update number of bits */
+ if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
+ mdContext->i[1]++;
+ mdContext->i[0] += ((UINT4)inLen << 3);
+ mdContext->i[1] += ((UINT4)inLen >> 29);
+
+ while (inLen--) {
+ /* add new character to buffer, increment mdi */
+ mdContext->in[mdi++] = *inBuf++;
+
+ /* transform if necessary */
+ if (mdi == 0x40) {
+ for (i = 0, ii = 0; i < 16; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+ mdi = 0;
+ }
+ }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+ ends with the desired message digest in mdContext->digest[0...15].
+ */
+void MD5_Final (hash, mdContext)
+unsigned char hash[];
+MD5_CTX *mdContext;
+{
+ UINT4 in[16];
+ int mdi;
+ unsigned int i, ii;
+ unsigned int padLen;
+
+ /* save number of bits */
+ in[14] = mdContext->i[0];
+ in[15] = mdContext->i[1];
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* pad out to 56 mod 64 */
+ padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+ MD5_Update (mdContext, PADDING, padLen);
+
+ /* append length in bits and transform */
+ for (i = 0, ii = 0; i < 14; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+
+ /* store buffer in digest */
+ for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+ mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+ mdContext->digest[ii+1] =
+ (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+ mdContext->digest[ii+2] =
+ (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+ mdContext->digest[ii+3] =
+ (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+ }
+ memcpy(hash, mdContext->digest, 16);
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void Transform (buf, in)
+UINT4 *buf;
+UINT4 *in;
+{
+ UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+ FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
+ FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
+ FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
+ FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
+ FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
+ FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
+ FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
+ FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
+ FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
+ FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
+ FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
+ FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
+ FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
+ FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
+ FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
+ FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
+
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
+ GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
+ GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
+ GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
+ GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
+ GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */
+ GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
+ GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
+ GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
+ GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
+ GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
+ GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
+ GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
+ GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
+ GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
+ GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
+
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
+ HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
+ HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
+ HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
+ HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
+ HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
+ HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
+ HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
+ HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
+ HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
+ HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
+ HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */
+ HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
+ HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
+ HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
+ HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
+
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
+ II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
+ II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
+ II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
+ II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
+ II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
+ II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
+ II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
+ II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
+ II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
+ II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
+ II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
+ II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
+ II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
+ II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
+ II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*
+ ***********************************************************************
+ ** End of md5.c **
+ ******************************** (cut) ********************************
+ */
--- /dev/null
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5 **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
+ ** Revised (for MD5): RLR 4/27/91 **
+ ** -- G modified to have y&~z instead of y&z **
+ ** -- FF, GG, HH modified to add in last register done **
+ ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
+ ** -- distinct additive constant for each step **
+ ** -- round 4 added, working mod 7 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#ifndef __MD5_INCLUDE__
+
+/* typedef a 32-bit type */
+#ifdef _LP64
+typedef unsigned int UINT4;
+typedef int INT4;
+#else
+typedef unsigned long UINT4;
+typedef long INT4;
+#endif
+#define _UINT4_T
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+ UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
+ UINT4 buf[4]; /* scratch buffer */
+ unsigned char in[64]; /* input buffer */
+ unsigned char digest[16]; /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5_Init ();
+void MD5_Update ();
+void MD5_Final ();
+
+#define __MD5_INCLUDE__
+#endif /* __MD5_INCLUDE__ */
+++ /dev/null
-
-
-#ifndef __MTD_MTD_H__
-#define __MTD_MTD_H__
-
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/version.h>
-#include <linux/types.h>
-#include <linux/mtd/compatmac.h>
-#include <linux/notifier.h>
-#include <linux/module.h>
-#include <linux/uio.h>
-
-#endif /* __KERNEL__ */
-
-struct erase_info_user {
- u_int32_t start;
- u_int32_t length;
-};
-
-struct mtd_oob_buf {
- u_int32_t start;
- u_int32_t length;
- unsigned char *ptr;
-};
-
-
-#define MTD_CHAR_MAJOR 90
-#define MTD_BLOCK_MAJOR 31
-#define MAX_MTD_DEVICES 16
-
-
-
-#define MTD_ABSENT 0
-#define MTD_RAM 1
-#define MTD_ROM 2
-#define MTD_NORFLASH 3
-#define MTD_NANDFLASH 4
-#define MTD_PEROM 5
-#define MTD_OTHER 14
-#define MTD_UNKNOWN 15
-
-
-
-#define MTD_CLEAR_BITS 1 // Bits can be cleared (flash)
-#define MTD_SET_BITS 2 // Bits can be set
-#define MTD_ERASEABLE 4 // Has an erase function
-#define MTD_WRITEB_WRITEABLE 8 // Direct IO is possible
-#define MTD_VOLATILE 16 // Set for RAMs
-#define MTD_XIP 32 // eXecute-In-Place possible
-#define MTD_OOB 64 // Out-of-band data (NAND flash)
-#define MTD_ECC 128 // Device capable of automatic ECC
-
-// Some common devices / combinations of capabilities
-#define MTD_CAP_ROM 0
-#define MTD_CAP_RAM (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE)
-#define MTD_CAP_NORFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE)
-#define MTD_CAP_NANDFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE|MTD_OOB)
-#define MTD_WRITEABLE (MTD_CLEAR_BITS|MTD_SET_BITS)
-
-
-// Types of automatic ECC/Checksum available
-#define MTD_ECC_NONE 0 // No automatic ECC available
-#define MTD_ECC_RS_DiskOnChip 1 // Automatic ECC on DiskOnChip
-#define MTD_ECC_SW 2 // SW ECC for Toshiba & Samsung devices
-
-struct mtd_info_user {
- u_char type;
- u_int32_t flags;
- u_int32_t size; // Total size of the MTD
- u_int32_t erasesize;
- u_int32_t oobblock; // Size of OOB blocks (e.g. 512)
- u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
- u_int32_t ecctype;
- u_int32_t eccsize;
-};
-
-struct region_info_user {
- u_int32_t offset; /* At which this region starts,
- * from the beginning of the MTD */
- u_int32_t erasesize; /* For this region */
- u_int32_t numblocks; /* Number of blocks in this region */
- u_int32_t regionindex;
-};
-
-#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
-#define MEMERASE _IOW('M', 2, struct erase_info_user)
-#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
-#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf)
-#define MEMLOCK _IOW('M', 5, struct erase_info_user)
-#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
-#define MEMGETREGIONCOUNT _IOR('M', 7, int)
-#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
-#define MEMREADDATA _IOWR('M', 9, struct mtd_oob_buf)
-#define MEMWRITEDATA _IOWR('M', 10, struct mtd_oob_buf)
-#define MTDREFRESH _IO('M', 23)
-
-#ifndef __KERNEL__
-
-typedef struct mtd_info_user mtd_info_t;
-typedef struct erase_info_user erase_info_t;
-typedef struct region_info_user region_info_t;
-
- /* User-space ioctl definitions */
-
-
-#else /* __KERNEL__ */
-
-
-#define MTD_ERASE_PENDING 0x01
-#define MTD_ERASING 0x02
-#define MTD_ERASE_SUSPEND 0x04
-#define MTD_ERASE_DONE 0x08
-#define MTD_ERASE_FAILED 0x10
-
-struct erase_info {
- struct mtd_info *mtd;
- u_int32_t addr;
- u_int32_t len;
- u_long time;
- u_long retries;
- u_int dev;
- u_int cell;
- void (*callback) (struct erase_info *self);
- u_long priv;
- u_char state;
- struct erase_info *next;
-};
-
-struct mtd_erase_region_info {
- u_int32_t offset; /* At which this region starts, from the beginning of the MTD */
- u_int32_t erasesize; /* For this region */
- u_int32_t numblocks; /* Number of blocks of erasesize in this region */
-};
-
-struct mtd_info {
- u_char type;
- u_int32_t flags;
- u_int32_t size; // Total size of the MTD
-
- /* "Major" erase size for the device. Naïve users may take this
- * to be the only erase size available, or may use the more detailed
- * information below if they desire
- */
- u_int32_t erasesize;
-
- u_int32_t oobblock; // Size of OOB blocks (e.g. 512)
- u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
- u_int32_t ecctype;
- u_int32_t eccsize;
-
- // Kernel-only stuff starts here.
- char *name;
- int index;
-
- /* Data for variable erase regions. If numeraseregions is zero,
- * it means that the whole device has erasesize as given above.
- */
- int numeraseregions;
- struct mtd_erase_region_info *eraseregions;
-
- /* This really shouldn't be here. It can go away in 2.5 */
- u_int32_t bank_size;
-
- struct module *module;
- int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
-
- /* This stuff for eXecute-In-Place */
- int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
-
- /* We probably shouldn't allow XIP if the unpoint isn't a NULL */
- void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len);
-
-
- int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
- int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
-
- int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
- int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
-
- int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
- int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
-
- /*
- * Methods to access the protection register area, present in some
- * flash devices. The user data is one time programmable but the
- * factory data is read only.
- */
- int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-
- int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-
- /* This function is not yet implemented */
- int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-
- /* iovec-based read/write methods. We need these especially for NAND flash,
- with its limited number of write cycles per erase.
- NB: The 'count' parameter is the number of _vectors_, each of
- which contains an (ofs, len) tuple.
- */
- int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen);
- int (*readv_ecc) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from,
- size_t *retlen, u_char *eccbuf, int oobsel);
- int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
- int (*writev_ecc) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to,
- size_t *retlen, u_char *eccbuf, int oobsel);
-
- /* Sync */
- void (*sync) (struct mtd_info *mtd);
-
- /* Chip-supported device locking */
- int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);
- int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len);
-
- /* Power Management functions */
- int (*suspend) (struct mtd_info *mtd);
- void (*resume) (struct mtd_info *mtd);
-
- struct notifier_block reboot_notifier;
-
- void *priv;
-};
-
-
- /* Kernel-side ioctl definitions */
-
-extern int add_mtd_device(struct mtd_info *mtd);
-extern int del_mtd_device (struct mtd_info *mtd);
-
-extern struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num);
-
-static inline struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
-{
- struct mtd_info *ret;
-
- ret = __get_mtd_device(mtd, num);
-
- if (ret && ret->module && !try_inc_mod_count(ret->module))
- return NULL;
-
- return ret;
-}
-
-static inline void put_mtd_device(struct mtd_info *mtd)
-{
- if (mtd->module)
- __MOD_DEC_USE_COUNT(mtd->module);
-}
-
-
-struct mtd_notifier {
- void (*add)(struct mtd_info *mtd);
- void (*remove)(struct mtd_info *mtd);
- struct mtd_notifier *next;
-};
-
-
-extern void register_mtd_user (struct mtd_notifier *new);
-extern int unregister_mtd_user (struct mtd_notifier *old);
-
-int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs,
- unsigned long count, loff_t to, size_t *retlen);
-
-int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs,
- unsigned long count, loff_t from, size_t *retlen);
-
-#ifndef MTDC
-#define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args)
-#define MTD_POINT(mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d))
-#define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg)
-#define MTD_READ(mtd, args...) (*(mtd->read))(mtd, args)
-#define MTD_WRITE(mtd, args...) (*(mtd->write))(mtd, args)
-#define MTD_READV(mtd, args...) (*(mtd->readv))(mtd, args)
-#define MTD_WRITEV(mtd, args...) (*(mtd->writev))(mtd, args)
-#define MTD_READECC(mtd, args...) (*(mtd->read_ecc))(mtd, args)
-#define MTD_WRITEECC(mtd, args...) (*(mtd->write_ecc))(mtd, args)
-#define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args)
-#define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args)
-#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0)
-#endif /* MTDC */
-
-/*
- * Debugging macro and defines
- */
-#define MTD_DEBUG_LEVEL0 (0) /* Quiet */
-#define MTD_DEBUG_LEVEL1 (1) /* Audible */
-#define MTD_DEBUG_LEVEL2 (2) /* Loud */
-#define MTD_DEBUG_LEVEL3 (3) /* Noisy */
-
-#ifdef CONFIG_MTD_DEBUG
-#define DEBUG(n, args...) \
- do { \
- if (n <= CONFIG_MTD_DEBUG_VERBOSE) \
- printk(KERN_INFO args); \
- } while(0)
-#else /* CONFIG_MTD_DEBUG */
-#define DEBUG(n, args...)
-#endif /* CONFIG_MTD_DEBUG */
-
-#endif /* __KERNEL__ */
-
-#endif /* __MTD_MTD_H__ */
#include <sys/stat.h>
#include <sys/reboot.h>
#include <linux/reboot.h>
-#include "mtd-api.h"
+#include <mtd/mtd-user.h>
#include "fis.h"
#include "mtd.h"
-#include "crc32.h"
-#define MAX_ARGS 8
-#define JFFS2_DEFAULT_DIR "" /* directory name without /, empty means root dir */
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define STORE32_LE(X) ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
-#define STORE32_LE(X) (X)
-#else
-#error unkown endianness!
+#ifndef MTDREFRESH
+#define MTDREFRESH _IO('M', 50)
#endif
-ssize_t pread(int fd, void *buf, size_t count, off_t offset);
-ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
-
-#define TRX_MAGIC 0x30524448 /* "HDR0" */
-struct trx_header {
- uint32_t magic; /* "HDR0" */
- uint32_t len; /* Length of file including header */
- uint32_t crc32; /* 32-bit CRC from flag_version to end of file */
- uint32_t flag_version; /* 0:15 flags, 16:31 version */
- uint32_t offsets[3]; /* Offsets of partitions from start of header */
-};
+#define MAX_ARGS 8
+#define JFFS2_DEFAULT_DIR "" /* directory name without /, empty means root dir */
static char *buf = NULL;
static char *imagefile = NULL;
static char *jffs2file = NULL, *jffs2dir = JFFS2_DEFAULT_DIR;
static int buflen = 0;
int quiet;
+int no_erase;
int mtdsize = 0;
int erasesize = 0;
image_check(int imagefd, const char *mtd)
{
int ret = 1;
-#ifdef target_brcm
- ret = trx_check(imagefd, mtd, buf, &buflen);
-#endif
+ if (trx_check) {
+ ret = trx_check(imagefd, mtd, buf, &buflen);
+ }
+
return ret;
}
}
-static int
-mtd_fixtrx(const char *mtd, size_t offset)
-{
- int fd;
- struct trx_header *trx;
- char *buf;
- ssize_t res;
- size_t block_offset;
-
- if (quiet < 2)
- fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset);
-
- block_offset = offset & ~(erasesize - 1);
- offset -= block_offset;
-
- fd = mtd_check_open(mtd);
- if(fd < 0) {
- fprintf(stderr, "Could not open mtd device: %s\n", mtd);
- exit(1);
- }
-
- if (block_offset + erasesize > mtdsize) {
- fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize);
- exit(1);
- }
-
- buf = malloc(erasesize);
- if (!buf) {
- perror("malloc");
- exit(1);
- }
-
- res = pread(fd, buf, erasesize, block_offset);
- if (res != erasesize) {
- perror("pread");
- exit(1);
- }
-
- trx = (struct trx_header *) (buf + offset);
- if (trx->magic != STORE32_LE(0x30524448)) {
- fprintf(stderr, "No trx magic found\n");
- exit(1);
- }
-
- if (trx->len == STORE32_LE(erasesize - offset)) {
- if (quiet < 2)
- fprintf(stderr, "Header already fixed, exiting\n");
- close(fd);
- return 0;
- }
-
- trx->len = STORE32_LE(erasesize - offset);
-
- trx->crc32 = STORE32_LE(crc32buf((char*) &trx->flag_version, erasesize - offset - 3*4));
- if (mtd_erase_block(fd, block_offset)) {
- fprintf(stderr, "Can't erease block at 0x%x (%s)\n", block_offset, strerror(errno));
- exit(1);
- }
-
- if (quiet < 2)
- fprintf(stderr, "New crc32: 0x%x, rewriting block\n", trx->crc32);
-
- if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
- fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
- exit(1);
- }
-
- if (quiet < 2)
- fprintf(stderr, "Done.\n");
-
- close (fd);
- sync();
- return 0;
-
-}
-
static int
mtd_refresh(const char *mtd)
{
return 0;
}
+static void
+indicate_writing(const char *mtd)
+{
+ if (quiet < 2)
+ fprintf(stderr, "\nWriting from %s to %s ... ", imagefile, mtd);
+
+ if (!quiet)
+ fprintf(stderr, " [ ]");
+}
+
static int
-mtd_write(int imagefd, const char *mtd, char *fis_layout)
+mtd_write(int imagefd, const char *mtd, char *fis_layout, size_t part_offset)
{
char *next = NULL;
char *str = NULL;
int fd, result;
ssize_t r, w, e;
+ ssize_t skip = 0;
uint32_t offset = 0;
+ int jffs2_replaced = 0;
#ifdef FIS_SUPPORT
static struct fis_part new_parts[MAX_ARGS];
exit(1);
}
- if (quiet < 2)
- fprintf(stderr, "Writing from %s to %s ... ", imagefile, mtd);
+ if (part_offset > 0) {
+ fprintf(stderr, "Seeking on mtd device '%s' to: %u\n", mtd, part_offset);
+ lseek(fd, part_offset, SEEK_SET);
+ }
- w = e = 0;
- if (!quiet)
- fprintf(stderr, " [ ]");
+ indicate_writing(mtd);
+ w = e = 0;
for (;;) {
/* buffer may contain data already (from trx check or last mtd partition write attempt) */
while (buflen < erasesize) {
if (buflen == 0)
break;
+ if (skip > 0) {
+ skip -= buflen;
+ buflen = 0;
+ if (skip <= 0)
+ indicate_writing(mtd);
+
+ continue;
+ }
+
if (jffs2file) {
if (memcmp(buf, JFFS2_EOF, sizeof(JFFS2_EOF) - 1) == 0) {
if (!quiet)
if (quiet < 2)
fprintf(stderr, "\nAppending jffs2 data from %s to %s...", jffs2file, mtd);
/* got an EOF marker - this is the place to add some jffs2 data */
- mtd_replace_jffs2(mtd, fd, e, jffs2file);
- goto done;
+ skip = mtd_replace_jffs2(mtd, fd, e, jffs2file);
+ jffs2_replaced = 1;
+
+ /* don't add it again */
+ jffs2file = NULL;
+
+ w += skip;
+ e += skip;
+ skip -= buflen;
+ buflen = 0;
+ offset = 0;
+ continue;
}
/* no EOF marker, make sure we figure out the last inode number
* before appending some data */
}
/* need to erase the next block before writing data to it */
- while (w + buflen > e) {
- if (!quiet)
- fprintf(stderr, "\b\b\b[e]");
-
-
- if (mtd_erase_block(fd, e) < 0) {
- if (next) {
- if (w < e) {
- write(fd, buf + offset, e - w);
- offset = e - w;
+ if(!no_erase)
+ {
+ while (w + buflen > e) {
+ if (!quiet)
+ fprintf(stderr, "\b\b\b[e]");
+
+
+ if (mtd_erase_block(fd, e) < 0) {
+ if (next) {
+ if (w < e) {
+ write(fd, buf + offset, e - w);
+ offset = e - w;
+ }
+ w = 0;
+ e = 0;
+ close(fd);
+ mtd = next;
+ fprintf(stderr, "\b\b\b \n");
+ goto resume;
+ } else {
+ fprintf(stderr, "Failed to erase block\n");
+ exit(1);
}
- w = 0;
- e = 0;
- close(fd);
- mtd = next;
- fprintf(stderr, "\b\b\b \n");
- goto resume;
- } else {
- fprintf(stderr, "Failed to erase block\n");
- exit(1);
}
- }
- /* erase the chunk */
- e += erasesize;
+ /* erase the chunk */
+ e += erasesize;
+ }
}
if (!quiet)
offset = 0;
}
+ if (jffs2_replaced && trx_fixup) {
+ trx_fixup(fd, mtd);
+ }
+
if (!quiet)
fprintf(stderr, "\b\b\b\b ");
" refresh refresh mtd partition\n"
" erase erase all data on device\n"
" write <imagefile>|- write <imagefile> (use - for stdin) to device\n"
- " jffs2write <file> append <file> to the jffs2 partition on the device\n"
- " fixtrx fix the checksum in a trx header on first boot\n"
+ " jffs2write <file> append <file> to the jffs2 partition on the device\n");
+ if (mtd_fixtrx) {
+ fprintf(stderr,
+ " fixtrx fix the checksum in a trx header on first boot\n");
+ }
+ if (mtd_fixseama) {
+ fprintf(stderr,
+ " fixseama fix the checksum in a seama header on first boot\n");
+ }
+ fprintf(stderr,
"Following options are available:\n"
" -q quiet mode (once: no [w] on writing,\n"
" twice: no status messages)\n"
+ " -n write without first erasing the blocks\n"
" -r reboot after successful command\n"
" -f force write without trx checks\n"
" -e <device> erase <device> before executing the command\n"
" -d <name> directory for jffs2write, defaults to \"tmp\"\n"
" -j <name> integrate <file> into jffs2 data when writing an image\n"
- " -o offset offset of the trx header in the partition (for fixtrx)\n"
+ " -p write beginning at partition offset\n");
+ if (mtd_fixtrx) {
+ fprintf(stderr,
+ " -o offset offset of the image header in the partition(for fixtrx)\n");
+ }
+ fprintf(stderr,
#ifdef FIS_SUPPORT
" -F <part>[:<size>[:<entrypoint>]][,<part>...]\n"
" alter the fis partition table to create new partitions replacing\n"
int ch, i, boot, imagefd = 0, force, unlocked;
char *erase[MAX_ARGS], *device = NULL;
char *fis_layout = NULL;
- size_t offset = 0;
+ size_t offset = 0, part_offset = 0;
enum {
CMD_ERASE,
CMD_WRITE,
CMD_REFRESH,
CMD_JFFS2WRITE,
CMD_FIXTRX,
+ CMD_FIXSEAMA,
} cmd = -1;
erase[0] = NULL;
force = 0;
buflen = 0;
quiet = 0;
+ no_erase = 0;
while ((ch = getopt(argc, argv,
#ifdef FIS_SUPPORT
"F:"
#endif
- "frqe:d:j:o:")) != -1)
+ "frnqe:d:j:p:o:")) != -1)
switch (ch) {
case 'f':
force = 1;
case 'r':
boot = 1;
break;
+ case 'n':
+ no_erase = 1;
+ break;
case 'j':
jffs2file = optarg;
break;
case 'd':
jffs2dir = optarg;
break;
+ case 'p':
+ errno = 0;
+ part_offset = strtoul(optarg, 0, 0);
+ if (errno) {
+ fprintf(stderr, "-p: illegal numeric string\n");
+ usage();
+ }
+ break;
case 'o':
+ if (!mtd_fixtrx) {
+ fprintf(stderr, "-o: is not available on this platform\n");
+ usage();
+ }
errno = 0;
offset = strtoul(optarg, 0, 0);
if (errno) {
} else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) {
cmd = CMD_ERASE;
device = argv[1];
- } else if ((strcmp(argv[0], "fixtrx") == 0) && (argc == 2)) {
+ } else if (((strcmp(argv[0], "fixtrx") == 0) && (argc == 2)) && mtd_fixtrx) {
cmd = CMD_FIXTRX;
device = argv[1];
+ } else if (((strcmp(argv[0], "fixseama") == 0) && (argc == 2)) && mtd_fixseama) {
+ cmd = CMD_FIXSEAMA;
+ device = argv[1];
} else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) {
cmd = CMD_WRITE;
device = argv[2];
case CMD_WRITE:
if (!unlocked)
mtd_unlock(device);
- mtd_write(imagefd, device, fis_layout);
+ mtd_write(imagefd, device, fis_layout, part_offset);
break;
case CMD_JFFS2WRITE:
if (!unlocked)
mtd_refresh(device);
break;
case CMD_FIXTRX:
- mtd_fixtrx(device, offset);
+ if (mtd_fixtrx) {
+ mtd_fixtrx(device, offset);
+ }
+ case CMD_FIXSEAMA:
+ if (mtd_fixseama)
+ mtd_fixseama(device, 0);
break;
}
extern int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename);
extern void mtd_parse_jffs2data(const char *buf, const char *dir);
-/* target specific */
-extern int trx_fixup(int fd, const char *name);
-extern int trx_check(int imagefd, const char *mtd, char *buf, int *len);
-
+/* target specific functions */
+extern int trx_fixup(int fd, const char *name) __attribute__ ((weak));
+extern int trx_check(int imagefd, const char *mtd, char *buf, int *len) __attribute__ ((weak));
+extern int mtd_fixtrx(const char *mtd, size_t offset) __attribute__ ((weak));
+extern int mtd_fixseama(const char *mtd, size_t offset) __attribute__ ((weak));
#endif /* __mtd_h */
--- /dev/null
+/*
+ * seama.c
+ *
+ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Based on the trx fixup code:
+ * Copyright (C) 2005 Mike Baker
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+#include "mtd.h"
+#include "seama.h"
+#include "md5.h"
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X) ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X) (X)
+#else
+#error unknown endianness!
+#endif
+
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+
+int
+seama_fix_md5(char *buf, size_t len)
+{
+ struct seama_hdr *shdr;
+ char *data;
+ size_t msize;
+ size_t isize;
+ MD5_CTX ctx;
+ unsigned char digest[16];
+ int i;
+
+ if (len < sizeof(struct seama_hdr))
+ return -1;
+
+ shdr = (struct seama_hdr *) buf;
+ if (shdr->magic != htonl(SEAMA_MAGIC)) {
+ fprintf(stderr, "no SEAMA header found\n");
+ return -1;
+ }
+
+ isize = ntohl(shdr->size);
+ msize = ntohs(shdr->metasize);
+ if (isize == 0) {
+ /* the image contains no checksum */
+ return -1;
+ }
+
+ len -= sizeof(struct seama_hdr) + sizeof(digest) + msize;
+ if (isize > len)
+ isize = len;
+
+ data = buf + sizeof(struct seama_hdr) + sizeof(digest) + msize;
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, data, isize);
+ MD5_Final(digest, &ctx);
+
+ if (!memcmp(digest, &buf[sizeof(struct seama_hdr)], sizeof(digest))) {
+ if (quiet < 2)
+ fprintf(stderr, "the header is fixed already\n");
+ return -1;
+ }
+
+ if (quiet < 2) {
+ fprintf(stderr, "new size:%u, new MD5: ", isize);
+ for (i = 0; i < sizeof(digest); i++)
+ fprintf(stderr, "%02x", digest[i]);
+
+ fprintf(stderr, "\n");
+ }
+
+ /* update the size in the image */
+ shdr->size = htonl(isize);
+
+ /* update the checksum in the image */
+ for (i = 0; i < sizeof(digest); i++)
+ buf[sizeof(struct seama_hdr) + i] = digest[i];
+
+ return 0;
+}
+
+int
+mtd_fixseama(const char *mtd, size_t offset)
+{
+ int fd;
+ char *buf;
+ ssize_t res;
+ size_t block_offset;
+
+ if (quiet < 2)
+ fprintf(stderr, "Trying to fix SEAMA header in %s at 0x%x...\n",
+ mtd, offset);
+
+ block_offset = offset & ~(erasesize - 1);
+ offset -= block_offset;
+
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ exit(1);
+ }
+
+ if (block_offset + erasesize > mtdsize) {
+ fprintf(stderr, "Offset too large, device size 0x%x\n",
+ mtdsize);
+ exit(1);
+ }
+
+ buf = malloc(mtdsize);
+ if (!buf) {
+ perror("malloc");
+ exit(1);
+ }
+
+ res = pread(fd, buf, mtdsize, block_offset);
+ if (res != mtdsize) {
+ perror("pread");
+ exit(1);
+ }
+
+ if (seama_fix_md5(buf, mtdsize))
+ goto out;
+
+ if (mtd_erase_block(fd, block_offset)) {
+ fprintf(stderr, "Can't erease block at 0x%x (%s)\n",
+ block_offset, strerror(errno));
+ exit(1);
+ }
+
+ if (quiet < 2)
+ fprintf(stderr, "Rewriting block at 0x%x\n", block_offset);
+
+ if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
+ fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
+ exit(1);
+ }
+
+ if (quiet < 2)
+ fprintf(stderr, "Done.\n");
+
+out:
+ close (fd);
+ sync();
+
+ return 0;
+}
+
--- /dev/null
+/* vi: set sw=4 ts=4: */
+/*
+ * (SEA)ttle i(MA)ge is the image which used in project seattle.
+ *
+ * Created by David Hsieh <david_hsieh@alphanetworks.com>
+ * Copyright (C) 2008-2009 Alpha Networks, Inc.
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either'
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * The GNU C Library is distributed in the hope that it will be useful,'
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the GNU C Library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA.
+ */
+
+#ifndef __SEAMA_HEADER_FILE__
+#define __SEAMA_HEADER_FILE__
+
+#include <stdint.h>
+
+#define SEAMA_MAGIC 0x5EA3A417
+
+/*
+ * SEAMA looks like the following map.
+ * All the data of the header should be in network byte order.
+ *
+ * +-------------+-------------+------------
+ * | SEAMA magic | ^
+ * +-------------+-------------+ |
+ * | reserved | meta size | |
+ * +-------------+-------------+ header
+ * | image size (0 bytes) | |
+ * +-------------+-------------+ |
+ * ~ Meta data ~ v
+ * +-------------+-------------+------------
+ * | SEAMA magic | ^ ^
+ * +-------------+-------------+ | |
+ * | reserved | meta size | | |
+ * +-------------+-------------+ | |
+ * | image size | | |
+ * +-------------+-------------+ header |
+ * | | | |
+ * | 16 bytes of MD5 digest | | |
+ * | | | |
+ * | | | |
+ * +-------------+-------------+ | |
+ * ~ Meta data ~ v |
+ * +-------------+-------------+------- |
+ * | | |
+ * | Image of the 1st entity | |
+ * ~ ~ 1st entity
+ * | | |
+ * | | v
+ * +-------------+-------------+-------------
+ * | SEAMA magic | ^ ^
+ * +-------------+-------------+ | |
+ * | reserved | meta size | | |
+ * +-------------+-------------+ | |
+ * | image size | | |
+ * +-------------+-------------+ header |
+ * | | | |
+ * | 16 bytes of MD5 digest | | |
+ * | | | |
+ * | | | |
+ * +-------------+-------------+ | |
+ * ~ Meta data ~ v |
+ * +-------------+-------------+------- |
+ * | | |
+ * | Image of the 2nd entity | |
+ * ~ ~ 2nd entity
+ * | | |
+ * | | v
+ * +-------------+-------------+-------------
+ */
+
+
+/*
+ * SEAMA header
+ *
+ * |<-------- 32 bits -------->|
+ * +-------------+-------------+
+ * | SEAMA magic |
+ * +-------------+-------------+
+ * | reserved | meta size |
+ * +-------------+-------------+
+ * | image size |
+ * +-------------+-------------+
+ */
+/* seama header */
+typedef struct seama_hdr seamahdr_t;
+struct seama_hdr
+{
+ uint32_t magic; /* should always be SEAMA_MAGIC. */
+ uint16_t reserved; /* reserved for */
+ uint16_t metasize; /* size of the META data */
+ uint32_t size; /* size of the image */
+} __attribute__ ((packed));
+
+
+#endif
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
+#include <errno.h>
#include <sys/ioctl.h>
-#include "mtd-api.h"
+#include <mtd/mtd-user.h>
#include "mtd.h"
#include "crc32.h"
#define TRX_MAGIC 0x30524448 /* "HDR0" */
struct trx_header {
- unsigned magic; /* "HDR0" */
- unsigned len; /* Length of file including header */
- unsigned crc32; /* 32-bit CRC from flag_version to end of file */
- unsigned flag_version; /* 0:15 flags, 16:31 version */
- unsigned offsets[3]; /* Offsets of partitions from start of header */
+ uint32_t magic; /* "HDR0" */
+ uint32_t len; /* Length of file including header */
+ uint32_t crc32; /* 32-bit CRC from flag_version to end of file */
+ uint32_t flag_version; /* 0:15 flags, 16:31 version */
+ uint32_t offsets[3]; /* Offsets of partitions from start of header */
};
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X) ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X) (X)
+#else
+#error unknown endianness!
+#endif
+
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+
int
trx_fixup(int fd, const char *name)
{
return 1;
}
+int
+mtd_fixtrx(const char *mtd, size_t offset)
+{
+ int fd;
+ struct trx_header *trx;
+ char *buf;
+ ssize_t res;
+ size_t block_offset;
+
+ if (quiet < 2)
+ fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset);
+
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ exit(1);
+ }
+
+ block_offset = offset & ~(erasesize - 1);
+ offset -= block_offset;
+
+ if (block_offset + erasesize > mtdsize) {
+ fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize);
+ exit(1);
+ }
+
+ buf = malloc(erasesize);
+ if (!buf) {
+ perror("malloc");
+ exit(1);
+ }
+
+ res = pread(fd, buf, erasesize, block_offset);
+ if (res != erasesize) {
+ perror("pread");
+ exit(1);
+ }
+
+ trx = (struct trx_header *) (buf + offset);
+ if (trx->magic != STORE32_LE(0x30524448)) {
+ fprintf(stderr, "No trx magic found\n");
+ exit(1);
+ }
+
+ if (trx->len == STORE32_LE(erasesize - offset)) {
+ if (quiet < 2)
+ fprintf(stderr, "Header already fixed, exiting\n");
+ close(fd);
+ return 0;
+ }
+
+ trx->len = STORE32_LE(erasesize - offset);
+
+ trx->crc32 = STORE32_LE(crc32buf((char*) &trx->flag_version, erasesize - offset - 3*4));
+ if (mtd_erase_block(fd, block_offset)) {
+ fprintf(stderr, "Can't erease block at 0x%x (%s)\n", block_offset, strerror(errno));
+ exit(1);
+ }
+
+ if (quiet < 2)
+ fprintf(stderr, "New crc32: 0x%x, rewriting block\n", trx->crc32);
+
+ if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
+ fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
+ exit(1);
+ }
+
+ if (quiet < 2)
+ fprintf(stderr, "Done.\n");
+
+ close (fd);
+ sync();
+ return 0;
+
+}
+
--- /dev/null
+#
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=quagga
+PKG_VERSION:=1.0.20160315
+PKG_RELEASE:=2
+PKG_MD5SUM:=61bfd0c8fb696dd778234ee8b05821bc
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=http://download.savannah.gnu.org/releases/quagga/
+PKG_CONFIG_DEPENDS:= \
+ CONFIG_IPV6 \
+ CONFIG_PACKAGE_quagga-watchquagga \
+ CONFIG_PACKAGE_quagga-zebra \
+ CONFIG_PACKAGE_quagga-libzebra \
+ CONFIG_PACKAGE_quagga-libospf \
+ CONFIG_PACKAGE_quagga-bgpd \
+ CONFIG_PACKAGE_quagga-isisd \
+ CONFIG_PACKAGE_quagga-ospf6d \
+ CONFIG_PACKAGE_quagga-ripd \
+ CONFIG_PACKAGE_quagga-ripngd \
+ CONFIG_PACKAGE_quagga-babeld \
+ CONFIG_PACKAGE_quagga-vtysh \
+ CONFIG_PACKAGE_quagga-pgbgp
+PKG_BUILD_PARALLEL:=1
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+
+PATCH_DIR:=patches-pgbgp
+ifeq ($(CONFIG_PACKAGE_quagga-pgbgp),)
+PATCH_DIR:=patches-upstream
+endif
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/quagga/Default
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=Routing and Redirection
+ DEPENDS:=quagga
+ TITLE:=The Quagga Software Routing Suite
+ URL:=http://www.quagga.net
+ MAINTAINER:=Vasilis Tsiligiannis <b_tsiligiannis@silverton.gr>
+endef
+
+define Package/quagga
+ $(call Package/quagga/Default)
+ DEPENDS:=+librt
+ MENU:=1
+endef
+
+define Package/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/quagga-watchquagga
+ $(call Package/quagga/Default)
+ TITLE:=Quagga watchdog
+ DEPENDS+=+quagga-libzebra
+ DEFAULT:=y if PACKAGE_quagga
+endef
+
+define Package/quagga-zebra
+ $(call Package/quagga/Default)
+ TITLE:=Zebra daemon
+ DEPENDS+=+quagga-libzebra
+ DEFAULT:=y if PACKAGE_quagga
+endef
+
+define Package/quagga-libzebra
+ $(call Package/quagga/Default)
+ TITLE:=zebra library
+endef
+
+define Package/quagga-libospf
+ $(call Package/quagga/Default)
+ TITLE:=OSPF library
+endef
+
+define Package/quagga-bgpd
+ $(call Package/quagga/Default)
+ DEPENDS+=+quagga-libzebra
+ TITLE:=BGPv4, BGPv4+, BGPv4- routing engine
+endef
+
+define Package/quagga-isisd
+ $(call Package/quagga/Default)
+ DEPENDS+=+quagga-libzebra
+ TITLE:=IS-IS routing engine
+endef
+
+define Package/quagga-ospfd
+ $(call Package/quagga/Default)
+ DEPENDS+=+quagga-libospf +quagga-libzebra
+ TITLE:=OSPFv2 routing engine
+endef
+
+define Package/quagga-ospf6d
+ $(call Package/quagga/Default)
+ DEPENDS+=+quagga-libospf +quagga-libzebra @IPV6
+ TITLE:=OSPFv3 routing engine
+endef
+
+define Package/quagga-ripd
+ $(call Package/quagga/Default)
+ DEPENDS+=+quagga-libzebra
+ TITLE:=RIP routing engine
+endef
+
+define Package/quagga-ripngd
+ $(call Package/quagga/Default)
+ DEPENDS+=+quagga-libzebra @IPV6
+ TITLE:=RIPNG routing engine
+endef
+
+define Package/quagga-babeld
+ $(call Package/quagga/Default)
+ DEPENDS+=+quagga-libzebra @IPV6
+ TITLE:=Babel routing engine
+endef
+
+define Package/quagga-vtysh
+ $(call Package/quagga/Default)
+ DEPENDS+=+quagga-libzebra +libreadline +libncurses
+ TITLE:=integrated shell for Quagga routing software
+endef
+
+define Package/quagga-pgbgp
+ $(call Package/quagga/Default)
+ DEPENDS+=+quagga-bgpd
+ TITLE:=include Pretty Good BGP functionality
+endef
+
+define Package/quagga-zebra/conffiles
+/etc/quagga/zebra.conf
+endef
+
+define Package/quagga-bgpd/conffiles
+/etc/quagga/bgpd.conf
+endef
+
+define Package/quagga-isisd/conffiles
+/etc/quagga/isisd.conf
+endef
+
+define Package/quagga-ospfd/conffiles
+/etc/quagga/ospfd.conf
+endef
+
+define Package/quagga-ospf6d/conffiles
+/etc/quagga/ospf6d.conf
+endef
+
+define Package/quagga-ripd/conffiles
+/etc/quagga/ripd.conf
+endef
+
+define Package/quagga-ripngd/conffiles
+/etc/quagga/ripngd.conf
+endef
+
+define Package/quagga-babeld/conffiles
+/etc/quagga/babeld.conf
+endef
+
+ifneq ($(SDK),)
+CONFIG_PACKAGE_quagga-libzebra:=m
+CONFIG_PACKAGE_quagga-libospf:=m
+CONFIG_PACKAGE_quagga-watchquagga:=m
+CONFIG_PACKAGE_quagga-zebra:=m
+CONFIG_PACKAGE_quagga-bgpd:=m
+CONFIG_PACKAGE_quagga-isisd:=m
+CONFIG_PACKAGE_quagga-ospf6d:=m
+CONFIG_PACKAGE_quagga-ripd:=m
+CONFIG_PACKAGE_quagga-ripngd:=m
+CONFIG_PACKAGE_quagga-babeld:=m
+CONFIG_PACKAGE_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 \
+ --disable-doc \
+ $(call autoconf_bool,CONFIG_PACKAGE_quagga-libzebra,zebra) \
+ $(call autoconf_bool,CONFIG_PACKAGE_quagga-libospf,ospfd) \
+ $(call autoconf_bool,CONFIG_PACKAGE_quagga-bgpd,bgpd) \
+ $(call autoconf_bool,CONFIG_PACKAGE_quagga-isisd,isisd) \
+ $(call autoconf_bool,CONFIG_PACKAGE_quagga-ospf6d,ospf6d) \
+ $(call autoconf_bool,CONFIG_PACKAGE_quagga-ripd,ripd) \
+ $(call autoconf_bool,CONFIG_PACKAGE_quagga-ripngd,ripngd) \
+ $(call autoconf_bool,CONFIG_PACKAGE_quagga-babeld,babeld) \
+ $(call autoconf_bool,CONFIG_PACKAGE_quagga-vtysh,vtysh) \
+ $(call autoconf_bool,CONFIG_PACKAGE_quagga-pgbgp,pgbgp) \
+
+MAKE_FLAGS += \
+ CFLAGS="$(TARGET_CFLAGS) -std=gnu99"
+
+define Package/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/quagga-watchquagga/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/watchquagga $(1)/usr/sbin/
+endef
+
+define Package/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/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/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/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/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/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/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/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/quagga-vtysh/install
+ $(INSTALL_DIR) $(1)/usr/bin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/vtysh $(1)/usr/bin/
+endef
+
+define Package/quagga-pgbgp/install
+endef
+
+define Package/quagga-libospf/install
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/libospf.so.* $(1)/usr/lib/
+endef
+
+define Package/quagga-libzebra/install
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/libzebra.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,quagga))
+$(eval $(call BuildPackage,quagga-libzebra))
+$(eval $(call BuildPackage,quagga-libospf))
+$(eval $(call BuildPackage,quagga-watchquagga))
+$(eval $(call BuildPackage,quagga-zebra))
+$(eval $(call BuildPackage,quagga-bgpd))
+$(eval $(call BuildPackage,quagga-pgbgp))
+$(eval $(call BuildPackage,quagga-isisd))
+$(eval $(call BuildPackage,quagga-ospfd))
+$(eval $(call BuildPackage,quagga-ospf6d))
+$(eval $(call BuildPackage,quagga-ripd))
+$(eval $(call BuildPackage,quagga-ripngd))
+$(eval $(call BuildPackage,quagga-babeld))
+$(eval $(call BuildPackage,quagga-vtysh))
--- /dev/null
+#!/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" -a -x "${BINDIR}/watchquagga" ]
+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
--- /dev/null
+password zebra
+!
+access-list vty permit 127.0.0.0/8
+access-list vty deny any
+!
+line vty
+ access-class vty
--- /dev/null
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006 OpenWrt.org
+
+START=60
+start() {
+ /usr/sbin/quagga.init start
+}
+
+stop() {
+ /usr/sbin/quagga.init stop
+}
--- /dev/null
+--- a/lib/log.c
++++ b/lib/log.c
+@@ -925,13 +925,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)
+@@ -944,13 +950,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
+@@ -1810,6 +1810,9 @@ netlink_route_multipath (int cmd, struct
+ if (rta->rta_len > RTA_LENGTH (0))
+ addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
+ RTA_PAYLOAD (rta));
++
++ if (rib->type == ZEBRA_ROUTE_OLSR)
++ req.r.rtm_scope = RT_SCOPE_LINK;
+ }
+
+ /* If there is no useful nexthop then return. */
+--- a/zebra/zebra_rib.c
++++ b/zebra/zebra_rib.c
+@@ -68,6 +68,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 */
+ };
+@@ -538,6 +541,18 @@ nexthop_active_ipv4 (struct rib *rib, st
+ }
+ return resolved;
+ }
++ 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;
+@@ -674,6 +689,18 @@ nexthop_active_ipv6 (struct rib *rib, st
+ }
+ return resolved;
+ }
++ 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;
+@@ -1509,6 +1536,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
+@@ -245,6 +245,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
+@@ -559,7 +559,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;
+@@ -754,7 +757,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;
+@@ -1550,7 +1556,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;
+@@ -1692,7 +1701,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;
--- /dev/null
+From: Timo Teräs <timo.teras@iki.fi>
+Date: Thu, 24 Apr 2014 07:22:37 +0000 (+0300)
+Subject: bgpd: implement "next-hop-self all"
+X-Git-Url: http://git.ozo.com/?p=quagga%2F.git;a=commitdiff_plain;h=9e7a53c179f6897128b24435452b5d3d0f8c715a
+
+bgpd: implement "next-hop-self all"
+
+As specified in:
+http://www.cisco.com/c/en/us/td/docs/ios-xml/ios/iproute_bgp/command/irg-cr-book/bgp-m1.html#wp4972925610
+
+This allows overriding next-hop for ibgp learned routes on an
+RR for reflected routes.
+
+Especially useful for using iBGP in DMVPN setups. See:
+http://blog.ipspace.net/2014/04/changes-in-ibgp-next-hop-processing.html
+
+Signed-off-by: Timo Teräs <timo.teras@iki.fi>
+---
+
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -973,7 +973,8 @@ bgp_announce_check (struct bgp_info *ri,
+ }
+
+ /* next-hop-set */
+- if (transparent || reflect
++ if (transparent
++ || (reflect && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF_ALL))
+ || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)
+ && ((p->family == AF_INET && attr->nexthop.s_addr)
+ #ifdef HAVE_IPV6
+--- a/bgpd/bgp_vty.c
++++ b/bgpd/bgp_vty.c
+@@ -2093,25 +2093,41 @@ DEFUN (no_neighbor_capability_orf_prefix
+ /* neighbor next-hop-self. */
+ DEFUN (neighbor_nexthop_self,
+ neighbor_nexthop_self_cmd,
+- NEIGHBOR_CMD2 "next-hop-self",
++ NEIGHBOR_CMD2 "next-hop-self {all}",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+- "Disable the next hop calculation for this neighbor\n")
++ "Disable the next hop calculation for this neighbor\n"
++ "Apply also to ibgp-learned routes when acting as a route reflector\n")
+ {
+- return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+- bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF);
++ u_int32_t flags = PEER_FLAG_NEXTHOP_SELF, unset = 0;
++ int rc;
++
++ /* Check if "all" is specified */
++ if (argv[1] != NULL)
++ flags |= PEER_FLAG_NEXTHOP_SELF_ALL;
++ else
++ unset |= PEER_FLAG_NEXTHOP_SELF_ALL;
++
++ rc = peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
++ bgp_node_safi (vty), flags);
++ if ( rc == CMD_SUCCESS && unset )
++ rc = peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
++ bgp_node_safi (vty), unset);
++ return rc;
+ }
+
+ DEFUN (no_neighbor_nexthop_self,
+ no_neighbor_nexthop_self_cmd,
+- NO_NEIGHBOR_CMD2 "next-hop-self",
++ NO_NEIGHBOR_CMD2 "next-hop-self {all}",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+- "Disable the next hop calculation for this neighbor\n")
++ "Disable the next hop calculation for this neighbor\n"
++ "Apply also to ibgp-learned routes when acting as a route reflector\n")
+ {
+ return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+- bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF);
++ bgp_node_safi (vty),
++ PEER_FLAG_NEXTHOP_SELF|PEER_FLAG_NEXTHOP_SELF_ALL);
+ }
+
+ /* neighbor remove-private-AS. */
+--- a/bgpd/bgpd.c
++++ b/bgpd/bgpd.c
+@@ -2355,6 +2355,7 @@ static const struct peer_flag_action pee
+ { PEER_FLAG_ORF_PREFIX_SM, 1, peer_change_reset },
+ { PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset },
+ { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out },
++ { PEER_FLAG_NEXTHOP_SELF_ALL, 1, peer_change_reset_out },
+ { 0, 0, 0 }
+ };
+
+@@ -4990,7 +4991,9 @@ bgp_config_write_peer (struct vty *vty,
+ /* Nexthop self. */
+ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF)
+ && ! peer->af_group[afi][safi])
+- vty_out (vty, " neighbor %s next-hop-self%s", addr, VTY_NEWLINE);
++ vty_out (vty, " neighbor %s next-hop-self%s%s", addr,
++ peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF_ALL) ?
++ " all" : "", VTY_NEWLINE);
+
+ /* Remove private AS. */
+ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)
+--- a/bgpd/bgpd.h
++++ b/bgpd/bgpd.h
+@@ -412,6 +412,7 @@ struct peer
+ #define PEER_FLAG_MAX_PREFIX (1 << 14) /* maximum prefix */
+ #define PEER_FLAG_MAX_PREFIX_WARNING (1 << 15) /* maximum prefix warning-only */
+ #define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1 << 16) /* leave link-local nexthop unchanged */
++#define PEER_FLAG_NEXTHOP_SELF_ALL (1 << 17) /* next-hop-self all */
+
+ /* MD5 password */
+ char *password;
+--- a/doc/bgpd.texi
++++ b/doc/bgpd.texi
+@@ -299,10 +299,12 @@ This command is deprecated and may be re
+ use should be avoided.
+ @end deffn
+
+-@deffn {BGP} {neighbor @var{peer} next-hop-self} {}
+-@deffnx {BGP} {no neighbor @var{peer} next-hop-self} {}
++@deffn {BGP} {neighbor @var{peer} next-hop-self [all]} {}
++@deffnx {BGP} {no neighbor @var{peer} next-hop-self [all]} {}
+ This command specifies an announced route's nexthop as being equivalent
+-to the address of the bgp router.
++to the address of the bgp router if it is learned via eBGP.
++If the optional keyword @code{all} is specified the modifiation is done
++also for routes learned via iBGP.
+ @end deffn
+
+ @deffn {BGP} {neighbor @var{peer} update-source @var{<ifname|address>}} {}
--- /dev/null
+From: Timo Teräs <timo.teras@iki.fi>
+Date: Tue, 20 May 2014 06:04:49 +0000 (+0300)
+Subject: bgpd: route-map: share aspath object compilation code where possible
+X-Git-Url: http://git.ozo.com/?p=quagga%2F.git;a=commitdiff_plain;h=b304dcb8abc4e5b93f86a4024990980746e730be
+
+bgpd: route-map: share aspath object compilation code where possible
+
+Signed-off-by: Timo Teräs <timo.teras@iki.fi>
+---
+
+--- a/bgpd/bgp_routemap.c
++++ b/bgpd/bgp_routemap.c
+@@ -101,6 +101,26 @@ o Local extention
+
+ */
+
++ /* generic as path object to be shared in multiple rules */
++
++static void *
++route_aspath_compile (const char *arg)
++{
++ struct aspath *aspath;
++
++ aspath = aspath_str2aspath (arg);
++ if (! aspath)
++ return NULL;
++ return aspath;
++}
++
++static void
++route_aspath_free (void *rule)
++{
++ struct aspath *aspath = rule;
++ aspath_free (aspath);
++}
++
+ /* 'match peer (A.B.C.D|X:X::X:X)' */
+
+ /* Compares the peer specified in the 'match peer' clause with the peer
+@@ -1228,33 +1248,13 @@ route_set_aspath_prepend (void *rule, st
+ return RMAP_OKAY;
+ }
+
+-/* Compile function for as-path prepend. */
+-static void *
+-route_set_aspath_prepend_compile (const char *arg)
+-{
+- struct aspath *aspath;
+-
+- aspath = aspath_str2aspath (arg);
+- if (! aspath)
+- return NULL;
+- return aspath;
+-}
+-
+-/* Compile function for as-path prepend. */
+-static void
+-route_set_aspath_prepend_free (void *rule)
+-{
+- struct aspath *aspath = rule;
+- aspath_free (aspath);
+-}
+-
+ /* Set metric rule structure. */
+ struct route_map_rule_cmd route_set_aspath_prepend_cmd =
+ {
+ "as-path prepend",
+ route_set_aspath_prepend,
+- route_set_aspath_prepend_compile,
+- route_set_aspath_prepend_free,
++ route_aspath_compile,
++ route_aspath_free,
+ };
+
+ /* `set as-path exclude ASn' */
+@@ -1282,37 +1282,13 @@ route_set_aspath_exclude (void *rule, st
+ return RMAP_OKAY;
+ }
+
+-/* FIXME: consider using route_set_aspath_prepend_compile() and
+- * route_set_aspath_prepend_free(), which two below function are
+- * exact clones of.
+- */
+-
+-/* Compile function for as-path exclude. */
+-static void *
+-route_set_aspath_exclude_compile (const char *arg)
+-{
+- struct aspath *aspath;
+-
+- aspath = aspath_str2aspath (arg);
+- if (! aspath)
+- return NULL;
+- return aspath;
+-}
+-
+-static void
+-route_set_aspath_exclude_free (void *rule)
+-{
+- struct aspath *aspath = rule;
+- aspath_free (aspath);
+-}
+-
+ /* Set ASn exlude rule structure. */
+ struct route_map_rule_cmd route_set_aspath_exclude_cmd =
+ {
+ "as-path exclude",
+ route_set_aspath_exclude,
+- route_set_aspath_exclude_compile,
+- route_set_aspath_exclude_free,
++ route_aspath_compile,
++ route_aspath_free,
+ };
+
+ /* `set community COMMUNITY' */
--- /dev/null
+From 06bd420d4646333bc7ed9964e348f19a942fcfe2 Mon Sep 17 00:00:00 2001
+From: Balaji <balajig81@gmail.com>
+Date: Mon, 16 Mar 2015 16:55:29 +0000
+Subject: [PATCH] bgpd: Display of configured dampening parameters
+
+Function to display configured bgp dampening parameters.
+
+Signed-off-by: Balaji.G <balajig81@gmail.com>
+[DL: formatting adjustments]
+Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
+---
+ bgpd/bgp_damp.c | 33 +++++++++++++++++++++++++++++++++
+ bgpd/bgp_damp.h | 2 ++
+ 2 files changed, 35 insertions(+)
+
+diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
+index 0ffafb7..dd6c759 100644
+--- a/bgpd/bgp_damp.c
++++ b/bgpd/bgp_damp.c
+@@ -639,3 +639,36 @@ bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo,
+
+ return bgp_get_reuse_time (penalty, timebuf, len);
+ }
++
++int
++bgp_show_dampening_parameters (struct vty *vty, afi_t afi, safi_t safi)
++{
++ struct bgp *bgp;
++ bgp = bgp_get_default();
++
++ if (bgp == NULL)
++ {
++ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
++ return CMD_WARNING;
++ }
++
++ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
++ {
++ vty_out (vty, "Half-life time: %ld min%s",
++ damp->half_life / 60, VTY_NEWLINE);
++ vty_out (vty, "Reuse penalty: %d%s",
++ damp->reuse_limit, VTY_NEWLINE);
++ vty_out (vty, "Suppress penalty: %d%s",
++ damp->suppress_value, VTY_NEWLINE);
++ vty_out (vty, "Max suppress time: %ld min%s",
++ damp->max_suppress_time / 60, VTY_NEWLINE);
++ vty_out (vty, "Max supress penalty: %u%s",
++ damp->ceiling, VTY_NEWLINE);
++ vty_out (vty, "%s", VTY_NEWLINE);
++ }
++ else
++ vty_out (vty, "dampening not enabled for %s%s",
++ afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE);
++
++ return CMD_SUCCESS;
++}
+diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h
+index e1d319b..16fd367 100644
+--- a/bgpd/bgp_damp.h
++++ b/bgpd/bgp_damp.h
+@@ -144,4 +144,6 @@ extern void bgp_damp_info_vty (struct vty *, struct bgp_info *);
+ extern const char * bgp_damp_reuse_time_vty (struct vty *, struct bgp_info *,
+ char *, size_t);
+
++extern int bgp_show_dampening_parameters (struct vty *vty, afi_t, safi_t);
++
+ #endif /* _QUAGGA_BGP_DAMP_H */
+--
+2.7.0
+
--- /dev/null
+From aa7dbb1067b7d02e1354fe1e5664ccb7d259d649 Mon Sep 17 00:00:00 2001
+From: Balaji <balajig81@gmail.com>
+Date: Mon, 16 Mar 2015 16:55:26 +0000
+Subject: [PATCH] bgpd: Configured suppress value cannot be less than the reuse
+ value in bgp dampening
+
+RFC 2439, Section 4.2; the values pair up for hysteresis.
+
+Signed-off-by: Balaji.G <balajig81@gmail.com>
+Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
+---
+ bgpd/bgp_route.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
+index e7357e5..f84a72d 100644
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -11976,6 +11976,14 @@ DEFUN (bgp_damp_set,
+ }
+
+ bgp = vty->index;
++
++ if (suppress < reuse)
++ {
++ vty_out (vty, "Suppress value cannot be less than reuse value %s",
++ VTY_NEWLINE);
++ return 0;
++ }
++
+ return bgp_damp_enable (bgp, bgp_node_afi (vty), bgp_node_safi (vty),
+ half, reuse, suppress, max);
+ }
+--
+2.7.0
+
--- /dev/null
+From bd4b7f1559ab5cb52bbe9dc2db9e50a032ccdbb7 Mon Sep 17 00:00:00 2001
+From: vivek <vivek@cumulusnetworks.com>
+Date: Tue, 30 Sep 2014 15:54:45 -0700
+Subject: [PATCH] bgpd: Ignore stale entry candidates during bestpath
+ selection.
+
+During best path selection, if one of the candidates is a stale entry, do not
+perform the neighbor address comparison as that information is invalid for
+the stale entry. Attempting to perform the comparison results in a bgpd
+exception.
+
+Signed-off-by: Vivek Venkataraman <vivek@cumulusnetworks.com>
+Reviewed-by: Dinesh G Dutt <ddutt@cumulusnetworks.com>
+---
+ bgpd/bgp_route.c | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
+index 34ba1ab..648dc9c 100644
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -524,7 +524,11 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist,
+ return 0;
+ }
+
+- /* 11. Rourter-ID comparision. */
++ /* 11. Router-ID comparision. */
++ /* If one of the paths is "stale", the corresponding peer router-id will
++ * be 0 and would always win over the other path. If originator id is
++ * used for the comparision, it will decide which path is better.
++ */
+ if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
+ new_id.s_addr = newattre->originator_id.s_addr;
+ else
+@@ -553,6 +557,14 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist,
+ return 0;
+
+ /* 13. Neighbor address comparision. */
++ /* Do this only if neither path is "stale" as stale paths do not have
++ * valid peer information (as the connection may or may not be up).
++ */
++ if (CHECK_FLAG (exist->flags, BGP_INFO_STALE))
++ return 1;
++ if (CHECK_FLAG (new->flags, BGP_INFO_STALE))
++ return 0;
++
+ ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote);
+
+ if (ret == 1)
+--
+2.7.0
+
--- /dev/null
+From 234e5c8d5a35339fb319affb952581bf5abb48a7 Mon Sep 17 00:00:00 2001
+From: Dinesh G Dutt <ddutt@cumulusnetworks.com>
+Date: Sun, 1 Feb 2015 00:56:12 -0800
+Subject: [PATCH] bgpd: Only use routes from Established peers for best path
+ selection
+
+Ensure that routes from a peer are not considered for best path
+comparison if the peer is not in an Established state. There can
+be a window between a peer being deleted and the background
+thread that actually clears the routes (marks them as "removed")
+runs during which best path may run. If this path selection
+compared two prefixes all the way down to peer IP addresses and
+one of these two peers had just been deleted, that peer would
+not have its sockunion structures, especially su_remote, resulting
+in a BGPD exception.
+
+Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
+---
+ bgpd/bgp_route.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
+index 648dc9c..02c926f 100644
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -1345,6 +1345,9 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
+ continue;
+ if (BGP_INFO_HOLDDOWN (ri1))
+ continue;
++ if (ri1->peer && ri1->peer != bgp->peer_self)
++ if (ri1->peer->status != Established)
++ continue;
+
+ new_select = ri1;
+ if (do_mpath)
+@@ -1357,6 +1360,11 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
+ continue;
+ if (BGP_INFO_HOLDDOWN (ri2))
+ continue;
++ if (ri2->peer &&
++ ri2->peer != bgp->peer_self &&
++ !CHECK_FLAG (ri2->peer->sflags, PEER_STATUS_NSF_WAIT))
++ if (ri2->peer->status != Established)
++ continue;
+
+ if (aspath_cmp_left (ri1->attr->aspath, ri2->attr->aspath)
+ || aspath_cmp_left_confed (ri1->attr->aspath,
+@@ -1408,6 +1416,12 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
+ continue;
+ }
+
++ if (ri->peer &&
++ ri->peer != bgp->peer_self &&
++ !CHECK_FLAG (ri->peer->sflags, PEER_STATUS_NSF_WAIT))
++ if (ri->peer->status != Established)
++ continue;
++
+ if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)
+ && (! CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED)))
+ {
+--
+2.7.0
+
--- /dev/null
+From c37b9bccdcc1266f52e50fa3e5a8dc81086c3fe7 Mon Sep 17 00:00:00 2001
+From: Daniel Walton <dwalton@cumulusnetworks.com>
+Date: Wed, 21 Oct 2015 06:42:50 -0700
+Subject: [PATCH] bgpd: Enable "bgp log-neighbor-changes" by default
+
+Signed-off-by: Daniel Walton <dwalton@cumulusnetworks.com>
+Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
+---
+ bgpd/bgpd.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
+index c94c381..c7f22e8 100644
+--- a/bgpd/bgpd.c
++++ b/bgpd/bgpd.c
+@@ -1974,6 +1974,7 @@ bgp_create (as_t *as, const char *name)
+ bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
+ bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
+ bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME;
++ bgp_flag_set (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES);
+
+ bgp->as = *as;
+
+@@ -5259,8 +5260,8 @@ bgp_config_write (struct vty *vty)
+ VTY_NEWLINE);
+
+ /* BGP log-neighbor-changes. */
+- if (bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
+- vty_out (vty, " bgp log-neighbor-changes%s", VTY_NEWLINE);
++ if (!bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
++ vty_out (vty, " no bgp log-neighbor-changes%s", VTY_NEWLINE);
+
+ /* BGP configuration. */
+ if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED))
+--
+2.7.0
+
--- /dev/null
+diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
+index 34cb7c0..438fb0c 100644
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -7169,6 +7169,17 @@ DEFUN (show_ip_bgp_flap_regexp,
+ bgp_show_type_flap_regexp);
+ }
+
++ALIAS (show_ip_bgp_flap_regexp,
++ show_ip_bgp_damp_flap_regexp_cmd,
++ "show ip bgp dampening flap-statistics regexp .LINE",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Display detailed information about dampening\n"
++ "Display flap statistics of routes\n"
++ "Display routes matching the AS path regular expression\n"
++ "A regular-expression to match the BGP AS paths\n")
++
+ DEFUN (show_ip_bgp_ipv4_regexp,
+ show_ip_bgp_ipv4_regexp_cmd,
+ "show ip bgp ipv4 (unicast|multicast) regexp .LINE",
+@@ -7284,6 +7295,17 @@ DEFUN (show_ip_bgp_flap_prefix_list,
+ bgp_show_type_flap_prefix_list);
+ }
+
++ALIAS (show_ip_bgp_flap_prefix_list,
++ show_ip_bgp_damp_flap_prefix_list_cmd,
++ "show ip bgp dampening flap-statistics prefix-list WORD",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Display detailed information about dampening\n"
++ "Display flap statistics of routes\n"
++ "Display routes conforming to the prefix-list\n"
++ "IP prefix-list name\n")
++
+ DEFUN (show_ip_bgp_ipv4_prefix_list,
+ show_ip_bgp_ipv4_prefix_list_cmd,
+ "show ip bgp ipv4 (unicast|multicast) prefix-list WORD",
+@@ -7398,6 +7420,17 @@ DEFUN (show_ip_bgp_flap_filter_list,
+ bgp_show_type_flap_filter_list);
+ }
+
++ALIAS (show_ip_bgp_flap_filter_list,
++ show_ip_bgp_damp_flap_filter_list_cmd,
++ "show ip bgp dampening flap-statistics filter-list WORD",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Display detailed information about dampening\n"
++ "Display flap statistics of routes\n"
++ "Display routes conforming to the filter-list\n"
++ "Regular expression access list name\n")
++
+ DEFUN (show_ip_bgp_ipv4_filter_list,
+ show_ip_bgp_ipv4_filter_list_cmd,
+ "show ip bgp ipv4 (unicast|multicast) filter-list WORD",
+@@ -7469,6 +7502,18 @@ DEFUN (show_ipv6_mbgp_filter_list,
+ }
+ #endif /* HAVE_IPV6 */
+
++DEFUN (show_ip_bgp_dampening_info,
++ show_ip_bgp_dampening_params_cmd,
++ "show ip bgp dampening parameters",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Display detailed information about dampening\n"
++ "Display detail of configured dampening parameters\n")
++{
++ return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST);
++}
++
+ static int
+ bgp_show_route_map (struct vty *vty, const char *rmap_str, afi_t afi,
+ safi_t safi, enum bgp_show_type type)
+@@ -7513,6 +7558,17 @@ DEFUN (show_ip_bgp_flap_route_map,
+ bgp_show_type_flap_route_map);
+ }
+
++ALIAS (show_ip_bgp_flap_route_map,
++ show_ip_bgp_damp_flap_route_map_cmd,
++ "show ip bgp dampening flap-statistics route-map WORD",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Display detailed information about dampening\n"
++ "Display flap statistics of routes\n"
++ "Display routes matching the route-map\n"
++ "A route-map to match on\n")
++
+ DEFUN (show_ip_bgp_ipv4_route_map,
+ show_ip_bgp_ipv4_route_map_cmd,
+ "show ip bgp ipv4 (unicast|multicast) route-map WORD",
+@@ -7579,6 +7635,16 @@ DEFUN (show_ip_bgp_flap_cidr_only,
+ bgp_show_type_flap_cidr_only, NULL);
+ }
+
++ALIAS (show_ip_bgp_flap_cidr_only,
++ show_ip_bgp_damp_flap_cidr_only_cmd,
++ "show ip bgp dampening flap-statistics cidr-only",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Display detailed information about dampening\n"
++ "Display flap statistics of routes\n"
++ "Display only routes with non-natural netmasks\n")
++
+ DEFUN (show_ip_bgp_ipv4_cidr_only,
+ show_ip_bgp_ipv4_cidr_only_cmd,
+ "show ip bgp ipv4 (unicast|multicast) cidr-only",
+@@ -9062,6 +9128,17 @@ DEFUN (show_ip_bgp_flap_prefix_longer,
+ bgp_show_type_flap_prefix_longer);
+ }
+
++ALIAS (show_ip_bgp_flap_prefix_longer,
++ show_ip_bgp_damp_flap_prefix_longer_cmd,
++ "show ip bgp dampening flap-statistics A.B.C.D/M longer-prefixes",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Display detailed information about dampening\n"
++ "Display flap statistics of routes\n"
++ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
++ "Display route and more specific routes\n")
++
+ DEFUN (show_ip_bgp_ipv4_prefix_longer,
+ show_ip_bgp_ipv4_prefix_longer_cmd,
+ "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes",
+@@ -9095,6 +9172,16 @@ DEFUN (show_ip_bgp_flap_address,
+ bgp_show_type_flap_address);
+ }
+
++ALIAS (show_ip_bgp_flap_address,
++ show_ip_bgp_damp_flap_address_cmd,
++ "show ip bgp dampening flap-statistics A.B.C.D",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Display detailed information about dampening\n"
++ "Display flap statistics of routes\n"
++ "Network in the BGP routing table to display\n")
++
+ DEFUN (show_ip_bgp_flap_prefix,
+ show_ip_bgp_flap_prefix_cmd,
+ "show ip bgp flap-statistics A.B.C.D/M",
+@@ -9107,6 +9194,17 @@ DEFUN (show_ip_bgp_flap_prefix,
+ return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST,
+ bgp_show_type_flap_prefix);
+ }
++
++ALIAS (show_ip_bgp_flap_prefix,
++ show_ip_bgp_damp_flap_prefix_cmd,
++ "show ip bgp dampening flap-statistics A.B.C.D/M",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Display detailed information about dampening\n"
++ "Display flap statistics of routes\n"
++ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
++
+ #ifdef HAVE_IPV6
+ DEFUN (show_bgp_prefix_longer,
+ show_bgp_prefix_longer_cmd,
+@@ -11981,6 +12079,15 @@ DEFUN (show_ip_bgp_dampened_paths,
+ NULL);
+ }
+
++ALIAS (show_ip_bgp_dampened_paths,
++ show_ip_bgp_damp_dampened_paths_cmd,
++ "show ip bgp dampening dampened-paths",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Display detailed information about dampening\n"
++ "Display paths suppressed due to dampening\n")
++
+ DEFUN (show_ip_bgp_flap_statistics,
+ show_ip_bgp_flap_statistics_cmd,
+ "show ip bgp flap-statistics",
+@@ -11993,6 +12100,15 @@ DEFUN (show_ip_bgp_flap_statistics,
+ bgp_show_type_flap_statistics, NULL);
+ }
+
++ALIAS (show_ip_bgp_flap_statistics,
++ show_ip_bgp_damp_flap_statistics_cmd,
++ "show ip bgp dampening flap-statistics",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Display detailed information about dampening\n"
++ "Display flap statistics of routes\n")
++
+ /* Display specified route of BGP table. */
+ static int
+ bgp_clear_damp_route (struct vty *vty, const char *view_name,
+@@ -12506,16 +12622,25 @@ bgp_route_init (void)
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd);
+ 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_dampening_params_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_damp_dampened_paths_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_damp_flap_statistics_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_damp_flap_address_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_damp_flap_cidr_only_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_damp_flap_filter_list_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_damp_flap_prefix_longer_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_damp_flap_route_map_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_rsclient_cmd);
+@@ -12639,16 +12764,27 @@ bgp_route_init (void)
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd);
+ 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_dampening_params_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_damp_dampened_paths_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_statistics_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_address_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_cidr_only_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_regexp_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_filter_list_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_prefix_longer_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_route_map_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_rsclient_cmd);
--- /dev/null
+From f89b09be92bed03b1e5add55dc14ef92e94c52e1 Mon Sep 17 00:00:00 2001
+From: Daniel Walton <dwalton@cumulusnetworks.com>
+Date: Wed, 21 Oct 2015 06:42:52 -0700
+Subject: [PATCH] bgpd: Lower BGP's default keepalive/holdtime to 3s/9s
+
+Signed-off-by: Daniel Walton <dwalton@cumulusnetworks.com>
+Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
+---
+ bgpd/bgpd.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
+index 105912e..d4c8dbd 100644
+--- a/bgpd/bgpd.h
++++ b/bgpd/bgpd.h
+@@ -742,8 +742,8 @@ struct bgp_nlri
+
+ /* BGP timers default value. */
+ #define BGP_INIT_START_TIMER 5
+-#define BGP_DEFAULT_HOLDTIME 180
+-#define BGP_DEFAULT_KEEPALIVE 60
++#define BGP_DEFAULT_HOLDTIME 9
++#define BGP_DEFAULT_KEEPALIVE 3
+ #define BGP_DEFAULT_EBGP_ROUTEADV 30
+ #define BGP_DEFAULT_IBGP_ROUTEADV 5
+ #define BGP_CLEAR_CONNECT_RETRY 20
+--
+2.7.0
+
--- /dev/null
+From 64e0ac29ddc43bb5b1a2999a8ebedbdff115e3ca Mon Sep 17 00:00:00 2001
+From: Paul Jakma <paul.jakma@hpe.com>
+Date: Wed, 18 Nov 2015 16:00:54 +0000
+Subject: [PATCH] bgpd: Implicit updates in BGP may require a withdrawal from
+ zebra RIB
+
+* J Yu <jackiesyu@hotmail.com> noted a problem with bgpd of routes not
+ having their nexthop updated correctly.
+
+ Martin Winter <mwinter@opensourcerouting.org> pinned this down to the
+ case where a BGP route is updated from one with a valid nexthop to an
+ invalid next-hop, using a test tool. Once the problem occurs, the incorrect
+ route may remain, even after further UPDATEs, so long as the nexthop in the
+ zebra RIB does not match the BGP route's nexthop.
+
+ Jacqueline Yu then pinned the issue down further to being due to bgpd
+ sending the DELETE for the route to zebra with the new nexthop after a
+ BGP UPDATE updates an existing route, but then is found to be invalid,
+ and zebra not finding the route as it requires a match on all attributes.
+
+* bgp_zebra.c: (bgp_zebra_withdraw) When deleting a prefix, we want it gone.
+ Do not send additional matching attributes like the nexthop, which can
+ only cause incorrect non-matches.
+Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
+---
+ bgpd/bgp_zebra.c | 46 +++++-----------------------------------------
+ 1 file changed, 5 insertions(+), 41 deletions(-)
+
+diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
+index e534bee..186657b 100644
+--- a/bgpd/bgp_zebra.c
++++ b/bgpd/bgp_zebra.c
+@@ -863,18 +863,14 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
+ if (p->family == AF_INET)
+ {
+ struct zapi_ipv4 api;
+- struct in_addr *nexthop;
+
+ api.vrf_id = VRF_DEFAULT;
+ api.flags = flags;
+- nexthop = &info->attr->nexthop;
+
+ api.type = ZEBRA_ROUTE_BGP;
+ api.message = 0;
+ api.safi = safi;
+- SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+- api.nexthop_num = 1;
+- api.nexthop = &nexthop;
++ api.nexthop_num = 0;
+ api.ifindex_num = 0;
+ SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
+ api.metric = info->attr->med;
+@@ -882,10 +878,9 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
+ if (BGP_DEBUG(zebra, ZEBRA))
+ {
+ char buf[2][INET_ADDRSTRLEN];
+- zlog_debug("Zebra send: IPv4 route delete %s/%d nexthop %s metric %u",
++ zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u",
+ inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
+ p->prefixlen,
+- inet_ntop(AF_INET, nexthop, buf[1], sizeof(buf[1])),
+ api.metric);
+ }
+
+@@ -897,54 +892,23 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
+ if (p->family == AF_INET6)
+ {
+ struct zapi_ipv6 api;
+- unsigned int ifindex;
+- struct in6_addr *nexthop;
+-
+- assert (info->attr->extra);
+
+- ifindex = 0;
+- nexthop = NULL;
+-
+- /* Only global address nexthop exists. */
+- if (info->attr->extra->mp_nexthop_len == 16)
+- nexthop = &info->attr->extra->mp_nexthop_global;
+-
+- /* If both global and link-local address present. */
+- if (info->attr->extra->mp_nexthop_len == 32)
+- {
+- nexthop = &info->attr->extra->mp_nexthop_local;
+- if (info->peer->nexthop.ifp)
+- ifindex = info->peer->nexthop.ifp->ifindex;
+- }
+-
+- if (nexthop == NULL)
+- return;
+-
+- if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex)
+- if (info->peer->ifname)
+- ifindex = ifname2ifindex (info->peer->ifname);
+-
+ api.vrf_id = VRF_DEFAULT;
+ api.flags = flags;
+ api.type = ZEBRA_ROUTE_BGP;
+ api.message = 0;
+ api.safi = safi;
+- SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+- api.nexthop_num = 1;
+- api.nexthop = &nexthop;
+- SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
+- api.ifindex_num = 1;
+- api.ifindex = &ifindex;
++ api.nexthop_num = 0;
++ api.ifindex_num = 0;
+ SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
+ api.metric = info->attr->med;
+
+ if (BGP_DEBUG(zebra, ZEBRA))
+ {
+ char buf[2][INET6_ADDRSTRLEN];
+- zlog_debug("Zebra send: IPv6 route delete %s/%d nexthop %s metric %u",
++ zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u",
+ inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
+ p->prefixlen,
+- inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])),
+ api.metric);
+ }
+
+--
+2.7.0
+
--- /dev/null
+--- a/bgpd/bgp_network.c
++++ b/bgpd/bgp_network.c
+@@ -256,8 +256,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
+@@ -739,6 +739,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
--- /dev/null
+--- a/lib/command.c
++++ b/lib/command.c
+@@ -3064,6 +3064,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,
+@@ -3077,7 +3084,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);
--- /dev/null
+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"
+@@ -353,6 +354,12 @@ bgp_info_cmp (struct bgp *bgp, struct bg
+ 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;
++
+ newattr = new->attr;
+ existattr = exist->attr;
+ newattre = newattr->extra;
+@@ -1602,6 +1609,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))
+@@ -1925,6 +1936,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. */
+@@ -2356,6 +2372,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);
+
+@@ -5626,6 +5647,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");
+@@ -6135,6 +6170,8 @@ route_vty_out_detail (struct vty *vty, s
+ #define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, "\
+ "h history, * valid, > best, = multipath,%s"\
+ " i internal, 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"
+@@ -6166,7 +6203,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
+@@ -6333,11 +6371,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)
+@@ -6415,6 +6459,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,
+@@ -11987,6 +12032,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>",
+@@ -12036,6 +12139,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",
+@@ -12562,6 +12678,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);
+@@ -12695,6 +12812,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);
+@@ -13085,6 +13203,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
+@@ -63,6 +63,8 @@ struct bgp_node
+
+ struct bgp_node *prn;
+
++ struct bgp_pgbgp_hist *hist;
++
+ u_char flags;
+ #define BGP_NODE_PROCESS_SCHEDULED (1 << 0)
+ };
+--- a/bgpd/bgpd.h
++++ b/bgpd/bgpd.h
+@@ -125,6 +125,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
+@@ -225,6 +225,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
+@@ -70,7 +70,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
+@@ -149,6 +149,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" },
+ { MTYPE_BGP_ADDR, "BGP own address" },
--- /dev/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
+@@ -5647,20 +5647,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");
+@@ -5676,6 +5662,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))
+@@ -6156,7 +6153,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));
+@@ -6169,9 +6181,8 @@ route_vty_out_detail (struct vty *vty, s
+
+ #define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, "\
+ "h history, * valid, > best, = multipath,%s"\
+- " i internal, 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"
++ " i internal, 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"
+@@ -6380,8 +6391,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)
+@@ -9913,7 +9923,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",
+@@ -9930,7 +9940,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;
+ }
+@@ -9954,7 +9964,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;
+ }
--- /dev/null
+--- a/bgpd/bgp_pgbgp.c
++++ b/bgpd/bgp_pgbgp.c
+@@ -694,7 +694,7 @@ findSuper (struct bgp_table *table, stru
+ struct bgp_node *matched;
+
+ matched = NULL;
+- node = table->top;
++ node = bgp_table_top_nolock (table);
+
+ while (node && node->p.prefixlen < p->prefixlen &&
+ prefix_match (&node->p, p))
+@@ -874,7 +874,8 @@ bgp_pgbgp_clean (struct bgp_table *table
+ if (changed && rn->info)
+ {
+ struct bgp_info *ri = rn->info;
+- bgp_process (ri->peer->bgp, rn, rn->table->afi, rn->table->safi);
++ bgp_process (ri->peer->bgp, rn, bgp_node_table (rn)->afi,
++ bgp_node_table (rn)->safi);
+ }
+ }
+
+@@ -1166,7 +1167,8 @@ bgp_pgbgp_rib_updated (struct bgp_node *
+ 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);
++ bgp_node_table (cur->sub)->afi,
++ bgp_node_table (cur->sub)->safi);
+
+ }
+
+@@ -1200,7 +1202,8 @@ bgp_pgbgp_rib_updated (struct bgp_node *
+ 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);
++ bgp_node_table (cur->sub)->afi,
++ bgp_node_table (cur->sub)->safi);
+ }
+ }
+ }
+@@ -1270,7 +1273,7 @@ bgp_pgbgp_update (struct bgp_info *binfo
+ struct bgp_node *superhn = NULL;
+
+ // implicit lock from node_get
+- superhn = findSuper (rn->table, &rn->p, t_now);
++ superhn = findSuper (bgp_node_table (rn), &rn->p, t_now);
+
+ int newPeer = bgp_pgbgp_updatePeer (binfo, t_now);
+ bgp_pgbgp_updateOrigin (rn->hist, binfo, at, rn, t_now, newPeer);
+@@ -1287,13 +1290,13 @@ bgp_pgbgp_update (struct bgp_info *binfo
+ // 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);
++ bgp_pgbgp_gc (bgp_node_table (rn));
+ pgbgp->lastgc = t_now;
+ }
+
+ if (t_now >= pgbgp->lastStore + PGBGP_STORE_DELTA)
+ {
+- bgp_pgbgp_store (rn->table);
++ bgp_pgbgp_store (bgp_node_table (rn));
+ pgbgp->lastStore = t_now;
+ }
+
+@@ -1682,8 +1685,8 @@ bgp_pgbgp_reuseOrigin (struct bgp_pgbgp_
+
+ // Rerun the decision process?
+ if (numChanged > 0)
+- bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi,
+- data.rn->table->safi);
++ bgp_process (ri->peer->bgp, data.rn, bgp_node_table (data.rn)->afi,
++ bgp_node_table (data.rn)->safi);
+
+
+ /*
+@@ -1962,8 +1965,8 @@ UPP_IGNORE:
+ if (changed)
+ {
+ struct bgp_info *ri = supernode->info;
+- bgp_process (ri->peer->bgp, supernode, supernode->table->afi,
+- supernode->table->safi);
++ bgp_process (ri->peer->bgp, supernode, bgp_node_table (supernode)->afi,
++ bgp_node_table (supernode)->safi);
+ }
+
+ UPP_DONE:
+@@ -1986,8 +1989,8 @@ bgp_pgbgp_reusePrefix (struct bgp_pgbgp_
+
+ // Rerun the decision process
+ if (ri != NULL)
+- bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi,
+- data.rn->table->safi);
++ bgp_process (ri->peer->bgp, data.rn, bgp_node_table (data.rn)->afi,
++ bgp_node_table (data.rn)->safi);
+
+
+ // Remove the avoid nodes from the super
+@@ -2021,8 +2024,8 @@ bgp_pgbgp_reusePrefix (struct bgp_pgbgp_
+
+ if (numChanged > 0 && ri != NULL)
+ bgp_process (ri->peer->bgp, data.rnsuper,
+- data.rnsuper->table->afi,
+- data.rnsuper->table->safi);
++ bgp_node_table (data.rnsuper)->afi,
++ bgp_node_table (data.rnsuper)->safi);
+ bgp_unlock_node (del->sub);
+ XFREE (MTYPE_BGP_PGBGP_AVOID, del);
+ }
+@@ -2419,8 +2422,8 @@ bgp_pgbgp_reuseEdge (struct bgp_pgbgp_r_
+ }
+ 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);
++ bgp_process (ri->peer->bgp, data.rn, bgp_node_table (data.rn)->afi,
++ bgp_node_table (data.rn)->safi);
+
+ struct bgp_pgbgp_hist *hist = data.rn->hist;
+ hist->pEdgeReuse = NULL;
--- /dev/null
+--- a/bgpd/bgp_pgbgp.c
++++ b/bgpd/bgp_pgbgp.c
+@@ -694,7 +694,7 @@ findSuper (struct bgp_table *table, stru
+ struct bgp_node *matched;
+
+ matched = NULL;
+- node = table->top;
++ node = bgp_table_top_nolock (table);
+
+ while (node && node->p.prefixlen < p->prefixlen &&
+ prefix_match (&node->p, p))
+@@ -874,7 +874,7 @@ bgp_pgbgp_clean (struct bgp_table *table
+ if (changed && rn->info)
+ {
+ struct bgp_info *ri = rn->info;
+- bgp_process (ri->peer->bgp, rn, rn->table->afi, rn->table->safi);
++ bgp_process (ri->peer->bgp, rn, table->afi, table->safi);
+ }
+ }
+
+@@ -1166,7 +1166,8 @@ bgp_pgbgp_rib_updated (struct bgp_node *
+ 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);
++ bgp_node_table (cur->sub)->afi,
++ bgp_node_table (cur->sub)->safi);
+
+ }
+
+@@ -1200,7 +1201,8 @@ bgp_pgbgp_rib_updated (struct bgp_node *
+ 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);
++ bgp_node_table (cur->sub)->afi,
++ bgp_node_table (cur->sub)->safi);
+ }
+ }
+ }
+@@ -1270,7 +1272,7 @@ bgp_pgbgp_update (struct bgp_info *binfo
+ struct bgp_node *superhn = NULL;
+
+ // implicit lock from node_get
+- superhn = findSuper (rn->table, &rn->p, t_now);
++ superhn = findSuper (bgp_node_table (rn), &rn->p, t_now);
+
+ int newPeer = bgp_pgbgp_updatePeer (binfo, t_now);
+ bgp_pgbgp_updateOrigin (rn->hist, binfo, at, rn, t_now, newPeer);
+@@ -1287,13 +1289,13 @@ bgp_pgbgp_update (struct bgp_info *binfo
+ // 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);
++ bgp_pgbgp_gc (bgp_node_table (rn));
+ pgbgp->lastgc = t_now;
+ }
+
+ if (t_now >= pgbgp->lastStore + PGBGP_STORE_DELTA)
+ {
+- bgp_pgbgp_store (rn->table);
++ bgp_pgbgp_store (bgp_node_table (rn));
+ pgbgp->lastStore = t_now;
+ }
+
+@@ -1682,8 +1684,8 @@ bgp_pgbgp_reuseOrigin (struct bgp_pgbgp_
+
+ // Rerun the decision process?
+ if (numChanged > 0)
+- bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi,
+- data.rn->table->safi);
++ bgp_process (ri->peer->bgp, data.rn, bgp_node_table (data.rn)->afi,
++ bgp_node_table (data.rn)->safi);
+
+
+ /*
+@@ -1962,8 +1964,8 @@ UPP_IGNORE:
+ if (changed)
+ {
+ struct bgp_info *ri = supernode->info;
+- bgp_process (ri->peer->bgp, supernode, supernode->table->afi,
+- supernode->table->safi);
++ bgp_process (ri->peer->bgp, supernode, bgp_node_table (supernode)->afi,
++ bgp_node_table (supernode)->safi);
+ }
+
+ UPP_DONE:
+@@ -1986,8 +1988,8 @@ bgp_pgbgp_reusePrefix (struct bgp_pgbgp_
+
+ // Rerun the decision process
+ if (ri != NULL)
+- bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi,
+- data.rn->table->safi);
++ bgp_process (ri->peer->bgp, data.rn, bgp_node_table (data.rn)->afi,
++ bgp_node_table (data.rn)->safi);
+
+
+ // Remove the avoid nodes from the super
+@@ -2021,8 +2023,8 @@ bgp_pgbgp_reusePrefix (struct bgp_pgbgp_
+
+ if (numChanged > 0 && ri != NULL)
+ bgp_process (ri->peer->bgp, data.rnsuper,
+- data.rnsuper->table->afi,
+- data.rnsuper->table->safi);
++ bgp_node_table (data.rnsuper)->afi,
++ bgp_node_table (data.rnsuper)->safi);
+ bgp_unlock_node (del->sub);
+ XFREE (MTYPE_BGP_PGBGP_AVOID, del);
+ }
+@@ -2419,8 +2421,8 @@ bgp_pgbgp_reuseEdge (struct bgp_pgbgp_r_
+ }
+ 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);
++ bgp_process (ri->peer->bgp, data.rn, bgp_node_table (data.rn)->afi,
++ bgp_node_table (data.rn)->safi);
+
+ struct bgp_pgbgp_hist *hist = data.rn->hist;
+ hist->pEdgeReuse = NULL;
--- /dev/null
+--- a/vtysh/vtysh.c
++++ b/vtysh/vtysh.c
+@@ -268,7 +268,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);
+ }
+
--- /dev/null
+--- a/bgpd/bgp_network.c
++++ b/bgpd/bgp_network.c
+@@ -256,8 +256,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
+@@ -739,6 +739,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
--- /dev/null
+--- a/lib/command.c
++++ b/lib/command.c
+@@ -3064,6 +3064,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,
+@@ -3077,7 +3084,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);
--- /dev/null
+--- a/vtysh/vtysh.c
++++ b/vtysh/vtysh.c
+@@ -268,7 +268,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);
+ }
+
--- /dev/null
+--- a/bgpd/bgp_packet.c
++++ b/bgpd/bgp_packet.c
+@@ -1631,7 +1631,7 @@ bgp_update_receive (struct peer *peer, b
+ NLRI_TYPE_MAX,
+ };
+ struct bgp_nlri nlris[NLRI_TYPE_MAX];
+-
++
+ /* Status must be Established. */
+ if (peer->status != Established)
+ {
+@@ -1645,6 +1645,7 @@ bgp_update_receive (struct peer *peer, b
+ memset (&attr, 0, sizeof (struct attr));
+ memset (&extra, 0, sizeof (struct attr_extra));
+ memset (&nlris, 0, sizeof nlris);
++
+ attr.extra = &extra;
+
+ s = peer->ibuf;
+@@ -1781,6 +1782,8 @@ bgp_update_receive (struct peer *peer, b
+ /* Parse any given NLRIs */
+ for (i = NLRI_UPDATE; i < NLRI_TYPE_MAX; i++)
+ {
++ if (!nlris[i].nlri) continue;
++
+ /* We use afi and safi as indices into tables and what not. It would
+ * be impossible, at this time, to support unknown afi/safis. And
+ * anyway, the peer needs to be configured to enable the afi/safi
--- /dev/null
+From f99d2f1c5cfdb21be1fa28dabc5fc48a7cd71ed8 Mon Sep 17 00:00:00 2001
+From: Balaji <balajig81@gmail.com>
+Date: Wed, 20 Jan 2016 17:29:27 +0000
+Subject: bgpd: Addition of bgp dampening configuration commands under IPv4/multicast
+
+Signed-off-by: Balaji Gurudoss <balajig81@gmail.com>
+Tested-by: NetDEF CI System <cisystem@netdef.org>
+---
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -16264,6 +16264,14 @@ bgp_route_init (void)
+ install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd);
+ install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd);
+ install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd);
++
++ /* IPv4 Multicast Mode */
++ install_element (BGP_IPV4M_NODE, &bgp_damp_set_cmd);
++ install_element (BGP_IPV4M_NODE, &bgp_damp_set2_cmd);
++ install_element (BGP_IPV4M_NODE, &bgp_damp_set3_cmd);
++ install_element (BGP_IPV4M_NODE, &bgp_damp_unset_cmd);
++ install_element (BGP_IPV4M_NODE, &bgp_damp_unset2_cmd);
++
+
+ /* Deprecated AS-Pathlimit commands */
+ install_element (BGP_NODE, &bgp_network_ttl_cmd);
--- /dev/null
+From 5cfa8d706450a65660ba589581790da8bd0e4adc Mon Sep 17 00:00:00 2001
+From: Balaji <balajig81@gmail.com>
+Date: Wed, 20 Jan 2016 17:29:26 +0000
+Subject: bgpd: Addition of dampening show commands under v4 unicast/multicast tree
+
+Patch contains addition of show ip bgp ipv4 (unicast| multicast)
+dampening tree.
+
+Signed-off-by: Balaji Gurudoss <balajig81@gmail.com>
+---
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -8603,6 +8603,66 @@ DEFUN (show_bgp_ipv6_filter_list,
+ bgp_show_type_filter_list);
+ }
+
++
++DEFUN (show_ip_bgp_ipv4_dampening_parameters,
++ show_ip_bgp_ipv4_dampening_parameters_cmd,
++ "show ip bgp ipv4 (unicast|multicast) dampening parameters",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Address family\n"
++ "Address Family modifier\n"
++ "Address Family modifier\n"
++ "Display detailed information about dampening\n"
++ "Display detail of configured dampening parameters\n")
++{
++ if (strncmp(argv[0], "m", 1) == 0)
++ return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_MULTICAST);
++
++ return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST);
++}
++
++
++DEFUN (show_ip_bgp_ipv4_dampening_flap_stats,
++ show_ip_bgp_ipv4_dampening_flap_stats_cmd,
++ "show ip bgp ipv4 (unicast|multicast) dampening flap-statistics",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Address family\n"
++ "Address Family modifier\n"
++ "Address Family modifier\n"
++ "Display detailed information about dampening\n"
++ "Display flap statistics of routes\n")
++{
++ if (strncmp(argv[0], "m", 1) == 0)
++ return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST,
++ bgp_show_type_flap_statistics, NULL);
++
++ return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST,
++ bgp_show_type_flap_statistics, NULL);
++}
++
++DEFUN (show_ip_bgp_ipv4_dampening_dampd_paths,
++ show_ip_bgp_ipv4_dampening_dampd_paths_cmd,
++ "show ip bgp ipv4 (unicast|multicast) dampening dampened-paths",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Address family\n"
++ "Address Family modifier\n"
++ "Address Family modifier\n"
++ "Display detailed information about dampening\n"
++ "Display paths suppressed due to dampening\n")
++{
++ if (strncmp(argv[0], "m", 1) == 0)
++ return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST,
++ bgp_show_type_dampend_paths, NULL);
++
++ return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST,
++ bgp_show_type_dampend_paths, NULL);
++}
++
+ static int
+ bgp_show_route_map (struct vty *vty, const char *rmap_str, afi_t afi,
+ safi_t safi, enum bgp_show_type type)
+@@ -16376,7 +16436,10 @@ 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_dampening_params_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_parameters_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_dampd_paths_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_flap_stats_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_damp_dampened_paths_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_damp_flap_statistics_cmd);
+@@ -16490,6 +16553,9 @@ bgp_route_init (void)
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_dampening_params_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_dampening_parameters_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_dampening_dampd_paths_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_dampening_flap_stats_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_damp_dampened_paths_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_damp_flap_statistics_cmd);
--- /dev/null
+From fc1c1cc5e2800431e1ca59c938b1329c2365ad60 Mon Sep 17 00:00:00 2001
+From: Colin Petrie <cpetrie@ripe.net>
+Date: Wed, 11 May 2016 09:56:58 +0000
+Subject: bgpd: fix MRT table dumps for locally-originated routes
+
+I've been working on a small patch to correct an issue in the BGP MRT
+table dump code. It's a quick'n'easy fix initially, and I'd appreciate
+any feedback on making it better :)
+
+Issue:
+
+When the BGP table dump code runs, it generates the peer_index_table.
+This walks the list of peers, and dumps out their IP, ASN, address
+family, etc. It also sets the peer index number in the peer struct.
+
+Then the code walks the RIB, and for each prefix, writes out RIB
+entries, that refer to the peer index number.
+
+However, when it finds prefixes that are locally originated, the
+associated peer is the 'self' peer, which wasn't in the list of peers,
+never gets an index number assigned, but because it is calloc'd, the
+index number is set to 0.
+
+End result: locally-originated routes are associated with whichever peer
+happens to be first in the list of remote peers in the index table :)
+
+Example (from one of our route collectors) - these are two of our
+originated prefixes (bgpdump output):
+TABLE_DUMP2|1457568002|B|12.0.1.63|7018|84.205.80.0/24||IGP|193.0.4.28|0|0||NAG|64512
+10.255.255.255|
+TABLE_DUMP2|1457568006|B|12.0.1.63|7018|2001:7fb:ff00::/48||IGP|::|0|0||NAG||
+
+The prefixes are announced by us (note it has an empty AS PATH (the
+field after the prefix)) but also looks like it was received from AS7018
+(12.0.1.63). In fact, the AS7018 peer just happens to be the first peer
+in the index table.
+
+Fix:
+
+The simplest fix (which is also the method adopted by both OpenBGPd and
+the BIRD mrtdump branch) is to create an empty placeholder 'peer' at the
+start of the peer index table, for all the routes which are locally
+originated to refer to.
+
+I've attached a patch for this.
+Here's a resulting bgpdump output after the patch:
+TABLE_DUMP2|1458828539|B|0.0.0.0|0|93.175.150.0/24||IGP|0.0.0.0|0|0||NAG||
+Now it is more obvious that the prefix is locally originated.
+
+There are more complicated potential ways of fixing it
+1) skip the local routes when dumping the RIB. This leads to questions
+about what an MRT table dump *should* contain :)
+2) include the 'self' peer in the list of peers used to generate the
+index table.
+etc etc.
+
+But I'm quite happy with my 'create a fake peer, and associate local
+routes with it' method :)
+
+Your thoughts and feedback are welcome!
+
+Regards,
+
+Colin Petrie
+Systems Engineer
+RIPE NCC RIS Project
+Tested-by: NetDEF CI System <cisystem@netdef.org>
+---
+--- a/bgpd/bgp_dump.c
++++ b/bgpd/bgp_dump.c
+@@ -226,7 +226,7 @@ bgp_dump_routes_index_table(struct bgp *
+ {
+ struct peer *peer;
+ struct listnode *node;
+- uint16_t peerno = 0;
++ uint16_t peerno = 1;
+ struct stream *obuf;
+
+ obuf = bgp_dump_obuf;
+@@ -250,8 +250,18 @@ bgp_dump_routes_index_table(struct bgp *
+ stream_putw(obuf, 0);
+ }
+
+- /* Peer count */
+- stream_putw (obuf, listcount(bgp->peer));
++ /* Peer count ( plus one extra internal peer ) */
++ stream_putw (obuf, listcount(bgp->peer) + 1);
++
++ /* Populate fake peer at index 0, for locally originated routes */
++ /* Peer type (IPv4) */
++ stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
++ /* Peer BGP ID (0.0.0.0) */
++ stream_putl (obuf, 0);
++ /* Peer IP address (0.0.0.0) */
++ stream_putl (obuf, 0);
++ /* Peer ASN (0) */
++ stream_putl (obuf, 0);
+
+ /* Walk down all peers */
+ for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
--- /dev/null
+From 3e1d78b2b6b0bffc255b97d40163681fb13a467a Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@cumulusnetworks.com>
+Date: Fri, 11 Mar 2016 01:16:47 +0000
+Subject: bgpd: Fix code path that leads to uninitialized variables
+
+subtype and sublength are not initialized and if on Line 1877
+BGP_ATTR_ENCAP != type we will not set subtype and sublength,
+but these variables are used immediately below that if statement.
+
+This issue was discovered via the freebsd compiler.
+
+Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
+---
+--- a/bgpd/bgp_attr.c
++++ b/bgpd/bgp_attr.c
+@@ -1870,8 +1870,8 @@ bgp_attr_encap(
+ }
+
+ while (length >= 4) {
+- uint16_t subtype;
+- uint16_t sublength;
++ uint16_t subtype = 0;
++ uint16_t sublength = 0;
+ struct bgp_attr_encap_subtlv *tlv;
+
+ if (BGP_ATTR_ENCAP == type) {
--- /dev/null
+From d1854f883508bb8d3637a85dbbb05e0c704552da Mon Sep 17 00:00:00 2001
+From: Donald Sharp <sharpd@cumulusnetworks.com>
+Date: Tue, 26 Jan 2016 04:38:53 +0000
+Subject: bgpd: Fix 'show bgp ipv4 vpnv4 statistics' cli.
+
+When attempting to use the 'show bgp ipv4 vpnv4 statistics' cli, the safi
+choosen is BGP_MPLS_LABELED_VPN which is #defined to 128. The afi/safi
+combination is fed to bgp->rib, which limits the size of the safi to BGP_SAFI_MAX
+which is #defined to 5. The correct value to use is BGP_MPLS_VPN
+
+The bgp code differentiates between the actual safi value for BGP_MPLS_LABELED_VPN
+used defined by RFC 4364, to a internal SAFI value used to limit array size.
+
+Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
+Tested-by: NetDEF CI System <cisystem@netdef.org>
+---
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -11794,7 +11794,8 @@ bgp_table_stats (struct vty *vty, struct
+
+ if (!bgp->rib[afi][safi])
+ {
+- vty_out (vty, "%% No RIB exists for the AFI/SAFI%s", VTY_NEWLINE);
++ vty_out (vty, "%% No RIB exists for the specified AFI(%d)/SAFI(%d) %s",
++ afi, safi, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+@@ -11908,7 +11909,7 @@ bgp_table_stats_vty (struct vty *vty, co
+ safi = SAFI_UNICAST;
+ break;
+ case 'v':
+- safi = SAFI_MPLS_LABELED_VPN;
++ safi = SAFI_MPLS_VPN;
+ break;
+ case 'e':
+ safi = SAFI_ENCAP;