summaryrefslogtreecommitdiffstats
path: root/proto/ospf/ospf.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/ospf.c')
-rw-r--r--proto/ospf/ospf.c84
1 files changed, 47 insertions, 37 deletions
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 191aa45..d345e49 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -42,6 +42,32 @@
* and deletion. Each LSA is kept in two pieces: header and body. Both of them are
* kept in the endianity of the CPU.
*
+ * In OSPFv2 specification, it is implied that there is one IP prefix
+ * for each physical network/interface (unless it is an ptp link). But
+ * in modern systems, there might be more independent IP prefixes
+ * associated with an interface. To handle this situation, we have
+ * one &ospf_iface for each active IP prefix (instead for each active
+ * iface); This behaves like virtual interface for the purpose of OSPF.
+ * If we receive packet, we associate it with a proper virtual interface
+ * mainly according to its source address.
+ *
+ * OSPF keeps one socket per &ospf_iface. This allows us (compared to
+ * one socket approach) to evade problems with a limit of multicast
+ * groups per socket and with sending multicast packets to appropriate
+ * interface in a portable way. The socket is associated with
+ * underlying physical iface and should not receive packets received
+ * on other ifaces (unfortunately, this is not true on
+ * BSD). Generally, one packet can be received by more sockets (for
+ * example, if there are more &ospf_iface on one physical iface),
+ * therefore we explicitly filter received packets according to
+ * src/dst IP address and received iface.
+ *
+ * Vlinks are implemented using particularly degenerate form of
+ * &ospf_iface, which has several exceptions: it does not have its
+ * iface or socket (it copies these from 'parent' &ospf_iface) and it
+ * is present in iface list even when down (it is not freed in
+ * ospf_iface_down()).
+ *
* The heart beat of ospf is ospf_disp(). It is called at regular intervals
* (&proto_ospf->tick). It is responsible for aging and flushing of LSAs in
* the database, for routing table calculaction and it call area_disp() of every
@@ -79,7 +105,6 @@
static int ospf_reload_routes(struct proto *p);
static void ospf_rt_notify(struct proto *p, struct rtable *table UNUSED, net * n, rte * new, rte * old UNUSED, ea_list * attrs);
-static void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a);
static int ospf_rte_better(struct rte *new, struct rte *old);
static int ospf_rte_same(struct rte *new, struct rte *old);
static void ospf_disp(timer *timer);
@@ -196,7 +221,7 @@ ospf_start(struct proto *p)
oa->options = OPT_R | OPT_E | OPT_V6;
#endif
}
- ospf_iface_new(po, NULL, ac, ipatt);
+ ospf_iface_new(po, NULL, NULL, ac, ipatt);
}
}
}
@@ -480,7 +505,9 @@ ospf_shutdown(struct proto *p)
OSPF_TRACE(D_EVENTS, "Shutdown requested");
/* And send to all my neighbors 1WAY */
- WALK_LIST(ifa, po->iface_list) ospf_iface_shutdown(ifa);
+ WALK_LIST(ifa, po->iface_list)
+ if (ifa->state > OSPF_IS_DOWN)
+ ospf_iface_shutdown(ifa);
return PS_DOWN;
}
@@ -502,27 +529,6 @@ ospf_rt_notify(struct proto *p, rtable *tbl UNUSED, net * n, rte * new, rte * ol
}
static void
-ospf_ifa_notify(struct proto *p, unsigned flags UNUSED, struct ifa *a)
-{
- struct proto_ospf *po = (struct proto_ospf *) p;
- struct ospf_iface *ifa;
-
- if ((a->flags & IA_SECONDARY) || (a->flags & IA_UNNUMBERED))
- return;
-
- WALK_LIST(ifa, po->iface_list)
- {
- if (ifa->iface == a->iface)
- {
- schedule_rt_lsa(ifa->oa);
- /* Event 5 from RFC5340 4.4.3. */
- schedule_link_lsa(ifa);
- return;
- }
- }
-}
-
-static void
ospf_get_status(struct proto *p, byte * buf)
{
struct proto_ospf *po = (struct proto_ospf *) p;
@@ -712,12 +718,17 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
WALK_LIST(ifa, po->iface_list)
{
+ /* FIXME: better handling of vlinks */
+ if (ifa->iface == NULL)
+ continue;
+
+ /* FIXME: better matching of interface_id in OSPFv3 */
if (oldip = (struct ospf_iface_patt *)
- iface_patt_find(&oldac->patt_list, ifa->iface))
+ iface_patt_find(&oldac->patt_list, ifa->iface, ifa->addr))
{
/* Now reconfigure interface */
if (!(newip = (struct ospf_iface_patt *)
- iface_patt_find(&newac->patt_list, ifa->iface)))
+ iface_patt_find(&newac->patt_list, ifa->iface, ifa->addr)))
return 0;
/* HELLO TIMER */
@@ -778,18 +789,17 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
}
/* stub */
- if ((oldip->stub == 0) && (newip->stub != 0))
+ int old_stub = ospf_iface_stubby(oldip, ifa->addr);
+ int new_stub = ospf_iface_stubby(newip, ifa->addr);
+ if (!old_stub && new_stub)
{
- ifa->stub = newip->stub;
+ ifa->stub = 1;
OSPF_TRACE(D_EVENTS, "Interface %s is now stub.", ifa->iface->name);
}
- if ((oldip->stub != 0) && (newip->stub == 0) &&
- ((ifa->ioprob & OSPF_I_IP) == 0) &&
- (((ifa->ioprob & OSPF_I_MC) == 0) || (ifa->type == OSPF_IT_NBMA)))
+ if (old_stub && !new_stub && (ifa->ioprob == OSPF_I_OK))
{
- ifa->stub = newip->stub;
- OSPF_TRACE(D_EVENTS,
- "Interface %s is no longer stub.", ifa->iface->name);
+ ifa->stub = 0;
+ OSPF_TRACE(D_EVENTS, "Interface %s is no longer stub.", ifa->iface->name);
}
#ifdef OSPFv2
@@ -1209,7 +1219,7 @@ show_lsa_sum_net(struct top_hash_entry *he)
lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest);
#endif
- cli_msg(-1016, "\t\txnetwork %I/%d", ip, pxlen);
+ cli_msg(-1016, "\t\txnetwork %I/%d metric %u", ip, pxlen, ls->metric);
}
static inline void
@@ -1218,7 +1228,7 @@ show_lsa_sum_rt(struct top_hash_entry *he)
u32 dst_rid, options;
#ifdef OSPFv2
- // struct ospf_lsa_sum *ls = he->lsa_body;
+ struct ospf_lsa_sum *ls = he->lsa_body;
dst_rid = he->lsa.id;
options = 0;
#else /* OSPFv3 */
@@ -1227,7 +1237,7 @@ show_lsa_sum_rt(struct top_hash_entry *he)
options = ls->options & OPTIONS_MASK;
#endif
- cli_msg(-1016, "\t\txrouter %R", dst_rid);
+ cli_msg(-1016, "\t\txrouter %R metric %u", dst_rid, ls->metric);
}