[原创文章不易,转载请注明出处链接]
SCTP协议有一个重要的特点,即Multi-homed(多归属),这是与TCP协议不同的显著地方之一,是对TCP协议的重大改进,充分利用了多条路由皆可承载数据流的特点,保证了物理网络级的冗余。
Multi-homed SCTP的直接表现就是有多个transport(即通路path),即到对端多个IP地址的path(通路)。一般来说有一条primary transport(主通路),其它的就是alternate transport(备用通路)。
SCTP的每条path实际上就是一条路由,而SCTP查找路由是根据destination address(目标地址)来决定,所以path的管理依赖于OSI L3(IP层)的路由缓存。而且,每条path的source
address(源端地址)由路由决定,所以多条path的source
address可能是本端的同一个IP
address,尽管本端也许绑定了多个IP
address。
先来看看与多path密切相关的IP地址列表的管理。
一. Manage address list
主要管理两个链表,即对端的peer_addr列表(实际上是path链表)和本地的bind_addr列表,都采用了内核的数据结构双向链表list_head。同时加上counter便于管理。这些地址表用双向链表list_head保存,而多个association却用哈希表,此处不详述。
1. 到对端的path链表
链表:asoc->peer.transport_addr_list
数量:asoc->peer.transport_count
主path的对端IP:assoc->peer.primary_addr
比如在函数sctp_seq_dump_remote_addrs中要打印对端的所有IP地址。
点击(此处)折叠或打开
-
list_for_each_entry(transport, &assoc->peer.transport_addr_list,
-
transports) {
-
addr = &transport->ipaddr;
-
af = sctp_get_af_specific(addr->sa.sa_family);
-
af->seq_dump_addr(seq, addr);
- }
管理链表的函数:sctp_assoc_add_peer和sctp_assoc_rm_peer
比如添加一个新的path到偶联的path链表:
点击(此处)折叠或打开
-
/* Add a transport address to an association. */
-
struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
-
const union sctp_addr *addr,
-
const gfp_t gfp,
-
const int peer_state)
-
{
-
struct sctp_transport *peer;
-
。。。(略)
-
peer = sctp_transport_new(net, addr, gfp);
-
。。。(略)
-
/* Attach the remote transport to our asoc. */
-
list_add_tail(&peer->transports, &asoc->peer.transport_addr_list);
-
asoc->peer.transport_count++;
-
-
/* If we do not yet have a primary path, set one. */
-
if (!asoc->peer.primary_path) {
-
sctp_assoc_set_primary(asoc, peer);
-
asoc->peer.retran_path = peer;
-
}
-
if (asoc->peer.active_path == asoc->peer.retran_path &&
-
peer->state != SCTP_UNCONFIRMED) {
-
asoc->peer.retran_path = peer;
-
}
-
-
return peer;
- }
2. 本端绑定的addr_entry链表
链表:asoc->base.bind_addr.address_list
数量:asoc->base.bind_addr.address_count //目前没有,可以考虑增加
主path的本端IP:asoc->peer.primary_path.saddr
比如,在获取路由函数sctp_v4_get_dst中,需遍历本端绑定地址链表:
点击(此处)折叠或打开
-
bp = &asoc->base.bind_addr;
-
if (dst) {
-
/* Walk through the bind address list and look for a bind
-
* address that matches the source address of the returned dst.
-
*/
-
sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port));
-
rcu_read_lock();
-
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
-
if (!laddr->valid || (laddr->state == SCTP_ADDR_DEL) ||
-
(laddr->state != SCTP_ADDR_SRC &&
-
!asoc->src_out_of_asoc_ok))
-
continue;
-
if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
-
goto out_unlock;
-
}
-
rcu_read_unlock();
-
。。。(略)
- }
再比如sctp_seq_dump_local_addrs中要打印本端地址列表,而且会标明primary path:
点击(此处)折叠或打开
-
if (epb->type == SCTP_EP_TYPE_ASSOCIATION) {
-
asoc = sctp_assoc(epb);
-
peer = asoc->peer.primary_path;
-
primary = &peer->saddr;
-
}
-
list_for_each_entry(laddr, &epb->bind_addr.address_list, list) {
-
addr = &laddr->a;
-
af = sctp_get_af_specific(addr->sa.sa_family);
-
if (primary && af->cmp_addr(addr, primary)) {
-
seq_printf(seq, "*");
-
}
-
af->seq_dump_addr(seq, addr); //printk
- }
下一篇继续看看path&assoc的断开和恢复管理。