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