Commit 48e5f32d authored by Ondřej Zajíček's avatar Ondřej Zajíček

Many changes in I/O and OSPF sockets and packet handling.

I/O:
 - BSD: specify src addr on IP sockets by IP_HDRINCL
 - BSD: specify src addr on UDP sockets by IP_SENDSRCADDR
 - Linux: specify src addr on IP/UDP sockets by IP_PKTINFO
 - IPv6: specify src addr on IP/UDP sockets by IPV6_PKTINFO
 - Alternative SKF_BIND flag for binding to IP address
 - Allows IP/UDP sockets without tx_hook, on these
   sockets a packet is discarded when TX queue is full
 - Use consistently SOL_ for socket layer values.

OSPF:
 - Packet src addr is always explicitly set
 - Support for secondary addresses in BSD
 - Dynamic RX/TX buffers
 - Fixes some minor buffer overruns
 - Interface option 'tx length'
 - Names for vlink pseudoifaces (vlinkX)
 - Vlinks use separate socket for TX
 - Vlinks do not use fixed associated iface
 - Fixes TTL for direct unicast packets
 - Fixes DONTROUTE for OSPF sockets
 - Use ifa->ifname instead of ifa->iface->name
parent f48fa142
......@@ -2212,7 +2212,9 @@ protocol ospf <name> {
wait <num>;
dead count <num>;
dead <num>;
secondary <switch>;
rx buffer [normal|large|<num>];
tx length <num>;
type [broadcast|bcast|pointopoint|ptp|
nonbroadcast|nbma|pointomultipoint|ptmp];
strict nonbroadcast <switch>;
......@@ -2419,12 +2421,32 @@ protocol ospf <name> {
<tag>dead <M>num</M></tag>
When the router does not receive any messages from a neighbor in
<m/dead/ seconds, it will consider the neighbor down. If both directives
<m/dead count/ and <m/dead/ are used, <m/dead/ has precendence.
<cf/dead count/ and <cf/dead/ are used, <cf/dead/ has precendence.
<tag>secondary <M>switch</M></tag>
On BSD systems, older versions of BIRD supported OSPFv2 only for the
primary IP address of an interface, other IP ranges on the interface
were handled as stub networks. Since v1.4.1, regular operation on
secondary IP addresses is supported, but disabled by default for
compatibility. This option allows to enable it. The option is a
transitional measure, will be removed in the next major release as the
behavior will be changed. On Linux systems, the option is irrelevant, as
operation on non-primary addresses is already the regular behavior.
<tag>rx buffer <M>num</M></tag>
This sets the size of buffer used for receiving packets. The buffer should
be bigger than maximal size of any packets. Value NORMAL (default)
means 2*MTU, value LARGE means maximal allowed packet - 65535.
This option allows to specify the size of buffers used for packet
processing. The buffer size should be bigger than maximal size of any
packets. By default, buffers are dynamically resized as needed, but a
fixed value could be specified. Value <cf/large/ means maximal allowed
packet size - 65535.
<tag>tx length <M>num</M></tag>
Transmitted OSPF messages that contain large amount of information are
segmented to separate OSPF packets to avoid IP fragmentation. This
option specifies the soft ceiling for the length of generated OSPF
packets. Default value is the MTU of the network interface. Note that
larger OSPF packets may still be generated if underlying OSPF messages
cannot be splitted (e.g. when one large LSA is propagated).
<tag>type broadcast|bcast</tag>
BIRD detects a type of a connected network automatically, but
......
......@@ -157,13 +157,13 @@ rfree(void *res)
{
resource *r = res;
if (r)
{
if (r->n.next)
rem_node(&r->n);
r->class->free(r);
xfree(r);
}
if (!r)
return;
if (r->n.next)
rem_node(&r->n);
r->class->free(r);
xfree(r);
}
/**
......@@ -408,6 +408,9 @@ mb_realloc(void *m, unsigned size)
void
mb_free(void *m)
{
if (!m)
return;
struct mblock *b = SKIP_BACK(struct mblock, data, m);
rfree(b);
}
......
......@@ -57,6 +57,9 @@ int sk_open(sock *); /* Open socket */
int sk_send(sock *, unsigned len); /* Send data, <0=err, >0=ok, 0=sleep */
int sk_send_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to given destination */
void sk_reallocate(sock *); /* Free and allocate tbuf & rbuf */
void sk_set_rbsize(sock *s, uint val); /* Resize RX buffer */
void sk_set_tbsize(sock *s, uint val); /* Resize TX buffer, keeping content */
void sk_set_tbuf(sock *s, void *tbuf); /* Switch TX buffer, NULL-> return to internal */
void sk_dump_all(void);
int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */
int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */
......@@ -89,10 +92,13 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shoul
#define SKF_V6ONLY 1 /* Use IPV6_V6ONLY socket option */
#define SKF_LADDR_RX 2 /* Report local address for RX packets */
#define SKF_LADDR_TX 4 /* Allow to specify local address for TX packets */
#define SKF_TTL_RX 8 /* Report TTL / Hop Limit for RX packets */
#define SKF_TTL_RX 4 /* Report TTL / Hop Limit for RX packets */
#define SKF_BIND 8 /* Bind datagram socket to given source address */
#define SKF_THREAD 0x100 /* Socked used in thread, Do not add to main loop */
#define SKF_TRUNCATED 0x200 /* Received packet was truncated, set by IO layer */
#define SKF_HDRINCL 0x400 /* Used internally */
#define SKF_PKTINFO 0x800 /* Used internally */
/*
* Socket types SA SP DA DP IF TTL SendTo (?=may, -=must not, *=must)
......@@ -118,6 +124,14 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shoul
* call sk_setup_multicast() to enable multicast on that socket,
* and then use sk_join_group() and sk_leave_group() to manage
* a set of received multicast groups.
*
* For datagram (SK_UDP, SK_IP) sockets, there are two ways to handle
* source address. The socket could be bound to it using bind()
* syscall, but that also forbids the reception of multicast packets,
* or the address could be set on per-packet basis using platform
* dependent options (but these are not available in some corner
* cases). The first way is used when SKF_BIND is specified, the
* second way is used otherwise.
*/
#endif
......@@ -230,7 +230,7 @@ bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa)
sk->tos = IP_PREC_INTERNET_CONTROL;
sk->priority = sk_priority_control;
sk->ttl = ifa ? 255 : -1;
sk->flags = SKF_THREAD;
sk->flags = SKF_THREAD | SKF_BIND;
#ifdef IPV6
sk->flags |= SKF_V6ONLY;
......
......@@ -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
;
......
......@@ -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;
}
......
......@@ -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);
}
......@@ -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;