summaryrefslogtreecommitdiff
path: root/proto/ospf/iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/iface.c')
-rw-r--r--proto/ospf/iface.c621
1 files changed, 301 insertions, 320 deletions
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index 50cf15e2..892e8a77 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -2,12 +2,15 @@
* BIRD -- OSPF
*
* (c) 1999--2005 Ondrej Filip <feela@network.cz>
+ * (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2009--2014 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include "ospf.h"
+
char *ospf_is[] = { "down", "loop", "waiting", "ptp", "drother",
"backup", "dr"
};
@@ -18,32 +21,33 @@ char *ospf_ism[] = { "interface up", "wait timer fired", "backup seen",
char *ospf_it[] = { "broadcast", "nbma", "ptp", "ptmp", "virtual link" };
+
static void
poll_timer_hook(timer * timer)
{
- ospf_hello_send(timer->data, OHS_POLL, NULL);
+ ospf_send_hello(timer->data, OHS_POLL, NULL);
}
static void
hello_timer_hook(timer * timer)
{
- ospf_hello_send(timer->data, OHS_HELLO, NULL);
+ ospf_send_hello(timer->data, OHS_HELLO, NULL);
}
static void
wait_timer_hook(timer * timer)
{
struct ospf_iface *ifa = (struct ospf_iface *) timer->data;
- struct proto *p = &ifa->oa->po->proto;
+ struct ospf_proto *p = ifa->oa->po;
- OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->ifname);
+ OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s", ifa->ifname);
ospf_iface_sm(ifa, ISM_WAITF);
}
static inline uint
ifa_tx_length(struct ospf_iface *ifa)
{
- return ifa->cf->tx_length ?: ifa->iface->mtu;
+ return ifa->cf->tx_length ?: ifa->iface->mtu;
}
static inline uint
@@ -58,10 +62,9 @@ ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen)
{
plen += SIZE_OF_IP_HEADER;
-#ifdef OSPFv2
+ /* This is relevant just for OSPFv2 */
if (ifa->autype == OSPF_AUTH_CRYPT)
plen += OSPF_AUTH_CRYPT_SIZE;
-#endif
if (plen <= ifa->sk->tbsize)
return 0;
@@ -77,12 +80,14 @@ ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen)
struct nbma_node *
-find_nbma_node_in(list *nnl, ip_addr ip)
+find_nbma_node_(list *nnl, ip_addr ip)
{
struct nbma_node *nn;
+
WALK_LIST(nn, *nnl)
if (ipa_equal(nn->ip, ip))
return nn;
+
return NULL;
}
@@ -90,7 +95,7 @@ find_nbma_node_in(list *nnl, ip_addr ip)
static int
ospf_sk_open(struct ospf_iface *ifa)
{
- struct proto_ospf *po = ifa->oa->po;
+ struct ospf_proto *p = ifa->oa->po;
sock *sk = sk_new(ifa->pool);
sk->type = SK_IP;
@@ -111,30 +116,31 @@ ospf_sk_open(struct ospf_iface *ifa)
if (sk_open(sk) < 0)
goto err;
-#ifdef OSPFv3
- /* 12 is an offset of the checksum in an OSPF packet */
- if (sk_set_ipv6_checksum(sk, 12) < 0)
- goto err;
-#endif
+ /* 12 is an offset of the checksum in an OSPFv3 packet */
+ if (ospf_is_v3(p))
+ if (sk_set_ipv6_checksum(sk, 12) < 0)
+ goto err;
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP))
{
if (ifa->cf->real_bcast)
{
ifa->all_routers = ifa->addr->brd;
+ ifa->des_routers = IPA_NONE;
if (sk_setup_broadcast(sk) < 0)
- goto err;
+ goto err;
}
else
{
- ifa->all_routers = AllSPFRouters;
+ ifa->all_routers = ospf_is_v2(p) ? IP4_OSPF_ALL_ROUTERS : IP6_OSPF_ALL_ROUTERS;
+ ifa->des_routers = ospf_is_v2(p) ? IP4_OSPF_DES_ROUTERS : IP6_OSPF_DES_ROUTERS;
if (sk_setup_multicast(sk) < 0)
- goto err;
+ goto err;
if (sk_join_group(sk, ifa->all_routers) < 0)
- goto err;
+ goto err;
}
}
@@ -143,7 +149,7 @@ ospf_sk_open(struct ospf_iface *ifa)
return 1;
err:
- sk_log_error(sk, po->proto.name);
+ sk_log_error(sk, p->p.name);
rfree(sk);
return 0;
}
@@ -154,8 +160,8 @@ ospf_sk_join_dr(struct ospf_iface *ifa)
if (ifa->sk_dr)
return;
- if (sk_join_group(ifa->sk, AllDRouters) < 0)
- sk_log_error(ifa->sk, ifa->oa->po->proto.name);
+ if (sk_join_group(ifa->sk, ifa->des_routers) < 0)
+ sk_log_error(ifa->sk, ifa->oa->po->p.name);
ifa->sk_dr = 1;
}
@@ -166,16 +172,16 @@ ospf_sk_leave_dr(struct ospf_iface *ifa)
if (!ifa->sk_dr)
return;
- if (sk_leave_group(ifa->sk, AllDRouters) < 0)
- sk_log_error(ifa->sk, ifa->oa->po->proto.name);
+ if (sk_leave_group(ifa->sk, ifa->des_routers) < 0)
+ sk_log_error(ifa->sk, ifa->oa->po->p.name);
ifa->sk_dr = 0;
}
void
-ospf_open_vlink_sk(struct proto_ospf *po)
+ospf_open_vlink_sk(struct ospf_proto *p)
{
- sock *sk = sk_new(po->proto.pool);
+ sock *sk = sk_new(p->p.pool);
sk->type = SK_IP;
sk->dport = OSPF_PROTO;
@@ -185,48 +191,48 @@ ospf_open_vlink_sk(struct proto_ospf *po)
sk->err_hook = ospf_verr_hook;
sk->rbsize = 0;
- sk->tbsize = OSPF_VLINK_MTU;
- sk->data = (void *) po;
+ sk->tbsize = ospf_is_v2(p) ? IP4_MIN_MTU : IP6_MIN_MTU;
+ sk->data = (void *) p;
sk->flags = 0;
if (sk_open(sk) < 0)
goto err;
-#ifdef OSPFv3
- /* 12 is an offset of the checksum in an OSPF packet */
- if (sk_set_ipv6_checksum(sk, 12) < 0)
- goto err;
-#endif
+ /* 12 is an offset of the checksum in an OSPFv3 packet */
+ if (ospf_is_v3(p))
+ if (sk_set_ipv6_checksum(sk, 12) < 0)
+ goto err;
- po->vlink_sk = sk;
+ p->vlink_sk = sk;
return;
err:
- sk_log_error(sk, po->proto.name);
- log(L_ERR "%s: Cannot open virtual link socket", po->proto.name);
+ sk_log_error(sk, p->p.name);
+ log(L_ERR "%s: Cannot open virtual link socket", p->p.name);
rfree(sk);
}
static void
ospf_iface_down(struct ospf_iface *ifa)
{
+ struct ospf_proto *p = ifa->oa->po;
struct ospf_neighbor *n, *nx;
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
struct ospf_iface *iff;
if (ifa->type != OSPF_IT_VLINK)
{
-#ifdef OSPFv2
- OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
- ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
-#else
- OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
- ifa->ifname, ifa->instance_id, ifa->oa->areaid);
-#endif
+ if (ospf_is_v3(ifa->oa->po))
+ OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
+ ifa->ifname, ifa->instance_id, ifa->oa->areaid);
+ else if (ifa->addr->flags & IA_PEER)
+ OSPF_TRACE(D_EVENTS, "Removing interface %s (peer %I) from area %R",
+ ifa->ifname, ifa->addr->opposite, ifa->oa->areaid);
+ else
+ OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
+ ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
/* First of all kill all the related vlinks */
- WALK_LIST(iff, po->iface_list)
+ WALK_LIST(iff, p->iface_list)
{
if ((iff->type == OSPF_IT_VLINK) && (iff->vifa == ifa))
ospf_iface_sm(iff, ISM_DOWN);
@@ -248,6 +254,10 @@ ospf_iface_down(struct ospf_iface *ifa)
if (ifa->wait_timer)
tm_stop(ifa->wait_timer);
+ ospf_flush2_lsa(p, &ifa->link_lsa);
+ ospf_flush2_lsa(p, &ifa->net_lsa);
+ ospf_flush2_lsa(p, &ifa->pxn_lsa);
+
if (ifa->type == OSPF_IT_VLINK)
{
ifa->vifa = NULL;
@@ -258,17 +268,16 @@ ospf_iface_down(struct ospf_iface *ifa)
ifa->rt_pos_beg = 0;
ifa->rt_pos_end = 0;
-#ifdef OSPFv3
ifa->px_pos_beg = 0;
ifa->px_pos_end = 0;
-#endif
}
void
ospf_iface_remove(struct ospf_iface *ifa)
{
- struct proto *p = &ifa->oa->po->proto;
+ struct ospf_proto *p = ifa->oa->po;
+
if (ifa->type == OSPF_IT_VLINK)
OSPF_TRACE(D_EVENTS, "Removing vlink to %R via area %R", ifa->vid, ifa->voa->areaid);
@@ -281,7 +290,7 @@ void
ospf_iface_shutdown(struct ospf_iface *ifa)
{
if (ifa->state > OSPF_IS_DOWN)
- ospf_hello_send(ifa, OHS_SHUTDOWN, NULL);
+ ospf_send_hello(ifa, OHS_SHUTDOWN, NULL);
}
/**
@@ -296,23 +305,18 @@ ospf_iface_shutdown(struct ospf_iface *ifa)
void
ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
{
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
+ struct ospf_proto *p = ifa->oa->po;
u8 oldstate = ifa->state;
- if (oldstate == state)
+ if (state == oldstate)
return;
- ifa->state = state;
+ OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
+ ifa->ifname, ospf_is[oldstate], ospf_is[state]);
- if (ifa->type == OSPF_IT_VLINK)
- OSPF_TRACE(D_EVENTS, "Changing state of virtual link %R from %s to %s",
- ifa->vid, ospf_is[oldstate], ospf_is[state]);
- else
- OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
- ifa->ifname, ospf_is[oldstate], ospf_is[state]);
+ ifa->state = state;
- if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk)
+ if ((ifa->type == OSPF_IT_BCAST) && ipa_nonzero(ifa->des_routers) && ifa->sk)
{
if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))
ospf_sk_join_dr(ifa);
@@ -320,22 +324,17 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
ospf_sk_leave_dr(ifa);
}
- if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL))
- {
- ifa->net_lsa->lsa.age = LSA_MAXAGE;
- if (state >= OSPF_IS_WAITING)
- ospf_lsupd_flush_nlsa(po, ifa->net_lsa);
-
- if (can_flush_lsa(po))
- flush_lsa(ifa->net_lsa, po);
- ifa->net_lsa = NULL;
- }
-
if ((oldstate > OSPF_IS_LOOP) && (state <= OSPF_IS_LOOP))
ospf_iface_down(ifa);
- schedule_rt_lsa(ifa->oa);
- // FIXME flushling of link LSA
+ /* RFC 2328 12.4 Event 2 - iface state change */
+ ospf_notify_rt_lsa(ifa->oa);
+
+ /* RFC 5340 4.4.3 Event 1 - iface state change */
+ ospf_notify_link_lsa(ifa);
+
+ /* RFC 2328 12.4 Event 3 - iface enters/leaves DR state */
+ ospf_notify_net_lsa(ifa);
}
/**
@@ -352,7 +351,7 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
void
ospf_iface_sm(struct ospf_iface *ifa, int event)
{
- DBG("SM on iface %s. Event is '%s'\n", ifa->ifname, ospf_ism[event]);
+ DBG("SM on %s. Event is '%s'\n", ifa->ifname, ospf_ism[event]);
switch (event)
{
@@ -360,7 +359,9 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
if (ifa->state <= OSPF_IS_LOOP)
{
/* Now, nothing should be adjacent */
- if ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP) || (ifa->type == OSPF_IT_VLINK))
+ if ((ifa->type == OSPF_IT_PTP) ||
+ (ifa->type == OSPF_IT_PTMP) ||
+ (ifa->type == OSPF_IT_VLINK))
{
ospf_iface_chstate(ifa, OSPF_IS_PTP);
}
@@ -382,26 +383,19 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
if (ifa->poll_timer)
tm_start(ifa->poll_timer, ifa->pollint);
- ospf_hello_send(ifa, OHS_HELLO, NULL);
- schedule_link_lsa(ifa);
+ ospf_send_hello(ifa, OHS_HELLO, NULL);
}
break;
case ISM_BACKS:
case ISM_WAITF:
if (ifa->state == OSPF_IS_WAITING)
- {
- bdr_election(ifa);
- }
+ ospf_dr_election(ifa);
break;
case ISM_NEICH:
- if ((ifa->state == OSPF_IS_DROTHER) || (ifa->state == OSPF_IS_DR) ||
- (ifa->state == OSPF_IS_BACKUP))
- {
- bdr_election(ifa);
- schedule_rt_lsa(ifa->oa);
- }
+ if (ifa->state >= OSPF_IS_DROTHER)
+ ospf_dr_election(ifa);
break;
case ISM_LOOP:
@@ -427,7 +421,7 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
}
static u8
-ospf_iface_classify_int(struct iface *ifa, struct ifa *addr)
+ospf_iface_classify_(struct iface *ifa, struct ifa *addr)
{
if (ipa_nonzero(addr->opposite))
return (ifa->flags & IF_MULTICAST) ? OSPF_IT_PTP : OSPF_IT_PTMP;
@@ -445,17 +439,19 @@ ospf_iface_classify_int(struct iface *ifa, struct ifa *addr)
static inline u8
ospf_iface_classify(u8 type, struct ifa *addr)
{
- return (type != OSPF_IT_UNDEF) ? type : ospf_iface_classify_int(addr->iface, addr);
+ return (type != OSPF_IT_UNDEF) ? type : ospf_iface_classify_(addr->iface, addr);
}
struct ospf_iface *
-ospf_iface_find(struct proto_ospf *p, struct iface *what)
+ospf_iface_find(struct ospf_proto *p, struct iface *what)
{
- struct ospf_iface *i;
+ struct ospf_iface *ifa;
+
+ WALK_LIST(ifa, p->iface_list)
+ if ((ifa->iface == what) && (ifa->type != OSPF_IT_VLINK))
+ return ifa;
- WALK_LIST(i, p->iface_list) if ((i->iface == what) && (i->type != OSPF_IT_VLINK))
- return i;
return NULL;
}
@@ -463,13 +459,12 @@ static void
ospf_iface_add(struct object_lock *lock)
{
struct ospf_iface *ifa = lock->data;
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
+ struct ospf_proto *p = ifa->oa->po;
/* Open socket if interface is not stub */
if (! ifa->stub && ! ospf_sk_open(ifa))
{
- log(L_ERR "%s: Cannot open socket for %s, declaring as stub", p->name, ifa->ifname);
+ log(L_ERR "%s: Cannot open socket for %s, declaring as stub", p->p.name, ifa->ifname);
ifa->ioprob = OSPF_I_SK;
ifa->stub = 1;
}
@@ -525,20 +520,22 @@ ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
void
ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
{
- struct proto *p = &oa->po->proto;
+ struct ospf_proto *p = oa->po;
struct iface *iface = addr->iface;
struct ospf_iface *ifa;
struct pool *pool;
-#ifdef OSPFv2
- OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
- iface->name, addr->prefix, addr->pxlen, oa->areaid);
-#else
- OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
- iface->name, ip->instance_id, oa->areaid);
-#endif
+ if (ospf_is_v3(p))
+ OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
+ iface->name, ip->instance_id, oa->areaid);
+ else if (addr->flags & IA_PEER)
+ OSPF_TRACE(D_EVENTS, "Adding interface %s (peer %I) to area %R",
+ iface->name, addr->opposite, oa->areaid);
+ else
+ OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
+ iface->name, addr->prefix, addr->pxlen, oa->areaid);
- pool = rp_new(p->pool, "OSPF Interface");
+ pool = rp_new(p->p.pool, "OSPF Interface");
ifa = mb_allocz(pool, sizeof(struct ospf_iface));
ifa->iface = iface;
ifa->addr = addr;
@@ -560,24 +557,18 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->deadint = ip->deadint;
ifa->stub = ospf_iface_stubby(ip, addr);
ifa->ioprob = OSPF_I_OK;
-
ifa->tx_length = ifa_tx_length(ifa);
ifa->check_link = ip->check_link;
ifa->ecmp_weight = ip->ecmp_weight;
ifa->check_ttl = (ip->ttl_security == 1);
ifa->bfd = ip->bfd;
-
-#ifdef OSPFv2
ifa->autype = ip->autype;
ifa->passwords = ip->passwords;
+ ifa->instance_id = ip->instance_id;
+
ifa->ptp_netmask = !(addr->flags & IA_PEER);
if (ip->ptp_netmask < 2)
ifa->ptp_netmask = ip->ptp_netmask;
-#endif
-
-#ifdef OSPFv3
- ifa->instance_id = ip->instance_id;
-#endif
ifa->type = ospf_iface_classify(ip->type, addr);
@@ -586,13 +577,11 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
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))
+ if (ospf_is_v2(p) && (ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
ifa->type = OSPF_IT_PTP;
- if ((ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
+ if (ospf_is_v2(p) && (ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
ifa->type = OSPF_IT_PTMP;
-#endif
if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag))
ifa->type = OSPF_IT_NBMA;
@@ -602,8 +591,11 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
if (ifa->type != old_type)
log(L_WARN "%s: Cannot use interface %s as %s, forcing %s",
- p->name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);
+ p->p.name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);
+
+ if ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP))
+ ifa->link_lsa_suppression = ip->link_lsa_suppression;
ifa->state = OSPF_IS_DOWN;
init_list(&ifa->neigh_list);
@@ -617,34 +609,22 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
should be used). Because OSPFv3 iface is not subnet-specific,
there is no need for ipa_in_net() check */
-#ifdef OSPFv2
- if (!ipa_in_net(nb->ip, addr->prefix, addr->pxlen))
+ if (ospf_is_v2(p) && !ipa_in_net(nb->ip, addr->prefix, addr->pxlen))
continue;
-#else
- if (!ipa_has_link_scope(nb->ip))
+
+ if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip))
log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip);
-#endif
add_nbma_node(ifa, nb, 0);
}
add_tail(&oa->po->iface_list, NODE ifa);
- /*
- * In some cases we allow more ospf_ifaces on one physical iface.
- * In OSPFv2, if they use different IP address prefix.
- * In OSPFv3, if they use different instance_id.
- * Therefore, we store such info to lock->addr field.
- */
-
struct object_lock *lock = olock_new(pool);
-#ifdef OSPFv2
- lock->addr = ifa->addr->prefix;
-#else /* OSPFv3 */
- lock->addr = _MI(0,0,0,ifa->instance_id);
-#endif
+ lock->addr = ospf_is_v2(p) ? ifa->addr->prefix : IPA_NONE;
lock->type = OBJLOCK_IP;
lock->port = OSPF_PROTO;
+ lock->inst = ifa->instance_id;
lock->iface = iface;
lock->data = ifa;
lock->hook = ospf_iface_add;
@@ -653,50 +633,43 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
}
void
-ospf_iface_new_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip)
+ospf_iface_new_vlink(struct ospf_proto *p, struct ospf_iface_patt *ip)
{
- struct proto *p = &po->proto;
struct ospf_iface *ifa;
struct pool *pool;
- if (!po->vlink_sk)
+ if (!p->vlink_sk)
return;
OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);
/* Vlink ifname is stored just after the ospf_iface structure */
- pool = rp_new(p->pool, "OSPF Vlink");
+ pool = rp_new(p->p.pool, "OSPF Vlink");
ifa = mb_allocz(pool, sizeof(struct ospf_iface) + 16);
- ifa->oa = po->backbone;
+ ifa->oa = p->backbone;
ifa->cf = ip;
ifa->pool = pool;
/* Assign iface ID, for vlinks, this is ugly hack */
- u32 vlink_id = po->last_vlink_id++;
+ u32 vlink_id = p->last_vlink_id++;
ifa->iface_id = vlink_id + OSPF_VLINK_ID_OFFSET;
ifa->ifname = (void *) (ifa + 1);
bsprintf(ifa->ifname, "vlink%d", vlink_id);
- ifa->voa = ospf_find_area(po, ip->voa);
+ ifa->voa = ospf_find_area(p, ip->voa);
ifa->vid = ip->vid;
- ifa->sk = po->vlink_sk;
+ ifa->sk = p->vlink_sk;
ifa->helloint = ip->helloint;
ifa->rxmtint = ip->rxmtint;
ifa->waitint = ip->waitint;
ifa->deadint = ip->deadint;
ifa->inftransdelay = ip->inftransdelay;
- ifa->tx_length = OSPF_VLINK_MTU;
-
-#ifdef OSPFv2
+ ifa->tx_length = ospf_is_v2(p) ? IP4_MIN_MTU : IP6_MIN_MTU;
ifa->autype = ip->autype;
ifa->passwords = ip->passwords;
-#endif
-
-#ifdef OSPFv3
ifa->instance_id = ip->instance_id;
-#endif
ifa->type = OSPF_IT_VLINK;
@@ -704,13 +677,13 @@ ospf_iface_new_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip)
init_list(&ifa->neigh_list);
init_list(&ifa->nbma_list);
- add_tail(&po->iface_list, NODE ifa);
+ add_tail(&p->iface_list, NODE ifa);
ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
}
static void
-ospf_iface_change_timer(timer *tm, unsigned val)
+ospf_iface_change_timer(timer *tm, uint val)
{
if (!tm)
return;
@@ -724,7 +697,7 @@ ospf_iface_change_timer(timer *tm, unsigned val)
int
ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
{
- struct proto *p = &ifa->oa->po->proto;
+ struct ospf_proto *p = ifa->oa->po;
struct ospf_iface_patt *old = ifa->cf;
char *ifname = ifa->ifname;
@@ -806,7 +779,6 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
ifa->inftransdelay = new->inftransdelay;
}
-#ifdef OSPFv2
/* AUTHENTICATION */
if (ifa->autype != new->autype)
{
@@ -816,7 +788,6 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* Update passwords */
ifa->passwords = new->passwords;
-#endif
/* Remaining options are just for proper interfaces */
if (ifa->type == OSPF_IT_VLINK)
@@ -837,7 +808,9 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
{
OSPF_TRACE(D_EVENTS, "Changing priority on interface %s from %d to %d",
ifname, ifa->priority, new->priority);
+
ifa->priority = new->priority;
+ ospf_notify_link_lsa(ifa);
}
/* STRICT NBMA */
@@ -852,7 +825,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* NBMA LIST - remove or update old */
WALK_LIST_DELSAFE(nb, nbx, ifa->nbma_list)
{
- struct nbma_node *nb2 = find_nbma_node_in(&new->nbma_list, nb->ip);
+ struct nbma_node *nb2 = find_nbma_node_(&new->nbma_list, nb->ip);
if (nb2)
{
if (nb->eligible != nb2->eligible)
@@ -875,13 +848,11 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
WALK_LIST(nb, new->nbma_list)
{
/* See related note in ospf_iface_new() */
-#ifdef OSPFv2
- if (!ipa_in_net(nb->ip, ifa->addr->prefix, ifa->addr->pxlen))
+ if (ospf_is_v2(p) && !ipa_in_net(nb->ip, ifa->addr->prefix, ifa->addr->pxlen))
continue;
-#else
- if (!ipa_has_link_scope(nb->ip))
+
+ if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip))
log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip);
-#endif
if (! find_nbma_node(ifa, nb->ip))
{
@@ -942,6 +913,17 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
ifa->ecmp_weight = new->ecmp_weight;
}
+ /* Link LSA suppression */
+ if (((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP)) &&
+ (ifa->link_lsa_suppression != new->link_lsa_suppression))
+ {
+ OSPF_TRACE(D_EVENTS, "Changing link LSA suppression of %s from %d to %d",
+ ifname, ifa->link_lsa_suppression, new->link_lsa_suppression);
+
+ ifa->link_lsa_suppression = new->link_lsa_suppression;
+ ospf_notify_link_lsa(ifa);
+ }
+
/* BFD */
if (ifa->bfd != new->bfd)
{
@@ -961,131 +943,119 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
}
-#ifdef OSPFv2
+/*
+ * State for matching iface pattterns walk
+ *
+ * This is significantly different in OSPFv2 and OSPFv3.
+ * In OSPFv2, OSPF ifaces are created for each IP prefix (struct ifa)
+ * In OSPFv3, OSPF ifaces are created based on real iface (struct iface)
+ * We support instance_id for both OSPFv2 (RFC 6549) and OSPFv3.
+ *
+ * We process one ifa/iface and match it for all configured instance IDs. We
+ * maintain bitfields to track whether given instance ID was already matched.
+ * We have two bitfields, one global (active) and one per area (ignore), to
+ * detect misconfigured cases where one iface with one instance ID matches in
+ * multiple areas.
+ */
-static inline struct ospf_iface_patt *
-ospf_iface_patt_find(struct ospf_area_config *ac, struct ifa *a)
-{
- return (struct ospf_iface_patt *) iface_patt_find(&ac->patt_list, a->iface, a);
-}
+struct ospf_mip_walk {
+ u32 active[8]; /* Bitfield of active instance IDs */
+ u32 ignore[8]; /* Bitfield of instance IDs matched in current area */
+ struct ospf_area *oa; /* Current area */
+ struct ospf_iface_patt *ip; /* Current iface pattern */
+ struct iface *iface; /* Specified iface (input) */
+ struct ifa *a; /* Specified ifa (input) */
+ int warn; /* Whether iface matched in multiple areas */
+};
-void
-ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
+static int
+ospf_walk_matching_iface_patts(struct ospf_proto *p, struct ospf_mip_walk *s)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
-
- if (a->flags & IA_SECONDARY)
- return;
+ int id;
- if (a->scope <= SCOPE_LINK)
- return;
+ if (s->ip)
+ goto step;
- /* In OSPFv2, we create OSPF iface for each address. */
- if (flags & IF_CHANGE_UP)
+ WALK_LIST(s->oa, p->area_list)
{
- int done = 0;
- struct ospf_area *oa;
- WALK_LIST(oa, po->area_list)
+ WALK_LIST(s->ip, s->oa->ac->patt_list)
{
- struct ospf_iface_patt *ip;
- if (ip = ospf_iface_patt_find(oa->ac, a))
+ id = s->ip->instance_id;
+ if (BIT32_TEST(s->ignore, id))
+ continue;
+
+ if (iface_patt_match(&s->ip->i, s->iface, s->a))
{
- if (!done)
- ospf_iface_new(oa, a, ip);
- done++;
- }
- }
+ /* Now we matched ifa/iface/instance_id for the first time in current area */
+ BIT32_SET(s->ignore, id);
- if (done > 1)
- log(L_WARN "%s: Interface %s (IP %I) matches for multiple areas", p->name, a->iface->name, a->ip);
- }
+ /* If we already found it in previous areas, ignore it and add warning */
+ if (BIT32_TEST(s->active, id))
+ { s->warn = 1; continue; }
- if (flags & IF_CHANGE_DOWN)
- {
- struct ospf_iface *ifa, *ifx;
- WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
- {
- if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
- ospf_iface_remove(ifa);
- /* See a note in ospf_iface_notify() */
+ BIT32_SET(s->active, id);
+ return 1;
+ step:
+ ;
+ }
}
+ BIT32_ZERO(s->ignore, 256);
}
+
+ if (s->warn)
+ log(L_WARN "%s: Interface %s matches for multiple areas", p->p.name, s->iface->name);
+
+ return 0;
}
+
static struct ospf_iface *
-ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a)
+ospf_iface_find_by_key(struct ospf_proto *p, struct ifa *a, int instance_id)
{
struct ospf_iface *ifa;
- WALK_LIST(ifa, oa->po->iface_list)
- if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->type != OSPF_IT_VLINK))
+
+ WALK_LIST(ifa, p->iface_list)
+ if ((ifa->addr == a) && (ifa->instance_id == instance_id) &&
+ (ifa->type != OSPF_IT_VLINK))
return ifa;
return NULL;
}
+
void
-ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
+ospf_ifa_notify2(struct proto *P, uint flags, struct ifa *a)
{
- struct proto *p = &oa->po->proto;
- struct ospf_iface_patt *ip;
- struct iface *iface;
- struct ifa *a;
-
- WALK_LIST(iface, iface_list)
- {
- if (! (iface->flags & IF_UP))
- continue;
-
- WALK_LIST(a, iface->addrs)
- {
- if (a->flags & IA_SECONDARY)
- continue;
+ struct ospf_proto *p = (struct ospf_proto *) P;
- if (a->scope <= SCOPE_LINK)
- continue;
+ if (a->flags & IA_SECONDARY)
+ return;
- if (ip = ospf_iface_patt_find(oa->ac, a))
- {
- /* Main inner loop */
- struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a);
- if (ifa)
- {
- if (ospf_iface_reconfigure(ifa, ip))
- continue;
+ if (a->scope <= SCOPE_LINK)
+ return;
- /* Hard restart */
- log(L_INFO "%s: Restarting interface %s (%I/%d) in area %R",
- p->name, ifa->ifname, a->prefix, a->pxlen, oa->areaid);
- ospf_iface_shutdown(ifa);
- ospf_iface_remove(ifa);
- }
-
- ospf_iface_new(oa, a, ip);
- }
- }
+ /* In OSPFv2, we create OSPF iface for each address. */
+ if (flags & IF_CHANGE_UP)
+ {
+ struct ospf_mip_walk s = { .iface = a->iface, .a = a };
+ while (ospf_walk_matching_iface_patts(p, &s))
+ ospf_iface_new(s.oa, a, s.ip);
}
-}
-
-#else /* OSPFv3 */
-
-struct ospf_iface_patt *
-ospf_iface_patt_find(struct ospf_area_config *ac, struct iface *iface, int iid)
-{
- struct ospf_iface_patt *pt, *res = NULL;
-
- WALK_LIST(pt, ac->patt_list)
- if ((pt->instance_id >= iid) && (iface_patt_match(&pt->i, iface, NULL)) &&
- (!res || (pt->instance_id < res->instance_id)))
- res = pt;
-
- return res;
+ if (flags & IF_CHANGE_DOWN)
+ {
+ struct ospf_iface *ifa, *ifx;
+ WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
+ if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
+ ospf_iface_remove(ifa);
+ /* See a note in ospf_iface_notify() */
+ }
}
void
-ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
+ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
+ struct ospf_proto *p = (struct ospf_proto *) P;
if (a->flags & IA_SECONDARY)
return;
@@ -1099,71 +1069,79 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
{
if (flags & IF_CHANGE_UP)
{
- int done0 = 0;
- struct ospf_area *oa;
-
- WALK_LIST(oa, po->area_list)
- {
- int iid = 0;
-
- struct ospf_iface_patt *ip;
- while (ip = ospf_iface_patt_find(oa->ac, a->iface, iid))
- {
- ospf_iface_new(oa, a, ip);
- if (ip->instance_id == 0)
- done0++;
- iid = ip->instance_id + 1;
- }
- }
-
- if (done0 > 1)
- log(L_WARN "%s: Interface %s matches for multiple areas",
- p->name, a->iface->name);
+ struct ospf_mip_walk s = { .iface = a->iface };
+ while (ospf_walk_matching_iface_patts(p, &s))
+ ospf_iface_new(s.oa, a, s.ip);
}
if (flags & IF_CHANGE_DOWN)
{
struct ospf_iface *ifa, *ifx;
- WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
- {
- if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
+ WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
+ if ((ifa->addr == a) && (ifa->type != OSPF_IT_VLINK))
ospf_iface_remove(ifa);
- /* See a note in ospf_iface_notify() */
- }
}
}
else
{
struct ospf_iface *ifa;
- WALK_LIST(ifa, po->iface_list)
- {
+ WALK_LIST(ifa, p->iface_list)
if (ifa->iface == a->iface)
{
- schedule_rt_lsa(ifa->oa);
- /* Event 5 from RFC5340 4.4.3. */
- schedule_link_lsa(ifa);
- return;
+ /* RFC 5340 4.4.3 Event 5 - prefix added/deleted */
+ ospf_notify_link_lsa(ifa);
+ ospf_notify_rt_lsa(ifa->oa);
}
- }
}
}
-static struct ospf_iface *
-ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a, int iid)
+
+static void
+ospf_reconfigure_ifaces2(struct ospf_proto *p)
{
- struct ospf_iface *ifa;
- WALK_LIST(ifa, oa->po->iface_list)
- if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->instance_id == iid) && (ifa->type != OSPF_IT_VLINK))
- return ifa;
+ struct iface *iface;
+ struct ifa *a;
- return NULL;
+ WALK_LIST(iface, iface_list)
+ {
+ if (! (iface->flags & IF_UP))
+ continue;
+
+ WALK_LIST(a, iface->addrs)
+ {
+ if (a->flags & IA_SECONDARY)
+ continue;
+
+ if (a->scope <= SCOPE_LINK)
+ continue;
+
+ struct ospf_mip_walk s = { .iface = iface, .a = a };
+ while (ospf_walk_matching_iface_patts(p, &s))
+ {
+ /* Main inner loop */
+ struct ospf_iface *ifa = ospf_iface_find_by_key(p, a, s.ip->instance_id);
+ if (ifa)
+ {
+ if ((ifa->oa == s.oa) && (ifa->marked < 2) &&
+ ospf_iface_reconfigure(ifa, s.ip))
+ continue;
+
+ /* Hard restart */
+ log(L_INFO "%s: Restarting interface %s (%I/%d) in area %R",
+ p->p.name, ifa->ifname, a->prefix, a->pxlen, s.oa->areaid);
+ ospf_iface_shutdown(ifa);
+ ospf_iface_remove(ifa);
+ }
+
+ ospf_iface_new(s.oa, a, s.ip);
+ }
+ }
+ }
}
-void
-ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
+static void
+ospf_reconfigure_ifaces3(struct ospf_proto *p)
{
- struct proto *p = &oa->po->proto;
- struct ospf_iface_patt *ip;
struct iface *iface;
struct ifa *a;
@@ -1180,38 +1158,43 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
if (a->scope != SCOPE_LINK)
continue;
- int iid = 0;
- while (ip = ospf_iface_patt_find(nac, iface, iid))
+ struct ospf_mip_walk s = { .iface = iface };
+ while (ospf_walk_matching_iface_patts(p, &s))
{
- iid = ip->instance_id + 1;
-
/* Main inner loop */
- struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a, ip->instance_id);
+ struct ospf_iface *ifa = ospf_iface_find_by_key(p, a, s.ip->instance_id);
if (ifa)
{
- if (ospf_iface_reconfigure(ifa, ip))
+ if ((ifa->oa == s.oa) && (ifa->marked < 2) &&
+ ospf_iface_reconfigure(ifa, s.ip))
continue;
/* Hard restart */
log(L_INFO "%s: Restarting interface %s (IID %d) in area %R",
- p->name, ifa->ifname, ifa->instance_id, oa->areaid);
+ p->p.name, ifa->ifname, ifa->instance_id, s.oa->areaid);
ospf_iface_shutdown(ifa);
ospf_iface_remove(ifa);
}
- ospf_iface_new(oa, a, ip);
+ ospf_iface_new(s.oa, a, s.ip);
}
}
}
}
-#endif
+void
+ospf_reconfigure_ifaces(struct ospf_proto *p)
+{
+ if (ospf_is_v2(p))
+ ospf_reconfigure_ifaces2(p);
+ else
+ ospf_reconfigure_ifaces3(p);
+}
+
static void
-ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
+ospf_iface_change_mtu(struct ospf_proto *p, struct ospf_iface *ifa)
{
- struct proto *p = &po->proto;
-
/* ifa is not vlink */
OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->ifname);
@@ -1230,7 +1213,7 @@ ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
}
static void
-ospf_iface_notify(struct proto_ospf *po, unsigned flags, struct ospf_iface *ifa)
+ospf_iface_notify(struct ospf_proto *p, uint flags, struct ospf_iface *ifa)
{
/* ifa is not vlink */
@@ -1244,13 +1227,13 @@ ospf_iface_notify(struct proto_ospf *po, unsigned flags, struct ospf_iface *ifa)
ospf_iface_sm(ifa, (ifa->iface->flags & IF_LINK_UP) ? ISM_UNLOOP : ISM_LOOP);
if (flags & IF_CHANGE_MTU)
- ospf_iface_change_mtu(po, ifa);
+ ospf_iface_change_mtu(p, ifa);
}
void
-ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
+ospf_if_notify(struct proto *P, uint flags, struct iface *iface)
{
- struct proto_ospf *po = (struct proto_ospf *) p;
+ struct ospf_proto *p = (struct ospf_proto *) P;
/*
if (iface->flags & IF_IGNORE)
@@ -1262,9 +1245,9 @@ ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
return;
struct ospf_iface *ifa, *ifx;
- WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
+ WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
if (ifa->iface == iface)
- ospf_iface_notify(po, flags, ifa);
+ ospf_iface_notify(p, flags, ifa);
/* We use here that even shutting down iface also shuts down
the vlinks, but vlinks are not freed and stays in the
@@ -1286,20 +1269,19 @@ ospf_iface_info(struct ospf_iface *ifa)
if (ifa->type == OSPF_IT_VLINK)
{
- cli_msg(-1015, "Virtual link %s to %R:", ifa->ifname, ifa->vid);
+ cli_msg(-1015, "Virtual link %s to %R", ifa->ifname, ifa->vid);
cli_msg(-1015, "\tPeer IP: %I", ifa->vip);
cli_msg(-1015, "\tTransit area: %R (%u)", ifa->voa->areaid, ifa->voa->areaid);
}
else
{
-#ifdef OSPFv2
- if (ifa->addr->flags & IA_PEER)
+ if (ospf_is_v3(ifa->oa->po))
+ cli_msg(-1015, "Interface %s (IID %d)", ifa->ifname, ifa->instance_id);
+ else if (ifa->addr->flags & IA_PEER)
cli_msg(-1015, "Interface %s (peer %I)", ifa->ifname, ifa->addr->opposite);
else
cli_msg(-1015, "Interface %s (%I/%d)", ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen);
-#else /* OSPFv3 */
- cli_msg(-1015, "Interface %s (IID %d)", ifa->ifname, ifa->instance_id);
-#endif
+
cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more);
cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid);
}
@@ -1325,4 +1307,3 @@ ospf_iface_info(struct ospf_iface *ifa)
cli_msg(-1015, "\tBackup designed router (IP): %I", ifa->bdrip);
}
}
-