diff --git a/Makefile b/Makefile index 4256ca1..fac45c2 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2006-2012 OpenWrt.org +# Copyright (C) 2006-2013 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -8,9 +8,9 @@ include $(TOPDIR)/rules.mk PKG_NAME:=quagga -PKG_VERSION:=0.99.21 +PKG_VERSION:=0.99.22 PKG_RELEASE:=6 -PKG_MD5SUM:=99840adbe57047c90dfba6b6ed9aec7f +PKG_MD5SUM:=3057bf3a91116a1017dd0df7e5e8ef93 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=http://download.savannah.gnu.org/releases/quagga/ diff --git a/patches/001-bgpd-fix-args-consolidation.patch b/patches/001-bgpd-fix-args-consolidation.patch deleted file mode 100644 index 30de1b5..0000000 --- a/patches/001-bgpd-fix-args-consolidation.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/bgpd/bgp_attr.c -+++ b/bgpd/bgp_attr.c -@@ -1646,7 +1646,7 @@ bgp_attr_ext_communities (struct bgp_att - static bgp_attr_parse_ret_t - bgp_attr_unknown (struct bgp_attr_parser_args *args) - { -- bgp_size_t total; -+ bgp_size_t total = args->total; - struct transit *transit; - struct attr_extra *attre; - struct peer *const peer = args->peer; diff --git a/patches/002-fix-metric-output.patch b/patches/002-fix-metric-output.patch deleted file mode 100644 index a92fc19..0000000 --- a/patches/002-fix-metric-output.patch +++ /dev/null @@ -1,58 +0,0 @@ ---- a/bgpd/bgp_debug.c -+++ b/bgpd/bgp_debug.c -@@ -194,11 +194,11 @@ bgp_dump_attr (struct peer *peer, struct - #endif /* HAVE_IPV6 */ - - if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) -- snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %d", -+ snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %u", - attr->local_pref); - - if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) -- snprintf (buf + strlen (buf), size - strlen (buf), ", metric %d", -+ snprintf (buf + strlen (buf), size - strlen (buf), ", metric %u", - attr->med); - - if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))) ---- a/bgpd/bgp_route.c -+++ b/bgpd/bgp_route.c -@@ -5954,7 +5954,7 @@ route_vty_out_detail (struct vty *vty, s - if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) - vty_out (vty, " (inaccessible)"); - else if (binfo->extra && binfo->extra->igpmetric) -- vty_out (vty, " (metric %d)", binfo->extra->igpmetric); -+ vty_out (vty, " (metric %u)", binfo->extra->igpmetric); - vty_out (vty, " from %s", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN)); - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) - vty_out (vty, " (%s)", inet_ntoa (attr->extra->originator_id)); ---- a/bgpd/bgp_vty.c -+++ b/bgpd/bgp_vty.c -@@ -8966,7 +8966,7 @@ bgp_config_write_redistribute (struct vt - vty_out (vty, " redistribute %s", zebra_route_string(i)); - - if (bgp->redist_metric_flag[afi][i]) -- vty_out (vty, " metric %d", bgp->redist_metric[afi][i]); -+ vty_out (vty, " metric %u", bgp->redist_metric[afi][i]); - - if (bgp->rmap[afi][i].name) - vty_out (vty, " route-map %s", bgp->rmap[afi][i].name); ---- a/zebra/zebra_vty.c -+++ b/zebra/zebra_vty.c -@@ -541,7 +541,7 @@ vty_show_ip_route_detail (struct vty *vt - inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, - VTY_NEWLINE); - vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); -- vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric); -+ vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) - vty_out (vty, ", best"); - if (rib->refcnt) -@@ -1519,7 +1519,7 @@ vty_show_ipv6_route_detail (struct vty * - rn->p.prefixlen, - VTY_NEWLINE); - vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); -- vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric); -+ vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) - vty_out (vty, ", best"); - if (rib->refcnt) diff --git a/patches/003-bgpd-fix-route-map-match-peer-local.patch b/patches/003-bgpd-fix-route-map-match-peer-local.patch deleted file mode 100644 index 597ab73..0000000 --- a/patches/003-bgpd-fix-route-map-match-peer-local.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/bgpd/bgp_routemap.c -+++ b/bgpd/bgp_routemap.c -@@ -172,7 +172,7 @@ route_match_peer_compile (const char *ar - - su = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union sockunion)); - -- ret = str2sockunion ( (arg)? arg : "0.0.0.0", su); -+ ret = str2sockunion (strcmp(arg, "local") ? arg : "0.0.0.0", su); - if (ret < 0) { - XFREE (MTYPE_ROUTE_MAP_COMPILED, su); - return NULL; -@@ -2430,7 +2430,7 @@ DEFUN (match_peer_local, - "Match peer address\n" - "Static or Redistributed routes\n") - { -- return bgp_route_match_add (vty, vty->index, "peer", NULL); -+ return bgp_route_match_add (vty, vty->index, "peer", "local"); - } - - DEFUN (no_match_peer, diff --git a/patches/004-fix-sockunion-memleaks.patch b/patches/004-fix-sockunion-memleaks.patch deleted file mode 100644 index 92f0dfc..0000000 --- a/patches/004-fix-sockunion-memleaks.patch +++ /dev/null @@ -1,539 +0,0 @@ ---- a/bgpd/bgp_routemap.c -+++ b/bgpd/bgp_routemap.c -@@ -111,7 +111,8 @@ route_match_peer (void *rule, struct pre - void *object) - { - union sockunion *su; -- union sockunion *su2; -+ union sockunion su_def = { .sa.sa_family = AF_INET, -+ .sin.sin_addr.s_addr = INADDR_ANY }; - struct peer_group *group; - struct peer *peer; - struct listnode *node, *nnode; -@@ -127,8 +128,7 @@ route_match_peer (void *rule, struct pre - - /* If su='0.0.0.0' (command 'match peer local'), and it's a NETWORK, - REDISTRIBUTE or DEFAULT_GENERATED route => return RMAP_MATCH */ -- su2 = sockunion_str2su ("0.0.0.0"); -- if ( sockunion_same (su, su2) ) -+ if (sockunion_same (su, &su_def)) - { - int ret; - if ( CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_NETWORK) || -@@ -137,12 +137,9 @@ route_match_peer (void *rule, struct pre - ret = RMAP_MATCH; - else - ret = RMAP_NOMATCH; -- -- sockunion_free (su2); - return ret; - } -- sockunion_free (su2); -- -+ - if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) - { - if (sockunion_same (su, &peer->su)) -@@ -878,7 +875,6 @@ route_set_ip_nexthop (void *rule, struct - route_map_object_t type, void *object) - { - struct rmap_ip_nexthop_set *rins = rule; -- struct in_addr peer_address; - struct bgp_info *bgp_info; - struct peer *peer; - -@@ -894,16 +890,14 @@ route_set_ip_nexthop (void *rule, struct - && peer->su_remote - && sockunion_family (peer->su_remote) == AF_INET) - { -- inet_aton (sockunion_su2str (peer->su_remote), &peer_address); -- bgp_info->attr->nexthop = peer_address; -+ bgp_info->attr->nexthop.s_addr = sockunion2ip (peer->su_remote); - bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); - } - else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT) - && peer->su_local - && sockunion_family (peer->su_local) == AF_INET) - { -- inet_aton (sockunion_su2str (peer->su_local), &peer_address); -- bgp_info->attr->nexthop = peer_address; -+ bgp_info->attr->nexthop.s_addr = sockunion2ip (peer->su_local); - bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); - } - } ---- a/lib/sockunion.h -+++ b/lib/sockunion.h -@@ -78,23 +78,17 @@ enum connect_result - #define SET_IN6_LINKLOCAL_IFINDEX(a, i) - #endif /* KAME */ - --/* shortcut macro to specify address field of struct sockaddr */ --#define sock2ip(X) (((struct sockaddr_in *)(X))->sin_addr.s_addr) --#ifdef HAVE_IPV6 --#define sock2ip6(X) (((struct sockaddr_in6 *)(X))->sin6_addr.s6_addr) --#endif /* HAVE_IPV6 */ -- - #define sockunion_family(X) (X)->sa.sa_family - -+#define sockunion2ip(X) (X)->sin.sin_addr.s_addr -+ - /* Prototypes. */ - extern int str2sockunion (const char *, union sockunion *); - extern const char *sockunion2str (union sockunion *, char *, size_t); - extern int sockunion_cmp (union sockunion *, union sockunion *); - extern int sockunion_same (union sockunion *, union sockunion *); - --extern char *sockunion_su2str (union sockunion *su); - extern union sockunion *sockunion_str2su (const char *str); --extern struct in_addr sockunion_get_in_addr (union sockunion *su); - extern int sockunion_accept (int sock, union sockunion *); - extern int sockunion_stream_socket (union sockunion *); - extern int sockopt_reuseaddr (int); ---- a/bgpd/bgp_fsm.c -+++ b/bgpd/bgp_fsm.c -@@ -597,8 +597,6 @@ bgp_stop_with_error (struct peer *peer) - static int - bgp_connect_success (struct peer *peer) - { -- char buf1[BUFSIZ]; -- - if (peer->fd < 0) - { - zlog_err ("bgp_connect_success peer's fd is negative value %d", -@@ -612,6 +610,8 @@ bgp_connect_success (struct peer *peer) - - if (BGP_DEBUG (normal, NORMAL)) - { -+ char buf1[SU_ADDRSTRLEN]; -+ - if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) - zlog_debug ("%s open active, local address %s", peer->host, - sockunion2str (peer->su_local, buf1, SU_ADDRSTRLEN)); ---- a/bgpd/bgp_mplsvpn.c -+++ b/bgpd/bgp_mplsvpn.c -@@ -581,24 +581,25 @@ DEFUN (show_ip_bgp_vpnv4_all_neighbor_ro - "Neighbor to display information about\n" - "Display routes learned from neighbor\n") - { -- union sockunion *su; -+ union sockunion su; - struct peer *peer; -- -- su = sockunion_str2su (argv[0]); -- if (su == NULL) -+ int ret; -+ -+ ret = str2sockunion (argv[0], &su); -+ if (ret < 0) - { - vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); -- return CMD_WARNING; -+ return CMD_WARNING; - } - -- peer = peer_lookup (NULL, su); -+ peer = peer_lookup (NULL, &su); - if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) - { - vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); - return CMD_WARNING; - } - -- return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_neighbor, su, 0); -+ return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_neighbor, &su, 0); - } - - DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes, -@@ -615,7 +616,7 @@ DEFUN (show_ip_bgp_vpnv4_rd_neighbor_rou - "Display routes learned from neighbor\n") - { - int ret; -- union sockunion *su; -+ union sockunion su; - struct peer *peer; - struct prefix_rd prd; - -@@ -626,21 +627,21 @@ DEFUN (show_ip_bgp_vpnv4_rd_neighbor_rou - return CMD_WARNING; - } - -- su = sockunion_str2su (argv[1]); -- if (su == NULL) -+ ret = str2sockunion (argv[1], &su); -+ if (ret < 0) - { - vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); -- return CMD_WARNING; -+ return CMD_WARNING; - } - -- peer = peer_lookup (NULL, su); -+ peer = peer_lookup (NULL, &su); - if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) - { - vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); - return CMD_WARNING; - } - -- return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, su, 0); -+ return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, &su, 0); - } - - DEFUN (show_ip_bgp_vpnv4_all_neighbor_advertised_routes, ---- a/bgpd/bgp_network.c -+++ b/bgpd/bgp_network.c -@@ -185,7 +185,7 @@ bgp_accept (struct thread *thread) - zlog_debug ("[Event] Make dummy peer structure until read Open packet"); - - { -- char buf[SU_ADDRSTRLEN + 1]; -+ char buf[SU_ADDRSTRLEN]; - - peer = peer_create_accept (peer1->bgp); - SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); ---- a/bgpd/bgp_route.c -+++ b/bgpd/bgp_route.c -@@ -10202,15 +10202,18 @@ DEFUN (show_ip_bgp_neighbor_received_pre - "Display the prefixlist filter\n") - { - char name[BUFSIZ]; -- union sockunion *su; -+ union sockunion su; - struct peer *peer; -- int count; -+ int count, ret; - -- su = sockunion_str2su (argv[0]); -- if (su == NULL) -- return CMD_WARNING; -+ ret = str2sockunion (argv[0], &su); -+ if (ret < 0) -+ { -+ vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); -+ return CMD_WARNING; -+ } - -- peer = peer_lookup (NULL, su); -+ peer = peer_lookup (NULL, &su); - if (! peer) - return CMD_WARNING; - -@@ -10241,15 +10244,18 @@ DEFUN (show_ip_bgp_ipv4_neighbor_receive - "Display the prefixlist filter\n") - { - char name[BUFSIZ]; -- union sockunion *su; -+ union sockunion su; - struct peer *peer; -- int count; -+ int count, ret; - -- su = sockunion_str2su (argv[1]); -- if (su == NULL) -- return CMD_WARNING; -+ ret = str2sockunion (argv[1], &su); -+ if (ret < 0) -+ { -+ vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); -+ return CMD_WARNING; -+ } - -- peer = peer_lookup (NULL, su); -+ peer = peer_lookup (NULL, &su); - if (! peer) - return CMD_WARNING; - -@@ -10312,15 +10318,18 @@ DEFUN (show_bgp_neighbor_received_prefix - "Display the prefixlist filter\n") - { - char name[BUFSIZ]; -- union sockunion *su; -+ union sockunion su; - struct peer *peer; -- int count; -+ int count, ret; - -- su = sockunion_str2su (argv[0]); -- if (su == NULL) -- return CMD_WARNING; -+ ret = str2sockunion (argv[0], &su); -+ if (ret < 0) -+ { -+ vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); -+ return CMD_WARNING; -+ } - -- peer = peer_lookup (NULL, su); -+ peer = peer_lookup (NULL, &su); - if (! peer) - return CMD_WARNING; - -@@ -10394,10 +10403,10 @@ DEFUN (show_bgp_view_neighbor_received_p - "Display the prefixlist filter\n") - { - char name[BUFSIZ]; -- union sockunion *su; -+ union sockunion su; - struct peer *peer; - struct bgp *bgp; -- int count; -+ int count, ret; - - /* BGP structure lookup. */ - bgp = bgp_lookup_by_name (argv[0]); -@@ -10407,11 +10416,14 @@ DEFUN (show_bgp_view_neighbor_received_p - return CMD_WARNING; - } - -- su = sockunion_str2su (argv[1]); -- if (su == NULL) -- return CMD_WARNING; -+ ret = str2sockunion (argv[1], &su); -+ if (ret < 0) -+ { -+ vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); -+ return CMD_WARNING; -+ } - -- peer = peer_lookup (bgp, su); -+ peer = peer_lookup (bgp, &su); - if (! peer) - return CMD_WARNING; - ---- a/bgpd/bgp_vty.c -+++ b/bgpd/bgp_vty.c -@@ -2943,7 +2943,6 @@ peer_update_source_vty (struct vty *vty, - const char *source_str) - { - struct peer *peer; -- union sockunion *su; - - peer = peer_and_group_lookup_vty (vty, peer_str); - if (! peer) -@@ -2951,12 +2950,11 @@ peer_update_source_vty (struct vty *vty, - - if (source_str) - { -- su = sockunion_str2su (source_str); -- if (su) -- { -- peer_update_source_addr_set (peer, su); -- sockunion_free (su); -- } -+ union sockunion su; -+ int ret = str2sockunion (source_str, &su); -+ -+ if (ret == 0) -+ peer_update_source_addr_set (peer, &su); - else - peer_update_source_if_set (peer, source_str); - } ---- a/lib/sockunion.c -+++ b/lib/sockunion.c -@@ -177,55 +177,15 @@ sockunion2str (union sockunion *su, char - union sockunion * - sockunion_str2su (const char *str) - { -- int ret; -- union sockunion *su; -- -- su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); -- -- ret = inet_pton (AF_INET, str, &su->sin.sin_addr); -- if (ret > 0) /* Valid IPv4 address format. */ -- { -- su->sin.sin_family = AF_INET; --#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN -- su->sin.sin_len = sizeof(struct sockaddr_in); --#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ -- return su; -- } --#ifdef HAVE_IPV6 -- ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr); -- if (ret > 0) /* Valid IPv6 address format. */ -- { -- su->sin6.sin6_family = AF_INET6; --#ifdef SIN6_LEN -- su->sin6.sin6_len = sizeof(struct sockaddr_in6); --#endif /* SIN6_LEN */ -- return su; -- } --#endif /* HAVE_IPV6 */ -- -+ union sockunion *su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); -+ -+ if (!str2sockunion (str, su)) -+ return su; -+ - XFREE (MTYPE_SOCKUNION, su); - return NULL; - } - --char * --sockunion_su2str (union sockunion *su) --{ -- char str[SU_ADDRSTRLEN]; -- -- switch (su->sa.sa_family) -- { -- case AF_INET: -- inet_ntop (AF_INET, &su->sin.sin_addr, str, sizeof (str)); -- break; --#ifdef HAVE_IPV6 -- case AF_INET6: -- inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, sizeof (str)); -- break; --#endif /* HAVE_IPV6 */ -- } -- return XSTRDUP (MTYPE_TMP, str); --} -- - /* Convert IPv4 compatible IPv6 address to IPv4 address. */ - static void - sockunion_normalise_mapped (union sockunion *su) -@@ -422,7 +382,7 @@ sockunion_bind (int sock, union sockunio - su->sin.sin_len = size; - #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - if (su_addr == NULL) -- su->sin.sin_addr.s_addr = htonl (INADDR_ANY); -+ sockunion2ip (su) = htonl (INADDR_ANY); - } - #ifdef HAVE_IPV6 - else if (su->sa.sa_family == AF_INET6) -@@ -779,9 +739,9 @@ sockunion_cmp (union sockunion *su1, uni - - if (su1->sa.sa_family == AF_INET) - { -- if (ntohl (su1->sin.sin_addr.s_addr) == ntohl (su2->sin.sin_addr.s_addr)) -+ if (ntohl (sockunion2ip (su1)) == ntohl (sockunion2ip (su2))) - return 0; -- if (ntohl (su1->sin.sin_addr.s_addr) > ntohl (su2->sin.sin_addr.s_addr)) -+ if (ntohl (sockunion2ip (su1)) > ntohl (sockunion2ip (su2))) - return 1; - else - return -1; ---- a/lib/vty.c -+++ b/lib/vty.c -@@ -1612,13 +1612,16 @@ vty_flush (struct thread *thread) - static struct vty * - vty_create (int vty_sock, union sockunion *su) - { -+ char buf[SU_ADDRSTRLEN]; - struct vty *vty; - -+ sockunion2str(su, buf, SU_ADDRSTRLEN); -+ - /* Allocate new vty structure and set up default values. */ - vty = vty_new (); - vty->fd = vty_sock; - vty->type = VTY_TERM; -- vty->address = sockunion_su2str (su); -+ strcpy (vty->address, buf); - if (no_password_check) - { - if (restricted_mode) -@@ -1693,7 +1696,7 @@ vty_accept (struct thread *thread) - int accept_sock; - struct prefix *p = NULL; - struct access_list *acl = NULL; -- char *bufp; -+ char buf[SU_ADDRSTRLEN]; - - accept_sock = THREAD_FD (thread); - -@@ -1719,10 +1722,8 @@ vty_accept (struct thread *thread) - if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) && - (access_list_apply (acl, p) == FILTER_DENY)) - { -- char *buf; - zlog (NULL, LOG_INFO, "Vty connection refused from %s", -- (buf = sockunion_su2str (&su))); -- free (buf); -+ sockunion2str (&su, buf, SU_ADDRSTRLEN)); - close (vty_sock); - - /* continue accepting connections */ -@@ -1741,10 +1742,8 @@ vty_accept (struct thread *thread) - if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) && - (access_list_apply (acl, p) == FILTER_DENY)) - { -- char *buf; - zlog (NULL, LOG_INFO, "Vty connection refused from %s", -- (buf = sockunion_su2str (&su))); -- free (buf); -+ sockunion2str (&su, buf, SU_ADDRSTRLEN)); - close (vty_sock); - - /* continue accepting connections */ -@@ -1767,9 +1766,7 @@ vty_accept (struct thread *thread) - safe_strerror (errno)); - - zlog (NULL, LOG_INFO, "Vty connection from %s", -- (bufp = sockunion_su2str (&su))); -- if (bufp) -- XFREE (MTYPE_TMP, bufp); -+ sockunion2str (&su, buf, SU_ADDRSTRLEN)); - - vty_create (vty_sock, &su); - -@@ -2193,8 +2190,6 @@ vty_close (struct vty *vty) - if (vty->fd > 0) - close (vty->fd); - -- if (vty->address) -- XFREE (MTYPE_TMP, vty->address); - if (vty->buf) - XFREE (MTYPE_VTY, vty->buf); - ---- a/lib/vty.h -+++ b/lib/vty.h -@@ -23,6 +23,7 @@ Software Foundation, Inc., 59 Temple Pla - - #include "thread.h" - #include "log.h" -+#include "sockunion.h" - - #define VTY_BUFSIZ 512 - #define VTY_MAXHIST 20 -@@ -39,9 +40,6 @@ struct vty - /* Node status of this vty */ - int node; - -- /* What address is this vty comming from. */ -- char *address; -- - /* Failure count */ - int fail; - -@@ -118,6 +116,9 @@ struct vty - /* Timeout seconds and thread. */ - unsigned long v_timeout; - struct thread *t_timeout; -+ -+ /* What address is this vty comming from. */ -+ char address[SU_ADDRSTRLEN]; - }; - - /* Integrated configuration file. */ ---- a/zebra/zebra_rib.c -+++ b/zebra/zebra_rib.c -@@ -678,8 +678,8 @@ rib_lookup_ipv4_route (struct prefix_ipv - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) - { - /* We are happy with either direct or recursive hexthop */ -- if (nexthop->gate.ipv4.s_addr == qgate->sin.sin_addr.s_addr || -- nexthop->rgate.ipv4.s_addr == qgate->sin.sin_addr.s_addr) -+ if (nexthop->gate.ipv4.s_addr == sockunion2ip (qgate) || -+ nexthop->rgate.ipv4.s_addr == sockunion2ip (qgate)) - return ZEBRA_RIB_FOUND_EXACT; - else - { -@@ -688,7 +688,7 @@ rib_lookup_ipv4_route (struct prefix_ipv - char gate_buf[INET_ADDRSTRLEN], rgate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN]; - inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN); - inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN); -- inet_ntop (AF_INET, &qgate->sin.sin_addr.s_addr, qgate_buf, INET_ADDRSTRLEN); -+ inet_ntop (AF_INET, &sockunion2ip (qgate), qgate_buf, INET_ADDRSTRLEN); - zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf); - } - return ZEBRA_RIB_FOUND_NOGATE; diff --git a/patches/005-zebra-connected-in-mrib.patch b/patches/005-zebra-connected-in-mrib.patch deleted file mode 100644 index 6d0a868..0000000 --- a/patches/005-zebra-connected-in-mrib.patch +++ /dev/null @@ -1,21 +0,0 @@ ---- a/zebra/connected.c -+++ b/zebra/connected.c -@@ -191,6 +191,9 @@ connected_up_ipv4 (struct interface *ifp - rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, - RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST); - -+ rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, -+ RT_TABLE_MAIN, ifp->metric, 0, SAFI_MULTICAST); -+ - rib_update (); - } - -@@ -297,6 +300,8 @@ connected_down_ipv4 (struct interface *i - /* Same logic as for connected_up_ipv4(): push the changes into the head. */ - rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_UNICAST); - -+ rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_MULTICAST); -+ - rib_update (); - } - diff --git a/patches/006-fix-no-ipv6.patch b/patches/006-fix-no-ipv6.patch deleted file mode 100644 index f39c453..0000000 --- a/patches/006-fix-no-ipv6.patch +++ /dev/null @@ -1,127 +0,0 @@ ---- a/zebra/main.c -+++ b/zebra/main.c -@@ -327,7 +327,9 @@ main (int argc, char **argv) - zebra_vty_init (); - access_list_init (); - prefix_list_init (); -+#ifdef RTADV - rtadv_init (); -+#endif - #ifdef HAVE_IRDP - irdp_init(); - #endif ---- a/zebra/rtadv.h -+++ b/zebra/rtadv.h -@@ -26,6 +26,9 @@ - #include "vty.h" - #include "zebra/interface.h" - -+/* NB: RTADV is defined in zebra/interface.h above */ -+#ifdef RTADV -+ - /* Router advertisement prefix. */ - struct rtadv_prefix - { -@@ -96,4 +99,6 @@ struct nd_opt_homeagent_info { /* Home - - extern const char *rtadv_pref_strs[]; - -+#endif /* RTADV */ -+ - #endif /* _ZEBRA_RTADV_H */ ---- a/zebra/zebra_vty.c -+++ b/zebra/zebra_vty.c -@@ -1197,6 +1197,40 @@ DEFUN (show_ip_protocol, - return CMD_SUCCESS; - } - -+/* -+ * Show IP mroute command to dump the BGP Multicast -+ * routing table -+ */ -+DEFUN (show_ip_mroute, -+ show_ip_mroute_cmd, -+ "show ip mroute", -+ SHOW_STR -+ IP_STR -+ "IP Multicast routing table\n") -+{ -+ struct route_table *table; -+ struct route_node *rn; -+ struct rib *rib; -+ int first = 1; -+ -+ table = vrf_table (AFI_IP, SAFI_MULTICAST, 0); -+ if (! table) -+ return CMD_SUCCESS; -+ -+ /* Show all IPv4 routes. */ -+ for (rn = route_top (table); rn; rn = route_next (rn)) -+ for (rib = rn->info; rib; rib = rib->next) -+ { -+ if (first) -+ { -+ vty_out (vty, SHOW_ROUTE_V4_HEADER); -+ first = 0; -+ } -+ vty_show_ip_route (vty, rn, rib); -+ } -+ return CMD_SUCCESS; -+} -+ - - #ifdef HAVE_IPV6 - /* General fucntion for IPv6 static route. */ -@@ -1952,40 +1986,6 @@ DEFUN (show_ipv6_route_summary, - } - - /* -- * Show IP mroute command to dump the BGP Multicast -- * routing table -- */ --DEFUN (show_ip_mroute, -- show_ip_mroute_cmd, -- "show ip mroute", -- SHOW_STR -- IP_STR -- "IP Multicast routing table\n") --{ -- struct route_table *table; -- struct route_node *rn; -- struct rib *rib; -- int first = 1; -- -- table = vrf_table (AFI_IP, SAFI_MULTICAST, 0); -- if (! table) -- return CMD_SUCCESS; -- -- /* Show all IPv4 routes. */ -- for (rn = route_top (table); rn; rn = route_next (rn)) -- for (rib = rn->info; rib; rib = rib->next) -- { -- if (first) -- { -- vty_out (vty, SHOW_ROUTE_V4_HEADER); -- first = 0; -- } -- vty_show_ip_route (vty, rn, rib); -- } -- return CMD_SUCCESS; --} -- --/* - * Show IPv6 mroute command.Used to dump - * the Multicast routing table. - */ -@@ -2020,11 +2020,6 @@ DEFUN (show_ipv6_mroute, - return CMD_SUCCESS; - } - -- -- -- -- -- - /* Write IPv6 static route configuration. */ - static int - static_config_ipv6 (struct vty *vty) diff --git a/patches/007-drop-heuristic-ipv6-recognition.patch b/patches/007-drop-heuristic-ipv6-recognition.patch deleted file mode 100644 index 1b49d7b..0000000 --- a/patches/007-drop-heuristic-ipv6-recognition.patch +++ /dev/null @@ -1,90 +0,0 @@ ---- a/lib/command.c -+++ b/lib/command.c -@@ -868,86 +868,7 @@ cmd_ipv6_match (const char *str) - if (ret == 1) - return exact_match; - -- while (*str != '\0') -- { -- switch (state) -- { -- case STATE_START: -- if (*str == ':') -- { -- if (*(str + 1) != ':' && *(str + 1) != '\0') -- return no_match; -- colons--; -- state = STATE_COLON; -- } -- else -- { -- sp = str; -- state = STATE_ADDR; -- } -- -- continue; -- case STATE_COLON: -- colons++; -- if (*(str + 1) == ':') -- state = STATE_DOUBLE; -- else -- { -- sp = str + 1; -- state = STATE_ADDR; -- } -- break; -- case STATE_DOUBLE: -- if (double_colon) -- return no_match; -- -- if (*(str + 1) == ':') -- return no_match; -- else -- { -- if (*(str + 1) != '\0') -- colons++; -- sp = str + 1; -- state = STATE_ADDR; -- } -- -- double_colon++; -- nums++; -- break; -- case STATE_ADDR: -- if (*(str + 1) == ':' || *(str + 1) == '\0') -- { -- if (str - sp > 3) -- return no_match; -- -- nums++; -- state = STATE_COLON; -- } -- if (*(str + 1) == '.') -- state = STATE_DOT; -- break; -- case STATE_DOT: -- state = STATE_ADDR; -- break; -- default: -- break; -- } -- -- if (nums > 8) -- return no_match; -- -- if (colons > 7) -- return no_match; -- -- str++; -- } -- --#if 0 -- if (nums < 11) -- return partly_match; --#endif /* 0 */ -- -- return exact_match; -+ return no_match; - } - - static enum match_type diff --git a/patches/008-fix-thread_cancel_event.patch b/patches/008-fix-thread_cancel_event.patch deleted file mode 100644 index 3dcb9f5..0000000 --- a/patches/008-fix-thread_cancel_event.patch +++ /dev/null @@ -1,27 +0,0 @@ ---- a/lib/thread.c -+++ b/lib/thread.c -@@ -916,6 +916,24 @@ thread_cancel_event (struct thread_maste - thread_add_unuse (m, t); - } - } -+ -+ /* thread can be on the ready list too */ -+ thread = m->ready.head; -+ while (thread) -+ { -+ struct thread *t; -+ -+ t = thread; -+ thread = t->next; -+ -+ if (t->arg == arg) -+ { -+ ret++; -+ thread_list_delete (&m->ready, t); -+ t->type = THREAD_UNUSED; -+ thread_add_unuse (m, t); -+ } -+ } - return ret; - } - diff --git a/patches/009-bgpd-fix-vpn4-soft-reconfiguration.patch b/patches/009-bgpd-fix-vpn4-soft-reconfiguration.patch deleted file mode 100644 index d8efa72..0000000 --- a/patches/009-bgpd-fix-vpn4-soft-reconfiguration.patch +++ /dev/null @@ -1,89 +0,0 @@ ---- a/bgpd/bgp_route.c -+++ b/bgpd/bgp_route.c -@@ -2616,7 +2616,7 @@ bgp_announce_route_all (struct peer *pee - - static void - bgp_soft_reconfig_table_rsclient (struct peer *rsclient, afi_t afi, -- safi_t safi, struct bgp_table *table) -+ safi_t safi, struct bgp_table *table, struct prefix_rd *prd) - { - struct bgp_node *rn; - struct bgp_adj_in *ain; -@@ -2627,8 +2627,11 @@ bgp_soft_reconfig_table_rsclient (struct - for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) - for (ain = rn->adj_in; ain; ain = ain->next) - { -+ struct bgp_info *ri = rn->info; -+ - bgp_update_rsclient (rsclient, afi, safi, ain->attr, ain->peer, -- &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL); -+ &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, -+ (bgp_info_extra_get (ri))->tag); - } - } - -@@ -2639,18 +2642,25 @@ bgp_soft_reconfig_rsclient (struct peer - struct bgp_node *rn; - - if (safi != SAFI_MPLS_VPN) -- bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, NULL); -+ bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, NULL, NULL); - - else - for (rn = bgp_table_top (rsclient->bgp->rib[afi][safi]); rn; - rn = bgp_route_next (rn)) - if ((table = rn->info) != NULL) -- bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, table); -+ { -+ struct prefix_rd prd; -+ prd.family = AF_UNSPEC; -+ prd.prefixlen = 64; -+ memcpy(&prd.val, rn->p.u.val, 8); -+ -+ bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, table, &prd); -+ } - } - - static void - bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi, -- struct bgp_table *table) -+ struct bgp_table *table, struct prefix_rd *prd) - { - int ret; - struct bgp_node *rn; -@@ -2664,9 +2674,12 @@ bgp_soft_reconfig_table (struct peer *pe - { - if (ain->peer == peer) - { -+ struct bgp_info *ri = rn->info; -+ - ret = bgp_update (peer, &rn->p, ain->attr, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, -- NULL, NULL, 1); -+ prd, (bgp_info_extra_get (ri))->tag, 1); -+ - if (ret < 0) - { - bgp_unlock_node (rn); -@@ -2687,12 +2700,19 @@ bgp_soft_reconfig_in (struct peer *peer, - return; - - if (safi != SAFI_MPLS_VPN) -- bgp_soft_reconfig_table (peer, afi, safi, NULL); -+ bgp_soft_reconfig_table (peer, afi, safi, NULL, NULL); - else - for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; - rn = bgp_route_next (rn)) - if ((table = rn->info) != NULL) -- bgp_soft_reconfig_table (peer, afi, safi, table); -+ { -+ struct prefix_rd prd; -+ prd.family = AF_UNSPEC; -+ prd.prefixlen = 64; -+ memcpy(&prd.val, rn->p.u.val, 8); -+ -+ bgp_soft_reconfig_table (peer, afi, safi, table, &prd); -+ } - } - - diff --git a/patches/010-bgpd-fix-struct-attr_extra-leak.patch b/patches/010-bgpd-fix-struct-attr_extra-leak.patch deleted file mode 100644 index 8f824bf..0000000 --- a/patches/010-bgpd-fix-struct-attr_extra-leak.patch +++ /dev/null @@ -1,17 +0,0 @@ ---- a/bgpd/bgp_route.c -+++ b/bgpd/bgp_route.c -@@ -2485,12 +2485,8 @@ bgp_default_originate (struct peer *peer - #ifdef HAVE_IPV6 - else if (afi == AFI_IP6) - { -- struct attr_extra *ae; -- attr.extra = NULL; -- -- ae = bgp_attr_extra_get (&attr); -- attr.extra = ae; -- -+ struct attr_extra *ae = attr.extra; -+ - str2prefix ("::/0", &p); - - /* IPv6 global nexthop must be included. */ diff --git a/patches/011-isisd-fix-typo.patch b/patches/011-isisd-fix-typo.patch deleted file mode 100644 index 142c8af..0000000 --- a/patches/011-isisd-fix-typo.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/isisd/isis_lsp.c -+++ b/isisd/isis_lsp.c -@@ -2413,7 +2413,7 @@ top_lsp_refresh (struct thread *thread) - isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname, - IS_LEVEL_1); - -- lsp->lsp_header->lsp_bits = lsp_bits_generate (level, -+ lsp->lsp_header->lsp_bits = lsp_bits_generate (lsp->level, - lsp->area->overload_bit); - rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1); - lsp->lsp_header->rem_lifetime = htons (rem_lifetime); diff --git a/patches/110-fix_ipctl_forwarding.patch b/patches/110-fix_ipctl_forwarding.patch deleted file mode 100644 index d757312..0000000 --- a/patches/110-fix_ipctl_forwarding.patch +++ /dev/null @@ -1,25 +0,0 @@ -Add definitions for IPCTL_FORWARDING and IP6CTL_FORWARDING. - -Inspired from -http://svn.gnumonks.org/trunk/grouter/build/src/quagga/quagga/quagga-0.99.1-forward_sysctl-2.6.14.patch - -Signed-off-by: Thomas Petazzoni - ---- a/zebra/ipforward_sysctl.c -+++ b/zebra/ipforward_sysctl.c -@@ -31,6 +31,15 @@ - - #define MIB_SIZ 4 - -+/* Fix for recent (2.6.14) kernel headers */ -+#ifndef IPCTL_FORWARDING -+#define IPCTL_FORWARDING NET_IPV4_FORWARD -+#endif -+ -+#ifndef IP6CTL_FORWARDING -+#define IP6CTL_FORWARDING NET_IPV6_FORWARDING -+#endif -+ - extern struct zebra_privs_t zserv_privs; - - /* IPv4 forwarding control MIB. */ diff --git a/patches/120-quagga_manet.patch b/patches/120-quagga_manet.patch index 99e3cc7..684a27d 100644 --- a/patches/120-quagga_manet.patch +++ b/patches/120-quagga_manet.patch @@ -1,6 +1,6 @@ --- a/lib/log.c +++ b/lib/log.c -@@ -929,13 +929,19 @@ proto_redistnum(int afi, const char *s) +@@ -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; @@ -22,7 +22,7 @@ return ZEBRA_ROUTE_BABEL; } if (afi == AFI_IP6) -@@ -948,13 +954,19 @@ proto_redistnum(int afi, const char *s) +@@ -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; @@ -107,7 +107,7 @@ --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c -@@ -1623,6 +1623,9 @@ netlink_route_multipath (int cmd, struct +@@ -1609,6 +1609,9 @@ netlink_route_multipath (int cmd, struct addattr_l (&req.n, sizeof req, RTA_PREFSRC, &nexthop->src.ipv4, bytelen); @@ -119,7 +119,7 @@ "nexthop via if %u", nexthop->ifindex); --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c -@@ -67,6 +67,9 @@ static const struct +@@ -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. */}, @@ -129,7 +129,7 @@ [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 95}, /* no entry/default: 150 */ }; -@@ -403,6 +406,18 @@ nexthop_active_ipv4 (struct rib *rib, st +@@ -456,6 +459,18 @@ nexthop_active_ipv4 (struct rib *rib, st } return 0; } @@ -148,7 +148,7 @@ else { return 0; -@@ -507,6 +522,18 @@ nexthop_active_ipv6 (struct rib *rib, st +@@ -560,6 +575,18 @@ nexthop_active_ipv6 (struct rib *rib, st } return 0; } @@ -167,7 +167,7 @@ else { return 0; -@@ -1236,6 +1263,8 @@ static const u_char meta_queue_map[ZEBRA +@@ -1376,6 +1403,8 @@ static const u_char meta_queue_map[ZEBRA [ZEBRA_ROUTE_ISIS] = 2, [ZEBRA_ROUTE_BGP] = 3, [ZEBRA_ROUTE_HSLS] = 4, @@ -178,7 +178,7 @@ --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c -@@ -251,6 +251,12 @@ proto_trans(int type) +@@ -245,6 +245,12 @@ proto_trans(int type) return 1; /* shouldn't happen */ case ZEBRA_ROUTE_BGP: return 14; /* bgp */ diff --git a/patches/130-fix_cpp.patch b/patches/130-fix_cpp.patch deleted file mode 100644 index 23991c3..0000000 --- a/patches/130-fix_cpp.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/vtysh/extract.pl.in -+++ b/vtysh/extract.pl.in -@@ -63,7 +63,7 @@ $ignore{'"show history"'} = "ignore"; - foreach (@ARGV) { - $file = $_; - -- open (FH, "cpp -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_srcdir@/isisd/topology @SNMP_INCLUDES@ @CPPFLAGS@ $file |"); -+ open (FH, "@CPP@ -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_srcdir@/isisd/topology @SNMP_INCLUDES@ @CPPFLAGS@ $file |"); - local $/; undef $/; - $line = ; - close (FH); diff --git a/patches/140-holdtimer-set.patch b/patches/140-holdtimer-set.patch index 6f0d79a..b699775 100644 --- a/patches/140-holdtimer-set.patch +++ b/patches/140-holdtimer-set.patch @@ -12,7 +12,7 @@ sockunion2str (&su, buf, SU_ADDRSTRLEN); --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h -@@ -718,6 +718,7 @@ struct bgp_nlri +@@ -732,6 +732,7 @@ struct bgp_nlri /* BGP timers default value. */ #define BGP_INIT_START_TIMER 5 #define BGP_ERROR_START_TIMER 30 diff --git a/patches/150-no-cross-fs-link.patch b/patches/150-no-cross-fs-link.patch index 2b84031..32c1208 100644 --- a/patches/150-no-cross-fs-link.patch +++ b/patches/150-no-cross-fs-link.patch @@ -1,6 +1,6 @@ --- a/lib/command.c +++ b/lib/command.c -@@ -2522,6 +2522,13 @@ DEFUN (config_write_file, +@@ -2527,6 +2527,13 @@ DEFUN (config_write_file, VTY_NEWLINE); goto finished; } @@ -14,7 +14,7 @@ if (link (config_file, config_file_sav) != 0) { vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav, -@@ -2535,7 +2542,23 @@ DEFUN (config_write_file, +@@ -2540,7 +2547,23 @@ DEFUN (config_write_file, VTY_NEWLINE); goto finished; } diff --git a/patches/160-pgbgp.patch b/patches/160-pgbgp.patch deleted file mode 100644 index a8273ab..0000000 --- a/patches/160-pgbgp.patch +++ /dev/null @@ -1,3104 +0,0 @@ -From: Josh Karlin -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 - - * 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 -+#include -+ -+#include "prefix.h" -+#include "memory.h" -+#include "command.h" -+#include "log.h" -+#include "pqueue.h" -+#include "table.h" -+#include "hash.h" -+#include "str.h" -+ -+#include "bgpd/bgpd.h" -+#include "bgpd/bgp_aspath.h" -+#include "bgpd/bgp_pgbgp.h" -+#include "bgpd/bgp_table.h" -+#include "bgpd/bgp_route.h" -+#include "bgpd/bgp_attr.h" -+#include "bgpd/bgp_advertise.h" -+ -+ -+#define true 1 -+#define false 0 -+ -+struct hash * ashash; -+ -+static void *edge_hash_alloc (void *arg); -+static unsigned int edge_key_make (void *p); -+static int edge_cmp (const void *arg1, const void *args); -+ -+// Helper Functions -+static struct bgp_pgbgp_pathSet bgp_pgbgp_pathOrigin (struct aspath *); -+static int bgp_pgbgp_pathLength (struct aspath *asp); -+static int bgp_pgbgp_gc (struct bgp_table *); -+static int bgp_pgbgp_clean (struct bgp_table *); -+static int bgp_pgbgp_reuse (time_t); -+static struct bgp_node *findSuper (struct bgp_table *table, struct prefix *p, -+ time_t t_now); -+static int bgp_pgbgp_store (struct bgp_table *table); -+static int bgp_pgbgp_restore (void); -+static struct bgp_info *bgp_pgbgp_selected (struct bgp_node *node); -+static int originInRIB (struct bgp_node *node, struct bgp_pgbgp_origin *origin); -+static int prefixInRIB (struct bgp_node *node, struct bgp_pgbgp_prefix *prefix); -+static int edgeInRIB (struct bgp_pgbgp_edge *e); -+ -+// MOAS Functions -+static void bgp_pgbgp_logOriginAnomaly (as_t asn, struct bgp_node *rn, -+ struct attr *); -+static int bgp_pgbgp_reuseOrigin (struct bgp_pgbgp_r_origin); -+static void bgp_pgbgp_cleanHistTable (struct bgp_table *); -+static int bgp_pgbgp_garbageCollectHistTable (struct bgp_table *); -+static void bgp_pgbgp_storeHistTable (struct bgp_table *table, FILE * file); -+static int bgp_pgbgp_updateOrigin (struct bgp_pgbgp_hist *, struct bgp_info *, -+ struct attr *, struct bgp_node *, time_t, int); -+ -+ -+// Sub-Prefix Hijack Detector Functions -+static int bgp_pgbgp_shouldIgnore (struct bgp_node *super, struct bgp_info *selected); -+static void bgp_pgbgp_logSubprefixAnomaly (as_t asn, struct bgp_node *rn, -+ struct attr *, struct bgp_node *super); -+static int bgp_pgbgp_reusePrefix (struct bgp_pgbgp_r_prefix); -+static int bgp_pgbgp_updatePrefix (struct bgp_pgbgp_hist *hist, struct bgp_node *, -+ struct bgp_info *, struct attr *, -+ struct bgp_node *, time_t, int); -+ -+ -+// Spoofed Edge Detector Functions -+static void bgp_pgbgp_cleanEdges (void); -+static void bgp_pgbgp_logEdgeAnomaly (struct bgp_node *rn, struct attr *, -+ struct edge *edge); -+static int bgp_pgbgp_reuseEdge (struct bgp_pgbgp_r_edge); -+static void bgp_pgbgp_storeEdges (struct bgp_table *, FILE *); -+static int bgp_pgbgp_garbageCollectEdges (struct bgp_table *); -+static int bgp_pgbgp_updateEdge (struct bgp_pgbgp_hist *hist, struct bgp_info *, -+ struct attr *, struct bgp_node *, time_t, int); -+static int bgp_pgbgp_restoreEdge (FILE * file); -+static void bgp_pgbgp_storeEdges (struct bgp_table *table, FILE * file); -+ -+ -+ -+// New Peer Detector Functions -+static int bgp_pgbgp_updatePeer (struct bgp_info *binfo, time_t now); -+ -+ -+/* --------------- Global Variables ------------------ */ -+struct bgp_pgbgp_config bgp_pgbgp_cfg; -+struct bgp_pgbgp_config *pgbgp = &bgp_pgbgp_cfg; -+/*! --------------- Global Variables ------------------ !*/ -+ -+/* --------------- VTY (others exist in bgp_route.c) ------------------ */ -+ -+struct nsearch -+{ -+ struct vty *pvty; -+ time_t time; -+ as_t asn; -+}; -+ -+static void -+edge_neighbor_iterator (struct hash_backet *backet, struct nsearch *pns) -+{ -+ struct bgp_pgbgp_edge *hedge = backet->data; -+ if ((hedge->e.a == pns->asn || hedge->e.b == pns->asn) -+ && hedge->e.a != hedge->e.b) -+ { -+ struct vty *vty = pns->pvty; -+ if (hedge->deprefUntil > pns->time) -+ vty_out (pns->pvty, "Untrusted: %d -- %d%s", hedge->e.a, hedge->e.b, -+ VTY_NEWLINE); -+ else -+ vty_out (pns->pvty, "Trusted: %d -- %d%s", hedge->e.a, hedge->e.b, -+ VTY_NEWLINE); -+ } -+} -+ -+static int -+bgp_pgbgp_stats_neighbors (struct vty *vty, afi_t afi, safi_t safi, as_t asn) -+{ -+ struct nsearch ns; -+ ns.pvty = vty; -+ ns.time = time (NULL); -+ ns.asn = asn; -+ -+ hash_iterate (pgbgp->edgeT, -+ (void (*)(struct hash_backet *, void *)) -+ edge_neighbor_iterator, &ns); -+ return CMD_SUCCESS; -+} -+ -+static int -+bgp_pgbgp_stats_origins (struct vty *vty, afi_t afi, safi_t safi, -+ const char *prefix) -+{ -+ struct bgp *bgp; -+ struct bgp_table *table; -+ time_t t_now = time (NULL); -+ bgp = bgp_get_default (); -+ if (bgp == NULL) -+ return CMD_WARNING; -+ if (bgp->rib == NULL) -+ return CMD_WARNING; -+ table = bgp->rib[afi][safi]; -+ if (table == NULL) -+ return CMD_WARNING; -+ -+ struct prefix p; -+ str2prefix (prefix, &p); -+ struct bgp_node *rn = bgp_node_match (table, &p); -+ vty_out (vty, "%s%s", prefix, VTY_NEWLINE); -+ if (rn) -+ { -+ if (rn->hist) -+ { -+ for (struct bgp_pgbgp_origin * cur = rn->hist->o; cur != NULL; -+ cur = cur->next) -+ { -+ if (cur->deprefUntil > t_now) -+ vty_out (vty, "Untrusted Origin AS: %d%s", cur->originAS, -+ VTY_NEWLINE); -+ else -+ vty_out (vty, "Trusted Origin AS: %d%s", cur->originAS, -+ VTY_NEWLINE); -+ } -+ } -+ bgp_unlock_node (rn); -+ } -+ return CMD_SUCCESS; -+} -+ -+static int -+bgp_pgbgp_stats (struct vty *vty, afi_t afi, safi_t safi) -+{ -+ struct bgp *bgp; -+ struct bgp_table *table; -+ -+ -+ bgp = bgp_get_default (); -+ if (bgp == NULL) -+ return CMD_WARNING; -+ if (bgp->rib == NULL) -+ return CMD_WARNING; -+ table = bgp->rib[afi][safi]; -+ if (table == NULL) -+ return CMD_WARNING; -+ -+ // bgp_pgbgp_store(table); -+ -+ // Print out the number of anomalous routes -+ int anomalous = 0; -+ int routes = 0; -+ int num_selected = 0; -+ int num_origin = 0; -+ int num_super = 0; -+ int num_ignored = 0; -+ int num_edge = 0; -+ -+ for (struct bgp_node * rn = bgp_table_top (table); rn; -+ rn = bgp_route_next (rn)) -+ { -+ for (struct bgp_info * ri = rn->info; ri; ri = ri->next) -+ { -+ routes += 1; -+ if (ANOMALOUS (ri->flags)) -+ { -+ anomalous += 1; -+ if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) -+ num_selected += 1; -+ -+ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O)) -+ num_origin += 1; -+ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_E)) -+ num_edge += 1; -+ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_P)) -+ num_super += 1; -+ if (CHECK_FLAG (ri->flags, BGP_INFO_IGNORED_P)) -+ num_ignored += 1; -+ } -+ } -+ } -+ -+ vty_out (vty, "%-30s: %10d%s", "Routes in the RIB", routes, VTY_NEWLINE); -+ vty_out (vty, "%-30s: %10d%s", "Anomalous routes in RIB", anomalous, -+ VTY_NEWLINE); -+ vty_out (vty, "%-30s: %10d%s", "Selected anomalous routes", num_selected, -+ VTY_NEWLINE); -+ vty_out (vty, "-----------------------------%s", VTY_NEWLINE); -+ vty_out (vty, "%-30s: %10d%s", "Routes with anomalous origins", num_origin, -+ VTY_NEWLINE); -+ vty_out (vty, "%-30s: %10d%s", "Routes with anomalous edges", num_edge, -+ VTY_NEWLINE); -+ vty_out (vty, "%-30s: %10d%s", "Routes ignored for sub-prefix", num_ignored, -+ VTY_NEWLINE); -+ vty_out (vty, "%-30s: %10d%s", "Less specific routes to avoid", num_super, -+ VTY_NEWLINE); -+ /* -+ vty_out (vty, "There are %d routes in the RIB.%s", routes, VTY_NEWLINE); -+ vty_out (vty, "%d are anomalous.%s", anomalous, VTY_NEWLINE); -+ vty_out (vty, "%d anomalous routes are selected.%s", num_selected, VTY_NEWLINE); -+ vty_out (vty, "%s", VTY_NEWLINE); -+ vty_out (vty, "Anomaly breakdown:%s", VTY_NEWLINE); -+ vty_out (vty, "%d contain anomalous origins%s", num_origin, VTY_NEWLINE); -+ vty_out (vty, "%d contain anomalous edges.%s", num_edge, VTY_NEWLINE); -+ vty_out (vty, "%d are for ignored sub-prefixes.%s", num_ignored, VTY_NEWLINE); -+ vty_out (vty, "%d are super-net routes through peers that announced anomalous sub-prefixes.%s", num_super, VTY_NEWLINE); -+ */ -+ return CMD_SUCCESS; -+} -+ -+ -+DEFUN (show_ip_bgp_pgbgp, -+ show_ip_bgp_pgbgp_cmd, -+ "show ip bgp pgbgp", -+ SHOW_STR IP_STR BGP_STR "Display PGBGP statistics\n") -+{ -+ return bgp_pgbgp_stats (vty, AFI_IP, SAFI_UNICAST); -+} -+ -+DEFUN (show_ip_bgp_pgbgp_neighbors, -+ show_ip_bgp_pgbgp_neighbors_cmd, -+ "show ip bgp pgbgp neighbors WORD", -+ SHOW_STR -+ IP_STR -+ BGP_STR -+ "BGP pgbgp\n" -+ "BGP pgbgp neighbors\n" "ASN whos neighbors should be displayed\n") -+{ -+ return bgp_pgbgp_stats_neighbors (vty, AFI_IP, SAFI_UNICAST, -+ atoi (argv[0])); -+} -+ -+DEFUN (show_ip_bgp_pgbgp_origins, -+ show_ip_bgp_pgbgp_origins_cmd, -+ "show ip bgp pgbgp origins A.B.C.D/M", -+ SHOW_STR -+ IP_STR -+ BGP_STR -+ "BGP pgbgp\n" -+ "BGP pgbgp neighbors\n" "Prefix to look up origin ASes of\n") -+{ -+ return bgp_pgbgp_stats_origins (vty, AFI_IP, SAFI_UNICAST, argv[0]); -+} -+ -+ -+ -+ -+/*! --------------- VTY (others exist in bgp_route.c) ------------------ !*/ -+ -+ -+ -+ -+ -+ -+ -+/* --------------- Helper Functions ------------------ */ -+/* -+ If the origin hasn't been seen/verified lately, look for it in the RIB -+*/ -+int -+originInRIB (struct bgp_node *node, struct bgp_pgbgp_origin *origin) -+{ -+ for (struct bgp_info * ri = node->info; ri; ri = ri->next) -+ { -+ struct bgp_pgbgp_pathSet pathOrigins; -+ pathOrigins = bgp_pgbgp_pathOrigin (ri->attr->aspath); -+ for (int i = 0; i < pathOrigins.length; ++i) -+ { -+ if (pathOrigins.ases[i] == origin->originAS) -+ { -+ return true; -+ } -+ } -+ } -+ return false; -+} -+ -+ -+/* -+ If the prefix hasn't been seen/verified lately, look for it in the RIB -+*/ -+int -+prefixInRIB (struct bgp_node *node, struct bgp_pgbgp_prefix *prefix) -+{ -+ if (node->info) -+ return true; -+ return false; -+} -+ -+static int -+edge_inRIB_iterator (struct hash_backet *backet, struct bgp_pgbgp_edge *hedge) -+{ -+ struct aspath *p = backet->data; -+ char first = true; -+ struct edge curEdge; -+ curEdge.a = 0; -+ curEdge.b = 0; -+ -+ struct assegment *seg; -+ -+ for (seg = p->segments; seg; seg = seg->next) -+ { -+ for (int i = 0; i < seg->length; i++) -+ { -+ curEdge.a = curEdge.b; -+ curEdge.b = seg->as[i]; -+ if (first) -+ { -+ first = false; -+ continue; -+ } -+ // Is this the edge we're looking for? -+ if (curEdge.a == hedge->e.a && curEdge.b == hedge->e.b) -+ { -+ hedge->lastSeen = time (NULL); -+ return false; -+ } -+ } -+ } -+ -+ return true; -+} -+ -+/* -+ If the edge hasn't been seen/verified lately, look for it in the AS path list -+ This function is expensive, use sparingly -+*/ -+int -+edgeInRIB (struct bgp_pgbgp_edge *e) -+{ -+ int completed; -+ completed = hash_iterate_until (ashash, -+ (int (*)(struct hash_backet *, void *)) -+ edge_inRIB_iterator, e); -+ if (completed) -+ return false; -+ -+ return true; -+} -+ -+ -+ -+/* -+ Return the selected route for the given route node -+ */ -+ -+struct bgp_info * -+bgp_pgbgp_selected (struct bgp_node *node) -+{ -+ for (struct bgp_info * ri = node->info; ri; ri = ri->next) -+ { -+ if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) -+ return ri; -+ } -+ return NULL; -+} -+ -+static int -+reuse_cmp (void *node1, void *node2) -+{ -+ struct bgp_pgbgp_reuse *a; -+ struct bgp_pgbgp_reuse *b; -+ a = (struct bgp_pgbgp_reuse *) node1; -+ b = (struct bgp_pgbgp_reuse *) node2; -+ return a->deprefUntil - b->deprefUntil; -+} -+ -+int -+bgp_pgbgp_pathLength (struct aspath *asp) -+{ -+ struct assegment *seg; -+ if ((asp == NULL) || (asp->segments == NULL)) -+ return 0; -+ int count = 0; -+ seg = asp->segments; -+ while (seg->next != NULL) -+ { -+ count += seg->length; -+ seg = seg->next; -+ } -+ return count; -+} -+ -+ -+ -+/* Find the origin(s) of the path -+ All ASes in the final set are considered origins */ -+static struct bgp_pgbgp_pathSet -+bgp_pgbgp_pathOrigin (struct aspath *asp) -+{ -+ struct assegment *seg, *last; -+ struct bgp_pgbgp_pathSet tmp; -+ tmp.length = 0; -+ tmp.ases = NULL; -+ -+ assert (asp != NULL && asp->segments != NULL); -+ -+ /* if ( (asp == NULL) || (asp->segments == NULL) ) -+ return tmp; -+ */ -+ seg = asp->segments; -+ last = NULL; -+ while (seg->next != NULL) -+ { -+ if (seg->type != AS_SET && seg->type != AS_CONFED_SET) -+ last = seg; -+ seg = seg->next; -+ } -+ -+ if (seg->type == AS_SET || seg->type == AS_CONFED_SET) -+ seg = last; -+ -+ assert (seg); -+ tmp.length = 1; -+ tmp.ases = &seg->as[seg->length - 1]; -+ -+ /* -+ if (seg->type == AS_SET || seg->type == AS_CONFED_SET) -+ { -+ tmp.length = seg->length; -+ tmp.ases = seg->as; -+ } -+ else -+ { -+ tmp.length = 1; -+ tmp.ases = &seg->as[seg->length - 1]; -+ } -+ */ -+ assert (tmp.length >= 1); -+ return tmp; -+ // return seg->as[seg->length-1]; -+} -+ -+int -+bgp_pgbgp_reuse (time_t t_now) -+{ -+ -+ struct bgp_pgbgp_reuse *cur = NULL; -+ -+ while (pgbgp->rq_size > 0) -+ { -+ cur = pqueue_dequeue (pgbgp->reuse_q); -+ pgbgp->rq_size -= 1; -+ -+ // Is the next item ready to be reused? -+ if (t_now < cur->deprefUntil) -+ { -+ pqueue_enqueue (cur, pgbgp->reuse_q); -+ pgbgp->rq_size += 1; -+ break; -+ } -+ -+ // Okay, it needs to be reused now -+ if (cur->type == PGBGP_REUSE_ORIGIN) -+ bgp_pgbgp_reuseOrigin (cur->data.origin); -+ -+ else if (cur->type == PGBGP_REUSE_PREFIX) -+ bgp_pgbgp_reusePrefix (cur->data.prefix); -+ -+ else if (cur->type == PGBGP_REUSE_EDGE) -+ bgp_pgbgp_reuseEdge (cur->data.edge); -+ -+ -+ XFREE (MTYPE_BGP_PGBGP_REUSE, cur); -+ } -+ return 0; -+} -+ -+/* Check bit of the prefix. */ -+static int -+check_bit (u_char * prefix, u_char prefixlen) -+{ -+ int offset; -+ int shift; -+ u_char *p = (u_char *) prefix; -+ -+ assert (prefixlen <= 128); -+ -+ offset = prefixlen / 8; -+ shift = 7 - (prefixlen % 8); -+ -+ return (p[offset] >> shift & 1); -+} -+ -+/* -+ Find a super-net in the tree that's not currently anomalous if one exists -+*/ -+struct bgp_node * -+findSuper (struct bgp_table *table, struct prefix *p, time_t t_now) -+{ -+ struct bgp_node *node; -+ struct bgp_node *matched; -+ -+ matched = NULL; -+ node = table->top; -+ -+ while (node && node->p.prefixlen < p->prefixlen && -+ prefix_match (&node->p, p)) -+ { -+ // Node may not yet have its info set when reading in from pgbgp log files -+ if (node->hist && node->p.prefixlen >= 8) -+ { -+ if (node->hist->p != NULL && node->hist->p->ignoreUntil < t_now) -+ //if (node->hist->p != NULL && prefixInRIB (node, NULL)) -+ //if (node->hist->p != NULL) -+ matched = node; -+ } -+ node = node->link[check_bit (&p->u.prefix, node->p.prefixlen)]; -+ } -+ if (matched) -+ return bgp_lock_node (matched); -+ return NULL; -+} -+ -+ -+ -+ -+ -+/*! --------------- Helper Functions ------------------ !*/ -+ -+ -+ -+ -+ -+ -+ -+/* --------------- Public PGBGP Interface ------------------ */ -+int -+bgp_pgbgp_enable (struct bgp *bgp, afi_t afi, safi_t safi, -+ int ost, int est, int sst, int oht, int pht, int eht, -+ const char *file, const char *anoms) -+{ -+ -+ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP)) -+ { -+ if (pgbgp->storage && pgbgp->anomalies) -+ { -+ if (pgbgp->origin_sus_time == ost -+ && pgbgp->edge_sus_time == est -+ && pgbgp->sub_sus_time == sst -+ && pgbgp->origin_hist_time == oht -+ && pgbgp->prefix_hist_time == pht -+ && pgbgp->edge_hist_time == eht -+ && strcmp (pgbgp->storage, file) == 0 -+ && strcmp (pgbgp->anomalies, anoms) == 0) -+ -+ return 0; -+ } -+ } -+ -+ SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP); -+ -+#ifndef PGBGP_DEBUG -+ time_t hour = 3600; -+ time_t day = 86400; -+#endif -+#ifdef PGBGP_DEBUG -+ time_t hour = 2; -+ time_t day = 5; -+#endif -+ -+ pgbgp->origin_sus_time = ost * hour; -+ pgbgp->edge_sus_time = est * hour; -+ pgbgp->sub_sus_time = sst * hour; -+ pgbgp->origin_hist_time = oht * day; -+ pgbgp->prefix_hist_time = pht * day; -+ pgbgp->edge_hist_time = eht * day; -+ pgbgp->peer_hist_time = DEFAULT_ORIGIN_HIST; -+ -+ if (file != NULL) -+ pgbgp->storage = strdup (file); -+ else -+ pgbgp->storage = NULL; -+ -+ if (anoms != NULL) -+ pgbgp->anomalies = strdup (anoms); -+ else -+ pgbgp->anomalies = NULL; -+ -+ -+ pgbgp->reuse_q = pqueue_create (); -+ pgbgp->reuse_q->cmp = reuse_cmp; -+ pgbgp->rq_size = 0; -+ pgbgp->lastgc = time (NULL); -+ pgbgp->lastStore = time (NULL); -+ pgbgp->startTime = time (NULL); -+ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_cmd); -+ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_cmd); -+ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_neighbors_cmd); -+ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_neighbors_cmd); -+ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_origins_cmd); -+ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_origins_cmd); -+ pgbgp->edgeT = hash_create_size (131072, edge_key_make, edge_cmp); -+ bgp_pgbgp_restore (); -+ return 0; -+} -+ -+int -+bgp_pgbgp_disable (struct bgp *bgp, afi_t afi, safi_t safi) -+{ -+ UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP); -+ -+ // Clean the tables -+ if (bgp->rib[afi][safi] != NULL) -+ bgp_pgbgp_clean (bgp->rib[afi][safi]); -+ -+ bgp_pgbgp_cleanEdges (); -+ -+ if (pgbgp->storage != NULL) -+ free (pgbgp->storage); -+ -+ if (pgbgp->anomalies != NULL) -+ free (pgbgp->anomalies); -+ -+ struct bgp_pgbgp_peerTime *pr = pgbgp->peerLast; -+ while (pr) -+ { -+ struct bgp_pgbgp_peerTime *cur = pr; -+ pr = pr->next; -+ XFREE (MTYPE_BGP_PGBGP_PEER, cur); -+ } -+ -+ return 0; -+} -+ -+int -+bgp_pgbgp_clean (struct bgp_table *table) -+{ -+ struct bgp_pgbgp_reuse *rnode = NULL; -+ -+ while (pgbgp->rq_size > 0) -+ { -+ rnode = (struct bgp_pgbgp_reuse *) pqueue_dequeue (pgbgp->reuse_q); -+ pgbgp->rq_size -= 1; -+ XFREE (MTYPE_BGP_PGBGP_REUSE, rnode); -+ } -+ pqueue_delete (pgbgp->reuse_q); -+ -+ if (table == NULL) -+ return 0; -+ -+ // Clean the detectors -+ bgp_pgbgp_cleanHistTable (table); -+ -+ bgp_pgbgp_cleanEdges (); -+ -+ -+ // Clean up the RIB nodes -+ for (struct bgp_node * rn = bgp_table_top (table); rn; -+ rn = bgp_route_next (rn)) -+ { -+ int changed = 0; -+ for (struct bgp_info * ri = rn->info; ri; ri = ri->next) -+ { -+ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O -+ | BGP_INFO_SUSPICIOUS_P | BGP_INFO_SUSPICIOUS_E -+ | BGP_INFO_IGNORED_P)) -+ { -+ changed = 1; -+ UNSET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O -+ | BGP_INFO_SUSPICIOUS_P | BGP_INFO_SUSPICIOUS_E -+ | BGP_INFO_IGNORED_P); -+ } -+ } -+ if (changed && rn->info) -+ { -+ struct bgp_info *ri = rn->info; -+ bgp_process (ri->peer->bgp, rn, rn->table->afi, rn->table->safi); -+ } -+ } -+ -+ hash_free (pgbgp->edgeT); -+ return 0; -+} -+ -+ -+int -+bgp_pgbgp_gc (struct bgp_table *table) -+{ -+ struct bgp *bgp = bgp_get_default (); -+ if (!bgp) -+ return 0; -+ -+ // Collect each AFI/SAFI RIB -+ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) -+ for (safi_t safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) -+ { -+ if (!CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP)) -+ continue; -+ struct bgp_table *curTable = bgp->rib[afi][safi]; -+ if (!curTable) -+ continue; -+ bgp_pgbgp_garbageCollectHistTable (curTable); -+ } -+ -+ bgp_pgbgp_garbageCollectEdges (table); -+ -+ return 0; -+} -+ -+int -+bgp_pgbgp_restore (void) -+{ -+ -+ if (pgbgp->storage == NULL) -+ return 0; -+ FILE *file = fopen (pgbgp->storage, "r"); -+ if (!file) -+ return 0; -+ -+ int type = 0; -+ struct prefix p; -+ struct bgp *bgp = bgp_get_default (); -+ struct bgp_node *curNode = NULL; -+ -+ // Get the log store time -+ long long int writetime; -+ fscanf (file, "%lld", &writetime); -+ time_t swtime = writetime; -+ -+ // If it's too old (more than 1 week old), start fresh -+ if (time (NULL) - swtime > 86400 * 7) -+ { -+ fclose (file); -+ return 0; -+ } -+ -+ -+ // Get the PGBGP init time -+ long long int stime; -+ fscanf (file, "%lld", &stime); -+ pgbgp->startTime = stime; -+ -+ while (fscanf (file, "%d", &type) != EOF) -+ { -+ -+ if (type == PREFIX_ID) -+ { -+ char pre[128]; -+ unsigned int afi; -+ unsigned int safi; -+ long long int time; -+ fscanf (file, "%s %u %u %lld", pre, &afi, &safi, &time); -+ str2prefix (pre, &p); -+ struct bgp_table *curTable = bgp->rib[afi][safi]; -+ assert (curTable != NULL); -+ -+ // Create and lock the node -+ curNode = bgp_node_get (curTable, &p); -+ assert (curNode->hist == NULL); -+ -+ // bgp_lock_node(curNode); -+ -+ curNode->hist = -+ XCALLOC (MTYPE_BGP_PGBGP_HIST, sizeof (struct bgp_pgbgp_hist)); -+ assert (curNode->hist != NULL); -+ -+ curNode->hist->p = -+ XCALLOC (MTYPE_BGP_PGBGP_PREFIX, -+ sizeof (struct bgp_pgbgp_prefix)); -+ assert (curNode->hist->p != NULL); -+ -+ curNode->hist->p->lastSeen = time; -+ } -+ else if (type == ORIGIN_ID) -+ { -+ unsigned int ASN; -+ long long int time; -+ fscanf (file, "%u %lld", &ASN, &time); -+ struct bgp_pgbgp_origin *or = XCALLOC (MTYPE_BGP_PGBGP_ORIGIN, -+ sizeof (struct -+ bgp_pgbgp_origin)); -+ or->lastSeen = time; -+ or->originAS = ASN; -+ or->next = curNode->hist->o; -+ curNode->hist->o = or; -+ } -+ else if (type == EDGE_ID) -+ { -+ bgp_pgbgp_restoreEdge (file); -+ } -+ else if (type == PEER_ID) -+ { -+ struct bgp_pgbgp_peerTime *pr; -+ long long int time; -+ union sockunion su; -+ char szsu[128]; -+ fscanf (file, "%s %lld", szsu, &time); -+ str2sockunion (szsu, &su); -+ pr = -+ XCALLOC (MTYPE_BGP_PGBGP_PEER, -+ sizeof (struct bgp_pgbgp_peerTime)); -+ pr->su = su; -+ pr->lastSeen = time; -+ pr->next = pgbgp->peerLast; -+ pgbgp->peerLast = pr; -+ } -+ } -+ -+ fclose (file); -+ return 0; -+} -+ -+int -+bgp_pgbgp_store (struct bgp_table *table) -+{ -+ if (pgbgp->storage == NULL) -+ return 0; -+ char *tmpname = malloc (sizeof (char) * (1 + 4 + strlen (pgbgp->storage))); -+ strcpy (tmpname, pgbgp->storage); -+ strcat (tmpname, ".tmp"); -+ FILE *file = fopen (tmpname, "w"); -+ -+ if (!file) -+ { -+ free (tmpname); -+ return 0; -+ } -+ -+ // Store the current time -+ fprintf (file, "%lld\n", (long long int) time (NULL)); -+ -+ // Store the init time -+ fprintf (file, "%lld\n", (long long int) pgbgp->startTime); -+ -+ // Store the peer times -+ for (struct bgp_pgbgp_peerTime * pr = pgbgp->peerLast; pr; pr = pr->next) -+ { -+ char strSock[128]; -+ sockunion2str (&pr->su, strSock, sizeof (strSock)); -+ -+ if (pr->deprefUntil < time (NULL)) -+ { -+ fprintf (file, "%d %s %lld\n", PEER_ID, strSock, -+ (long long int) pr->lastSeen); -+ } -+ } -+ -+ // Store the tables -+ bgp_pgbgp_storeHistTable (table, file); -+ bgp_pgbgp_storeEdges (table, file); -+ -+ fclose (file); -+ -+ rename (tmpname, pgbgp->storage); -+ -+ free (tmpname); -+ return 0; -+} -+ -+/* -+ Check to see if we've seen the peer recently -+ If not, then we need to return true and not delay routes -+ for awhile -+*/ -+int -+bgp_pgbgp_updatePeer (struct bgp_info *binfo, time_t now) -+{ -+ int status = false; -+ // Find the peer -+ struct bgp_pgbgp_peerTime *pr = pgbgp->peerLast; -+ for (; pr; pr = pr->next) -+ if (sockunion_same (&pr->su, &binfo->peer->su)) -+ break; -+ -+ // If this is a new peer, create it -+ if (pr == NULL) -+ { -+ pr = XCALLOC (MTYPE_BGP_PGBGP_PEER, sizeof (struct bgp_pgbgp_peerTime)); -+ pr->su = binfo->peer->su; -+ pr->next = pgbgp->peerLast; -+ pgbgp->peerLast = pr; -+ -+ } -+ // Is it currently marked as new? -+ if (pr->deprefUntil > now) -+ goto UPPEER_DEPREF; -+ -+ // Have we seen the peer recently? -+ if (pr->lastSeen + pgbgp->peer_hist_time > now) -+ goto UPPEER_CLEAN; -+ -+ // It must not have been seen lately, depref it -+ pr->deprefUntil = now + PGBGP_PEER_GRACE; -+ -+ -+UPPEER_DEPREF: -+ status = true; -+ -+UPPEER_CLEAN: -+ pr->lastSeen = now; -+ -+ return status; -+} -+ -+ -+/* -+ Returns whether or not the sub-prefix should be ignored -+*/ -+int -+bgp_pgbgp_shouldIgnore (struct bgp_node *super, struct bgp_info *selected) -+{ -+ if (!selected || CHECK_FLAG (selected->flags, BGP_INFO_SUSPICIOUS_P)) -+ return false; -+ return true; -+} -+ -+/* -+ This is a special case function for smoothly handling sub-prefix hijacks. -+ -+ It handles the following 2 events: -+ -+ Event 1: The super-prefix of an anomalous prefix has a route through a non-anomalous -+ -+ Event 1: An anomalous sub-prefix is ignored, but no best route for the super-prefix exists -+ Response: Announce the sub-prefix until the super-prefix comes back -+ -+ Event 2: A super-prefix comes back to the RIB and its anomalous sub-prefix is in use -+ Response: Ignore the sub-prefix again -+ */ -+ -+ -+int -+bgp_pgbgp_rib_updated (struct bgp_node *rn, struct bgp_info *old_best, -+ struct bgp_info *new_best) -+{ -+ // return 0; -+ struct bgp_pgbgp_hist *hist = rn->hist; -+ if (!hist) -+ return 0; -+ if (!hist->p) -+ return 0; -+ time_t t_now = time (NULL); -+ -+ /* -+ If we can't avoid the sub-prefix by routing to the super-prefix, -+ then route as normal to the sub-prefix -+ */ -+ if (!bgp_pgbgp_shouldIgnore (rn, new_best)) -+ { -+ for (struct bgp_pgbgp_avoid * cur = hist->p->avoid; cur; -+ cur = cur->next) -+ { -+ if (cur->avoidUntil > t_now) -+ { -+ int changed = false; -+ for (struct bgp_info * ri = cur->sub->info; ri; ri = ri->next) -+ { -+ if (CHECK_FLAG (ri->flags, BGP_INFO_IGNORED_P)) -+ { -+ changed = true; -+ UNSET_FLAG (ri->flags, BGP_INFO_IGNORED_P); -+ } -+ } -+ if (changed) -+ { -+ struct bgp_info *ri = cur->sub->info; -+ if (ri && ri->peer && ri->peer->bgp) -+ bgp_process (ri->peer->bgp, cur->sub, -+ cur->sub->table->afi, cur->sub->table->safi); -+ -+ } -+ -+ } -+ } -+ } -+ -+ /* -+ If we can avoid the sub-prefix by routing to the super-prefix, -+ then do so -+ */ -+ -+ else -+ { -+ for (struct bgp_pgbgp_avoid * cur = hist->p->avoid; cur; -+ cur = cur->next) -+ { -+ if (cur->avoidUntil > t_now) -+ { -+ int changed = false; -+ for (struct bgp_info * ri = cur->sub->info; ri; ri = ri->next) -+ { -+ if (!CHECK_FLAG (ri->flags, BGP_INFO_IGNORED_P)) -+ { -+ changed = true; -+ SET_FLAG (ri->flags, BGP_INFO_IGNORED_P); -+ } -+ } -+ if (changed) -+ { -+ struct bgp_info *ri = cur->sub->info; -+ if (ri && ri->peer && ri->peer->bgp) -+ bgp_process (ri->peer->bgp, cur->sub, -+ cur->sub->table->afi, cur->sub->table->safi); -+ } -+ } -+ } -+ } -+ -+ /* -+ if (old_best && !new_best) -+ { -+ time_t t_now = time(NULL); -+ for (struct bgp_pgbgp_avoid * cur = hist->p->avoid; cur; -+ cur = cur->next) -+ { -+ if (cur->avoidUntil > t_now) -+ { -+ for (struct bgp_info * ri = cur->sub->info; ri; ri = ri->next) -+ UNSET_FLAG (ri->flags, BGP_INFO_IGNORED_P); -+ -+ struct bgp_info *ri = cur->sub->info; -+ if (ri && ri->peer && ri->peer->bgp) -+ bgp_process (ri->peer->bgp, cur->sub, cur->sub->table->afi, -+ cur->sub->table->safi); -+ } -+ } -+ } -+ -+ -+ else if (!old_best && new_best) -+ { -+ time_t t_now = time(NULL); -+ for (struct bgp_pgbgp_avoid * av = hist->p->avoid; av; av = av->next) -+ { -+ struct bgp_info * ri = av->sub->info; -+ if (av->avoidUntil > t_now && ri && !CHECK_FLAG(ri->flags, BGP_INFO_IGNORED_P)) -+ { -+ for (; ri; ri = ri->next) -+ SET_FLAG (ri->flags, BGP_INFO_IGNORED_P); -+ ri = av->sub->info; -+ if (ri && ri->peer && ri->peer->bgp) -+ bgp_process (ri->peer->bgp, av->sub, -+ av->sub->table->afi, av->sub->table->safi); -+ -+ } -+ } -+ } -+ */ -+ return 0; -+} -+ -+int -+bgp_pgbgp_update (struct bgp_info *binfo, struct attr *at, -+ struct bgp_node *rn) -+{ -+ time_t t_now = time (NULL); -+ -+ // Clean up the reuse list -+ bgp_pgbgp_reuse (t_now); -+ -+ -+ if (!rn->hist) -+ { -+ rn->hist = -+ XCALLOC (MTYPE_BGP_PGBGP_HIST, sizeof (struct bgp_pgbgp_hist)); -+ // Get the PGBGP history lock on rn -+ bgp_lock_node (rn); -+ } -+ -+ struct bgp_node *superhn = NULL; -+ -+ // implicit lock from node_get -+ superhn = findSuper (rn->table, &rn->p, t_now); -+ -+ int newPeer = bgp_pgbgp_updatePeer (binfo, t_now); -+ bgp_pgbgp_updateOrigin (rn->hist, binfo, at, rn, t_now, newPeer); -+ bgp_pgbgp_updatePrefix (rn->hist, superhn, binfo, at, rn, t_now, newPeer); -+ bgp_pgbgp_updateEdge (rn->hist, binfo, at, rn, t_now, newPeer); -+ -+ if (superhn != NULL) -+ bgp_unlock_node (superhn); -+ -+ -+ -+ // GC and storage must be last, as they update lastSeen values of objects -+ // which would cause new routes to be recently seen, which is undesired behavior -+ // Make sure you don't collect anything that might be in use! -+ if (t_now >= pgbgp->lastgc + PGBGP_GC_DELTA) -+ { -+ bgp_pgbgp_gc (rn->table); -+ pgbgp->lastgc = t_now; -+ } -+ -+ if (t_now >= pgbgp->lastStore + PGBGP_STORE_DELTA) -+ { -+ bgp_pgbgp_store (rn->table); -+ pgbgp->lastStore = t_now; -+ } -+ -+ -+ -+ return 0; -+} -+ -+ -+ -+ -+/*! --------------- Public PGBGP Interface ------------------ !*/ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+/* --------------- MOAS Detection ------------------ */ -+void -+bgp_pgbgp_storeHistTable (struct bgp_table *table, FILE * file) -+{ -+ time_t t_now; -+ t_now = time (NULL); -+ -+ struct bgp *bgp = bgp_get_default (); -+ if (!bgp) -+ return; -+ -+ // Store each AFI/SAFI RIB -+ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) -+ for (safi_t safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) -+ { -+ if (!CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP)) -+ continue; -+ struct bgp_table *curTable = bgp->rib[afi][safi]; -+ if (!curTable) -+ continue; -+ -+ for (struct bgp_node * rn = bgp_table_top (curTable); rn; -+ rn = bgp_route_next (rn)) -+ { -+ struct bgp_pgbgp_hist *hist = rn->hist; -+ if (hist == NULL) -+ continue; -+ char szPrefix[128]; -+ prefix2str (&rn->p, szPrefix, sizeof (szPrefix)); -+ -+ -+ struct bgp_pgbgp_prefix *pre = hist->p; -+ if (pre && pre->ignoreUntil <= t_now) -+ { -+ if (pre->lastSeen + pgbgp->prefix_hist_time > t_now) -+ fprintf (file, "%d %s %u %u %lld\n", PREFIX_ID, szPrefix, -+ (unsigned int) afi, (unsigned int) safi, -+ (long long int) pre->lastSeen); -+ else -+ continue; -+ } -+ /* Need a prefix in the file before the origins, -+ if no prefix.. skip origins */ -+ else -+ continue; -+ -+ for (struct bgp_pgbgp_origin * cur = hist->o; cur; -+ cur = cur->next) -+ { -+ if (cur->deprefUntil > t_now) -+ continue; -+ -+ if (cur->lastSeen + pgbgp->origin_hist_time > t_now) -+ fprintf (file, "%d %u %lld\n", ORIGIN_ID, cur->originAS, -+ (long long int) cur->lastSeen); -+ } -+ -+ } -+ } -+} -+ -+ -+int -+bgp_pgbgp_garbageCollectHistTable (struct bgp_table *table) -+{ -+ time_t t_now; -+ t_now = time (NULL); -+ -+ -+ for (struct bgp_node * rn = bgp_table_top (table); rn; -+ rn = bgp_route_next (rn)) -+ { -+ int collect = false; -+ struct bgp_pgbgp_hist *hist = rn->hist; -+ if (hist == NULL) -+ continue; -+ -+ struct bgp_pgbgp_origin *cur = hist->o; -+ struct bgp_pgbgp_prefix *pre = hist->p; -+ struct bgp_pgbgp_origin *parent = NULL; -+ -+ int used = false; -+ if (cur != NULL || pre != NULL) -+ used = true; -+ -+ while (cur != NULL) -+ { -+ // Update the lastSeen time w/ originInRIB -+ if (originInRIB (rn, cur)) -+ cur->lastSeen = t_now; -+ -+ collect = false; -+ -+ // Collect if old -+ if (cur->lastSeen + pgbgp->origin_hist_time <= t_now) -+ collect = true; -+ -+ // Collect if anomaly just became okay but not seen since last collection -+ if (cur->deprefUntil != 0 && cur->deprefUntil < t_now) -+ { -+ if (cur->lastSeen < pgbgp->lastgc) -+ collect = true; -+ cur->deprefUntil = 0; -+ } -+ -+ if (collect) -+ { -+ if (parent == NULL) -+ hist->o = cur->next; -+ else -+ parent->next = cur->next; -+ -+ // Delete cur, parent doesn't change -+ struct bgp_pgbgp_origin *del = cur; -+ cur = cur->next; -+ XFREE (MTYPE_BGP_PGBGP_ORIGIN, del); -+ } -+ else -+ { -+ parent = cur; -+ cur = cur->next; -+ } -+ } -+ -+ // Update the lastSeen time w/ prefixInRIB -+ if (pre && prefixInRIB (rn, pre)) -+ pre->lastSeen = t_now; -+ -+ collect = false; -+ -+ // Collect if old -+ if (pre && pre->lastSeen + pgbgp->prefix_hist_time <= t_now) -+ collect = true; -+ -+ // Collect if anomaly just became okay but not seen since last collection -+ if (pre && pre->ignoreUntil != 0 && pre->ignoreUntil < t_now) -+ { -+ if (pre->lastSeen < pgbgp->lastgc) -+ collect = true; -+ pre->ignoreUntil = 0; -+ } -+ -+ if (collect) -+ { -+ for (struct bgp_pgbgp_avoid * av = pre->avoid; av;) -+ { -+ struct bgp_pgbgp_avoid *del = av; -+ av = av->next; -+ bgp_unlock_node (del->sub); -+ XFREE (MTYPE_BGP_PGBGP_AVOID, del); -+ } -+ -+ XFREE (MTYPE_BGP_PGBGP_PREFIX, pre); -+ hist->p = NULL; -+ } -+ -+ // If the node isn't in use, remove it -+ if (used && hist->o == NULL && hist->p == NULL) -+ { -+ XFREE (MTYPE_BGP_PGBGP_HIST, hist); -+ rn->hist = NULL; -+ bgp_unlock_node (rn); -+ } -+ } -+ -+ return 0; -+} -+ -+void -+bgp_pgbgp_cleanHistTable (struct bgp_table *table) -+{ -+ // Clean up the RIB nodes -+ for (struct bgp_node * rn = bgp_table_top (table); rn; -+ rn = bgp_route_next (rn)) -+ { -+ struct bgp_pgbgp_hist *hist = rn->hist; -+ if (hist == NULL) -+ continue; -+ -+ if (hist->p) -+ { -+ for (struct bgp_pgbgp_avoid * av = hist->p->avoid; av;) -+ { -+ struct bgp_pgbgp_avoid *del = av; -+ av = av->next; -+ bgp_unlock_node (del->sub); -+ XFREE (MTYPE_BGP_PGBGP_AVOID, del); -+ } -+ hist->p->avoid = NULL; -+ XFREE (MTYPE_BGP_PGBGP_PREFIX, hist->p); -+ hist->p = NULL; -+ } -+ -+ for (struct bgp_pgbgp_origin * cur = hist->o; cur;) -+ { -+ struct bgp_pgbgp_origin *next = cur->next; -+ XFREE (MTYPE_BGP_PGBGP_ORIGIN, cur); -+ cur = next; -+ } -+ hist->o = NULL; -+ XFREE (MTYPE_BGP_PGBGP_HIST, hist); -+ rn->hist = NULL; -+ bgp_unlock_node (rn); -+ } -+} -+ -+void -+bgp_pgbgp_logOriginAnomaly (as_t asn, struct bgp_node *rn, struct attr *at) -+{ -+ assert (pgbgp); -+ if (!pgbgp->anomalies) -+ return; -+ FILE *file = fopen (pgbgp->anomalies, "a"); -+ if (!file) -+ return; -+ -+ char pre[256]; -+ prefix2str (&rn->p, pre, sizeof (pre)); -+ -+ // MOAS | TIME | NEXTHOP | PREFIX | SUSPICIOUS_ORIGIN | TRUSTED_ORIGINS | PATH -+ fprintf (file, "%d|%lld|%s|%s|%d|", MOAS, (long long int) time (NULL), -+ inet_ntoa (at->nexthop), pre, asn); -+ -+ -+ // Print the trusted origins -+ assert (rn->hist); -+ assert (rn->hist->o); -+ -+ struct bgp_pgbgp_hist *hist = rn->hist; -+ -+ for (struct bgp_pgbgp_origin * cur = hist->o; cur != NULL; cur = cur->next) -+ { -+ if (cur->deprefUntil > time (NULL)) -+ continue; -+ fprintf (file, "%d", cur->originAS); -+ if (cur->next != NULL) -+ fprintf (file, " "); -+ } -+ -+ fprintf (file, " |%s\n", aspath_print (at->aspath)); -+ fclose (file); -+} -+ -+int -+bgp_pgbgp_updateOrigin (struct bgp_pgbgp_hist *hist, struct bgp_info *binfo, -+ struct attr *at, struct bgp_node *rn, time_t t_now, -+ int newPeer) -+{ -+ struct bgp_pgbgp_pathSet pathOrigins; -+ struct bgp_pgbgp_origin *pi = NULL; -+ int status = 0; -+ struct bgp_pgbgp_reuse *r; -+ pathOrigins = bgp_pgbgp_pathOrigin (at->aspath); -+ -+ -+ for (int i = 0; i < pathOrigins.length; i++) -+ { -+ as_t pathOrigin = pathOrigins.ases[i]; -+ -+ /* Is the Origin AS in the history? */ -+ for (pi = hist->o; pi; pi = pi->next) -+ if (pi->originAS == pathOrigin) -+ break; -+ -+ if (pi == NULL) -+ { -+ pi = -+ XCALLOC (MTYPE_BGP_PGBGP_ORIGIN, -+ sizeof (struct bgp_pgbgp_origin)); -+ pi->next = hist->o; -+ pi->originAS = pathOrigin; -+ hist->o = pi; -+ } -+ -+ // If this is our first origin for the prefix, let the sub-prefix -+ // check take care of it -+ if (pi->next == NULL) -+ goto UPO_CLEAN; -+ -+ /* Is the origin currently marked as suspicious? */ -+ if (pi->deprefUntil > t_now) -+ goto UPO_DEPREF; -+ -+ /* Have we seen the origin recently? */ -+ if (pi->lastSeen + pgbgp->origin_hist_time > t_now) -+ goto UPO_CLEAN; -+ -+#ifndef PGBGP_DEBUG -+ /* Are we within the initial grace period? */ -+ if (newPeer) -+ goto UPO_CLEAN; -+#endif -+ -+ /* It must not be in recent history, depref origin for first time */ -+ pi->deprefUntil = t_now + pgbgp->origin_sus_time; -+ bgp_pgbgp_logOriginAnomaly (pathOrigin, rn, at); -+ -+ r = XCALLOC (MTYPE_BGP_PGBGP_REUSE, sizeof (struct bgp_pgbgp_reuse)); -+ r->type = PGBGP_REUSE_ORIGIN; -+ r->deprefUntil = pi->deprefUntil; -+ r->data.origin.originAS = pathOrigin; -+ r->data.origin.rn = rn; -+ bgp_lock_node (rn); -+ pqueue_enqueue (r, pgbgp->reuse_q); -+ pgbgp->rq_size += 1; -+ -+ -+ UPO_DEPREF: -+ SET_FLAG (binfo->flags, BGP_INFO_SUSPICIOUS_O); -+ status = BGP_INFO_SUSPICIOUS_O; -+ -+ UPO_CLEAN: -+ pi->lastSeen = t_now; -+ } -+ return status; -+} -+ -+int -+bgp_pgbgp_reuseOrigin (struct bgp_pgbgp_r_origin data) -+{ -+ struct bgp_info *ri; -+ int numChanged = 0; -+ time_t t_now = time (NULL); -+ assert (data.rn->hist != NULL); -+ -+ // Repreference paths for this prefix that are now okay -+ for (ri = data.rn->info; ri; ri = ri->next) -+ { -+ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O)) -+ { -+ struct bgp_pgbgp_pathSet pathOrigins; -+ pathOrigins = bgp_pgbgp_pathOrigin (ri->attr->aspath); -+ int numOkay = 0; -+ for (int i = 0; i < pathOrigins.length; i++) -+ { -+ as_t pathOrigin = pathOrigins.ases[i]; -+ // Find the origin -+ struct bgp_pgbgp_origin *o = NULL; -+ for (o = data.rn->hist->o; o != NULL; o = o->next) -+ if (o->originAS == pathOrigin) -+ break; -+ /* -+ if (o == NULL) { -+ for(struct bgp_pgbgp_origin * z = data.rn->hist->o; z != NULL; z = z->next) -+ printf("Known origin: %d\n", z->originAS); -+ char pre[128]; -+ prefix2str(&data.rn->p, pre, 128); -+ printf("%s : %s : %d\n", pre, ri->attr->aspath->str, pathOrigin); -+ } -+ */ -+ assert (o != NULL); -+ -+ if (o->deprefUntil <= t_now) -+ numOkay += 1; -+ } -+ if (numOkay == pathOrigins.length) -+ { -+ UNSET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O); -+ numChanged += 1; -+ } -+ } -+ } -+ -+ ri = data.rn->info; -+ -+ // Rerun the decision process? -+ if (numChanged > 0) -+ bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi, -+ data.rn->table->safi); -+ -+ -+ /* -+ // Remove this (origin,prefix) pair from the normal database -+ // if it's not still in the RIB -+ struct bgp_pgbgp_hist *hist = rn->hist; -+ struct bgp_pgbgp_origin * cur = hist->o; -+ struct bgp_pgbgp_origin * parent = NULL; -+ -+ // Find the origin AS node -+ while(cur != NULL) -+ { -+ if (cur->originAS == data.originAS) -+ { -+ // Delete the node if it hasn't been seen -+ // since the last storage run -+ if (cur->lastSeen < pgbgp->lastStore) { -+ // Delete this node -+ if (parent == NULL) -+ hist->o = cur->next; -+ else -+ parent->next = cur->next; -+ -+ XFREE(MTYPE_BGP_PGBGP_ORIGIN, cur); -+ } -+ break; -+ } -+ parent = cur; -+ cur = cur->next; -+ } -+ */ -+ -+ bgp_unlock_node (data.rn); -+ return 0; -+} -+ -+/*! --------------- MOAS Detection ------------------ !*/ -+ -+ -+/* --------------- Sub-Prefix Detection ------------------ */ -+ -+ -+ -+ -+ -+void -+bgp_pgbgp_logSubprefixAnomaly (as_t asn, struct bgp_node *rn, struct attr *at, -+ struct bgp_node *super) -+{ -+ assert (pgbgp); -+ if (!pgbgp->anomalies) -+ return; -+ FILE *file = fopen (pgbgp->anomalies, "a"); -+ if (!file) -+ return; -+ -+ char pre[256]; -+ prefix2str (&rn->p, pre, sizeof (pre)); -+ -+ char superpre[256]; -+ prefix2str (&super->p, superpre, sizeof (superpre)); -+ -+ // SUBPREFIX | TIME | NEXTHOP | PREFIX | SUPER-PREFIX | SUSPICIOUS_ORIGIN | TRUSTED_ORIGINS | PATH -+ fprintf (file, "%d|%lld|%s|%s|%s|%d|", SUBPREFIX, -+ (long long int) time (NULL), inet_ntoa (at->nexthop), pre, -+ superpre, asn); -+ -+ // Print the trusted origins -+ assert (super->hist); -+ assert (super->hist->o); -+ -+ struct bgp_pgbgp_hist *hist = super->hist; -+ -+ for (struct bgp_pgbgp_origin * cur = hist->o; cur != NULL; cur = cur->next) -+ { -+ if (cur->deprefUntil > time (NULL)) -+ continue; -+ fprintf (file, "%d", cur->originAS); -+ if (cur->next != NULL) -+ fprintf (file, " "); -+ } -+ -+ fprintf (file, " |%s\n", aspath_print (at->aspath)); -+ fclose (file); -+} -+ -+/* -+ If the first path is a prefix of the second, then return true -+ */ -+ -+static int -+bgp_pgbgp_pathIsPrefix(struct aspath *trusted, struct aspath * new) -+{ -+ if (trusted == new) -+ return true; -+ -+ struct assegment *seg1 = trusted->segments; -+ struct assegment *seg2 = new->segments; -+ -+ while (seg1 || seg2) -+ { -+ if ((!seg1 && seg2) || (seg1 && !seg2)) -+ return false; -+ if (seg1->type != seg2->type) -+ return false; -+ -+ if (seg1->length > seg2->length) -+ return false; -+ -+ for(int i = 0; i < seg1->length; i++) -+ if (seg1->as[i] != seg2->as[i]) -+ return false; -+ -+ seg1 = seg1->next; -+ seg2 = seg2->next; -+ } -+ -+ return true; -+} -+ -+int -+bgp_pgbgp_updatePrefix (struct bgp_pgbgp_hist *hist, -+ struct bgp_node *supernode, struct bgp_info *binfo, -+ struct attr *at, struct bgp_node *rn, time_t t_now, -+ int newPeer) -+{ -+ struct bgp_pgbgp_prefix *pre = NULL; -+ struct bgp_pgbgp_reuse *r = NULL; -+ int status = 0; -+ int changed = false; -+ -+ pre = hist->p; -+ -+ -+ /* Do we have this prefix? */ -+ if (pre == NULL) -+ { -+ pre = -+ XCALLOC (MTYPE_BGP_PGBGP_PREFIX, sizeof (struct bgp_pgbgp_prefix)); -+ hist->p = pre; -+ } -+ -+ /* Is the prefix currently marked as suspicious? */ -+ if (pre->ignoreUntil > t_now) -+ { -+ goto UPP_IGNORE; -+ } -+ -+ /* Should this neighbor be avoided for this prefix because it -+ sent us info. about a suspicious sub-prefix? */ -+ for (struct bgp_pgbgp_avoid * av = hist->p->avoid; av; av = av->next) -+ { -+ if (binfo->peer->as == av->peerASN && av->avoidUntil > t_now) -+ { -+ SET_FLAG (binfo->flags, BGP_INFO_SUSPICIOUS_P); -+ status = BGP_INFO_SUSPICIOUS_P; -+ goto UPP_DONE; -+ } -+ } -+ -+ /* Have we seen the prefix recently? */ -+ if (pre->lastSeen + pgbgp->prefix_hist_time > t_now) -+ goto UPP_DONE; -+ -+#ifndef PGBGP_DEBUG -+ /* Are we within the initial grace period? */ -+ if (newPeer) -+ goto UPP_DONE; -+#endif -+ -+ /* Is there a less specific *in recent history* that this could be hijacking? */ -+ if (supernode == NULL) -+ goto UPP_DONE; -+ -+ /* Does this path the super-net's non-anomalous path from this peer? If so it's okay */ -+ int found = false; -+ for (struct bgp_info * ri = supernode->info; ri; ri = ri->next) -+ { -+ if (ri->peer->as == binfo->peer->as) -+ { -+ if (!ANOMALOUS(ri->flags) && bgp_pgbgp_pathIsPrefix(ri->attr->aspath, at->aspath)) -+ found = true; -+ break; -+ } -+ } -+ -+ if (found) -+ goto UPP_DONE; -+ -+ /* -+ It's not in recent history, and there is a less specific currently in use -+ Response: -+ . Ignore this prefix -+ . Make the less specific's route for this neighbor suspicious -+ */ -+ -+ -+ pre->ignoreUntil = t_now + pgbgp->sub_sus_time; -+ -+ struct bgp_pgbgp_pathSet pathOrigins; -+ pathOrigins = bgp_pgbgp_pathOrigin (at->aspath); -+ for (int i = 0; i < pathOrigins.length; i++) -+ bgp_pgbgp_logSubprefixAnomaly (pathOrigins.ases[i], rn, at, supernode); -+ -+ -+ -+ r = XCALLOC (MTYPE_BGP_PGBGP_REUSE, sizeof (struct bgp_pgbgp_reuse)); -+ r->type = PGBGP_REUSE_PREFIX; -+ r->deprefUntil = pre->ignoreUntil; -+ r->data.prefix.rn = rn; -+ r->data.prefix.rnsuper = supernode; -+ bgp_lock_node (rn); -+ bgp_lock_node (supernode); -+ pqueue_enqueue (r, pgbgp->reuse_q); -+ pgbgp->rq_size += 1; -+ -+UPP_IGNORE: -+ // Sanity check -+ if (supernode == NULL) -+ goto UPP_DONE; -+ -+ /* Set the less specific's route from this peer to suspicious */ -+ changed = false; -+ -+ for (struct bgp_info * ri = supernode->info; ri; ri = ri->next) -+ { -+ if (ri->peer->as == binfo->peer->as) -+ { -+ if (!CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_P)) -+ { -+ SET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_P); -+ changed = true; -+ } -+ break; -+ } -+ } -+ -+ // Make note of it in the less specific's history information -+ found = false; -+ struct bgp_pgbgp_hist *superhist = supernode->hist; -+ -+ if (superhist && superhist->p) -+ { -+ for (struct bgp_pgbgp_avoid * av = superhist->p->avoid; av; -+ av = av->next) -+ { -+ if (av->peerASN == binfo->peer->as) -+ { -+ if (av->avoidUntil < pre->ignoreUntil) -+ av->avoidUntil = pre->ignoreUntil; -+ found = true; -+ break; -+ } -+ } -+ if (!found) -+ { -+ struct bgp_pgbgp_avoid *newavoid = -+ XCALLOC (MTYPE_BGP_PGBGP_AVOID, sizeof (struct bgp_pgbgp_avoid)); -+ newavoid->peerASN = binfo->peer->as; -+ newavoid->avoidUntil = pre->ignoreUntil; -+ newavoid->next = superhist->p->avoid; -+ newavoid->sub = rn; -+ bgp_lock_node (rn); -+ superhist->p->avoid = newavoid; -+ } -+ } -+ /* -+ ignore this route unless the supernet's node -+ is only a placeholder from loaded pgbgp data -+ */ -+ if (bgp_pgbgp_shouldIgnore (supernode, bgp_pgbgp_selected (supernode))) -+ { -+ SET_FLAG (binfo->flags, BGP_INFO_IGNORED_P); -+ status = BGP_INFO_IGNORED_P; -+ } -+ if (changed) -+ { -+ struct bgp_info *ri = supernode->info; -+ bgp_process (ri->peer->bgp, supernode, supernode->table->afi, -+ supernode->table->safi); -+ } -+ -+UPP_DONE: -+ pre->lastSeen = t_now; -+ -+ return status; -+} -+ -+int -+bgp_pgbgp_reusePrefix (struct bgp_pgbgp_r_prefix data) -+{ -+ struct bgp_info *ri = NULL; -+ -+ time_t t_now = time (NULL); -+ -+ // Repreference all routes for this node -+ for (ri = data.rn->info; ri; ri = ri->next) -+ UNSET_FLAG (ri->flags, BGP_INFO_IGNORED_P); -+ ri = data.rn->info; -+ -+ // Rerun the decision process -+ if (ri != NULL) -+ bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi, -+ data.rn->table->safi); -+ -+ -+ // Remove the avoid nodes from the super -+ struct bgp_pgbgp_hist *superhist = data.rnsuper->hist; -+ if (superhist != NULL && superhist->p != NULL) -+ { -+ struct bgp_pgbgp_avoid *parent = NULL; -+ for (struct bgp_pgbgp_avoid * av = superhist->p->avoid; av;) -+ { -+ int numChanged = 0; -+ if (av->avoidUntil <= t_now) -+ { -+ struct bgp_pgbgp_avoid *del = av; -+ av = av->next; -+ if (parent == NULL) -+ superhist->p->avoid = av; -+ else -+ parent->next = av; -+ -+ // Repreference any routes -+ for (ri = data.rnsuper->info; ri; ri = ri->next) -+ { -+ if (ri->peer->as == del->peerASN) -+ { -+ UNSET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_P); -+ numChanged += 1; -+ break; -+ } -+ } -+ ri = data.rnsuper->info; -+ -+ if (numChanged > 0 && ri != NULL) -+ bgp_process (ri->peer->bgp, data.rnsuper, -+ data.rnsuper->table->afi, -+ data.rnsuper->table->safi); -+ bgp_unlock_node (del->sub); -+ XFREE (MTYPE_BGP_PGBGP_AVOID, del); -+ } -+ else -+ { -+ parent = av; -+ av = av->next; -+ } -+ } -+ } -+ -+ // Remove this prefix from the normal database -+ // if it hasn't been seen in the RIB since the last -+ // storage run -+ /* -+ struct bgp_pgbgp_hist *hist = rn->hist; -+ struct bgp_pgbgp_prefix * pre = hist->p; -+ -+ if (pre && pre->lastSeen < pgbgp->lastStore) -+ { -+ // Delete this node -+ for(struct bgp_pgbgp_avoid * av = hist->p->avoid; av;) -+ { -+ struct bgp_pgbgp_avoid *del = av; -+ av = av->next; -+ bgp_unlock_node(del->sub); -+ XFREE (MTYPE_BGP_PGBGP_AVOID, del); -+ } -+ XFREE(MTYPE_BGP_PGBGP_PREFIX, pre); -+ hist->p = NULL; -+ } -+ */ -+ bgp_unlock_node (data.rn); -+ bgp_unlock_node (data.rnsuper); -+ return 0; -+} -+ -+/*! --------------- Sub-Prefix Detection ------------------ !*/ -+ -+ -+ -+ -+ -+/* --------------- Edge Detection ------------------ */ -+ -+static void -+edge_store_clear_iterator (struct hash_backet *backet, void *file) -+{ -+ struct bgp_pgbgp_edge *hedge = backet->data; -+} -+ -+static void -+edge_store_iterator (struct hash_backet *backet, FILE * file) -+{ -+ struct bgp_pgbgp_edge *hedge = backet->data; -+ time_t t_now = time (NULL); -+ if (hedge->deprefUntil > t_now) -+ return; -+ if (hedge->lastSeen + pgbgp->edge_hist_time > t_now) -+ { -+ fprintf (file, "%d %u %u %lld\n", EDGE_ID, hedge->e.a, hedge->e.b, -+ (long long int) hedge->lastSeen); -+ } -+} -+ -+ -+void -+bgp_pgbgp_storeEdges (struct bgp_table *table, FILE * file) -+{ -+ hash_iterate (pgbgp->edgeT, -+ (void (*)(struct hash_backet *, void *)) -+ edge_store_iterator, file); -+ return; -+} -+ -+ -+int -+bgp_pgbgp_restoreEdge (FILE * file) -+{ -+ unsigned int a, b; -+ long long int lastSeen; -+ fscanf (file, "%u %u %lld", &a, &b, &lastSeen); -+ struct bgp_pgbgp_edge finder; -+ finder.e.a = a; -+ finder.e.b = b; -+ finder.lastSeen = lastSeen; -+ struct bgp_pgbgp_edge *hedge = -+ hash_get (pgbgp->edgeT, &finder, edge_hash_alloc); -+ hedge->lastSeen = finder.lastSeen; -+ return 0; -+} -+ -+unsigned int -+edge_key_make (void *p) -+{ -+ struct bgp_pgbgp_edge *pe = p; -+ struct edge *e = &pe->e; -+ return (e->a << 16) + e->b; -+} -+ -+static int -+edge_cmp (const void *arg1, const void *arg2) -+{ -+ -+ const struct edge *e1 = &((const struct bgp_pgbgp_edge *) arg1)->e; -+ const struct edge *e2 = &((const struct bgp_pgbgp_edge *) arg2)->e; -+ if (e1->a == e2->a && e1->b == e2->b) -+ return 1; -+ return 0; -+} -+ -+static void * -+edge_hash_alloc (void *arg) -+{ -+ struct bgp_pgbgp_edge *hedge = -+ XCALLOC (MTYPE_BGP_PGBGP_EDGE, sizeof (struct bgp_pgbgp_edge)); -+ struct bgp_pgbgp_edge *lookup = arg; -+ if (hedge == NULL) -+ return NULL; -+ hedge->e = lookup->e; -+ return hedge; -+} -+ -+ -+static void -+edge_gc_iterator (struct hash_backet *backet, time_t * time) -+{ -+ time_t t_now = *time; -+ struct bgp_pgbgp_edge *hedge = backet->data; -+ -+ int collect = false; -+ -+ // Collect if we haven't seen it in awhile -+ if (hedge->lastSeen + pgbgp->edge_hist_time <= t_now) -+ collect = true; -+ -+ // Collect if it has just gotten out of anomaly stage -+ // but hasn't been in the RIB since the last GC -+ if (hedge->deprefUntil != 0 && hedge->deprefUntil < t_now) -+ { -+ if (hedge->lastSeen < pgbgp->lastgc) -+ collect = true; -+ hedge->deprefUntil = 0; -+ } -+ -+ if (collect) -+ { -+ struct bgp_pgbgp_edge *ret = hash_release (pgbgp->edgeT, hedge); -+ assert (ret != NULL); -+ XFREE (MTYPE_BGP_PGBGP_EDGE, hedge); -+ } -+} -+ -+ -+ -+static void -+edge_update_iterator (struct hash_backet *backet, void *v) -+{ -+ struct aspath *p = backet->data; -+ time_t t_now = time (NULL); -+ int first = true; -+ -+ struct edge cur; -+ cur.a = 0; -+ cur.b = 0; -+ struct assegment *seg; -+ struct bgp_pgbgp_edge *hedge = NULL; -+ for (seg = p->segments; seg; seg = seg->next) -+ { -+ for (int i = 0; i < seg->length; i++) -+ { -+ cur.a = cur.b; -+ cur.b = seg->as[i]; -+ if (first) -+ { -+ first = false; -+ continue; -+ } -+ if (cur.a == cur.b) -+ continue; -+ // printf("%d -- %d\n", cur.a, cur.b); -+ struct bgp_pgbgp_edge finder; -+ finder.e = cur; -+ hedge = hash_lookup (pgbgp->edgeT, &finder); -+ -+ if (!hedge) -+ continue; -+ hedge->lastSeen = t_now; -+ } -+ } -+} -+ -+int -+bgp_pgbgp_garbageCollectEdges (struct bgp_table *table) -+{ -+ // Update the timings -+ hash_iterate (ashash, -+ (void (*)(struct hash_backet *, void *)) -+ edge_update_iterator, NULL); -+ -+ // Perform the collection -+ time_t t_now = time (NULL); -+ hash_iterate (pgbgp->edgeT, -+ (void (*)(struct hash_backet *, void *)) -+ edge_gc_iterator, &t_now); -+ return 0; -+} -+ -+static void -+edge_clean_iterator (struct hash_backet *backet, void *a1) -+{ -+ struct bgp_pgbgp_edge *hedge = backet->data; -+ struct bgp_pgbgp_edge *ret = hash_release (pgbgp->edgeT, hedge); -+ assert (ret != NULL); -+ XFREE (MTYPE_BGP_PGBGP_EDGE, hedge); -+} -+ -+static void -+bgp_pgbgp_cleanEdges (void) -+{ -+ if (pgbgp->edgeT != NULL) -+ { -+ hash_iterate (pgbgp->edgeT, -+ (void (*)(struct hash_backet *, void *)) -+ edge_clean_iterator, NULL); -+ hash_free (pgbgp->edgeT); -+ } -+ return; -+} -+ -+void -+bgp_pgbgp_logEdgeAnomaly (struct bgp_node *rn, struct attr *at, -+ struct edge *edge) -+{ -+ assert (pgbgp); -+ if (!pgbgp->anomalies) -+ return; -+ FILE *file = fopen (pgbgp->anomalies, "a"); -+ if (!file) -+ return; -+ -+ char pre[256]; -+ prefix2str (&rn->p, pre, sizeof (pre)); -+ -+ // EDGE | TIME | NEXTHOP | PREFIX | PATH | Edge.a | Edge.b -+ -+ fprintf (file, "%d|%lld|%s|%s|%s|%d|%d\n", EDGE, -+ (long long int) time (NULL), inet_ntoa (at->nexthop), pre, -+ aspath_print (at->aspath), edge->a, edge->b); -+ -+ fclose (file); -+} -+ -+ -+int -+bgp_pgbgp_updateEdge (struct bgp_pgbgp_hist *hist, struct bgp_info *binfo, -+ struct attr *at, struct bgp_node *rn, time_t t_now, -+ int newPeer) -+{ -+ -+ char first = true; -+ struct edge curEdge; -+ curEdge.a = 0; -+ curEdge.b = 0; -+ -+ -+ if (at->aspath == NULL) -+ return 0; -+ struct assegment *seg = at->aspath->segments; -+ if (seg == NULL) -+ return 0; -+ time_t max_depref = 0; -+ for (seg = at->aspath->segments; seg; seg = seg->next) -+ { -+ for (int i = 0; i < seg->length; i++) -+ { -+ curEdge.a = curEdge.b; -+ curEdge.b = seg->as[i]; -+ if (first) -+ { -+ first = false; -+ continue; -+ } -+ if (curEdge.a == curEdge.b) -+ continue; -+ -+ // We have an edge to consider -+ struct bgp_pgbgp_edge finder; -+ finder.e = curEdge; -+ struct bgp_pgbgp_edge *hedge = -+ hash_get (pgbgp->edgeT, &finder, edge_hash_alloc); -+ -+ // Is this edge marked as suspicious? -+ if (hedge->deprefUntil > t_now) -+ goto UPE_DEPREF; -+ -+ // Have we seen the edge recently? -+ if (hedge->lastSeen + pgbgp->edge_hist_time > t_now) -+ goto UPE_CLEAN; -+#ifndef PGBGP_DEBUG -+ /* Are we within the initial grace period? */ -+ if (newPeer) -+ goto UPE_CLEAN; -+#endif -+ // It must not be in recent history, depref edge for first time -+ hedge->deprefUntil = t_now + pgbgp->edge_sus_time; -+ bgp_pgbgp_logEdgeAnomaly (rn, at, &curEdge); -+ -+ -+ UPE_DEPREF: -+ if (hedge->deprefUntil > max_depref) -+ max_depref = hedge->deprefUntil; -+ UPE_CLEAN: -+ hedge->lastSeen = t_now; -+ } -+ } -+ if (max_depref) -+ { -+ SET_FLAG (binfo->flags, BGP_INFO_SUSPICIOUS_E); -+ if (!hist->pEdgeReuse) -+ { -+ struct bgp_pgbgp_reuse *r; -+ r = -+ XCALLOC (MTYPE_BGP_PGBGP_REUSE, sizeof (struct bgp_pgbgp_reuse)); -+ r->type = PGBGP_REUSE_EDGE; -+ r->deprefUntil = max_depref; -+ r->data.edge.rn = rn; -+ bgp_lock_node (rn); -+ pqueue_enqueue (r, pgbgp->reuse_q); -+ pgbgp->rq_size += 1; -+ hist->pEdgeReuse = r; -+ } -+ return BGP_INFO_SUSPICIOUS_E; -+ } -+ -+ return 0; -+} -+ -+int -+bgp_pgbgp_reuseEdge (struct bgp_pgbgp_r_edge data) -+{ -+ -+ // Okay, go through all of the paths for the prefix -+ // and find the path that needs to be updated next and -+ // enqueue it -+ time_t minMax = 0; -+ int numChanged = 0; -+ time_t t_now = time (NULL); -+ -+ for (struct bgp_info * ri = data.rn->info; ri; ri = ri->next) -+ { -+ char first = true; -+ struct edge curEdge = { 0, 0 }; -+ struct assegment *seg; -+ time_t max_depref = 0; -+ -+ for (seg = ri->attr->aspath->segments; seg; seg = seg->next) -+ { -+ for (int i = 0; i < seg->length; i++) -+ { -+ curEdge.a = curEdge.b; -+ curEdge.b = seg->as[i]; -+ if (first) -+ { -+ first = false; -+ continue; -+ } -+ struct bgp_pgbgp_edge finder; -+ finder.e = curEdge; -+ struct bgp_pgbgp_edge *hedge = -+ hash_lookup (pgbgp->edgeT, &finder); -+ if (!hedge) -+ continue; -+ // Is this edge suspicious? -+ if (hedge->deprefUntil > t_now -+ && hedge->deprefUntil > max_depref) -+ max_depref = hedge->deprefUntil; -+ } -+ } -+ -+ if (max_depref) -+ { -+ if (!minMax || max_depref < minMax) -+ minMax = max_depref; -+ } -+ else -+ { -+ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_E)) -+ { -+ UNSET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_E); -+ numChanged += 1; -+ } -+ } -+ } -+ struct bgp_info *ri = data.rn->info; -+ if (numChanged > 0 && ri) -+ bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi, -+ data.rn->table->safi); -+ -+ struct bgp_pgbgp_hist *hist = data.rn->hist; -+ hist->pEdgeReuse = NULL; -+ -+ if (minMax) -+ { -+ struct bgp_pgbgp_reuse *r; -+ r = XCALLOC (MTYPE_BGP_PGBGP_REUSE, sizeof (struct bgp_pgbgp_reuse)); -+ r->type = PGBGP_REUSE_EDGE; -+ r->deprefUntil = minMax; -+ r->data.edge.rn = data.rn; -+ pqueue_enqueue (r, pgbgp->reuse_q); -+ pgbgp->rq_size += 1; -+ hist->pEdgeReuse = r; -+ } -+ else -+ { -+ bgp_unlock_node (data.rn); -+ } -+ -+ return 0; -+} ---- /dev/null -+++ b/bgpd/bgp_pgbgp.h -@@ -0,0 +1,286 @@ -+/* BGP Pretty Good BGP -+ Copyright (C) 2008 University of New Mexico (Josh Karlin) -+ -+This file is part of GNU Zebra. -+ -+GNU Zebra is free software; you can redistribute it and/or modify it -+under the terms of the GNU General Public License as published by the -+Free Software Foundation; either version 2, or (at your option) any -+later version. -+ -+GNU Zebra is distributed in the hope that it will be useful, but -+WITHOUT ANY WARRANTY; without even the implied warranty of -+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+General Public License for more details. -+ -+You should have received a copy of the GNU General Public License -+along with GNU Zebra; see the file COPYING. If not, write to the Free -+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -+02111-1307, USA. */ -+ -+#ifndef _QUAGGA_BGP_PGBGP_H -+#define _QUAGGA_BGP_PGBGP_H -+ -+#include "bgpd.h" -+#include "bgp_route.h" -+#include "table.h" -+ -+#define MOAS 0 -+#define SUBPREFIX 1 -+#define EDGE 2 -+ -+/* Global PGBGP data */ -+struct bgp_pgbgp_config -+{ -+ /* Depref time for a new origin AS */ -+ time_t origin_sus_time; -+ -+ /* Depref time for a new edge */ -+ time_t edge_sus_time; -+ -+ /* Depref time for a new sub-prefix */ -+ time_t sub_sus_time; -+ -+ /* Origin AS Mapping History Length */ -+ time_t origin_hist_time; -+ -+ /* Prefix Mapping History Length */ -+ time_t prefix_hist_time; -+ -+ /* Edge Mapping History Length */ -+ time_t edge_hist_time; -+ -+ /* Peer Mapping History Length */ -+ time_t peer_hist_time; -+ -+ /* The list of depreferenced routes */ -+ struct pqueue *reuse_q; -+ int rq_size; -+ -+ /* Time that the last garbage collection (gc) took place */ -+ time_t lastgc; -+ -+ /* History table */ -+ // struct route_table *histT; -+ -+ /* Edge Hash Table */ -+ struct hash *edgeT; -+ -+ /* File path for history storage */ -+ char *storage; -+ -+ /* File path for dump of anomalous routes */ -+ char *anomalies; -+ -+ /* The time that we last stored to disk */ -+ time_t lastStore; -+ -+ /* The time that PGBGP started counting */ -+ time_t startTime; -+ -+ /* Last time each peer was seen */ -+ struct bgp_pgbgp_peerTime *peerLast; -+ -+}; -+ -+ -+struct bgp_pgbgp_peerTime -+{ -+ struct bgp_pgbgp_peerTime *next; -+ time_t lastSeen; -+ union sockunion su; -+ time_t deprefUntil; -+}; -+ -+struct edge -+{ -+ as_t a; -+ as_t b; -+}; -+ -+/* -+ Avoid the neighbors for the less specific that told you about -+ the more specific -+ */ -+struct bgp_pgbgp_avoid -+{ -+ struct bgp_pgbgp_avoid *next; -+ time_t avoidUntil; -+ as_t peerASN; -+ struct bgp_node *sub; -+}; -+ -+/* A list of origin ASes for a path -+ Usually it's only one but if the last AS -+ in the path is an AS set, then the whole -+ set must be returned -+*/ -+struct bgp_pgbgp_pathSet -+{ -+ int length; -+ as_t *ases; -+}; -+ -+/* -+ Avoid paths with suspicious origins -+ */ -+struct bgp_pgbgp_origin -+{ -+ struct bgp_pgbgp_origin *next; -+ time_t lastSeen; -+ time_t deprefUntil; -+ as_t originAS; -+}; -+ -+/* -+ Ignore routes for this prefix -+ */ -+struct bgp_pgbgp_prefix -+{ -+ time_t lastSeen; -+ time_t ignoreUntil; -+ struct bgp_pgbgp_avoid *avoid; -+}; -+ -+struct bgp_pgbgp_edge -+{ -+ time_t lastSeen; -+ time_t deprefUntil; -+ struct edge e; -+}; -+ -+struct bgp_pgbgp_hist -+{ -+ struct bgp_pgbgp_origin *o; -+ struct bgp_pgbgp_prefix *p; -+ struct bgp_pgbgp_reuse *pEdgeReuse; -+}; -+ -+struct bgp_pgbgp_r_origin -+{ -+ as_t originAS; -+ struct bgp_node *rn; -+}; -+ -+struct bgp_pgbgp_r_prefix -+{ -+ struct bgp_node *rn; -+ struct bgp_node *rnsuper; -+}; -+ -+/* -+ This node contained a route with a bad edge, check -+ it again for bad edges in 24 hours -+*/ -+struct bgp_pgbgp_r_edge -+{ -+ struct bgp_node *rn; -+}; -+ -+ -+union reuseTypes -+{ -+ struct bgp_pgbgp_r_origin origin; -+ struct bgp_pgbgp_r_prefix prefix; -+ struct bgp_pgbgp_r_edge edge; -+}; -+ -+struct bgp_pgbgp_reuse -+{ -+ union reuseTypes data; -+ short type; -+ time_t deprefUntil; -+}; -+ -+#define ANOMALOUS(V) \ -+(CHECK_FLAG(V, BGP_INFO_SUSPICIOUS_O | BGP_INFO_SUSPICIOUS_P \ -+ | BGP_INFO_SUSPICIOUS_E | BGP_INFO_IGNORED_P)) -+ -+#define PGBGP_REUSE_ORIGIN 0 -+#define PGBGP_REUSE_PREFIX 1 -+#define PGBGP_REUSE_EDGE 2 -+ -+#define BGP_PGBGP_NONE 0 -+#define BGP_PGBGP_DEPREFFED 1 -+ -+// For storage -+#define ORIGIN_ID 0 -+#define PREFIX_ID 1 -+#define EDGE_ID 2 -+#define PEER_ID 3 -+ -+/* Default timing values */ -+#define DEFAULT_ORIGIN_SUS (86400 * 1) -+#define DEFAULT_EDGE_SUS (86400 * 1) -+#define DEFAULT_SUB_SUS (86400 * 1) -+#define DEFAULT_ORIGIN_HIST (86400 * 30) -+#define DEFAULT_PREFIX_HIST (86400 * 10) -+#define DEFAULT_EDGE_HIST (86400 * 60) -+// Time between garbage collections -+#define PGBGP_GC_DELTA (3600) -+// Time between file stores -+#define PGBGP_STORE_DELTA (28800) -+// Time that a new peer's routes are not considered suspicious -+#define PGBGP_PEER_GRACE (86400 * 1) -+ -+ -+ -+///////// PUBLIC PGBGP FUNCTIONS ///////// -+ -+/* -+ bgp_pgbgp_enable: -+ Enable PGBGP depreferencing / history tracking for this afi/safi -+ -+ Arguments: -+ . ost: Depref. time of new prefix origins (in hours) -+ . est: Depref. time of new edges (in hours) -+ . sst: Depref. time of new sub-prefixes (in hours) -+ . oht: Storage time of known origins for prefixes (in days) -+ . pht: Storage time of known prefixes (in days) -+ . eht: Storage time of known edges (in days) -+ . storage: File to periodically store history in (can be /dev/null) -+ . anoms: File to store history of depreferenced routes (can be /dev/null) -+ -+ Caution: -+ It is important that the storage times are longer than the depreference times -+*/ -+extern int bgp_pgbgp_enable (struct bgp *, afi_t afi, safi_t safi, int ost, -+ int est, int sst, int oht, int pht, int eht, -+ const char *storage, const char *anoms); -+extern int bgp_pgbgp_disable (struct bgp *, afi_t afi, safi_t safi); -+ -+/* -+ bgp_pgbgp_update: -+ Call on the event of an announcement update -+ -+ Arguments: -+ bgp_info: The route -+ at: The new route's attributes -+*/ -+extern int bgp_pgbgp_update (struct bgp_info *, struct attr *at, -+ struct bgp_node *); -+ -+/* -+ bgp_pgbgp_rib_updated: -+ Call upon discovery of a new best path (or lack thereof) -+ -+ This is a special case function for smoothly handling sub-prefix hijacks. -+ -+ It handles the following 2 events: -+ -+ Event 1: An anomalous sub-prefix is ignored, but no best route for the super-prefix exists -+ Response: Announce the sub-prefix until the super-prefix comes back -+ -+ Event 2: A super-prefix comes back to the RIB and its anomalous sub-prefix is in use -+ Response: Ignore the sub-prefix again -+ -+ Arguments: -+ rn: The route node that a new best path was found for -+ old_best: The old best route (NULL if one did not exist) -+ new_best: The current best route (NULL if one does not exist) -+ */ -+extern int -+bgp_pgbgp_rib_updated (struct bgp_node *rn, struct bgp_info *old_best, -+ struct bgp_info *new_best); -+ -+#endif ---- a/bgpd/bgp_route.c -+++ b/bgpd/bgp_route.c -@@ -51,6 +51,7 @@ Software Foundation, Inc., 59 Temple Pla - #include "bgpd/bgp_mplsvpn.h" - #include "bgpd/bgp_nexthop.h" - #include "bgpd/bgp_damp.h" -+#include "bgpd/bgp_pgbgp.h" - #include "bgpd/bgp_advertise.h" - #include "bgpd/bgp_zebra.h" - #include "bgpd/bgp_vty.h" -@@ -339,12 +340,19 @@ bgp_info_cmp (struct bgp *bgp, struct bg - - *paths_eq = 0; - -+ - /* 0. Null check. */ - if (new == NULL) - return 0; - if (exist == NULL) - return 1; - -+ /* 0.5 PGBGP Depref. Check */ -+ if (ANOMALOUS(exist->flags) && !ANOMALOUS(new->flags)) -+ return 1; -+ if (!ANOMALOUS(exist->flags) && ANOMALOUS(new->flags)) -+ return 0; -+ - /* 1. Weight check. */ - if (new->attr->extra) - new_weight = new->attr->extra->weight; -@@ -1583,6 +1591,10 @@ bgp_process_main (struct work_queue *wq, - UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); - } - -+ /* PGBGP needs to know about selected routes */ -+ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP)) -+ bgp_pgbgp_rib_updated(rn, old_select, new_select); -+ - - /* Check each BGP peer. */ - for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) -@@ -1906,6 +1918,11 @@ bgp_update_rsclient (struct peer *rsclie - /* If the update is implicit withdraw. */ - if (ri) - { -+ /* Update PGBGP state, and mark the route as anomalous if necessary */ -+ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP) -+ && peer_sort(peer) == BGP_PEER_EBGP) -+ bgp_pgbgp_update(ri, attr_new, rn); -+ - ri->uptime = bgp_clock (); - - /* Same attribute comes in. */ -@@ -2337,6 +2354,11 @@ bgp_update_main (struct peer *peer, stru - /* Increment prefix */ - bgp_aggregate_increment (bgp, p, new, afi, safi); - -+ /* Update PGBGP state, and mark the route as anomalous if necessary */ -+ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP) -+ && peer_sort(peer) == BGP_PEER_EBGP) -+ bgp_pgbgp_update(new, attr_new, rn); -+ - /* Register new BGP information. */ - bgp_info_add (rn, new); - -@@ -5575,6 +5597,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"); -@@ -6080,6 +6116,7 @@ route_vty_out_detail (struct vty *vty, s - } - - #define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s r RIB-failure, S Stale, R Removed%s" -+#define BGP_SHOW_PCODE_HEADER "Status code: a (anomalous) of: [p] prefix hijack, [s] sub-prefix hijack,%s [i] informant of sub-prefix [e] new edge%s" - #define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s" - #define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s" - #define BGP_SHOW_DAMP_HEADER " Network From Reuse Path%s" -@@ -6111,7 +6148,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 -@@ -6278,11 +6316,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) -@@ -6360,6 +6404,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, -@@ -11932,6 +11977,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>", -@@ -11981,6 +12084,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", -@@ -12507,6 +12623,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); -@@ -12640,6 +12757,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); -@@ -13030,6 +13148,10 @@ bgp_route_init (void) - install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd); - install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd); - -+ install_element (BGP_NODE, &bgp_pgbgp_cmd); -+ install_element (BGP_NODE, &bgp_pgbgp_arg_cmd); -+ install_element (BGP_NODE, &bgp_pgbgp_unset_cmd); -+ - /* Deprecated AS-Pathlimit commands */ - install_element (BGP_NODE, &bgp_network_ttl_cmd); - install_element (BGP_NODE, &bgp_network_mask_ttl_cmd); ---- a/bgpd/bgp_route.h -+++ b/bgpd/bgp_route.h -@@ -1,3 +1,4 @@ -+ - /* BGP routing information base - Copyright (C) 1996, 97, 98, 2000 Kunihiro Ishiguro - -@@ -68,7 +69,7 @@ struct bgp_info - int lock; - - /* BGP information status. */ -- u_int16_t flags; -+ u_int32_t flags; - #define BGP_INFO_IGP_CHANGED (1 << 0) - #define BGP_INFO_DAMPED (1 << 1) - #define BGP_INFO_HISTORY (1 << 2) -@@ -82,6 +83,10 @@ struct bgp_info - #define BGP_INFO_COUNTED (1 << 10) - #define BGP_INFO_MULTIPATH (1 << 11) - #define BGP_INFO_MULTIPATH_CHG (1 << 12) -+#define BGP_INFO_SUSPICIOUS_O (1 << 13) -+#define BGP_INFO_SUSPICIOUS_P (1 << 14) -+#define BGP_INFO_IGNORED_P (1 << 15) -+#define BGP_INFO_SUSPICIOUS_E (1 << 16) - - /* BGP route type. This can be static, RIP, OSPF, BGP etc. */ - u_char type; -@@ -126,7 +131,7 @@ struct bgp_static - - /* Flags which indicate a route is unuseable in some form */ - #define BGP_INFO_UNUSEABLE \ -- (BGP_INFO_HISTORY|BGP_INFO_DAMPED|BGP_INFO_REMOVED) -+ (BGP_INFO_HISTORY|BGP_INFO_DAMPED|BGP_INFO_REMOVED|BGP_INFO_IGNORED_P) - /* Macro to check BGP information is alive or not. Sadly, - * not equivalent to just checking previous, because of the - * sense of the additional VALID flag. ---- a/bgpd/bgp_table.h -+++ b/bgpd/bgp_table.h -@@ -65,6 +65,8 @@ struct bgp_node - - int lock; - -+ struct bgp_pgbgp_hist *hist; -+ - u_char flags; - #define BGP_NODE_PROCESS_SCHEDULED (1 << 0) - }; ---- a/bgpd/bgpd.h -+++ b/bgpd/bgpd.h -@@ -123,6 +123,7 @@ struct bgp - /* BGP Per AF flags */ - u_int16_t af_flags[AFI_MAX][SAFI_MAX]; - #define BGP_CONFIG_DAMPENING (1 << 0) -+#define BGP_CONFIG_PGBGP (1 << 1) - - /* Static route configuration. */ - struct bgp_table *route[AFI_MAX][SAFI_MAX]; ---- a/lib/hash.c -+++ b/lib/hash.c -@@ -166,6 +166,35 @@ hash_iterate (struct hash *hash, - } - } - -+/* -+ Iterates until 0 is returned or until completion -+ Return: 1 if iteration completed -+ Return: 0 if iteration was interrupted -+*/ -+ -+int -+hash_iterate_until(struct hash *hash, -+ int (*func) (struct hash_backet *, void *), void *arg) -+{ -+ unsigned int i; -+ struct hash_backet *hb; -+ struct hash_backet *hbnext; -+ int ret; -+ -+ for (i = 0; i < hash->size; i++) -+ for (hb = hash->index[i]; hb; hb = hbnext) -+ { -+ /* get pointer to next hash backet here, in case (*func) -+ * decides to delete hb by calling hash_release -+ */ -+ hbnext = hb->next; -+ ret = (*func) (hb, arg); -+ if (!ret) -+ return 0; -+ } -+ return 1; -+} -+ - /* Clean up hash. */ - void - hash_clean (struct hash *hash, void (*free_func) (void *)) ---- a/lib/hash.h -+++ b/lib/hash.h -@@ -66,7 +66,8 @@ extern void *hash_release (struct hash * - - extern void hash_iterate (struct hash *, - void (*) (struct hash_backet *, void *), void *); -- -+extern int hash_iterate_until(struct hash *, -+ int (*) (struct hash_backet *, void *), void *); - extern void hash_clean (struct hash *, void (*) (void *)); - extern void hash_free (struct hash *); - ---- a/lib/memtypes.c -+++ b/lib/memtypes.c -@@ -148,6 +148,15 @@ struct memory_list memory_list_bgp[] = - { MTYPE_PEER_UPDATE_SOURCE, "BGP peer update interface" }, - { MTYPE_BGP_DAMP_INFO, "Dampening info" }, - { MTYPE_BGP_DAMP_ARRAY, "BGP Dampening array" }, -+ { 0, NULL }, -+ { MTYPE_BGP_PGBGP_ORIGIN, "BGP PGBGP Origin AS Node" }, -+ { MTYPE_BGP_PGBGP_PREFIX, "BGP PGBGP Prefix AS Node" }, -+ { MTYPE_BGP_PGBGP_EDGE, "BGP PGBGP Edge Node" }, -+ { MTYPE_BGP_PGBGP_REUSE, "BGP PGBGP Reuse Node" }, -+ { MTYPE_BGP_PGBGP_HIST, "BGP PGBGP History Node" }, -+ { MTYPE_BGP_PGBGP_AVOID, "BGP PGBGP Avoid Peer Node" }, -+ { MTYPE_BGP_PGBGP_PEER, "BGP PGBGP Peer Timing" }, -+ { 0, NULL }, - { MTYPE_BGP_REGEXP, "BGP regexp" }, - { MTYPE_BGP_AGGREGATE, "BGP aggregate" }, - { -1, NULL } diff --git a/patches/161-pgbgp-addon.patch b/patches/161-pgbgp-addon.patch deleted file mode 100644 index 5bcd907..0000000 --- a/patches/161-pgbgp-addon.patch +++ /dev/null @@ -1,318 +0,0 @@ -From: Paul Jakma -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 -@@ -5597,20 +5597,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"); -@@ -5626,6 +5612,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)) -@@ -6104,7 +6101,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)); -@@ -6115,8 +6127,9 @@ route_vty_out_detail (struct vty *vty, s - vty_out (vty, "%s", VTY_NEWLINE); - } - --#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s r RIB-failure, S Stale, R Removed%s" --#define BGP_SHOW_PCODE_HEADER "Status code: a (anomalous) of: [p] prefix hijack, [s] sub-prefix hijack,%s [i] informant of sub-prefix [e] new edge%s" -+#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s" \ -+ " r RIB-failure, S Stale, R Removed, %s" \ -+ " p prefix hijack, P sub-prefix hijack, a other anomaly%s" - #define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s" - #define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s" - #define BGP_SHOW_DAMP_HEADER " Network From Reuse Path%s" -@@ -6325,8 +6338,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) -@@ -9858,7 +9870,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", -@@ -9875,7 +9887,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; - } -@@ -9899,7 +9911,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; - } diff --git a/patches/170-use-supported-pagers.patch b/patches/170-use-supported-pagers.patch index d42e145..15595a7 100644 --- a/patches/170-use-supported-pagers.patch +++ b/patches/170-use-supported-pagers.patch @@ -1,6 +1,6 @@ --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c -@@ -269,7 +269,7 @@ vtysh_pager_init (void) +@@ -268,7 +268,7 @@ vtysh_pager_init (void) if (pager_defined) vtysh_pager_name = strdup (pager_defined); else @@ -9,7 +9,7 @@ } /* Command execution over the vty interface. */ -@@ -1885,7 +1885,7 @@ DEFUN (vtysh_terminal_length, +@@ -1884,7 +1884,7 @@ DEFUN (vtysh_terminal_length, { int lines; char *endptr = NULL; @@ -18,7 +18,7 @@ lines = strtol (argv[0], &endptr, 10); if (lines < 0 || lines > 512 || *endptr != '\0') -@@ -1902,7 +1902,7 @@ DEFUN (vtysh_terminal_length, +@@ -1901,7 +1901,7 @@ DEFUN (vtysh_terminal_length, if (lines != 0) {