static void bgp_clear(struct bgp_peer *peer);
static void bgp_set_retry(struct bgp_peer *peer);
-static void bgp_cidr(in_addr_t ip, in_addr_t mask, struct bgp_ip_prefix *pfx);
static struct bgp_route_list *bgp_insert_route(struct bgp_route_list *head,
struct bgp_route_list *new);
static struct bgp_route6_list *bgp_insert_route6(struct bgp_route6_list *head,
struct bgp_route6_list *new);
+static void bgp_process_timers(struct bgp_peer *peer);
static void bgp_free_routes(struct bgp_route_list *routes);
static void bgp_free_routes6(struct bgp_route6_list *routes);
static char const *bgp_msg_type_str(uint8_t type);
/* start connection with a peer */
int bgp_start(struct bgp_peer *peer, char *name, int as, int keepalive,
- int hold, int enable)
+ int hold, struct in_addr update_source, int enable)
{
struct hostent *h;
int ibgp;
}
memcpy(&peer->addr, h->h_addr, sizeof(peer->addr));
+ peer->source_addr = update_source.s_addr;
peer->as = as > 0 ? as : our_as;
ibgp = peer->as == our_as;
/* NEXT_HOP */
a.flags = BGP_PATH_ATTR_FLAG_TRANS;
a.code = BGP_PATH_ATTR_CODE_NEXT_HOP;
- ip = my_address; /* we're it */
+ if (config->nexthop_address)
+ {
+ ip = config->nexthop_address;
+ }
+ else
+ {
+ ip = my_address; /* we're it */
+ }
a.data.s.len = sizeof(ip);
memcpy(a.data.s.value, &ip, sizeof(ip));
bgp_halt(peer); /* give up */
}
-/* convert ip/mask to CIDR notation */
-static void bgp_cidr(in_addr_t ip, in_addr_t mask, struct bgp_ip_prefix *pfx)
-{
- int i;
- uint32_t b;
-
- /* convert to prefix notation */
- pfx->len = 32;
- pfx->prefix = ip;
-
- if (!mask) /* bogus */
- mask = 0xffffffff;
-
- for (i = 0; i < 32 && ((b = ntohl(1 << i)), !(mask & b)); i++)
- {
- pfx->len--;
- pfx->prefix &= ~b;
- }
-}
-
/* insert route into list; sorted */
static struct bgp_route_list *bgp_insert_route(struct bgp_route_list *head,
struct bgp_route_list *new)
* that if that route is later deleted we don't have to be concerned
* about adding back the more specific one).
*/
-int bgp_add_route(in_addr_t ip, in_addr_t mask)
+int bgp_add_route(in_addr_t ip, int prefixlen)
{
struct bgp_route_list *r = bgp_routes;
struct bgp_route_list add;
int i;
- bgp_cidr(ip, mask, &add.dest);
+ add.dest.prefix = ip;
+ add.dest.len = prefixlen;
add.next = 0;
/* check for duplicate */
}
/* remove route from list for peers */
-int bgp_del_route(in_addr_t ip, in_addr_t mask)
+int bgp_del_route(in_addr_t ip, int prefixlen)
{
struct bgp_route_list *r = bgp_routes;
struct bgp_route_list *e = 0;
struct bgp_route_list del;
int i;
- bgp_cidr(ip, mask, &del.dest);
+ del.dest.prefix = ip;
+ del.dest.len = prefixlen;
del.next = 0;
/* find entry in routes list and remove */
}
/* process timers */
- if (peer->state == Established)
- {
- if (time_now > peer->expire_time)
- {
- LOG(1, 0, 0, "No message from BGP peer %s in %ds\n",
- peer->name, peer->hold);
+ bgp_process_timers(peer);
+ }
- bgp_send_notification(peer, BGP_ERR_HOLD_TIMER_EXP, 0);
- continue;
- }
+ return 1;
+}
- if (time_now > peer->keepalive_time && !peer->outbuf->packet.header.len)
- bgp_send_keepalive(peer);
- }
- else if (peer->state == Idle)
- {
- if (time_now > peer->retry_time)
- bgp_connect(peer);
- }
- else if (time_now > peer->state_time + BGP_STATE_TIME)
+/* process bgp timers only */
+void bgp_process_peers_timers()
+{
+ int i;
+
+ if (!bgp_configured)
+ return;
+
+ for (i = 0; i < BGP_NUM_PEERS; i++)
+ {
+ struct bgp_peer *peer = &bgp_peers[i];
+
+ if (peer->state == Disabled)
+ continue;
+
+ bgp_process_timers(peer);
+ }
+}
+
+static void bgp_process_timers(struct bgp_peer *peer)
+{
+ if (peer->state == Established)
+ {
+ if (time_now > peer->expire_time)
{
- LOG(1, 0, 0, "%s timer expired for BGP peer %s\n",
- bgp_state_str(peer->state), peer->name);
+ LOG(1, 0, 0, "No message from BGP peer %s in %ds\n",
+ peer->name, peer->hold);
- bgp_restart(peer);
+ bgp_send_notification(peer, BGP_ERR_HOLD_TIMER_EXP, 0);
+ return;
}
+
+ if (time_now > peer->keepalive_time && !peer->outbuf->packet.header.len)
+ bgp_send_keepalive(peer);
+ }
+ else if (peer->state == Idle)
+ {
+ if (time_now > peer->retry_time)
+ bgp_connect(peer);
}
+ else if (time_now > peer->state_time + BGP_STATE_TIME)
+ {
+ LOG(1, 0, 0, "%s timer expired for BGP peer %s\n",
+ bgp_state_str(peer->state), peer->name);
- return 1;
+ bgp_restart(peer);
+ }
}
static void bgp_free_routes(struct bgp_route_list *routes)
{
static int bgp_port = 0;
struct sockaddr_in addr;
+ struct sockaddr_in source_addr;
struct epoll_event ev;
if (!bgp_port)
/* set to non-blocking */
fcntl(peer->sock, F_SETFL, fcntl(peer->sock, F_GETFL, 0) | O_NONBLOCK);
+ /* set source address */
+ memset(&source_addr, 0, sizeof(source_addr));
+ source_addr.sin_family = AF_INET;
+ source_addr.sin_addr.s_addr = peer->source_addr; /* defaults to INADDR_ANY */
+ if (bind(peer->sock, (struct sockaddr *) &source_addr, sizeof(source_addr)) < 0)
+ {
+ LOG(1, 0, 0, "Can't set source address to %s: %s\n",
+ inet_ntoa(source_addr.sin_addr), strerror(errno));
+
+ bgp_set_retry(peer);
+ return 0;
+ }
+
/* try connect */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
if (notification->error_code == BGP_ERR_CEASE)
{
LOG(4, 0, 0, "BGP peer %s sent CEASE\n", peer->name);
- bgp_restart(peer);
+ bgp_set_retry(peer);
return 0;
}
data.version = BGP_VERSION;
data.as = htons(our_as);
data.hold_time = htons(peer->hold);
- data.identifier = my_address;
+ /* use the source IP we use as identifier, if available */
+ if (peer->source_addr != INADDR_ANY)
+ data.identifier = peer->source_addr;
+ else
+ data.identifier = my_address;
/* if we know peer doesn't support MP (mp_handling == DoesntHandleIPv6Routes)
then don't add this parameter */