diff --git a/conf/conf.h b/conf/conf.h index f174d352..a2c09282 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -30,6 +30,8 @@ struct config { char *syslog_name; /* Name used for syslog (NULL -> no syslog) */ struct rtable_config *def_tables[NET_MAX]; /* Default routing tables for each network */ struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */ + struct rtable_config *local4; + struct rtable_config *local6; u32 router_id; /* Our Router ID */ unsigned proto_default_debug; /* Default protocol debug mask */ diff --git a/nest/config.Y b/nest/config.Y index 5cfadecf..0650be04 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -74,7 +74,7 @@ CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENER CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION, SORTED, ORDERED) CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP) CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US) -CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS, STATISTICS) +CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS, STATISTICS, NETWORKS, ADDRESSES) /* For r_args_channel */ CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC) diff --git a/nest/neighbor.c b/nest/neighbor.c index 4f93e29e..085d3f59 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -122,6 +122,8 @@ neigh_find(struct proto *p, ip_addr *a, unsigned flags) return neigh_find2(p, a, NULL, flags); } +struct iface * net_route_ifa(const ip_addr *a, struct iface *vrf); + neighbor * neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) @@ -153,13 +155,11 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) scope = class & IADDR_SCOPE_MASK; } else - WALK_LIST(i, iface_list) - if ((!p->vrf || p->vrf == i->master) && + { + if ((i = net_route_ifa(a, p->vrf)) && ((scope = if_connected(a, i, &addr)) >= 0)) - { - ifa = i; - break; - } + ifa = i; + } /* scope < 0 means i don't know neighbor */ /* scope >= 0 implies ifa != NULL */ diff --git a/nest/proto.c b/nest/proto.c index 4dab562d..38c251a5 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -737,6 +737,7 @@ proto_new(struct proto_config *cf) p->proto = cf->protocol; p->net_type = cf->net_type; p->disabled = cf->disabled; + p->hidden = cf->hidden; p->hash_key = random_u32(); cf->proto = p; @@ -1025,7 +1026,13 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty DBG("Protocol start\n"); - /* Start device protocol first */ + + /* Start direct protocols first */ + WALK_LIST_DELSAFE(p, n, proto_list) + if (p->proto == &proto_device) + proto_rethink_goal(p); + + /* Start device protocol second */ if (first_dev_proto) proto_rethink_goal(first_dev_proto); @@ -1903,7 +1910,7 @@ proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, uintptr_t, int), u int cnt = 0; WALK_LIST(p, proto_list) - if (!patt || patmatch(patt, p->name)) + if ((!patt || patmatch(patt, p->name)) && !p->hidden) cmd(p, arg, cnt++); if (!cnt) @@ -1943,7 +1950,7 @@ proto_get_named(struct symbol *sym, struct protocol *pr) { p = NULL; WALK_LIST(q, proto_list) - if ((q->proto == pr) && (q->proto_state != PS_DOWN)) + if ((q->proto == pr) && (q->proto_state != PS_DOWN) && !q->hidden) { if (p) cf_error("There are multiple %s protocols running", pr->name); diff --git a/nest/protocol.h b/nest/protocol.h index 058f362d..8c870084 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -96,6 +96,7 @@ struct proto_config { int class; /* SYM_PROTO or SYM_TEMPLATE */ u8 net_type; /* Protocol network type (NET_*), 0 for undefined */ u8 disabled; /* Protocol enabled/disabled by default */ + byte hidden; /* Protocol not showed in show protocols */ u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */ u32 router_id; /* Protocol specific router ID */ @@ -160,6 +161,7 @@ struct proto { byte gr_recovery; /* Protocol should participate in graceful restart recovery */ byte down_sched; /* Shutdown is scheduled for later (PDS_*) */ byte down_code; /* Reason for shutdown (PDC_* codes) */ + byte hidden; /* Protocol not showed in show protocols */ u32 hash_key; /* Random key used for hashing of neighbors */ btime last_state_change; /* Time of last state transition */ char *last_state_name_announced; /* Last state name we've announced to the user */ diff --git a/nest/rt-dev.c b/nest/rt-dev.c index 66f458e7..2b7c0186 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -54,6 +54,12 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad) if (!c) return; + if (cf->host_ip) + { + net = alloca(sizeof(net_addr)); + net_fill_ip_host(net, ad->ip); + } + /* For IPv6 SADR, replace regular prefix with SADR prefix */ if (c->net_type == NET_IP6_SADR) { diff --git a/nest/rt-dev.h b/nest/rt-dev.h index 5d91242a..695e1351 100644 --- a/nest/rt-dev.h +++ b/nest/rt-dev.h @@ -13,6 +13,7 @@ struct rt_dev_config { struct proto_config c; list iface_list; /* list of struct iface_patt */ int check_link; + int host_ip; /* Annunce local IP instead of prefix */ struct channel_config *ip4_channel; struct channel_config *ip6_channel; diff --git a/nest/rt-table.c b/nest/rt-table.c index 47a08d2a..001cfd10 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -34,6 +34,7 @@ #include "nest/route.h" #include "nest/protocol.h" #include "nest/iface.h" +#include "nest/rt-dev.h" #include "nest/cli.h" #include "lib/resource.h" #include "lib/event.h" @@ -171,6 +172,87 @@ net_route(rtable *tab, const net_addr *n) } } +static inline struct iface * +net_route_ifa4(rtable *t, net_addr_ip4 *a, struct iface *vrf) +{ + while (1) + { + if (!BIT32_TEST(t->pxlens, a->pxlen)) + goto next; + + net *n = net_find(t, (net_addr *) a); + + if (!n) + goto next; + + for (rte *e = n->routes; e; e = e->next) + { + struct iface *i = e->attrs->nh.iface; + if (rte_is_valid(e) && + (e->attrs->dest == RTD_UNICAST) && + (!vrf || vrf == i->master)) + return i; + } + + next: + if (!a->pxlen) + return NULL; + + a->pxlen--; + ip4_clrbit(&a->prefix, a->pxlen); + } +} + +static inline struct iface * +net_route_ifa6(rtable *t, net_addr_ip6 *a, struct iface *vrf) +{ + while (1) + { + if (!BIT32_TEST(t->pxlens, a->pxlen)) + goto next; + + net *n = net_find(t, (net_addr *) a); + + if (!n) + goto next; + + for (rte *e = n->routes; e; e = e->next) + { + struct iface *i = e->attrs->nh.iface; + if (rte_is_valid(e) && + (e->attrs->dest == RTD_UNICAST) && + (!vrf || vrf == i->master)) + return i; + } + + next: + if (!a->pxlen) + return NULL; + + a->pxlen--; + ip6_clrbit(&a->prefix, a->pxlen); + } +} + +struct iface * +net_route_ifa(const ip_addr *a, struct iface *vrf) +{ + net_addr n0; + net_fill_ip_host(&n0, *a); + + switch (n0.type) + { + case NET_IP4: + return net_route_ifa4(config->local4->table, (net_addr_ip4 *) &n0, vrf); + + case NET_IP6: + return net_route_ifa6(config->local6->table, (net_addr_ip6 *) &n0, vrf); + + default: + return NULL; + } +} + static int net_roa_check_ip4(rtable *tab, const net_addr_ip4 *px, u32 asn) @@ -1821,6 +1903,50 @@ rt_preconfig(struct config *c) rt_new_table(cf_get_symbol("master4"), NET_IP4); rt_new_table(cf_get_symbol("master6"), NET_IP6); + + c->local4 = rt_new_table(cf_get_symbol("local4"), NET_IP4); + c->local6 = rt_new_table(cf_get_symbol("local6"), NET_IP6); + + + /* Define two direct protocols and connect them to local tables */ + + struct symbol *s; + struct rt_dev_config *dev; + static struct channel_config *cc; + + s = cf_get_symbol("networks"); + dev = proto_config_new(&proto_device, SYM_PROTO); + init_list(&dev->iface_list); + cf_define_symbol(s, SYM_PROTO, dev); + dev->c.name = s->name; + dev->c.hidden = 1; + // dev->c.debug = D_EVENTS | D_STATES | D_IFACES; + + cc = channel_config_get(NULL, net_label[NET_IP4], NET_IP4, &dev->c); + cc->table = c->local4; + + cc = channel_config_get(NULL, net_label[NET_IP6], NET_IP6, &dev->c); + cc->table = c->local6; + + proto_device.postconfig(&dev->c); + + + s = cf_get_symbol("addresses"); + dev = proto_config_new(&proto_device, SYM_PROTO); + init_list(&dev->iface_list); + cf_define_symbol(s, SYM_PROTO, dev); + dev->c.name = s->name; + dev->c.hidden = 1; + // dev->c.debug = D_EVENTS | D_STATES | D_IFACES; + dev->host_ip = 1; + + cc = channel_config_get(NULL, net_label[NET_IP4], NET_IP4, &dev->c); + cc->table = c->local4; + + cc = channel_config_get(NULL, net_label[NET_IP6], NET_IP6, &dev->c); + cc->table = c->local6; + + proto_device.postconfig(&dev->c); }