From ffb38dfb8b454dc23cd08836d7236a5a9c9f80c1 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Thu, 30 Mar 2017 13:29:34 +0200 Subject: [PATCH] Static: Support for dual-AF IGP tables When recursive routes with hybrid next hops (e.g. IPv6 route with IPv4 next hop) are allowed, we need both IPv4 and IPv6 IGP tables. --- proto/bgp/bgp.c | 10 +++----- proto/static/config.Y | 9 ++++++- proto/static/static.c | 58 +++++++++++++++++++++++++++---------------- proto/static/static.h | 5 +++- 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 01ac5453..86f7be1b 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1732,6 +1732,8 @@ bgp_reconfigure(struct proto *P, struct proto_config *CF) return same; } +#define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL ) + static int bgp_channel_reconfigure(struct channel *C, struct channel_config *CC) { @@ -1746,12 +1748,8 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC) return 0; /* Check change in IGP tables */ - rtable *old4 = old->igp_table_ip4 ? old->igp_table_ip4->table : NULL; - rtable *old6 = old->igp_table_ip6 ? old->igp_table_ip6->table : NULL; - rtable *new4 = new->igp_table_ip4 ? new->igp_table_ip4->table : NULL; - rtable *new6 = new->igp_table_ip6 ? new->igp_table_ip6->table : NULL; - - if ((old4 != new4) || (old6 != new6)) + if ((IGP_TABLE(old, ip4) != IGP_TABLE(new, ip4)) || + (IGP_TABLE(old, ip6) != IGP_TABLE(new, ip6))) return 0; c->cf = new; diff --git a/proto/static/config.Y b/proto/static/config.Y index cd8bfcec..6643ba69 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -59,7 +59,14 @@ static_proto: | static_proto proto_item ';' | static_proto proto_channel ';' { this_proto->net_type = $2->net_type; } | static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; } - | static_proto IGP TABLE rtable ';' { STATIC_CFG->igp_table = $4; } + | static_proto IGP TABLE rtable ';' { + if ($4->addr_type == NET_IP4) + STATIC_CFG->igp_table_ip4 = $4; + else if ($4->addr_type == NET_IP6) + STATIC_CFG->igp_table_ip6 = $4; + else + cf_error("Incompatible IGP table type"); + } | static_proto stat_route stat_route_opt_list ';' { static_route_finish(); } ; diff --git a/proto/static/static.c b/proto/static/static.c index adefa0b2..f74ecee0 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -49,13 +49,6 @@ static linpool *static_lp; -static inline rtable * -p_igp_table(struct static_proto *p) -{ - struct static_config *cf = (void *) p->p.cf; - return cf->igp_table ? cf->igp_table->table : p->p.main_channel->table; -} - static void static_announce_rte(struct static_proto *p, struct static_route *r) { @@ -95,7 +88,10 @@ static_announce_rte(struct static_proto *p, struct static_route *r) } if (r->dest == RTDX_RECURSIVE) - rta_set_recursive_next_hop(p->p.main_channel->table, a, p_igp_table(p), r->via, IPA_NONE, r->mls); + { + rtable *tab = ipa_is_ip4(r->via) ? p->igp_table_ip4 : p->igp_table_ip6; + rta_set_recursive_next_hop(p->p.main_channel->table, a, tab, r->via, IPA_NONE, r->mls); + } /* Already announced */ if (r->state == SRS_CLEAN) @@ -370,6 +366,16 @@ static_postconfig(struct proto_config *CF) if (EMPTY_LIST(CF->channels)) cf_error("Channel not specified"); + struct channel_config *cc = proto_cf_main_channel(CF); + + if (!cf->igp_table_ip4) + cf->igp_table_ip4 = (cc->table->addr_type == NET_IP4) ? + cc->table : cf->c.global->def_tables[NET_IP4]; + + if (!cf->igp_table_ip6) + cf->igp_table_ip6 = (cc->table->addr_type == NET_IP6) ? + cc->table : cf->c.global->def_tables[NET_IP6]; + WALK_LIST(r, cf->routes) if (r->net && (r->net->type != CF->net_type)) cf_error("Route %N incompatible with channel type", r->net); @@ -379,14 +385,20 @@ static struct proto * static_init(struct proto_config *CF) { struct proto *P = proto_new(CF); - // struct static_proto *p = (void *) P; - // struct static_config *cf = (void *) CF; + struct static_proto *p = (void *) P; + struct static_config *cf = (void *) CF; P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF)); P->neigh_notify = static_neigh_notify; P->rte_mergable = static_rte_mergable; + if (cf->igp_table_ip4) + p->igp_table_ip4 = cf->igp_table_ip4->table; + + if (cf->igp_table_ip6) + p->igp_table_ip6 = cf->igp_table_ip6->table; + return P; } @@ -400,8 +412,11 @@ static_start(struct proto *P) if (!static_lp) static_lp = lp_new(&root_pool, 1008); - if (cf->igp_table) - rt_lock_table(cf->igp_table->table); + if (p->igp_table_ip4) + rt_lock_table(p->igp_table_ip4); + + if (p->igp_table_ip6) + rt_lock_table(p->igp_table_ip6); p->event = ev_new(p->p.pool); p->event->hook = static_announce_marked; @@ -435,10 +450,13 @@ static_shutdown(struct proto *P) static void static_cleanup(struct proto *P) { - struct static_config *cf = (void *) P->cf; + struct static_proto *p = (void *) P; - if (cf->igp_table) - rt_unlock_table(cf->igp_table->table); + if (p->igp_table_ip4) + rt_unlock_table(p->igp_table_ip4); + + if (p->igp_table_ip6) + rt_unlock_table(p->igp_table_ip6); } static void @@ -465,11 +483,7 @@ static_dump(struct proto *P) static_dump_rte(r); } -static inline rtable * -cf_igp_table(struct static_config *cf) -{ - return cf->igp_table ? cf->igp_table->table : NULL; -} +#define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL ) static inline int static_cmp_rte(const void *X, const void *Y) @@ -486,7 +500,9 @@ static_reconfigure(struct proto *P, struct proto_config *CF) struct static_config *n = (void *) CF; struct static_route *r, *r2, *or, *nr; - if (cf_igp_table(o) != cf_igp_table(n)) + /* Check change in IGP tables */ + if ((IGP_TABLE(o, ip4) != IGP_TABLE(n, ip4)) || + (IGP_TABLE(o, ip6) != IGP_TABLE(n, ip6))) return 0; if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF))) diff --git a/proto/static/static.h b/proto/static/static.h index 0976a9c9..c84dfa98 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -17,7 +17,8 @@ struct static_config { struct proto_config c; list routes; /* List of static routes (struct static_route) */ int check_link; /* Whether iface link state is used */ - struct rtable_config *igp_table; /* Table used for recursive next hop lookups */ + struct rtable_config *igp_table_ip4; /* Table for recursive IPv4 next hop lookups */ + struct rtable_config *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */ }; struct static_proto { @@ -25,6 +26,8 @@ struct static_proto { struct event *event; /* Event for announcing updated routes */ BUFFER(struct static_route *) marked; /* Routes marked for reannouncement */ + rtable *igp_table_ip4; /* Table for recursive IPv4 next hop lookups */ + rtable *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */ }; struct static_route {