diff options
Diffstat (limited to 'proto')
-rw-r--r-- | proto/bgp/attrs.c | 20 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 15 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 12 | ||||
-rw-r--r-- | proto/bgp/packets.c | 60 | ||||
-rw-r--r-- | proto/ospf/config.Y | 15 | ||||
-rw-r--r-- | proto/ospf/iface.c | 2 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 4 | ||||
-rw-r--r-- | proto/rip/config.Y | 25 | ||||
-rw-r--r-- | proto/rip/rip.c | 4 |
9 files changed, 95 insertions, 62 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index a015c2b..8a849e7 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -786,18 +786,13 @@ bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p put_u16(z+2, p->local_as); } - z = bgp_set_attr_wa(ea->attrs+2, pool, BA_NEXT_HOP, sizeof(ip_addr)); + z = bgp_set_attr_wa(ea->attrs+2, pool, BA_NEXT_HOP, NEXT_HOP_LENGTH); if (p->cf->next_hop_self || - !p->is_internal || - rta->dest != RTD_ROUTER) - { - if (ipa_nonzero(p->cf->source_addr)) - *(ip_addr *)z = p->cf->source_addr; - else - *(ip_addr *)z = p->local_addr; - } + rta->dest != RTD_ROUTER || + (!p->is_internal && (e->attrs->iface != p->neigh->iface))) + set_next_hop(z, p->source_addr); else - *(ip_addr *)z = e->attrs->gw; + set_next_hop(z, e->attrs->gw); bgp_set_attr(ea->attrs+3, BA_LOCAL_PREF, 0); @@ -860,14 +855,15 @@ bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p } 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))) + if (a && !p->cf->next_hop_self && (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 */ - bgp_attach_attr_ip(attrs, pool, BA_NEXT_HOP, p->local_addr); + byte *b = bgp_attach_attr_wa(attrs, pool, BA_NEXT_HOP, NEXT_HOP_LENGTH); + set_next_hop(b, p->source_addr); } if (rr) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 41c8d53..cbc699b 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -500,10 +500,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c DBG("BGP: Connecting\n"); s = sk_new(p->p.pool); s->type = SK_TCP_ACTIVE; - if (ipa_nonzero(p->cf->source_addr)) - s->saddr = p->cf->source_addr; - else - s->saddr = p->local_addr; + s->saddr = p->source_addr; s->daddr = p->cf->remote_ip; s->dport = BGP_PORT; s->ttl = p->cf->multihop ? : 1; @@ -609,17 +606,23 @@ static void bgp_start_neighbor(struct bgp_proto *p) { p->local_addr = p->neigh->iface->addr->ip; - DBG("BGP: local=%I remote=%I\n", p->local_addr, p->next_hop); + p->source_addr = ipa_nonzero(p->cf->source_addr) ? p->cf->source_addr : p->local_addr; + + DBG("BGP: local=%I remote=%I\n", p->source_addr, p->next_hop); #ifdef IPV6 { struct ifa *a; - p->local_link = ipa_or(ipa_build(0xfe80,0,0,0), ipa_and(p->local_addr, ipa_build(0,0,~0,~0))); + p->local_link = IPA_NONE; WALK_LIST(a, p->neigh->iface->addrs) if (a->scope == SCOPE_LINK) { p->local_link = a->ip; break; } + + if (! ipa_nonzero(p->local_link)) + log(L_WARN "%s: Missing link local address on interface %s", p->p.name, p->neigh->iface->name); + DBG("BGP: Selected link-level address %I\n", p->local_link); } #endif diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index d5448a6..8477f9e 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -79,6 +79,7 @@ struct bgp_proto { ip_addr next_hop; /* Either the peer or multihop_via */ struct neighbor *neigh; /* Neighbor entry corresponding to next_hop */ ip_addr local_addr; /* Address of the local end of the link to next_hop */ + ip_addr source_addr; /* Address used as advertised next hop, usually local_addr */ struct event *event; /* Event for respawning and shutting process */ struct bgp_bucket **bucket_hash; /* Hash table of attribute buckets */ unsigned int hash_size, hash_count, hash_limit; @@ -147,6 +148,17 @@ void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code /* attrs.c */ +/* Hack: although BA_NEXT_HOP attribute has type EAF_TYPE_IP_ADDRESS, in IPv6 + * we store two addesses in it - a global address and a link local address. + */ +#ifdef IPV6 +#define NEXT_HOP_LENGTH (2*sizeof(ip_addr)) +static inline void set_next_hop(byte *b, ip_addr addr) { ((ip_addr *) b)[0] = addr; ((ip_addr *) b)[1] = IPA_NONE; } +#else +#define NEXT_HOP_LENGTH sizeof(ip_addr) +static inline void set_next_hop(byte *b, ip_addr addr) { ((ip_addr *) b)[0] = addr; } +#endif + void bgp_attach_attr(struct ea_list **to, struct linpool *pool, unsigned attr, uintptr_t val); byte *bgp_attach_attr_wa(struct ea_list **to, struct linpool *pool, unsigned attr, unsigned len); struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, unsigned int len, struct linpool *pool, int mandatory); diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 1370ee7..27adc16 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -234,10 +234,10 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) { struct bgp_proto *p = conn->bgp; struct bgp_bucket *buck; - int size, is_ll; + int size; int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4; byte *w, *tmp, *tstart; - ip_addr ip, ip_ll; + ip_addr *ipp, ip, ip_ll; ea_list *ea; eattr *nh; neighbor *n; @@ -291,26 +291,42 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) *tmp++ = 1; nh = ea_find(buck->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP)); ASSERT(nh); - ip = *(ip_addr *) nh->u.ptr->data; - is_ll = 0; - if (ipa_equal(ip, p->local_addr)) - { - is_ll = 1; - ip_ll = p->local_link; - } + + /* We have two addresses here in 'nh'. Really. */ + ipp = (ip_addr *) nh->u.ptr->data; + ip = ipp[0]; + ip_ll = IPA_NONE; + + if (ipa_equal(ip, p->source_addr)) + ip_ll = p->local_link; else { + /* If we send a route with 'third party' next hop destinated + * in the same interface, we should also send a link local + * next hop address. We use the received one (stored in the + * other part of BA_NEXT_HOP eattr). If we didn't received + * it (for example it is a static route), we can't use + * 'third party' next hop and we have to use local IP address + * as next hop. Sending original next hop address without + * link local address seems to be a natural way to solve that + * problem, but it is contrary to RFC 2545 and Quagga does not + * accept such routes. + */ + n = neigh_find(&p->p, &ip, 0); if (n && n->iface == p->neigh->iface) { - /* FIXME: We are assuming the global scope addresses use the lower 64 bits - * as an interface identifier which hasn't necessarily to be true. - */ - is_ll = 1; - ip_ll = ipa_or(ipa_build(0xfe800000,0,0,0), ipa_and(ip, ipa_build(0,0,~0,~0))); + if (ipa_nonzero(ipp[1])) + ip_ll = ipp[1]; + else + { + ip = p->source_addr; + ip_ll = p->local_link; + } } } - if (is_ll) + + if (ipa_nonzero(ip_ll)) { *tmp++ = 32; ipa_hton(ip); @@ -326,6 +342,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) memcpy(tmp, &ip, 16); tmp += 16; } + *tmp++ = 0; /* No SNPA information */ tmp += bgp_encode_prefixes(p, tmp, buck, remains - (8+3+32+1)); ea->attrs[0].u.ptr->length = tmp - tstart; @@ -778,9 +795,18 @@ bgp_do_rx_update(struct bgp_conn *conn, if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2) goto bad; - byte *nh = bgp_attach_attr_wa(&a0->eattrs, bgp_linpool, BA_NEXT_HOP, 16); + ip_addr *nh = (ip_addr *) bgp_attach_attr_wa(&a0->eattrs, bgp_linpool, BA_NEXT_HOP, NEXT_HOP_LENGTH); memcpy(nh, x+1, 16); - ipa_ntoh(*(ip_addr *)nh); + ipa_ntoh(nh[0]); + + /* We store received link local address in the other part of BA_NEXT_HOP eattr. */ + if (*x == 32) + { + memcpy(nh+1, x+17, 16); + ipa_ntoh(nh[1]); + } + else + nh[1] = IPA_NONE; /* Also ignore one reserved byte */ len -= *x + 2; diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index bfe2d9c..7f7d6a3 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -13,9 +13,9 @@ CF_HDR CF_DEFINES #define OSPF_CFG ((struct ospf_config *) this_proto) -static struct ospf_area_config *this_area; -static struct iface_patt *this_ipatt; #define OSPF_PATT ((struct ospf_iface_patt *) this_ipatt) + +static struct ospf_area_config *this_area; static struct nbma_node *this_nbma; static struct area_net_config *this_pref; @@ -90,7 +90,7 @@ ospf_area_item: STUB COST expr { this_area->stub = $3 ; if($3<=0) cf_error("Stub cost must be greater than zero"); } | STUB bool {if($2) { if(!this_area->stub) this_area->stub=DEFAULT_STUB_COST;}else{ this_area->stub=0;}} | NETWORKS '{' pref_list '}' - | INTERFACE ospf_iface_list + | INTERFACE ospf_iface | ospf_vlink ; @@ -122,6 +122,7 @@ ospf_vlink_start: VIRTUAL LINK idval if (this_area->areaid == 0) cf_error("Virtual link cannot be in backbone"); this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt)); add_tail(&this_area->vlink_list, NODE this_ipatt); + init_list(&this_ipatt->ipn_list); OSPF_PATT->vid = $3; OSPF_PATT->cost = COST_D; OSPF_PATT->helloint = HELLOINT_D; @@ -222,6 +223,7 @@ ospf_iface_start: { this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt)); add_tail(&this_area->patt_list, NODE this_ipatt); + init_list(&this_ipatt->ipn_list); OSPF_PATT->cost = COST_D; OSPF_PATT->helloint = HELLOINT_D; OSPF_PATT->pollint = POLLINT_D; @@ -251,12 +253,7 @@ ospf_iface_opt_list: ; ospf_iface: - ospf_iface_start iface_patt ospf_iface_opt_list { finish_iface_config(OSPF_PATT); } - ; - -ospf_iface_list: - ospf_iface - | ospf_iface_list ',' ospf_iface + ospf_iface_start iface_patt_list ospf_iface_opt_list { finish_iface_config(OSPF_PATT); } ; opttext: diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index a4c9741..5162f9f 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -550,7 +550,7 @@ ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface) WALK_LIST(ac, c->area_list) { if (ip = (struct ospf_iface_patt *) - iface_patt_match(&ac->patt_list, iface)) + iface_patt_find(&ac->patt_list, iface)) break; } diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 1eae376..0cab1d7 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -634,11 +634,11 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) WALK_LIST(ifa, po->iface_list) { if (oldip = (struct ospf_iface_patt *) - iface_patt_match(&oldac->patt_list, ifa->iface)) + iface_patt_find(&oldac->patt_list, ifa->iface)) { /* Now reconfigure interface */ if (!(newip = (struct ospf_iface_patt *) - iface_patt_match(&newac->patt_list, ifa->iface))) + iface_patt_find(&newac->patt_list, ifa->iface))) return 0; /* HELLO TIMER */ diff --git a/proto/rip/config.Y b/proto/rip/config.Y index f1ae43c..9a11069 100644 --- a/proto/rip/config.Y +++ b/proto/rip/config.Y @@ -55,7 +55,7 @@ rip_cfg: | rip_cfg HONOR ALWAYS ';' { RIP_CFG->honor = HO_ALWAYS; } | rip_cfg HONOR NEIGHBOR ';' { RIP_CFG->honor = HO_NEIGHBOR; } | rip_cfg HONOR NEVER ';' { RIP_CFG->honor = HO_NEVER; } - | rip_cfg rip_iface_list ';' + | rip_cfg INTERFACE rip_iface ';' ; rip_auth: @@ -64,6 +64,7 @@ rip_auth: | NONE { $$=AT_NONE; } ; + rip_mode: BROADCAST { $$=IM_BROADCAST; } | MULTICAST { $$=0; } @@ -78,28 +79,26 @@ rip_iface_item: ; rip_iface_opts: - '{' + /* empty */ | rip_iface_opts rip_iface_item ';' ; -rip_iface_opt_list: /* EMPTY */ | rip_iface_opts '}' ; +rip_iface_opt_list: + /* empty */ + | '{' rip_iface_opts '}' + ; rip_iface_init: /* EMPTY */ { - struct rip_patt *k = cfg_allocz(sizeof(struct rip_patt)); - k->metric = 1; - add_tail(&RIP_CFG->iface_list, &k->i.n); - this_ipatt = &k->i; + this_ipatt = cfg_allocz(sizeof(struct rip_patt)); + add_tail(&RIP_CFG->iface_list, NODE this_ipatt); + init_list(&this_ipatt->ipn_list); + RIP_IPATT->metric = 1; } ; rip_iface: - rip_iface_init iface_patt rip_iface_opt_list - ; - -rip_iface_list: - INTERFACE rip_iface - | rip_iface_list ',' rip_iface + rip_iface_init iface_patt_list rip_iface_opt_list ; CF_ADDTO(dynamic_attr, RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_RIP_METRIC); }) diff --git a/proto/rip/rip.c b/proto/rip/rip.c index b5a4cc3..12cc878 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -742,7 +742,7 @@ rip_real_if_add(struct object_lock *lock) struct iface *iface = lock->iface; struct proto *p = lock->data; struct rip_interface *rif; - struct iface_patt *k = iface_patt_match(&P_CF->iface_list, iface); + struct iface_patt *k = iface_patt_find(&P_CF->iface_list, iface); if (!k) bug("This can not happen! It existed few seconds ago!" ); @@ -771,7 +771,7 @@ rip_if_notify(struct proto *p, unsigned c, struct iface *iface) } } if (c & IF_CHANGE_UP) { - struct iface_patt *k = iface_patt_match(&P_CF->iface_list, iface); + struct iface_patt *k = iface_patt_find(&P_CF->iface_list, iface); struct object_lock *lock; struct rip_patt *PATT = (struct rip_patt *) k; |