📄 link.c
字号:
err("Attempt to delete non-existent link\n"); return; } dbg("tipc_link_delete()\n"); k_cancel_timer(&l_ptr->timer); tipc_node_lock(l_ptr->owner); tipc_link_reset(l_ptr); tipc_node_detach_link(l_ptr->owner, l_ptr); tipc_link_stop(l_ptr); list_del_init(&l_ptr->link_list); if (LINK_LOG_BUF_SIZE) kfree(l_ptr->print_buf.buf); tipc_node_unlock(l_ptr->owner); k_term_timer(&l_ptr->timer); kfree(l_ptr);}void tipc_link_start(struct link *l_ptr){ dbg("tipc_link_start %x\n", l_ptr); link_state_event(l_ptr, STARTING_EVT);}/** * link_schedule_port - schedule port for deferred sending * @l_ptr: pointer to link * @origport: reference to sending port * @sz: amount of data to be sent * * Schedules port for renewed sending of messages after link congestion * has abated. */static int link_schedule_port(struct link *l_ptr, u32 origport, u32 sz){ struct port *p_ptr; spin_lock_bh(&tipc_port_list_lock); p_ptr = tipc_port_lock(origport); if (p_ptr) { if (!p_ptr->wakeup) goto exit; if (!list_empty(&p_ptr->wait_list)) goto exit; p_ptr->congested_link = l_ptr; p_ptr->publ.congested = 1; p_ptr->waiting_pkts = 1 + ((sz - 1) / link_max_pkt(l_ptr)); list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports); l_ptr->stats.link_congs++;exit: tipc_port_unlock(p_ptr); } spin_unlock_bh(&tipc_port_list_lock); return -ELINKCONG;}void tipc_link_wakeup_ports(struct link *l_ptr, int all){ struct port *p_ptr; struct port *temp_p_ptr; int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size; if (all) win = 100000; if (win <= 0) return; if (!spin_trylock_bh(&tipc_port_list_lock)) return; if (link_congested(l_ptr)) goto exit; list_for_each_entry_safe(p_ptr, temp_p_ptr, &l_ptr->waiting_ports, wait_list) { if (win <= 0) break; list_del_init(&p_ptr->wait_list); p_ptr->congested_link = NULL; spin_lock_bh(p_ptr->publ.lock); p_ptr->publ.congested = 0; p_ptr->wakeup(&p_ptr->publ); win -= p_ptr->waiting_pkts; spin_unlock_bh(p_ptr->publ.lock); }exit: spin_unlock_bh(&tipc_port_list_lock);}/** * link_release_outqueue - purge link's outbound message queue * @l_ptr: pointer to link */static void link_release_outqueue(struct link *l_ptr){ struct sk_buff *buf = l_ptr->first_out; struct sk_buff *next; while (buf) { next = buf->next; buf_discard(buf); buf = next; } l_ptr->first_out = NULL; l_ptr->out_queue_size = 0;}/** * tipc_link_reset_fragments - purge link's inbound message fragments queue * @l_ptr: pointer to link */void tipc_link_reset_fragments(struct link *l_ptr){ struct sk_buff *buf = l_ptr->defragm_buf; struct sk_buff *next; while (buf) { next = buf->next; buf_discard(buf); buf = next; } l_ptr->defragm_buf = NULL;}/** * tipc_link_stop - purge all inbound and outbound messages associated with link * @l_ptr: pointer to link */void tipc_link_stop(struct link *l_ptr){ struct sk_buff *buf; struct sk_buff *next; buf = l_ptr->oldest_deferred_in; while (buf) { next = buf->next; buf_discard(buf); buf = next; } buf = l_ptr->first_out; while (buf) { next = buf->next; buf_discard(buf); buf = next; } tipc_link_reset_fragments(l_ptr); buf_discard(l_ptr->proto_msg_queue); l_ptr->proto_msg_queue = NULL;}#if 0/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */static void link_recv_event(struct link_event *ev){ ev->fcn(ev->addr, ev->name, ev->up); kfree(ev);}static void link_send_event(void (*fcn)(u32 a, char *n, int up), struct link *l_ptr, int up){ struct link_event *ev; ev = kmalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { warn("Link event allocation failure\n"); return; } ev->addr = l_ptr->addr; ev->up = up; ev->fcn = fcn; memcpy(ev->name, l_ptr->name, TIPC_MAX_LINK_NAME); tipc_k_signal((Handler)link_recv_event, (unsigned long)ev);}#else#define link_send_event(fcn, l_ptr, up) do { } while (0)#endifvoid tipc_link_reset(struct link *l_ptr){ struct sk_buff *buf; u32 prev_state = l_ptr->state; u32 checkpoint = l_ptr->next_in_no; int was_active_link = tipc_link_is_active(l_ptr); msg_set_session(l_ptr->pmsg, msg_session(l_ptr->pmsg) + 1); /* Link is down, accept any session: */ l_ptr->peer_session = 0; /* Prepare for max packet size negotiation */ link_init_max_pkt(l_ptr); l_ptr->state = RESET_UNKNOWN; dbg_link_state("Resetting Link\n"); if ((prev_state == RESET_UNKNOWN) || (prev_state == RESET_RESET)) return; tipc_node_link_down(l_ptr->owner, l_ptr); tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr);#if 0 tipc_printf(TIPC_CONS, "\nReset link <%s>\n", l_ptr->name); dbg_link_dump();#endif if (was_active_link && tipc_node_has_active_links(l_ptr->owner) && l_ptr->owner->permit_changeover) { l_ptr->reset_checkpoint = checkpoint; l_ptr->exp_msg_count = START_CHANGEOVER; } /* Clean up all queues: */ link_release_outqueue(l_ptr); buf_discard(l_ptr->proto_msg_queue); l_ptr->proto_msg_queue = NULL; buf = l_ptr->oldest_deferred_in; while (buf) { struct sk_buff *next = buf->next; buf_discard(buf); buf = next; } if (!list_empty(&l_ptr->waiting_ports)) tipc_link_wakeup_ports(l_ptr, 1); l_ptr->retransm_queue_head = 0; l_ptr->retransm_queue_size = 0; l_ptr->last_out = NULL; l_ptr->first_out = NULL; l_ptr->next_out = NULL; l_ptr->unacked_window = 0; l_ptr->checkpoint = 1; l_ptr->next_out_no = 1; l_ptr->deferred_inqueue_sz = 0; l_ptr->oldest_deferred_in = NULL; l_ptr->newest_deferred_in = NULL; l_ptr->fsm_msg_cnt = 0; l_ptr->stale_count = 0; link_reset_statistics(l_ptr); link_send_event(tipc_cfg_link_event, l_ptr, 0); if (!in_own_cluster(l_ptr->addr)) link_send_event(tipc_disc_link_event, l_ptr, 0);}static void link_activate(struct link *l_ptr){ l_ptr->next_in_no = l_ptr->stats.recv_info = 1; tipc_node_link_up(l_ptr->owner, l_ptr); tipc_bearer_add_dest(l_ptr->b_ptr, l_ptr->addr); link_send_event(tipc_cfg_link_event, l_ptr, 1); if (!in_own_cluster(l_ptr->addr)) link_send_event(tipc_disc_link_event, l_ptr, 1);}/** * link_state_event - link finite state machine * @l_ptr: pointer to link * @event: state machine event to process */static void link_state_event(struct link *l_ptr, unsigned event){ struct link *other; u32 cont_intv = l_ptr->continuity_interval; if (!l_ptr->started && (event != STARTING_EVT)) return; /* Not yet. */ if (link_blocked(l_ptr)) { if (event == TIMEOUT_EVT) { link_set_timer(l_ptr, cont_intv); } return; /* Changeover going on */ } dbg_link("STATE_EV: <%s> ", l_ptr->name); switch (l_ptr->state) { case WORKING_WORKING: dbg_link("WW/"); switch (event) { case TRAFFIC_MSG_EVT: dbg_link("TRF-"); /* fall through */ case ACTIVATE_MSG: dbg_link("ACT\n"); break; case TIMEOUT_EVT: dbg_link("TIM "); if (l_ptr->next_in_no != l_ptr->checkpoint) { l_ptr->checkpoint = l_ptr->next_in_no; if (tipc_bclink_acks_missing(l_ptr->owner)) { tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; } else if (l_ptr->max_pkt < l_ptr->max_pkt_target) { tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; } link_set_timer(l_ptr, cont_intv); break; } dbg_link(" -> WU\n"); l_ptr->state = WORKING_UNKNOWN; l_ptr->fsm_msg_cnt = 0; tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv / 4); break; case RESET_MSG: dbg_link("RES -> RR\n"); info("Resetting link <%s>, requested by peer\n", l_ptr->name); tipc_link_reset(l_ptr); l_ptr->state = RESET_RESET; l_ptr->fsm_msg_cnt = 0; tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); break; default: err("Unknown link event %u in WW state\n", event); } break; case WORKING_UNKNOWN: dbg_link("WU/"); switch (event) { case TRAFFIC_MSG_EVT: dbg_link("TRF-"); case ACTIVATE_MSG: dbg_link("ACT -> WW\n"); l_ptr->state = WORKING_WORKING; l_ptr->fsm_msg_cnt = 0; link_set_timer(l_ptr, cont_intv); break; case RESET_MSG: dbg_link("RES -> RR\n"); info("Resetting link <%s>, requested by peer " "while probing\n", l_ptr->name); tipc_link_reset(l_ptr); l_ptr->state = RESET_RESET; l_ptr->fsm_msg_cnt = 0; tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); break; case TIMEOUT_EVT: dbg_link("TIM "); if (l_ptr->next_in_no != l_ptr->checkpoint) { dbg_link("-> WW \n"); l_ptr->state = WORKING_WORKING; l_ptr->fsm_msg_cnt = 0; l_ptr->checkpoint = l_ptr->next_in_no; if (tipc_bclink_acks_missing(l_ptr->owner)) { tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; } link_set_timer(l_ptr, cont_intv); } else if (l_ptr->fsm_msg_cnt < l_ptr->abort_limit) { dbg_link("Probing %u/%u,timer = %u ms)\n", l_ptr->fsm_msg_cnt, l_ptr->abort_limit, cont_intv / 4); tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv / 4); } else { /* Link has failed */ dbg_link("-> RU (%u probes unanswered)\n", l_ptr->fsm_msg_cnt); warn("Resetting link <%s>, peer not responding\n", l_ptr->name); tipc_link_reset(l_ptr); l_ptr->state = RESET_UNKNOWN; l_ptr->fsm_msg_cnt = 0; tipc_link_send_proto_msg(l_ptr, RESET_MSG, 0, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); } break; default: err("Unknown link event %u in WU state\n", event); } break; case RESET_UNKNOWN: dbg_link("RU/"); switch (event) { case TRAFFIC_MSG_EVT: dbg_link("TRF-\n"); break; case ACTIVATE_MSG: other = l_ptr->owner->active_links[0]; if (other && link_working_unknown(other)) { dbg_link("ACT\n"); break; } dbg_link("ACT -> WW\n"); l_ptr->state = WORKING_WORKING; l_ptr->fsm_msg_cnt = 0; link_activate(l_ptr); tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); break; case RESET_MSG: dbg_link("RES \n"); dbg_link(" -> RR\n"); l_ptr->state = RESET_RESET; l_ptr->fsm_msg_cnt = 0; tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 1, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); break; case STARTING_EVT: dbg_link("START-"); l_ptr->started = 1; /* fall through */ case TIMEOUT_EVT: dbg_link("TIM \n"); tipc_link_send_proto_msg(l_ptr, RESET_MSG, 0, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); break; default: err("Unknown link event %u in RU state\n", event); } break; case RESET_RESET: dbg_link("RR/ "); switch (event) { case TRAFFIC_MSG_EVT: dbg_link("TRF-"); /* fall through */ case ACTIVATE_MSG: other = l_ptr->owner->active_links[0]; if (other && link_working_unknown(other)) { dbg_link("ACT\n"); break; } dbg_link("ACT -> WW\n"); l_ptr->state = WORKING_WORKING; l_ptr->fsm_msg_cnt = 0; link_activate(l_ptr); tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); break; case RESET_MSG: dbg_link("RES\n"); break; case TIMEOUT_EVT: dbg_link("TIM\n"); tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); dbg_link("fsm_msg_cnt %u\n", l_ptr->fsm_msg_cnt); break; default: err("Unknown link event %u in RR state\n", event); } break; default: err("Unknown link state %u/%u\n", l_ptr->state, event); }}/* * link_bundle_buf(): Append contents of a buffer to * the tail of an existing one. */static int link_bundle_buf(struct link *l_ptr, struct sk_buff *bundler, struct sk_buff *buf){ struct tipc_msg *bundler_msg = buf_msg(bundler); struct tipc_msg *msg = buf_msg(buf); u32 size = msg_size(msg); u32 bundle_size = msg_size(bundler_msg); u32 to_pos = align(bundle_size); u32 pad = to_pos - bundle_size; if (msg_user(bundler_msg) != MSG_BUNDLER)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -