Created
November 12, 2009 15:33
-
-
Save kjmkznr/232985 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/nest/iface.h b/nest/iface.h | |
index af98a76..2ba8139 100644 | |
--- a/nest/iface.h | |
+++ b/nest/iface.h | |
@@ -99,6 +99,7 @@ typedef struct neighbor { | |
#define NEF_STICKY 1 | |
neighbor *neigh_find(struct proto *, ip_addr *, unsigned flags); | |
+neighbor *neigh_find_by_if(struct proto *, ip_addr *, unsigned flags, struct iface *i); | |
static inline int neigh_connected_to(struct proto *p, ip_addr *a, struct iface *i) | |
{ | |
diff --git a/nest/neighbor.c b/nest/neighbor.c | |
index 2c5af6a..156eaa9 100644 | |
--- a/nest/neighbor.c | |
+++ b/nest/neighbor.c | |
@@ -115,7 +115,7 @@ neigh_find(struct proto *p, ip_addr *a, unsigned flags) | |
class = ipa_classify(*a); | |
if (class < 0) /* Invalid address */ | |
return NULL; | |
- if ((class & IADDR_SCOPE_MASK) < SCOPE_SITE || | |
+ if ((class & IADDR_SCOPE_MASK) < SCOPE_LINK || | |
!(class & IADDR_HOST)) | |
return NULL; /* Bad scope or a somecast */ | |
@@ -150,6 +150,71 @@ neigh_find(struct proto *p, ip_addr *a, unsigned flags) | |
return n; | |
} | |
+ | |
+/** | |
+ * neigh_find_by_if - find or create a neighbor entry by interface. | |
+ * @p: protocol which asks for the entry. | |
+ * @a: pointer to IP address of the node to be searched for. | |
+ * @flags: 0 or %NEF_STICKY if you want to create a sticky entry. | |
+ * @i: interface | |
+ * | |
+ * Search the neighbor cache for a node with given IP address. If | |
+ * it's found, a pointer to the neighbor entry is returned. If no | |
+ * such entry exists and the node is directly connected on | |
+ * one of our active interfaces, a new entry is created and returned | |
+ * to the caller with protocol-dependent fields initialized to zero. | |
+ * If the node is not connected directly or *@a is not a valid unicast | |
+ * IP address, neigh_find() returns %NULL. | |
+ */ | |
+neighbor * | |
+neigh_find_by_if(struct proto *p, ip_addr *a, unsigned flags, struct iface *i) | |
+{ | |
+ neighbor *n; | |
+ int class, scope = SCOPE_HOST; | |
+ unsigned int h = neigh_hash(p, a); | |
+ struct iface *j; | |
+ | |
+ WALK_LIST(n, neigh_hash_table[h]) /* Search the cache */ | |
+ if (n->proto == p && ipa_equal(*a, n->addr)) | |
+ return n; | |
+ | |
+ class = ipa_classify(*a); | |
+ if (class < 0) /* Invalid address */ | |
+ return NULL; | |
+ if ((class & IADDR_SCOPE_MASK) < SCOPE_LINK || | |
+ !(class & IADDR_HOST)) | |
+ return NULL; /* Bad scope or a somecast */ | |
+ | |
+ j = NULL; | |
+ if ((scope = if_connected(a, i)) >= 0) | |
+ { | |
+ j = i; | |
+ } | |
+ if (!j && !(flags & NEF_STICKY)) | |
+ return NULL; | |
+ | |
+ n = sl_alloc(neigh_slab); | |
+ if_dump_all(); | |
+ n->addr = *a; | |
+ n->iface = j; | |
+ if (j) | |
+ { | |
+ add_tail(&neigh_hash_table[h], &n->n); | |
+ add_tail(&j->neighbors, &n->if_n); | |
+ } | |
+ else | |
+ { | |
+ add_tail(&sticky_neigh_list, &n->n); | |
+ scope = 0; | |
+ } | |
+ n->proto = p; | |
+ n->data = NULL; | |
+ n->aux = 0; | |
+ n->flags = flags; | |
+ n->scope = scope; | |
+ return n; | |
+} | |
+ | |
/** | |
* neigh_dump - dump specified neighbor entry. | |
* @n: the entry to dump | |
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c | |
index b38c6b1..2f3bdf6 100644 | |
--- a/proto/bgp/bgp.c | |
+++ b/proto/bgp/bgp.c | |
@@ -536,6 +536,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c | |
s->tos = IP_PREC_INTERNET_CONTROL; | |
s->password = p->cf->password; | |
s->tx_hook = bgp_connected; | |
+ s->iface = p->neigh->iface; | |
BGP_TRACE(D_EVENTS, "Connecting to %I from local address %I", s->daddr, s->saddr); | |
bgp_setup_conn(p, conn); | |
bgp_setup_sk(p, conn, s); | |
@@ -691,7 +692,10 @@ bgp_start_locked(struct object_lock *lock) | |
DBG("BGP: Got lock\n"); | |
p->local_id = proto_get_router_id(&cf->c); | |
p->next_hop = cf->multihop ? cf->multihop_via : cf->remote_ip; | |
- p->neigh = neigh_find(&p->p, &p->next_hop, NEF_STICKY); | |
+ if(cf->source_iface) | |
+ p->neigh = neigh_find_by_if(&p->p, &p->next_hop, NEF_STICKY, if_find_by_name(cf->source_iface)); | |
+ else | |
+ p->neigh = neigh_find(&p->p, &p->next_hop, NEF_STICKY); | |
if (cf->rr_client) | |
{ | |
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h | |
index 0a82be2..d3a97ff 100644 | |
--- a/proto/bgp/bgp.h | |
+++ b/proto/bgp/bgp.h | |
@@ -22,6 +22,7 @@ struct bgp_config { | |
int multihop; /* Number of hops if multihop */ | |
ip_addr multihop_via; /* Multihop: address to route to */ | |
ip_addr source_addr; /* Source address to use */ | |
+ char *source_iface; /* Source interface to use */ | |
int next_hop_self; /* Always set next hop to local IP address */ | |
int compare_path_lengths; /* Use path lengths when selecting best route */ | |
u32 default_local_pref; /* Default value for LOCAL_PREF attribute */ | |
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y | |
index 7360820..bbe3a43 100644 | |
--- a/proto/bgp/config.Y | |
+++ b/proto/bgp/config.Y | |
@@ -21,7 +21,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE, | |
ERROR, START, DELAY, FORGET, WAIT, ENABLE, DISABLE, AFTER, | |
BGP_PATH, BGP_LOCAL_PREF, BGP_MED, BGP_ORIGIN, BGP_NEXT_HOP, | |
BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY, SOURCE, ADDRESS, | |
- PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4, ADVERTISE, IPV4, | |
+ INTERFACE, PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4, ADVERTISE, IPV4, | |
CAPABILITIES, LIMIT, PASSIVE) | |
CF_GRAMMAR | |
@@ -68,6 +68,7 @@ bgp_proto: | |
| bgp_proto DEFAULT BGP_MED expr ';' { BGP_CFG->default_med = $4; } | |
| bgp_proto DEFAULT BGP_LOCAL_PREF expr ';' { BGP_CFG->default_local_pref = $4; } | |
| bgp_proto SOURCE ADDRESS ipa ';' { BGP_CFG->source_addr = $4; } | |
+ | bgp_proto SOURCE INTERFACE TEXT ';' { BGP_CFG->source_iface = $4; } | |
| bgp_proto START DELAY TIME expr ';' { BGP_CFG->start_delay_time = $5; } | |
| bgp_proto ERROR FORGET TIME expr ';' { BGP_CFG->error_amnesia_time = $5; } | |
| bgp_proto ERROR WAIT TIME expr ',' expr ';' { BGP_CFG->error_delay_time_min = $5; BGP_CFG->error_delay_time_max = $7; } | |
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c | |
index d126fe5..edadb17 100644 | |
--- a/proto/bgp/packets.c | |
+++ b/proto/bgp/packets.c | |
@@ -678,7 +678,10 @@ bgp_get_nexthop(struct bgp_proto *bgp, rta *a) | |
struct eattr *nh = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP)); | |
ASSERT(nh); | |
nexthop = *(ip_addr *) nh->u.ptr->data; | |
- neigh = neigh_find(&bgp->p, &nexthop, 0); | |
+ if(bgp->cf->source_iface) | |
+ neigh = neigh_find_by_if(&bgp->p, &nexthop, 0, if_find_by_name(bgp->cf->source_iface)); | |
+ else | |
+ neigh = neigh_find(&bgp->p, &nexthop, 0); | |
if (neigh) | |
{ | |
if (neigh->scope == SCOPE_HOST) | |
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c | |
index 330aea4..34369b1 100644 | |
--- a/sysdep/unix/io.c | |
+++ b/sysdep/unix/io.c | |
@@ -17,6 +17,7 @@ | |
#include <sys/un.h> | |
#include <unistd.h> | |
#include <errno.h> | |
+#include <net/if.h> | |
#include "nest/bird.h" | |
#include "lib/lists.h" | |
@@ -911,6 +912,21 @@ sk_open(sock *s) | |
break; | |
} | |
} | |
+#ifdef IPV6 | |
+ /* Use link local address */ | |
+ if(s->iface){ | |
+ struct ifa *a; | |
+ WALK_LIST(a, s->iface->addrs) | |
+ if(a->scope == SCOPE_LINK) | |
+ { | |
+ struct ifreq ifr; | |
+ log(L_TRACE "Using Interface %s", s->iface->name); | |
+ strcpy(ifr.ifr_name, s->iface->name); | |
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) | |
+ ERR("SO_BINDTODEVICE"); | |
+ } | |
+ } | |
+#endif /* IPV6 */ | |
if (has_src) | |
{ | |
int port; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c | |
index 4410c04..9c4019d 100644 | |
--- a/proto/bgp/bgp.c | |
+++ b/proto/bgp/bgp.c | |
@@ -553,6 +553,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c | |
s->tos = IP_PREC_INTERNET_CONTROL; | |
s->password = p->cf->password; | |
s->tx_hook = bgp_connected; | |
+ s->iface = p->neigh->iface; | |
BGP_TRACE(D_EVENTS, "Connecting to %I from local address %I", s->daddr, s->saddr); | |
bgp_setup_conn(p, conn); | |
bgp_setup_sk(conn, s); | |
@@ -729,7 +730,10 @@ bgp_start_locked(struct object_lock *lock) | |
DBG("BGP: Got lock\n"); | |
p->local_id = proto_get_router_id(&cf->c); | |
p->next_hop = cf->multihop ? cf->multihop_via : cf->remote_ip; | |
- p->neigh = neigh_find(&p->p, &p->next_hop, NEF_STICKY); | |
+ if(cf->ifname) | |
+ p->neigh = neigh_find2(&p->p, &p->next_hop, if_find_by_name(cf->ifname), NEF_STICKY); | |
+ else | |
+ p->neigh = neigh_find(&p->p, &p->next_hop, NEF_STICKY); | |
if (cf->rr_client) | |
{ | |
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h | |
index 1a29195..cef519f 100644 | |
--- a/proto/bgp/bgp.h | |
+++ b/proto/bgp/bgp.h | |
@@ -22,6 +22,7 @@ struct bgp_config { | |
int multihop; /* Number of hops if multihop */ | |
ip_addr multihop_via; /* Multihop: address to route to */ | |
ip_addr source_addr; /* Source address to use */ | |
+ char *ifname; /* Source interface to use */ | |
int next_hop_self; /* Always set next hop to local IP address */ | |
int missing_lladdr; /* What we will do when we don' know link-local addr, see MLL_* */ | |
int compare_path_lengths; /* Use path lengths when selecting best route */ | |
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y | |
index f882aaa..24ab8b0 100644 | |
--- a/proto/bgp/config.Y | |
+++ b/proto/bgp/config.Y | |
@@ -23,7 +23,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE, | |
BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY, SOURCE, ADDRESS, | |
PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4, ADVERTISE, IPV4, | |
CAPABILITIES, LIMIT, PASSIVE, PREFER, OLDER, MISSING, LLADDR, | |
- DROP, IGNORE, ROUTE, REFRESH, INTERPRET, COMMUNITIES) | |
+ DROP, IGNORE, ROUTE, REFRESH, INTERPRET, COMMUNITIES, INTERFACE) | |
CF_GRAMMAR | |
@@ -53,11 +53,12 @@ bgp_proto: | |
bgp_proto_start proto_name '{' | |
| bgp_proto proto_item ';' | |
| bgp_proto LOCAL AS expr ';' { BGP_CFG->local_as = $4; } | |
- | bgp_proto NEIGHBOR ipa AS expr ';' { | |
+ | bgp_proto NEIGHBOR ipa AS expr INTERFACE TEXT ';' { | |
if (ipa_nonzero(BGP_CFG->remote_ip)) cf_error("Only one neighbor per BGP instance is allowed"); | |
BGP_CFG->remote_ip = $3; | |
BGP_CFG->remote_as = $5; | |
+ BGP_CFG->ifname = $7; | |
} | |
| bgp_proto RR CLUSTER ID idval ';' { BGP_CFG->rr_cluster_id = $5; } | |
| bgp_proto RR CLIENT ';' { BGP_CFG->rr_client = 1; } | |
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c | |
index 2baa6e3..a83a5d9 100644 | |
--- a/proto/bgp/packets.c | |
+++ b/proto/bgp/packets.c | |
@@ -809,7 +809,10 @@ bgp_get_nexthop(struct bgp_proto *bgp, rta *a) | |
struct eattr *nh = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP)); | |
ASSERT(nh); | |
nexthop = *(ip_addr *) nh->u.ptr->data; | |
- neigh = neigh_find(&bgp->p, &nexthop, 0); | |
+ if(bgp->cf->ifname) | |
+ neigh = neigh_find2(&bgp->p, &nexthop, if_find_by_name(bgp->cf->ifname), 0); | |
+ else | |
+ neigh = neigh_find(&bgp->p, &nexthop, 0); | |
if (neigh) | |
{ | |
if (neigh->scope == SCOPE_HOST) | |
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c | |
index d86c8cb..2876062 100644 | |
--- a/sysdep/unix/io.c | |
+++ b/sysdep/unix/io.c | |
@@ -17,6 +17,7 @@ | |
#include <sys/un.h> | |
#include <unistd.h> | |
#include <errno.h> | |
+#include <net/if.h> | |
#include "nest/bird.h" | |
#include "lib/lists.h" | |
@@ -1002,6 +1003,22 @@ sk_open(sock *s) | |
if (err = sk_setup(s)) | |
goto bad; | |
+#ifdef IPV6 | |
+ /* Use link local address */ | |
+ if(s->iface){ | |
+ struct ifa *a; | |
+ WALK_LIST(a, s->iface->addrs) | |
+ if(a->scope == SCOPE_LINK) | |
+ { | |
+ struct ifreq ifr; | |
+ log(L_TRACE "Using Interface %s", s->iface->name); | |
+ strcpy(ifr.ifr_name, s->iface->name); | |
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) | |
+ ERR("SO_BINDTODEVICE"); | |
+ } | |
+ } | |
+#endif /* IPV6 */ | |
+ | |
if (has_src) | |
{ | |
int port; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment