This is bgp_rt.c in view mode; [Download] [Up]
/*
* $Header: /disk/d/src/devel/gated/dist/src/RCS/bgp_rt.c,v 2.1 92/02/24 14:12:26 jch Exp $
*/
/*%Copyright%*/
/************************************************************************
* *
* GateD, Release 2 *
* *
* Copyright (c) 1990,1991,1992 by Cornell University *
* All rights reserved. *
* *
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY *
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT *
* LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY *
* AND FITNESS FOR A PARTICULAR PURPOSE. *
* *
* Royalty-free licenses to redistribute GateD Release *
* 2 in whole or in part may be obtained by writing to: *
* *
* GateDaemon Project *
* Information Technologies/Network Resources *
* 143 Caldwell Hall *
* Cornell University *
* Ithaca, NY 14853-2602 *
* *
* GateD is based on Kirton's EGP, UC Berkeley's routing *
* daemon (routed), and DCN's HELLO routing Protocol. *
* Development of Release 2 has been supported by the *
* National Science Foundation. *
* *
* Please forward bug fixes, enhancements and questions to the *
* gated mailing list: gated-people@gated.cornell.edu. *
* *
* Authors: *
* *
* Jeffrey C Honig <jch@gated.cornell.edu> *
* Scott W Brim <swb@gated.cornell.edu> *
* *
*************************************************************************
* *
* Portions of this software may fall under the following *
* copyrights: *
* *
* Copyright (c) 1988 Regents of the University of California. *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms are *
* permitted provided that the above copyright notice and *
* this paragraph are duplicated in all such forms and that *
* any documentation, advertising materials, and other *
* materials related to such distribution and use *
* acknowledge that the software was developed by the *
* University of California, Berkeley. The name of the *
* University may not be used to endorse or promote *
* products derived from this software without specific *
* prior written permission. THIS SOFTWARE IS PROVIDED *
* ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *
* *
************************************************************************/
#include "include.h"
#include "bgp.h"
#ifdef PROTO_BGP
static rt_data as_base =
{&as_base, &as_base};
static bits asorigin_bits[] =
{
{0, NULL},
{ASO_IGP, "IGP"},
{ASO_EGP, "EGP"},
{ASO_INCOMPLETE, "Incomplete"},
{0}
};
/*
* Dump the AS paths
*/
void
bgp_as_dump(fd)
FILE *fd;
{
int i;
rt_data *rtd;
as_path *asp;
/* Dump AS path information */
(void) fprintf(fd,
"\n\nAS Paths:\n");
RTDATA_LIST(rtd, &as_base) {
asp = (as_path *) rtd->rtd_data;
(void) fprintf(fd,
"\tRefcount %4d Length %3d:",
rtd->rtd_refcount,
asp->as_count);
for (i = 0; i < asp->as_count; i++) {
(void) fprintf(fd,
" %5u",
asp->as_number[i]);
}
(void) fprintf(fd,
" %5s\n",
trace_state(asorigin_bits, asp->as_origin));
} RTDATA_LIST_END(rtd, &as_base);
(void) fprintf(fd, "\n");
}
/*
* Dump an AS path
*/
static void
bgp_rt_dump(fd, rt)
FILE *fd;
rt_entry *rt;
{
int i;
as_path *asp;
if (rt->rt_data && rt->rt_data->rtd_data) {
asp = (as_path *) rt->rt_data->rtd_data;
if (asp) {
(void) fprintf(fd, "\t\t\tPath:");
for (i = 0; i < asp->as_count; i++) {
(void) fprintf(fd,
" %u",
asp->as_number[i]);
}
(void) fprintf(fd, " %s\n",
trace_state(asorigin_bits, asp->as_origin));
}
}
}
/*
* Allocate an AS entry given it's size
*/
rt_data *
bgp_as_alloc(pairs)
int pairs;
{
rt_data *rtd;
rtd = rtd_alloc(sizeof(as_path) + (sizeof(as_t) * (pairs - 1)));
rtd->rtd_dump = bgp_rt_dump;
return (rtd);
}
/*
* Build a one or two entry AS path, locate preexisting path and increment reference count
*/
as_path *
#ifdef USE_PROTOTYPES
bgp_as_build(int count, int origin, as_t AS)
#else /* USE_PROTOTYPES */
bgp_as_build(count, origin, AS)
int count;
int origin;
as_t AS;
#endif /* USE_PROTOTYPES */
{
static as_path asp;
if (count) {
asp.as_count = count;
asp.as_number[0] = AS;
}
asp.as_origin = origin;
return (&asp);
}
void
bgp_recv_Update(bnp, PDU, length)
bgpPeer *bnp;
bgpPdu *PDU;
int length;
{
u_char *cp, *lp;
int i, j;
u_char asCount;
u_char asDirection;
as_t asNumber;
u_short netCount;
u_short netMetric;
int error = 0;
pref_t preference;
struct sockaddr_in gateway;
struct in_addr bgp_gateway;
struct sockaddr_in netNumber;
metric_t metric = 0;
time_t rt_maxage = 0; /* BGP routes don't time out */
rt_entry *rt;
rt_data *rtd = (rt_data *) 0;
as_path *asp;
sockclear_in(&gateway);
sockclear_in(&netNumber);
cp = (u_char *) PDU;
lp = cp + length;
cp += sizeof(pduHeader);
rt_open(bnp->bgp_task);
/* Parse the gateway */
if ((cp + sizeof(bgp_gateway)) >= lp) {
/* This should probably be an invalid length error */
error = BGPUPDERR_GATEWAY;
goto Error;
}
PickUp(cp, bgp_gateway);
if (bnp->bgp_options & BGPO_GATEWAY) {
gateway = bnp->bgp_gateway; /* struct copy */
} else {
gateway.sin_addr = bgp_gateway; /* struct copy */
}
/* Parse the AS path */
PickUp(cp, asCount);
if (asCount == 0) {
error = BGPUPDERR_ASCOUNT;
goto Error;
}
if ((cp + asCount * (sizeof(asDirection) + sizeof(asNumber))) >= lp) {
error = BGPUPDERR_ASCOUNT;
goto Error;
}
rtd = bgp_as_alloc(i = asCount);
asp = (as_path *) rtd->rtd_data;
asp->as_count = asCount;
for (i = 0; i < asCount; i++) {
/* Pickup direction and As Number */
PickUp(cp, asDirection);
PickUp(cp, asNumber);
asNumber = ntohs(asNumber);
/* Make sure direction is valid */
if (!asDirection || (asDirection > asDirMax)) {
error = BGPUPDERR_DIRECTION;
goto Error;
}
/* Make sure EGP and Incompelete types only occur at the end of the list */
if (((asDirection == asDirEgp) || (asDirection == asDirIncomplete)) && (i != asCount - 1)) {
error = BGPUPDERR_ORDER;
goto Error;
}
/* Check for loops */
for (j = 0; j < i; j++) {
if ((asNumber == asp->as_number[j]) || (asNumber == bnp->bgp_asout)) {
error = BGPUPDERR_LOOP;
goto Error;
}
}
/* Looks OK, store this AS in the path structure */
asp->as_number[i] = asNumber;
}
if (asDirection == asDirEgp) {
asp->as_origin = ASO_EGP;
} else if (asDirection == asDirIncomplete) {
asp->as_origin = ASO_INCOMPLETE;
} else {
asp->as_origin = ASO_IGP;
}
/* Two phase rule violation check goes here */
/* Lookup this path, if duplicate return pointer to old path */
rtd = rtd_insert(rtd, &as_base);
asp = (as_path *) rtd->rtd_data;
/* Parse the networks */
PickUp(cp, netCount);
netCount = ntohs(netCount);
if (netCount == 0) {
error = BGPUPDERR_NETCOUNT;
goto Error;
}
if ((cp + netCount * (sizeof(netMetric) + sizeof(netNumber.sin_addr))) != lp) {
error = BGPUPDERR_NETCOUNT;
goto Error;
}
for (i = 0; i < netCount; i++) {
PickUp(cp, netNumber.sin_addr);
PickUp(cp, netMetric);
netMetric = ntohs(netMetric);
metric = netMetric;
/* Set default value of preference */
preference = bnp->bgp_preference;
/* Check if this network is valid from this peer */
if (!is_valid_in((sockaddr_un *) & netNumber, bnp->bgp_accept, (adv_entry *) 0, (adv_entry *) 0, &preference)) {
IF_BGPUPD {
trace(TR_BGP, 0, "bgp_recv_Update: net %-15A not valid from AS %5d",
&netNumber,
bnp->bgp_asin);
}
continue;
}
rt = rt_locate_gw(RTS_NETROUTE,
(sockaddr_un *) & netNumber,
bnp->bgp_task->task_rtproto,
&bnp->bgp_gw);
if (!rt) {
/* New route */
if (netMetric == bgpMetricInfinity) {
continue;
}
rt = rt_add((sockaddr_un *) & netNumber,
(sockaddr_un *) 0,
(sockaddr_un *) & gateway,
&bnp->bgp_gw,
metric,
(flag_t) (RTS_NOAGE |
((bnp->bgp_linktype == openLinkInternal) ?
(RTS_INTERIOR | RTS_NOTINSTALL | RTS_NOADVISE) : (RTS_EXTERIOR))),
bnp->bgp_task->task_rtproto,
bnp->bgp_asin,
rt_maxage,
preference);
if (rt) {
rt->rt_data = rtd;
rtd->rtd_refcount++;
} else {
error = BGPUPDERR_NETWORK;
goto Error;
}
} else {
/* Existing route */
if (netMetric == bgpMetricInfinity) {
/* Route is to be deleted */
(void) rt_delete(rt);
} else {
/* Change metric/gateway */
if (rt_change(rt,
(sockaddr_un *) & gateway,
metric,
rt_maxage,
preference)) {
rtd_unlink(rt->rt_data);
rt->rt_data = rtd;
rtd->rtd_refcount++;
}
}
}
}
Error:
/* Send error and close connection if necessary */
if (error) {
bgp_send_NotifyUpdate(bnp, error, PDU, length);
}
/* Free the as_path pointer if necessary */
if (rtd) {
rtd_unlink(rtd);
}
i = netCount;
if (!(bnp->bgp_options & BGPO_NOGENDEFAULT) && !(bnp->bgp_flags & BGPF_GENDEFAULT) && i) {
if (rt_default_add()) {
bnp->bgp_flags |= BGPF_GENDEFAULT;
}
}
if (rt_close(bnp->bgp_task, &bnp->bgp_gw, i)) {
task_flash(bnp->bgp_task);
}
return;
}
struct update_packet {
struct update_packet *up_next; /* Pointer to next packet on chain */
struct in_addr up_gateway; /* Gateway */
as_path *up_asp; /* Pointer to AS path */
u_char *up_ncp; /* Pointer to netCount field */
u_char *up_np; /* Network/Metric fill field */
u_short up_net_count; /* Number of networks in this update */
};
void
bgp_send_update_packet(bnp, packet)
bgpPeer *bnp;
struct update_packet *packet;
{
int length;
u_short uns_short;
bgpPdu *PDU;
u_char *cp;
cp = (u_char *) packet + sizeof(struct update_packet); /* Point to PDU */
PDU = (bgpPdu *) cp;
length = packet->up_np - cp - sizeof(pduHeader); /* Calculate length */
/* Set packet type */
PDU->header.type = bgpPduUpdate;
/* Add Network Count field to packet */
uns_short = htons(packet->up_net_count);
packet->up_net_count = 0;
packet->up_np = packet->up_ncp;
PutDown(packet->up_np, uns_short);
bgp_send(bnp, PDU, length);
}
void
bgp_send_update(bnp, flash_flag)
bgpPeer *bnp;
int flash_flag; /* Flash update */
{
int i;
u_short uns_short;
u_short net_Metric;
metric_t metric;
u_char *cp;
u_char uns_char;
as_path *asp;
struct update_packet *up, *upn;
struct update_packet *up_base = NULL;
struct sockaddr_in *gateway;
rt_entry *rt;
trace(TR_TASK, 0, "bgp_send_update: sending updates to %s",
bnp->bgp_name);
RT_TABLE(rt) {
metric = bgp_default_metric;
if (rt->rt_state & (RTS_HOSTROUTE | RTS_SUBNET | RTS_NOADVISE)) {
/* Subnets and hostroutes not allowed - also catch routes not to be announced */
continue;
}
if (flash_flag && (bnp->bgp_task->task_rtrevision >= rt->rt_revision)) {
/* Processing a flash update and this route has not been modified */
continue;
}
if (!propagate(rt,
(proto_t) 0,
bnp->bgp_propagate,
(adv_entry *) 0,
(adv_entry *) 0,
&metric)) {
continue;
}
/* Get pointer to an asp path for this route */
switch (rt->rt_proto) {
case RTPROTO_BGP:
asp = (as_path *) rt->rt_data->rtd_data;
if (!asp->as_count && (bnp->bgp_linktype == openLinkInternal)) {
/* Don't propogate internal routes over Internal links */
continue;
}
break;
case RTPROTO_EGP:
asp = bgp_as_build(1, ASO_EGP, rt->rt_as);
break;
default:
if (bnp->bgp_linktype == openLinkInternal) {
/* Do not propagate interior routes over Internal links */
continue;
}
asp = bgp_as_build(0, ASO_IGP, 0);
break;
}
/* Check for split horizon */
for (i = 0; i < asp->as_count; i++) {
if (asp->as_number[i] == bnp->bgp_asin) {
/* Don't send route back to this peer, it would cause a loop */
break;
}
}
if (i != asp->as_count) {
continue;
}
/* Determine gateway for this path */
if (gd_inet_wholenetof(rt->rt_router.in.sin_addr) !=gd_inet_wholenetof(bnp->bgp_interface->int_addr.in.sin_addr)) {
/* Gateway is my address */
gateway = &bnp->bgp_interface->int_addr.in;
} else {
/* Gateway is next hop */
gateway = &rt->rt_router.in;
}
/* Locate or allocate a packet for this path */
for (up = up_base; up; up = up->up_next) {
if ((asp == up->up_asp) && equal_in(gateway->sin_addr, up->up_gateway)) {
/* Send packet if already full */
if ((up->up_np - (u_char *) up - sizeof(struct update_packet) + 6 /* XXX */ ) > BGPMAXPACKETSIZE) {
bgp_send_update_packet(bnp, up);
}
break;
}
}
if (!up) {
up = (struct update_packet *) calloc(1, BGPMAXPACKETSIZE + sizeof(struct update_packet));
if (!up) {
trace(TR_ALL, LOG_ERR, "bgp_send_update: calloc %m");
quit(errno);
}
/* Add to chain */
up->up_next = up_base;
up_base = up;
/* Save gateway and as_path pointers */
up->up_gateway = gateway->sin_addr;
up->up_asp = asp;
/* Point to packet */
cp = (u_char *) up + sizeof(struct update_packet) + sizeof(pduHeader);
/* Add gateway */
PutDown(cp, gateway->sin_addr);
/* AS path */
if (bnp->bgp_linktype == openLinkInternal) {
/* Don't prepend my AS and link type if Internal */
uns_char = asp->as_count;
PutDown(cp, uns_char); /* Save AS count */
} else {
/* Prepend my AS and link type if not Internal */
uns_char = asp->as_count + 1;
PutDown(cp, uns_char); /* Save AS count */
uns_char = bnp->bgp_linktype;
PutDown(cp, uns_char); /* Put down direction */
uns_short = htons(bnp->bgp_asout);
PutDown(cp, uns_short); /* Put down AS number */
}
/* Add AS path */
for (i = 0; i < asp->as_count; i++) {
uns_char = asDirHorizontal;
PutDown(cp, uns_char);
uns_short = htons(asp->as_number[i]);
PutDown(cp, uns_short);
}
up->up_ncp = cp; /* Save pointer to network count */
up->up_np = cp + sizeof(u_short); /* Save pointer to where to save network */
/* XXX - The following is for compatibility with BGP */
/* version 1 and will hopefully be removed soon */
cp -= sizeof(as_t) + sizeof(uns_char);
if (asp->as_origin == ASO_IGP) {
uns_char = asDirHorizontal;
} else if (asp->as_origin == ASO_EGP) {
uns_char = asDirEgp;
} else {
uns_char = asDirIncomplete;
}
PutDown(cp, uns_char);
/* XXX - end of compatibility*/
}
up->up_net_count++;
/* Add networks and metrics */
/* Store the network */
PutDown(up->up_np, rt->rt_dest.in.sin_addr);
/* Metric is already set. Check here for metricout or unreachable */
if (!(rt->rt_ifp->int_state & IFS_UP) || (rt->rt_state & (RTS_HOLDDOWN | RTS_DELETE))) {
metric = bgpMetricInfinity;
} else if (bnp->bgp_options & BGPO_METRICOUT) {
metric = bnp->bgp_metricout;
}
net_Metric = metric;
PutDown(up->up_np, net_Metric);
} RT_TABLEEND;
/* Send and free any packets */
for (up = up_base; up; up = upn) {
upn = up->up_next;
bgp_send_update_packet(bnp, up);
(void) free((caddr_t) up);
}
bnp->bgp_task->task_rtrevision = rt_revision;
}
#endif /* PROTO_BGP */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.