diff options
Diffstat (limited to 'proto')
-rw-r--r-- | proto/bgp/bgp.c | 75 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 2 | ||||
-rw-r--r-- | proto/bgp/config.Y | 6 | ||||
-rw-r--r-- | proto/bgp/packets.c | 6 | ||||
-rw-r--r-- | proto/ospf/config.Y | 26 | ||||
-rw-r--r-- | proto/ospf/hello.c | 2 | ||||
-rw-r--r-- | proto/ospf/iface.c | 44 | ||||
-rw-r--r-- | proto/ospf/lsack.c | 8 | ||||
-rw-r--r-- | proto/ospf/lsupd.c | 6 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 6 | ||||
-rw-r--r-- | proto/ospf/ospf.h | 12 | ||||
-rw-r--r-- | proto/ospf/packet.c | 5 | ||||
-rw-r--r-- | proto/ospf/packet.h | 2 | ||||
-rw-r--r-- | proto/ospf/topology.c | 6 | ||||
-rw-r--r-- | proto/pipe/pipe.c | 45 | ||||
-rw-r--r-- | proto/radv/config.Y | 126 | ||||
-rw-r--r-- | proto/radv/packets.c | 181 | ||||
-rw-r--r-- | proto/radv/radv.c | 4 | ||||
-rw-r--r-- | proto/radv/radv.h | 31 | ||||
-rw-r--r-- | proto/rip/rip.c | 5 |
20 files changed, 500 insertions, 98 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index d59b4308..0b52dedc 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -542,22 +542,6 @@ bgp_active(struct bgp_proto *p) bgp_start_timer(conn->connect_retry_timer, delay); } -int -bgp_apply_limits(struct bgp_proto *p) -{ - if (p->cf->route_limit && (p->p.stats.imp_routes > p->cf->route_limit)) - { - log(L_WARN "%s: Route limit exceeded, shutting down", p->p.name); - bgp_store_error(p, NULL, BE_AUTO_DOWN, BEA_ROUTE_LIMIT_EXCEEDED); - bgp_update_startup_delay(p); - bgp_stop(p, 1); // Errcode 6, 1 - max number of prefixes reached - return -1; - } - - return 0; -} - - /** * bgp_connect - initiate an outgoing connection * @p: BGP instance @@ -864,28 +848,58 @@ bgp_start(struct proto *P) return PS_START; } +extern int proto_restart; + static int bgp_shutdown(struct proto *P) { struct bgp_proto *p = (struct bgp_proto *) P; - unsigned subcode; + unsigned subcode = 0; BGP_TRACE(D_EVENTS, "Shutdown requested"); - bgp_store_error(p, NULL, BE_MAN_DOWN, 0); - if (P->reconfiguring) + switch (P->down_code) { - if (P->cf_new) - subcode = 6; // Errcode 6, 6 - other configuration change + case PDC_CF_REMOVE: + case PDC_CF_DISABLE: + subcode = 3; // Errcode 6, 3 - peer de-configured + break; + + case PDC_CF_RESTART: + subcode = 6; // Errcode 6, 6 - other configuration change + break; + + case PDC_CMD_DISABLE: + subcode = 2; // Errcode 6, 2 - administrative shutdown + break; + + case PDC_CMD_RESTART: + subcode = 4; // Errcode 6, 4 - administrative reset + break; + + case PDC_IN_LIMIT_HIT: + subcode = 1; // Errcode 6, 1 - max number of prefixes reached + /* log message for compatibility */ + log(L_WARN "%s: Route limit exceeded, shutting down", p->p.name); + goto limit; + + case PDC_OUT_LIMIT_HIT: + subcode = proto_restart ? 4 : 2; // Administrative reset or shutdown + + limit: + bgp_store_error(p, NULL, BE_AUTO_DOWN, BEA_ROUTE_LIMIT_EXCEEDED); + if (proto_restart) + bgp_update_startup_delay(p); else - subcode = 3; // Errcode 6, 3 - peer de-configured + p->startup_delay = 0; + goto done; } - else - subcode = 2; // Errcode 6, 2 - administrative shutdown + bgp_store_error(p, NULL, BE_MAN_DOWN, 0); p->startup_delay = 0; - bgp_stop(p, subcode); + done: + bgp_stop(p, subcode); return p->p.proto_state; } @@ -972,6 +986,10 @@ bgp_check_config(struct bgp_config *c) if (!c->gw_mode) c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT; + /* Disable after error incompatible with restart limit action */ + if (c->c.in_limit && (c->c.in_limit->action == PLA_RESTART) && c->disable_after_error) + c->c.in_limit->action = PLA_DISABLE; + if ((c->gw_mode == GW_RECURSIVE) && c->c.table->sorted) cf_error("BGP in recursive mode prohibits sorted table"); @@ -1128,9 +1146,6 @@ bgp_get_status(struct proto *P, byte *buf) bsprintf(buf, "%-14s%s%s", bgp_state_dsc(p), err1, err2); } -static inline bird_clock_t tm_remains(timer *t) -{ return t->expires ? t->expires - now : 0; } - static void bgp_show_proto_info(struct proto *P) { @@ -1170,9 +1185,9 @@ bgp_show_proto_info(struct proto *P) p->rs_client ? " route-server" : "", p->as4_session ? " AS4" : ""); cli_msg(-1006, " Source address: %I", p->source_addr); - if (p->cf->route_limit) + if (P->cf->in_limit) cli_msg(-1006, " Route limit: %d/%d", - p->p.stats.imp_routes, p->cf->route_limit); + p->p.stats.imp_routes, P->cf->in_limit->limit); cli_msg(-1006, " Hold timer: %d/%d", tm_remains(c->hold_timer), c->hold_time); cli_msg(-1006, " Keepalive timer: %d/%d", diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 87734425..c3adf254 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -40,7 +40,6 @@ struct bgp_config { int rr_client; /* Whether neighbor is RR client of me */ int rs_client; /* Whether neighbor is RS client of me */ int advertise_ipv4; /* Whether we should add IPv4 capability advertisement to OPEN message */ - u32 route_limit; /* Number of routes that may be imported, 0 means disable limit */ int passive; /* Do not initiate outgoing connection */ int interpret_communities; /* Hardwired handling of well-known communities */ int secondary; /* Accept also non-best routes (i.e. RA_ACCEPTED) */ @@ -153,7 +152,6 @@ void bgp_conn_enter_established_state(struct bgp_conn *conn); void bgp_conn_enter_close_state(struct bgp_conn *conn); void bgp_conn_enter_idle_state(struct bgp_conn *conn); void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code); -int bgp_apply_limits(struct bgp_proto *p); void bgp_stop(struct bgp_proto *p, unsigned subcode); diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index f9a5be65..8b80d7fd 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -99,7 +99,11 @@ bgp_proto: | bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; } | bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; } | bgp_proto PASSWORD TEXT ';' { BGP_CFG->password = $3; } - | bgp_proto ROUTE LIMIT expr ';' { BGP_CFG->route_limit = $4; } + | bgp_proto ROUTE LIMIT expr ';' { + this_proto->in_limit = cfg_allocz(sizeof(struct proto_limit)); + this_proto->in_limit->limit = $4; + this_proto->in_limit->action = PLA_RESTART; + } | bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; } | bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; } | bgp_proto SECONDARY bool ';' { BGP_CFG->secondary = $3; } diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index d3e9b6a1..cfa37fb5 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -915,9 +915,6 @@ bgp_do_rx_update(struct bgp_conn *conn, if (n = net_find(p->p.table, prefix, pxlen)) rte_update(p->p.table, n, &p->p, &p->p, NULL); } - - if (bgp_apply_limits(p) < 0) - goto done; } done: @@ -1034,9 +1031,6 @@ bgp_do_rx_update(struct bgp_conn *conn, if (n = net_find(p->p.table, prefix, pxlen)) rte_update(p->p.table, n, &p->p, &p->p, NULL); } - - if (bgp_apply_limits(p) < 0) - goto done; } } diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 38e59886..67b0785f 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -107,7 +107,17 @@ static inline void check_defcost(int cost) { if ((cost <= 0) || (cost >= LSINFINITY)) - cf_error("Default cost must be in range 1-%d", LSINFINITY); + cf_error("Default cost must be in range 1-%d", LSINFINITY-1); +} + +static inline void +set_instance_id(unsigned id) +{ +#ifdef OSPFv3 + OSPF_PATT->instance_id = id; +#else + cf_error("Instance ID requires OSPFv3"); +#endif } CF_DECLS @@ -120,7 +130,7 @@ CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC) CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK) CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL) CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY) -CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF) +CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL) %type <t> opttext %type <ld> lsadb_args @@ -218,8 +228,8 @@ ospf_stubnet_item: ; ospf_vlink: - ospf_vlink_start '{' ospf_vlink_opts '}' { ospf_iface_finish(); } - | ospf_vlink_start { ospf_iface_finish(); } + ospf_vlink_start ospf_instance_id '{' ospf_vlink_opts '}' { ospf_iface_finish(); } + | ospf_vlink_start ospf_instance_id { ospf_iface_finish(); } ; ospf_vlink_opts: @@ -277,6 +287,7 @@ ospf_iface_item: | TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; } | TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; } | TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; } + | REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (OSPF_VERSION != 2) cf_error("Real broadcast option requires OSPFv2"); } | TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); } | PRIORITY expr { OSPF_PATT->priority = $2 ; if (($2<0) || ($2>255)) cf_error("Priority must be in range 0-255"); } | STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; } @@ -364,6 +375,11 @@ ospf_iface_start: } ; +ospf_instance_id: + /* empty */ + | INSTANCE expr { set_instance_id($2); } + ; + ospf_iface_opts: /* empty */ | ospf_iface_opts ospf_iface_item ';' @@ -375,7 +391,7 @@ ospf_iface_opt_list: ; ospf_iface: - ospf_iface_start iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); } + ospf_iface_start iface_patt_list ospf_instance_id ospf_iface_opt_list { ospf_iface_finish(); } ; opttext: diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index d04cb54c..f9ba28f6 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -303,7 +303,7 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn) { case OSPF_IT_BCAST: case OSPF_IT_PTP: - ospf_send_to(ifa, AllSPFRouters); + ospf_send_to_all(ifa); break; case OSPF_IT_NBMA: diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 405e49df..a6a0c6c1 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -120,13 +120,24 @@ ospf_sk_open(struct ospf_iface *ifa) sk->saddr = ifa->addr->ip; if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP)) { - sk->ttl = 1; /* Hack, this will affect just multicast packets */ + if (ifa->cf->real_bcast) + { + ifa->all_routers = ifa->addr->brd; + + if (sk_set_broadcast(sk, 1) < 0) + goto err; + } + else + { + ifa->all_routers = AllSPFRouters; + sk->ttl = 1; /* Hack, this will affect just multicast packets */ - if (sk_setup_multicast(sk) < 0) - goto err; + if (sk_setup_multicast(sk) < 0) + goto err; - if (sk_join_group(sk, AllSPFRouters) < 0) - goto err; + if (sk_join_group(sk, ifa->all_routers) < 0) + goto err; + } } ifa->sk = sk; @@ -265,7 +276,7 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state) OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s", ifa->iface->name, ospf_is[oldstate], ospf_is[state]); - if ((ifa->type == OSPF_IT_BCAST) && ifa->sk) + if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk) { if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR)) ospf_sk_join_dr(ifa); @@ -536,6 +547,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i /* Check validity of interface type */ int old_type = ifa->type; + u32 if_multi_flag = ip->real_bcast ? IF_BROADCAST : IF_MULTICAST; #ifdef OSPFv2 if ((ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER)) @@ -545,10 +557,10 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i ifa->type = OSPF_IT_PTMP; #endif - if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & IF_MULTICAST)) + if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag)) ifa->type = OSPF_IT_NBMA; - if ((ifa->type == OSPF_IT_PTP) && !(iface->flags & IF_MULTICAST)) + if ((ifa->type == OSPF_IT_PTP) && !(iface->flags & if_multi_flag)) ifa->type = OSPF_IT_PTMP; if (ifa->type != old_type) @@ -628,6 +640,9 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) if (ifa->stub != new_stub) return 0; + if (new->real_bcast != ifa->cf->real_bcast) + return 0; + ifa->cf = new; ifa->marked = 0; @@ -1099,11 +1114,15 @@ ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface) void ospf_iface_info(struct ospf_iface *ifa) { - char *strict = ""; + char *more = ""; if (ifa->strictnbma && ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))) - strict = "(strict)"; + more = " (strict)"; + + if (ifa->cf->real_bcast && + ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP))) + more = " (real)"; if (ifa->type == OSPF_IT_VLINK) { @@ -1124,11 +1143,10 @@ ospf_iface_info(struct ospf_iface *ifa) #else /* OSPFv3 */ cli_msg(-1015, "Interface %s (IID %d)", ifa->iface->name, ifa->instance_id); #endif - cli_msg(-1015, "\tType: %s %s", ospf_it[ifa->type], strict); + cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more); cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid); } - cli_msg(-1015, "\tState: %s %s", ospf_is[ifa->state], - ifa->stub ? "(stub)" : ""); + cli_msg(-1015, "\tState: %s%s", ospf_is[ifa->state], ifa->stub ? " (stub)" : ""); cli_msg(-1015, "\tPriority: %u", ifa->priority); cli_msg(-1015, "\tCost: %u", ifa->cost); if (ifa->oa->po->ecmp) diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c index 53422e53..00c50caf 100644 --- a/proto/ospf/lsack.c +++ b/proto/ospf/lsack.c @@ -97,7 +97,9 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) if (ifa->type == OSPF_IT_BCAST) { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - ospf_send_to(ifa, AllSPFRouters); + ospf_send_to_all(ifa); + else if (ifa->cf->real_bcast) + ospf_send_to_bdr(ifa); else ospf_send_to(ifa, AllDRouters); } @@ -124,7 +126,9 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) if (ifa->type == OSPF_IT_BCAST) { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - ospf_send_to(ifa, AllSPFRouters); + ospf_send_to_all(ifa); + else if (ifa->cf->real_bcast) + ospf_send_to_bdr(ifa); else ospf_send_to(ifa, AllDRouters); } diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index 325a8d00..f71c72d1 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -314,7 +314,9 @@ ospf_lsupd_flood(struct proto_ospf *po, { case OSPF_IT_BCAST: if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR)) - ospf_send_to(ifa, AllSPFRouters); + ospf_send_to_all(ifa); + else if (ifa->cf->real_bcast) + ospf_send_to_bdr(ifa); else ospf_send_to(ifa, AllDRouters); break; @@ -327,7 +329,7 @@ ospf_lsupd_flood(struct proto_ospf *po, break; case OSPF_IT_PTP: - ospf_send_to(ifa, AllSPFRouters); + ospf_send_to_all(ifa); break; case OSPF_IT_PTMP: diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 9872faf2..ef7b0363 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -1145,16 +1145,16 @@ show_lsa_sum_net(struct top_hash_entry *he) static inline void show_lsa_sum_rt(struct top_hash_entry *he) { - u32 dst_rid, options; + u32 dst_rid; #ifdef OSPFv2 struct ospf_lsa_sum *ls = he->lsa_body; dst_rid = he->lsa.id; - options = 0; + // options = 0; #else /* OSPFv3 */ struct ospf_lsa_sum_rt *ls = he->lsa_body; dst_rid = ls->drid; - options = ls->options & OPTIONS_MASK; + // options = ls->options & OPTIONS_MASK; #endif cli_msg(-1016, "\t\txrouter %R metric %u", dst_rid, ls->metric); diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 96da9aa7..3bffaf91 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -205,6 +205,7 @@ struct ospf_iface bird_clock_t csn_use; /* Last time when packet with that CSN was sent */ #endif + ip_addr all_routers; /* */ ip_addr drip; /* Designated router */ ip_addr bdrip; /* Backup DR */ u32 drid; @@ -790,22 +791,23 @@ struct ospf_iface_patt u32 deadc; u32 deadint; u32 inftransdelay; - u32 priority; - u32 strictnbma; list nbma_list; + u32 priority; u32 voa; u32 vid; u16 rxbuf; - u8 check_link; - u8 ecmp_weight; #define OSPF_RXBUF_NORMAL 0 #define OSPF_RXBUF_LARGE 1 #define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */ - u32 autype; /* Not really used in OSPFv3 */ + u16 autype; /* Not really used in OSPFv3 */ #define OSPF_AUTH_NONE 0 #define OSPF_AUTH_SIMPLE 1 #define OSPF_AUTH_CRYPT 2 #define OSPF_AUTH_CRYPT_SIZE 16 + u8 strictnbma; + u8 check_link; + u8 ecmp_weight; + u8 real_bcast; /* Not really used in OSPFv3 */ #ifdef OSPFv2 list *passwords; diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 7a26967f..241a58f7 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -273,7 +273,7 @@ ospf_rx_hook(sock *sk, int size) int src_local, dst_local UNUSED, dst_mcast; src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen); dst_local = ipa_equal(sk->laddr, ifa->addr->ip); - dst_mcast = ipa_equal(sk->laddr, AllSPFRouters) || ipa_equal(sk->laddr, AllDRouters); + dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, AllDRouters); #ifdef OSPFv2 /* First, we eliminate packets with strange address combinations. @@ -287,6 +287,9 @@ ospf_rx_hook(sock *sk, int size) if (!dst_mcast && !dst_local) return 1; + /* Ignore my own broadcast packets */ + if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip)) + return 1; #else /* OSPFv3 */ /* In OSPFv3, src_local and dst_local mean link-local. diff --git a/proto/ospf/packet.h b/proto/ospf/packet.h index c0185b9c..fbcb4288 100644 --- a/proto/ospf/packet.h +++ b/proto/ospf/packet.h @@ -19,6 +19,8 @@ void ospf_send_to_agt(struct ospf_iface *ifa, u8 state); void ospf_send_to_bdr(struct ospf_iface *ifa); void ospf_send_to(struct ospf_iface *ifa, ip_addr ip); +static inline void ospf_send_to_all(struct ospf_iface *ifa) { ospf_send_to(ifa, ifa->all_routers); } + static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; } static inline unsigned diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 604c8ea7..7e9bad50 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -798,7 +798,7 @@ originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric) body = originate_sum_net_lsa_body(po, &lsa.length, fn, metric); lsasum_calculate(&lsa, body); - en = lsa_install_new(po, &lsa, dom, body); + lsa_install_new(po, &lsa, dom, body); ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); } @@ -835,7 +835,7 @@ originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 body = originate_sum_rt_lsa_body(po, &lsa.length, lsa.id, metric, options); lsasum_calculate(&lsa, body); - en = lsa_install_new(po, &lsa, dom, body); + lsa_install_new(po, &lsa, dom, body); ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); } @@ -1117,7 +1117,7 @@ originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, if (src) fn->x1 = src; - en = lsa_install_new(po, &lsa, dom, body); + lsa_install_new(po, &lsa, dom, body); ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1); if (po->ebit == 0) diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index 36b06d43..6099d284 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -24,9 +24,10 @@ * rte_update(), an import filter in ahook 2 is called. When a new * route is announced in the peer table, an export filter in ahook2 * and an import filter in ahook 1 are used. Oviously, there is no - * need in filtering the same route twice, so both import filters - * are set to accept, while user configured 'import' and 'export' - * filters are used as export filters in ahooks 2 and 1. + * need in filtering the same route twice, so both import filters are + * set to accept, while user configured 'import' and 'export' filters + * are used as export filters in ahooks 2 and 1. Route limits are + * handled similarly, but on the import side of ahooks. */ #undef LOCAL_DEBUG @@ -116,6 +117,8 @@ pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpo static int pipe_reload_routes(struct proto *P) { + struct pipe_proto *p = (struct pipe_proto *) P; + /* * Because the pipe protocol feeds routes from both routing tables * together, both directions are reloaded during refeed and 'reload @@ -123,6 +126,10 @@ pipe_reload_routes(struct proto *P) * request refeed when 'reload in' command is used. */ proto_request_feeding(P); + + proto_reset_limit(P->main_ahook->in_limit); + proto_reset_limit(p->peer_ahook->in_limit); + return 1; } @@ -146,6 +153,7 @@ pipe_init(struct proto_config *C) static int pipe_start(struct proto *P) { + struct pipe_config *cf = (struct pipe_config *) P->cf; struct pipe_proto *p = (struct pipe_proto *) P; /* Lock both tables, unlock is handled in pipe_cleanup() */ @@ -155,10 +163,15 @@ pipe_start(struct proto *P) /* Going directly to PS_UP - prepare for feeding, connect the protocol to both routing tables */ - P->main_ahook = proto_add_announce_hook(P, P->table, - FILTER_ACCEPT, P->cf->out_filter, &P->stats); - p->peer_ahook = proto_add_announce_hook(P, p->peer_table, - FILTER_ACCEPT, P->cf->in_filter, &p->peer_stats); + P->main_ahook = proto_add_announce_hook(P, P->table, &P->stats); + P->main_ahook->out_filter = cf->c.out_filter; + P->main_ahook->in_limit = cf->c.in_limit; + proto_reset_limit(P->main_ahook->in_limit); + + p->peer_ahook = proto_add_announce_hook(P, p->peer_table, &p->peer_stats); + p->peer_ahook->out_filter = cf->c.in_filter; + p->peer_ahook->in_limit = cf->c.out_limit; + proto_reset_limit(p->peer_ahook->in_limit); return PS_UP; } @@ -204,10 +217,16 @@ pipe_reconfigure(struct proto *P, struct proto_config *new) /* Update output filters in ahooks */ if (P->main_ahook) - P->main_ahook->out_filter = new->out_filter; + { + P->main_ahook->out_filter = new->out_filter; + P->main_ahook->in_limit = new->in_limit; + } if (p->peer_ahook) - p->peer_ahook->out_filter = new->in_filter; + { + p->peer_ahook->out_filter = new->in_filter; + p->peer_ahook->in_limit = new->out_limit; + } if ((P->proto_state != PS_UP) || (proto_reconfig_type == RECONFIG_SOFT)) return 1; @@ -283,12 +302,16 @@ static void pipe_show_proto_info(struct proto *P) { struct pipe_proto *p = (struct pipe_proto *) P; + struct pipe_config *cf = (struct pipe_config *) P->cf; // cli_msg(-1006, " Table: %s", P->table->name); // cli_msg(-1006, " Peer table: %s", p->peer_table->name); cli_msg(-1006, " Preference: %d", P->preference); - cli_msg(-1006, " Input filter: %s", filter_name(P->cf->in_filter)); - cli_msg(-1006, " Output filter: %s", filter_name(P->cf->out_filter)); + cli_msg(-1006, " Input filter: %s", filter_name(cf->c.in_filter)); + cli_msg(-1006, " Output filter: %s", filter_name(cf->c.out_filter)); + + proto_show_limit(cf->c.in_limit, "Import limit:"); + proto_show_limit(cf->c.out_limit, "Export limit:"); if (P->proto_state != PS_DOWN) pipe_show_stats(p); diff --git a/proto/radv/config.Y b/proto/radv/config.Y index 495d9a05..abccd2c7 100644 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@ -14,32 +14,45 @@ CF_DEFINES #define RADV_CFG ((struct radv_config *) this_proto) #define RADV_IFACE ((struct radv_iface_config *) this_ipatt) #define RADV_PREFIX this_radv_prefix +#define RADV_RDNSS (&this_radv_rdnss) +#define RADV_DNSSL (&this_radv_dnssl) static struct radv_prefix_config *this_radv_prefix; +static struct radv_rdnss_config this_radv_rdnss; +static struct radv_dnssl_config this_radv_dnssl; +static list radv_dns_list; /* Used by radv_rdnss and radv_dnssl */ +static u8 radv_mult_val; /* Used by radv_mult for second return value */ + CF_DECLS CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL, MANAGED, OTHER, CONFIG, LINK, MTU, REACHABLE, TIME, RETRANS, - TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, - LIFETIME, SKIP, ONLINK, AUTONOMOUS) + TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT, + LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN, + LOCAL) +%type<i> radv_mult CF_GRAMMAR -CF_ADDTO(proto, radv_proto '}') +CF_ADDTO(proto, radv_proto) radv_proto_start: proto_start RADV { this_proto = proto_config_new(&proto_radv, sizeof(struct radv_config), $1); init_list(&RADV_CFG->patt_list); init_list(&RADV_CFG->pref_list); + init_list(&RADV_CFG->rdnss_list); + init_list(&RADV_CFG->dnssl_list); }; radv_proto_item: proto_item - | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); } | INTERFACE radv_iface + | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); } + | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); } + | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); } ; radv_proto_opts: @@ -48,7 +61,7 @@ radv_proto_opts: ; radv_proto: - radv_proto_start proto_name '{' radv_proto_opts; + radv_proto_start proto_name '{' radv_proto_opts '}'; radv_iface_start: @@ -57,6 +70,8 @@ radv_iface_start: add_tail(&RADV_CFG->patt_list, NODE this_ipatt); init_list(&this_ipatt->ipn_list); init_list(&RADV_IFACE->pref_list); + init_list(&RADV_IFACE->rdnss_list); + init_list(&RADV_IFACE->dnssl_list); RADV_IFACE->min_ra_int = -1; /* undefined */ RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT; @@ -77,6 +92,10 @@ radv_iface_item: | CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if (($4 < 0) || ($4 > 255)) cf_error("Current hop limit must be in range 0-255"); } | DEFAULT LIFETIME expr { RADV_IFACE->default_lifetime = $3; if (($3 < 0) || ($3 > 9000)) cf_error("Default lifetime must be in range 0-9000"); } | PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); } + | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); } + | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); } + | RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; } + | DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; } ; radv_iface_finish: @@ -152,6 +171,103 @@ radv_prefix: radv_prefix_start radv_prefix_opt_list radv_prefix_finish; + +radv_rdnss_node: ipa +{ + struct radv_rdnss_config *cf = cfg_allocz(sizeof(struct radv_rdnss_config)); + add_tail(&radv_dns_list, NODE cf); + + cf->server = $1; + cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; +}; + +radv_rdnss_start: +{ + RADV_RDNSS->lifetime = 0; + RADV_RDNSS->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; +}; + +radv_rdnss_item: + | NS radv_rdnss_node + | LIFETIME radv_mult { RADV_RDNSS->lifetime = $2; RADV_RDNSS->lifetime_mult = radv_mult_val; } + ; + +radv_rdnss_finish: +{ + if (EMPTY_LIST(radv_dns_list)) + cf_error("No nameserver in RDNSS section"); + + struct radv_rdnss_config *cf; + WALK_LIST(cf, radv_dns_list) + { + cf->lifetime = RADV_RDNSS->lifetime; + cf->lifetime_mult = RADV_RDNSS->lifetime_mult; + } +}; + +radv_rdnss_opts: + /* empty */ + | radv_rdnss_opts radv_rdnss_item ';' + ; + +radv_rdnss: + radv_rdnss_node + | '{' radv_rdnss_start radv_rdnss_opts '}' radv_rdnss_finish + ; + + +radv_dnssl_node: TEXT +{ + struct radv_dnssl_config *cf = cfg_allocz(sizeof(struct radv_dnssl_config)); + add_tail(&radv_dns_list, NODE cf); + + cf->domain = $1; + cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; + + if (radv_process_domain(cf) < 0) + cf_error("Invalid domain dame"); +}; + +radv_dnssl_start: +{ + RADV_DNSSL->lifetime = 0; + RADV_DNSSL->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; +}; + +radv_dnssl_item: + | DOMAIN radv_dnssl_node + | LIFETIME radv_mult { RADV_DNSSL->lifetime = $2; RADV_DNSSL->lifetime_mult = radv_mult_val; } + ; + +radv_dnssl_finish: +{ + if (EMPTY_LIST(radv_dns_list)) + cf_error("No domain in DNSSL section"); + + struct radv_dnssl_config *cf; + WALK_LIST(cf, radv_dns_list) + { + cf->lifetime = RADV_DNSSL->lifetime; + cf->lifetime_mult = RADV_DNSSL->lifetime_mult; + } +}; + +radv_dnssl_opts: + /* empty */ + | radv_dnssl_opts radv_dnssl_item ';' + ; + +radv_dnssl: + radv_dnssl_node + | '{' radv_dnssl_start radv_dnssl_opts '}' radv_dnssl_finish + ; + + +radv_mult: + expr { $$ = $1; radv_mult_val = 0; } + | MULT expr { $$ = 0; radv_mult_val = $2; if (($2 < 1) || ($2 > 254)) cf_error("Multiplier must be in range 1-254"); } + ; + CF_CODE CF_END diff --git a/proto/radv/packets.c b/proto/radv/packets.c index ac59ce94..6fdfcaa3 100644 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@ -24,8 +24,10 @@ struct radv_ra_packet #define OPT_RA_MANAGED 0x80 #define OPT_RA_OTHER_CFG 0x40 -#define OPT_PREFIX 3 -#define OPT_MTU 5 +#define OPT_PREFIX 3 +#define OPT_MTU 5 +#define OPT_RDNSS 25 +#define OPT_DNSSL 31 struct radv_opt_prefix { @@ -50,6 +52,25 @@ struct radv_opt_mtu u32 mtu; }; +struct radv_opt_rdnss +{ + u8 type; + u8 length; + u16 reserved; + u32 lifetime; + ip_addr servers[]; +}; + +struct radv_opt_dnssl +{ + u8 type; + u8 length; + u16 reserved; + u32 lifetime; + char domain[]; +}; + + static struct radv_prefix_config default_prefix = { .onlink = 1, .autonomous = 1, @@ -57,6 +78,7 @@ static struct radv_prefix_config default_prefix = { .preferred_lifetime = DEFAULT_PREFERRED_LIFETIME }; + static struct radv_prefix_config * radv_prefix_match(struct radv_iface *ifa, struct ifa *a) { @@ -78,10 +100,146 @@ radv_prefix_match(struct radv_iface *ifa, struct ifa *a) return &default_prefix; } +static int +radv_prepare_rdnss(struct radv_iface *ifa, list *rdnss_list, char **buf, char *bufend) +{ + struct radv_rdnss_config *rcf = HEAD(*rdnss_list); + + while(NODE_VALID(rcf)) + { + struct radv_rdnss_config *rcf_base = rcf; + struct radv_opt_rdnss *op = (void *) *buf; + int max_i = (bufend - *buf - sizeof(struct radv_opt_rdnss)) / sizeof(ip_addr); + int i = 0; + + if (max_i < 1) + goto too_much; + + op->type = OPT_RDNSS; + op->reserved = 0; + + if (rcf->lifetime_mult) + op->lifetime = htonl(rcf->lifetime_mult * ifa->cf->max_ra_int); + else + op->lifetime = htonl(rcf->lifetime); + + while(NODE_VALID(rcf) && + (rcf->lifetime == rcf_base->lifetime) && + (rcf->lifetime_mult == rcf_base->lifetime_mult)) + { + if (i >= max_i) + goto too_much; + + op->servers[i] = rcf->server; + ipa_hton(op->servers[i]); + i++; + + rcf = NODE_NEXT(rcf); + } + + op->length = 1+2*i; + *buf += 8 * op->length; + } + + return 0; + + too_much: + log(L_WARN "%s: Too many RA options on interface %s", + ifa->ra->p.name, ifa->iface->name); + return -1; +} + +int +radv_process_domain(struct radv_dnssl_config *cf) +{ + /* Format of domain in search list is <size> <label> <size> <label> ... 0 */ + + char *dom = cf->domain; + char *dom_end = dom; /* Just to */ + u8 *dlen_save = &cf->dlen_first; + int len; + + while (dom_end) + { + dom_end = strchr(dom, '.'); + len = dom_end ? (dom_end - dom) : strlen(dom); + + if (len < 1 || len > 63) + return -1; + + *dlen_save = len; + dlen_save = (u8 *) dom_end; + + dom += len + 1; + } + + len = dom - cf->domain; + if (len > 254) + return -1; + + cf->dlen_all = len; + + return 0; +} + +static int +radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *bufend) +{ + struct radv_dnssl_config *dcf = HEAD(*dnssl_list); + + while(NODE_VALID(dcf)) + { + struct radv_dnssl_config *dcf_base = dcf; + struct radv_opt_dnssl *op = (void *) *buf; + int bsize = bufend - *buf - sizeof(struct radv_opt_dnssl); + int bpos = 0; + + if (bsize < 0) + goto too_much; + + bsize = bsize & ~7; /* Round down to multiples of 8 */ + + op->type = OPT_DNSSL; + op->reserved = 0; + + if (dcf->lifetime_mult) + op->lifetime = htonl(dcf->lifetime_mult * ifa->cf->max_ra_int); + else + op->lifetime = htonl(dcf->lifetime); + + while(NODE_VALID(dcf) && + (dcf->lifetime == dcf_base->lifetime) && + (dcf->lifetime_mult == dcf_base->lifetime_mult)) + { + if (bpos + dcf->dlen_all + 1 > bsize) + goto too_much; + + op->domain[bpos++] = dcf->dlen_first; + memcpy(op->domain + bpos, dcf->domain, dcf->dlen_all); + bpos += dcf->dlen_all; + + dcf = NODE_NEXT(dcf); + } + + int blen = (bpos + 7) / 8; + bzero(op->domain + bpos, 8 * blen - bpos); + op->length = 1 + blen; + *buf += 8 * op->length; + } + + return 0; + + too_much: + log(L_WARN "%s: Too many RA options on interface %s", + ifa->ra->p.name, ifa->iface->name); + return -1; +} + static void radv_prepare_ra(struct radv_iface *ifa) { struct proto_radv *ra = ifa->ra; + struct radv_config *cf = (struct radv_config *) (ra->p.cf); char *buf = ifa->sk->tbuf; char *bufstart = buf; @@ -121,7 +279,7 @@ radv_prepare_ra(struct radv_iface *ifa) if (buf + sizeof(struct radv_opt_prefix) > bufend) { log(L_WARN "%s: Too many prefixes on interface %s", ra->p.name, ifa->iface->name); - break; + goto done; } struct radv_opt_prefix *op = (void *) buf; @@ -137,7 +295,22 @@ radv_prepare_ra(struct radv_iface *ifa) ipa_hton(op->prefix); buf += sizeof(*op); } - + + if (! ifa->cf->rdnss_local) + if (radv_prepare_rdnss(ifa, &cf->rdnss_list, &buf, bufend) < 0) + goto done; + + if (radv_prepare_rdnss(ifa, &ifa->cf->rdnss_list, &buf, bufend) < 0) + goto done; + + if (! ifa->cf->dnssl_local) + if (radv_prepare_dnssl(ifa, &cf->dnssl_list, &buf, bufend) < 0) + goto done; + + if (radv_prepare_dnssl(ifa, &ifa->cf->dnssl_list, &buf, bufend) < 0) + goto done; + + done: ifa->plen = buf - bufstart; } diff --git a/proto/radv/radv.c b/proto/radv/radv.c index d6fc8da5..5e7296a3 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -29,6 +29,10 @@ * radv_iface_notify(), which processes asynchronous events (specified * by RA_EV_* codes), and radv_timer(), which triggers sending RAs and * computes the next timeout. + * + * Supported standards: + * - RFC 4861 - main RA standard + * - RFC 6106 - DNS extensions (RDDNS, DNSSL) */ static void diff --git a/proto/radv/radv.h b/proto/radv/radv.h index 12bfe42e..48af8c00 100644 --- a/proto/radv/radv.h +++ b/proto/radv/radv.h @@ -42,24 +42,33 @@ #define DEFAULT_VALID_LIFETIME 86400 #define DEFAULT_PREFERRED_LIFETIME 14400 +#define DEFAULT_DNS_LIFETIME_MULT 3 + struct radv_config { struct proto_config c; list patt_list; /* List of iface configs (struct radv_iface_config) */ list pref_list; /* Global list of prefix configs (struct radv_prefix_config) */ + list rdnss_list; /* Global list of RDNSS configs (struct radv_rdnss_config) */ + list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */ }; struct radv_iface_config { struct iface_patt i; list pref_list; /* Local list of prefix configs (struct radv_prefix_config) */ + list rdnss_list; /* Local list of RDNSS configs (struct radv_rdnss_config) */ + list dnssl_list; /* Local list of DNSSL configs (struct radv_dnssl_config) */ u32 min_ra_int; /* Standard options from RFC 4261 */ u32 max_ra_int; u32 min_delay; - u8 managed; + u8 rdnss_local; /* Global list is not used for RDNSS */ + u8 dnssl_local; /* Global list is not used for DNSSL */ + + u8 managed; /* Standard options from RFC 4261 */ u8 other_config; u32 link_mtu; u32 reachable_time; @@ -81,6 +90,25 @@ struct radv_prefix_config u32 preferred_lifetime; }; +struct radv_rdnss_config +{ + node n; + u32 lifetime; /* Valid if lifetime_mult is 0 */ + u16 lifetime_mult; /* Lifetime specified as multiple of max_ra_int */ + ip_addr server; /* IP address of recursive DNS server */ +}; + +struct radv_dnssl_config +{ + node n; + u32 lifetime; /* Valid if lifetime_mult is 0 */ + u16 lifetime_mult; /* Lifetime specified as multiple of max_ra_int */ + u8 dlen_first; /* Length of first label in domain */ + u8 dlen_all; /* Both dlen_ filled in radv_process_domain() */ + char *domain; /* Domain for DNS search list, in processed form */ +}; + + struct proto_radv { struct proto p; @@ -123,6 +151,7 @@ struct radv_iface void radv_iface_notify(struct radv_iface *ifa, int event); /* packets.c */ +int radv_process_domain(struct radv_dnssl_config *cf); void radv_send_ra(struct radv_iface *ifa, int shutdown); int radv_sk_open(struct radv_iface *ifa); diff --git a/proto/rip/rip.c b/proto/rip/rip.c index b41c3f8d..281296a5 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -624,7 +624,6 @@ rip_dump(struct proto *p) int i; node *w; struct rip_interface *rif; - i = 0; CHK_MAGIC; WALK_LIST( w, P->connections ) { @@ -995,8 +994,8 @@ static int rip_get_attr(eattr *a, byte *buf, int buflen UNUSED) { switch (a->id) { - case EA_RIP_METRIC: buf += bsprintf( buf, "metric: %d", a->u.data ); return GA_FULL; - case EA_RIP_TAG: buf += bsprintf( buf, "tag: %d", a->u.data ); return GA_FULL; + case EA_RIP_METRIC: bsprintf( buf, "metric: %d", a->u.data ); return GA_FULL; + case EA_RIP_TAG: bsprintf( buf, "tag: %d", a->u.data ); return GA_FULL; default: return GA_UNKNOWN; } } |