diff --git a/doc/bird.sgml b/doc/bird.sgml index 820ebaa2..b43eb263 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1825,6 +1825,7 @@ protocol ospf <name> { type [broadcast|bcast|pointopoint|ptp| nonbroadcast|nbma|pointomultipoint|ptmp]; strict nonbroadcast <switch>; + real broadcast <switch>; check link <switch>; ecmp weight <num>; authentication [none|simple|cryptographic]; @@ -2058,6 +2059,16 @@ protocol ospf <name> { If set, don't send hello to any undefined neighbor. This switch is ignored on other than NBMA or PtMP networks. Default value is no. + real broadcast + In check link switch If set, a hardware link state (reported by OS) is taken into consideration. When a link disappears (e.g. an ethernet cable is diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 0c36b7f8..67b0785f 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -130,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, INSTANCE) +CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL) %type opttext %type lsadb_args @@ -287,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 ; } 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_setup_multicast(sk) < 0) - goto err; + 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_join_group(sk, AllSPFRouters) < 0) - goto err; + if (sk_setup_multicast(sk) < 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.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