aboutsummaryrefslogtreecommitdiffstats
path: root/net/quagga
diff options
context:
space:
mode:
authorsem <sem@FreeBSD.org>2007-08-28 18:48:38 +0800
committersem <sem@FreeBSD.org>2007-08-28 18:48:38 +0800
commitf57e8739b083c6fcd0cb2a88edef69cfbabba112 (patch)
treeea4f40cba48bd8702fbcb80d2b62c17b0f49fbbd /net/quagga
parentf50e668d31bae4c9b8f5b62c5709b850d414cdfe (diff)
downloadfreebsd-ports-gnome-f57e8739b083c6fcd0cb2a88edef69cfbabba112.tar.gz
freebsd-ports-gnome-f57e8739b083c6fcd0cb2a88edef69cfbabba112.tar.zst
freebsd-ports-gnome-f57e8739b083c6fcd0cb2a88edef69cfbabba112.zip
- Integrate patches from quagga CVS.
They fix a few problems with inconsistences routes between quagga and kernel route tables, loss MTU, assert in route-map code, etc. Submitted by: Yandex company Approved by: maintainer
Diffstat (limited to 'net/quagga')
-rw-r--r--net/quagga/Makefile1
-rw-r--r--net/quagga/files/patch-cvs-1-bgpd-rm-assert210
-rw-r--r--net/quagga/files/patch-cvs-2-ribcode46
-rw-r--r--net/quagga/files/patch-cvs-3-ribdebug642
-rw-r--r--net/quagga/files/patch-cvs-4-nexthop_active_update47
-rw-r--r--net/quagga/files/patch-cvs-5-sendbuffer294
-rw-r--r--net/quagga/files/patch-cvs-6-RTF_DONE20
-rw-r--r--net/quagga/files/patch-cvs-7-ifm_read18
8 files changed, 1278 insertions, 0 deletions
diff --git a/net/quagga/Makefile b/net/quagga/Makefile
index 68c365d4e556..92810dba5922 100644
--- a/net/quagga/Makefile
+++ b/net/quagga/Makefile
@@ -7,6 +7,7 @@
PORTNAME= quagga
PORTVERSION= 0.99.8
+PORTREVISION= 1
CATEGORIES= net ipv6
MASTER_SITES= http://quagga.net/download/ \
http://www.ru.quagga.net/download/ \
diff --git a/net/quagga/files/patch-cvs-1-bgpd-rm-assert b/net/quagga/files/patch-cvs-1-bgpd-rm-assert
new file mode 100644
index 000000000000..979572948340
--- /dev/null
+++ b/net/quagga/files/patch-cvs-1-bgpd-rm-assert
@@ -0,0 +1,210 @@
+--- bgpd/ChangeLog.orig 23 Aug 2007 23:22:02 -0000 1.140
++++ bgpd/ChangeLog 27 Aug 2007 11:48:47 -0000
+@@ -1,3 +1,24 @@
++2007-08-27 Paul Jakma <paul.jakma@sun.com>
++
++ * bgp_route.c: (bgp_announce_check) Fix bug #398, slight
++ modification of Vladimir Ivanov's suggested fix - to keep
++ memory alloc conditional.
++ (bgp_process_announce_selected) Don't take struct attr as
++ argument, none of the callers need it and it needlessly
++ distances allocation from use.
++ Free the extended attr, the attr itself is on the stack.
++ Fix bad indentation.
++ * bgp_attr.c: (bgp_packet_attribute) Remove incorrect assert,
++ and adjust conditional to test attr->extra, diagnosis by
++ Vladimir Ivanov in bug #398.
++
++2007-08-27 Vladimir Ivanov <wawa@yandex-team.ru>
++
++ * bgp_route.c: (bgp_announce_check_rsclient) copy of
++ ri->attr is no longer deep enough, due to addition of
++ attr->extra. It should use bgp_attr_dup, as
++ bgp_announce_check() does.
++
+ 2007-08-23 Paul Jakma <paul.jakma@sun.com>
+
+ * bgp_regex.c: (bgp_regcomp) Pass NOSUB flag to regcomp to
+--- bgpd/bgp_attr.c.orig 6 Aug 2007 15:24:51 -0000 1.22
++++ bgpd/bgp_attr.c 27 Aug 2007 11:48:47 -0000
+@@ -1673,8 +1673,6 @@ bgp_packet_attribute (struct bgp *bgp, s
+ && from
+ && peer_sort (from) == BGP_PEER_IBGP)
+ {
+- assert (attr->extra);
+-
+ /* Originator ID. */
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+ stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
+@@ -1689,7 +1687,7 @@ bgp_packet_attribute (struct bgp *bgp, s
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+ stream_putc (s, BGP_ATTR_CLUSTER_LIST);
+
+- if (attr->extra->cluster)
++ if (attr->extra && attr->extra->cluster)
+ {
+ stream_putc (s, attr->extra->cluster->length + 4);
+ /* If this peer configuration's parent BGP has cluster_id. */
+--- bgpd/bgp_route.c.orig 6 Aug 2007 15:24:51 -0000 1.63
++++ bgpd/bgp_route.c 27 Aug 2007 11:48:48 -0000
+@@ -1045,20 +1045,18 @@ bgp_announce_check (struct bgp_info *ri,
+ || (ri->extra && ri->extra->suppress) )
+ {
+ struct bgp_info info;
+- struct attr dummy_attr;
++ struct attr dummy_attr = { 0 };
+
+ info.peer = peer;
+ info.attr = attr;
+-
+
+ /* The route reflector is not allowed to modify the attributes
+ of the reflected IBGP routes. */
+ if (peer_sort (from) == BGP_PEER_IBGP
+ && peer_sort (peer) == BGP_PEER_IBGP)
+ {
+- dummy_attr.extra = NULL;
+ bgp_attr_dup (&dummy_attr, attr);
+- info.attr = &dummy_attr;
++ info.attr = &dummy_attr;
+ }
+
+ SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT);
+@@ -1070,7 +1068,8 @@ bgp_announce_check (struct bgp_info *ri,
+
+ peer->rmap_type = 0;
+
+- bgp_attr_extra_free (&dummy_attr);
++ if (dummy_attr.extra)
++ bgp_attr_extra_free (&dummy_attr);
+
+ if (ret == RMAP_DENYMATCH)
+ {
+@@ -1173,7 +1172,7 @@ bgp_announce_check_rsclient (struct bgp_
+ #endif /* BGP_SEND_ASPATH_CHECK */
+
+ /* For modify attribute, copy it to temporary structure. */
+- *attr = *ri->attr;
++ bgp_attr_dup (attr, ri->attr);
+
+ /* next-hop-set */
+ if ((p->family == AF_INET && attr->nexthop.s_addr == 0)
+@@ -1375,21 +1374,22 @@ bgp_best_selection (struct bgp *bgp, str
+
+ static int
+ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected,
+- struct bgp_node *rn, struct attr *attr, afi_t afi, safi_t safi)
+- {
++ struct bgp_node *rn, afi_t afi, safi_t safi)
++{
+ struct prefix *p;
++ struct attr attr = { 0 };
+
+ p = &rn->p;
+
+- /* Announce route to Established peer. */
+- if (peer->status != Established)
++ /* Announce route to Established peer. */
++ if (peer->status != Established)
+ return 0;
+
+- /* Address family configuration check. */
+- if (! peer->afc_nego[afi][safi])
++ /* Address family configuration check. */
++ if (! peer->afc_nego[afi][safi])
+ return 0;
+
+- /* First update is deferred until ORF or ROUTE-REFRESH is received */
++ /* First update is deferred until ORF or ROUTE-REFRESH is received */
+ if (CHECK_FLAG (peer->af_sflags[afi][safi],
+ PEER_STATUS_ORF_WAIT_REFRESH))
+ return 0;
+@@ -1399,21 +1399,24 @@ bgp_process_announce_selected (struct pe
+ case BGP_TABLE_MAIN:
+ /* Announcement to peer->conf. If the route is filtered,
+ withdraw it. */
+- if (selected && bgp_announce_check (selected, peer, p, attr, afi, safi))
+- bgp_adj_out_set (rn, peer, p, attr, afi, safi, selected);
++ if (selected && bgp_announce_check (selected, peer, p, &attr, afi, safi))
++ bgp_adj_out_set (rn, peer, p, &attr, afi, safi, selected);
+ else
+ bgp_adj_out_unset (rn, peer, p, afi, safi);
+ break;
+ case BGP_TABLE_RSCLIENT:
+ /* Announcement to peer->conf. If the route is filtered,
+ withdraw it. */
+- if (selected && bgp_announce_check_rsclient
+- (selected, peer, p, attr, afi, safi))
+- bgp_adj_out_set (rn, peer, p, attr, afi, safi, selected);
+- else
+- bgp_adj_out_unset (rn, peer, p, afi, safi);
++ if (selected &&
++ bgp_announce_check_rsclient (selected, peer, p, &attr, afi, safi))
++ bgp_adj_out_set (rn, peer, p, &attr, afi, safi, selected);
++ else
++ bgp_adj_out_unset (rn, peer, p, afi, safi);
+ break;
+ }
++
++ bgp_attr_extra_free (&attr);
++
+ return 0;
+ }
+
+@@ -1463,8 +1466,7 @@ bgp_process_rsclient (struct work_queue
+ bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED);
+ }
+
+- bgp_process_announce_selected (rsclient, new_select, rn, &attr,
+- afi, safi);
++ bgp_process_announce_selected (rsclient, new_select, rn, afi, safi);
+ }
+ }
+ else
+@@ -1476,8 +1478,7 @@ bgp_process_rsclient (struct work_queue
+ bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED);
+ bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED);
+ }
+- bgp_process_announce_selected (rsclient, new_select, rn,
+- &attr, afi, safi);
++ bgp_process_announce_selected (rsclient, new_select, rn, afi, safi);
+ }
+
+ if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
+@@ -1503,9 +1504,6 @@ bgp_process_main (struct work_queue *wq,
+ struct bgp_info_pair old_and_new;
+ struct listnode *node, *nnode;
+ struct peer *peer;
+- struct attr attr;
+-
+- memset (&attr, 0, sizeof (struct attr));
+
+ /* Best path selection. */
+ bgp_best_selection (bgp, rn, &old_and_new);
+@@ -1537,7 +1535,7 @@ bgp_process_main (struct work_queue *wq,
+ /* Check each BGP peer. */
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+- bgp_process_announce_selected (peer, new_select, rn, &attr, afi, safi);
++ bgp_process_announce_selected (peer, new_select, rn, afi, safi);
+ }
+
+ /* FIB update. */
+@@ -1562,8 +1560,6 @@ bgp_process_main (struct work_queue *wq,
+ if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
+ bgp_info_reap (rn, old_select);
+
+- bgp_attr_extra_free (&attr);
+-
+ UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
+ return WQ_SUCCESS;
+ }
+@@ -6214,7 +6210,7 @@ bgp_show_table (struct vty *vty, struct
+ {
+ struct route_map *rmap = output_arg;
+ struct bgp_info binfo;
+- struct attr dummy_attr;
++ struct attr dummy_attr = { 0 };
+ int ret;
+
+ bgp_attr_dup (&dummy_attr, ri->attr);
diff --git a/net/quagga/files/patch-cvs-2-ribcode b/net/quagga/files/patch-cvs-2-ribcode
new file mode 100644
index 000000000000..bdf05a47561b
--- /dev/null
+++ b/net/quagga/files/patch-cvs-2-ribcode
@@ -0,0 +1,46 @@
+--- zebra/rt_socket.c.orig 2007-05-10 00:59:35.000000000 +0400
++++ zebra/rt_socket.c 2007-07-31 15:58:18.000000000 +0400
+@@ -99,9 +99,7 @@
+ if ((cmd == RTM_ADD
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ || (cmd == RTM_DELETE
+-#if 0
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+-#endif
+ ))
+ {
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+@@ -138,9 +136,6 @@
+ }
+ }
+
+- if (cmd == RTM_ADD)
+- SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+-
+ if (gate && p->prefixlen == 32)
+ mask = NULL;
+ else
+@@ -152,7 +147,6 @@
+ #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
+ mask = &sin_mask;
+ }
+- }
+
+ error = rtm_write (cmd,
+ (union sockunion *)&sin_dest,
+@@ -169,8 +163,13 @@
+ nexthop_num, error);
+ }
+ #endif
+-
+- nexthop_num++;
++ if (error == 0)
++ {
++ nexthop_num++;
++ if (cmd == RTM_ADD)
++ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
++ }
++ }
+ }
+
+ /* If there is no useful nexthop then return. */
diff --git a/net/quagga/files/patch-cvs-3-ribdebug b/net/quagga/files/patch-cvs-3-ribdebug
new file mode 100644
index 000000000000..a6b80f9f3cfd
--- /dev/null
+++ b/net/quagga/files/patch-cvs-3-ribdebug
@@ -0,0 +1,642 @@
+--- lib/zebra.h.orig 2007-06-14 14:02:13.000000000 +0400
++++ lib/zebra.h 2007-08-08 12:19:21.000000000 +0400
+@@ -454,10 +454,12 @@
+ #define ZEBRA_FAMILY_MAX 3
+
+ /* Error codes of zebra. */
++#define ZEBRA_ERR_NOERROR 0
+ #define ZEBRA_ERR_RTEXIST -1
+ #define ZEBRA_ERR_RTUNREACH -2
+ #define ZEBRA_ERR_EPERM -3
+ #define ZEBRA_ERR_RTNOEXIST -4
++#define ZEBRA_ERR_KERNEL -5
+
+ /* Zebra message flags */
+ #define ZEBRA_FLAG_INTERNAL 0x01
+--- zebra/kernel_socket.c.orig 2007-07-27 20:40:57.000000000 +0400
++++ zebra/kernel_socket.c 2007-08-08 14:52:36.000000000 +0400
+@@ -160,6 +160,7 @@
+ #endif /* RTM_IFANNOUNCE */
+ {0, NULL}
+ };
++int rtm_type_str_max = sizeof (rtm_type_str) / sizeof (struct message) - 1;
+
+ struct message rtm_flag_str[] =
+ {
+@@ -737,14 +738,12 @@
+
+ zebra_flags = 0;
+
+- /* Discard self send message. */
+- if (rtm->rtm_type != RTM_GET
+- && (rtm->rtm_pid == pid || rtm->rtm_pid == old_pid))
+- return;
+-
+ /* Read destination and netmask and gateway from rtm message
+ structure. */
+ flags = rtm_read_mesg (rtm, &dest, &mask, &gate, ifname, &ifnlen);
++ if (IS_ZEBRA_DEBUG_KERNEL)
++ zlog_debug ("%s: got rtm of type %d (%s)", __func__, rtm->rtm_type,
++ LOOKUP (rtm_type_str, rtm->rtm_type));
+
+ #ifdef RTF_CLONED /*bsdi, netbsd 1.6*/
+ if (flags & RTF_CLONED)
+@@ -786,6 +785,79 @@
+ else
+ p.prefixlen = ip_masklen (mask.sin.sin_addr);
+
++ /* Catch self originated messages and match them against our current RIB.
++ * At the same time, ignore unconfirmed messages, they should be tracked
++ * by rtm_write() and kernel_rtm_ipv4().
++ */
++ if (rtm->rtm_type != RTM_GET
++ && (rtm->rtm_pid == pid || rtm->rtm_pid == old_pid))
++ {
++ char buf[INET_ADDRSTRLEN], gate_buf[INET_ADDRSTRLEN];
++ int ret;
++ if (!(flags & RTF_DONE))
++ return;
++ if (! IS_ZEBRA_DEBUG_RIB)
++ return;
++ ret = rib_lookup_ipv4_route (&p, &gate);
++ inet_ntop (AF_INET, &p.prefix, buf, INET_ADDRSTRLEN);
++ switch (rtm->rtm_type)
++ {
++ case RTM_ADD:
++ case RTM_GET:
++ case RTM_CHANGE:
++ /* The kernel notifies us about a new route in FIB created by us.
++ Do we have a correspondent entry in our RIB? */
++ switch (ret)
++ {
++ case ZEBRA_RIB_NOTFOUND:
++ zlog_debug ("%s: %s %s/%d: desync: RR isn't yet in RIB, while already in FIB",
++ __func__, LOOKUP (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
++ break;
++ case ZEBRA_RIB_FOUND_CONNECTED:
++ case ZEBRA_RIB_FOUND_NOGATE:
++ inet_ntop (AF_INET, &gate.sin.sin_addr, gate_buf, INET_ADDRSTRLEN);
++ zlog_debug ("%s: %s %s/%d: desync: RR is in RIB, but gate differs (ours is %s)",
++ __func__, LOOKUP (rtm_type_str, rtm->rtm_type), buf, p.prefixlen, gate_buf);
++ break;
++ case ZEBRA_RIB_FOUND_EXACT: /* RIB RR == FIB RR */
++ zlog_debug ("%s: %s %s/%d: done Ok",
++ __func__, LOOKUP (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
++ rib_lookup_and_dump (&p);
++ return;
++ break;
++ }
++ break;
++ case RTM_DELETE:
++ /* The kernel notifies us about a route deleted by us. Do we still
++ have it in the RIB? Do we have anything instead? */
++ switch (ret)
++ {
++ case ZEBRA_RIB_FOUND_EXACT:
++ zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, while already not in FIB",
++ __func__, LOOKUP (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
++ rib_lookup_and_dump (&p);
++ break;
++ case ZEBRA_RIB_FOUND_CONNECTED:
++ case ZEBRA_RIB_FOUND_NOGATE:
++ zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, plus gate differs",
++ __func__, LOOKUP (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
++ rib_lookup_and_dump (&p);
++ break;
++ case ZEBRA_RIB_NOTFOUND: /* RIB RR == FIB RR */
++ zlog_debug ("%s: %s %s/%d: done Ok",
++ __func__, LOOKUP (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
++ rib_lookup_and_dump (&p);
++ return;
++ break;
++ }
++ break;
++ default:
++ zlog_debug ("%s: %s/%d: warning: loopback RTM of type %s received",
++ __func__, buf, p.prefixlen, LOOKUP (rtm_type_str, rtm->rtm_type));
++ }
++ return;
++ }
++
+ /* Change, delete the old prefix, we have no further information
+ * to specify the route really
+ */
+@@ -903,7 +975,13 @@
+ {
+ if (!ifp)
+ {
+- zlog_warn ("no gateway found for interface index %d", index);
++ char dest_buf[INET_ADDRSTRLEN] = "NULL", mask_buf[INET_ADDRSTRLEN] = "255.255.255.255";
++ if (dest)
++ inet_ntop (AF_INET, &dest->sin.sin_addr, dest_buf, INET_ADDRSTRLEN);
++ if (mask)
++ inet_ntop (AF_INET, &mask->sin.sin_addr, mask_buf, INET_ADDRSTRLEN);
++ zlog_warn ("%s: %s/%s: gate == NULL and no gateway found for ifindex %d",
++ __func__, dest_buf, mask_buf, index);
+ return -1;
+ }
+ gate = (union sockunion *) & ifp->sdl;
+@@ -959,11 +1037,13 @@
+ return ZEBRA_ERR_RTEXIST;
+ if (errno == ENETUNREACH)
+ return ZEBRA_ERR_RTUNREACH;
++ if (errno == ESRCH)
++ return ZEBRA_ERR_RTNOEXIST;
+
+- zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
+- return -1;
++ zlog_warn ("%s: write : %s (%d)", __func__, safe_strerror (errno), errno);
++ return ZEBRA_ERR_KERNEL;
+ }
+- return 0;
++ return ZEBRA_ERR_NOERROR;
+ }
+
+
+@@ -974,17 +1054,7 @@
+ static void
+ rtmsg_debug (struct rt_msghdr *rtm)
+ {
+- const char *type = "Unknown";
+- struct message *mes;
+-
+- for (mes = rtm_type_str; mes->str; mes++)
+- if (mes->key == rtm->rtm_type)
+- {
+- type = mes->str;
+- break;
+- }
+-
+- zlog_debug ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, type);
++ zlog_debug ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, LOOKUP (rtm_type_str, rtm->rtm_type));
+ rtm_flag_dump (rtm->rtm_flags);
+ zlog_debug ("Kernel: message seq %d", rtm->rtm_seq);
+ zlog_debug ("Kernel: pid %d, rtm_addrs 0x%x", rtm->rtm_pid, rtm->rtm_addrs);
+--- zebra/kernel_socket.h.orig 2005-11-24 18:10:48.000000000 +0300
++++ zebra/kernel_socket.h 2007-08-08 12:19:21.000000000 +0400
+@@ -28,5 +28,7 @@
+ extern int ifm_read (struct if_msghdr *);
+ extern int rtm_write (int, union sockunion *, union sockunion *,
+ union sockunion *, unsigned int, int, int);
++extern struct message rtm_type_str[];
++extern int rtm_type_str_max;
+
+ #endif /* __ZEBRA_KERNEL_SOCKET_H */
+--- zebra/rib.h.orig 2007-05-02 19:28:33.000000000 +0400
++++ zebra/rib.h 2007-08-08 12:19:21.000000000 +0400
+@@ -211,6 +211,15 @@
+ extern struct nexthop *nexthop_blackhole_add (struct rib *);
+ extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *,
+ struct in_addr *);
++extern void rib_lookup_and_dump (struct prefix_ipv4 *);
++extern void rib_dump (const char *, const struct prefix_ipv4 *, const struct rib *);
++extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *);
++#define ZEBRA_RIB_LOOKUP_ERROR -1
++#define ZEBRA_RIB_FOUND_EXACT 0
++#define ZEBRA_RIB_FOUND_NOGATE 1
++#define ZEBRA_RIB_FOUND_CONNECTED 2
++#define ZEBRA_RIB_NOTFOUND 3
++
+ #ifdef HAVE_IPV6
+ extern struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *);
+ #endif /* HAVE_IPV6 */
+--- zebra/rt_socket.c.orig 2007-08-08 12:08:40.000000000 +0400
++++ zebra/rt_socket.c 2007-08-08 12:41:01.000000000 +0400
+@@ -32,6 +32,7 @@
+ #include "zebra/debug.h"
+ #include "zebra/rib.h"
+ #include "zebra/rt.h"
++#include "zebra/kernel_socket.h"
+
+ extern struct zebra_privs_t zserv_privs;
+
+@@ -75,7 +76,10 @@
+ unsigned int ifindex = 0;
+ int gate = 0;
+ int error;
++ char prefix_buf[INET_ADDRSTRLEN];
+
++ if (IS_ZEBRA_DEBUG_RIB)
++ inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN);
+ memset (&sin_dest, 0, sizeof (struct sockaddr_in));
+ sin_dest.sin_family = AF_INET;
+ #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+@@ -95,6 +99,7 @@
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ gate = 0;
++ char gate_buf[INET_ADDRSTRLEN] = "NULL";
+
+ if ((cmd == RTM_ADD
+ && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+@@ -156,29 +161,61 @@
+ rib->flags,
+ rib->metric);
+
+-#if 0
+- if (error)
+- {
+- zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.",
+- nexthop_num, error);
+- }
+-#endif
+- if (error == 0)
+- {
+- nexthop_num++;
+- if (cmd == RTM_ADD)
+- SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+- }
+- }
+- }
+-
+- /* If there is no useful nexthop then return. */
+- if (nexthop_num == 0)
+- {
+- if (IS_ZEBRA_DEBUG_KERNEL)
+- zlog_debug ("kernel_rtm_ipv4(): No useful nexthop.");
+- return 0;
+- }
++ if (IS_ZEBRA_DEBUG_RIB)
++ {
++ if (!gate)
++ {
++ zlog_debug ("%s: %s/%d: attention! gate not found for rib %p",
++ __func__, prefix_buf, p->prefixlen, rib);
++ rib_dump (__func__, (struct prefix_ipv4 *)p, rib);
++ }
++ else
++ inet_ntop (AF_INET, &sin_gate.sin_addr, gate_buf, INET_ADDRSTRLEN);
++ }
++
++ switch (error)
++ {
++ /* We only flag nexthops as being in FIB if rtm_write() did its work. */
++ case ZEBRA_ERR_NOERROR:
++ nexthop_num++;
++ if (IS_ZEBRA_DEBUG_RIB)
++ zlog_debug ("%s: %s/%d: successfully did NH %s",
++ __func__, prefix_buf, p->prefixlen, gate_buf);
++ if (cmd == RTM_ADD)
++ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
++ break;
++
++ /* The only valid case for this error is kernel's failure to install
++ * a multipath route, which is common for FreeBSD. This should be
++ * ignored silently, but logged as an error otherwise.
++ */
++ case ZEBRA_ERR_RTEXIST:
++ if (cmd != RTM_ADD)
++ zlog_err ("%s: rtm_write() returned %d for command %d",
++ __func__, error, cmd);
++ continue;
++ break;
++
++ /* Given that our NEXTHOP_FLAG_FIB matches real kernel FIB, it isn't
++ * normal to get any other messages in ANY case.
++ */
++ case ZEBRA_ERR_RTNOEXIST:
++ case ZEBRA_ERR_RTUNREACH:
++ default:
++ zlog_err ("%s: %s/%d: rtm_write() unexpectedly returned %d for command %s",
++ __func__, prefix_buf, p->prefixlen, error, LOOKUP (rtm_type_str, cmd));
++ break;
++ }
++ } /* if (cmd and flags make sense) */
++ else
++ if (IS_ZEBRA_DEBUG_RIB)
++ zlog_debug ("%s: odd command %s for flags %d",
++ __func__, LOOKUP (rtm_type_str, cmd), nexthop->flags);
++ } /* for (nexthop = ... */
++
++ /* If there was no useful nexthop, then complain. */
++ if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL)
++ zlog_debug ("%s: No useful nexthops were found in RIB entry %p", __func__, rib);
+
+ return 0; /*XXX*/
+ }
+--- zebra/zebra_rib.c.orig 2007-06-25 14:17:53.000000000 +0400
++++ zebra/zebra_rib.c 2007-08-08 12:30:23.000000000 +0400
+@@ -631,6 +631,82 @@
+ return NULL;
+ }
+
++/*
++ * This clone function, unlike its original rib_lookup_ipv4(), checks
++ * if specified IPv4 route record (prefix/mask -> gate) exists in
++ * the whole RIB and has ZEBRA_FLAG_SELECTED set.
++ *
++ * Return values:
++ * -1: error
++ * 0: exact match found
++ * 1: a match was found with a different gate
++ * 2: connected route found
++ * 3: no matches found
++ */
++int
++rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate)
++{
++ struct route_table *table;
++ struct route_node *rn;
++ struct rib *match;
++ struct nexthop *nexthop;
++
++ /* Lookup table. */
++ table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
++ if (! table)
++ return ZEBRA_RIB_LOOKUP_ERROR;
++
++ /* Scan the RIB table for exactly matching RIB entry. */
++ rn = route_node_lookup (table, (struct prefix *) p);
++
++ /* No route for this prefix. */
++ if (! rn)
++ return ZEBRA_RIB_NOTFOUND;
++
++ /* Unlock node. */
++ route_unlock_node (rn);
++
++ /* Find out if a "selected" RR for the discovered RIB entry exists ever. */
++ for (match = rn->info; match; match = match->next)
++ {
++ if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
++ continue;
++ if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
++ break;
++ }
++
++ /* None such found :( */
++ if (!match)
++ return ZEBRA_RIB_NOTFOUND;
++
++ if (match->type == ZEBRA_ROUTE_CONNECT)
++ return ZEBRA_RIB_FOUND_CONNECTED;
++
++ /* Ok, we have a cood candidate, let's check it's nexthop list... */
++ for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
++ 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)
++ return ZEBRA_RIB_FOUND_EXACT;
++ else
++ {
++ if (IS_ZEBRA_DEBUG_RIB)
++ {
++ 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);
++ zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf);
++ }
++ return ZEBRA_RIB_FOUND_NOGATE;
++ }
++ }
++
++ return ZEBRA_RIB_NOTFOUND;
++}
++
+ #ifdef HAVE_IPV6
+ struct rib *
+ rib_match_ipv6 (struct in6_addr *addr)
+@@ -694,6 +770,16 @@
+ #define RIB_SYSTEM_ROUTE(R) \
+ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
+
++/* This function verifies reachability of one given nexthop, which can be
++ * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
++ * in nexthop->flags field. If the 4th parameter, 'set', is non-zero,
++ * nexthop->ifindex will be updated appropriately as well.
++ * An existing route map can turn (otherwise active) nexthop into inactive, but
++ * not vice versa.
++ *
++ * The return value is the final value of 'ACTIVE' flag.
++ */
++
+ static int
+ nexthop_active_check (struct route_node *rn, struct rib *rib,
+ struct nexthop *nexthop, int set)
+@@ -839,6 +925,7 @@
+ #endif /* HAVE_IPV6 */
+ }
+
++ /* This condition is never met, if we are using rt_socket.c */
+ if (ret < 0)
+ {
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+@@ -860,6 +947,8 @@
+ break;
+ #ifdef HAVE_IPV6
+ case AF_INET6:
++ if (IS_ZEBRA_DEBUG_RIB)
++ zlog_debug ("%s: calling kernel_delete_ipv4 (%p, %p)", __func__, rn, rib);
+ ret = kernel_delete_ipv6 (&rn->p, rib);
+ break;
+ #endif /* HAVE_IPV6 */
+@@ -903,6 +992,9 @@
+
+ for (rib = rn->info; rib; rib = next)
+ {
++ /* The next pointer is saved, because current pointer
++ * may be passed to rib_unlink() in the middle of iteration.
++ */
+ next = rib->next;
+
+ /* Currently installed rib. */
+@@ -978,9 +1070,16 @@
+ /* metric tie-breaks equal distance */
+ if (rib->metric <= select->metric)
+ select = rib;
+- }
+-
+- /* Same route is selected. */
++ } /* for (rib = rn->info; rib; rib = next) */
++
++ /* After the cycle is finished, the following pointers will be set:
++ * select --- the winner RIB entry, if any was found, otherwise NULL
++ * fib --- the SELECTED RIB entry, if any, otherwise NULL
++ * del --- equal to fib, if fib is queued for deletion, NULL otherwise
++ * rib --- NULL
++ */
++
++ /* Same RIB entry is selected. Update FIB and finish. */
+ if (select && select == fib)
+ {
+ if (IS_ZEBRA_DEBUG_RIB)
+@@ -1019,7 +1118,10 @@
+ goto end;
+ }
+
+- /* Uninstall old rib from forwarding table. */
++ /* At this point we either haven't found the best RIB entry or it is
++ * different from what we currently intend to flag with SELECTED. In both
++ * cases, if a RIB block is present in FIB, it should be withdrawn.
++ */
+ if (fib)
+ {
+ if (IS_ZEBRA_DEBUG_RIB)
+@@ -1033,7 +1135,10 @@
+ nexthop_active_update (rn, fib, 1);
+ }
+
+- /* Install new rib into forwarding table. */
++ /* Regardless of some RIB entry being SELECTED or not before, now we can
++ * tell, that if a new winner exists, FIB is still not updated with this
++ * data, but ready to be.
++ */
+ if (select)
+ {
+ if (IS_ZEBRA_DEBUG_RIB)
+@@ -1350,16 +1455,127 @@
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ /* Link new rib to node.*/
++ if (IS_ZEBRA_DEBUG_RIB)
++ zlog_debug ("%s: calling rib_addnode (%p, %p)", __func__, rn, rib);
+ rib_addnode (rn, rib);
+
+ /* Free implicit route.*/
+ if (same)
++ {
++ if (IS_ZEBRA_DEBUG_RIB)
++ zlog_debug ("%s: calling rib_delnode (%p, %p)", __func__, rn, rib);
+ rib_delnode (rn, same);
++ }
+
+ route_unlock_node (rn);
+ return 0;
+ }
+
++/* This function dumps the contents of a given RIB entry into
++ * standard debug log. Calling function name and IP prefix in
++ * question are passed as 1st and 2nd arguments.
++ */
++
++void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib * rib)
++{
++ char straddr1[INET_ADDRSTRLEN], straddr2[INET_ADDRSTRLEN];
++ struct nexthop *nexthop;
++
++ inet_ntop (AF_INET, &p->prefix, straddr1, INET_ADDRSTRLEN);
++ zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr1, p->prefixlen);
++ zlog_debug
++ (
++ "%s: refcnt == %lu, uptime == %u, type == %u, table == %d",
++ func,
++ rib->refcnt,
++ rib->uptime,
++ rib->type,
++ rib->table
++ );
++ zlog_debug
++ (
++ "%s: metric == %u, distance == %u, flags == %u, status == %u",
++ func,
++ rib->metric,
++ rib->distance,
++ rib->flags,
++ rib->status
++ );
++ zlog_debug
++ (
++ "%s: nexthop_num == %u, nexthop_active_num == %u, nexthop_fib_num == %u",
++ func,
++ rib->nexthop_num,
++ rib->nexthop_active_num,
++ rib->nexthop_fib_num
++ );
++ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
++ {
++ inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr1, INET_ADDRSTRLEN);
++ inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, straddr2, INET_ADDRSTRLEN);
++ zlog_debug
++ (
++ "%s: NH %s (%s) with flags %s%s%s",
++ func,
++ straddr1,
++ straddr2,
++ (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""),
++ (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""),
++ (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "")
++ );
++ }
++ zlog_debug ("%s: dump complete", func);
++}
++
++/* This is an exported helper to rtm_read() to dump the strange
++ * RIB entry found by rib_lookup_ipv4_route()
++ */
++
++void rib_lookup_and_dump (struct prefix_ipv4 * p)
++{
++ struct route_table *table;
++ struct route_node *rn;
++ struct rib *rib;
++ char prefix_buf[INET_ADDRSTRLEN];
++
++ /* Lookup table. */
++ table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
++ if (! table)
++ {
++ zlog_err ("%s: vrf_table() returned NULL", __func__);
++ return;
++ }
++
++ inet_ntop (AF_INET, &p->prefix.s_addr, prefix_buf, INET_ADDRSTRLEN);
++ /* Scan the RIB table for exactly matching RIB entry. */
++ rn = route_node_lookup (table, (struct prefix *) p);
++
++ /* No route for this prefix. */
++ if (! rn)
++ {
++ zlog_debug ("%s: lookup failed for %s/%d", __func__, prefix_buf, p->prefixlen);
++ return;
++ }
++
++ /* Unlock node. */
++ route_unlock_node (rn);
++
++ /* let's go */
++ for (rib = rn->info; rib; rib = rib->next)
++ {
++ zlog_debug
++ (
++ "%s: rn %p, rib %p: %s, %s",
++ __func__,
++ rn,
++ rib,
++ (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"),
++ (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected")
++ );
++ rib_dump (__func__, p, rib);
++ }
++}
++
+ int
+ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib)
+ {
+@@ -1408,10 +1624,24 @@
+
+ /* Link new rib to node.*/
+ rib_addnode (rn, rib);
++ if (IS_ZEBRA_DEBUG_RIB)
++ {
++ zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry",
++ __func__, rn, rib);
++ rib_dump (__func__, p, rib);
++ }
+
+ /* Free implicit route.*/
+ if (same)
++ {
++ if (IS_ZEBRA_DEBUG_RIB)
++ {
++ zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry",
++ __func__, rn, same);
++ rib_dump (__func__, p, same);
++ }
+ rib_delnode (rn, same);
++ }
+
+ route_unlock_node (rn);
+ return 0;
diff --git a/net/quagga/files/patch-cvs-4-nexthop_active_update b/net/quagga/files/patch-cvs-4-nexthop_active_update
new file mode 100644
index 000000000000..11ae35a428d5
--- /dev/null
+++ b/net/quagga/files/patch-cvs-4-nexthop_active_update
@@ -0,0 +1,47 @@
+--- zebra/zebra_rib.c.orig 2007-06-25 14:17:53.000000000 +0400
++++ zebra/zebra_rib.c 2007-08-08 11:38:18.000000000 +0400
+@@ -795,27 +795,32 @@
+ return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ }
+
++/* Iterate over all nexthops of the given RIB entry and refresh their
++ * ACTIVE flag. rib->nexthop_active_num is updated accordingly. If any
++ * nexthop is found to toggle the ACTIVE flag, the whole rib structure
++ * is flagged with ZEBRA_FLAG_CHANGED. The 4th 'set' argument is
++ * transparently passed to nexthop_active_check().
++ *
++ * Return value is the new number of active nexthops.
++ */
++
+ static int
+ nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
+ {
+ struct nexthop *nexthop;
+- int active;
++ int prev_active, new_active;
+
+ rib->nexthop_active_num = 0;
+ UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
+
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+- {
+- active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+-
+- nexthop_active_check (rn, rib, nexthop, set);
+- if ((MULTIPATH_NUM == 0 || rib->nexthop_active_num < MULTIPATH_NUM)
+- && active != CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+- SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
+-
+- if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+- rib->nexthop_active_num++;
+- }
++ {
++ prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
++ if ((new_active = nexthop_active_check (rn, rib, nexthop, set)))
++ rib->nexthop_active_num++;
++ if (prev_active != new_active)
++ SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
++ }
+ return rib->nexthop_active_num;
+ }
+
diff --git a/net/quagga/files/patch-cvs-5-sendbuffer b/net/quagga/files/patch-cvs-5-sendbuffer
new file mode 100644
index 000000000000..52187f7e0426
--- /dev/null
+++ b/net/quagga/files/patch-cvs-5-sendbuffer
@@ -0,0 +1,294 @@
+--- lib/sockopt.c.orig 2007-07-09 16:36:45.000000000 +0400
++++ lib/sockopt.c 2007-08-02 17:38:50.000000000 +0400
+@@ -29,20 +29,49 @@
+ int ret;
+
+ if ( (ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *)
+ &size, sizeof (int))) < 0)
+ zlog_err ("fd %d: can't setsockopt SO_RCVBUF to %d: %s",
+ sock,size,safe_strerror(errno));
+
+ return ret;
+ }
+
++int
++setsockopt_so_sendbuf (const int sock, int size)
++{
++ int ret = setsockopt (sock, SOL_SOCKET, SO_SNDBUF,
++ (char *)&size, sizeof (int));
++
++ if (ret < 0)
++ zlog_err ("fd %d: can't setsockopt SO_SNDBUF to %d: %s",
++ sock, size, safe_strerror (errno));
++
++ return ret;
++}
++
++int
++getsockopt_so_sendbuf (const int sock)
++{
++ u_int32_t optval;
++ socklen_t optlen = sizeof (optval);
++ int ret = getsockopt (sock, SOL_SOCKET, SO_SNDBUF,
++ (char *)&optval, &optlen);
++ if (ret < 0)
++ {
++ zlog_err ("fd %d: can't getsockopt SO_SNDBUF: %d (%s)",
++ sock, errno, safe_strerror (errno));
++ return ret;
++ }
++ return optval;
++}
++
+ static void *
+ getsockopt_cmsg_data (struct msghdr *msgh, int level, int type)
+ {
+ struct cmsghdr *cmsg;
+ void *ptr = NULL;
+
+ for (cmsg = ZCMSG_FIRSTHDR(msgh);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(msgh, cmsg))
+ if (cmsg->cmsg_level == level && cmsg->cmsg_type)
+--- lib/sockopt.h.orig 2007-07-09 16:36:45.000000000 +0400
++++ lib/sockopt.h 2007-08-01 17:37:33.000000000 +0400
+@@ -16,20 +16,22 @@
+ * 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 _ZEBRA_SOCKOPT_H
+ #define _ZEBRA_SOCKOPT_H
+
+ extern int setsockopt_so_recvbuf (int sock, int size);
++extern int setsockopt_so_sendbuf (const int sock, int size);
++extern int getsockopt_so_sendbuf (const int sock);
+
+ #ifdef HAVE_IPV6
+ extern int setsockopt_ipv6_pktinfo (int, int);
+ extern int setsockopt_ipv6_checksum (int, int);
+ extern int setsockopt_ipv6_multicast_hops (int, int);
+ extern int setsockopt_ipv6_unicast_hops (int, int);
+ extern int setsockopt_ipv6_hoplimit (int, int);
+ extern int setsockopt_ipv6_multicast_loop (int, int);
+ #endif /* HAVE_IPV6 */
+
+--- ospfd/ospfd.c.orig 2007-05-01 03:42:20.000000000 +0400
++++ ospfd/ospfd.c 2007-08-01 19:07:46.000000000 +0400
+@@ -205,20 +205,22 @@
+ new->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker,
+ new, new->lsa_refresh_interval);
+ new->lsa_refresher_started = quagga_time (NULL);
+
+ if ((new->fd = ospf_sock_init()) < 0)
+ {
+ zlog_err("ospf_new: fatal error: ospf_sock_init was unable to open "
+ "a socket");
+ exit(1);
+ }
++ new->maxsndbuflen = 0;
++ ospf_adjust_sndbuflen (new, OSPF_SNDBUFLEN_DEFAULT);
+ if ((new->ibuf = stream_new(OSPF_MAX_PACKET_SIZE+1)) == NULL)
+ {
+ zlog_err("ospf_new: fatal error: stream_new(%u) failed allocating ibuf",
+ OSPF_MAX_PACKET_SIZE+1);
+ exit(1);
+ }
+ new->t_read = thread_add_read (master, ospf_read, new, new->fd);
+ new->oi_write_q = list_new ();
+
+ return new;
+--- ospfd/ospfd.h.orig 2006-10-18 00:45:04.000000000 +0400
++++ ospfd/ospfd.h 2007-08-01 17:10:36.000000000 +0400
+@@ -122,20 +122,23 @@
+
+ /* OSPF Database Description flags. */
+ #define OSPF_DD_FLAG_MS 0x01
+ #define OSPF_DD_FLAG_M 0x02
+ #define OSPF_DD_FLAG_I 0x04
+ #define OSPF_DD_FLAG_ALL 0x07
+
+ #define OSPF_LS_REFRESH_SHIFT (60 * 15)
+ #define OSPF_LS_REFRESH_JITTER 60
+
++/* Initial send buffer size for ospfd raw sending socket. */
++#define OSPF_SNDBUFLEN_DEFAULT 1024
++
+ /* OSPF master for system wide configuration and variables. */
+ struct ospf_master
+ {
+ /* OSPF instance. */
+ struct list *ospf;
+
+ /* OSPF thread master. */
+ struct thread_master *master;
+
+ /* Zebra interface list. */
+@@ -259,20 +262,21 @@
+ #ifdef HAVE_OPAQUE_LSA
+ struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */
+ #endif /* HAVE_OPAQUE_LSA */
+ struct thread *t_maxage; /* MaxAge LSA remover timer. */
+ struct thread *t_maxage_walker; /* MaxAge LSA checking timer. */
+ struct thread *t_deferred_shutdown; /* deferred/stub-router shutdown timer*/
+
+ struct thread *t_write;
+ struct thread *t_read;
+ int fd;
++ int maxsndbuflen;
+ struct stream *ibuf;
+ struct list *oi_write_q;
+
+ /* Distribute lists out of other route sources. */
+ struct
+ {
+ char *name;
+ struct access_list *list;
+ } dlist[ZEBRA_ROUTE_MAX];
+ #define DISTRIBUTE_NAME(O,T) (O)->dlist[T].name
+--- ospfd/ospf_interface.c.orig 2007-04-22 17:26:38.000000000 +0400
++++ ospfd/ospf_interface.c 2007-08-02 18:31:53.000000000 +0400
+@@ -774,20 +774,25 @@
+ int
+ ospf_if_up (struct ospf_interface *oi)
+ {
+ if (oi == NULL)
+ return 0;
+
+ if (oi->type == OSPF_IFTYPE_LOOPBACK)
+ OSPF_ISM_EVENT_SCHEDULE (oi, ISM_LoopInd);
+ else
+ {
++ struct ospf *ospf = ospf_lookup ();
++ if (ospf != NULL)
++ ospf_adjust_sndbuflen (ospf, oi->ifp->mtu);
++ else
++ zlog_warn ("%s: ospf_lookup() returned NULL");
+ ospf_if_stream_set (oi);
+ OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceUp);
+ }
+
+ return 1;
+ }
+
+ int
+ ospf_if_down (struct ospf_interface *oi)
+ {
+--- ospfd/ospf_network.c.orig 2005-05-09 22:37:56.000000000 +0400
++++ ospfd/ospf_network.c 2007-08-01 20:03:26.000000000 +0400
+@@ -34,20 +34,21 @@
+ extern struct zebra_privs_t ospfd_privs;
+
+ #include "ospfd/ospfd.h"
+ #include "ospfd/ospf_network.h"
+ #include "ospfd/ospf_interface.h"
+ #include "ospfd/ospf_asbr.h"
+ #include "ospfd/ospf_lsa.h"
+ #include "ospfd/ospf_lsdb.h"
+ #include "ospfd/ospf_neighbor.h"
+ #include "ospfd/ospf_packet.h"
++#include "ospfd/ospf_dump.h"
+
+
+
+ /* Join to the OSPF ALL SPF ROUTERS multicast group. */
+ int
+ ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p,
+ unsigned int ifindex)
+ {
+ int ret;
+
+@@ -226,10 +227,44 @@
+ zlog_warn ("Can't set pktinfo option for fd %d", ospf_sock);
+
+ if (ospfd_privs.change (ZPRIVS_LOWER))
+ {
+ zlog_err ("ospf_sock_init: could not lower privs, %s",
+ safe_strerror (errno) );
+ }
+
+ return ospf_sock;
+ }
++
++void
++ospf_adjust_sndbuflen (struct ospf * ospf, int buflen)
++{
++ int ret, newbuflen;
++ /* Check if any work has to be done at all. */
++ if (ospf->maxsndbuflen >= buflen)
++ return;
++ if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
++ zlog_debug ("%s: adjusting OSPF send buffer size to %d",
++ __func__, buflen);
++ if (ospfd_privs.change (ZPRIVS_RAISE))
++ zlog_err ("%s: could not raise privs, %s", __func__,
++ safe_strerror (errno));
++ /* Now we try to set SO_SNDBUF to what our caller has requested
++ * (OSPF_SNDBUFLEN_DEFAULT initially, which seems to be a sane
++ * default; or the MTU of a newly added interface). However,
++ * if the OS has truncated the actual buffer size to somewhat
++ * less or bigger size, try to detect it and update our records
++ * appropriately.
++ */
++ ret = setsockopt_so_sendbuf (ospf->fd, buflen);
++ newbuflen = getsockopt_so_sendbuf (ospf->fd);
++ if (ret < 0 || newbuflen != buflen)
++ zlog_warn ("%s: tried to set SO_SNDBUF to %d, but got %d",
++ __func__, buflen, newbuflen);
++ if (newbuflen >= 0)
++ ospf->maxsndbuflen = newbuflen;
++ else
++ zlog_warn ("%s: failed to get SO_SNDBUF", __func__);
++ if (ospfd_privs.change (ZPRIVS_LOWER))
++ zlog_err ("%s: could not lower privs, %s", __func__,
++ safe_strerror (errno));
++}
+--- ospfd/ospf_network.h.orig 2005-05-06 21:26:18.000000000 +0400
++++ ospfd/ospf_network.h 2007-08-01 19:17:11.000000000 +0400
+@@ -27,12 +27,13 @@
+ extern int ospf_if_add_allspfrouters (struct ospf *, struct prefix *,
+ unsigned int);
+ extern int ospf_if_drop_allspfrouters (struct ospf *, struct prefix *,
+ unsigned int);
+ extern int ospf_if_add_alldrouters (struct ospf *, struct prefix *,
+ unsigned int);
+ extern int ospf_if_drop_alldrouters (struct ospf *, struct prefix *,
+ unsigned int);
+ extern int ospf_if_ipmulticast (struct ospf *, struct prefix *, unsigned int);
+ extern int ospf_sock_init (void);
++extern void ospf_adjust_sndbuflen (struct ospf *, int);
+
+ #endif /* _ZEBRA_OSPF_NETWORK_H */
+--- ospfd/ospf_packet.c.orig 2007-05-10 00:59:34.000000000 +0400
++++ ospfd/ospf_packet.c 2007-08-01 18:32:36.000000000 +0400
+@@ -595,22 +595,26 @@
+ assert (node);
+ oi = listgetdata (node);
+ assert (oi);
+
+ #ifdef WANT_OSPF_WRITE_FRAGMENT
+ /* seed ipid static with low order bits of time */
+ if (ipid == 0)
+ ipid = (time(NULL) & 0xffff);
+ #endif /* WANT_OSPF_WRITE_FRAGMENT */
+
+- /* convenience - max OSPF data per packet */
+- maxdatasize = oi->ifp->mtu - sizeof (struct ip);
++ /* convenience - max OSPF data per packet,
++ * and reliability - not more data, than our
++ * socket can accept
++ */
++ maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) -
++ sizeof (struct ip);
+
+ /* Get one packet from queue. */
+ op = ospf_fifo_head (oi->obuf);
+ assert (op);
+ assert (op->length >= OSPF_HEADER_SIZE);
+
+ if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS)
+ || op->dst.s_addr == htonl (OSPF_ALLDROUTERS))
+ ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex);
+
diff --git a/net/quagga/files/patch-cvs-6-RTF_DONE b/net/quagga/files/patch-cvs-6-RTF_DONE
new file mode 100644
index 000000000000..0cdd1d5d3b56
--- /dev/null
+++ b/net/quagga/files/patch-cvs-6-RTF_DONE
@@ -0,0 +1,20 @@
+--- zebra/kernel_socket.c.orig 13 Aug 2007 16:03:07 -0000 1.45
++++ zebra/kernel_socket.c 17 Aug 2007 12:38:10 -0000
+@@ -741,6 +741,8 @@
+ /* Read destination and netmask and gateway from rtm message
+ structure. */
+ flags = rtm_read_mesg (rtm, &dest, &mask, &gate, ifname, &ifnlen);
++ if (!(flags & RTF_DONE))
++ return;
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s: got rtm of type %d (%s)", __func__, rtm->rtm_type,
+ LOOKUP (rtm_type_str, rtm->rtm_type));
+@@ -794,8 +796,6 @@
+ {
+ char buf[INET_ADDRSTRLEN], gate_buf[INET_ADDRSTRLEN];
+ int ret;
+- if (!(flags & RTF_DONE))
+- return;
+ if (! IS_ZEBRA_DEBUG_RIB)
+ return;
+ ret = rib_lookup_ipv4_route (&p, &gate);
diff --git a/net/quagga/files/patch-cvs-7-ifm_read b/net/quagga/files/patch-cvs-7-ifm_read
new file mode 100644
index 000000000000..41e04d69982b
--- /dev/null
+++ b/net/quagga/files/patch-cvs-7-ifm_read
@@ -0,0 +1,18 @@
+--- zebra/kernel_socket.c.orig 17 Aug 2007 14:16:30 -0000 1.46
++++ zebra/kernel_socket.c 21 Aug 2007 14:30:40 -0000
+@@ -472,6 +472,15 @@
+ if_delete_update (ifp);
+ }
+ #endif /* RTM_IFANNOUNCE */
++ if (if_is_up (ifp))
++ {
++#if defined(__bsdi__)
++ if_kvm_get_mtu (ifp);
++#else
++ if_get_mtu (ifp);
++#endif /* __bsdi__ */
++ if_get_metric (ifp);
++ }
+ }
+
+ #ifdef HAVE_NET_RT_IFLIST