summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@diac24.net>2010-02-02 20:18:23 +0100
committerDenis Ovsienko <infrastation@yandex.ru>2011-11-21 19:41:59 +0400
commit1727d2e2b939c8670d0f0e0d1a0e5eb0a8be2135 (patch)
tree3bdfda661f96113d61eae25059608d468a8ea4cc
parent17e52061bacec93e84324b23382e5ec61e1f16d0 (diff)
bgpd: fix update-source for IPv6 (BZ#548)
if update-source was given as interface name, bgpd was unconditionally trying to bind to an IPv4 address from that interface. change function to find the best-matching (number of address bits) same-family address on the interface.
-rw-r--r--bgpd/bgp_network.c39
1 files changed, 27 insertions, 12 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 52c72b67..b9cb6223 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -263,21 +263,37 @@ bgp_bind_address (int sock, struct in_addr *addr)
return 0;
}
-static struct in_addr *
-bgp_update_address (struct interface *ifp)
+static int
+bgp_update_address (struct interface *ifp, const union sockunion *dst,
+ union sockunion *addr)
{
- struct prefix_ipv4 *p;
+ struct prefix *p, *sel, *d;
struct connected *connected;
struct listnode *node;
+ int common;
+
+ d = sockunion2hostprefix (dst);
+ sel = NULL;
+ common = -1;
for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
{
- p = (struct prefix_ipv4 *) connected->address;
-
- if (p->family == AF_INET)
- return &p->prefix;
+ p = connected->address;
+ if (p->family != d->family)
+ continue;
+ if (prefix_common_bits (p, d) > common)
+ {
+ sel = p;
+ common = prefix_common_bits (sel, d);
+ }
}
- return NULL;
+
+ prefix_free (d);
+ if (!sel)
+ return 1;
+
+ prefix2sockunion (sel, addr);
+ return 0;
}
/* Update source selection. */
@@ -285,7 +301,7 @@ static void
bgp_update_source (struct peer *peer)
{
struct interface *ifp;
- struct in_addr *addr;
+ union sockunion addr;
/* Source is specified with interface name. */
if (peer->update_if)
@@ -294,11 +310,10 @@ bgp_update_source (struct peer *peer)
if (! ifp)
return;
- addr = bgp_update_address (ifp);
- if (! addr)
+ if (bgp_update_address (ifp, &peer->su, &addr))
return;
- bgp_bind_address (peer->fd, addr);
+ sockunion_bind (peer->fd, &addr, 0, &addr);
}
/* Source is specified with IP address. */