diff options
Diffstat (limited to 'proto/bgp/attrs.c')
-rw-r--r-- | proto/bgp/attrs.c | 81 |
1 files changed, 47 insertions, 34 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 0fdc3b6..841fe10 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -23,16 +23,20 @@ void bgp_rt_notify(struct proto *P, net *n, rte *new, rte *old, ea_list *tmpa) { DBG("BGP: Got route %I/%d\n", n->n.prefix, n->n.pxlen); + /* FIXME: Normalize attributes */ + /* FIXME: Check next hop */ + /* FIXME: Someone might have undefined the mandatory attributes */ } -static ea_list * -bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list *old, struct linpool *pool) +static int +bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *pool) { ea_list *ea = lp_alloc(pool, sizeof(ea_list) + 3*sizeof(eattr)); eattr *a = ea->attrs; rta *rta = e->attrs; - ea->next = old; + ea->next = *attrs; + *attrs = ea; ea->flags = EALF_SORTED; ea->count = 3; @@ -68,17 +72,14 @@ bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list *old, struct linpool *pool a->type = EAF_TYPE_IP_ADDRESS; a->u.ptr = lp_alloc(pool, sizeof(struct adata) + sizeof(ip_addr)); a->u.ptr->length = sizeof(ip_addr); - - /* FIXME: These rules are bogus!!! */ - if (rta->dest == RTD_ROUTER) - *(ip_addr *)a->u.ptr->data = e->attrs->gw; + if (p->cf->next_hop_self || + !p->is_internal || + rta->dest != RTD_ROUTER) + *(ip_addr *)a->u.ptr->data = p->local_addr; else - { - /* FIXME: Next hop == self ... how to do that? */ - *(ip_addr *)a->u.ptr->data = IPA_NONE; - } + *(ip_addr *)a->u.ptr->data = e->attrs->gw; - return ea; + return 0; /* Leave decision to the filters */ } ea_list * @@ -115,15 +116,37 @@ bgp_path_prepend(struct linpool *pool, eattr *a, ea_list *old, int as) return e; } -static ea_list * -bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list *old, struct linpool *pool) +static int +bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *pool) { + eattr *a; + if (!p->is_internal) - old = bgp_path_prepend(pool, ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH)), old, p->local_as); + *attrs = bgp_path_prepend(pool, ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH)), *attrs, p->local_as); - /* FIXME: Set NEXT_HOP to self */ + a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP)); + if (a && (p->is_internal || (!p->is_internal && e->attrs->iface == p->neigh->iface))) + { + /* Leave the original next hop attribute, will check later where does it point */ + } + else + { + /* Need to create new one */ + ea_list *ea = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr)); + ea->next = *attrs; + *attrs = ea; + ea->flags = EALF_SORTED; + ea->count = 1; + a = ea->attrs; + a->id = EA_CODE(EAP_BGP, BA_NEXT_HOP); + a->flags = BAF_TRANSITIVE; + a->type = EAF_TYPE_IP_ADDRESS; + a->u.ptr = lp_alloc(pool, sizeof(struct adata) + sizeof(ip_addr)); + a->u.ptr->length = sizeof(ip_addr); + *(ip_addr *)a->u.ptr->data = p->local_addr; + } - return old; + return 0; /* Leave decision to the filters */ } int @@ -133,19 +156,16 @@ bgp_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool * struct bgp_proto *p = (struct bgp_proto *) P; struct bgp_proto *new_bgp = (e->attrs->proto->proto == &proto_bgp) ? (struct bgp_proto *) e->attrs->proto : NULL; - if (e->attrs->dest != RTD_ROUTER) /* FIXME: This is a debugging kludge, remove some day */ + if (p == new_bgp) /* Poison reverse updates */ return -1; if (new_bgp) { if (p->local_as == new_bgp->local_as && p->is_internal && new_bgp->is_internal) return -1; /* Don't redistribute internal routes with IBGP */ - *attrs = bgp_update_attrs(p, e, *attrs, pool); + return bgp_update_attrs(p, e, attrs, pool); } else - *attrs = bgp_create_attrs(p, e, *attrs, pool); - if (p == new_bgp) /* FIXME: Use a more realistic check based on the NEXT_HOP attribute */ - return 1; - return 0; /* Leave the decision to the filter */ + return bgp_create_attrs(p, e, attrs, pool); } int @@ -284,7 +304,7 @@ static struct attr_desc bgp_attr_table[] = { { "aggregator", 6, BAF_OPTIONAL, EAF_TYPE_OPAQUE, /* BA_AGGREGATOR */ NULL, NULL }, #if 0 - /* FIXME: Handle community lists */ + /* FIXME: Handle community lists and remember to convert their endianity and normalize them */ { 0, 0 }, /* BA_COMMUNITY */ { 0, 0 }, /* BA_ORIGINATOR_ID */ { 0, 0 }, /* BA_CLUSTER_LIST */ @@ -443,19 +463,12 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP)); ASSERT(e); nexthop = *(ip_addr *) e->u.ptr->data; - neigh = neigh_find(&bgp->p, &nexthop, 0); - if (!neigh) - { - if (bgp->cf->multihop) - neigh = neigh_find(&bgp->p, &bgp->cf->multihop_via, 0); - else - neigh = neigh_find(&bgp->p, &bgp->cf->remote_ip, 0); - } - if (!neigh || !neigh->iface) + if (ipa_equal(nexthop, bgp->local_addr)) { - DBG("BGP: No route to peer!\n"); /* FIXME */ + DBG("BGP: Loop!\n"); /* FIXME */ return NULL; } + neigh = neigh_find(&bgp->p, &nexthop, 0) ? : bgp->neigh; a->gw = neigh->addr; a->iface = neigh->iface; return rta_lookup(a); |