struct attr_flags *a, struct nexthop *nh)
struct rde_aspath *a)
up_generate_attr(struct rde_peer *peer, struct update_attr *upa,    struct attr_flags *a, struct nexthop *nh){	struct aspath	*path;	struct attr	*oa;	u_int32_t	 tmp32;	in_addr_t	 nexthop, mask;	int		 r;	u_int16_t	 len = sizeof(up_attr_buf), wlen = 0;	/* origin */	if ((r = attr_write(up_attr_buf + wlen, len, ATTR_WELL_KNOWN,	    ATTR_ORIGIN, &a->origin, 1)) == -1)		return (-1);	wlen += r; len -= r;	/* aspath */	path = aspath_prepend(a->aspath, rde_local_as(), peer->conf.ebgp);	if ((r = attr_write(up_attr_buf + wlen, len, ATTR_WELL_KNOWN,	    ATTR_ASPATH, path->data, path->len)) == -1)		return (-1);	aspath_put(path);	wlen += r; len -= r;	/* nexthop, already network byte order */	if (peer->conf.ebgp == 0) {		/*		 * if directly connected use peer->local_addr		 */		if (nh->flags & NEXTHOP_ANNOUNCE)			nexthop = peer->local_addr.v4.s_addr;		else if (a->nexthop.s_addr == peer->remote_addr.v4.s_addr)			/*			 * per rfc: if remote peer address is equal to			 * the nexthop set the nexthop to our local address.			 * This reduces the risk of routing loops.			 */			nexthop = peer->local_addr.v4.s_addr;		else			nexthop = nh->exit_nexthop.v4.s_addr;	} else if (peer->conf.distance == 1) {		/* ebgp directly connected */		if (nh->flags & NEXTHOP_CONNECTED) {			mask = 0xffffffff << (32 - nh->nexthop_netlen);			mask = htonl(mask);			if ((peer->remote_addr.v4.s_addr & mask) ==			    (nh->nexthop_net.v4.s_addr & mask))				/* nexthop and peer are in the same net */				nexthop = nh->exit_nexthop.v4.s_addr;			else				nexthop = peer->local_addr.v4.s_addr;		} else			nexthop = peer->local_addr.v4.s_addr;	} else		/* ebgp multihop */		/*		 * XXX for ebgp multihop nh->flags should never have		 * NEXTHOP_CONNECTED set so it should be possible to unify the		 * two ebgp cases.		 */		nexthop = peer->local_addr.v4.s_addr;	if ((r = attr_write(up_attr_buf + wlen, len, ATTR_WELL_KNOWN,	    ATTR_NEXTHOP, &nexthop, 4)) == -1)		return (-1);	wlen += r; len -= r;	/*	 * The MED of other peers MUST not be announced to others.	 * Currently we just dump it. Possibilities are setting the MED via	 * a filter or set it to local-pref. struct attr_flags probably needs	 * a med_in and a med_out field.	 */	if (peer->conf.ebgp == 0) {		/* local preference, only valid for ibgp */		tmp32 = htonl(a->lpref);		if ((r = attr_write(up_attr_buf + wlen, len, ATTR_WELL_KNOWN,		    ATTR_LOCALPREF, &tmp32, 4)) == -1)			return (-1);		wlen += r; len -= r;	}	/*	 * dump all other path attributes. Following rules apply:	 *  1. well-known attrs: ATTR_ATOMIC_AGGREGATE and ATTR_AGGREGATOR	 *     pass unmodified (enforce flags to correct values)	 *  2. non-transitive attrs: don't re-announce to ebgp peers	 *  3. transitive known attrs: announce unmodified	 *  4. transitive unknown attrs: set partial bit and re-announce	 */	TAILQ_FOREACH(oa, &a->others, entry) {		switch (oa->type) {		case ATTR_ATOMIC_AGGREGATE:			if ((r = attr_write(up_attr_buf + wlen, len,			    ATTR_WELL_KNOWN, ATTR_ATOMIC_AGGREGATE,			    NULL, 0)) == -1)				return (-1);			break;		case ATTR_AGGREGATOR:		case ATTR_COMMUNITIES:		case ATTR_ORIGINATOR_ID:		case ATTR_CLUSTER_LIST:			if ((!(oa->flags & ATTR_TRANSITIVE)) &&			    peer->conf.ebgp != 0) {				r = 0;				break;			}			if ((r = attr_write(up_attr_buf + wlen, len,			    oa->flags, oa->type, oa->data, oa->len)) == -1)				return (-1);			break;		default:			/* unknown attribute */			if (!(oa->flags & ATTR_TRANSITIVE)) {				/*				 * RFC 1771:				 * Unrecognized non-transitive optional				 * attributes must be quietly ignored and				 * not passed along to other BGP peers.				 */				r = 0;				break;			}			if ((r = attr_write(up_attr_buf + wlen, len,			    oa->flags | ATTR_PARTIAL, oa->type,			    oa->data, oa->len)) == -1)				return (-1);			break;		}		wlen += r; len -= r;	}	/* the bgp path attributes are now stored in the global buf */	upa->attr = malloc(wlen);	if (upa->attr == NULL)		fatal("up_generate_attr");	memcpy(upa->attr, up_attr_buf, wlen);	upa->attr_len = wlen;	return (wlen);}