summaryrefslogtreecommitdiff
path: root/proto/ospf
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf')
-rw-r--r--proto/ospf/config.Y11
-rw-r--r--proto/ospf/dbdes.c37
-rw-r--r--proto/ospf/hello.c21
-rw-r--r--proto/ospf/iface.c351
-rw-r--r--proto/ospf/iface.h5
-rw-r--r--proto/ospf/lsack.c6
-rw-r--r--proto/ospf/lsreq.c4
-rw-r--r--proto/ospf/lsupd.c30
-rw-r--r--proto/ospf/neighbor.c23
-rw-r--r--proto/ospf/ospf.c20
-rw-r--r--proto/ospf/ospf.h28
-rw-r--r--proto/ospf/packet.c54
-rw-r--r--proto/ospf/packet.h17
-rw-r--r--proto/ospf/rt.c38
-rw-r--r--proto/ospf/topology.c23
15 files changed, 389 insertions, 279 deletions
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index c47a8cd2..f894f134 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -131,7 +131,8 @@ CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC, TTL, SECURITY)
CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD)
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, REAL, NETMASK, TX, PRIORITY)
+CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
+CF_KEYWORDS(SECONDARY)
%type <t> opttext
%type <ld> lsadb_args
@@ -302,14 +303,16 @@ ospf_iface_item:
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; }
- | RX BUFFER LARGE { OSPF_PATT->rxbuf = OSPF_RXBUF_LARGE ; }
- | RX BUFFER NORMAL { OSPF_PATT->rxbuf = OSPF_RXBUF_NORMAL ; }
- | RX BUFFER expr { OSPF_PATT->rxbuf = $3 ; if (($3 < OSPF_RXBUF_MINSIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
+ | RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; }
+ | RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; }
+ | RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
| TX tos { OSPF_PATT->tx_tos = $2; }
| TX PRIORITY expr { OSPF_PATT->tx_priority = $3; }
+ | TX LENGTH expr { OSPF_PATT->tx_length = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("TX length must be in range 256-65535"); }
| TTL SECURITY bool { OSPF_PATT->ttl_security = $3; }
| TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
| BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); }
+ | SECONDARY bool { OSPF_PATT->bsd_secondary = $2; }
| password_list
;
diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c
index 75ecf24c..6b291344 100644
--- a/proto/ospf/dbdes.c
+++ b/proto/ospf/dbdes.c
@@ -103,7 +103,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
length = sizeof(struct ospf_dbdes_packet);
op->length = htons(length);
- OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
+ OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
ospf_send_to(ifa, n->ip);
break;
@@ -115,7 +115,14 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
snode *sn;
struct ospf_lsa_header *lsa;
- pkt = n->ldbdes;
+ if (n->ldd_bsize != ifa->tx_length)
+ {
+ mb_free(n->ldd_buffer);
+ n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
+ n->ldd_bsize = ifa->tx_length;
+ }
+
+ pkt = n->ldd_buffer;
op = (struct ospf_packet *) pkt;
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
@@ -124,7 +131,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
pkt->options = hton_opt(oa->options);
j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header); /* Number of possible lsaheaders to send */
- lsa = (n->ldbdes + sizeof(struct ospf_dbdes_packet));
+ lsa = (n->ldd_buffer + sizeof(struct ospf_dbdes_packet));
if (n->myimms.bit.m)
{
@@ -175,7 +182,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
case NEIGHBOR_LOADING:
case NEIGHBOR_FULL:
- length = ntohs(((struct ospf_packet *) n->ldbdes)->length);
+ length = n->ldd_buffer ? ntohs(((struct ospf_packet *) n->ldd_buffer)->length) : 0;
if (!length)
{
@@ -184,12 +191,13 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
return;
}
- /* Copy last sent packet again */
- pkt = ospf_tx_buffer(ifa);
- memcpy(pkt, n->ldbdes, length);
+ /* Send last packet from ldd buffer */
- OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
+ OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer, "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
+
+ sk_set_tbuf(ifa->sk, n->ldd_buffer);
ospf_send_to(ifa, n->ip);
+ sk_set_tbuf(ifa->sk, NULL);
if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */
@@ -262,7 +270,7 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
u32 ps_options = ntoh_opt(ps->options);
u16 ps_iface_mtu = ntohs(ps->iface_mtu);
- OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->iface->name);
+ OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->ifname);
ospf_neigh_sm(n, INM_HELLOREC);
@@ -279,10 +287,10 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
return;
case NEIGHBOR_EXSTART:
- if ((ps_iface_mtu != ifa->iface->mtu) && (ifa->type != OSPF_IT_VLINK)
+ if ((ifa->type != OSPF_IT_VLINK) && (ps_iface_mtu != ifa->iface->mtu)
&& (ps_iface_mtu != 0) && (ifa->iface->mtu != 0))
log(L_WARN "OSPF: MTU mismatch with neighbour %I on interface %s (remote %d, local %d)",
- n->ip, ifa->iface->name, ps_iface_mtu, ifa->iface->mtu);
+ n->ip, ifa->ifname, ps_iface_mtu, ifa->iface->mtu);
if ((ps->imms.bit.m && ps->imms.bit.ms && ps->imms.bit.i)
&& (n->rid > po->router_id) && (size == sizeof(struct ospf_dbdes_packet)))
@@ -361,8 +369,8 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
{
if (ps_ddseq != n->dds) /* MASTER */
{
- OSPF_TRACE(D_PACKETS,
- "dbdes - sequence mismatch neighbor %I (master)", n->ip);
+ OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (master)",
+ n->ip);
ospf_neigh_sm(n, INM_SEQMIS);
break;
}
@@ -383,8 +391,7 @@ ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
{
if (ps_ddseq != (n->dds + 1)) /* SLAVE */
{
- OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)",
- n->ip);
+ OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)", n->ip);
ospf_neigh_sm(n, INM_SEQMIS);
break;
}
diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c
index b6b11004..e8bce09f 100644
--- a/proto/ospf/hello.c
+++ b/proto/ospf/hello.c
@@ -61,8 +61,7 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_hello_packet *ps = (void *) ps_i;
- OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s%s", faddr,
- (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name);
+ OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s", faddr, ifa->ifname);
#ifdef OSPFv2
ip_addr mask = ps->netmask;
@@ -120,8 +119,7 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
if (!nn && ifa->strictnbma)
{
- log(L_WARN "Ignoring new neighbor: %I on %s", faddr,
- ifa->iface->name);
+ log(L_WARN "Ignoring new neighbor: %I on %s", faddr, ifa->ifname);
return;
}
@@ -129,8 +127,7 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
(((ps->priority == 0) && nn->eligible) ||
((ps->priority > 0) && !nn->eligible)))
{
- log(L_ERR "Eligibility mismatch for neighbor: %I on %s",
- faddr, ifa->iface->name);
+ log(L_ERR "Eligibility mismatch for neighbor: %I on %s", faddr, ifa->ifname);
return;
}
@@ -138,8 +135,7 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
nn->found = 1;
}
- OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr,
- ifa->iface->name);
+ OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr, ifa->ifname);
n = ospf_neighbor_new(ifa);
@@ -263,7 +259,7 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
p = (struct proto *) (ifa->oa->po);
DBG("%s: Hello/Poll timer fired on interface %s with IP %I\n",
- p->name, ifa->iface->name, ifa->addr->ip);
+ p->name, ifa->ifname, ifa->addr->ip);
/* Now we should send a hello packet */
pkt = ospf_tx_buffer(ifa);
@@ -309,9 +305,9 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
u32 *pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
WALK_LIST(neigh, ifa->neigh_list)
{
- if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa))
+ if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_maxsize(ifa))
{
- log(L_WARN "%s: Too many neighbors on interface %s", p->name, ifa->iface->name);
+ log(L_WARN "%s: Too many neighbors on interface %s", p->name, ifa->ifname);
break;
}
*(pp + i) = htonl(neigh->rid);
@@ -376,6 +372,5 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
bug("Bug in ospf_hello_send()");
}
- OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s%s",
- (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name);
+ OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s", ifa->ifname);
}
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index 333c2a6d..f4d9be55 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -36,29 +36,46 @@ wait_timer_hook(timer * timer)
struct ospf_iface *ifa = (struct ospf_iface *) timer->data;
struct proto *p = &ifa->oa->po->proto;
- OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->iface->name);
+ OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->ifname);
ospf_iface_sm(ifa, ISM_WAITF);
}
-static void ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa);
+static inline uint
+ifa_tx_length(struct ospf_iface *ifa)
+{
+ return ifa->cf->tx_length ?: ifa->iface->mtu;
+}
-u32
-rxbufsize(struct ospf_iface *ifa)
+static inline uint
+ifa_bufsize(struct ospf_iface *ifa)
{
- switch(ifa->rxbuf)
- {
- case OSPF_RXBUF_NORMAL:
- return (ifa->iface->mtu * 2);
- break;
- case OSPF_RXBUF_LARGE:
- return OSPF_MAX_PKT_SIZE;
- break;
- default:
- return ifa->rxbuf;
- break;
- }
+ uint bsize = ifa->cf->rx_buffer ?: ifa->iface->mtu;
+ return MAX(bsize, ifa->tx_length);
}
+int
+ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen)
+{
+ plen += SIZE_OF_IP_HEADER;
+
+#ifdef OSPFv2
+ if (ifa->autype == OSPF_AUTH_CRYPT)
+ plen += OSPF_AUTH_CRYPT_SIZE;
+#endif
+
+ if (plen <= ifa->sk->tbsize)
+ return 0;
+
+ if (ifa->cf->rx_buffer || (plen > 0xffff))
+ return -1;
+
+ plen = BIRD_ALIGN(plen, 1024);
+ plen = MIN(plen, 0xffff);
+ sk_set_tbsize(ifa->sk, plen);
+ return 1;
+}
+
+
struct nbma_node *
find_nbma_node_in(list *nnl, ip_addr ip)
{
@@ -69,27 +86,27 @@ find_nbma_node_in(list *nnl, ip_addr ip)
return NULL;
}
+
static int
ospf_sk_open(struct ospf_iface *ifa)
{
sock *sk = sk_new(ifa->pool);
sk->type = SK_IP;
sk->dport = OSPF_PROTO;
- sk->saddr = IPA_NONE;
+ sk->saddr = ifa->addr->ip;
+ sk->iface = ifa->iface;
sk->tos = ifa->cf->tx_tos;
sk->priority = ifa->cf->tx_priority;
sk->rx_hook = ospf_rx_hook;
- sk->tx_hook = ospf_tx_hook;
+ // sk->tx_hook = ospf_tx_hook;
sk->err_hook = ospf_err_hook;
- sk->iface = ifa->iface;
- sk->rbsize = rxbufsize(ifa);
- sk->tbsize = rxbufsize(ifa);
+ sk->rbsize = sk->tbsize = ifa_bufsize(ifa);
sk->data = (void *) ifa;
sk->flags = SKF_LADDR_RX | (ifa->check_ttl ? SKF_TTL_RX : 0);
- sk->ttl = ifa->cf->ttl_security ? 255 : -1;
+ sk->ttl = ifa->cf->ttl_security ? 255 : 1;
- if (sk_open(sk) != 0)
+ if (sk_open(sk) < 0)
goto err;
#ifdef OSPFv3
@@ -98,28 +115,6 @@ ospf_sk_open(struct ospf_iface *ifa)
goto err;
#endif
- /*
- * For OSPFv2: When sending a packet, it is important to have a
- * proper source address. We expect that when we send one-hop
- * unicast packets, OS chooses a source address according to the
- * destination address (to be in the same prefix). We also expect
- * that when we send multicast packets, OS uses the source address
- * from sk->saddr registered to OS by sk_setup_multicast(). This
- * behavior is needed to implement multiple virtual ifaces (struct
- * ospf_iface) on one physical iface and is signalized by
- * CONFIG_MC_PROPER_SRC.
- *
- * If this behavior is not available (for example on BSD), we create
- * non-stub iface just for the primary IP address (see
- * ospf_iface_stubby()) and we expect OS to use primary IP address
- * as a source address for both unicast and multicast packets.
- *
- * FIXME: the primary IP address is currently just the
- * lexicographically smallest address on an interface, it should be
- * signalized by sysdep code which one is really the primary.
- */
-
- sk->saddr = ifa->addr->ip;
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP))
{
if (ifa->cf->real_bcast)
@@ -132,7 +127,6 @@ ospf_sk_open(struct ospf_iface *ifa)
else
{
ifa->all_routers = AllSPFRouters;
- sk->ttl = ifa->cf->ttl_security ? 255 : 1;
if (sk_setup_multicast(sk) < 0)
goto err;
@@ -171,6 +165,42 @@ ospf_sk_leave_dr(struct ospf_iface *ifa)
ifa->sk_dr = 0;
}
+void
+ospf_open_vlink_sk(struct proto_ospf *po)
+{
+ struct proto *p = &po->proto;
+
+ sock *sk = sk_new(po->proto.pool);
+ sk->type = SK_IP;
+ sk->dport = OSPF_PROTO;
+
+ /* FIXME: configurable tos/priority ? */
+ sk->tos = IP_PREC_INTERNET_CONTROL;
+ sk->priority = sk_priority_control;
+ sk->err_hook = ospf_verr_hook;
+
+ sk->rbsize = 0;
+ sk->tbsize = OSPF_VLINK_MTU;
+ sk->data = (void *) po;
+ 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
+
+ po->vlink_sk = sk;
+ return;
+
+ err:
+ rfree(sk);
+ log(L_ERR "%s: Cannot open virtual link socket", p->name);
+}
+
static void
ospf_iface_down(struct ospf_iface *ifa)
{
@@ -183,10 +213,10 @@ ospf_iface_down(struct ospf_iface *ifa)
{
#ifdef OSPFv2
OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
- ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
+ 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->iface->name, ifa->instance_id, ifa->oa->areaid);
+ ifa->ifname, ifa->instance_id, ifa->oa->areaid);
#endif
/* First of all kill all the related vlinks */
@@ -215,9 +245,7 @@ ospf_iface_down(struct ospf_iface *ifa)
if (ifa->type == OSPF_IT_VLINK)
{
ifa->vifa = NULL;
- ifa->iface = NULL;
ifa->addr = NULL;
- ifa->sk = NULL;
ifa->cost = 0;
ifa->vip = IPA_NONE;
}
@@ -276,7 +304,7 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
ifa->vid, ospf_is[oldstate], ospf_is[state]);
else
OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
- ifa->iface->name, ospf_is[oldstate], ospf_is[state]);
+ ifa->ifname, ospf_is[oldstate], ospf_is[state]);
if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk)
{
@@ -318,8 +346,7 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
void
ospf_iface_sm(struct ospf_iface *ifa, int event)
{
- DBG("SM on %s %s. Event is '%s'\n", (ifa->type == OSPF_IT_VLINK) ? "vlink" : "iface",
- ifa->iface ? ifa->iface->name : "(none)" , ospf_ism[event]);
+ DBG("SM on iface %s. Event is '%s'\n", ifa->ifname, ospf_ism[event]);
switch (event)
{
@@ -436,7 +463,7 @@ ospf_iface_add(struct object_lock *lock)
/* Open socket if interface is not stub */
if (! ifa->stub && ! ospf_sk_open(ifa))
{
- log(L_ERR "%s: Socket open failed on interface %s, declaring as stub", p->name, ifa->iface->name);
+ log(L_ERR "%s: Socket open failed on interface %s, declaring as stub", p->name, ifa->ifname);
ifa->ioprob = OSPF_I_SK;
ifa->stub = 1;
}
@@ -469,9 +496,6 @@ add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found)
static int
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
{
- if (! addr)
- return 0;
-
/* a host address */
if (addr->flags & IA_HOST)
return 1;
@@ -481,12 +505,11 @@ ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
return 1;
/*
- * We cannot properly support multiple OSPF ifaces on real iface
- * with multiple prefixes, therefore we force OSPF ifaces with
- * non-primary IP prefixes to be stub.
+ * For compatibility reasons on BSD systems, we force OSPF
+ * interfaces with non-primary IP prefixes to be stub.
*/
#if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC)
- if (! (addr->flags & IA_PRIMARY))
+ if (!ip->bsd_secondary && !(addr->flags & IA_PRIMARY))
return 1;
#endif
@@ -497,25 +520,17 @@ void
ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
{
struct proto *p = &oa->po->proto;
- struct iface *iface = addr ? addr->iface : NULL;
- struct pool *pool;
-
+ struct iface *iface = addr->iface;
struct ospf_iface *ifa;
- struct nbma_node *nb;
- struct object_lock *lock;
+ struct pool *pool;
- if (ip->type == OSPF_IT_VLINK)
- OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);
- else
- {
#ifdef OSPFv2
- OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
- iface->name, addr->prefix, addr->pxlen, oa->areaid);
+ 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);
+ OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
+ iface->name, ip->instance_id, oa->areaid);
#endif
- }
pool = rp_new(p->pool, "OSPF Interface");
ifa = mb_allocz(pool, sizeof(struct ospf_iface));
@@ -525,6 +540,9 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->cf = ip;
ifa->pool = pool;
+ ifa->iface_id = iface->index;
+ ifa->ifname = iface->name;
+
ifa->cost = ip->cost;
ifa->rxmtint = ip->rxmtint;
ifa->inftransdelay = ip->inftransdelay;
@@ -536,7 +554,8 @@ 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->rxbuf = ip->rxbuf;
+
+ 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);
@@ -545,7 +564,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
#ifdef OSPFv2
ifa->autype = ip->autype;
ifa->passwords = ip->passwords;
- ifa->ptp_netmask = addr ? !(addr->flags & IA_PEER) : 0;
+ ifa->ptp_netmask = !(addr->flags & IA_PEER);
if (ip->ptp_netmask < 2)
ifa->ptp_netmask = ip->ptp_netmask;
#endif
@@ -554,6 +573,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->instance_id = ip->instance_id;
#endif
+
ifa->type = ospf_iface_classify(ip->type, addr);
/* Check validity of interface type */
@@ -578,12 +598,12 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
log(L_WARN "%s: Cannot use interface %s as %s, forcing %s",
p->name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);
- /* Assign iface ID, for vlinks, this is ugly hack */
- ifa->iface_id = (ifa->type != OSPF_IT_VLINK) ? iface->index : oa->po->last_vlink_id++;
+ ifa->state = OSPF_IS_DOWN;
init_list(&ifa->neigh_list);
init_list(&ifa->nbma_list);
+ struct nbma_node *nb;
WALK_LIST(nb, ip->nbma_list)
{
/* In OSPFv3, addr is link-local while configured neighbors could
@@ -602,19 +622,8 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
add_nbma_node(ifa, nb, 0);
}
- ifa->state = OSPF_IS_DOWN;
add_tail(&oa->po->iface_list, NODE ifa);
- if (ifa->type == OSPF_IT_VLINK)
- {
- ifa->voa = ospf_find_area(oa->po, ip->voa);
- ifa->vid = ip->vid;
-
- ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
-
- return; /* Don't lock, don't add sockets */
- }
-
/*
* In some cases we allow more ospf_ifaces on one physical iface.
* In OSPFv2, if they use different IP address prefix.
@@ -622,7 +631,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
* Therefore, we store such info to lock->addr field.
*/
- lock = olock_new(pool);
+ struct object_lock *lock = olock_new(pool);
#ifdef OSPFv2
lock->addr = ifa->addr->prefix;
#else /* OSPFv3 */
@@ -637,6 +646,63 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
olock_acquire(lock);
}
+void
+ospf_iface_new_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip)
+{
+ struct proto *p = &po->proto;
+ struct ospf_iface *ifa;
+ struct pool *pool;
+
+ if (!po->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");
+ ifa = mb_allocz(pool, sizeof(struct ospf_iface) + 16);
+ ifa->oa = po->backbone;
+ ifa->cf = ip;
+ ifa->pool = pool;
+
+ /* Assign iface ID, for vlinks, this is ugly hack */
+ u32 vlink_id = po->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->vid = ip->vid;
+ ifa->sk = po->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->autype = ip->autype;
+ ifa->passwords = ip->passwords;
+#endif
+
+#ifdef OSPFv3
+ ifa->instance_id = ip->instance_id;
+#endif
+
+ ifa->type = OSPF_IT_VLINK;
+
+ ifa->state = OSPF_IS_DOWN;
+ init_list(&ifa->neigh_list);
+ init_list(&ifa->nbma_list);
+
+ add_tail(&po->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)
{
@@ -653,12 +719,12 @@ int
ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
{
struct proto *p = &ifa->oa->po->proto;
- struct nbma_node *nb, *nbx;
- char *ifname = (ifa->type != OSPF_IT_VLINK) ? ifa->iface->name : "vlink";
+ struct ospf_iface_patt *old = ifa->cf;
+ char *ifname = ifa->ifname;
/* Type could be changed in ospf_iface_new(),
but if config values are same then also results are same */
- int old_type = ospf_iface_classify(ifa->cf->type, ifa->addr);
+ int old_type = ospf_iface_classify(old->type, ifa->addr);
int new_type = ospf_iface_classify(new->type, ifa->addr);
if (old_type != new_type)
return 0;
@@ -668,10 +734,10 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
return 0;
/* Change of these options would require to reset the iface socket */
- if ((new->real_bcast != ifa->cf->real_bcast) ||
- (new->tx_tos != ifa->cf->tx_tos) ||
- (new->tx_priority != ifa->cf->tx_priority) ||
- (new->ttl_security != ifa->cf->ttl_security))
+ if ((new->real_bcast != old->real_bcast) ||
+ (new->tx_tos != old->tx_tos) ||
+ (new->tx_priority != old->tx_priority) ||
+ (new->ttl_security != old->ttl_security))
return 0;
ifa->cf = new;
@@ -775,6 +841,8 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
ifa->strictnbma = new->strictnbma;
}
+ struct nbma_node *nb, *nbx;
+
/* NBMA LIST - remove or update old */
WALK_LIST_DELSAFE(nb, nbx, ifa->nbma_list)
{
@@ -817,13 +885,35 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
}
}
- /* RX BUFF */
- if (ifa->rxbuf != new->rxbuf)
+ int update_buffers = 0;
+
+ /* TX LENGTH */
+ if (old->tx_length != new->tx_length)
+ {
+ OSPF_TRACE(D_EVENTS, "Changing TX length on interface %s from %d to %d",
+ ifname, old->tx_length, new->tx_length);
+
+ /* ifa cannot be vlink */
+ ifa->tx_length = ifa_tx_length(ifa);
+ update_buffers = 1;
+ }
+
+ /* RX BUFFER */
+ if (old->rx_buffer != new->rx_buffer)
+ {
+ OSPF_TRACE(D_EVENTS, "Changing buffer size on interface %s from %d to %d",
+ ifname, old->rx_buffer, new->rx_buffer);
+
+ /* ifa cannot be vlink */
+ update_buffers = 1;
+ }
+
+ /* Buffer size depends on both tx_length and rx_buffer options */
+ if (update_buffers && ifa->sk)
{
- OSPF_TRACE(D_EVENTS, "Changing rxbuf interface %s from %d to %d",
- ifname, ifa->rxbuf, new->rxbuf);
- ifa->rxbuf = new->rxbuf;
- ospf_iface_change_mtu(ifa->oa->po, ifa);
+ uint bsize = ifa_bufsize(ifa);
+ sk_set_rbsize(ifa->sk, bsize);
+ sk_set_tbsize(ifa->sk, bsize);
}
/* LINK */
@@ -833,6 +923,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
new->check_link ? "Enabling" : "Disabling", ifname);
ifa->check_link = new->check_link;
+ /* ifa cannot be vlink */
if (!(ifa->iface->flags & IF_LINK_UP))
ospf_iface_sm(ifa, ifa->check_link ? ISM_LOOP : ISM_UNLOOP);
}
@@ -929,6 +1020,7 @@ ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a)
void
ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
{
+ struct proto *p = &oa->po->proto;
struct ospf_iface_patt *ip;
struct iface *iface;
struct ifa *a;
@@ -956,6 +1048,8 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
continue;
/* 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);
}
@@ -1062,6 +1156,7 @@ ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a, int iid)
void
ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
{
+ struct proto *p = &oa->po->proto;
struct ospf_iface_patt *ip;
struct iface *iface;
struct ifa *a;
@@ -1092,6 +1187,8 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
continue;
/* Hard restart */
+ log(L_INFO "%s: Restarting interface %s (IID %d) in area %R",
+ p->name, ifa->ifname, ifa->instance_id, oa->areaid);
ospf_iface_shutdown(ifa);
ospf_iface_remove(ifa);
}
@@ -1108,32 +1205,29 @@ static void
ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
{
struct proto *p = &po->proto;
- struct ospf_packet *op;
- struct ospf_neighbor *n;
- OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->iface->name);
- if (ifa->sk)
- {
- ifa->sk->rbsize = rxbufsize(ifa);
- ifa->sk->tbsize = rxbufsize(ifa);
- sk_reallocate(ifa->sk);
- }
+ /* ifa is not vlink */
- WALK_LIST(n, ifa->neigh_list)
- {
- op = (struct ospf_packet *) n->ldbdes;
- n->ldbdes = mb_allocz(n->pool, ifa->iface->mtu);
+ OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->ifname);
- if (ntohs(op->length) <= ifa->iface->mtu) /* If the packet in old buffer is bigger, let it filled by zeros */
- memcpy(n->ldbdes, op, ifa->iface->mtu); /* If the packet is old is same or smaller, copy it */
+ ifa->tx_length = ifa_tx_length(ifa);
- mb_free(op);
- }
+ if (!ifa->sk)
+ return;
+
+ /* We do not shrink dynamic buffers */
+ uint bsize = ifa_bufsize(ifa);
+ if (bsize > ifa->sk->rbsize)
+ sk_set_rbsize(ifa->sk, bsize);
+ if (bsize > ifa->sk->tbsize)
+ sk_set_tbsize(ifa->sk, bsize);
}
static void
ospf_iface_notify(struct proto_ospf *po, unsigned flags, struct ospf_iface *ifa)
{
+ /* ifa is not vlink */
+
if (flags & IF_CHANGE_DOWN)
{
ospf_iface_remove(ifa);
@@ -1163,7 +1257,7 @@ ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
struct ospf_iface *ifa, *ifx;
WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
- if ((ifa->type != OSPF_IT_VLINK) && (ifa->iface == iface))
+ if (ifa->iface == iface)
ospf_iface_notify(po, flags, ifa);
/* We use here that even shutting down iface also shuts down
@@ -1186,22 +1280,19 @@ ospf_iface_info(struct ospf_iface *ifa)
if (ifa->type == OSPF_IT_VLINK)
{
- cli_msg(-1015, "Virtual link to %R:", 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);
- cli_msg(-1015, "\tInterface: \"%s\"",
- (ifa->iface ? ifa->iface->name : "(none)"));
+ cli_msg(-1015, "\tTransit area: %R (%u)", ifa->voa->areaid, ifa->voa->areaid);
}
else
{
#ifdef OSPFv2
if (ifa->addr->flags & IA_PEER)
- cli_msg(-1015, "Interface %s (peer %I)", ifa->iface->name, ifa->addr->opposite);
+ cli_msg(-1015, "Interface %s (peer %I)", ifa->ifname, ifa->addr->opposite);
else
- cli_msg(-1015, "Interface %s (%I/%d)", ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen);
+ 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->iface->name, ifa->instance_id);
+ 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);
diff --git a/proto/ospf/iface.h b/proto/ospf/iface.h
index 3f887728..5a250e0a 100644
--- a/proto/ospf/iface.h
+++ b/proto/ospf/iface.h
@@ -17,11 +17,16 @@ void ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface);
void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a);
void ospf_iface_info(struct ospf_iface *ifa);
void ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip);
+void ospf_iface_new_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip);
void ospf_iface_remove(struct ospf_iface *ifa);
void ospf_iface_shutdown(struct ospf_iface *ifa);
int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new);
void ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac);
+int ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen);
+
+void ospf_open_vlink_sk(struct proto_ospf *po);
+
struct nbma_node *find_nbma_node_in(list *nnl, ip_addr ip);
static inline struct nbma_node *
diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c
index 00c50caf..fd8ead01 100644
--- a/proto/ospf/lsack.c
+++ b/proto/ospf/lsack.c
@@ -92,7 +92,7 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue)
op->length = htons(len);
DBG("Sending and continuing! Len=%u\n", len);
- OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->iface->name);
+ OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname);
if (ifa->type == OSPF_IT_BCAST)
{
@@ -121,7 +121,7 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue)
op->length = htons(len);
DBG("Sending! Len=%u\n", len);
- OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->iface->name);
+ OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname);
if (ifa->type == OSPF_IT_BCAST)
{
@@ -153,7 +153,7 @@ ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
}
struct ospf_lsack_packet *ps = (void *) ps_i;
- OSPF_PACKET(ospf_dump_lsack, ps, "LSACK packet received from %I via %s", n->ip, ifa->iface->name);
+ OSPF_PACKET(ospf_dump_lsack, ps, "LSACK packet received from %I via %s", n->ip, ifa->ifname);
ospf_neigh_sm(n, INM_HELLOREC);
diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c
index 1ba4fff9..15854ce7 100644
--- a/proto/ospf/lsreq.c
+++ b/proto/ospf/lsreq.c
@@ -82,7 +82,7 @@ ospf_lsreq_send(struct ospf_neighbor *n)
i) * sizeof(struct ospf_lsreq_header);
op->length = htons(length);
- OSPF_PACKET(ospf_dump_lsreq, pk, "LSREQ packet sent to %I via %s", n->ip, n->ifa->iface->name);
+ OSPF_PACKET(ospf_dump_lsreq, pk, "LSREQ packet sent to %I via %s", n->ip, n->ifa->ifname);
ospf_send_to(n->ifa, n->ip);
}
@@ -107,7 +107,7 @@ ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
}
struct ospf_lsreq_packet *ps = (void *) ps_i;
- OSPF_PACKET(ospf_dump_lsreq, ps, "LSREQ packet received from %I via %s", n->ip, ifa->iface->name);
+ OSPF_PACKET(ospf_dump_lsreq, ps, "LSREQ packet received from %I via %s", n->ip, ifa->ifname);
if (n->state < NEIGHBOR_EXCHANGE)
return;
diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c
index beac6c83..1859867b 100644
--- a/proto/ospf/lsupd.c
+++ b/proto/ospf/lsupd.c
@@ -278,22 +278,22 @@ ospf_lsupd_flood(struct proto_ospf *po,
struct ospf_packet *op;
struct ospf_lsa_header *lh;
- pk = ospf_tx_buffer(ifa);
- op = &pk->ospf_packet;
-
- ospf_pkt_fill_hdr(ifa, pk, LSUPD_P);
- pk->lsano = htonl(1);
-
/* Check iface buffer size */
- int len2 = sizeof(struct ospf_lsupd_packet) + (hn ? ntohs(hn->length) : hh->length);
- if (len2 > ospf_pkt_bufsize(ifa))
+ uint len2 = sizeof(struct ospf_lsupd_packet) + (hn ? ntohs(hn->length) : hh->length);
+ if (ospf_iface_assure_bufsize(ifa, len2) < 0)
{
/* Cannot fit in a tx buffer, skip that iface */
log(L_ERR "OSPF: LSA too large to flood on %s (Type: %04x, Id: %R, Rt: %R)",
- ifa->iface->name, hh->type, hh->id, hh->rt);
+ ifa->ifname, hh->type, hh->id, hh->rt);
continue;
}
+ pk = ospf_tx_buffer(ifa);
+ op = &pk->ospf_packet;
+
+ ospf_pkt_fill_hdr(ifa, pk, LSUPD_P);
+ pk->lsano = htonl(1);
+
lh = (struct ospf_lsa_header *) (pk + 1);
/* Copy LSA into the packet */
@@ -322,7 +322,7 @@ ospf_lsupd_flood(struct proto_ospf *po,
op->length = htons(len);
- OSPF_PACKET(ospf_dump_lsupd, pk, "LSUPD packet flooded via %s", ifa->iface->name);
+ OSPF_PACKET(ospf_dump_lsupd, pk, "LSUPD packet flooded via %s", ifa->ifname);
switch (ifa->type)
{
@@ -406,7 +406,7 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
break;
/* LSA is larger than MTU, check buffer size */
- if (len2 > ospf_pkt_bufsize(n->ifa))
+ if (ospf_iface_assure_bufsize(n->ifa, len2) < 0)
{
/* Cannot fit in a tx buffer, skip that */
log(L_ERR "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)",
@@ -414,6 +414,10 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
lsr = NODE_NEXT(lsr);
continue;
}
+
+ /* TX buffer could be reallocated */
+ pkt = ospf_tx_buffer(n->ifa);
+ buf = (void *) pkt;
}
/* Copy the LSA to the packet */
@@ -432,7 +436,7 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
pkt->lsano = htonl(lsano);
pkt->ospf_packet.length = htons(len);
OSPF_PACKET(ospf_dump_lsupd, pkt, "LSUPD packet sent to %I via %s",
- n->ip, n->ifa->iface->name);
+ n->ip, n->ifa->ifname);
ospf_send_to(n->ifa, n->ip);
}
}
@@ -455,7 +459,7 @@ ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
}
struct ospf_lsupd_packet *ps = (void *) ps_i;
- OSPF_PACKET(ospf_dump_lsupd, ps, "LSUPD packet received from %I via %s", n->ip, ifa->iface->name);
+ OSPF_PACKET(ospf_dump_lsupd, ps, "LSUPD packet received from %I via %s", n->ip, ifa->ifname);
if (n->state < NEIGHBOR_EXCHANGE)
{
diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c
index 61224ec2..faaaf232 100644
--- a/proto/ospf/neighbor.c
+++ b/proto/ospf/neighbor.c
@@ -69,7 +69,6 @@ ospf_neighbor_new(struct ospf_iface *ifa)
add_tail(&ifa->neigh_list, NODE n);
n->adj = 0;
n->csn = 0;
- n->ldbdes = mb_allocz(pool, ifa->iface->mtu);
n->state = NEIGHBOR_DOWN;
init_lists(n);
@@ -286,10 +285,10 @@ can_do_adj(struct ospf_neighbor *n)
{
case OSPF_IS_DOWN:
case OSPF_IS_LOOP:
- bug("%s: Iface %s in down state?", p->name, ifa->iface->name);
+ bug("%s: Iface %s in down state?", p->name, ifa->ifname);
break;
case OSPF_IS_WAITING:
- DBG("%s: Neighbor? on iface %s\n", p->name, ifa->iface->name);
+ DBG("%s: Neighbor? on iface %s\n", p->name, ifa->ifname);
break;
case OSPF_IS_DROTHER:
if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid))
@@ -303,15 +302,15 @@ can_do_adj(struct ospf_neighbor *n)
i = 1;
break;
default:
- bug("%s: Iface %s in unknown state?", p->name, ifa->iface->name);
+ bug("%s: Iface %s in unknown state?", p->name, ifa->ifname);
break;
}
break;
default:
- bug("%s: Iface %s is unknown type?", p->name, ifa->iface->name);
+ bug("%s: Iface %s is unknown type?", p->name, ifa->ifname);
break;
}
- DBG("%s: Iface %s can_do_adj=%d\n", p->name, ifa->iface->name, i);
+ DBG("%s: Iface %s can_do_adj=%d\n", p->name, ifa->ifname, i);
return i;
}
@@ -556,9 +555,8 @@ neighbor_timer_hook(timer * timer)
struct ospf_iface *ifa = n->ifa;
struct proto *p = &ifa->oa->po->proto;
- OSPF_TRACE(D_EVENTS,
- "Inactivity timer fired on interface %s for neighbor %I.",
- ifa->iface->name, n->ip);
+ OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I.",
+ ifa->ifname, n->ip);
ospf_neigh_remove(n);
}
@@ -591,7 +589,7 @@ ospf_neigh_bfd_hook(struct bfd_request *req)
if (req->down)
{
OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s",
- n->ip, n->ifa->iface->name);
+ n->ip, n->ifa->ifname);
ospf_neigh_remove(n);
}
@@ -641,8 +639,7 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
pos = "ptp ";
cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority,
- ospf_ns[n->state], pos, etime,
- (ifa->type == OSPF_IT_VLINK ? "vlink" : ifa->iface->name), n->ip);
+ ospf_ns[n->state], pos, etime, ifa->ifname, n->ip);
}
static void
@@ -653,7 +650,7 @@ rxmt_timer_hook(timer * timer)
struct top_hash_entry *en;
DBG("%s: RXMT timer fired on interface %s for neigh: %I.\n",
- p->name, n->ifa->iface->name, n->ip);
+ p->name, n->ifa->ifname, n->ip);
if(n->state < NEIGHBOR_EXSTART) return;
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 232f3f6c..cf520401 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -232,7 +232,6 @@ ospf_start(struct proto *p)
struct ospf_area_config *ac;
po->router_id = proto_get_router_id(p->cf);
- po->last_vlink_id = 0x80000000;
po->rfc1583 = c->rfc1583;
po->stub_router = c->stub_router;
po->ebit = 0;
@@ -258,10 +257,13 @@ ospf_start(struct proto *p)
WALK_LIST(ac, c->area_list)
ospf_area_add(po, ac, 0);
+ if (c->abr)
+ ospf_open_vlink_sk(po);
+
/* Add all virtual links */
struct ospf_iface_patt *ic;
WALK_LIST(ic, c->vlink_list)
- ospf_iface_new(po->backbone, NULL, ic);
+ ospf_iface_new_vlink(po, ic);
return PS_UP;
}
@@ -277,7 +279,7 @@ ospf_dump(struct proto *p)
WALK_LIST(ifa, po->iface_list)
{
- OSPF_TRACE(D_EVENTS, "Interface: %s", (ifa->iface ? ifa->iface->name : "(null)"));
+ OSPF_TRACE(D_EVENTS, "Interface: %s", ifa->ifname);
OSPF_TRACE(D_EVENTS, "state: %u", ifa->state);
OSPF_TRACE(D_EVENTS, "DR: %R", ifa->drid);
OSPF_TRACE(D_EVENTS, "BDR: %R", ifa->bdrid);
@@ -381,7 +383,7 @@ schedule_net_lsa(struct ospf_iface *ifa)
{
struct proto *p = &ifa->oa->po->proto;
- OSPF_TRACE(D_EVENTS, "Scheduling network-LSA origination for iface %s", ifa->iface->name);
+ OSPF_TRACE(D_EVENTS, "Scheduling network-LSA origination for iface %s", ifa->ifname);
ifa->orignet = 1;
}
@@ -391,7 +393,7 @@ schedule_link_lsa(struct ospf_iface *ifa)
{
struct proto *p = &ifa->oa->po->proto;
- OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->iface->name);
+ OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->ifname);
ifa->origlink = 1;
}
#endif
@@ -631,7 +633,7 @@ ospf_get_route_info(rte * rte, byte * buf, ea_list * attrs UNUSED)
{
char *type = "<bug>";
- switch(rte->attrs->source)
+ switch (rte->attrs->source)
{
case RTS_OSPF:
type = "I";
@@ -769,7 +771,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
if (ifa)
ospf_iface_reconfigure(ifa, ip);
else
- ospf_iface_new(po->backbone, NULL, ip);
+ ospf_iface_new_vlink(po, ip);
}
/* Delete remaining ifaces and areas */
@@ -808,7 +810,7 @@ ospf_sh_neigh(struct proto *p, char *iff)
cli_msg(-1013, "%-12s\t%3s\t%-15s\t%-5s\t%-10s %-12s", "Router ID", "Pri",
" State", "DTime", "Interface", "Router IP");
WALK_LIST(ifa, po->iface_list)
- if ((iff == NULL) || patmatch(iff, ifa->iface->name))
+ if ((iff == NULL) || patmatch(iff, ifa->ifname))
WALK_LIST(n, ifa->neigh_list)
ospf_sh_neigh_info(n);
cli_msg(0, "");
@@ -917,7 +919,7 @@ ospf_sh_iface(struct proto *p, char *iff)
cli_msg(-1015, "%s:", p->name);
WALK_LIST(ifa, po->iface_list)
- if ((iff == NULL) || patmatch(iff, ifa->iface->name))
+ if ((iff == NULL) || patmatch(iff, ifa->ifname))
ospf_iface_info(ifa);
cli_msg(0, "");
}
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 46a1c3c1..66719e30 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -10,14 +10,8 @@
#define _BIRD_OSPF_H_
#define MAXNETS 10
+#define OSPF_MIN_PKT_SIZE 256
#define OSPF_MAX_PKT_SIZE 65535
-/*
- * RFC 2328 says, maximum packet size is 65535 (IP packet size
- * limit). Really a bit less for OSPF, because this contains also IP
- * header. This could be too much for small systems, so I normally
- * allocate 2*mtu (i found one cisco sending packets mtu+16). OSPF
- * packets are almost always sent small enough to not be fragmented.
- */
#ifdef LOCAL_DEBUG
#define OSPF_FORCE_DEBUG 1
@@ -78,6 +72,8 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
#define DEFAULT_ECMP_LIMIT 16
#define DEFAULT_TRANSINT 40
+#define OSPF_VLINK_ID_OFFSET 0x80000000
+
struct ospf_config
{
@@ -179,12 +175,14 @@ struct ospf_area_config
struct ospf_iface
{
node n;
- struct iface *iface; /* Nest's iface, non-NULL (unless type OSPF_IT_VLINK) */
+ struct iface *iface; /* Nest's iface (NULL for vlinks) */
struct ifa *addr; /* IP prefix associated with that OSPF iface */
struct ospf_area *oa;
struct ospf_iface_patt *cf;
+ char *ifname; /* Interface name (iface->name), new one for vlinks */
+
pool *pool;
- sock *sk; /* IP socket (for DD ...) */
+ sock *sk; /* IP socket */
list neigh_list; /* List of neigbours */
u32 cost; /* Cost of iface */
u32 waitint; /* number of sec before changing state from wait */
@@ -273,6 +271,7 @@ struct ospf_iface
u8 sk_dr; /* Socket is a member of DRouters group */
u8 marked; /* Used in OSPF reconfigure */
u16 rxbuf; /* Buffer size */
+ u16 tx_length; /* Soft TX packet length limit, usually MTU */
u8 check_link; /* Whether iface link change is used */
u8 ecmp_weight; /* Weight used for ECMP */
u8 ptp_netmask; /* Send real netmask for P2P */
@@ -704,13 +703,14 @@ struct ospf_neighbor
slist lsrtl; /* Link state retransmission list */
siterator lsrti;
struct top_graph *lsrth;
- void *ldbdes; /* Last database description packet */
timer *rxmt_timer; /* RXMT timer */
list ackl[2];
#define ACKL_DIRECT 0
#define ACKL_DELAY 1
timer *ackd_timer; /* Delayed ack timer */
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
+ void *ldd_buffer; /* Last database description packet */
+ u32 ldd_bsize; /* Buffer size for ldd_buffer */
u32 csn; /* Last received crypt seq number (for MD5) */
};
@@ -783,6 +783,7 @@ struct proto_ospf
void *lsab; /* LSA buffer used when originating router LSAs */
int lsab_size, lsab_used;
linpool *nhpool; /* Linpool used for next hops computed in SPF */
+ sock *vlink_sk; /* IP socket used for vlink TX */
u32 router_id;
u32 last_vlink_id; /* Interface IDs for vlinks (starts at 0x80000000) */
};
@@ -806,9 +807,9 @@ struct ospf_iface_patt
u32 vid;
int tx_tos;
int tx_priority;
- u16 rxbuf;
-#define OSPF_RXBUF_NORMAL 0
-#define OSPF_RXBUF_LARGE 1
+ u16 tx_length;
+ u16 rx_buffer;
+
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
u16 autype; /* Not really used in OSPFv3 */
#define OSPF_AUTH_NONE 0
@@ -822,6 +823,7 @@ struct ospf_iface_patt
u8 ptp_netmask; /* bool + 2 for unspecified */
u8 ttl_security; /* bool + 2 for TX only */
u8 bfd;
+ u8 bsd_secondary;
#ifdef OSPFv2
list *passwords;
diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c
index 4338bc1a..cd4b8a97 100644
--- a/proto/ospf/packet.c
+++ b/proto/ospf/packet.c
@@ -39,7 +39,6 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
unsigned
ospf_pkt_maxsize(struct ospf_iface *ifa)
{
- unsigned mtu = (ifa->type == OSPF_IT_VLINK) ? OSPF_VLINK_MTU : ifa->iface->mtu;
unsigned headers = SIZE_OF_IP_HEADER;
#ifdef OSPFv2
@@ -47,7 +46,7 @@ ospf_pkt_maxsize(struct ospf_iface *ifa)
headers += OSPF_AUTH_CRYPT_SIZE;
#endif
- return mtu - headers;
+ return ifa->tx_length - headers;
}
#ifdef OSPFv2
@@ -263,7 +262,7 @@ ospf_rx_hook(sock *sk, int size)
return 1;
DBG("OSPF: RX hook called (iface %s, src %I, dst %I)\n",
- sk->iface->name, sk->faddr, sk->laddr);
+ sk->ifname, sk->faddr, sk->laddr);
/* Initially, the packet is associated with the 'master' iface */
struct ospf_iface *ifa = sk->data;
@@ -321,22 +320,31 @@ ospf_rx_hook(sock *sk, int size)
return 1;
}
- int osize = ntohs(ps->length);
- if ((unsigned) osize < sizeof(struct ospf_packet))
+ uint plen = ntohs(ps->length);
+ if ((plen < sizeof(struct ospf_packet)) || ((plen % 4) != 0))
{
- log(L_ERR "%s%I - too low value in size field (%u bytes)", mesg, sk->faddr, osize);
+ log(L_ERR "%s%I - invalid length (%u)", mesg, sk->faddr, plen);
return 1;
}
- if ((osize > size) || ((osize % 4) != 0))
+ if (sk->flags & SKF_TRUNCATED)
{
- log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, osize, size);
+ log(L_WARN "%s%I - too large (%d/%d)", mesg, sk->faddr, plen, size);
+
+ /* If we have dynamic buffers and received truncated message, we expand RX buffer */
+
+ uint bs = plen + 256;
+ bs = BIRD_ALIGN(bs, 1024);
+
+ if (!ifa->cf->rx_buffer && (bs > sk->rbsize))
+ sk_set_rbsize(sk, bs);
+
return 1;
}
- if ((unsigned) size > sk->rbsize)
+ if (plen > size)
{
- log(L_ERR "%s%I - too large (%d vs %d)", mesg, sk->faddr, size, sk->rbsize);
+ log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, plen, size);
return 1;
}
@@ -349,7 +357,7 @@ ospf_rx_hook(sock *sk, int size)
#ifdef OSPFv2
if ((ps->autype != htons(OSPF_AUTH_CRYPT)) &&
(!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
- osize - sizeof(struct ospf_packet), NULL)))
+ plen - sizeof(struct ospf_packet), NULL)))
{
log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
return 1;
@@ -448,7 +456,7 @@ ospf_rx_hook(sock *sk, int size)
if(!n && (ps->type != HELLO_P))
{
log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)",
- sk->faddr, ifa->iface->name);
+ sk->faddr, ifa->ifname);
return 1;
}
@@ -495,20 +503,30 @@ ospf_rx_hook(sock *sk, int size)
return 1;
}
+/*
void
ospf_tx_hook(sock * sk)
{
struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
// struct proto *p = (struct proto *) (ifa->oa->po);
- log(L_ERR "OSPF: TX hook called on %s", ifa->iface->name);
+ log(L_ERR "OSPF: TX hook called on %s", ifa->ifname);
}
+*/
void
ospf_err_hook(sock * sk, int err)
{
struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
-// struct proto *p = (struct proto *) (ifa->oa->po);
- log(L_ERR "OSPF: Socket error on %s: %M", ifa->iface->name, err);
+ struct proto *p = &(ifa->oa->po->proto);
+ log(L_ERR "%s: Socket error on %s: %M", p->name, ifa->ifname, err);
+}
+
+void
+ospf_verr_hook(sock *sk, int err)
+{
+ struct proto_ospf *po = (struct proto_ospf *) (sk->data);
+ struct proto *p = &po->proto;
+ log(L_ERR "%s: Vlink socket error: %M", p->name, err);
}
void
@@ -543,9 +561,9 @@ ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
#endif
ospf_pkt_finalize(ifa, pkt);
- if (sk->tbuf != sk->tpos)
- log(L_ERR "Aiee, old packet was overwritten in TX buffer");
- sk_send_to(sk, len, dst, 0);
+ int done = sk_send_to(sk, len, dst, 0);
+ if (!done)
+ log(L_WARN "OSPF: TX queue full on %s", ifa->ifname);
}
diff --git a/proto/ospf/packet.h b/proto/ospf/packet.h
index fbcb4288..4ba1f08c 100644
--- a/proto/ospf/packet.h
+++ b/proto/ospf/packet.h
@@ -11,10 +11,11 @@
#define _BIRD_OSPF_PACKET_H_
void ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type);
-unsigned ospf_pkt_maxsize(struct ospf_iface *ifa);
+uint ospf_pkt_maxsize(struct ospf_iface *ifa);
int ospf_rx_hook(sock * sk, int size);
-void ospf_tx_hook(sock * sk);
+// void ospf_tx_hook(sock * sk);
void ospf_err_hook(sock * sk, int err);
+void ospf_verr_hook(sock *sk, int err);
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);
@@ -23,17 +24,5 @@ static inline void ospf_send_to_all(struct ospf_iface *ifa) { ospf_send_to(ifa,
static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; }
-static inline unsigned
-ospf_pkt_bufsize(struct ospf_iface *ifa)
-{
-#ifdef OSPFv2
- unsigned headers = (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0;
-#else
- unsigned headers = 0;
-#endif
-
- return ifa->sk->tbsize - headers;
-}
-
#endif /* _BIRD_OSPF_PACKET_H_ */
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index 52110aa1..1b39bda0 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -1079,44 +1079,42 @@ ospf_check_vlinks(struct proto_ospf *po)
{
struct proto *p = &po->proto;
- struct ospf_iface *iface;
- WALK_LIST(iface, po->iface_list)
+ struct ospf_iface *ifa;
+ WALK_LIST(ifa, po->iface_list)
{
- if (iface->type == OSPF_IT_VLINK)
+ if (ifa->type == OSPF_IT_VLINK)
{
struct top_hash_entry *tmp;
- tmp = ospf_hash_find_rt(po->gr, iface->voa->areaid, iface->vid);
+ tmp = ospf_hash_find_rt(po->gr, ifa->voa->areaid, ifa->vid);
if (tmp && (tmp->color == INSPF) && ipa_nonzero(tmp->lb) && tmp->nhs)
{
struct ospf_iface *nhi = ospf_iface_find(po, tmp->nhs->iface);
- if ((iface->state != OSPF_IS_PTP)
- || (iface->vifa != nhi)
- || !ipa_equal(iface->vip, tmp->lb))
+ if ((ifa->state != OSPF_IS_PTP)
+ || (ifa->vifa != nhi)
+ || !ipa_equal(ifa->vip, tmp->lb))
{
OSPF_TRACE(D_EVENTS, "Vlink peer %R found", tmp->lsa.id);
- ospf_iface_sm(iface, ISM_DOWN);
- iface->vifa = nhi;
- iface->iface = nhi->iface;
- iface->addr = nhi->addr;
- iface->sk = nhi->sk;
- iface->cost = tmp->dist;
- iface->vip = tmp->lb;
- ospf_iface_sm(iface, ISM_UP);
+ ospf_iface_sm(ifa, ISM_DOWN);
+ ifa->vifa = nhi;
+ ifa->addr = nhi->addr;
+ ifa->cost = tmp->dist;
+ ifa->vip = tmp->lb;
+ ospf_iface_sm(ifa, ISM_UP);
}
- else if ((iface->state == OSPF_IS_PTP) && (iface->cost != tmp->dist))
+ else if ((ifa->state == OSPF_IS_PTP) && (ifa->cost != tmp->dist))
{
- iface->cost = tmp->dist;
+ ifa->cost = tmp->dist;
schedule_rt_lsa(po->backbone);
}
}
else
{
- if (iface->state > OSPF_IS_DOWN)
+ if (ifa->state > OSPF_IS_DOWN)
{
- OSPF_TRACE(D_EVENTS, "Vlink peer %R lost", iface->vid);
- ospf_iface_sm(iface, ISM_DOWN);
+ OSPF_TRACE(D_EVENTS, "Vlink peer %R lost", ifa->vid);
+ ospf_iface_sm(ifa, ISM_DOWN);
}
}
}
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index f25db9a7..4af5afa5 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -306,7 +306,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
break;
default:
- log("Unknown interface type %s", ifa->iface->name);
+ log("Unknown interface type %s", ifa->ifname);
break;
}
@@ -447,7 +447,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
break;
default:
- log("Unknown interface type %s", ifa->iface->name);
+ log("Unknown interface type %s", ifa->ifname);
break;
}
@@ -596,8 +596,7 @@ originate_net_lsa(struct ospf_iface *ifa)
void *body;
- OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s",
- ifa->iface->name);
+ OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->ifname);
lsa.age = 0;
lsa.type = LSA_T_NET;
@@ -628,8 +627,7 @@ flush_net_lsa(struct ospf_iface *ifa)
if (ifa->net_lsa == NULL)
return;
- OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s",
- ifa->iface->name);
+ OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s", ifa->ifname);
ifa->net_lsa->lsa.sn += 1;
ifa->net_lsa->lsa.age = LSA_MAXAGE;
lsasum_calculate(&ifa->net_lsa->lsa, ifa->net_lsa->lsa_body);
@@ -1212,8 +1210,11 @@ originate_link_lsa(struct ospf_iface *ifa)
struct proto *p = &po->proto;
void *body;
- /* FIXME check for vlink and skip that? */
- OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->iface->name);
+ /* Vlinks do not have link-LSAs */
+ if (ifa->type == OSPF_IT_VLINK)
+ return;
+
+ OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->ifname);
lsa.age = 0;
lsa.type = LSA_T_LINK;
@@ -1498,8 +1499,7 @@ originate_prefix_net_lsa(struct ospf_iface *ifa)
struct ospf_lsa_header lsa;
void *body;
- OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s",
- ifa->iface->name);
+ OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->ifname);
lsa.age = 0;
lsa.type = LSA_T_PREFIX;
@@ -1525,8 +1525,7 @@ flush_prefix_net_lsa(struct ospf_iface *ifa)
if (en == NULL)
return;
- OSPF_TRACE(D_EVENTS, "Flushing network prefix-LSA for iface %s",
- ifa->iface->name);
+ OSPF_TRACE(D_EVENTS, "Flushing network prefix-LSA for iface %s", ifa->ifname);
en->lsa.sn += 1;
en->lsa.age = LSA_MAXAGE;